Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
44d4bba
ft(wip): support dep syntax
NQPhuc Jun 10, 2026
68a95ce
ft(wip): support dep ele in model structure
NQPhuc Jun 11, 2026
5be7e07
misc: clean up comment
NQPhuc Jun 16, 2026
cef8c87
Merge branch 'master' into data-dependency
NQPhuc Jun 16, 2026
42f4772
v9.0.0-alpha.0
NQPhuc Jun 16, 2026
e956f12
ft: move duplicate dep check to parser
NQPhuc Jun 18, 2026
266d08a
fix: show exact duplicate dep location
NQPhuc Jun 18, 2026
a5d691b
v9.0.0-alpha.1
NQPhuc Jun 18, 2026
db753e1
Merge branch 'master' into data-dependency
NQPhuc Jun 22, 2026
7886ecd
ft: merge master and support dep color
NQPhuc Jul 1, 2026
29e83a7
v9.0.0-alpha.2
NQPhuc Jul 1, 2026
8a9b11f
ft: support sync dep color and add language services for dep
NQPhuc Jul 2, 2026
a33d523
ft: support jump to definition
NQPhuc Jul 3, 2026
c25a2e9
v9.0.0-alpha.3
NQPhuc Jul 3, 2026
9519dd4
Merge branch 'master' into data-dependency
huydo862003 Jul 9, 2026
612efd1
Merge branch 'master' into data-dependency
huydo862003 Jul 9, 2026
2430f7c
feat: add note transform queries
huydo862003 Jul 10, 2026
7dea09b
feat: syncDep note support, setting utils, simplify inline deps
huydo862003 Jul 10, 2026
a99ca35
v9.0.0-alpha.4
huydo862003 Jul 10, 2026
0dffd2f
fix: case-insensitive search
huydo862003 Jul 10, 2026
d9827b7
fix: rename custom to metadata
huydo862003 Jul 10, 2026
a9e8240
feat: validate dep node settings properly
huydo862003 Jul 10, 2026
422f284
v9.0.0-alpha.5
huydo862003 Jul 10, 2026
4d80b13
feat: dep note/settings validation, transform utils, and magic string…
huydo862003 Jul 10, 2026
38fc782
v9.0.0-alpha.6
huydo862003 Jul 10, 2026
9a3517a
fix: validate self-ref deps
huydo862003 Jul 13, 2026
a4e4566
v9.0.0-alpha.7
huydo862003 Jul 13, 2026
4ad29ae
feat: support updateElementSetting query
huydo862003 Jul 14, 2026
3049d76
v9.0.0-alpha.8
huydo862003 Jul 14, 2026
151dbfb
refactor: updateElementSetting and syncDep
huydo862003 Jul 14, 2026
1982108
v9.0.0-alpha.9
huydo862003 Jul 14, 2026
73ddff6
v9.0.0-alpha.10
huydo862003 Jul 14, 2026
d111a38
fix: undo some breaking changes
huydo862003 Jul 14, 2026
da99890
v9.0.0-alpha.11
huydo862003 Jul 14, 2026
a7f3487
feat: add a variant of updateElementSetting that returns edits
huydo862003 Jul 15, 2026
7c16e9a
feat: improve updateElementSetting
huydo862003 Jul 15, 2026
b6a2cb9
v9.0.0-alpha.12
huydo862003 Jul 15, 2026
2b4e442
fix: properly validate dep settings
huydo862003 Jul 15, 2026
5cc1f4e
Merge branch 'master' into data-dependency
huydo862003 Jul 15, 2026
4b10c24
doc: add comment about table partial columns
huydo862003 Jul 15, 2026
b2788ca
refactor: node referee of table settings
huydo862003 Jul 15, 2026
c4c1e93
fix: bug nodeReferee of inline ref and dep
huydo862003 Jul 15, 2026
b94c9f3
fix: add depIds to normalized model
huydo862003 Jul 15, 2026
ed0f5e9
fix: remove unnecessary any
huydo862003 Jul 15, 2026
209e604
fix: formatDepCustomValue reuse escape string
huydo862003 Jul 15, 2026
9134634
refactor: simplify create view visitor
huydo862003 Jul 15, 2026
1c41bc6
fix: always render Deps DbSection
huydo862003 Jul 15, 2026
265990d
refactor: syncDep
huydo862003 Jul 15, 2026
aad3f58
v9.0.0-alpha.13
huydo862003 Jul 15, 2026
d28e545
feat: validate dep block downstream table constraints and extract pro…
huydo862003 Jul 15, 2026
d78ea32
v9.0.0-alpha.14
huydo862003 Jul 15, 2026
918ee88
refactor: make code more readable
huydo862003 Jul 16, 2026
6b55b7c
v9.0.0-alpha.15
huydo862003 Jul 16, 2026
7fa8ba3
Merge branch 'master' into data-dependency
huydo862003 Jul 16, 2026
18be101
fix: syncDep should match table dep to column dep
huydo862003 Jul 16, 2026
d1ac5ed
v9.0.0-alpha.16
huydo862003 Jul 16, 2026
d8523b7
fix: normalize note content
huydo862003 Jul 16, 2026
d976249
v9.0.0-alpha.17
huydo862003 Jul 16, 2026
4f35e50
refactor: convert config, dbState, dep, depEdge to TypeScript
huydo862003 Jul 16, 2026
75eefe3
fix: validate dep in table header settings
huydo862003 Jul 17, 2026
01352d5
fix: some bugs in data dep
huydo862003 Jul 17, 2026
49e4005
doc: refactor data dep doc
huydo862003 Jul 20, 2026
9dd1154
fix: remove strict checks
huydo862003 Jul 20, 2026
3242dc9
fix: only disallow column self dep
huydo862003 Jul 20, 2026
5493de9
v9.0.0-alpha.18
huydo862003 Jul 20, 2026
89d6610
fix: disallow mixed table and column level in deps
huydo862003 Jul 20, 2026
01691d6
v9.0.0-alpha.19
huydo862003 Jul 20, 2026
9ce12f8
fix: allow self-loop dep on table-level in dbml-core
huydo862003 Jul 21, 2026
f30be2c
v9.0.0-alpha.20
huydo862003 Jul 21, 2026
566fe5a
Merge branch 'master' into data-dependency
huydo862003 Jul 21, 2026
d539b02
test: trailing newlines
huydo862003 Jul 21, 2026
1cb761a
doc: update llms.txt
huydo862003 Jul 23, 2026
abb53ab
ft: support table to column dep.
NQPhuc Jul 24, 2026
a615886
v9.0.0-alpha.21
NQPhuc Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions dbml-homepage/docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ This part covers all constructs that define database structure and map directly
- [TablePartial](#tablepartial)
- [Data Sample](#data-sample)
- [Data Types](#data-types)
- [Data Lineage](#data-lineage)

## Project Definition

Expand Down Expand Up @@ -534,3 +535,68 @@ records users(id, name, age, status, created_at) {
3, 'Charlie', , Status.pending, '2024-01-15'
}
```

## Data Lineage

`Dep` lets you describe **data dependency** among tables and their columns. It allows you to model: Which tables (or columns) this table (or column) is computed from? Think of it like a SQL view where the view is computed from one or more source tables (or other views).

A **dependency** syntax consists of 3 parts:
- The **upstream** endpoint: The source table (or column) that data come from
- The **downstream** endpoint: The destination table (or column) where the source data are processed and computed to derive a new value
- An arrow (`<-` or `->`) pointing from the **upstream** endpoint to the **downstream** endpoint

A **dependency** can be categorized into one of the two types:
- Table-level dependency: Both the upstream endpoint and the downstream endpoint are tables.
- Column-level dependency: Both the upstream endpoint and the downstream endpoint are columns.

Note that both sides of an edge must be at the same level (table-to-table or column-to-column).

```text
/* Short form — separate from the table or column*/

// `raw_orders` is the upstream table endpoint
// `stg_orders` is the downstream table endpoint
// `->` and `<-` always point from the upstream to the downstream
Dep: raw_orders -> stg_orders
Dep: stg_orders <- raw_orders

// Column-level dependency
Dep: raw_orders.amount -> stg_orders.revenue // column-level

/* Short form — on a table header or column */
Table fct_orders [dep: <- stg_orders] {
id int
revenue decimal [dep: <- stg_orders.amount]
}
```

### Dependency Block

When a table is produced by a specific transformation step (e.g. a dbt model, a SQL view, or an ETL job), you can express this transformation using a dependency block:

```
/* Block form — group edges for a transformation step */
Dep order_staging [color: #79AD51] {
raw_orders -> stg_orders
raw_payments -> stg_orders
raw_orders.amount -> stg_orders.revenue

note: 'Join orders with payments, compute revenue'
materialized: table
query: '''
Transformation query
'''
owner: 'data-team'
}
```

Block settings:

- `note`: description of the transformation. Supports [multi-line strings](./syntax/language-basics.md#multi-line-string).
- `color`: lineage line color. See [Colors](./syntax/enrichment-visualization.md#colors).
- Custom keys (e.g. `materialized`, `owner`) are preserved in the output.

:::note
- All edges in a block must target the **same downstream table**.
- Each directed edge must be unique. Reversed pairs and different levels are considered distinct.
:::
2 changes: 1 addition & 1 deletion dbml-homepage/static/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For the dbdiagram.io web app (diagrams, collaboration, API), see [dbdiagram docs
## Language and reference

- [Home](https://dbml.dbdiagram.io/home): Overview, ecosystem, and links to tools.
- [Core database markup](https://dbml.dbdiagram.io/docs): Tables, columns, relationships, indexes, enums, and other core syntax.
- [Core database markup](https://dbml.dbdiagram.io/docs): Tables, columns, relationships (including optional and inactive refs), indexes, enums, records (sample data), data dependencies (Dep), and other core syntax.
- [Enrichment and visualization](https://dbml.dbdiagram.io/syntax/enrichment-visualization): Notes, labels, colors, and display-oriented syntax like table groups, diagram views.
- [Language basics](https://dbml.dbdiagram.io/syntax/language-basics): Core language constructs (strings, comments, and syntax conventions).

Expand Down
6 changes: 3 additions & 3 deletions dbml-playground/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dbml/playground",
"version": "8.4.0-alpha.1",
"version": "9.0.0-alpha.21",
"description": "Interactive playground for debugging and visualizing the DBML parser pipeline",
"author": "Holistics <dev@holistics.io>",
"license": "Apache-2.0",
Expand All @@ -25,8 +25,8 @@
"format": "prettier --write src/"
},
"dependencies": {
"@dbml/core": "^8.4.0-alpha.1",
"@dbml/parse": "^8.4.0-alpha.1",
"@dbml/core": "^9.0.0-alpha.21",
"@dbml/parse": "^9.0.0-alpha.21",
"@phosphor-icons/vue": "^2.2.0",
"floating-vue": "^5.2.2",
"lodash-es": "^4.17.21",
Expand Down
44 changes: 43 additions & 1 deletion dbml-playground/src/components/panes/output/tabs/DatabaseTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,39 @@
</div>
</DbSection>

<!-- Deps -->
<DbSection
label="Deps"
:count="database.deps.length ?? 0"
:icon="PhArrowRight"
icon-color="text-orange-500"
>
<template
v-for="(dep, di) in database.deps"
:key="di"
>
<div
v-for="(edge, ei) in dep.edges"
:key="`${di}-${ei}`"
class="flex items-center gap-2 py-1 border-b border-gray-50 hover:bg-blue-50"
:style="{ paddingLeft: '20px', paddingRight: '12px' }"
>
<VTooltip
placement="right"
:distance="6"
>
<PhArrowRight class="w-3.5 h-3.5 text-orange-500 flex-shrink-0" />
<template #popper>
<span class="text-xs">Dep</span>
</template>
</VTooltip>
<span class="text-blue-500">{{ depEndpointLabel(edge.upstream) }}</span>
<span class="text-gray-400">→</span>
<span class="text-blue-500">{{ depEndpointLabel(edge.downstream) }}</span>
</div>
</template>
</DbSection>

<!-- Enums -->
<DbSection
label="Enums"
Expand Down Expand Up @@ -541,6 +574,7 @@ import {
PhListBullets,
PhArrowsLeftRight,
PhArrowsDownUp,
PhArrowRight,
PhTextAa,
PhNumberSquareOne,
PhFolder,
Expand All @@ -557,6 +591,7 @@ import TabSettingsButton from './common/TabSettingsButton.vue';
import type { Database } from '@dbml/parse';

type RefEndpoint = Database['refs'][number]['endpoints'][number];
type DepEndpoint = NonNullable<Database['deps']>[number]['edges'][number]['upstream'];
type IndexEntry = Database['tables'][number]['indexes'][number];

import DbSection from './common/DbSection.vue';
Expand Down Expand Up @@ -594,7 +629,7 @@ const totalCount = computed(() => {
const db = database;
if (!db) return 0;
const indexCount = db.tables.reduce((n, t) => n + t.indexes.length, 0);
return db.tables.length + indexCount + db.refs.length + db.enums.length
return db.tables.length + indexCount + db.refs.length + (db.deps?.length ?? 0) + db.enums.length
+ db.tableGroups.length + (db.records?.length ?? 0) + (db.tablePartials?.length ?? 0)
+ (db.notes?.length ?? 0) + (db.diagramViews?.length ?? 0) + externalsCount.value;
});
Expand Down Expand Up @@ -720,4 +755,11 @@ function endpointLabel (ep: RefEndpoint): string {
const fields = ep.fieldNames.length === 1 ? ep.fieldNames[0] : `(${ep.fieldNames.join(', ')})`;
return ep.schemaName ? `${ep.schemaName}.${ep.tableName}.${fields}` : `${ep.tableName}.${fields}`;
}

function depEndpointLabel (ep: DepEndpoint): string {
const base = ep.schemaName ? `${ep.schemaName}.${ep.tableName}` : ep.tableName;
if (ep.fieldNames.length === 0) return base;
const fields = ep.fieldNames.length === 1 ? ep.fieldNames[0] : `(${ep.fieldNames.join(', ')})`;
return `${base}.${fields}`;
}
</script>
50 changes: 50 additions & 0 deletions dbml-playground/src/services/sample-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,62 @@ export interface SampleCategory {
readonly content: string;
}

export const DATA_LINEAGE_SAMPLE_CONTENT = `Table raw_orders {
id int [pk]
user_id int
amount decimal
created_at timestamp
}

Table stg_orders {
id int [pk]
user_id int
amount decimal
}

Table fct_orders {
id int [pk]
user_id int
revenue decimal
}

// Short form
Dep: raw_orders -> stg_orders

// Long form with custom attrs
Dep {
stg_orders -> fct_orders

note: 'Aggregate staging orders into facts'
materialized: table
owner: 'data-team'
}

// Reverse direction (sugar — same edge as stg_orders -> fct_orders)
Dep: fct_orders <- stg_orders

// Column-level
Dep {
stg_orders.amount -> fct_orders.revenue
}

// Inline on table header
Table mart_orders [dep: <- fct_orders] {
id int [pk]
total decimal
}`;

export const SAMPLE_CATEGORIES: readonly SampleCategory[] = [
{
name: 'Basic Example',
description: 'Simple tables with relationships',
content: DEFAULT_SAMPLE_CONTENT,
},
{
name: 'Data Lineage',
description: 'Dep blocks (data flow) — short, long, reverse, column-level, inline',
content: DATA_LINEAGE_SAMPLE_CONTENT,
},
{
name: 'E-commerce Schema',
description: 'Complete e-commerce database with users, products, and orders',
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "8.4.0-alpha.1",
"version": "9.0.0-alpha.21",
"npmClient": "yarn",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
8 changes: 4 additions & 4 deletions packages/dbml-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "@dbml/cli",
"version": "8.4.0-alpha.1",
"version": "9.0.0-alpha.21",
"description": "",
"main": "lib/index.js",
"license": "Apache-2.0",
Expand Down Expand Up @@ -32,9 +32,9 @@
],
"dependencies": {
"@babel/cli": "^7.21.0",
"@dbml/connector": "^8.4.0-alpha.1",
"@dbml/core": "^8.4.0-alpha.1",
"@dbml/parse": "^8.4.0-alpha.1",
"@dbml/connector": "^9.0.0-alpha.21",
"@dbml/core": "^9.0.0-alpha.21",
"@dbml/parse": "^9.0.0-alpha.21",
"bluebird": "^3.5.5",
"chalk": "^2.4.2",
"commander": "^2.20.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/dbml-connector/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package",
"name": "@dbml/connector",
"version": "8.4.0-alpha.1",
"version": "9.0.0-alpha.21",
"description": "This package was created to fetch the schema JSON from many kind of databases.",
"author": "huy.phung.sw@gmail.com",
"license": "MIT",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"tables": [
{
"name": "raw_orders",
"fields": [
{ "name": "id", "type": { "type_name": "int" }, "pk": true }
]
},
{
"name": "stg_orders",
"fields": [
{ "name": "id", "type": { "type_name": "int" }, "pk": true }
]
},
{
"name": "fct_orders",
"fields": [
{ "name": "id", "type": { "type_name": "int" }, "pk": true },
{ "name": "amount", "type": { "type_name": "decimal" } }
]
}
],
"refs": [],
"enums": [],
"tableGroups": [],
"notes": [],
"records": [],
"tablePartials": [],
"deps": [
{
"schemaName": "public",
"edges": [
{ "upstream": { "tableName": "raw_orders", "fieldNames": [] }, "downstream": { "tableName": "stg_orders", "fieldNames": [] } }
]
},
{
"schemaName": "public",
"note": { "value": "Aggregate staging into facts" },
"metadata": { "materialized": "table", "owner": "data-team", "priority": 1 },
"edges": [
{ "upstream": { "tableName": "stg_orders", "fieldNames": [] }, "downstream": { "tableName": "fct_orders", "fieldNames": [] } },
{ "upstream": { "tableName": "stg_orders", "fieldNames": ["id"] }, "downstream": { "tableName": "fct_orders", "fieldNames": ["amount"] } }
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Table "raw_orders" {
"id" int [pk]
}

Table "stg_orders" {
"id" int [pk]
}

Table "fct_orders" {
"id" int [pk]
"amount" decimal
}

Dep: "raw_orders" -> "stg_orders"

Dep {
"stg_orders" -> "fct_orders"
"stg_orders"."id" -> "fct_orders"."amount"

note: 'Aggregate staging into facts'
materialized: 'table'
owner: 'data-team'
priority: 1
}
43 changes: 43 additions & 0 deletions packages/dbml-core/__tests__/examples/model_structure/dep.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"schemas": [],
"aliases": [],
"project": { "database_type": "Lineage", "name": "lineage_test" },
"tables": [
{ "name": "raw_orders", "schemaName": "public", "fields": [{ "name": "id", "type": { "type_name": "int" }, "pk": true }] },
{ "name": "stg_orders", "schemaName": "public", "fields": [{ "name": "id", "type": { "type_name": "int" }, "pk": true }] },
{ "name": "fct_orders", "schemaName": "public", "fields": [{ "name": "id", "type": { "type_name": "int" }, "pk": true }, { "name": "amount", "type": { "type_name": "decimal" } }] },
{ "name": "events", "schemaName": "analytics", "fields": [{ "name": "id", "type": { "type_name": "int" }, "pk": true }, { "name": "ts", "type": { "type_name": "timestamp" } }] }
],
"refs": [],
"enums": [],
"tableGroups": [],
"notes": [],
"records": [],
"tablePartials": [],
"deps": [
{
"name": null,
"schemaName": "public",
"edges": [
{ "upstream": { "schemaName": null, "tableName": "raw_orders", "fieldNames": [] }, "downstream": { "schemaName": null, "tableName": "stg_orders", "fieldNames": [] } }
]
},
{
"name": null,
"schemaName": "public",
"note": { "value": "Aggregate staging into facts" },
"metadata": { "materialized": "table", "owner": "data-team" },
"edges": [
{ "upstream": { "schemaName": null, "tableName": "stg_orders", "fieldNames": [] }, "downstream": { "schemaName": null, "tableName": "fct_orders", "fieldNames": [] } },
{ "upstream": { "schemaName": null, "tableName": "stg_orders", "fieldNames": ["id"] }, "downstream": { "schemaName": null, "tableName": "fct_orders", "fieldNames": ["amount"] } }
]
},
{
"name": null,
"schemaName": "public",
"edges": [
{ "upstream": { "schemaName": "analytics", "tableName": "events", "fieldNames": ["ts"] }, "downstream": { "schemaName": "public", "tableName": "fct_orders", "fieldNames": ["id"] } }
]
}
]
}
Loading
Loading