Each case is labeled VALID (no error), VALID with a warning (a warning and no error), or INVALID (a parse error or at least one error diagnostic). The cases that import from ./catalog, ./auth, ./billing, ./crm, ./internal-helpers or ./other read the small files of grammar/fixtures/. Since v0.6.4, the reference parser's test suite runs every case and fails when a case and the parser disagree. A corpus with expected ASTs in JSON form is planned for a future release.
§17.1 Version declaration
VALID -- bare version
xdbml: 0.1
Project p { targets: Oracle }VALID -- with experimental opt-in
xdbml: 0.1
experimental: [graph_path_expressions]
Project p { targets: Oracle }VALID -- DBML compatibility (no version declaration)
Table users {
id int [pk]
email varchar
}INVALID -- version declared after other constructs
Project p { }
xdbml: 0.1Expected error: "version declaration must precede all other constructs."
§17.2 Nested / hierarchical structures
VALID -- nested object
xdbml: 0.1
Entity customers {
id int [pk]
address object {
street varchar [not null]
city varchar [not null]
}
}VALID -- array of named objects
xdbml: 0.1
Entity orders {
id int [pk]
line_items array [
line_item object {
sku varchar
quantity int
}
]
}VALID -- heterogeneous tuple
xdbml: 0.1
Entity customers {
id int [pk]
addresses array [
[0] billing object {
street varchar
city varchar
}
[1] shipping object {
street varchar
city varchar
}
]
}VALID -- recursive named type
xdbml: 0.1
Type TreeNode {
value int
children array [child TreeNode]
}
Entity org_chart {
root_id int [pk]
tree TreeNode
}INVALID -- tuple positions not contiguous
xdbml: 0.6
Entity bad {
arr array [
[0] first object { x int }
[2] third object { x int }
]
}Expected error: invalid-tuple-positions. Positions run from [0] without a gap, each once (§8.6).
VALID with a warning -- tuple positions not contiguous, in a document declaring v0.5 (invalid-tuple-positions)
xdbml: 0.5
Entity bad {
arr array [
[0] first object { x int }
[2] third object { x int }
]
}No parser checked tuple positions before v0.6.4, so a document declaring a version earlier than 0.6 draws a warning (§8.6).
Expected error (semantic-analysis pass, not grammar): "tuple positions must be contiguous starting at 0."
§17.3 Polymorphism
VALID -- oneOf with discriminator
xdbml: 0.1
Entity payments {
method oneOf {
card object {
last4 varchar(4)
brand varchar
}
bank object { iban varchar }
} [discriminator: method_kind]
}VALID -- union (scalar type alternatives)
xdbml: 0.1
Entity records {
score union [int, decimal, null]
legacy_id union [string, int] [not null]
}VALID -- array element-type shorthand (folds to a union)
xdbml: 0.1
Entity records {
ids array [int, varchar] // shorthand for array [union [int, varchar]]
mixed array [int, varchar, null]
tagged array [union [int, varchar]] // explicit form, still valid
labels set [int, varchar] // set takes the same shorthand
}VALID -- polymorphism inside an array
xdbml: 0.1
Entity event_log {
events array [
event oneOf {
user_event object {
type varchar
user_id objectId
action varchar
}
item_event object {
type varchar
item_id objectId
qty int
}
} [discriminator: type]
]
}§17.5 JSON-with-schema
VALID -- opaque JSON
xdbml: 0.1
Entity api_logs {
payload json
response variant
}VALID -- JSON with inline schema
xdbml: 0.1
Entity orders {
id int [pk]
payload json {
shipping_address object {
street varchar
city varchar
}
items array [
item object {
sku varchar
quantity int
}
]
}
}VALID -- BSON types
xdbml: 0.1
Container app [type: database] {
Collection users {
_id objectId [pk]
email varchar [unique]
balance Decimal128
last_login Date
avatar BinData
}
}§17.6 Path syntax
VALID -- path on index
xdbml: 0.1
Entity orders {
id int [pk]
line_items array [
line_item object {
sku varchar
quantity int
}
]
indexes {
line_items.sku // implicit array iteration (allowed in indexes)
line_items.[*].sku // explicit array iteration
line_items.[0].sku // positional
}
}VALID -- quoted segment for non-identifier name
xdbml: 0.1
Entity legacy {
data object {
"user.id" varchar
}
indexes {
data."user.id"
}
}VALID -- quoted names at the head of a path, in a key and in a relationship (v0.6.7)
xdbml: 0.6
Container sales {
Entity "Work Order" {
"Work Order ID" int [pk]
}
}
Entity "Work Order Part" {
"Work Order ID" int [ref: > "sales"."Work Order"."Work Order ID"]
"Part ID" int
indexes {
"Part ID"
}
constraints {
("Work Order ID", "Part ID") [pk]
}
}
TableGroup operations {
"sales"."Work Order"
"Work Order Part"
}VALID -- a dot inside quotes is part of the name (v0.6.7)
xdbml: 0.6
Container my {
Table table {
id int [pk]
}
}
Table "my.table" {
id int [pk]
}
Table other {
a int
b int
}
Ref: other.a > my.table.id
Ref: other.b > "my.table".idINVALID -- a quoted name holding a dot does not name an entity of a Container (unresolved-entity, v0.6.7)
xdbml: 0.6
Container my {
Table table {
id int [pk]
}
}
Table other {
a int
}
Ref: other.a > "my.table".idVALID -- JSONPath alias (parses, normalizes to dot-prefixed)
xdbml: 0.1
Entity orders {
id int [pk]
items array [item object { sku varchar }]
indexes {
items[*].sku // JSONPath alias; normalizes to items.[*].sku
}
}INVALID -- implicit array iteration in Ref source path
xdbml: 0.1
Entity orders {
id int [pk]
line_items array [item object { sku varchar }]
}
Entity products {
sku varchar [pk]
}
Ref: orders.line_items.sku > products.skuExpected error (semantic-analysis pass): "Ref source path crosses array; explicit .[*] required."
VALID -- explicit .[*] in Ref
xdbml: 0.6
Entity products {
sku varchar [pk]
}
Entity orders {
id int [pk]
line_items array [
line_item object {
sku varchar
quantity int
}
]
}
Ref: orders.line_items.[*].sku > products.sku§17.7 Container
VALID -- explicit container
xdbml: 0.1
Container core [type: schema] {
Entity users {
id int [pk]
name varchar
}
}VALID -- container synonyms
xdbml: 0.1
Database orders_store {
Collection orders {
_id objectId [pk]
}
}
Keyspace metrics {
Table page_views {
event_id varchar [pk]
}
}
Namespace events {
Record OrderPlaced {
event_id varchar [pk]
}
}VALID -- cross-container reference
xdbml: 0.1
Container core [type: schema] {
Entity customers {
id int [pk]
}
}
Container sales [type: schema] {
Entity orders {
id int [pk]
customer_id int [ref: > core.customers.id]
}
}
Ref: sales.orders.customer_id > core.customers.idVALID -- container-qualified Enum, declared and referenced by qualified name (DBML form)
enum core.job_status {
created
running
done
}
Table core.jobs {
id int [pk]
status core.job_status [not null]
}INVALID -- the same Enum declared in a Container block and with a qualified name (duplicate-declaration)
xdbml: 0.5
Container core [type: schema] {
Enum job_status {
created
}
}
enum core.job_status {
queued
}§17.8 Named types
VALID -- named type referenced from multiple entities
xdbml: 0.1
Type Address {
street varchar
city varchar
}
Entity customers {
primary_address Address
alternate_address Address
}
Entity orders {
shipping_address Address
}INVALID -- named type shadows builtin
xdbml: 0.6
Type varchar { // shadows builtin
custom_field int
}Expected error: named-type-shadows-builtin (§15.2).
VALID with a warning -- named type shadows builtin, in a document declaring v0.5 (named-type-shadows-builtin)
xdbml: 0.5
Type varchar {
custom_field int
}No parser reported this before v0.6.4, so a document declaring a version earlier than 0.6 draws a warning (§15.2).
Expected error (semantic-analysis pass): "named type 'varchar' shadows built-in type keyword; rename or remove."
§17.9 AI-readiness settings
VALID -- all four AI-readiness settings
xdbml: 0.1
Entity customers {
mrr_amount decimal(10,2) [
synonyms: ['monthly revenue', 'recurring revenue'],
business_term: 'https://glossary.acme.com/MRR',
tags: ['finance', 'kpi'],
granularity: month
]
}VALID -- custom property with x_ prefix
xdbml: 0.1
Entity customers [
x_governance_owner: 'finance-team@acme.com',
x_collibra_asset_id: 'urn:collibra:asset:abc-123'
] {
id int [pk]
name varchar
}§17.10 Cardinality
VALID -- compact form
xdbml: 0.1
Entity customers { id int [pk] }
Entity orders { id int [pk]; customer_id int }
Ref: orders.customer_id > customers.idVALID -- explicit source/target cardinality
xdbml: 0.6
Entity customers {
id int [pk]
}
Entity orders {
id int [pk]
customer_id int
}
Ref: orders.customer_id > customers.id [source: '1..*', target: '1..1']VALID -- four-key alternative form
xdbml: 0.6
Entity people {
id int [pk]
}
Entity pets {
id int [pk]
owner_id int
}
Ref: pets.owner_id > people.id [
min_source: 0, max_source: '*',
min_target: 0, max_target: 1
]VALID -- optional marks on the operator, short, long and inline (DBML, v0.7)
Table users {
id int [pk]
}
Table posts {
id int [pk]
author_id int
owner_id int
reviewer_id int
editor_id int [ref: ?>? users.id]
}
Ref: posts.author_id >? users.id
Ref: users.id ?< posts.owner_id
Ref pair {
posts.reviewer_id -? users.id [delete: cascade]
}VALID with a warning -- a ? and a setting that disagree on an end (v0.7)
xdbml: 0.7
Entity customers {
id int [pk]
}
Entity orders {
id int [pk]
customer_id int [not null]
}
Ref: orders.customer_id >? customers.id [target: '1..1']INVALID -- a ? apart from the operator (DBML, v0.7)
Table users {
id int [pk]
}
Table posts {
author_id int
}
Ref: posts.author_id > ? users.idVALID -- a ? on a relationship between entities (v0.7)
xdbml: 0.7
Entity Customer { }
Entity Order { }
Ref: Customer >? Order§17.11 Edge
VALID -- basic edge
xdbml: 0.1
Entity Person { id int [pk]; name varchar }
Edge KNOWS [source: Person, target: Person] {
since date [not null]
intimacy int [minimum: 0, maximum: 10]
}VALID -- edge with cardinality
Edge OWNS [source: Person, target: Pet,
source_cardinality: '0..*', target_cardinality: '0..1'] {
acquired_date date
}VALID -- undirected edge
Edge FRIENDS_WITH [source: Person, target: Person, undirected: true] {
since date
}VALID -- multiple edges between same entities
Edge LIKES [source: User, target: Post] { liked_at timestamp }
Edge SHARED [source: User, target: Post] { shared_at timestamp }
Edge BLOCKED [source: User, target: Post] { blocked_at timestamp }§17.12 View
VALID -- virtual view
xdbml: 0.1
View active_customers [materialized: false] {
source_query: '''
SELECT id, email, name
FROM customers
WHERE deleted_at IS NULL
'''
id int [pk]
email varchar
name varchar
}VALID -- materialized view with refresh settings
View monthly_revenue [materialized: true,
refresh_schedule: 'daily',
source_database: 'Oracle'] {
source_query: '''
SELECT TRUNC(placed_at, 'MM') AS month, SUM(total) AS revenue
FROM orders
GROUP BY TRUNC(placed_at, 'MM')
'''
month date [pk]
revenue decimal(15,2)
}VALID -- view inside container
xdbml: 0.1
Container analytics [type: schema] {
Entity orders {
id int [pk]
total decimal(10,2)
placed_at timestamp
}
View daily_totals [materialized: true] {
source_query: 'SELECT DATE(placed_at) day, SUM(total) total FROM orders GROUP BY DATE(placed_at)'
day date [pk]
total decimal(10,2)
}
}End-to-end: polyglot model
VALID -- full polyglot model with Oracle, MongoDB, Avro, Neo4j
xdbml: 0.1
Project polyglot { targets: [Oracle, MongoDB, Avro, Neo4j] }
Type Address {
street varchar [not null]
city varchar [not null]
country varchar
}
Type MonetaryAmount {
amount Decimal128 [not null]
currency string [not null, pattern: '^[A-Z]{3}$', minLength: 3, maxLength: 3]
}
Container core [type: schema, target: Oracle] {
Entity customers {
id int [pk]
email varchar [unique, not null, pattern: '^[^@]+@[^@]+$']
display_name varchar [not null]
primary_address Address
}
}
Container orders_store [type: database, target: MongoDB] {
Collection orders {
_id objectId [pk]
customer_id int32 [not null]
placed_at Date [granularity: second]
total MonetaryAmount
line_items array [
line_item object {
sku string [not null]
quantity int32 [not null, minimum: 1]
unit_price MonetaryAmount
}
]
payment_method oneOf {
card object {
last4 string [maxLength: 4]
brand string
}
bank object { iban string }
wallet object {
provider string
account string
}
} [discriminator: method_kind]
}
}
Container events [type: namespace, target: Avro] {
Record OrderPlaced {
event_id string [pk]
occurred long [granularity: millisecond, not null]
order_id string [not null]
customer_id int [not null]
total MonetaryAmount
}
}
Container catalog [type: schema, target: Oracle] {
Entity products {
sku varchar [pk]
title varchar [not null]
}
}
Container social [type: database, target: Neo4j] {
Edge FOLLOWS [source: core.customers, target: core.customers,
source_cardinality: '0..*', target_cardinality: '0..*'] {
since date [not null]
is_close boolean [default: false]
}
}
Ref: orders_store.orders.customer_id > core.customers.id [source: '1..*', target: '1..1']
Ref: orders_store.orders.line_items.[*].sku > catalog.products.sku
Ref: events.OrderPlaced.order_id > orders_store.orders._id§14.7 Scalar Named Types (v0.2)
VALID -- scalar Named Type with validation settings
xdbml: 0.2
Type Email varchar [pattern: '^[^@]+@[^@]+$', tags: ['pii']]
Type CountryCode varchar [pattern: '^[A-Z]{2}$', minLength: 2, maxLength: 2]
Type Percentage decimal(5,2) [minimum: 0, maximum: 100]
Entity users {
id int [pk]
email Email
country CountryCode
}VALID -- scalar Named Type alongside object-shaped Type
xdbml: 0.2
Type Email varchar [pattern: '^[^@]+@[^@]+$']
Type Address {
street varchar [not null]
city varchar [not null]
}
Entity customers {
id int [pk]
email Email
primary_address Address
}VALID -- scalar Named Type referencing another Type
xdbml: 0.2
Type Email varchar [pattern: '^[^@]+@[^@]+$']
Type PII_Email Email [tags: ['pii', 'gdpr-subject']]
Entity customers {
id int [pk]
email PII_Email
}§26 Module system (v0.2)
VALID -- reuse * (import all) at file scope
xdbml: 0.2
Project app { targets: [PostgreSQL] }
reuse * from './catalog'
Container ordering [type: schema] {
Entity orders {
id int [pk]
customer_id int
}
}VALID -- selective import inside Container body
xdbml: 0.2
Project app { targets: [PostgreSQL] }
Container ordering [type: schema] {
reuse { entity core.products, entity core.categories } from './catalog'
Entity orders {
id int [pk]
customer_id int
}
Entity order_lines {
order_id int [ref: > ordering.orders.id]
product_id int [ref: > ordering.products.id]
quantity int
}
}VALID -- import with clone block
xdbml: 0.2
Project sales_data_product { targets: [Snowflake] }
Container facts [type: schema] {
reuse { entity core.dim_customer } from './conformed-dimensions' [cloned_at: '2026-06-06T14:30:00Z'] {
Entity dim_customer {
id int [pk]
email varchar [pattern: '^[^@]+@[^@]+$', tags: ['pii']]
}
}
Entity fact_sales {
customer_id int [ref: > facts.dim_customer.id]
amount decimal(10,2)
}
}VALID -- aliased import
xdbml: 0.2
Project app { targets: [PostgreSQL] }
Container app [type: schema] {
reuse { entity users as auth_users } from './auth'
reuse { entity users as billing_users } from './billing'
Entity sessions {
id int [pk]
auth_user_id int [ref: > app.auth_users.id]
billing_user_id int [ref: > app.billing_users.id]
}
}VALID -- field-level import at file scope, used as a field type
xdbml: 0.2
Project new_system { targets: [PostgreSQL] }
reuse { field ops.customer_legacy.legacy_email as contact_email } from './legacy-customer' [cloned_at: '2026-06-06T14:30:00Z'] {
contact_email varchar [pattern: '^[^@]+@[^@]+$', tags: ['pii']]
}
Container app [type: schema] {
Entity new_customer {
id int [pk]
contact_email contact_email
}
}VALID -- use (non-transitive) for private internal imports
xdbml: 0.2
use { type InternalAuditFields } from './internal-helpers'
Container ordering [type: schema] {
Entity orders {
id int [pk]
audit InternalAuditFields
customer_id int
}
}VALID -- multi-line and comma-separated equivalence
xdbml: 0.2
// Multi-line form: one item per line, no separator
reuse {
entity products
entity categories
type Email
} from './catalog'The import list is a list body (§3.9, §28.2): the single-line form of the next case imports the same three declarations. The two directives go in separate documents, since importing one declaration twice into one document declares it twice.
VALID -- comma-separated single-line import list
xdbml: 0.2
reuse { entity products, entity categories, type Email } from './catalog'VALID -- reference-only directive (no clone block, DBML-compatible)
xdbml: 0.2
Project order_system { targets: [PostgreSQL] }
Container ordering [type: schema] {
reuse { entity core.products } from './catalog'
Entity orders {
id int [pk]
customer_id int
}
}INVALID -- field import inside Container body
xdbml: 0.2
Container app [type: schema] {
reuse { field core.dim_customer.email } from './conformed-dimensions'
Entity new_customer {
id int [pk]
email email
}
}Expected semantic error: "field imports may only appear at file scope (§25.5)."
INVALID -- absolute path
xdbml: 0.2
reuse * from '/absolute/path/to/file.xdbml'Expected error: "an absolute path; a module source is read relative to the importing file, as in DBML (§28.13)."
INVALID -- a URL with a scheme other than https (§28.14)
xdbml: 0.3
reuse * from 'http://example.com/schemas/users.xdbml'Expected error: "Module source scheme 'http:' is not allowed; remote sources must use 'https://'."
INVALID -- v0.1 file using v0.2-only constructs
xdbml: 0.1
reuse { entity core.products } from './catalog'Expected error: "the module system (use/reuse directives) requires xdbml: 0.2 or later; this document declares xdbml: 0.1."
INVALID -- unrecognized element-type slot value
xdbml: 0.2
reuse { widget core.products } from './catalog'Expected error: "unrecognized element type 'widget'; expected one of: table, entity, collection, record, enum, tablepartial, note, schema, container, tablegroup, type, edge, view, diagramview, field."
INVALID -- importing Project
xdbml: 0.2
reuse { project some_project } from './other'Expected error: "Project declarations are not importable (§26.4)."
§10 Checks -- entity-level constraints (v0.2)
VALID -- multi-column check expression
xdbml: 0.2
Entity users {
id int [pk]
wealth decimal(15,2)
debt decimal(15,2)
checks {
`debt + wealth >= 0` [name: 'chk_positive_net_worth']
}
}VALID -- multiple checks with and without names
xdbml: 0.2
Entity reservations {
id int [pk]
start_date date
end_date date
checks {
`start_date <= end_date` [name: 'chk_valid_date_range']
`end_date - start_date <= 30` [name: 'chk_max_30_days']
`start_date >= CURRENT_DATE`
}
}VALID -- check with note
xdbml: 0.2
Entity orders {
id int [pk]
status varchar
shipped_at timestamp
checks {
`(status != 'shipped') OR (shipped_at IS NOT NULL)` [
name: 'chk_shipped_has_timestamp',
note: 'A shipped order must record the shipment timestamp.'
]
}
}VALID -- entity with both checks and indexes
xdbml: 0.2
Entity inventory {
id int [pk]
sku varchar
warehouse varchar
qty int
indexes {
(sku, warehouse) [unique]
}
checks {
`qty >= 0` [name: 'chk_non_negative_qty']
}
}INVALID -- check expression not backtick-wrapped
xdbml: 0.2
Entity users {
id int [pk]
wealth decimal(15,2)
checks {
wealth >= 0
}
}Expected error: "check expressions must be backtick-wrapped EXPRESSION_LITERAL values."
§11.9 Relationship settings -- inactive and color (v0.2)
VALID -- inactive flag on Ref
xdbml: 0.2
Entity posts {
id int [pk]
user_id int
}
Entity users {
id int [pk]
}
Ref: posts.user_id > users.id [inactive]VALID -- inactive + color + note
xdbml: 0.2
Entity audit_log {
id int [pk]
user_id int
}
Entity users {
id int [pk]
}
Ref: audit_log.user_id > users.id [
inactive,
color: '#999999',
note: 'Historical FK; superseded by audit_ref table'
]VALID -- color alone (active relationship with custom color)
xdbml: 0.2
Entity orders {
id int [pk]
customer_id int
}
Entity customers {
id int [pk]
}
Ref: orders.customer_id > customers.id [color: '#3f51b5']§16.2 TableGroup color (v0.2)
VALID -- TableGroup with color and note
xdbml: 0.2
Entity orders { id int [pk] }
Entity order_lines { id int [pk] }
Entity invoices { id int [pk] }
TableGroup ecommerce [color: '#3498DB', note: 'Commerce-side entities'] {
orders
order_lines
invoices
}VALID -- TableGroup with only color
xdbml: 0.2
Entity users { id int [pk] }
Entity sessions { id int [pk] }
TableGroup auth [color: '#FF5722'] {
users
sessions
}§25 Records -- expanded forms (v0.2)
VALID -- records inside entity (implicit column list, v0.1 syntax)
xdbml: 0.2
Entity users {
id int [pk]
name varchar
email varchar
records {
1, 'Alice', 'alice@example.com'
2, 'Bob', 'bob@example.com'
}
}VALID -- top-level records with explicit column list
xdbml: 0.2
Entity users {
id int [pk]
name varchar
email varchar
}
records users (id, name, email) {
1, 'Alice', 'alice@example.com'
2, 'Bob', 'bob@example.com'
}VALID -- top-level records with cross-container reference
xdbml: 0.2
Container core [type: schema] {
Entity users {
id int [pk]
email varchar
}
}
records core.users (id, email) {
1, 'alice@example.com'
2, 'bob@example.com'
}VALID -- value forms (string, number, boolean, null, date, enum, backtick)
xdbml: 0.2
Enum Status { active inactive pending }
Entity events {
id int [pk]
occurred_at timestamp
status Status
is_archived boolean
payload varchar
records {
1, '2026-06-10T14:30:00Z', Status.active, true, 'string value'
2, '2026-06-11T09:00:00Z', Status.pending, false, null
3, `gen_random_uuid()`, Status.inactive, null, '''multi
line string'''
}
}§19 Sticky notes (v0.7)
VALID -- a sticky note with a color and custom properties (DBML)
Table orders {
id int [pk]
}
Note design_decision [color: #F4D03F, author: "docs"] {
'''
## Line items stay in orders
Reads outnumber writes **100 to 1**.
'''
}VALID -- color none, a quoted name, and a qualified name in the implicit Container (DBML)
Table core.users {
id int [pk]
}
Note "Release plan" [color: none] {
'Deprecated fields leave in release 4.2.'
}
Note core.legend {
'Every table of core belongs to the web shop.'
}VALID -- a sticky note in a Container, beside the Container's own note (v0.7)
xdbml: 0.7
Container sales [type: schema] {
Note: 'Order management'
Entity orders {
id int [pk]
status varchar
}
Note order_states [color: #FBCFE8] {
'An order moves from placed to shipped to delivered.'
}
}
DiagramView order_flow {
Tables {
sales.orders
}
Notes {
sales.order_states
}
}
Metadata Note sales.order_states {
owner: 'ops'
}VALID -- a top-level Note without a name is the note of the project
Table orders {
id int [pk]
}
Note: 'Reference model of the web shop'VALID with a warning -- a second note of the project (duplicate-project-note, §19.5)
Project shop {
Note: 'Reference model'
}
Note: 'Maintained by the data team'INVALID -- a sticky note in a Container, without xdbml: 0.7 (§19.4)
Container sales [type: schema] {
Note order_states {
'placed, shipped, delivered'
}
}INVALID -- a color of another form (invalid-note-color, §19.3)
Note reminder [color: red] {
'Review the owners'
}INVALID -- settings on a Note without a name (§19.5)
Note [color: #F4D03F] {
'Reference model'
}INVALID -- a sticky note with an empty body (§19.2)
Note reminder {
}INVALID -- two sticky notes of one name (duplicate-declaration, §19.2)
Note reminder {
'one'
}
Note reminder {
'two'
}§24.7 Metadata blocks (v0.7)
VALID -- Table, Column, TableGroup and Note blocks (DBML)
Table users [owner: 'jane'] {
id int [pk]
email varchar
}
TableGroup accounts {
users
}
Note reminder {
'Review the owners'
}
Metadata Table users {
owner: 'data-team'
note: 'Accounts of the web shop'
headercolor: #3498DB
}
Metadata Column users.email {
classification: 'confidential'
}
Metadata TableGroup accounts {
color: #2ECC71
}
Metadata Note reminder {
color: none
}VALID -- Container, View, DiagramView and the entity and field synonyms (v0.7)
xdbml: 0.7
Container sales [type: schema] {
Entity orders {
id int [pk]
addr object {
city varchar
}
}
View open_orders {
id int
}
}
DiagramView order_flow {
Tables {
sales.orders
}
}
Metadata Container sales {
note: 'Sales schema'
color: #E67E22
}
Metadata Entity sales.orders {
x_owner: 'sales-ops'
}
Metadata Field orders.addr.city {
note: 'City of delivery'
}
Metadata View open_orders {
headercolor: #95A5A6
}
Metadata DiagramView order_flow {
note: 'Order lifecycle'
}INVALID -- an xDBML kind without a version declaration
Table users {
id int [pk]
}
Metadata Entity users {
owner: 'x'
}INVALID -- a target that names nothing (DBML)
Table users {
id int [pk]
}
Metadata Column users.nickname {
owner: 'x'
}INVALID -- a flag in the body (DBML)
Table users {
id int
}
Metadata Column users.id {
pk
}INVALID -- a Metadata block inside a Container
xdbml: 0.7
Container core [type: schema] {
Table users {
id int
}
Metadata Table users {
owner: 'x'
}
}VALID with a warning -- a block that changes the entity's own value (DBML)
Table users [owner: 'jane'] {
id int [pk]
}
Metadata Table users {
owner: 'scott'
}VALID with a warning -- synonyms in a Metadata block read as a custom property
xdbml: 0.7
Entity customers {
id int [pk]
}
Metadata Entity customers {
synonyms: 'clients'
}VALID with a warning -- a setting written twice in one list
Table users [owner: 'a', owner: 'b'] {
id int [pk]
}§26 Records -- DBML 10.3.1 forms (v0.7)
VALID -- example flag on a top-level declaration, after the column list (DBML)
Table users {
id int [pk]
name varchar
}
records users (id, name) [example] {
1, 'Alice'
2, 'Bob'
}VALID -- example flag inside a table, with and without a column list (DBML)
Table users {
id int [pk]
name varchar
records [example] {
1, 'Alice'
}
}
Table orders {
id int [pk]
user_id int
total decimal
records (id, user_id) [example] {
10, 1
}
}VALID -- column list on records inside an entity
xdbml: 0.7
Entity users {
id int [pk]
name varchar
email varchar
records (id, email) {
1, 'alice@example.com'
2, 'bob@example.com'
}
}VALID -- empty fields read as null (DBML)
Table events {
id int [pk]
kind varchar
payload varchar
}
records events (id, kind, payload) {
1, , 'no kind'
, 'orphan', 'no id'
3, 'last payload empty',
}INVALID -- a second records block inside an entity
Table users {
id int [pk]
records {
1
}
records {
2
}
}INVALID -- a records block inside an entity and a top-level declaration for it
xdbml: 0.7
Entity users {
id int [pk]
name varchar
records {
1, 'Alice'
}
}
records users (id, name) [example] {
2, 'Bob'
}VALID with a warning -- a second records block in a document declaring 0.6
xdbml: 0.6
Entity users {
id int [pk]
name varchar
}
records users (id) {
1
}
records users (name) {
'Alice'
}INVALID -- the brackets before the column list
Table users {
id int [pk]
records [example] (id) {
1
}
}INVALID -- a column of the list that is not a field of the entity
xdbml: 0.7
Entity users {
id int [pk]
records (id, nickname) {
1, 'Al'
}
}§27 Data lineage (v0.7)
VALID -- the three forms of DBML, in a document without a version
Table raw_orders {
id int [pk]
amount_usd decimal(12, 2)
}
Table stg_orders [dep: <- raw_orders] {
order_id int [pk, dep: <- raw_orders.id]
revenue decimal(12, 2)
}
Table fct_orders {
order_id int [pk]
revenue decimal(12, 2)
}
Dep: raw_orders.amount_usd -> stg_orders.revenue [note: 'Converted to the reporting currency']
Dep order_revenue: fct_orders.revenue <- stg_orders.revenue
Dep build_fct_orders [owner: 'analytics', color: #d97706] {
stg_orders -> fct_orders
materialized: 'table'
Note: '''
One row per order.
'''
}VALID -- entity to field and field to entity, a table built from its own previous state, and a cycle
Table orders {
id int [pk]
line_items json
}
Table order_lines {
order_id int
sku varchar
}
Table daily_kpis {
day date [pk]
order_count int
}
Dep: orders -> daily_kpis.order_count
Dep: orders.line_items -> order_lines
Dep: daily_kpis -> daily_kpis
Dep: order_lines -> ordersVALID -- a block gathers the source fields of one target field, each with settings of its own
Table customers {
id int [pk]
first_name varchar
last_name varchar
}
Table dim_customer {
id int [pk]
full_name varchar
}
Dep full_name [note: 'Concatenates the first and the last name'] {
customers.first_name -> dim_customer.full_name [color: #0891b2]
customers.last_name -> dim_customer.full_name
}VALID -- Views, nested fields and a Container (§27.1)
xdbml: 0.7
Container stripe [type: database, target: 'Stripe API'] {
Entity charges {
id varchar [pk]
amount int
}
}
Collection events {
_id objectId [pk]
payload object {
customer object {
id int
}
}
items array [object {
sku varchar
}]
}
Table payments {
id varchar [pk]
amount_cents int
}
View payment_summary {
customer_id int
total int
}
Dep: stripe.charges.amount -> payments.amount_cents
Dep: events.payload.customer.id -> payment_summary.customer_id
Dep: events.items.[*].sku -> payments.id
Dep: payments -> payment_summaryVALID -- an alias names the entity, two Deps share a name, and dep names a field
Table very_long_orders_table as O {
id int [pk]
dep varchar
}
Table summary {
id int [pk]
}
Dep load: O.id -> summary.id
Dep load: O -> summaryVALID with a warning -- a block with no dependency declares nothing (empty-dep, §27.2)
Table a {
id int
}
Dep nothing_yet {
note: 'To be mapped'
}VALID with a warning -- dep without an arrow stays a custom property in a v0.6 document (invalid-dep-value, §27.9)
xdbml: 0.6
Table orders [dep: 'nightly batch'] {
id int [pk]
}INVALID -- dep without an arrow in a document without a version (invalid-dep-value, §27.2)
Table orders [dep: 'nightly batch'] {
id int [pk]
}INVALID -- a Dep in a Container (§27.4)
xdbml: 0.7
Container sales {
Entity orders {
id int
}
Dep: orders -> orders
}INVALID -- a Dep in the body of a table (§27.4)
Table orders {
id int
Dep: orders -> orders
}INVALID -- an endpoint that names no element (unresolved-dep-endpoint, §27.1)
Table orders {
id int
}
Dep: payments.amount -> orders.idINVALID -- an endpoint that names a field the entity does not declare (unresolved-dep-endpoint, §27.1)
Table orders {
id int
}
Table payments {
id int
}
Dep: payments.amount -> orders.idINVALID -- an endpoint that names an Edge (invalid-dep-endpoint, §27.1)
xdbml: 0.7
Table person {
id int [pk]
}
Edge knows [source: person, target: person] {
since date
}
Dep: person -> knowsINVALID -- a composite endpoint (invalid-dep-endpoint, §27.1)
Table orders {
a int
b int
}
Table totals {
t int
}
Dep: orders.(a, b) -> totals.tINVALID -- a relationship operator in a dependency (§27.2)
Table a {
id int
}
Table b {
id int
}
Dep: a > bINVALID -- a space inside the arrow (§27.2)
Table a {
id int
}
Table b {
id int
}
Dep: a - > bINVALID -- three endpoints in one dependency (§27.2)
Table a {
id int
}
Table b {
id int
}
Table c {
id int
}
Dep: a -> b -> cINVALID -- two upstream elements in one dependency, without a version declaration (§27.2)
Table a {
id int
}
Table b {
id int
}
Table c {
id int
}
Dep: a, b -> cINVALID -- a block whose dependencies feed two elements (dep-mixed-downstream, §27.2)
Table a {
id int
}
Table b {
id int
}
Table c {
id int
}
Dep load {
a -> b
a -> c
}INVALID -- a block mixing a dependency between entities with one naming a field, without a version declaration (dep-mixed-level, §27.2)
Table a {
id int
}
Table b {
id int
}
Dep load {
a -> b
a.id -> b.id
}INVALID -- an inline dep on a field naming an entity (dep-wrong-kind, §27.2)
Table a {
id int
}
Table b {
id int [dep: <- a]
}INVALID -- an inline dep on an entity naming a field (dep-wrong-kind, §27.2)
Table a {
id int
}
Table b [dep: <- a.id] {
id int
}INVALID -- a dep on a TablePartial (dep-in-partial, §27.2)
Table a {
id int
}
TablePartial audited [dep: <- a] {
loaded_at timestamp
}INVALID -- a color that is no hex code (invalid-dep-color, §27.3)
Table a {
id int
}
Table b {
id int
}
Dep: a -> b [color: none]INVALID -- a field depending on itself (dep-self-loop, §27.4)
Table a {
id int
}
Dep: a.id -> a.idINVALID -- a dependency stated twice, inline and as a Dep (duplicate-dep, §27.4)
Table a {
id int
}
Table b [dep: <- a] {
id int
}
Dep: a -> bINVALID -- a Dep name qualified with a Container (§27.4)
Table a {
id int
}
Dep sales.load: a -> a§28.13 Module specifiers -- DBML 10.3.1 resolution (v0.7)
The cases import from grammar/fixtures/, where legacy.dbml is a DBML file with no .xdbml twin.
VALID -- an import without an extension reads a .dbml file
xdbml: 0.7
use { table legacy_orders } from './legacy'VALID -- an explicit .dbml extension
xdbml: 0.7
use { table legacy_orders } from './legacy.dbml'VALID -- a specifier without ./, read relative to the importing file as in DBML
use { table products } from 'catalog'VALID -- a first folder that looks like a host is a folder (a clone keeps the case offline)
xdbml: 0.7
use { entity products } from 'acme.com/catalog' {
Entity products {
id int [pk]
}
}INVALID -- a Windows drive path, absolute, that no host resolves
xdbml: 0.7
use * from 'C:\\models\\catalog'Expected error: "an absolute path; a module source is read relative to the importing file, as in DBML (§28.13)."
INVALID -- a specifier naming no file under either extension
xdbml: 0.7
use * from './missing'Expected error: "Failed to read referenced module file '.../missing.xdbml' or '.../missing.dbml'."
§12 SupertypeGroup (v0.5)
VALID -- one group with completeness and exclusivity
xdbml: 0.5
Entity Party {
party_id int [pk]
name varchar [not null]
}
Entity Person {
birth_date date
}
Entity Organization {
legal_form varchar
}
SupertypeGroup legal_nature [supertype: Party, completeness: total, exclusivity: disjoint] {
Person
Organization
}VALID -- materialization settings, a per-subtype strategy, and TableGroup-style separators
xdbml: 0.5
Entity Vehicle { vehicle_id int [pk] }
Entity Car { seats int }
Entity Motorcycle { sidecar boolean }
Entity Truck { payload decimal }
SupertypeGroup vehicle_kind [supertype: Vehicle, completeness: total, exclusivity: disjoint, strategy: roll_up, merge: flat, discriminator: kind] {
Car, Motorcycle; Truck [strategy: roll_down]
}VALID -- aliases normalize to canonical values
xdbml: 0.5
Entity A { id int [pk] }
Entity B { b int }
Entity C { c int }
SupertypeGroup g [supertype: A, completeness: complete, exclusivity: non_exclusive, strategy: joined] {
B
C [strategy: table_per_class]
}VALID -- several axes on one supertype, and a second level
xdbml: 0.5
Entity Party { party_id int [pk] }
Entity Person { birth_date date }
Entity Organization { legal_form varchar }
Entity Customer { since date }
Entity Supplier { terms varchar }
Entity Employee { hire_date date }
SupertypeGroup legal_nature [supertype: Party, completeness: total, exclusivity: disjoint] {
Person
Organization
}
SupertypeGroup business_role [supertype: Party, completeness: partial, exclusivity: overlapping] {
Customer
Supplier
}
SupertypeGroup person_role [supertype: Person] {
Employee
}VALID -- a relationship names a subtype as an entity-level endpoint
xdbml: 0.5
Entity Party { party_id int [pk] }
Entity Employee { hire_date date }
Entity Assignment {
assignment_id int [pk]
employee_id int [not null]
}
SupertypeGroup g [supertype: Party] {
Employee
}
Ref assigned: Assignment.employee_id > Employee [source: '0..*', target: '1..1']INVALID -- group without a name (parse error)
xdbml: 0.5
Entity A { id int [pk] }
Entity B { b int }
SupertypeGroup [supertype: A] {
B
}INVALID -- an entity listed as a subtype in two groups (subtype-in-multiple-groups)
xdbml: 0.5
Entity Party { party_id int [pk] }
Entity Worker { worker_id int [pk] }
Entity Person { birth_date date }
SupertypeGroup legal_nature [supertype: Party] {
Person
}
SupertypeGroup workforce [supertype: Worker] {
Person
}INVALID -- a subtype redeclares a supertype attribute (supertype-attribute-redeclared)
xdbml: 0.5
Entity Party {
party_id int [pk]
name varchar
}
Entity Person {
name varchar
}
SupertypeGroup legal_nature [supertype: Party] {
Person
}INVALID -- discriminator on an overlapping group (discriminator-on-overlapping-group)
xdbml: 0.5
Entity Party { party_id int [pk] }
Entity Customer { since date }
Entity Supplier { terms varchar }
SupertypeGroup business_role [supertype: Party, exclusivity: overlapping, discriminator: role] {
Customer
Supplier
}INVALID -- a newer version than the parser supports (unsupported-version)
xdbml: 0.8
Entity A { id int [pk] }§10 Constraints -- keys and checks (v0.6)
VALID -- named composite primary key, composite unique key, quoted checks
xdbml: 0.6
Table pitstops {
raceid int
driverid int
stop int
lap int
constraints {
(raceid, driverid, stop) [pk, name: 'pk_pitstops']
(raceid, driverid, lap) [unique, name: 'uk_pitstops_lap']
'stop >= 1' [name: 'chk_pitstops_stop']
`lap IN (1, 2)`
}
}VALID -- a unique key on a nested field
xdbml: 0.6
Collection profiles {
_id objectId [pk]
identity object {
driverref string
}
constraints {
identity.driverref [unique, name: 'uk_profiles_driverref']
}
}VALID -- a field named constraints
xdbml: 0.6
Table rules {
id int [pk]
constraints varchar
}VALID -- composite foreign key referencing a unique key
xdbml: 0.6
Table results {
resultid int [pk]
raceid int
driverid int
constraints {
(raceid, driverid) [unique]
}
}
Table pitstops {
raceid int
driverid int
}
Ref: pitstops.(raceid, driverid) > results.(driverid, raceid)INVALID -- key line with neither pk nor unique (invalid-key-flags)
xdbml: 0.6
Table t {
id int
constraints {
id [name: 'k']
}
}INVALID -- key path crossing an array (key-path-crosses-collection)
xdbml: 0.6
Table t {
id int [pk]
tags array [object {
code varchar
}]
constraints {
tags.code [unique]
}
}INVALID -- second primary key (duplicate-primary-key)
xdbml: 0.6
Table t {
id int [pk]
code int
constraints {
code [pk]
}
}INVALID -- null on a primary key field (null-in-primary-key)
xdbml: 0.6
Table t {
id int [pk, null]
}INVALID -- relationship to a field that is not a key (ref-target-not-key)
xdbml: 0.6
Table customers {
id int [pk]
email varchar
}
Table orders {
customer_email varchar
}
Ref: orders.customer_email > customers.emailINVALID -- constraints block in a v0.5 document (construct-requires-version)
xdbml: 0.5
Table t {
id int
constraints {
id [pk]
}
}§3.9 List bodies (v0.6.1)
VALID -- Enum values separated by commas, as AI assistants often write them
Enum service_status {
'scheduled' [note: 'Appointment booked'],
'in_progress' [note: 'Currently being serviced'],
'on_hold' [note: 'Paused, awaiting parts or decision'],
'cancelled' [note: 'Cancelled by customer or shop']
}VALID -- fields on one line, commas and semicolons, a trailing separator
xdbml: 0.6
Entity service_visits { id int [pk], status service_status; visited_at timestamp, }
Enum service_status { scheduled, in_progress, completed }VALID -- separators in constraints, object, oneOf and View bodies
xdbml: 0.6
Entity payments {
id int,
amount decimal(12,2),
method oneOf {
card object { last4 varchar, brand varchar },
cash object { change_given decimal(12,2) },
} [discriminator: kind],
constraints { (id) [pk], 'amount > 0' },
}
View large_payments {
source_query: 'SELECT id, amount FROM payments WHERE amount > 1000',
id int,
amount decimal(12,2),
}INVALID -- a comma between index entries
xdbml: 0.6
Entity people {
id int [pk]
email varchar
name varchar
indexes {
email, name
}
}Expected error: a comma between index entries is not accepted; a composite index is written (email, name).
INVALID -- a separator inside a field declaration
xdbml: 0.6
Entity people { id, int }§3.10 Keywords and field names (v0.6.1)
VALID -- fields named note, records, indexes and checks beside a table note and an index block
Table appointments {
id int [pk]
note varchar
records int
indexes varchar
checks varchar
Note: 'One row per booked appointment'
indexes {
note
}
}VALID -- a View field named source_query
xdbml: 0.6
View query_log {
source_query: 'SELECT id, source_query FROM query_history'
id int
source_query varchar
}§4 Version declaration with a patch number (v0.6.1)
VALID -- xdbml: 0.6.1
xdbml: 0.6.1
Entity A { id int [pk] }INVALID -- a patch release newer than the parser supports (unsupported-version)
xdbml: 0.7.99
Entity A { id int [pk] }§14 View settings and source query (v0.6.1)
VALID -- settings in the brackets, the source query in the body
xdbml: 0.6
View monthly_revenue [materialized: true, refresh_schedule: 'daily'] {
source_query: 'SELECT month, SUM(total) AS revenue FROM orders GROUP BY month'
month date [pk]
revenue decimal(15,2)
}INVALID -- a setting written in the body
xdbml: 0.6
View monthly_revenue {
materialized: true
month date [pk]
}Expected error: materialized is a setting and goes in the brackets after the View name.
VALID with a warning -- source_query in the brackets (source-query-in-settings)
xdbml: 0.6
View active_customers [source_query: 'SELECT id FROM customers'] {
id int [pk]
}The bracketed query is not the view's source query.
VALID with a warning -- a second source query (duplicate-source-query)
xdbml: 0.6
View active_customers {
source_query: 'SELECT id FROM customers'
source_query: 'SELECT id FROM clients'
id int [pk]
}The first source_query: is the view's source query.
§10.3 A key declared twice (v0.6.1)
INVALID -- a primary key written inline and restated in constraints (duplicate-primary-key)
xdbml: 0.6
Table customers {
customer_id int [pk]
constraints {
(customer_id) [pk]
}
}VALID with a warning -- a unique key written inline and restated in constraints (duplicate-unique-key)
xdbml: 0.6
Table customers {
customer_id int [pk]
tax_id varchar(50) [unique]
constraints {
tax_id [unique, name: 'uk_customers_tax_id']
}
}v0.6.2 DBML forms and spec rules
VALID -- an unquoted color, as DBML writes it (§3.3)
xdbml: 0.6
Table customers [headercolor: #3498DB] {
id int [pk]
}VALID -- a relationship names an entity by its alias (§7.4)
xdbml: 0.6
Table very_long_customer_table as C {
id int [pk]
}
Table orders {
id int [pk]
customer_id int [ref: > C.id]
}VALID -- target array types keep their brackets (§8.1)
xdbml: 0.6
Table posts {
id int [pk]
tags text[]
refs varchar(20)[]
}INVALID -- a Container without a target in a Project with several (container-target-missing, §5.2)
xdbml: 0.6
Project fleet {
targets: [PostgreSQL, MongoDB]
}
Schema core {
Table vehicles { id int [pk] }
}INVALID -- a Container target the Project does not list (container-target-not-in-project, §5.2)
xdbml: 0.6
Project fleet {
targets: [PostgreSQL]
}
Schema core [target: Oracle] {
Table vehicles { id int [pk] }
}INVALID -- a Type and an Entity with one name (name-collision, §15.5)
xdbml: 0.6
Type customers {
a int
}
Table customers {
id int [pk]
}§18 Diagram views (v0.6.3)
VALID -- Containers narrowed by the entities named beside them (§18.1, §18.2)
xdbml: 0.6
Schema sales {
Table orders { id int [pk] }
Table order_lines { id int [pk] }
Table returns { id int [pk] }
}
Schema billing {
Table invoices { id int [pk] }
}
Schema crm {
Table customers { id int [pk] }
}
DiagramView order_flow {
Containers {
sales
billing
}
Tables {
sales.orders
sales.order_lines
crm.customers
}
}VALID -- the DBML form in a document without a version declaration (§18.5)
Table core.users { id int [pk] }
Table analytics.events { id int [pk] }
DiagramView "Sales team" {
Tables { core.users }
Schemas { analytics }
}
DiagramView everything { * }VALID -- commas and semicolons in category lists (§3.9)
xdbml: 0.6
Table a { id int [pk] }
Table b { id int [pk] }
DiagramView v {
Tables { a, b; }
}INVALID -- an Edges category (§18.1)
xdbml: 0.6
Table a { id int [pk] }
DiagramView v {
Edges { * }
}INVALID -- a DiagramView inside a Container (§18.1)
xdbml: 0.6
Schema sales {
Table orders { id int [pk] }
DiagramView v { Tables { orders } }
}INVALID -- a name that matches nothing (unresolved-diagram-view-name, §18.3)
xdbml: 0.6
Table orders { id int [pk] }
DiagramView v {
Tables { order }
}INVALID -- an unqualified name held by two Containers (ambiguous-diagram-view-name, §18.3)
xdbml: 0.6
Schema a { Table orders { id int [pk] } }
Schema b { Table orders { id int [pk] } }
DiagramView v {
Tables { orders }
}INVALID -- a database view under Tables (diagram-view-wrong-category, §18.3)
xdbml: 0.6
Table orders { id int [pk] }
View revenue [materialized: true] {
source_query: 'SELECT 1 AS total'
total int
}
DiagramView v {
Tables { revenue }
}INVALID -- Schemas and Containers in one diagram view (duplicate-diagram-view-category, §18.1)
xdbml: 0.6
Schema sales { Table orders { id int [pk] } }
DiagramView v {
Schemas { sales }
Containers { sales }
}VALID with a warning -- a category written twice without a version declaration (duplicate-diagram-view-category, §18.6)
Table a { id int [pk] }
Table b { id int [pk] }
DiagramView v {
Tables { a }
Tables { b }
}INVALID -- two diagram views with one name (duplicate-diagram-view, §18.1)
xdbml: 0.6
Table a { id int [pk] }
DiagramView v { Tables { a } }
DiagramView v { Tables { * } }VALID -- a note in the brackets, a note in the body, and a custom property (§18.1)
xdbml: 0.6
Table orders { id int [pk] }
DiagramView ordering [note: 'Orders only', x_owner: 'sales-ops'] {
Tables { orders }
}
DiagramView ordering_too {
Note: 'Orders only'
Tables { orders }
}VALID -- any key other than note is a custom property, prefixed or not, as on a TableGroup (§18.1, v0.7.1)
xdbml: 0.6
Table orders { id int [pk] }
DiagramView ordering [owner: 'sales-ops', "x-hackolade-id": 'ordering-4'] {
Tables { orders }
}INVALID -- a note without a version declaration (construct-requires-version, §18.5)
Table orders { id int [pk] }
DiagramView ordering {
Note: 'Orders only'
Tables { orders }
}INVALID -- Containers without a version declaration (construct-requires-version, §18.5)
Table core.users { id int [pk] }
DiagramView v {
Containers { core }
}§15.8 Internal definitions (v0.6.5)
VALID -- internal definitions in an entity, object and scalar forms (§15.8.1)
xdbml: 0.6
Project crm { targets: 'JSON Schema' }
Entity customers {
id string [not null]
billing Address [not null]
contacts array [Contact]
definitions {
Address {
street string [not null]
country CountryCode
}
CountryCode string [pattern: '^[A-Z]{2}$']
Contact [note: 'One way to reach the customer'] {
kind string [not null]
address Address
}
}
}VALID -- a field named definitions beside the block, and commas between entries (§3.9, §3.10)
xdbml: 0.6
Collection settings {
_id objectId [pk]
definitions varchar
theme Theme
definitions { Theme { color string, font string }, Size int }
}VALID -- MongoDB accepts the block; its generator inlines the shapes (§15.8.4, §15.8.5)
xdbml: 0.6
Project shop { targets: MongoDB }
Collection orders {
_id objectId [pk]
shipping Address
definitions {
Address { street string, city string }
}
}VALID with a warning -- an entry named like a Type of the Project (definition-shadows-type, §15.8.2)
xdbml: 0.6
Type Address { line string }
Entity customers {
id string [not null]
billing Address
definitions {
Address { street string, city string }
}
}INVALID -- a definitions block for a relational target (definitions-unsupported-target, §15.8.4)
xdbml: 0.6
Project erp { targets: Oracle }
Table customers {
id number(11) [pk]
billing Address
definitions {
Address { street varchar2(100) }
}
}INVALID -- a definitions block for a property graph target (definitions-unsupported-target, §15.8.4)
xdbml: 0.6
Project graph { targets: Neo4j }
Entity Person {
id string [pk]
home Address
definitions {
Address { city string }
}
}INVALID -- a definitions block in a TablePartial (definitions-outside-entity, §15.8.1)
xdbml: 0.6
TablePartial audited {
created Stamp
definitions {
Stamp { at timestamp, by varchar }
}
}INVALID -- a definitions block in a View (§15.8.1)
xdbml: 0.6
View active_customers {
id varchar
definitions {
Address { street varchar }
}
}INVALID -- a second definitions block (duplicate-definitions-block, §15.8.1)
xdbml: 0.6
Entity customers {
billing Address
definitions { Address { street string } }
definitions { Phone string }
}INVALID -- two entries under one name (duplicate-definition, §15.8.2)
xdbml: 0.6
Entity customers {
billing Address
definitions {
Address { street string }
Address string
}
}INVALID -- an entry under the name of a built-in type (named-type-shadows-builtin, §15.8.2)
xdbml: 0.6
Entity customers {
amount money
definitions {
money decimal(10,2)
}
}VALID -- a field imported on its own takes the shape of the definitions it names (§15.8.3)
xdbml: 0.6
reuse { field customers.billing } from './crm'
Entity invoices {
id string [not null]
bill_to billing
}INVALID -- a field imported on its own that reaches a recursive definition (§15.8.3)
xdbml: 0.6
reuse { field customers.root } from './crm'
Entity trees {
id string [not null]
root root
}v0.7.1 -- EntityPartial and EntityGroup, color, x- custom properties
VALID -- EntityPartial and EntityGroup, with TablePartial and TableGroup as aliases (§17)
xdbml: 0.7.1
EntityPartial audit [color: '#F1C40F'] {
created_at timestamp
}
TablePartial versioned {
version int
}
Entity orders {
id int [pk]
~audit
~versioned
}
Entity customers {
id int [pk]
}
EntityGroup commerce [color: '#3498DB'] {
orders
}
TableGroup crm {
customers
}VALID -- Entities and EntityGroups in a diagram view (§18.1)
xdbml: 0.7.1
Entity orders { id int [pk] }
Entity customers { id int [pk] }
EntityGroup crm { customers }
DiagramView ordering {
Entities { orders }
EntityGroups { crm }
}INVALID -- Entities and Tables in one diagram view (duplicate-diagram-view-category, §18.1)
xdbml: 0.7.1
Entity orders { id int [pk] }
DiagramView ordering {
Entities { orders }
Tables { orders }
}INVALID -- Entities without a version declaration (construct-requires-version, §18.5)
Table orders { id int [pk] }
DiagramView ordering {
Entities { orders }
}VALID -- a quoted x- custom property on a diagram view, a TableGroup and an entity (§24.5, §18.1)
xdbml: 0.7.1
Table orders ["x-hackolade-id": 'orders-1'] { id int [pk] }
TableGroup billing [color: '#E74C3C', "x-hackolade-id": 'billing-2'] {
orders
}
DiagramView "Customers and Vehicles" ["x-hackolade-id": 'view-3', x_owner: 'ops'] {
Tables { orders }
}VALID -- color sets the header color of an entity, a View and an EntityPartial (§7.5)
xdbml: 0.7.1
Entity orders [color: '#3498DB'] { id int [pk] }
View open_orders [color: '#2ECC71'] { id int }
Metadata Entity orders {
note: 'Orders of the web shop'
}VALID with a warning -- color and headercolor in one settings list (duplicate-setting, §7.5, §24.5)
xdbml: 0.7.1
Entity orders [color: '#3498DB', headercolor: '#E74C3C'] { id int [pk] }INVALID -- color and headercolor in one Metadata block (duplicate-metadata-setting, §24.7.3)
xdbml: 0.7.1
Entity orders { id int [pk] }
Metadata Entity orders {
color: '#3498DB'
headercolor: '#E74C3C'
}VALID -- color on a Table without a version declaration is a custom property, as in DBML (§7.5)
Table orders [color: #3498DB, headercolor: #E74C3C] { id int [pk] }v0.7.2 -- Source-to-target mapping, metrics and grain
VALID -- a source-to-target mapping with its statement (§27.10)
xdbml: 0.7
Container legacy [type: database, target: Oracle] {
Table MBR {
MBR_ID number [pk]
FIRST_NM varchar2(50)
LAST_NM varchar2(50)
STATUS char(1)
CNTRY_CD char(2)
}
Table COUNTRY {
CODE char(2) [pk]
NAME varchar2(80)
}
}
Container dw [type: schema, target: Snowflake] {
Table dim_member [grain: 'One row per member'] {
member_key int [pk, increment]
member_id int [unique]
full_name varchar
country_name varchar
email varchar [note: 'Not available in the source system.']
loaded_at timestamp [default: `CURRENT_TIMESTAMP`]
}
}
Dep load_dim_member [source_database: snowflake] {
legacy.MBR.MBR_ID -> dw.dim_member.member_id [transformation: identity]
legacy.MBR.FIRST_NM, legacy.MBR.LAST_NM -> dw.dim_member.full_name [transformation: calculation]
legacy.COUNTRY.NAME -> dw.dim_member.country_name [transformation: identity]
legacy.MBR.CNTRY_CD, legacy.COUNTRY.CODE -> dw.dim_member [transformation: lookup]
legacy.MBR.STATUS -> dw.dim_member [transformation: filter]
source_query: '''
SELECT m.MBR_ID AS member_id,
TRIM(m.FIRST_NM) || ' ' || TRIM(m.LAST_NM) AS full_name,
c.NAME AS country_name
FROM legacy.MBR m
LEFT JOIN legacy.COUNTRY c ON c.CODE = m.CNTRY_CD
WHERE m.STATUS <> 'X'
'''
Note: 'Initial load, then a daily delta of the members of the legacy system.'
}VALID -- a CASE: calculation of the value, conditional of the field it tests (§27.10.1)
xdbml: 0.7
Container src {
Table payment {
id int [pk]
amount decimal(12, 2)
state char(1)
}
}
Container dw {
Table fct_payment {
id int [pk]
settled_amount decimal(12, 2)
}
}
Dep load_fct_payment [source_database: ansi_sql] {
src.payment.amount -> dw.fct_payment.settled_amount [transformation: calculation]
src.payment.state -> dw.fct_payment.settled_amount [transformation: conditional]
source_query: '''
SELECT CASE WHEN state = 'S' THEN amount END AS settled_amount
FROM src.payment
'''
}VALID -- a Data Vault record source, from the source entity to the field (§27.10.4)
xdbml: 0.7
Container legacy {
Table MBR {
MBR_ID number [pk]
}
}
Container crm {
Table contacts {
member_number int [pk]
}
}
Container dv {
Table hub_member {
member_id int [pk]
REC_SRC varchar
}
}
Dep load_hub_member_legacy {
legacy.MBR.MBR_ID -> dv.hub_member.member_id
legacy.MBR -> dv.hub_member.REC_SRC
source_query: '''
SELECT MBR_ID AS member_id, 'LEGACY' AS REC_SRC FROM legacy.MBR
'''
}
Dep load_hub_member_crm {
crm.contacts.member_number -> dv.hub_member.member_id
crm.contacts -> dv.hub_member.REC_SRC
source_query: '''
SELECT member_number AS member_id, 'CRM' AS REC_SRC FROM crm.contacts
'''
}VALID -- metrics: fields of a View that is not materialized (§27.11)
xdbml: 0.7
Table fct_orders [grain: 'One row per order'] {
order_id int [pk]
customer_id int
revenue decimal(12, 2)
ordered_at date
}
View sales_metrics [source_database: ansi_sql, note: 'Measures of the order process, computed at query time.'] {
source_query: '''
SELECT SUM(revenue) AS total_revenue,
SUM(revenue) / COUNT(DISTINCT order_id) AS average_order_value
FROM fct_orders
'''
total_revenue decimal(18, 2) [synonyms: ['revenue', 'total sales'], note: 'Revenue of the orders, net of refunds.']
average_order_value decimal(12, 2)
}
Dep sales_metrics_lineage {
fct_orders.revenue -> sales_metrics.total_revenue [transformation: aggregation]
fct_orders.revenue, fct_orders.order_id -> sales_metrics.average_order_value [transformation: aggregation]
}VALID -- several upstream ends, with either arrow (§27.2)
xdbml: 0.7
Table stg_customers {
first_name varchar
last_name varchar
nick_name varchar
}
Table dim_customer {
full_name varchar
display_name varchar
}
Dep: stg_customers.first_name, stg_customers.last_name -> dim_customer.full_name
Dep: dim_customer.display_name <- stg_customers.nick_name, stg_customers.first_nameVALID -- a block mixing the entity level and the field level (§27.2)
xdbml: 0.7
Table raw_orders {
amount_usd decimal(12, 2)
}
Table stg_orders {
revenue decimal(12, 2)
}
Dep stg_orders {
raw_orders -> stg_orders
raw_orders.amount_usd -> stg_orders.revenue
}VALID -- values in any casing, and dialect as an alias of source_database (§27.3)
xdbml: 0.7
Table customers {
id int [pk]
country_id int
}
Table countries {
id int [pk]
name varchar
}
Table dim_customer {
id int [pk]
country varchar
}
Dep load_dim_customer [Dialect: ANSI_SQL] {
customers.id -> dim_customer.id [transformation: Identity]
countries.name -> dim_customer.country [transformation: 'IDENTITY']
customers.country_id, countries.id -> dim_customer [transformation: Lookup]
}VALID -- without a version declaration, transformation is a custom property, as in DBML (§27.3)
Table a {
id int
}
Table b {
id int
}
Dep: a -> b [transformation: copy, source_query: 'SELECT id FROM a']VALID -- a copy between two entities (identity, §27.10.1)
xdbml: 0.7
Container crm {
Table contacts {
member_number int [pk]
email varchar
}
}
Container stage {
Table contacts {
member_number int [pk]
email varchar
}
}
Dep replicate_contacts: crm.contacts -> stage.contacts [transformation: identity]VALID -- a role-playing date dimension: one field feeds three fields of a fact (§27.4)
xdbml: 0.7
Table dim_date {
date_key int [pk]
}
Table fct_orders {
order_date_key int
ship_date_key int
delivery_date_key int
}
Dep load_fct_orders {
dim_date.date_key -> fct_orders.order_date_key [transformation: lookup]
dim_date.date_key -> fct_orders.ship_date_key [transformation: lookup]
dim_date.date_key -> fct_orders.delivery_date_key [transformation: lookup]
}VALID -- one field in several roles of one load: the same pair once for each kind (§27.4)
xdbml: 0.7
Table orders {
member_id int
order_dt date
amount decimal(12, 2)
}
Table members {
member_id int [pk]
}
Table fct_daily_sales {
member_id int
sale_date date
total decimal(14, 2)
}
Dep load_fct_daily_sales {
orders.member_id -> fct_daily_sales.member_id [transformation: identity]
orders.order_dt -> fct_daily_sales.sale_date [transformation: identity]
orders.amount -> fct_daily_sales.total [transformation: aggregation]
orders.member_id, members.member_id -> fct_daily_sales [transformation: join]
orders.member_id, orders.order_dt -> fct_daily_sales [transformation: group_by]
}INVALID -- the same pair with the same kind twice (duplicate-dep, §27.4)
xdbml: 0.7
Table a {
x int
}
Table b {
x int
}
Dep load {
a.x -> b [transformation: filter]
a.x -> b [transformation: filter]
}INVALID -- two downstream ends in one dependency (§27.2)
xdbml: 0.7
Table a {
x int
}
Table b {
x int
y int
}
Dep: a.x -> b.x, b.yINVALID -- an unknown value of transformation (unknown-transformation, §27.10.1)
xdbml: 0.7
Table a {
x int
}
Table b {
x int
}
Dep: a.x -> b.x [transformation: copy]INVALID -- a transformation between two entities (transformation-between-entities, §27.10.1)
xdbml: 0.7
Table raw_orders {
id int
}
Table stg_orders {
id int
}
Dep: raw_orders -> stg_orders [transformation: filter]INVALID -- a kind that gives the value of a field, ending at an entity (transformation-target-mismatch, §27.10.1)
xdbml: 0.7
Table a {
first_name varchar
}
Table b {
full_name varchar
}
Dep: a.first_name -> b [transformation: calculation]VALID with a warning -- identity with several upstream ends (transformation-mismatch, §27.10.5)
xdbml: 0.7
Table a {
first_name varchar
last_name varchar
}
Table b {
full_name varchar
}
Dep: a.first_name, a.last_name -> b.full_name [transformation: identity]VALID with a warning -- an indirect kind from a whole entity (indirect-from-entity, §27.10.5)
xdbml: 0.7
Table members {
id int
status char(1)
}
Table dim_member {
id int
}
Dep: members -> dim_member.id [transformation: filter]VALID with a warning -- source_query in the brackets of a Dep (source-query-in-settings, §27.3)
xdbml: 0.7
Table a {
id int
}
Table b {
id int
}
Dep load [source_query: 'SELECT id FROM a'] {
a.id -> b.id
}VALID with a warning -- dialect and source_database in one settings list (duplicate-setting, §24.5)
xdbml: 0.7
Table a {
id int
}
View v [dialect: snowflake, source_database: oracle] {
source_query: 'SELECT id FROM a'
id int
}VALID with a warning -- grain in a Metadata block (metadata-custom-property, §24.7.3)
xdbml: 0.7
Table fct_orders {
order_id int [pk]
}
Metadata Table fct_orders {
grain: 'One row per order'
}v0.7.3 -- calculation
INVALID -- derivation is no kind of transformation (unknown-transformation, §27.10.1)
xdbml: 0.7
Table a {
first_name varchar
last_name varchar
}
Table b {
full_name varchar
}
Dep: a.first_name, a.last_name -> b.full_name [transformation: derivation]v0.7.4 -- types of several words without quotes
VALID with a warning -- a type of several words without quotes reads as the quoted name (unquoted-type-name, §8.1)
xdbml: 0.7
TablePartial Audit {
"Created At" TIMESTAMP WITH TIME ZONE [not null, default: `CURRENT_TIMESTAMP`]
"Updated At" TIMESTAMP WITH TIME ZONE [not null, default: `CURRENT_TIMESTAMP`]
}VALID with a warning -- an even number of words after the first, and parameters on a later word (unquoted-type-name, §8.1)
xdbml: 0.7
Table events {
id int [pk]
created_at TIMESTAMP WITH LOCAL TIME ZONE [not null]
duration INTERVAL DAY(2) TO SECOND(6)
}VALID with a warning -- in a document without a version declaration (unquoted-type-name, §8.1)
Table measures {
id int [pk]
value double precision
}VALID -- the quoted form, which tools write (§8.1)
xdbml: 0.7
Table events {
id int [pk]
created_at "timestamp with time zone" [not null]
value "double precision"
}INVALID -- a type in the brackets of a map takes the quotes (§8.1)
xdbml: 0.7
Table readings {
id int [pk]
values map [string, double precision]
}v0.7.5 -- relationship flags
VALID -- a flag written alone, with true, or with false, on a Ref and on an Edge (§11.9, §13.3)
xdbml: 0.7
Entity Person { id int [pk] }
Entity Phone {
phone_id int [pk]
owner_id int
}
Entity Headset { headset_id int [pk] }
Edge KNOWS [source: Person, target: Person, undirected] { since date }
Edge FOLLOWS [source: Person, target: Person, undirected: false] { since date }
Ref paired_with: Phone - Headset [undirected]
Ref sold_with: Phone - Headset [undirected: true]
Ref owned_by: Phone.owner_id > Person.id [inactive: false, foreign_master: false]VALID -- foreign_master: false on a field needs no inline ref (§11.9, §11.10.2)
xdbml: 0.7
Table orders {
id int [pk]
customer_name varchar [foreign_master: false]
}INVALID -- undirected on an Edge with a value other than true or false (invalid-undirected, §11.9)
xdbml: 0.7
Entity Person { id int [pk] }
Edge KNOWS [source: Person, target: Person, undirected: yes] { since date }INVALID -- inactive with a value other than true or false (invalid-inactive, §11.9)
xdbml: 0.7
Table users { id int [pk] }
Table posts {
id int [pk]
user_id int
}
Ref: posts.user_id > users.id [inactive: 'soon']Test runner
The reference parser runs this corpus in its test suite (parser/test/run-tests.ts, the "grammar test corpus" group, part of npm run check). For each case it parses the code block with grammar/fixtures/ as the directory of the importing file, resolves names, and checks the label: VALID means no parse error and no error diagnostic, VALID with a warning means at least one warning and no error, and INVALID means a parse error or at least one error diagnostic. Implementations in other languages can run the same corpus with the same three rules and the same fixtures.