drizzle-docs-generator 0.2.0 → 0.4.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.
Files changed (61) hide show
  1. package/README.ja.md +59 -15
  2. package/README.md +55 -11
  3. package/dist/adapter/types.d.ts +40 -0
  4. package/dist/adapter/types.d.ts.map +1 -0
  5. package/dist/adapter/v0-adapter.d.ts +73 -0
  6. package/dist/adapter/v0-adapter.d.ts.map +1 -0
  7. package/dist/adapter/v0-adapter.js +136 -0
  8. package/dist/adapter/v0-adapter.js.map +1 -0
  9. package/dist/adapter/v1-adapter.d.ts +40 -0
  10. package/dist/adapter/v1-adapter.d.ts.map +1 -0
  11. package/dist/adapter/v1-adapter.js +83 -0
  12. package/dist/adapter/v1-adapter.js.map +1 -0
  13. package/dist/cli/index.js +194 -71
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/integration-test-utils.d.ts +19 -0
  16. package/dist/cli/integration-test-utils.d.ts.map +1 -0
  17. package/dist/formatter/dbml-builder.d.ts +29 -0
  18. package/dist/formatter/dbml-builder.d.ts.map +1 -0
  19. package/dist/formatter/dbml-builder.js +39 -0
  20. package/dist/formatter/dbml-builder.js.map +1 -0
  21. package/dist/formatter/dbml.d.ts +81 -0
  22. package/dist/formatter/dbml.d.ts.map +1 -0
  23. package/dist/formatter/dbml.js +163 -0
  24. package/dist/formatter/dbml.js.map +1 -0
  25. package/dist/formatter/markdown.d.ts +126 -0
  26. package/dist/formatter/markdown.d.ts.map +1 -0
  27. package/dist/formatter/markdown.js +235 -0
  28. package/dist/formatter/markdown.js.map +1 -0
  29. package/dist/formatter/mermaid.d.ts +102 -0
  30. package/dist/formatter/mermaid.d.ts.map +1 -0
  31. package/dist/formatter/mermaid.js +177 -0
  32. package/dist/formatter/mermaid.js.map +1 -0
  33. package/dist/formatter/types.d.ts +37 -0
  34. package/dist/formatter/types.d.ts.map +1 -0
  35. package/dist/generator/common.d.ts +115 -208
  36. package/dist/generator/common.d.ts.map +1 -1
  37. package/dist/generator/common.js +260 -479
  38. package/dist/generator/common.js.map +1 -1
  39. package/dist/generator/mysql.js +3 -3
  40. package/dist/generator/pg.d.ts +8 -7
  41. package/dist/generator/pg.d.ts.map +1 -1
  42. package/dist/generator/pg.js +29 -31
  43. package/dist/generator/pg.js.map +1 -1
  44. package/dist/generator/sqlite.js +3 -3
  45. package/dist/index.d.ts +15 -4
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +22 -18
  48. package/dist/index.js.map +1 -1
  49. package/dist/test-utils/cli-runner.d.ts +4 -1
  50. package/dist/test-utils/cli-runner.d.ts.map +1 -1
  51. package/dist/test-utils/dbml-validator.d.ts +29 -0
  52. package/dist/test-utils/dbml-validator.d.ts.map +1 -1
  53. package/dist/types.d.ts +128 -16
  54. package/dist/types.d.ts.map +1 -1
  55. package/package.json +3 -2
  56. package/dist/generator/index.d.ts +0 -15
  57. package/dist/generator/index.d.ts.map +0 -1
  58. package/dist/parser/index.d.ts +0 -5
  59. package/dist/parser/index.d.ts.map +0 -1
  60. package/dist/test-utils/index.d.ts +0 -7
  61. package/dist/test-utils/index.d.ts.map +0 -1
@@ -1,59 +1,26 @@
1
- import { is as m, Relation as j, getTableName as g, getTableColumns as d, One as b } from "drizzle-orm";
2
- import { PgTable as C, getTableConfig as v } from "drizzle-orm/pg-core";
3
- import { MySqlTable as T, getTableConfig as N } from "drizzle-orm/mysql-core";
4
- import { SQLiteTable as R, getTableConfig as K } from "drizzle-orm/sqlite-core";
5
- import { mkdirSync as q, writeFileSync as V } from "node:fs";
6
- import { resolve as O, dirname as x } from "node:path";
7
- import { extractComments as S } from "../parser/comments.js";
8
- import { extractRelations as k } from "../parser/relations.js";
9
- class D {
10
- lines = [];
11
- indentLevel = 0;
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 d } from "drizzle-orm/mysql-core";
4
+ import { SQLiteTable as u, getTableConfig as T } 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 V } from "../parser/relations.js";
10
+ import { V0RelationAdapter as x } from "../adapter/v0-adapter.js";
11
+ import { V1RelationAdapter as K } from "../adapter/v1-adapter.js";
12
+ class N {
45
13
  schema;
46
- relational;
47
14
  generatedRefs = [];
48
15
  comments;
49
16
  parsedRelations;
50
17
  source;
51
18
  /**
52
19
  * Create a new generator instance
53
- * @param options - Configuration options including schema, relational mode, source code, and comments
20
+ * @param options - Configuration options including schema, source code, and comments
54
21
  */
55
22
  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 = S(this.source)), this.relational && this.source && (this.parsedRelations = k(this.source));
23
+ this.schema = e.schema, this.source = e.source, e.comments ? this.comments = e.comments : this.source && (this.comments = v(this.source)), this.source && (this.parsedRelations = V(this.source));
57
24
  }
58
25
  /**
59
26
  * Generate complete DBML output from the schema
@@ -66,13 +33,8 @@ class B {
66
33
  * @returns The complete DBML string
67
34
  */
68
35
  generate() {
69
- const e = new D(), t = this.getTables(), n = this.getV0Relations(), s = this.getV1RelationEntries();
70
- for (const o of t)
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();
36
+ const e = this.toIntermediateSchema();
37
+ return new j().format(e);
76
38
  }
77
39
  /**
78
40
  * Get all tables from schema
@@ -98,32 +60,7 @@ class B {
98
60
  * @returns True if value is a Drizzle table
99
61
  */
100
62
  isTable(e) {
101
- return m(e, C) || m(e, T) || m(e, R);
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";
63
+ return r(e, c) || r(e, f) || r(e, u);
127
64
  }
128
65
  /**
129
66
  * Check if a value is a v1 relation entry (from defineRelations())
@@ -140,8 +77,8 @@ class B {
140
77
  const t = e;
141
78
  if (!("table" in t) || !("name" in t) || typeof t.name != "string" || !("relations" in t) || typeof t.relations != "object" || t.relations === null)
142
79
  return !1;
143
- const n = t.relations, s = Object.values(n);
144
- return s.length > 0 ? s.some((o) => m(o, j)) : this.isTable(t.table);
80
+ const n = t.relations, o = Object.values(n);
81
+ return o.length > 0 ? o.some((s) => r(s, h)) : this.isTable(t.table);
145
82
  }
146
83
  /**
147
84
  * Get all v1 relation entries from schema (defineRelations() API)
@@ -174,26 +111,7 @@ class B {
174
111
  if (typeof e != "object" || e === null || Array.isArray(e))
175
112
  return !1;
176
113
  const n = Object.values(e);
177
- return n.length > 0 && n.every((s) => this.isV1RelationEntry(s));
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);
114
+ return n.length > 0 && n.every((o) => this.isV1RelationEntry(o));
197
115
  }
198
116
  /**
199
117
  * Get table configuration from a Drizzle table
@@ -205,85 +123,51 @@ class B {
205
123
  * @returns Table configuration or undefined if dialect is not supported
206
124
  */
207
125
  getTableConfig(e) {
208
- if (m(e, C)) {
209
- const t = v(e);
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
- };
126
+ if (r(e, c)) {
127
+ const t = b(e);
128
+ return this.mapTableConfig(t);
225
129
  }
226
- if (m(e, R)) {
227
- const t = K(e);
228
- return {
229
- indexes: t.indexes || [],
230
- primaryKeys: t.primaryKeys || [],
231
- uniqueConstraints: t.uniqueConstraints || [],
232
- foreignKeys: t.foreignKeys || []
233
- };
130
+ if (r(e, f)) {
131
+ const t = d(e);
132
+ return this.mapTableConfig(t);
234
133
  }
235
- }
236
- /**
237
- * Generate a column definition in DBML format
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)}'`);
134
+ if (r(e, u)) {
135
+ const t = T(e);
136
+ return this.mapTableConfig(t);
276
137
  }
277
- return n;
278
138
  }
279
139
  /**
280
- * Format attributes into a string
140
+ * Map Drizzle's internal table config to our typed TableConfig
281
141
  *
282
- * @param attrs - Array of attribute strings
283
- * @returns Comma-separated attribute string
142
+ * Note: Drizzle ORM's columns type is `SQL<unknown> | IndexedColumn` union,
143
+ * so we use `{ name?: string }` and cast to access the name property.
144
+ * This is unavoidable due to Drizzle's internal type structure.
284
145
  */
285
- formatAttributes(e) {
286
- return e.join(", ");
146
+ mapTableConfig(e) {
147
+ return {
148
+ indexes: (e.indexes || []).map((t) => ({
149
+ config: {
150
+ columns: t.config.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
151
+ name: t.config.name,
152
+ unique: t.config.unique ?? !1,
153
+ using: t.config.using
154
+ }
155
+ })),
156
+ primaryKeys: (e.primaryKeys || []).map((t) => ({
157
+ columns: t.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
158
+ name: t.name
159
+ })),
160
+ uniqueConstraints: (e.uniqueConstraints || []).map((t) => ({
161
+ columns: t.columns.filter((n) => typeof n.name == "string").map((n) => ({ name: n.name })),
162
+ name: t.name
163
+ })),
164
+ foreignKeys: (e.foreignKeys || []).map((t) => ({
165
+ reference: t.reference,
166
+ name: t.name,
167
+ onDelete: t.onDelete,
168
+ onUpdate: t.onUpdate
169
+ }))
170
+ };
287
171
  }
288
172
  /**
289
173
  * Get the default value for a column
@@ -303,58 +187,19 @@ class B {
303
187
  if (t !== void 0) {
304
188
  if (typeof t == "object" && t !== null) {
305
189
  if ("queryChunks" in t) {
306
- const n = t.queryChunks, s = [];
307
- for (const o of n)
308
- typeof o == "string" ? s.push(o) : typeof o == "object" && o !== null && "value" in o && s.push(String(o.value));
309
- return `\`${s.join("")}\``;
190
+ const n = t.queryChunks, o = [];
191
+ for (const s of n)
192
+ typeof s == "string" ? o.push(s) : typeof s == "object" && s !== null && "value" in s && o.push(String(s.value));
193
+ return o.join("");
310
194
  }
311
- return "sql" in t ? `\`${t.sql}\`` : `'${JSON.stringify(t)}'`;
195
+ return "sql" in t ? t.sql : JSON.stringify(t);
312
196
  }
313
197
  if (typeof t == "string")
314
- return `'${t.replace(/'/g, "\\'")}'`;
198
+ return `'${t.replace(/'/g, "''")}'`;
315
199
  if (typeof t == "number" || typeof t == "boolean")
316
200
  return String(t);
317
201
  }
318
202
  }
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
203
  /**
359
204
  * Collect foreign keys from table configuration
360
205
  *
@@ -366,8 +211,8 @@ class B {
366
211
  */
367
212
  collectForeignKeysFromConfig(e, t) {
368
213
  for (const n of t) {
369
- const s = this.parseForeignKey(e, n);
370
- s && this.generatedRefs.push(s);
214
+ const o = this.parseForeignKey(e, n);
215
+ this.generatedRefs.push(o);
371
216
  }
372
217
  }
373
218
  /**
@@ -378,322 +223,258 @@ class B {
378
223
  *
379
224
  * @param tableName - The name of the source table
380
225
  * @param fk - The foreign key definition to parse
381
- * @returns GeneratedRef object or undefined if parsing fails
226
+ * @returns GeneratedRef object
382
227
  */
383
228
  parseForeignKey(e, t) {
384
- try {
385
- const n = t, s = n.reference(), o = s.columns.map((a) => a.name), i = s.foreignColumns.map((a) => a.name), r = g(s.foreignTable);
386
- return {
387
- fromTable: e,
388
- fromColumns: o,
389
- toTable: r,
390
- toColumns: i,
391
- type: ">",
392
- onDelete: n.onDelete,
393
- onUpdate: n.onUpdate
394
- };
395
- } catch {
396
- return;
397
- }
398
- }
399
- /**
400
- * Get a mapping from variable names to table names in the schema
401
- *
402
- * Creates a map from TypeScript variable names (e.g., "usersTable") to
403
- * actual database table names (e.g., "users").
404
- *
405
- * @returns Map of variable names to table names
406
- */
407
- getTableNameMapping() {
408
- const e = /* @__PURE__ */ new Map();
409
- for (const [t, n] of Object.entries(this.schema))
410
- if (this.isTable(n)) {
411
- const s = g(n);
412
- e.set(t, s);
413
- }
414
- return e;
229
+ const n = t.reference(), o = n.columns.map((a) => a.name), s = n.foreignColumns.map((a) => a.name), i = m(n.foreignTable);
230
+ return {
231
+ fromTable: e,
232
+ fromColumns: o,
233
+ toTable: i,
234
+ toColumns: s,
235
+ type: ">",
236
+ onDelete: t.onDelete,
237
+ onUpdate: t.onUpdate
238
+ };
415
239
  }
416
240
  /**
417
- * Get a mapping from TypeScript property names to database column names for a table
241
+ * Detect if relation definitions are present in the schema
418
242
  *
419
- * Creates a map from TypeScript property names (e.g., "authorId") to
420
- * actual database column names (e.g., "author_id").
243
+ * Checks for both v1 (defineRelations()) and v0 (relations()) API usage.
244
+ * Returns true if any relation definitions are found.
421
245
  *
422
- * @param tableVarName - The variable name of the table in the schema
423
- * @returns Map of property names to column names
246
+ * @returns True if relations are defined, false otherwise
424
247
  */
425
- getColumnNameMapping(e) {
426
- const t = /* @__PURE__ */ new Map(), n = this.schema[e];
427
- if (n && this.isTable(n)) {
428
- const s = d(n);
429
- for (const [o, i] of Object.entries(s))
430
- t.set(o, i.name);
431
- }
432
- return t;
248
+ hasRelationDefinitions() {
249
+ return !!(this.getV1RelationEntries().length > 0 || this.parsedRelations && this.parsedRelations.relations.length > 0);
433
250
  }
434
251
  /**
435
- * Check if there's a reverse one() relation (B->A when we have A->B)
252
+ * Create the appropriate relation adapter based on schema contents
436
253
  *
437
- * Used to detect one-to-one relationships by checking if both tables
438
- * have one() relations pointing to each other.
254
+ * Detects whether v1 or v0 relations are present and returns the
255
+ * corresponding adapter implementation.
439
256
  *
440
- * @param sourceTable - The source table variable name
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
257
+ * @returns RelationAdapter instance (V1RelationAdapter or V0RelationAdapter)
445
258
  */
446
- hasReverseOneRelation(e, t, n, s) {
447
- if (!this.parsedRelations) return !1;
448
- for (const o of this.parsedRelations.relations)
449
- if (o.type === "one" && o.sourceTable === t && o.targetTable === e && o.fields.length > 0 && o.references.length > 0) {
450
- const i = o.fields, r = o.references;
451
- if (this.arraysEqual(i, s) && this.arraysEqual(r, n))
452
- return !0;
453
- }
454
- return !1;
259
+ createRelationAdapter() {
260
+ const e = this.getV1RelationEntries();
261
+ return e.length > 0 ? new K(e) : new x(this.schema, this.parsedRelations);
455
262
  }
456
263
  /**
457
- * Helper to check if two arrays are equal
264
+ * Convert a UnifiedRelation to a RelationDefinition
458
265
  *
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
266
+ * Maps the unified relation format from adapters to the intermediate
267
+ * schema's RelationDefinition format.
468
268
  *
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.
269
+ * @param unified - The unified relation from adapter
270
+ * @returns RelationDefinition for intermediate schema
473
271
  */
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);
503
- }
272
+ unifiedRelationToDefinition(e) {
273
+ return {
274
+ fromTable: e.sourceTable,
275
+ fromColumns: e.sourceColumns,
276
+ toTable: e.targetTable,
277
+ toColumns: e.targetColumns,
278
+ type: e.relationType,
279
+ onDelete: e.onDelete,
280
+ onUpdate: e.onUpdate
281
+ };
504
282
  }
505
283
  /**
506
- * Generate references from v1 defineRelations() entries
284
+ * Convert the Drizzle schema to an intermediate schema representation
507
285
  *
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.
286
+ * Creates a database-agnostic intermediate representation that can be
287
+ * used to generate various output formats (DBML, Markdown, JSON, etc.)
511
288
  *
512
- * @param entries - Array of v1 relation entries from defineRelations()
289
+ * @returns The intermediate schema representation
513
290
  */
514
- generateRelationalRefsFromV1(e) {
515
- const t = /* @__PURE__ */ new Set();
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);
291
+ toIntermediateSchema() {
292
+ const e = this.getTables(), t = this.getDatabaseType(e[0]), n = e.map(
293
+ (i) => this.tableToDefinition(i)
294
+ );
295
+ let o = [];
296
+ if (this.hasRelationDefinitions())
297
+ o = this.createRelationAdapter().extract().map((l) => this.unifiedRelationToDefinition(l));
298
+ else {
299
+ this.generatedRefs = [];
300
+ for (const i of e) {
301
+ const a = m(i), l = this.getTableConfig(i);
302
+ l && l.foreignKeys.length > 0 && this.collectForeignKeysFromConfig(a, l.foreignKeys);
542
303
  }
304
+ o = this.generatedRefs.map((i) => this.refToRelationDefinition(i));
543
305
  }
306
+ const s = this.collectEnumDefinitions();
307
+ return {
308
+ databaseType: t,
309
+ tables: n,
310
+ relations: o,
311
+ enums: s
312
+ };
544
313
  }
545
314
  /**
546
- * Check if there's a reverse One relation in v1 entries
315
+ * Determine the database type from a Drizzle table
547
316
  *
548
- * Detects one-to-one relationships by checking if the target table
549
- * has a matching One relation pointing back to the source table.
550
- *
551
- * @param entries - All v1 relation entries
552
- * @param fromTableName - The table to search for reverse relation
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
317
+ * @param table - The table to check (can be undefined for empty schemas)
318
+ * @returns The database type
557
319
  */
558
- hasV1ReverseOneRelation(e, t, n, s, o) {
559
- const i = e.find((r) => g(r.table) === t);
560
- if (!i)
561
- return !1;
562
- for (const r of Object.values(i.relations)) {
563
- if (!m(r, b))
564
- continue;
565
- const a = r;
566
- if (g(a.targetTable) !== n)
567
- continue;
568
- const c = a.sourceColumns.map((f) => f.name), h = a.targetColumns.map((f) => f.name);
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;
320
+ getDatabaseType(e) {
321
+ return !e || r(e, c) ? "postgresql" : r(e, f) ? "mysql" : r(e, u) ? "sqlite" : "postgresql";
573
322
  }
574
323
  /**
575
- * Get unique key for a relation to avoid duplicates
576
- *
577
- * Creates a consistent key by sorting table names alphabetically.
324
+ * Convert a Drizzle table to a TableDefinition
578
325
  *
579
- * @param tableName - The source table name
580
- * @param relation - The relation object
581
- * @returns A unique key string for the relation
326
+ * @param table - The Drizzle table to convert
327
+ * @returns The table definition
582
328
  */
583
- getRelationKey(e, t) {
584
- const n = t, s = n.referencedTable ? g(n.referencedTable) : "unknown", o = [e, s].sort();
585
- return `${o[0]}-${o[1]}`;
329
+ tableToDefinition(e) {
330
+ const t = m(e), n = y(e), o = this.getTableConfig(e), s = Object.values(n).map(
331
+ (g) => this.columnToDefinition(g, t)
332
+ ), i = this.extractIndexDefinitions(o), a = this.extractConstraintDefinitions(o), l = this.comments?.tables[t]?.comment;
333
+ return {
334
+ name: t,
335
+ comment: l,
336
+ columns: s,
337
+ indexes: i,
338
+ constraints: a
339
+ };
586
340
  }
587
341
  /**
588
- * Parse a relation into a GeneratedRef
342
+ * Convert a Drizzle column to a ColumnDefinition
589
343
  *
590
- * Extracts relation information from a legacy relation object and converts
591
- * it to a GeneratedRef for DBML output.
592
- *
593
- * @param tableName - The source table name
594
- * @param relation - The relation object to parse
595
- * @returns GeneratedRef object or undefined if parsing fails
344
+ * @param column - The Drizzle column to convert
345
+ * @param tableName - The name of the table containing the column
346
+ * @returns The column definition
596
347
  */
597
- parseRelation(e, t) {
598
- try {
599
- const n = t;
600
- if (!n.referencedTable)
601
- return;
602
- const s = g(n.referencedTable), o = n.sourceColumns || [], i = n.referencedColumns || [];
603
- if (o.length === 0 || i.length === 0)
604
- return;
605
- const r = o.map((c) => c.name), a = i.map((c) => c.name);
606
- let l = ">";
607
- return n.relationType === "one" && (l = "-"), {
608
- fromTable: e,
609
- fromColumns: r,
610
- toTable: s,
611
- toColumns: a,
612
- type: l
613
- };
614
- } catch {
615
- return;
616
- }
348
+ columnToDefinition(e, t) {
349
+ const n = this.comments?.tables[t]?.columns[e.name]?.comment, o = this.getDefaultValue(e);
350
+ return {
351
+ name: e.name,
352
+ type: e.getSQLType(),
353
+ nullable: !e.notNull,
354
+ defaultValue: o,
355
+ primaryKey: e.primary,
356
+ unique: e.isUnique,
357
+ autoIncrement: this.dialectConfig.isIncrement(e) || void 0,
358
+ comment: n
359
+ };
617
360
  }
618
361
  /**
619
- * Generate a reference line in DBML format
362
+ * Extract index definitions from table config
620
363
  *
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
636
- *
637
- * @param idx - The index definition to extract columns from
638
- * @returns Array of column names in the index
364
+ * @param tableConfig - The table configuration
365
+ * @returns Array of index definitions
639
366
  */
640
- getIndexColumns(e) {
641
- try {
642
- return e.config.columns.map((n) => typeof n == "object" && n !== null && "name" in n ? n.name : "").filter(Boolean);
643
- } catch {
367
+ extractIndexDefinitions(e) {
368
+ if (!e)
644
369
  return [];
370
+ const t = [];
371
+ for (const n of e.indexes) {
372
+ const o = n.config.columns.map((s) => s.name);
373
+ o.length > 0 && t.push({
374
+ name: n.config.name || `idx_${o.join("_")}`,
375
+ columns: o,
376
+ unique: n.config.unique,
377
+ type: n.config.using
378
+ });
645
379
  }
380
+ return t;
646
381
  }
647
382
  /**
648
- * Check if an index is unique
383
+ * Extract constraint definitions from table config
649
384
  *
650
- * @param idx - The index definition to check
651
- * @returns True if the index has the unique flag
385
+ * @param tableConfig - The table configuration
386
+ * @returns Array of constraint definitions
652
387
  */
653
- isUniqueIndex(e) {
654
- try {
655
- return e.config.unique === !0;
656
- } catch {
657
- return !1;
388
+ extractConstraintDefinitions(e) {
389
+ if (!e)
390
+ return [];
391
+ const t = [];
392
+ for (const n of e.primaryKeys) {
393
+ const o = n.columns.map((s) => s.name);
394
+ o.length > 0 && t.push({
395
+ name: n.name || `pk_${o.join("_")}`,
396
+ type: "primary_key",
397
+ columns: o
398
+ });
399
+ }
400
+ for (const n of e.uniqueConstraints) {
401
+ const o = n.columns.map((s) => s.name);
402
+ o.length > 0 && t.push({
403
+ name: n.name || `uq_${o.join("_")}`,
404
+ type: "unique",
405
+ columns: o
406
+ });
658
407
  }
408
+ for (const n of e.foreignKeys) {
409
+ const o = this.parseForeignKeyForConstraint(n);
410
+ o && t.push(o);
411
+ }
412
+ return t;
659
413
  }
660
414
  /**
661
- * Get column names from a primary key constraint
662
- *
663
- * @param pk - The primary key definition to extract columns from
664
- * @returns Array of column names in the primary key
665
- */
666
- getPrimaryKeyColumns(e) {
667
- try {
668
- return e.columns.map((n) => n.name);
669
- } catch {
670
- return [];
415
+ * Parse a foreign key into a ConstraintDefinition
416
+ *
417
+ * @param fk - The foreign key definition
418
+ * @returns ConstraintDefinition
419
+ */
420
+ parseForeignKeyForConstraint(e) {
421
+ const t = e.reference(), n = t.columns.map((i) => i.name), o = t.foreignColumns.map((i) => i.name), s = m(t.foreignTable);
422
+ return {
423
+ name: e.name || `fk_${n.join("_")}_${s}`,
424
+ type: "foreign_key",
425
+ columns: n,
426
+ referencedTable: s,
427
+ referencedColumns: o
428
+ };
429
+ }
430
+ /**
431
+ * Convert a GeneratedRef to a RelationDefinition
432
+ *
433
+ * @param ref - The generated reference
434
+ * @returns The relation definition
435
+ */
436
+ refToRelationDefinition(e) {
437
+ let t;
438
+ switch (e.type) {
439
+ case "-":
440
+ t = "one-to-one";
441
+ break;
442
+ case ">":
443
+ t = "many-to-one";
444
+ break;
445
+ case "<":
446
+ t = "one-to-many";
447
+ break;
448
+ default:
449
+ t = "many-to-one";
671
450
  }
451
+ return {
452
+ fromTable: e.fromTable,
453
+ fromColumns: e.fromColumns,
454
+ toTable: e.toTable,
455
+ toColumns: e.toColumns,
456
+ type: t,
457
+ onDelete: e.onDelete,
458
+ onUpdate: e.onUpdate
459
+ };
672
460
  }
673
461
  /**
674
- * Get column names from a unique constraint
462
+ * Collect enum definitions from the schema
463
+ *
464
+ * Override in subclasses for dialect-specific enum handling (e.g., PostgreSQL)
675
465
  *
676
- * @param uc - The unique constraint definition to extract columns from
677
- * @returns Array of column names in the unique constraint
466
+ * @returns Array of enum definitions (empty by default)
678
467
  */
679
- getUniqueConstraintColumns(e) {
680
- try {
681
- return e.columns.map((n) => n.name);
682
- } catch {
683
- return [];
684
- }
468
+ collectEnumDefinitions() {
469
+ return [];
685
470
  }
686
471
  }
687
- function P(y, e) {
688
- const t = O(y), n = x(t);
689
- q(n, { recursive: !0 }), V(t, e, "utf-8");
690
- }
691
- function $(y) {
692
- return y.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n");
472
+ function P(p, e) {
473
+ const t = R(p), n = q(t);
474
+ C(n, { recursive: !0 }), D(t, e, "utf-8");
693
475
  }
694
476
  export {
695
- B as BaseGenerator,
696
- D as DbmlBuilder,
477
+ N as BaseGenerator,
697
478
  P as writeDbmlFile
698
479
  };
699
480
  //# sourceMappingURL=common.js.map