drizzle-docs-generator 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +67 -8
- package/README.md +62 -3
- package/dist/adapter/index.d.ts +10 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/types.d.ts +40 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/adapter/v0-adapter.d.ts +73 -0
- package/dist/adapter/v0-adapter.d.ts.map +1 -0
- package/dist/adapter/v0-adapter.js +136 -0
- package/dist/adapter/v0-adapter.js.map +1 -0
- package/dist/adapter/v1-adapter.d.ts +40 -0
- package/dist/adapter/v1-adapter.d.ts.map +1 -0
- package/dist/adapter/v1-adapter.js +83 -0
- package/dist/adapter/v1-adapter.js.map +1 -0
- package/dist/cli/index.js +213 -40
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/integration-test-utils.d.ts +19 -0
- package/dist/cli/integration-test-utils.d.ts.map +1 -0
- package/dist/formatter/dbml-builder.d.ts +29 -0
- package/dist/formatter/dbml-builder.d.ts.map +1 -0
- package/dist/formatter/dbml-builder.js +39 -0
- package/dist/formatter/dbml-builder.js.map +1 -0
- package/dist/formatter/dbml.d.ts +81 -0
- package/dist/formatter/dbml.d.ts.map +1 -0
- package/dist/formatter/dbml.js +163 -0
- package/dist/formatter/dbml.js.map +1 -0
- package/dist/formatter/index.d.ts +7 -0
- package/dist/formatter/index.d.ts.map +1 -0
- package/dist/formatter/markdown.d.ts +125 -0
- package/dist/formatter/markdown.d.ts.map +1 -0
- package/dist/formatter/markdown.js +235 -0
- package/dist/formatter/markdown.js.map +1 -0
- package/dist/formatter/mermaid.d.ts +102 -0
- package/dist/formatter/mermaid.d.ts.map +1 -0
- package/dist/formatter/mermaid.js +177 -0
- package/dist/formatter/mermaid.js.map +1 -0
- package/dist/formatter/types.d.ts +37 -0
- package/dist/formatter/types.d.ts.map +1 -0
- package/dist/generator/common.d.ts +109 -211
- package/dist/generator/common.d.ts.map +1 -1
- package/dist/generator/common.js +252 -481
- package/dist/generator/common.js.map +1 -1
- package/dist/generator/index.d.ts +2 -1
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/mysql.js +3 -3
- package/dist/generator/pg.d.ts +8 -7
- package/dist/generator/pg.d.ts.map +1 -1
- package/dist/generator/pg.js +29 -31
- package/dist/generator/pg.js.map +1 -1
- package/dist/generator/sqlite.js +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -9
- package/dist/index.js.map +1 -1
- package/dist/test-utils/cli-runner.d.ts +4 -0
- package/dist/test-utils/cli-runner.d.ts.map +1 -1
- package/dist/test-utils/dbml-validator.d.ts +37 -0
- package/dist/test-utils/dbml-validator.d.ts.map +1 -1
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/generator/common.js
CHANGED
|
@@ -1,47 +1,15 @@
|
|
|
1
|
-
import { is as
|
|
2
|
-
import { PgTable as
|
|
3
|
-
import { MySqlTable as
|
|
4
|
-
import { SQLiteTable as
|
|
5
|
-
import { mkdirSync as
|
|
6
|
-
import { resolve as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* Increase the indentation level by one
|
|
14
|
-
* @returns This instance for method chaining
|
|
15
|
-
*/
|
|
16
|
-
indent() {
|
|
17
|
-
return this.indentLevel++, this;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Decrease the indentation level by one (minimum 0)
|
|
21
|
-
* @returns This instance for method chaining
|
|
22
|
-
*/
|
|
23
|
-
dedent() {
|
|
24
|
-
return this.indentLevel = Math.max(0, this.indentLevel - 1), this;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Add a line with the current indentation level
|
|
28
|
-
* @param content - The content to add (empty string adds a blank line)
|
|
29
|
-
* @returns This instance for method chaining
|
|
30
|
-
*/
|
|
31
|
-
line(e = "") {
|
|
32
|
-
const t = " ".repeat(this.indentLevel);
|
|
33
|
-
return this.lines.push(e ? `${t}${e}` : ""), this;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Build the final DBML string from all added lines
|
|
37
|
-
* @returns The complete DBML content as a string
|
|
38
|
-
*/
|
|
39
|
-
build() {
|
|
40
|
-
return this.lines.join(`
|
|
41
|
-
`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
class B {
|
|
1
|
+
import { is as r, Relation as h, getTableName as m, getTableColumns as y } from "drizzle-orm";
|
|
2
|
+
import { PgTable as c, getTableConfig as b } from "drizzle-orm/pg-core";
|
|
3
|
+
import { MySqlTable as f, getTableConfig as T } from "drizzle-orm/mysql-core";
|
|
4
|
+
import { SQLiteTable as u, getTableConfig as d } from "drizzle-orm/sqlite-core";
|
|
5
|
+
import { mkdirSync as C, writeFileSync as D } from "node:fs";
|
|
6
|
+
import { resolve as R, dirname as q } from "node:path";
|
|
7
|
+
import { DbmlFormatter as j } from "../formatter/dbml.js";
|
|
8
|
+
import { extractComments as v } from "../parser/comments.js";
|
|
9
|
+
import { extractRelations as x } from "../parser/relations.js";
|
|
10
|
+
import { V0RelationAdapter as K } from "../adapter/v0-adapter.js";
|
|
11
|
+
import { V1RelationAdapter as V } from "../adapter/v1-adapter.js";
|
|
12
|
+
class N {
|
|
45
13
|
schema;
|
|
46
14
|
relational;
|
|
47
15
|
generatedRefs = [];
|
|
@@ -53,7 +21,7 @@ class B {
|
|
|
53
21
|
* @param options - Configuration options including schema, relational mode, source code, and comments
|
|
54
22
|
*/
|
|
55
23
|
constructor(e) {
|
|
56
|
-
this.schema = e.schema, this.relational = e.relational ?? !1, this.source = e.source, e.comments ? this.comments = e.comments : this.source && (this.comments =
|
|
24
|
+
this.schema = e.schema, this.relational = e.relational ?? !1, this.source = e.source, e.comments ? this.comments = e.comments : this.source && (this.comments = v(this.source)), this.relational && this.source && (this.parsedRelations = x(this.source));
|
|
57
25
|
}
|
|
58
26
|
/**
|
|
59
27
|
* Generate complete DBML output from the schema
|
|
@@ -66,13 +34,8 @@ class B {
|
|
|
66
34
|
* @returns The complete DBML string
|
|
67
35
|
*/
|
|
68
36
|
generate() {
|
|
69
|
-
const e =
|
|
70
|
-
|
|
71
|
-
this.generateTable(e, o), e.line();
|
|
72
|
-
this.relational && (s.length > 0 ? this.generateRelationalRefsFromV1(s) : (n.length > 0 || this.parsedRelations) && this.generateRelationalRefsFromV0());
|
|
73
|
-
for (const o of this.generatedRefs)
|
|
74
|
-
this.generateRef(e, o);
|
|
75
|
-
return e.build().trim();
|
|
37
|
+
const e = this.toIntermediateSchema();
|
|
38
|
+
return new j().format(e);
|
|
76
39
|
}
|
|
77
40
|
/**
|
|
78
41
|
* Get all tables from schema
|
|
@@ -98,32 +61,7 @@ class B {
|
|
|
98
61
|
* @returns True if value is a Drizzle table
|
|
99
62
|
*/
|
|
100
63
|
isTable(e) {
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Get all v0 relations from schema (legacy relations() API)
|
|
105
|
-
*
|
|
106
|
-
* Extracts legacy relations defined using the old relations() API.
|
|
107
|
-
* These are identified by having 'table' and 'config' properties.
|
|
108
|
-
*
|
|
109
|
-
* @returns Array of legacy relation objects
|
|
110
|
-
*/
|
|
111
|
-
getV0Relations() {
|
|
112
|
-
const e = [];
|
|
113
|
-
for (const t of Object.values(this.schema))
|
|
114
|
-
this.isV0Relations(t) && e.push(t);
|
|
115
|
-
return e;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Check if a value is a Drizzle v0 relations object (from relations())
|
|
119
|
-
*
|
|
120
|
-
* Validates the legacy relations() format by checking for 'table' and 'config' properties.
|
|
121
|
-
*
|
|
122
|
-
* @param value - The value to check
|
|
123
|
-
* @returns True if value is a legacy relations object
|
|
124
|
-
*/
|
|
125
|
-
isV0Relations(e) {
|
|
126
|
-
return typeof e != "object" || e === null ? !1 : "table" in e && "config" in e && typeof e.config == "object";
|
|
64
|
+
return r(e, c) || r(e, f) || r(e, u);
|
|
127
65
|
}
|
|
128
66
|
/**
|
|
129
67
|
* Check if a value is a v1 relation entry (from defineRelations())
|
|
@@ -140,8 +78,8 @@ class B {
|
|
|
140
78
|
const t = e;
|
|
141
79
|
if (!("table" in t) || !("name" in t) || typeof t.name != "string" || !("relations" in t) || typeof t.relations != "object" || t.relations === null)
|
|
142
80
|
return !1;
|
|
143
|
-
const n = t.relations,
|
|
144
|
-
return
|
|
81
|
+
const n = t.relations, o = Object.values(n);
|
|
82
|
+
return o.length > 0 ? o.some((s) => r(s, h)) : this.isTable(t.table);
|
|
145
83
|
}
|
|
146
84
|
/**
|
|
147
85
|
* Get all v1 relation entries from schema (defineRelations() API)
|
|
@@ -174,26 +112,7 @@ class B {
|
|
|
174
112
|
if (typeof e != "object" || e === null || Array.isArray(e))
|
|
175
113
|
return !1;
|
|
176
114
|
const n = Object.values(e);
|
|
177
|
-
return n.length > 0 && n.every((
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Generate a table definition in DBML format
|
|
181
|
-
*
|
|
182
|
-
* Creates the complete table definition including columns, indexes, constraints,
|
|
183
|
-
* and table-level comments. Also collects foreign keys if not in relational mode.
|
|
184
|
-
*
|
|
185
|
-
* @param dbml - The DBML builder to add the table to
|
|
186
|
-
* @param table - The Drizzle table to generate
|
|
187
|
-
*/
|
|
188
|
-
generateTable(e, t) {
|
|
189
|
-
const n = g(t), s = d(t), o = this.dialectConfig.escapeName(n);
|
|
190
|
-
e.line(`Table ${o} {`), e.indent();
|
|
191
|
-
for (const a of Object.values(s))
|
|
192
|
-
this.generateColumn(e, a, n);
|
|
193
|
-
const i = this.getTableConfig(t);
|
|
194
|
-
i && this.generateIndexesBlock(e, i);
|
|
195
|
-
const r = this.comments?.tables[n]?.comment;
|
|
196
|
-
r && (e.line(), e.line(`Note: '${$(r)}'`)), e.dedent(), e.line("}"), !this.relational && i && i.foreignKeys.length > 0 && this.collectForeignKeysFromConfig(n, i.foreignKeys);
|
|
115
|
+
return n.length > 0 && n.every((o) => this.isV1RelationEntry(o));
|
|
197
116
|
}
|
|
198
117
|
/**
|
|
199
118
|
* Get table configuration from a Drizzle table
|
|
@@ -205,85 +124,51 @@ class B {
|
|
|
205
124
|
* @returns Table configuration or undefined if dialect is not supported
|
|
206
125
|
*/
|
|
207
126
|
getTableConfig(e) {
|
|
208
|
-
if (
|
|
209
|
-
const t =
|
|
210
|
-
return
|
|
211
|
-
indexes: t.indexes || [],
|
|
212
|
-
primaryKeys: t.primaryKeys || [],
|
|
213
|
-
uniqueConstraints: t.uniqueConstraints || [],
|
|
214
|
-
foreignKeys: t.foreignKeys || []
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
if (m(e, T)) {
|
|
218
|
-
const t = N(e);
|
|
219
|
-
return {
|
|
220
|
-
indexes: t.indexes || [],
|
|
221
|
-
primaryKeys: t.primaryKeys || [],
|
|
222
|
-
uniqueConstraints: t.uniqueConstraints || [],
|
|
223
|
-
foreignKeys: t.foreignKeys || []
|
|
224
|
-
};
|
|
127
|
+
if (r(e, c)) {
|
|
128
|
+
const t = b(e);
|
|
129
|
+
return this.mapTableConfig(t);
|
|
225
130
|
}
|
|
226
|
-
if (
|
|
227
|
-
const t =
|
|
228
|
-
return
|
|
229
|
-
indexes: t.indexes || [],
|
|
230
|
-
primaryKeys: t.primaryKeys || [],
|
|
231
|
-
uniqueConstraints: t.uniqueConstraints || [],
|
|
232
|
-
foreignKeys: t.foreignKeys || []
|
|
233
|
-
};
|
|
131
|
+
if (r(e, f)) {
|
|
132
|
+
const t = T(e);
|
|
133
|
+
return this.mapTableConfig(t);
|
|
234
134
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
*
|
|
239
|
-
* Creates a column line with type and attributes (primary key, not null, unique, etc.)
|
|
240
|
-
* and includes column-level comments if available.
|
|
241
|
-
*
|
|
242
|
-
* @param dbml - The DBML builder to add the column to
|
|
243
|
-
* @param column - The Drizzle column to generate
|
|
244
|
-
* @param tableName - Optional table name for looking up comments
|
|
245
|
-
*/
|
|
246
|
-
generateColumn(e, t, n) {
|
|
247
|
-
const s = this.dialectConfig.escapeName(t.name), o = this.getColumnType(t), i = this.getColumnAttributes(t, n), r = this.formatAttributes(i);
|
|
248
|
-
r ? e.line(`${s} ${o} [${r}]`) : e.line(`${s} ${o}`);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Get the SQL type for a column
|
|
252
|
-
*
|
|
253
|
-
* @param column - The column to get the SQL type from
|
|
254
|
-
* @returns The SQL type string (e.g., "varchar", "integer")
|
|
255
|
-
*/
|
|
256
|
-
getColumnType(e) {
|
|
257
|
-
return e.getSQLType();
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Get column attributes for DBML
|
|
261
|
-
*
|
|
262
|
-
* Extracts attributes like primary key, not null, unique, increment, default value,
|
|
263
|
-
* and note from the column. Uses column metadata and comments if available.
|
|
264
|
-
*
|
|
265
|
-
* @param column - The column to get attributes from
|
|
266
|
-
* @param tableName - Optional table name for looking up comments
|
|
267
|
-
* @returns Array of attribute strings for DBML format
|
|
268
|
-
*/
|
|
269
|
-
getColumnAttributes(e, t) {
|
|
270
|
-
const n = [];
|
|
271
|
-
e.primary && n.push("primary key"), e.notNull && n.push("not null"), e.isUnique && n.push("unique"), this.dialectConfig.isIncrement(e) && n.push("increment");
|
|
272
|
-
const s = this.getDefaultValue(e);
|
|
273
|
-
if (s !== void 0 && n.push(`default: ${s}`), t) {
|
|
274
|
-
const o = this.comments?.tables[t]?.columns[e.name]?.comment;
|
|
275
|
-
o && n.push(`note: '${$(o)}'`);
|
|
135
|
+
if (r(e, u)) {
|
|
136
|
+
const t = d(e);
|
|
137
|
+
return this.mapTableConfig(t);
|
|
276
138
|
}
|
|
277
|
-
return n;
|
|
278
139
|
}
|
|
279
140
|
/**
|
|
280
|
-
*
|
|
141
|
+
* Map Drizzle's internal table config to our typed TableConfig
|
|
281
142
|
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
143
|
+
* Note: Drizzle ORM's columns type is `SQL<unknown> | IndexedColumn` union,
|
|
144
|
+
* so we use `{ name?: string }` and cast to access the name property.
|
|
145
|
+
* This is unavoidable due to Drizzle's internal type structure.
|
|
284
146
|
*/
|
|
285
|
-
|
|
286
|
-
return
|
|
147
|
+
mapTableConfig(e) {
|
|
148
|
+
return {
|
|
149
|
+
indexes: (e.indexes || []).map((t) => ({
|
|
150
|
+
config: {
|
|
151
|
+
columns: t.config.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
|
|
152
|
+
name: t.config.name,
|
|
153
|
+
unique: t.config.unique ?? !1,
|
|
154
|
+
using: t.config.using
|
|
155
|
+
}
|
|
156
|
+
})),
|
|
157
|
+
primaryKeys: (e.primaryKeys || []).map((t) => ({
|
|
158
|
+
columns: t.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
|
|
159
|
+
name: t.name
|
|
160
|
+
})),
|
|
161
|
+
uniqueConstraints: (e.uniqueConstraints || []).map((t) => ({
|
|
162
|
+
columns: t.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
|
|
163
|
+
name: t.name
|
|
164
|
+
})),
|
|
165
|
+
foreignKeys: (e.foreignKeys || []).map((t) => ({
|
|
166
|
+
reference: t.reference,
|
|
167
|
+
name: t.name,
|
|
168
|
+
onDelete: t.onDelete,
|
|
169
|
+
onUpdate: t.onUpdate
|
|
170
|
+
}))
|
|
171
|
+
};
|
|
287
172
|
}
|
|
288
173
|
/**
|
|
289
174
|
* Get the default value for a column
|
|
@@ -303,58 +188,19 @@ class B {
|
|
|
303
188
|
if (t !== void 0) {
|
|
304
189
|
if (typeof t == "object" && t !== null) {
|
|
305
190
|
if ("queryChunks" in t) {
|
|
306
|
-
const n = t.queryChunks,
|
|
307
|
-
for (const
|
|
308
|
-
typeof
|
|
309
|
-
return
|
|
191
|
+
const n = t.queryChunks, o = [];
|
|
192
|
+
for (const s of n)
|
|
193
|
+
typeof s == "string" ? o.push(s) : typeof s == "object" && s !== null && "value" in s && o.push(String(s.value));
|
|
194
|
+
return o.join("");
|
|
310
195
|
}
|
|
311
|
-
return "sql" in t ?
|
|
196
|
+
return "sql" in t ? t.sql : JSON.stringify(t);
|
|
312
197
|
}
|
|
313
198
|
if (typeof t == "string")
|
|
314
|
-
return `'${t.replace(/'/g, "
|
|
199
|
+
return `'${t.replace(/'/g, "''")}'`;
|
|
315
200
|
if (typeof t == "number" || typeof t == "boolean")
|
|
316
201
|
return String(t);
|
|
317
202
|
}
|
|
318
203
|
}
|
|
319
|
-
/**
|
|
320
|
-
* Generate indexes block from table configuration
|
|
321
|
-
*
|
|
322
|
-
* Creates the indexes block containing primary keys, unique constraints,
|
|
323
|
-
* and regular indexes with their respective attributes.
|
|
324
|
-
*
|
|
325
|
-
* @param dbml - The DBML builder to add the indexes block to
|
|
326
|
-
* @param tableConfig - The table configuration containing index information
|
|
327
|
-
*/
|
|
328
|
-
generateIndexesBlock(e, t) {
|
|
329
|
-
const { indexes: n, primaryKeys: s, uniqueConstraints: o } = t;
|
|
330
|
-
if (!(n.length === 0 && s.length === 0 && o.length === 0)) {
|
|
331
|
-
e.line(), e.line("indexes {"), e.indent();
|
|
332
|
-
for (const i of s) {
|
|
333
|
-
const r = this.getPrimaryKeyColumns(i);
|
|
334
|
-
if (r.length > 0) {
|
|
335
|
-
const a = r.map((l) => this.dialectConfig.escapeName(l)).join(", ");
|
|
336
|
-
e.line(`(${a}) [pk]`);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
for (const i of o) {
|
|
340
|
-
const r = this.getUniqueConstraintColumns(i);
|
|
341
|
-
if (r.length > 0) {
|
|
342
|
-
const a = r.map((l) => this.dialectConfig.escapeName(l)).join(", ");
|
|
343
|
-
e.line(`(${a}) [unique]`);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
for (const i of n) {
|
|
347
|
-
const r = this.getIndexColumns(i);
|
|
348
|
-
if (r.length > 0) {
|
|
349
|
-
const a = r.map((h) => this.dialectConfig.escapeName(h)).join(", "), l = [];
|
|
350
|
-
this.isUniqueIndex(i) && l.push("unique");
|
|
351
|
-
const c = l.length > 0 ? ` [${l.join(", ")}]` : "";
|
|
352
|
-
e.line(`(${a})${c}`);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
e.dedent(), e.line("}");
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
204
|
/**
|
|
359
205
|
* Collect foreign keys from table configuration
|
|
360
206
|
*
|
|
@@ -366,8 +212,8 @@ class B {
|
|
|
366
212
|
*/
|
|
367
213
|
collectForeignKeysFromConfig(e, t) {
|
|
368
214
|
for (const n of t) {
|
|
369
|
-
const
|
|
370
|
-
|
|
215
|
+
const o = this.parseForeignKey(e, n);
|
|
216
|
+
this.generatedRefs.push(o);
|
|
371
217
|
}
|
|
372
218
|
}
|
|
373
219
|
/**
|
|
@@ -378,322 +224,247 @@ class B {
|
|
|
378
224
|
*
|
|
379
225
|
* @param tableName - The name of the source table
|
|
380
226
|
* @param fk - The foreign key definition to parse
|
|
381
|
-
* @returns GeneratedRef object
|
|
227
|
+
* @returns GeneratedRef object
|
|
382
228
|
*/
|
|
383
229
|
parseForeignKey(e, t) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
};
|
|
395
|
-
} catch {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
230
|
+
const n = t.reference(), o = n.columns.map((a) => a.name), s = n.foreignColumns.map((a) => a.name), i = m(n.foreignTable);
|
|
231
|
+
return {
|
|
232
|
+
fromTable: e,
|
|
233
|
+
fromColumns: o,
|
|
234
|
+
toTable: i,
|
|
235
|
+
toColumns: s,
|
|
236
|
+
type: ">",
|
|
237
|
+
onDelete: t.onDelete,
|
|
238
|
+
onUpdate: t.onUpdate
|
|
239
|
+
};
|
|
398
240
|
}
|
|
399
241
|
/**
|
|
400
|
-
*
|
|
242
|
+
* Create the appropriate relation adapter based on schema contents
|
|
401
243
|
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
244
|
+
* Detects whether v1 or v0 relations are present and returns the
|
|
245
|
+
* corresponding adapter implementation.
|
|
404
246
|
*
|
|
405
|
-
* @returns
|
|
247
|
+
* @returns RelationAdapter instance (V1RelationAdapter or V0RelationAdapter)
|
|
406
248
|
*/
|
|
407
|
-
|
|
408
|
-
const e =
|
|
409
|
-
|
|
410
|
-
if (this.isTable(n)) {
|
|
411
|
-
const s = g(n);
|
|
412
|
-
e.set(t, s);
|
|
413
|
-
}
|
|
414
|
-
return e;
|
|
249
|
+
createRelationAdapter() {
|
|
250
|
+
const e = this.getV1RelationEntries();
|
|
251
|
+
return e.length > 0 ? new V(e) : new K(this.schema, this.parsedRelations);
|
|
415
252
|
}
|
|
416
253
|
/**
|
|
417
|
-
*
|
|
254
|
+
* Convert a UnifiedRelation to a RelationDefinition
|
|
418
255
|
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
256
|
+
* Maps the unified relation format from adapters to the intermediate
|
|
257
|
+
* schema's RelationDefinition format.
|
|
421
258
|
*
|
|
422
|
-
* @param
|
|
423
|
-
* @returns
|
|
259
|
+
* @param unified - The unified relation from adapter
|
|
260
|
+
* @returns RelationDefinition for intermediate schema
|
|
424
261
|
*/
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
262
|
+
unifiedRelationToDefinition(e) {
|
|
263
|
+
return {
|
|
264
|
+
fromTable: e.sourceTable,
|
|
265
|
+
fromColumns: e.sourceColumns,
|
|
266
|
+
toTable: e.targetTable,
|
|
267
|
+
toColumns: e.targetColumns,
|
|
268
|
+
type: e.relationType,
|
|
269
|
+
onDelete: e.onDelete,
|
|
270
|
+
onUpdate: e.onUpdate
|
|
271
|
+
};
|
|
433
272
|
}
|
|
434
273
|
/**
|
|
435
|
-
*
|
|
274
|
+
* Convert the Drizzle schema to an intermediate schema representation
|
|
436
275
|
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
276
|
+
* Creates a database-agnostic intermediate representation that can be
|
|
277
|
+
* used to generate various output formats (DBML, Markdown, JSON, etc.)
|
|
439
278
|
*
|
|
440
|
-
* @
|
|
441
|
-
* @param targetTable - The target table variable name
|
|
442
|
-
* @param sourceFields - The source table's field names
|
|
443
|
-
* @param targetReferences - The target table's reference column names
|
|
444
|
-
* @returns True if a reverse one() relation exists
|
|
279
|
+
* @returns The intermediate schema representation
|
|
445
280
|
*/
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
281
|
+
toIntermediateSchema() {
|
|
282
|
+
const e = this.getTables(), t = this.getDatabaseType(e[0]), n = e.map(
|
|
283
|
+
(i) => this.tableToDefinition(i)
|
|
284
|
+
);
|
|
285
|
+
let o = [];
|
|
286
|
+
if (this.relational)
|
|
287
|
+
o = this.createRelationAdapter().extract().map((l) => this.unifiedRelationToDefinition(l));
|
|
288
|
+
else {
|
|
289
|
+
this.generatedRefs = [];
|
|
290
|
+
for (const i of e) {
|
|
291
|
+
const a = m(i), l = this.getTableConfig(i);
|
|
292
|
+
l && l.foreignKeys.length > 0 && this.collectForeignKeysFromConfig(a, l.foreignKeys);
|
|
453
293
|
}
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Helper to check if two arrays are equal
|
|
458
|
-
*
|
|
459
|
-
* @param a - First array
|
|
460
|
-
* @param b - Second array
|
|
461
|
-
* @returns True if arrays have same length and same elements in order
|
|
462
|
-
*/
|
|
463
|
-
arraysEqual(e, t) {
|
|
464
|
-
return e.length !== t.length ? !1 : e.every((n, s) => n === t[s]);
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Generate references from v0 relations() API
|
|
468
|
-
*
|
|
469
|
-
* Uses TypeScript Compiler API to parse relations() definitions from source file
|
|
470
|
-
* and extract fields/references to generate DBML Ref lines.
|
|
471
|
-
*
|
|
472
|
-
* Detects one-to-one relationships when bidirectional one() relations exist.
|
|
473
|
-
*/
|
|
474
|
-
generateRelationalRefsFromV0() {
|
|
475
|
-
if (!this.parsedRelations || this.parsedRelations.relations.length === 0)
|
|
476
|
-
return;
|
|
477
|
-
const e = this.getTableNameMapping(), t = /* @__PURE__ */ new Set();
|
|
478
|
-
for (const n of this.parsedRelations.relations) {
|
|
479
|
-
if (n.type !== "one" || n.fields.length === 0 || n.references.length === 0)
|
|
480
|
-
continue;
|
|
481
|
-
const s = e.get(n.sourceTable), o = e.get(n.targetTable);
|
|
482
|
-
if (!s || !o)
|
|
483
|
-
continue;
|
|
484
|
-
const i = this.getColumnNameMapping(n.sourceTable), r = this.getColumnNameMapping(n.targetTable), a = n.fields.map(
|
|
485
|
-
(u) => i.get(u) || u
|
|
486
|
-
), l = n.references.map((u) => r.get(u) || u), c = `${s}.${a.join(",")}-${o}.${l.join(",")}`, h = `${o}.${l.join(",")}-${s}.${a.join(",")}`;
|
|
487
|
-
if (t.has(c) || t.has(h))
|
|
488
|
-
continue;
|
|
489
|
-
t.add(c);
|
|
490
|
-
const f = this.hasReverseOneRelation(
|
|
491
|
-
n.sourceTable,
|
|
492
|
-
n.targetTable,
|
|
493
|
-
n.fields,
|
|
494
|
-
n.references
|
|
495
|
-
), p = {
|
|
496
|
-
fromTable: s,
|
|
497
|
-
fromColumns: a,
|
|
498
|
-
toTable: o,
|
|
499
|
-
toColumns: l,
|
|
500
|
-
type: f ? "-" : ">"
|
|
501
|
-
};
|
|
502
|
-
this.generatedRefs.push(p);
|
|
294
|
+
o = this.generatedRefs.map((i) => this.refToRelationDefinition(i));
|
|
503
295
|
}
|
|
296
|
+
const s = this.collectEnumDefinitions();
|
|
297
|
+
return {
|
|
298
|
+
databaseType: t,
|
|
299
|
+
tables: n,
|
|
300
|
+
relations: o,
|
|
301
|
+
enums: s
|
|
302
|
+
};
|
|
504
303
|
}
|
|
505
304
|
/**
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
* Uses official Drizzle v1 types (TableRelationalConfig, Relation, One).
|
|
509
|
-
* Processes One relations to extract foreign key information and generates
|
|
510
|
-
* DBML Ref lines. Detects one-to-one relationships with bidirectional checks.
|
|
305
|
+
* Determine the database type from a Drizzle table
|
|
511
306
|
*
|
|
512
|
-
* @param
|
|
307
|
+
* @param table - The table to check (can be undefined for empty schemas)
|
|
308
|
+
* @returns The database type
|
|
513
309
|
*/
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
for (const n of e) {
|
|
517
|
-
const s = g(n.table);
|
|
518
|
-
for (const o of Object.values(n.relations)) {
|
|
519
|
-
if (!m(o, b) || o.isReversed)
|
|
520
|
-
continue;
|
|
521
|
-
const i = o, r = i.sourceColumns.map((u) => u.name), a = i.targetColumns.map((u) => u.name);
|
|
522
|
-
if (r.length === 0 || a.length === 0)
|
|
523
|
-
continue;
|
|
524
|
-
const l = g(i.targetTable), c = `${s}.${r.join(",")}->${l}.${a.join(",")}`, h = `${l}.${a.join(",")}->${s}.${r.join(",")}`;
|
|
525
|
-
if (t.has(c) || t.has(h))
|
|
526
|
-
continue;
|
|
527
|
-
t.add(c);
|
|
528
|
-
const f = this.hasV1ReverseOneRelation(
|
|
529
|
-
e,
|
|
530
|
-
l,
|
|
531
|
-
s,
|
|
532
|
-
a,
|
|
533
|
-
r
|
|
534
|
-
), p = {
|
|
535
|
-
fromTable: s,
|
|
536
|
-
fromColumns: r,
|
|
537
|
-
toTable: l,
|
|
538
|
-
toColumns: a,
|
|
539
|
-
type: f ? "-" : ">"
|
|
540
|
-
};
|
|
541
|
-
this.generatedRefs.push(p);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
310
|
+
getDatabaseType(e) {
|
|
311
|
+
return !e || r(e, c) ? "postgresql" : r(e, f) ? "mysql" : r(e, u) ? "sqlite" : "postgresql";
|
|
544
312
|
}
|
|
545
313
|
/**
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
* Detects one-to-one relationships by checking if the target table
|
|
549
|
-
* has a matching One relation pointing back to the source table.
|
|
314
|
+
* Convert a Drizzle table to a TableDefinition
|
|
550
315
|
*
|
|
551
|
-
* @param
|
|
552
|
-
* @
|
|
553
|
-
* @param toTableName - The expected target table of the reverse relation
|
|
554
|
-
* @param fromColumns - The expected source columns of the reverse relation
|
|
555
|
-
* @param toColumns - The expected target columns of the reverse relation
|
|
556
|
-
* @returns True if a matching reverse One relation exists
|
|
316
|
+
* @param table - The Drizzle table to convert
|
|
317
|
+
* @returns The table definition
|
|
557
318
|
*/
|
|
558
|
-
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
if (c.length === s.length && h.length === o.length && c.every((f, p) => f === s[p]) && h.every((f, p) => f === o[p]))
|
|
570
|
-
return !0;
|
|
571
|
-
}
|
|
572
|
-
return !1;
|
|
319
|
+
tableToDefinition(e) {
|
|
320
|
+
const t = m(e), n = y(e), o = this.getTableConfig(e), s = Object.values(n).map(
|
|
321
|
+
(g) => this.columnToDefinition(g, t)
|
|
322
|
+
), i = this.extractIndexDefinitions(o), a = this.extractConstraintDefinitions(o), l = this.comments?.tables[t]?.comment;
|
|
323
|
+
return {
|
|
324
|
+
name: t,
|
|
325
|
+
comment: l,
|
|
326
|
+
columns: s,
|
|
327
|
+
indexes: i,
|
|
328
|
+
constraints: a
|
|
329
|
+
};
|
|
573
330
|
}
|
|
574
331
|
/**
|
|
575
|
-
*
|
|
332
|
+
* Convert a Drizzle column to a ColumnDefinition
|
|
576
333
|
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
* @
|
|
580
|
-
* @param relation - The relation object
|
|
581
|
-
* @returns A unique key string for the relation
|
|
334
|
+
* @param column - The Drizzle column to convert
|
|
335
|
+
* @param tableName - The name of the table containing the column
|
|
336
|
+
* @returns The column definition
|
|
582
337
|
*/
|
|
583
|
-
|
|
584
|
-
const n = t
|
|
585
|
-
return
|
|
338
|
+
columnToDefinition(e, t) {
|
|
339
|
+
const n = this.comments?.tables[t]?.columns[e.name]?.comment, o = this.getDefaultValue(e);
|
|
340
|
+
return {
|
|
341
|
+
name: e.name,
|
|
342
|
+
type: e.getSQLType(),
|
|
343
|
+
nullable: !e.notNull,
|
|
344
|
+
defaultValue: o,
|
|
345
|
+
primaryKey: e.primary,
|
|
346
|
+
unique: e.isUnique,
|
|
347
|
+
autoIncrement: this.dialectConfig.isIncrement(e) || void 0,
|
|
348
|
+
comment: n
|
|
349
|
+
};
|
|
586
350
|
}
|
|
587
351
|
/**
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
* Extracts relation information from a legacy relation object and converts
|
|
591
|
-
* it to a GeneratedRef for DBML output.
|
|
352
|
+
* Extract index definitions from table config
|
|
592
353
|
*
|
|
593
|
-
* @param
|
|
594
|
-
* @
|
|
595
|
-
* @returns GeneratedRef object or undefined if parsing fails
|
|
354
|
+
* @param tableConfig - The table configuration
|
|
355
|
+
* @returns Array of index definitions
|
|
596
356
|
*/
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
fromColumns: r,
|
|
610
|
-
toTable: s,
|
|
611
|
-
toColumns: a,
|
|
612
|
-
type: l
|
|
613
|
-
};
|
|
614
|
-
} catch {
|
|
615
|
-
return;
|
|
357
|
+
extractIndexDefinitions(e) {
|
|
358
|
+
if (!e)
|
|
359
|
+
return [];
|
|
360
|
+
const t = [];
|
|
361
|
+
for (const n of e.indexes) {
|
|
362
|
+
const o = n.config.columns.map((s) => s.name);
|
|
363
|
+
o.length > 0 && t.push({
|
|
364
|
+
name: n.config.name || `idx_${o.join("_")}`,
|
|
365
|
+
columns: o,
|
|
366
|
+
unique: n.config.unique,
|
|
367
|
+
type: n.config.using
|
|
368
|
+
});
|
|
616
369
|
}
|
|
370
|
+
return t;
|
|
617
371
|
}
|
|
618
372
|
/**
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
* Creates a Ref line showing the relationship between tables with optional
|
|
622
|
-
* onDelete and onUpdate actions.
|
|
623
|
-
*
|
|
624
|
-
* @param dbml - The DBML builder to add the reference to
|
|
625
|
-
* @param ref - The reference definition to generate
|
|
626
|
-
*/
|
|
627
|
-
generateRef(e, t) {
|
|
628
|
-
const n = `${this.dialectConfig.escapeName(t.fromTable)}.${t.fromColumns.map((r) => this.dialectConfig.escapeName(r)).join(", ")}`, s = `${this.dialectConfig.escapeName(t.toTable)}.${t.toColumns.map((r) => this.dialectConfig.escapeName(r)).join(", ")}`;
|
|
629
|
-
let o = `Ref: ${n} ${t.type} ${s}`;
|
|
630
|
-
const i = [];
|
|
631
|
-
t.onDelete && t.onDelete !== "no action" && i.push(`delete: ${t.onDelete}`), t.onUpdate && t.onUpdate !== "no action" && i.push(`update: ${t.onUpdate}`), i.length > 0 && (o += ` [${i.join(", ")}]`), e.line(o);
|
|
632
|
-
}
|
|
633
|
-
// Helper methods for extracting column information from constraints
|
|
634
|
-
/**
|
|
635
|
-
* Get column names from an index definition
|
|
373
|
+
* Extract constraint definitions from table config
|
|
636
374
|
*
|
|
637
|
-
* @param
|
|
638
|
-
* @returns Array of
|
|
375
|
+
* @param tableConfig - The table configuration
|
|
376
|
+
* @returns Array of constraint definitions
|
|
639
377
|
*/
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
return e.config.columns.map((n) => typeof n == "object" && n !== null && "name" in n ? n.name : "").filter(Boolean);
|
|
643
|
-
} catch {
|
|
378
|
+
extractConstraintDefinitions(e) {
|
|
379
|
+
if (!e)
|
|
644
380
|
return [];
|
|
381
|
+
const t = [];
|
|
382
|
+
for (const n of e.primaryKeys) {
|
|
383
|
+
const o = n.columns.map((s) => s.name);
|
|
384
|
+
o.length > 0 && t.push({
|
|
385
|
+
name: n.name || `pk_${o.join("_")}`,
|
|
386
|
+
type: "primary_key",
|
|
387
|
+
columns: o
|
|
388
|
+
});
|
|
645
389
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
isUniqueIndex(e) {
|
|
654
|
-
try {
|
|
655
|
-
return e.config.unique === !0;
|
|
656
|
-
} catch {
|
|
657
|
-
return !1;
|
|
390
|
+
for (const n of e.uniqueConstraints) {
|
|
391
|
+
const o = n.columns.map((s) => s.name);
|
|
392
|
+
o.length > 0 && t.push({
|
|
393
|
+
name: n.name || `uq_${o.join("_")}`,
|
|
394
|
+
type: "unique",
|
|
395
|
+
columns: o
|
|
396
|
+
});
|
|
658
397
|
}
|
|
398
|
+
for (const n of e.foreignKeys) {
|
|
399
|
+
const o = this.parseForeignKeyForConstraint(n);
|
|
400
|
+
o && t.push(o);
|
|
401
|
+
}
|
|
402
|
+
return t;
|
|
659
403
|
}
|
|
660
404
|
/**
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
* @param
|
|
664
|
-
* @returns
|
|
665
|
-
*/
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
405
|
+
* Parse a foreign key into a ConstraintDefinition
|
|
406
|
+
*
|
|
407
|
+
* @param fk - The foreign key definition
|
|
408
|
+
* @returns ConstraintDefinition
|
|
409
|
+
*/
|
|
410
|
+
parseForeignKeyForConstraint(e) {
|
|
411
|
+
const t = e.reference(), n = t.columns.map((i) => i.name), o = t.foreignColumns.map((i) => i.name), s = m(t.foreignTable);
|
|
412
|
+
return {
|
|
413
|
+
name: e.name || `fk_${n.join("_")}_${s}`,
|
|
414
|
+
type: "foreign_key",
|
|
415
|
+
columns: n,
|
|
416
|
+
referencedTable: s,
|
|
417
|
+
referencedColumns: o
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Convert a GeneratedRef to a RelationDefinition
|
|
422
|
+
*
|
|
423
|
+
* @param ref - The generated reference
|
|
424
|
+
* @returns The relation definition
|
|
425
|
+
*/
|
|
426
|
+
refToRelationDefinition(e) {
|
|
427
|
+
let t;
|
|
428
|
+
switch (e.type) {
|
|
429
|
+
case "-":
|
|
430
|
+
t = "one-to-one";
|
|
431
|
+
break;
|
|
432
|
+
case ">":
|
|
433
|
+
t = "many-to-one";
|
|
434
|
+
break;
|
|
435
|
+
case "<":
|
|
436
|
+
t = "one-to-many";
|
|
437
|
+
break;
|
|
438
|
+
default:
|
|
439
|
+
t = "many-to-one";
|
|
671
440
|
}
|
|
441
|
+
return {
|
|
442
|
+
fromTable: e.fromTable,
|
|
443
|
+
fromColumns: e.fromColumns,
|
|
444
|
+
toTable: e.toTable,
|
|
445
|
+
toColumns: e.toColumns,
|
|
446
|
+
type: t,
|
|
447
|
+
onDelete: e.onDelete,
|
|
448
|
+
onUpdate: e.onUpdate
|
|
449
|
+
};
|
|
672
450
|
}
|
|
673
451
|
/**
|
|
674
|
-
*
|
|
452
|
+
* Collect enum definitions from the schema
|
|
453
|
+
*
|
|
454
|
+
* Override in subclasses for dialect-specific enum handling (e.g., PostgreSQL)
|
|
675
455
|
*
|
|
676
|
-
* @
|
|
677
|
-
* @returns Array of column names in the unique constraint
|
|
456
|
+
* @returns Array of enum definitions (empty by default)
|
|
678
457
|
*/
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
return e.columns.map((n) => n.name);
|
|
682
|
-
} catch {
|
|
683
|
-
return [];
|
|
684
|
-
}
|
|
458
|
+
collectEnumDefinitions() {
|
|
459
|
+
return [];
|
|
685
460
|
}
|
|
686
461
|
}
|
|
687
|
-
function P(
|
|
688
|
-
const t =
|
|
689
|
-
|
|
690
|
-
}
|
|
691
|
-
function $(y) {
|
|
692
|
-
return y.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n");
|
|
462
|
+
function P(p, e) {
|
|
463
|
+
const t = R(p), n = q(t);
|
|
464
|
+
C(n, { recursive: !0 }), D(t, e, "utf-8");
|
|
693
465
|
}
|
|
694
466
|
export {
|
|
695
|
-
|
|
696
|
-
D as DbmlBuilder,
|
|
467
|
+
N as BaseGenerator,
|
|
697
468
|
P as writeDbmlFile
|
|
698
469
|
};
|
|
699
470
|
//# sourceMappingURL=common.js.map
|