drizzle-docs-generator 0.1.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +89 -0
  3. package/README.md +89 -0
  4. package/dist/cli/index.d.ts +8 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +69 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/generator/common.d.ts +393 -0
  9. package/dist/generator/common.d.ts.map +1 -0
  10. package/dist/generator/common.js +699 -0
  11. package/dist/generator/common.js.map +1 -0
  12. package/dist/generator/index.d.ts +15 -0
  13. package/dist/generator/index.d.ts.map +1 -0
  14. package/dist/generator/mysql.d.ts +36 -0
  15. package/dist/generator/mysql.d.ts.map +1 -0
  16. package/dist/generator/mysql.js +16 -0
  17. package/dist/generator/mysql.js.map +1 -0
  18. package/dist/generator/pg.d.ts +48 -0
  19. package/dist/generator/pg.d.ts.map +1 -0
  20. package/dist/generator/pg.js +52 -0
  21. package/dist/generator/pg.js.map +1 -0
  22. package/dist/generator/sqlite.d.ts +36 -0
  23. package/dist/generator/sqlite.d.ts.map +1 -0
  24. package/dist/generator/sqlite.js +16 -0
  25. package/dist/generator/sqlite.js.map +1 -0
  26. package/dist/index.d.ts +13 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +21 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/parser/comments.d.ts +31 -0
  31. package/dist/parser/comments.d.ts.map +1 -0
  32. package/dist/parser/comments.js +113 -0
  33. package/dist/parser/comments.js.map +1 -0
  34. package/dist/parser/index.d.ts +5 -0
  35. package/dist/parser/index.d.ts.map +1 -0
  36. package/dist/parser/relations.d.ts +34 -0
  37. package/dist/parser/relations.d.ts.map +1 -0
  38. package/dist/parser/relations.js +111 -0
  39. package/dist/parser/relations.js.map +1 -0
  40. package/dist/test-utils/cli-runner.d.ts +35 -0
  41. package/dist/test-utils/cli-runner.d.ts.map +1 -0
  42. package/dist/test-utils/dbml-validator.d.ts +70 -0
  43. package/dist/test-utils/dbml-validator.d.ts.map +1 -0
  44. package/dist/test-utils/index.d.ts +7 -0
  45. package/dist/test-utils/index.d.ts.map +1 -0
  46. package/dist/types.d.ts +53 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/package.json +69 -0
@@ -0,0 +1,699 @@
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 {
45
+ schema;
46
+ relational;
47
+ generatedRefs = [];
48
+ comments;
49
+ parsedRelations;
50
+ source;
51
+ /**
52
+ * Create a new generator instance
53
+ * @param options - Configuration options including schema, relational mode, source code, and comments
54
+ */
55
+ 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));
57
+ }
58
+ /**
59
+ * Generate complete DBML output from the schema
60
+ *
61
+ * Creates DBML representation including:
62
+ * - Table definitions with columns, indexes, and constraints
63
+ * - Foreign key references (from table config or relations)
64
+ * - Comments for tables and columns
65
+ *
66
+ * @returns The complete DBML string
67
+ */
68
+ 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();
76
+ }
77
+ /**
78
+ * Get all tables from schema
79
+ *
80
+ * Extracts all Drizzle table objects from the schema by checking each value
81
+ * with isTable() method.
82
+ *
83
+ * @returns Array of table objects
84
+ */
85
+ getTables() {
86
+ const e = [];
87
+ for (const t of Object.values(this.schema))
88
+ this.isTable(t) && e.push(t);
89
+ return e;
90
+ }
91
+ /**
92
+ * Check if a value is a Drizzle table
93
+ *
94
+ * Validates whether a value is a table instance from any supported dialect
95
+ * (PostgreSQL, MySQL, or SQLite).
96
+ *
97
+ * @param value - The value to check
98
+ * @returns True if value is a Drizzle table
99
+ */
100
+ 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";
127
+ }
128
+ /**
129
+ * Check if a value is a v1 relation entry (from defineRelations())
130
+ *
131
+ * Uses official Drizzle v1 types: TableRelationalConfig with Relation instances.
132
+ * Validates the structure has 'table', 'name', and 'relations' properties with valid types.
133
+ *
134
+ * @param value - The value to check
135
+ * @returns True if value is a v1 relation entry
136
+ */
137
+ isV1RelationEntry(e) {
138
+ if (typeof e != "object" || e === null)
139
+ return !1;
140
+ const t = e;
141
+ if (!("table" in t) || !("name" in t) || typeof t.name != "string" || !("relations" in t) || typeof t.relations != "object" || t.relations === null)
142
+ 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);
145
+ }
146
+ /**
147
+ * Get all v1 relation entries from schema (defineRelations() API)
148
+ *
149
+ * Handles both individual entries and the full defineRelations() result object.
150
+ * Extracts relation configurations that use the modern v1 API with official types.
151
+ *
152
+ * @returns Array of v1 relation entries
153
+ */
154
+ getV1RelationEntries() {
155
+ const e = [];
156
+ for (const t of Object.values(this.schema))
157
+ if (this.isV1RelationEntry(t))
158
+ e.push(t);
159
+ else if (this.isV1DefineRelationsResult(t))
160
+ for (const n of Object.values(t))
161
+ this.isV1RelationEntry(n) && e.push(n);
162
+ return e;
163
+ }
164
+ /**
165
+ * Check if a value is a full v1 defineRelations() result object
166
+ *
167
+ * This is an object where all values are TableRelationalConfig objects.
168
+ * Used to detect the full result of calling defineRelations() in v1.
169
+ *
170
+ * @param value - The value to check
171
+ * @returns True if value is a full defineRelations() result
172
+ */
173
+ isV1DefineRelationsResult(e) {
174
+ if (typeof e != "object" || e === null || Array.isArray(e))
175
+ return !1;
176
+ 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);
197
+ }
198
+ /**
199
+ * Get table configuration from a Drizzle table
200
+ *
201
+ * Extracts indexes, primary keys, unique constraints, and foreign keys
202
+ * from the table using the appropriate dialect-specific config getter.
203
+ *
204
+ * @param table - The Drizzle table to get configuration from
205
+ * @returns Table configuration or undefined if dialect is not supported
206
+ */
207
+ 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
+ };
225
+ }
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
+ };
234
+ }
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)}'`);
276
+ }
277
+ return n;
278
+ }
279
+ /**
280
+ * Format attributes into a string
281
+ *
282
+ * @param attrs - Array of attribute strings
283
+ * @returns Comma-separated attribute string
284
+ */
285
+ formatAttributes(e) {
286
+ return e.join(", ");
287
+ }
288
+ /**
289
+ * Get the default value for a column
290
+ *
291
+ * Extracts and formats the default value from a column, handling SQL expressions,
292
+ * objects, and primitive values. Returns undefined if no default value exists.
293
+ *
294
+ * @param column - The column to get the default value from
295
+ * @returns Formatted default value string or undefined
296
+ */
297
+ getDefaultValue(e) {
298
+ if (!e.hasDefault)
299
+ return;
300
+ const t = e.default;
301
+ if (t === null)
302
+ return "null";
303
+ if (t !== void 0) {
304
+ if (typeof t == "object" && t !== null) {
305
+ 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("")}\``;
310
+ }
311
+ return "sql" in t ? `\`${t.sql}\`` : `'${JSON.stringify(t)}'`;
312
+ }
313
+ if (typeof t == "string")
314
+ return `'${t.replace(/'/g, "\\'")}'`;
315
+ if (typeof t == "number" || typeof t == "boolean")
316
+ return String(t);
317
+ }
318
+ }
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
+ /**
359
+ * Collect foreign keys from table configuration
360
+ *
361
+ * Parses all foreign key definitions from the table config and adds them
362
+ * to the generatedRefs collection for later output.
363
+ *
364
+ * @param tableName - The name of the source table
365
+ * @param foreignKeys - Array of foreign key definitions from table config
366
+ */
367
+ collectForeignKeysFromConfig(e, t) {
368
+ for (const n of t) {
369
+ const s = this.parseForeignKey(e, n);
370
+ s && this.generatedRefs.push(s);
371
+ }
372
+ }
373
+ /**
374
+ * Parse a foreign key into a GeneratedRef
375
+ *
376
+ * Extracts foreign key information (source/target tables and columns, actions)
377
+ * and converts it to a GeneratedRef object for DBML output.
378
+ *
379
+ * @param tableName - The name of the source table
380
+ * @param fk - The foreign key definition to parse
381
+ * @returns GeneratedRef object or undefined if parsing fails
382
+ */
383
+ 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;
415
+ }
416
+ /**
417
+ * Get a mapping from TypeScript property names to database column names for a table
418
+ *
419
+ * Creates a map from TypeScript property names (e.g., "authorId") to
420
+ * actual database column names (e.g., "author_id").
421
+ *
422
+ * @param tableVarName - The variable name of the table in the schema
423
+ * @returns Map of property names to column names
424
+ */
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;
433
+ }
434
+ /**
435
+ * Check if there's a reverse one() relation (B->A when we have A->B)
436
+ *
437
+ * Used to detect one-to-one relationships by checking if both tables
438
+ * have one() relations pointing to each other.
439
+ *
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
445
+ */
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;
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);
503
+ }
504
+ }
505
+ /**
506
+ * Generate references from v1 defineRelations() entries
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.
511
+ *
512
+ * @param entries - Array of v1 relation entries from defineRelations()
513
+ */
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);
542
+ }
543
+ }
544
+ }
545
+ /**
546
+ * Check if there's a reverse One relation in v1 entries
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.
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
557
+ */
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;
573
+ }
574
+ /**
575
+ * Get unique key for a relation to avoid duplicates
576
+ *
577
+ * Creates a consistent key by sorting table names alphabetically.
578
+ *
579
+ * @param tableName - The source table name
580
+ * @param relation - The relation object
581
+ * @returns A unique key string for the relation
582
+ */
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]}`;
586
+ }
587
+ /**
588
+ * Parse a relation into a GeneratedRef
589
+ *
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
596
+ */
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
+ }
617
+ }
618
+ /**
619
+ * Generate a reference line in DBML format
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
636
+ *
637
+ * @param idx - The index definition to extract columns from
638
+ * @returns Array of column names in the index
639
+ */
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 {
644
+ return [];
645
+ }
646
+ }
647
+ /**
648
+ * Check if an index is unique
649
+ *
650
+ * @param idx - The index definition to check
651
+ * @returns True if the index has the unique flag
652
+ */
653
+ isUniqueIndex(e) {
654
+ try {
655
+ return e.config.unique === !0;
656
+ } catch {
657
+ return !1;
658
+ }
659
+ }
660
+ /**
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 [];
671
+ }
672
+ }
673
+ /**
674
+ * Get column names from a unique constraint
675
+ *
676
+ * @param uc - The unique constraint definition to extract columns from
677
+ * @returns Array of column names in the unique constraint
678
+ */
679
+ getUniqueConstraintColumns(e) {
680
+ try {
681
+ return e.columns.map((n) => n.name);
682
+ } catch {
683
+ return [];
684
+ }
685
+ }
686
+ }
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");
693
+ }
694
+ export {
695
+ B as BaseGenerator,
696
+ D as DbmlBuilder,
697
+ P as writeDbmlFile
698
+ };
699
+ //# sourceMappingURL=common.js.map