@danceroutine/tango-migrations 1.11.1 → 1.11.3

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 (142) hide show
  1. package/dist/Builder-y8vj7XXN.d.ts +25 -0
  2. package/dist/{CollectingBuilder--4fqDQdE.js → CollectingBuilder-BIfAKs_x.js} +6 -4
  3. package/dist/CollectingBuilder-BIfAKs_x.js.map +1 -0
  4. package/dist/CompilerFactory-Czv-zEOS.d.ts +30 -0
  5. package/dist/CompilerStrategy-DqmcqAC-.d.ts +44 -0
  6. package/dist/{CompilerStrategy-_AiXiyjS.js → CompilerStrategy-vcZKg8qf.js} +14 -10
  7. package/dist/CompilerStrategy-vcZKg8qf.js.map +1 -0
  8. package/dist/Dialect-Cp4r7UfW.d.ts +12 -0
  9. package/dist/{InternalColumnType-G9zV9StN.js → InternalColumnType-Dzs9T6a6.js} +3 -4
  10. package/dist/{InternalColumnType-G9zV9StN.js.map → InternalColumnType-Dzs9T6a6.js.map} +1 -1
  11. package/dist/{InternalOperationKind-Bt6Weuon.js → InternalOperationKind-M4a4H9OZ.js} +3 -4
  12. package/dist/{InternalOperationKind-Bt6Weuon.js.map → InternalOperationKind-M4a4H9OZ.js.map} +1 -1
  13. package/dist/{IntrospectorStrategy-BEIG5GqA.js → IntrospectorStrategy-BijuyIaN.js} +14 -9
  14. package/dist/IntrospectorStrategy-BijuyIaN.js.map +1 -0
  15. package/dist/{Migration-DYQ0hUG7.js → Migration-DxHHPyzn.js} +9 -4
  16. package/dist/Migration-DxHHPyzn.js.map +1 -0
  17. package/dist/{MigrationGenerator-B1p0jHnx.js → MigrationGenerator-BmmerPXJ.js} +24 -35
  18. package/dist/MigrationGenerator-BmmerPXJ.js.map +1 -0
  19. package/dist/MigrationOperation-qpdhPEs9.d.ts +145 -0
  20. package/dist/{MigrationRunner-DomrOZIn.js → MigrationRunner-B5AJel12.js} +52 -24
  21. package/dist/MigrationRunner-B5AJel12.js.map +1 -0
  22. package/dist/{MigrationSqlSafetyAdapter-CGRbB2k2.js → MigrationSqlSafetyAdapter-yP6fPjeC.js} +13 -9
  23. package/dist/MigrationSqlSafetyAdapter-yP6fPjeC.js.map +1 -0
  24. package/dist/PostgresIntrospector-DQDTZUW_.d.ts +77 -0
  25. package/dist/{SqliteCompilerFactory-BvdJ0kBl.js → SqliteCompilerFactory-CXlPAclY.js} +38 -40
  26. package/dist/SqliteCompilerFactory-CXlPAclY.js.map +1 -0
  27. package/dist/{SqliteIntrospector-CWwPWhmA.js → SqliteIntrospector-CfItmGgA.js} +15 -15
  28. package/dist/SqliteIntrospector-CfItmGgA.js.map +1 -0
  29. package/dist/builder/index.d.ts +4 -10
  30. package/dist/builder/index.js +3 -6
  31. package/dist/{builder-xJ-Bq2pk.js → builder-BSepa_PF.js} +24 -24
  32. package/dist/builder-BSepa_PF.js.map +1 -0
  33. package/dist/chunk-D7D4PA-g.js +13 -0
  34. package/dist/{cli-7j3R1Y1r.js → cli-e8I1-dab.js} +34 -47
  35. package/dist/cli-e8I1-dab.js.map +1 -0
  36. package/dist/cli.d.ts +1 -2
  37. package/dist/cli.js +3 -16
  38. package/dist/cli.js.map +1 -1
  39. package/dist/commands/index.d.ts +2 -4
  40. package/dist/commands/index.js +7 -16
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/compilers/index.d.ts +3 -10
  43. package/dist/compilers/index.js +3 -7
  44. package/dist/{compilers-C-GiumJB.js → compilers-BW-WALoD.js} +9 -16
  45. package/dist/{compilers-C-GiumJB.js.map → compilers-BW-WALoD.js.map} +1 -1
  46. package/dist/diff/index.d.ts +2 -5
  47. package/dist/diff/index.js +2 -7
  48. package/dist/{diff-B9MhagJF.js → diff-7Xw8k4vp.js} +14 -14
  49. package/dist/diff-7Xw8k4vp.js.map +1 -0
  50. package/dist/domain/index.d.ts +5 -7
  51. package/dist/domain/index.js +7 -3
  52. package/dist/domain/index.js.map +1 -0
  53. package/dist/generator/index.d.ts +2 -4
  54. package/dist/generator/index.js +7 -4
  55. package/dist/generator/index.js.map +1 -0
  56. package/dist/index-B8VoE0M4.d.ts +56 -0
  57. package/dist/index-CsTGwtZ0.d.ts +110 -0
  58. package/dist/index-CzdR_Ig9.d.ts +47 -0
  59. package/dist/index-CzpjLzoS.d.ts +180 -0
  60. package/dist/index-D7qe9iKG.d.ts +13 -0
  61. package/dist/index-DdCF5yCg.d.ts +38 -0
  62. package/dist/index-a1Y--85Y.d.ts +41 -0
  63. package/dist/index-ni7Db8Lv.d.ts +86 -0
  64. package/dist/index-sywIP4pt.d.ts +61 -0
  65. package/dist/index.d.ts +17 -27
  66. package/dist/index.js +19 -23
  67. package/dist/introspect/index.d.ts +3 -6
  68. package/dist/introspect/index.js +10 -4
  69. package/dist/introspect/index.js.map +1 -0
  70. package/dist/runner/index.d.ts +2 -4
  71. package/dist/runner/index.js +7 -10
  72. package/dist/runner/index.js.map +1 -0
  73. package/dist/strategies/index.d.ts +3 -5
  74. package/dist/strategies/index.js +13 -9
  75. package/dist/strategies/index.js.map +1 -0
  76. package/package.json +9 -9
  77. package/dist/CollectingBuilder--4fqDQdE.js.map +0 -1
  78. package/dist/CompilerStrategy-_AiXiyjS.js.map +0 -1
  79. package/dist/IntrospectorStrategy-BEIG5GqA.js.map +0 -1
  80. package/dist/Migration-DYQ0hUG7.js.map +0 -1
  81. package/dist/MigrationGenerator-B1p0jHnx.js.map +0 -1
  82. package/dist/MigrationRunner-DomrOZIn.js.map +0 -1
  83. package/dist/MigrationSqlSafetyAdapter-CGRbB2k2.js.map +0 -1
  84. package/dist/SqliteCompilerFactory-BvdJ0kBl.js.map +0 -1
  85. package/dist/SqliteIntrospector-CWwPWhmA.js.map +0 -1
  86. package/dist/builder/contracts/Builder.d.ts +0 -11
  87. package/dist/builder/contracts/ColumnSpec.d.ts +0 -20
  88. package/dist/builder/contracts/ColumnType.d.ts +0 -2
  89. package/dist/builder/contracts/DeleteReferentialAction.d.ts +0 -2
  90. package/dist/builder/contracts/UpdateReferentialAction.d.ts +0 -2
  91. package/dist/builder/contracts/index.d.ts +0 -8
  92. package/dist/builder/ops/OpBuilder.d.ts +0 -129
  93. package/dist/builder/ops/index.d.ts +0 -4
  94. package/dist/builder/runtime/CollectingBuilder.d.ts +0 -39
  95. package/dist/builder/runtime/index.d.ts +0 -4
  96. package/dist/builder-xJ-Bq2pk.js.map +0 -1
  97. package/dist/chunk-BkvOhyD0.js +0 -12
  98. package/dist/cli-7j3R1Y1r.js.map +0 -1
  99. package/dist/commands/cli.d.ts +0 -5
  100. package/dist/commands-Cl2MU7tq.js +0 -10
  101. package/dist/commands-Cl2MU7tq.js.map +0 -1
  102. package/dist/compilers/contracts/CompilerFactory.d.ts +0 -8
  103. package/dist/compilers/contracts/SQL.d.ts +0 -4
  104. package/dist/compilers/contracts/SQLCompiler.d.ts +0 -11
  105. package/dist/compilers/contracts/index.d.ts +0 -6
  106. package/dist/compilers/dialects/PostgresCompiler.d.ts +0 -32
  107. package/dist/compilers/dialects/SqliteCompiler.d.ts +0 -27
  108. package/dist/compilers/dialects/index.d.ts +0 -5
  109. package/dist/compilers/factories/PostgresCompilerFactory.d.ts +0 -17
  110. package/dist/compilers/factories/SqliteCompilerFactory.d.ts +0 -17
  111. package/dist/compilers/factories/index.d.ts +0 -5
  112. package/dist/diff/diffSchema.d.ts +0 -39
  113. package/dist/diff-B9MhagJF.js.map +0 -1
  114. package/dist/domain/Dialect.d.ts +0 -2
  115. package/dist/domain/Migration.d.ts +0 -29
  116. package/dist/domain/MigrationMode.d.ts +0 -2
  117. package/dist/domain/MigrationOperation.d.ts +0 -77
  118. package/dist/domain/internal/InternalColumnType.d.ts +0 -11
  119. package/dist/domain/internal/InternalDialect.d.ts +0 -5
  120. package/dist/domain/internal/InternalMigrationMode.d.ts +0 -5
  121. package/dist/domain/internal/InternalOperationKind.d.ts +0 -14
  122. package/dist/domain/internal/InternalReferentialAction.d.ts +0 -7
  123. package/dist/domain-CwR-kUNS.js +0 -10
  124. package/dist/domain-CwR-kUNS.js.map +0 -1
  125. package/dist/generator/MigrationGenerator.d.ts +0 -48
  126. package/dist/generator-DK-_f-PF.js +0 -10
  127. package/dist/generator-DK-_f-PF.js.map +0 -1
  128. package/dist/internal/MigrationSqlSafetyAdapter.d.ts +0 -24
  129. package/dist/introspect/DatabaseIntrospector.d.ts +0 -17
  130. package/dist/introspect/PostgresIntrospector.d.ts +0 -56
  131. package/dist/introspect/SqliteIntrospector.d.ts +0 -53
  132. package/dist/introspect-DD3fm15e.js +0 -13
  133. package/dist/introspect-DD3fm15e.js.map +0 -1
  134. package/dist/runner/MigrationRunner.d.ts +0 -79
  135. package/dist/runner-C97xT8_W.js +0 -10
  136. package/dist/runner-C97xT8_W.js.map +0 -1
  137. package/dist/runtime/loadModule.d.ts +0 -18
  138. package/dist/schema/buildMigrationModelMetadataProjection.d.ts +0 -3
  139. package/dist/strategies/CompilerStrategy.d.ts +0 -42
  140. package/dist/strategies/IntrospectorStrategy.d.ts +0 -34
  141. package/dist/strategies-HwUWvmLC.js +0 -16
  142. package/dist/strategies-HwUWvmLC.js.map +0 -1
@@ -0,0 +1,145 @@
1
+ import { TrustedSqlFragment } from "@danceroutine/tango-core";
2
+
3
+ //#region src/domain/internal/InternalOperationKind.d.ts
4
+ declare const InternalOperationKind: {
5
+ readonly TABLE_CREATE: "table.create";
6
+ readonly TABLE_DROP: "table.drop";
7
+ readonly COLUMN_ADD: "column.add";
8
+ readonly COLUMN_DROP: "column.drop";
9
+ readonly COLUMN_ALTER: "column.alter";
10
+ readonly COLUMN_RENAME: "column.rename";
11
+ readonly INDEX_CREATE: "index.create";
12
+ readonly INDEX_DROP: "index.drop";
13
+ readonly FK_CREATE: "fk.create";
14
+ readonly FK_VALIDATE: "fk.validate";
15
+ readonly FK_DROP: "fk.drop";
16
+ };
17
+ type InternalOperationKind = (typeof InternalOperationKind)[keyof typeof InternalOperationKind];
18
+ //#endregion
19
+ //#region src/domain/internal/InternalColumnType.d.ts
20
+ declare const InternalColumnType: {
21
+ readonly SERIAL: "serial";
22
+ readonly INT: "int";
23
+ readonly BIGINT: "bigint";
24
+ readonly TEXT: "text";
25
+ readonly BOOL: "bool";
26
+ readonly TIMESTAMPTZ: "timestamptz";
27
+ readonly JSONB: "jsonb";
28
+ readonly UUID: "uuid";
29
+ };
30
+ type InternalColumnType = (typeof InternalColumnType)[keyof typeof InternalColumnType];
31
+ //#endregion
32
+ //#region src/builder/contracts/ColumnType.d.ts
33
+ type ColumnType = (typeof InternalColumnType)[keyof typeof InternalColumnType];
34
+ //#endregion
35
+ //#region src/domain/internal/InternalReferentialAction.d.ts
36
+ declare const InternalReferentialAction: {
37
+ readonly CASCADE: "CASCADE";
38
+ readonly SET_NULL: "SET NULL";
39
+ readonly RESTRICT: "RESTRICT";
40
+ readonly NO_ACTION: "NO ACTION";
41
+ };
42
+ type InternalReferentialAction = (typeof InternalReferentialAction)[keyof typeof InternalReferentialAction];
43
+ //#endregion
44
+ //#region src/builder/contracts/DeleteReferentialAction.d.ts
45
+ type DeleteReferentialAction = (typeof InternalReferentialAction)[keyof typeof InternalReferentialAction];
46
+ //#endregion
47
+ //#region src/builder/contracts/UpdateReferentialAction.d.ts
48
+ type UpdateReferentialAction = Extract<InternalReferentialAction, 'CASCADE' | 'RESTRICT' | 'NO_ACTION'>;
49
+ //#endregion
50
+ //#region src/builder/contracts/ColumnSpec.d.ts
51
+ interface ColumnSpec {
52
+ name: string;
53
+ type: ColumnType;
54
+ notNull?: boolean;
55
+ default?: TrustedSqlFragment | {
56
+ now: true;
57
+ } | null;
58
+ primaryKey?: boolean;
59
+ unique?: boolean;
60
+ references?: {
61
+ table: string;
62
+ column: string;
63
+ onDelete?: DeleteReferentialAction;
64
+ onUpdate?: UpdateReferentialAction;
65
+ };
66
+ }
67
+ //#endregion
68
+ //#region src/domain/MigrationOperation.d.ts
69
+ type TableCreate = {
70
+ kind: typeof InternalOperationKind.TABLE_CREATE;
71
+ table: string;
72
+ columns: ColumnSpec[];
73
+ };
74
+ type TableDrop = {
75
+ kind: typeof InternalOperationKind.TABLE_DROP;
76
+ table: string;
77
+ cascade?: boolean;
78
+ };
79
+ type ColumnAdd = {
80
+ kind: typeof InternalOperationKind.COLUMN_ADD;
81
+ table: string;
82
+ column: ColumnSpec;
83
+ };
84
+ type ColumnDrop = {
85
+ kind: typeof InternalOperationKind.COLUMN_DROP;
86
+ table: string;
87
+ column: string;
88
+ };
89
+ type ColumnAlter = {
90
+ kind: typeof InternalOperationKind.COLUMN_ALTER;
91
+ table: string;
92
+ column: string;
93
+ to: Partial<ColumnSpec>;
94
+ };
95
+ type ColumnRename = {
96
+ kind: typeof InternalOperationKind.COLUMN_RENAME;
97
+ table: string;
98
+ from: string;
99
+ to: string;
100
+ };
101
+ type IndexCreate = {
102
+ kind: typeof InternalOperationKind.INDEX_CREATE;
103
+ table: string;
104
+ name: string;
105
+ on: string[];
106
+ unique?: boolean;
107
+ where?: TrustedSqlFragment;
108
+ concurrently?: boolean;
109
+ };
110
+ type IndexDrop = {
111
+ kind: typeof InternalOperationKind.INDEX_DROP;
112
+ table: string;
113
+ name: string;
114
+ concurrently?: boolean;
115
+ };
116
+ type ForeignKeyCreate = {
117
+ kind: typeof InternalOperationKind.FK_CREATE;
118
+ table: string;
119
+ name?: string;
120
+ columns: string[];
121
+ refTable: string;
122
+ refColumns: string[];
123
+ onDelete?: string;
124
+ onUpdate?: string;
125
+ notValid?: boolean;
126
+ };
127
+ type ForeignKeyValidate = {
128
+ kind: typeof InternalOperationKind.FK_VALIDATE;
129
+ table: string;
130
+ name: string;
131
+ };
132
+ type ForeignKeyDrop = {
133
+ kind: typeof InternalOperationKind.FK_DROP;
134
+ table: string;
135
+ name: string;
136
+ };
137
+ type CustomMigrationOperation<TName extends string = string, TArgs extends object = Record<string, unknown>> = {
138
+ kind: 'custom';
139
+ name: TName;
140
+ args: TArgs;
141
+ };
142
+ type MigrationOperation = TableCreate | TableDrop | ColumnAdd | ColumnDrop | ColumnAlter | ColumnRename | IndexCreate | IndexDrop | ForeignKeyCreate | ForeignKeyValidate | ForeignKeyDrop | CustomMigrationOperation;
143
+ //#endregion
144
+ export { ColumnType as _, CustomMigrationOperation as a, ForeignKeyValidate as c, MigrationOperation as d, TableCreate as f, DeleteReferentialAction as g, UpdateReferentialAction as h, ColumnRename as i, IndexCreate as l, ColumnSpec as m, ColumnAlter as n, ForeignKeyCreate as o, TableDrop as p, ColumnDrop as r, ForeignKeyDrop as s, ColumnAdd as t, IndexDrop as u };
145
+ //# sourceMappingURL=MigrationOperation-qpdhPEs9.d.ts.map
@@ -1,13 +1,12 @@
1
- import { CollectingBuilder } from "./CollectingBuilder--4fqDQdE.js";
2
- import { Migration } from "./Migration-DYQ0hUG7.js";
3
- import { InternalDialect, createDefaultCompilerStrategy } from "./CompilerStrategy-_AiXiyjS.js";
4
- import { readdir } from "node:fs/promises";
5
- import { extname, resolve, resolve as resolve$1 } from "node:path";
1
+ import { t as Migration } from "./Migration-DxHHPyzn.js";
2
+ import { t as CollectingBuilder } from "./CollectingBuilder-BIfAKs_x.js";
3
+ import { n as createDefaultCompilerStrategy, r as InternalDialect } from "./CompilerStrategy-vcZKg8qf.js";
6
4
  import { isError } from "@danceroutine/tango-core";
5
+ import { readdir } from "node:fs/promises";
6
+ import { extname, resolve } from "node:path";
7
7
  import { pathToFileURL } from "node:url";
8
8
  import { createJiti } from "jiti";
9
9
  import { ModelRegistry } from "@danceroutine/tango-schema";
10
-
11
10
  //#region src/runtime/loadModule.ts
12
11
  const TS_EXTENSIONS = new Set([
13
12
  ".ts",
@@ -16,36 +15,68 @@ const TS_EXTENSIONS = new Set([
16
15
  ".cts"
17
16
  ]);
18
17
  function toAbsolutePath(modulePath, projectRoot) {
19
- return resolve$1(projectRoot, modulePath);
18
+ return resolve(projectRoot, modulePath);
20
19
  }
21
20
  function isTypeScriptModule(modulePath) {
22
21
  return TS_EXTENSIONS.has(extname(modulePath).toLowerCase());
23
22
  }
23
+ /**
24
+ * Load a module from a Tango app project root.
25
+ *
26
+ * TypeScript modules are loaded through jiti and JavaScript/ESM modules are loaded
27
+ * through native dynamic import so published installs behave like end-user runtime.
28
+ */
24
29
  async function loadModule(modulePath, options) {
25
30
  const projectRoot = options?.projectRoot ?? process.cwd();
26
31
  const absolutePath = toAbsolutePath(modulePath, projectRoot);
27
32
  const executeImport = async () => {
28
- if (isTypeScriptModule(absolutePath)) {
29
- const jiti = createJiti(resolve$1(projectRoot, "tango.config.ts"), {
30
- interopDefault: true,
31
- moduleCache: options?.moduleCache ?? true
32
- });
33
- return await jiti.import(absolutePath);
34
- }
33
+ if (isTypeScriptModule(absolutePath)) return await createJiti(resolve(projectRoot, "tango.config.ts"), {
34
+ interopDefault: true,
35
+ moduleCache: options?.moduleCache ?? true
36
+ }).import(absolutePath);
35
37
  return await import(pathToFileURL(absolutePath).href);
36
38
  };
37
39
  if (options?.registry) return ModelRegistry.runWithRegistry(options.registry, executeImport);
38
40
  return executeImport();
39
41
  }
42
+ /**
43
+ * Load a module and return default export when present.
44
+ */
40
45
  async function loadDefaultExport(modulePath, options) {
41
46
  const loaded = await loadModule(modulePath, options);
42
47
  return loaded.default ?? loaded;
43
48
  }
44
-
45
49
  //#endregion
46
50
  //#region src/runner/MigrationRunner.ts
47
51
  const JOURNAL = "_tango_migrations";
52
+ /**
53
+ * Manages the lifecycle of database migrations: applying, planning, and tracking status.
54
+ *
55
+ * The runner reads migration files from a directory, compiles operations to SQL
56
+ * for the target dialect, and maintains a journal table to track which migrations
57
+ * have been applied. Each applied migration is checksummed to detect tampering.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const runner = new MigrationRunner(client, 'postgres', './migrations');
62
+ *
63
+ * // Apply all pending migrations
64
+ * await runner.apply();
65
+ *
66
+ * // Apply up to a specific migration
67
+ * await runner.apply('003_add_indexes');
68
+ *
69
+ * // Preview the SQL that would be generated
70
+ * const sql = await runner.plan();
71
+ *
72
+ * // Check which migrations are applied
73
+ * const statuses = await runner.status();
74
+ * ```
75
+ */
48
76
  var MigrationRunner = class MigrationRunner {
77
+ client;
78
+ dialect;
79
+ migrationsDir;
49
80
  static BRAND = "tango.migrations.runner";
50
81
  __tangoBrand = MigrationRunner.BRAND;
51
82
  compilerStrategy;
@@ -86,8 +117,7 @@ var MigrationRunner = class MigrationRunner {
86
117
  migrations.forEach((migration) => {
87
118
  const builder = new CollectingBuilder();
88
119
  migration.up(builder);
89
- const preparedOps = this.compilerStrategy.prepareOperations(this.dialect, builder.ops);
90
- const sqls = preparedOps.flatMap((op) => this.compileOperation(op));
120
+ const sqls = this.compilerStrategy.prepareOperations(this.dialect, builder.ops).flatMap((op) => this.compileOperation(op));
91
121
  output += `# ${migration.id}\n`;
92
122
  sqls.forEach((statement) => {
93
123
  output += statement.sql + ";\n";
@@ -102,8 +132,7 @@ var MigrationRunner = class MigrationRunner {
102
132
  */
103
133
  async status() {
104
134
  const applied = await this.listApplied();
105
- const migrations = await this.loadMigrations();
106
- return migrations.map((m) => ({
135
+ return (await this.loadMigrations()).map((m) => ({
107
136
  id: m.id,
108
137
  applied: applied.has(m.id)
109
138
  }));
@@ -152,8 +181,7 @@ var MigrationRunner = class MigrationRunner {
152
181
  async applyMigration(migration) {
153
182
  const builder = new CollectingBuilder();
154
183
  await migration.up(builder);
155
- const preparedOps = this.compilerStrategy.prepareOperations(this.dialect, builder.ops);
156
- const sqls = preparedOps.flatMap((op) => this.compileOperation(op));
184
+ const sqls = this.compilerStrategy.prepareOperations(this.dialect, builder.ops).flatMap((op) => this.compileOperation(op));
157
185
  const checksum = String(this.hashJSON(builder.ops));
158
186
  const isOnline = (migration.mode ?? builder.getMode()) === "online";
159
187
  if (!isOnline && this.dialect === InternalDialect.POSTGRES) await this.client.query("BEGIN");
@@ -188,7 +216,7 @@ var MigrationRunner = class MigrationRunner {
188
216
  return this.compilerStrategy.compile(this.dialect, op);
189
217
  }
190
218
  };
191
-
192
219
  //#endregion
193
- export { MigrationRunner, loadModule };
194
- //# sourceMappingURL=MigrationRunner-DomrOZIn.js.map
220
+ export { loadModule as n, MigrationRunner as t };
221
+
222
+ //# sourceMappingURL=MigrationRunner-B5AJel12.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MigrationRunner-B5AJel12.js","names":[],"sources":["../src/runtime/loadModule.ts","../src/runner/MigrationRunner.ts"],"sourcesContent":["import { resolve, extname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport { ModelRegistry } from '@danceroutine/tango-schema';\n\nconst TS_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);\n\nfunction toAbsolutePath(modulePath: string, projectRoot: string): string {\n return resolve(projectRoot, modulePath);\n}\n\nfunction isTypeScriptModule(modulePath: string): boolean {\n return TS_EXTENSIONS.has(extname(modulePath).toLowerCase());\n}\n\n/**\n * Load a module from a Tango app project root.\n *\n * TypeScript modules are loaded through jiti and JavaScript/ESM modules are loaded\n * through native dynamic import so published installs behave like end-user runtime.\n */\nexport async function loadModule(\n modulePath: string,\n options?: { projectRoot?: string; registry?: ModelRegistry; moduleCache?: boolean }\n): Promise<Record<string, unknown>> {\n const projectRoot = options?.projectRoot ?? process.cwd();\n const absolutePath = toAbsolutePath(modulePath, projectRoot);\n const executeImport = async (): Promise<Record<string, unknown>> => {\n if (isTypeScriptModule(absolutePath)) {\n const jiti = createJiti(resolve(projectRoot, 'tango.config.ts'), {\n interopDefault: true,\n moduleCache: options?.moduleCache ?? true,\n });\n return (await jiti.import<Record<string, unknown>>(absolutePath)) as Record<string, unknown>;\n }\n\n return (await import(pathToFileURL(absolutePath).href)) as Record<string, unknown>;\n };\n\n if (options?.registry) {\n return ModelRegistry.runWithRegistry(options.registry, executeImport);\n }\n\n return executeImport();\n}\n\n/**\n * Load a module and return default export when present.\n */\nexport async function loadDefaultExport(modulePath: string, options?: { projectRoot?: string }): Promise<unknown> {\n const loaded = await loadModule(modulePath, options);\n return loaded.default ?? loaded;\n}\n","import { CollectingBuilder } from '../builder/runtime/CollectingBuilder';\nimport type { Dialect } from '../domain/Dialect';\nimport { Migration } from '../domain/Migration';\nimport type { SQL } from '../compilers/contracts/SQL';\nimport type { MigrationOperation } from '../domain/MigrationOperation';\nimport type { CompilerStrategy } from '../strategies/CompilerStrategy';\nimport { createDefaultCompilerStrategy } from '../strategies/CompilerStrategy';\nimport { InternalDialect } from '../domain/internal/InternalDialect';\nimport { isError } from '@danceroutine/tango-core';\nimport { readdir } from 'node:fs/promises';\nimport { resolve } from 'node:path';\nimport { loadDefaultExport } from '../runtime/loadModule';\n\nconst JOURNAL = '_tango_migrations';\n\n/** DB client contract required by migration execution. */\ninterface DBClient {\n /** Execute SQL with optional parameters. */\n query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }>;\n /** Release underlying database resources. */\n close(): Promise<void>;\n}\n\n/**\n * Manages the lifecycle of database migrations: applying, planning, and tracking status.\n *\n * The runner reads migration files from a directory, compiles operations to SQL\n * for the target dialect, and maintains a journal table to track which migrations\n * have been applied. Each applied migration is checksummed to detect tampering.\n *\n * @example\n * ```typescript\n * const runner = new MigrationRunner(client, 'postgres', './migrations');\n *\n * // Apply all pending migrations\n * await runner.apply();\n *\n * // Apply up to a specific migration\n * await runner.apply('003_add_indexes');\n *\n * // Preview the SQL that would be generated\n * const sql = await runner.plan();\n *\n * // Check which migrations are applied\n * const statuses = await runner.status();\n * ```\n */\nexport class MigrationRunner {\n static readonly BRAND = 'tango.migrations.runner' as const;\n readonly __tangoBrand: typeof MigrationRunner.BRAND = MigrationRunner.BRAND;\n private compilerStrategy: CompilerStrategy;\n\n constructor(\n private client: DBClient,\n private dialect: Dialect,\n private migrationsDir: string = 'migrations',\n compilerStrategy?: CompilerStrategy\n ) {\n this.compilerStrategy = compilerStrategy ?? createDefaultCompilerStrategy();\n }\n\n /**\n * Narrow an unknown value to `MigrationRunner`.\n */\n static isMigrationRunner(value: unknown): value is MigrationRunner {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === MigrationRunner.BRAND\n );\n }\n\n /**\n * Apply all pending migrations, optionally stopping at a specific migration ID.\n * Migrations are applied in file-sort order. Already-applied migrations are skipped.\n * Non-online migrations are wrapped in a transaction on Postgres.\n */\n async apply(toId?: string): Promise<void> {\n await this.ensureJournal();\n const applied = await this.listApplied();\n const migrations = await this.loadMigrations();\n\n for (const migration of migrations) {\n if (toId && migration.id > toId) {\n break;\n }\n if (applied.has(migration.id)) {\n continue;\n }\n\n await this.applyMigration(migration);\n }\n }\n\n /**\n * Generate a dry-run SQL plan for all migrations without executing anything.\n * Useful for reviewing what SQL would be run before applying.\n */\n async plan(): Promise<string> {\n const migrations = await this.loadMigrations();\n let output = '';\n\n migrations.forEach((migration) => {\n const builder = new CollectingBuilder();\n migration.up(builder);\n const preparedOps = this.compilerStrategy.prepareOperations(this.dialect, builder.ops);\n const sqls = preparedOps.flatMap((op) => this.compileOperation(op));\n\n output += `# ${migration.id}\\n`;\n sqls.forEach((statement) => {\n output += statement.sql + ';\\n';\n });\n if (builder.dataFns.length) {\n output += '-- (data step present)\\n';\n }\n output += '\\n';\n });\n\n return output;\n }\n\n /**\n * Return the applied/pending status of every migration found on disk.\n */\n async status(): Promise<{ id: string; applied: boolean }[]> {\n const applied = await this.listApplied();\n const migrations = await this.loadMigrations();\n\n return migrations.map((m) => ({\n id: m.id,\n applied: applied.has(m.id),\n }));\n }\n\n private async ensureJournal(): Promise<void> {\n const sql =\n this.dialect === InternalDialect.POSTGRES\n ? `CREATE TABLE IF NOT EXISTS \"${JOURNAL}\" (\n id TEXT PRIMARY KEY,\n applied_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n checksum TEXT NOT NULL\n )`\n : `CREATE TABLE IF NOT EXISTS ${JOURNAL} (\n id TEXT PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now')),\n checksum TEXT NOT NULL\n )`;\n\n await this.client.query(sql);\n }\n\n private async listApplied(): Promise<Set<string>> {\n const table = this.dialect === InternalDialect.POSTGRES ? `\"${JOURNAL}\"` : JOURNAL;\n const { rows } = await this.client.query<{ id: string }>(`SELECT id FROM ${table}`);\n return new Set(rows.map((r) => r.id));\n }\n\n private async loadMigrations(): Promise<Migration[]> {\n const files = (await readdir(this.migrationsDir)).filter((f) => f.endsWith('.ts') || f.endsWith('.js')).sort();\n\n const migrations: Migration[] = [];\n\n for (const file of files) {\n const absolutePath = resolve(this.migrationsDir, file);\n let loaded: unknown;\n try {\n loaded = await loadDefaultExport(absolutePath, { projectRoot: process.cwd() });\n } catch (error) {\n const reason = isError(error) ? error.message : String(error);\n throw new Error(`Failed to load migration module '${file}': ${reason}`, { cause: error });\n }\n\n if (Migration.isMigration(loaded)) {\n migrations.push(loaded);\n continue;\n }\n\n if (Migration.isMigrationConstructor(loaded)) {\n migrations.push(new loaded());\n continue;\n }\n\n throw new Error(\n `Invalid migration module '${file}'. Default export must be a Migration subclass or instance.`\n );\n }\n\n return migrations;\n }\n\n private async applyMigration(migration: Migration): Promise<void> {\n const builder = new CollectingBuilder();\n await migration.up(builder);\n\n const preparedOps = this.compilerStrategy.prepareOperations(this.dialect, builder.ops);\n const sqls = preparedOps.flatMap((op) => this.compileOperation(op));\n const checksum = String(this.hashJSON(builder.ops));\n\n const isOnline = (migration.mode ?? builder.getMode()) === 'online';\n\n if (!isOnline && this.dialect === InternalDialect.POSTGRES) {\n await this.client.query('BEGIN');\n }\n\n try {\n for (const statement of sqls) {\n await this.client.query(statement.sql, statement.params);\n }\n\n for (const fn of builder.dataFns) {\n await fn({ query: (sql, params) => this.client.query(sql, params).then(() => {}) });\n }\n\n const table = this.dialect === InternalDialect.POSTGRES ? `\"${JOURNAL}\"` : JOURNAL;\n const placeholder = this.dialect === InternalDialect.POSTGRES ? '$1, $2' : '?, ?';\n await this.client.query(`INSERT INTO ${table} (id, checksum) VALUES (${placeholder})`, [\n migration.id,\n checksum,\n ]);\n\n if (!isOnline && this.dialect === InternalDialect.POSTGRES) {\n await this.client.query('COMMIT');\n }\n } catch (error) {\n if (!isOnline && this.dialect === InternalDialect.POSTGRES) {\n await this.client.query('ROLLBACK');\n }\n throw error;\n }\n }\n\n /**\n * Compute a simple hash of the migration's operation list.\n * Stored alongside each applied migration in the journal table to detect\n * if a migration file has been modified after it was already applied.\n * Uses a djb2-like hash over the JSON-serialized operations.\n */\n private hashJSON(x: unknown): number {\n const s = JSON.stringify(x);\n let h = 0;\n for (let i = 0; i < s.length; i++) {\n // oxlint-disable-next-line prefer-code-point\n h = Math.imul(31, h) + s.charCodeAt(i);\n // oxlint-disable-next-line prefer-math-trunc\n h = h | 0;\n }\n // oxlint-disable-next-line unicorn/prefer-math-trunc\n return h >>> 0;\n }\n\n private compileOperation(op: MigrationOperation): SQL[] {\n return this.compilerStrategy.compile(this.dialect, op);\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,12 @@
1
1
  import { SqlSafetyEngine, isTrustedSqlFragment, quoteSqlIdentifier } from "@danceroutine/tango-core";
2
-
3
2
  //#region src/internal/MigrationSqlSafetyAdapter.ts
3
+ /**
4
+ * Migrations-local adapter that maps migration operations into the shared SQL
5
+ * safety engine and returns quoted identifiers or trusted raw fragments.
6
+ */
4
7
  var MigrationSqlSafetyAdapter = class {
8
+ dialect;
9
+ engine;
5
10
  constructor(dialect, engine = new SqlSafetyEngine()) {
6
11
  this.dialect = dialect;
7
12
  this.engine = engine;
@@ -31,11 +36,11 @@ var MigrationSqlSafetyAdapter = class {
31
36
  }] }).rawFragments[key].sql;
32
37
  }
33
38
  optionalRawFragment(key, value) {
34
- if (!value) return undefined;
39
+ if (!value) return;
35
40
  return this.rawFragment(key, value);
36
41
  }
37
42
  rawDefault(value, nowSql) {
38
- if (value === undefined) return undefined;
43
+ if (value === void 0) return;
39
44
  if (value === null) return null;
40
45
  if (this.isNowDefault(value)) return nowSql;
41
46
  return this.rawFragment("default", value);
@@ -44,19 +49,18 @@ var MigrationSqlSafetyAdapter = class {
44
49
  return isTrustedSqlFragment(value);
45
50
  }
46
51
  quote(key, role, value, allowlist) {
47
- const validated = this.engine.validate({ identifiers: [{
52
+ return quoteSqlIdentifier(this.engine.validate({ identifiers: [{
48
53
  key,
49
54
  role,
50
55
  value,
51
56
  allowlist
52
- }] });
53
- return quoteSqlIdentifier(validated.identifiers[key], this.dialect);
57
+ }] }).identifiers[key], this.dialect);
54
58
  }
55
59
  isNowDefault(value) {
56
60
  return typeof value === "object" && value !== null && "now" in value && value.now === true;
57
61
  }
58
62
  };
59
-
60
63
  //#endregion
61
- export { MigrationSqlSafetyAdapter };
62
- //# sourceMappingURL=MigrationSqlSafetyAdapter-CGRbB2k2.js.map
64
+ export { MigrationSqlSafetyAdapter as t };
65
+
66
+ //# sourceMappingURL=MigrationSqlSafetyAdapter-yP6fPjeC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MigrationSqlSafetyAdapter-yP6fPjeC.js","names":[],"sources":["../src/internal/MigrationSqlSafetyAdapter.ts"],"sourcesContent":["import {\n SqlSafetyEngine,\n isTrustedSqlFragment,\n quoteSqlIdentifier,\n type SqlDialect,\n type SqlIdentifierRole,\n type TrustedSqlFragment,\n} from '@danceroutine/tango-core';\n\ntype IdentifierRole = Extract<SqlIdentifierRole, 'table' | 'column' | 'index' | 'constraint' | 'schema'>;\n\n/**\n * Migrations-local adapter that maps migration operations into the shared SQL\n * safety engine and returns quoted identifiers or trusted raw fragments.\n */\nexport class MigrationSqlSafetyAdapter {\n constructor(\n private readonly dialect: SqlDialect,\n private readonly engine: SqlSafetyEngine = new SqlSafetyEngine()\n ) {}\n\n table(value: string): string {\n return this.quote('table', 'table', value);\n }\n\n column(value: string, allowlist?: readonly string[]): string {\n return this.quote('column', 'column', value, allowlist);\n }\n\n columns(values: readonly string[], allowlist?: readonly string[]): string[] {\n return values.map((value, index) => this.quote(`column:${index}`, 'column', value, allowlist));\n }\n\n index(value: string): string {\n return this.quote('index', 'index', value);\n }\n\n constraint(value: string): string {\n return this.quote('constraint', 'constraint', value);\n }\n\n schema(value: string): string {\n return this.quote('schema', 'schema', value);\n }\n\n rawFragment(key: string, value: TrustedSqlFragment): string {\n return this.engine.validate({\n rawFragments: [{ key, value }],\n }).rawFragments[key]!.sql;\n }\n\n optionalRawFragment(key: string, value?: TrustedSqlFragment): string | undefined {\n if (!value) {\n return undefined;\n }\n\n return this.rawFragment(key, value);\n }\n\n rawDefault(\n value: TrustedSqlFragment | { now: true } | null | undefined,\n nowSql: string\n ): string | null | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (value === null) {\n return null;\n }\n\n if (this.isNowDefault(value)) {\n return nowSql;\n }\n\n return this.rawFragment('default', value);\n }\n\n isTrustedFragment(value: unknown): value is TrustedSqlFragment {\n return isTrustedSqlFragment(value);\n }\n\n private quote(key: string, role: IdentifierRole, value: string, allowlist?: readonly string[]): string {\n const validated = this.engine.validate({\n identifiers: [{ key, role, value, allowlist }],\n });\n\n return quoteSqlIdentifier(validated.identifiers[key]!, this.dialect);\n }\n\n private isNowDefault(value: TrustedSqlFragment | { now: true }): value is { now: true } {\n return typeof value === 'object' && value !== null && 'now' in value && value.now === true;\n }\n}\n"],"mappings":";;;;;;AAeA,IAAa,4BAAb,MAAuC;CAEd;CACA;CAFrB,YACI,SACA,SAA2C,IAAI,gBAAgB,GACjE;EAFmB,KAAA,UAAA;EACA,KAAA,SAAA;CAClB;CAEH,MAAM,OAAuB;EACzB,OAAO,KAAK,MAAM,SAAS,SAAS,KAAK;CAC7C;CAEA,OAAO,OAAe,WAAuC;EACzD,OAAO,KAAK,MAAM,UAAU,UAAU,OAAO,SAAS;CAC1D;CAEA,QAAQ,QAA2B,WAAyC;EACxE,OAAO,OAAO,KAAK,OAAO,UAAU,KAAK,MAAM,UAAU,SAAS,UAAU,OAAO,SAAS,CAAC;CACjG;CAEA,MAAM,OAAuB;EACzB,OAAO,KAAK,MAAM,SAAS,SAAS,KAAK;CAC7C;CAEA,WAAW,OAAuB;EAC9B,OAAO,KAAK,MAAM,cAAc,cAAc,KAAK;CACvD;CAEA,OAAO,OAAuB;EAC1B,OAAO,KAAK,MAAM,UAAU,UAAU,KAAK;CAC/C;CAEA,YAAY,KAAa,OAAmC;EACxD,OAAO,KAAK,OAAO,SAAS,EACxB,cAAc,CAAC;GAAE;GAAK;EAAM,CAAC,EACjC,CAAC,EAAE,aAAa,KAAM;CAC1B;CAEA,oBAAoB,KAAa,OAAgD;EAC7E,IAAI,CAAC,OACD;EAGJ,OAAO,KAAK,YAAY,KAAK,KAAK;CACtC;CAEA,WACI,OACA,QACyB;EACzB,IAAI,UAAU,KAAA,GACV;EAGJ,IAAI,UAAU,MACV,OAAO;EAGX,IAAI,KAAK,aAAa,KAAK,GACvB,OAAO;EAGX,OAAO,KAAK,YAAY,WAAW,KAAK;CAC5C;CAEA,kBAAkB,OAA6C;EAC3D,OAAO,qBAAqB,KAAK;CACrC;CAEA,MAAc,KAAa,MAAsB,OAAe,WAAuC;EAKnG,OAAO,mBAJW,KAAK,OAAO,SAAS,EACnC,aAAa,CAAC;GAAE;GAAK;GAAM;GAAO;EAAU,CAAC,EACjD,CAEkC,EAAE,YAAY,MAAO,KAAK,OAAO;CACvE;CAEA,aAAqB,OAAmE;EACpF,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,SAAS,SAAS,MAAM,QAAQ;CAC1F;AACJ"}
@@ -0,0 +1,77 @@
1
+ //#region src/introspect/DatabaseIntrospector.d.ts
2
+ /**
3
+ * Minimal DB client shape required by schema introspection.
4
+ */
5
+ interface DBClient {
6
+ /** Execute a SQL statement and return row results. */
7
+ query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
8
+ rows: T[];
9
+ }>;
10
+ }
11
+ /**
12
+ * Dialect-specific schema introspection contract.
13
+ */
14
+ interface DatabaseIntrospector {
15
+ /** Read the current database schema state. */
16
+ introspect(client: DBClient): Promise<DbSchema>;
17
+ }
18
+ //#endregion
19
+ //#region src/introspect/PostgresIntrospector.d.ts
20
+ /** Introspected column metadata. */
21
+ interface DbColumn {
22
+ name: string;
23
+ type: string;
24
+ notNull: boolean;
25
+ default: string | null;
26
+ isPk: boolean;
27
+ isUnique: boolean;
28
+ }
29
+ /** Introspected index metadata. */
30
+ interface DbIndex {
31
+ name: string;
32
+ table: string;
33
+ unique: boolean;
34
+ columns: string[];
35
+ where: string | null;
36
+ }
37
+ /** Introspected foreign key metadata. */
38
+ interface DbForeignKey {
39
+ name: string;
40
+ table: string;
41
+ columns: string[];
42
+ refTable: string;
43
+ refColumns: string[];
44
+ onDelete: string | null;
45
+ onUpdate: string | null;
46
+ validated: boolean;
47
+ }
48
+ /** Introspected table metadata. */
49
+ interface DbTable {
50
+ name: string;
51
+ columns: Record<string, DbColumn>;
52
+ pks: string[];
53
+ indexes: Record<string, DbIndex>;
54
+ fks: Record<string, DbForeignKey>;
55
+ }
56
+ /** Introspected schema metadata. */
57
+ interface DbSchema {
58
+ tables: Record<string, DbTable>;
59
+ }
60
+ /**
61
+ * PostgreSQL implementation of schema introspection.
62
+ */
63
+ declare class PostgresIntrospector implements DatabaseIntrospector {
64
+ static readonly BRAND: "tango.migrations.postgres_introspector";
65
+ readonly __tangoBrand: typeof PostgresIntrospector.BRAND;
66
+ /**
67
+ * Narrow an unknown value to the PostgreSQL schema introspector.
68
+ */
69
+ static isPostgresIntrospector(value: unknown): value is PostgresIntrospector;
70
+ /**
71
+ * Read table and column metadata from PostgreSQL system catalogs.
72
+ */
73
+ introspect(client: DBClient): Promise<DbSchema>;
74
+ }
75
+ //#endregion
76
+ export { DbTable as a, DatabaseIntrospector as c, DbSchema as i, DbForeignKey as n, PostgresIntrospector as o, DbIndex as r, DBClient as s, DbColumn as t };
77
+ //# sourceMappingURL=PostgresIntrospector-DQDTZUW_.d.ts.map
@@ -1,8 +1,10 @@
1
- import { InternalOperationKind } from "./InternalOperationKind-Bt6Weuon.js";
2
- import { InternalColumnType } from "./InternalColumnType-G9zV9StN.js";
3
- import { MigrationSqlSafetyAdapter } from "./MigrationSqlSafetyAdapter-CGRbB2k2.js";
4
-
1
+ import { t as InternalColumnType } from "./InternalColumnType-Dzs9T6a6.js";
2
+ import { t as InternalOperationKind } from "./InternalOperationKind-M4a4H9OZ.js";
3
+ import { t as MigrationSqlSafetyAdapter } from "./MigrationSqlSafetyAdapter-yP6fPjeC.js";
5
4
  //#region src/compilers/dialects/PostgresCompiler.ts
5
+ /**
6
+ * PostgreSQL SQL compiler for migration operations.
7
+ */
6
8
  var PostgresCompiler = class PostgresCompiler {
7
9
  static BRAND = "tango.migrations.postgres_compiler";
8
10
  __tangoBrand = PostgresCompiler.BRAND;
@@ -21,7 +23,7 @@ var PostgresCompiler = class PostgresCompiler {
21
23
  const tableCreates = [];
22
24
  const remainder = [];
23
25
  for (const operation of operations) if (operation.kind === InternalOperationKind.TABLE_CREATE) tableCreates.push(operation);
24
- else remainder.push(operation);
26
+ else remainder.push(operation);
25
27
  const strippedCreates = [];
26
28
  const foreignKeys = [];
27
29
  for (const operation of tableCreates) {
@@ -54,9 +56,8 @@ else remainder.push(operation);
54
56
  constraints.push(fk);
55
57
  });
56
58
  const allParts = [cols, ...constraints].join(", ");
57
- const sql = `CREATE TABLE ${this.sqlSafety.table(op.table)} (${allParts})`;
58
59
  return [{
59
- sql,
60
+ sql: `CREATE TABLE ${this.sqlSafety.table(op.table)} (${allParts})`,
60
61
  params: []
61
62
  }];
62
63
  }
@@ -78,7 +79,7 @@ else remainder.push(operation);
78
79
  sql: `ALTER TABLE ${this.sqlSafety.table(op.table)} ALTER COLUMN ${this.sqlSafety.column(op.column)} TYPE ${this.typeToSQL(op.to.type)}`,
79
80
  params: []
80
81
  });
81
- if (op.to.notNull !== undefined) out.push({
82
+ if (op.to.notNull !== void 0) out.push({
82
83
  sql: `ALTER TABLE ${this.sqlSafety.table(op.table)} ALTER COLUMN ${this.sqlSafety.column(op.column)} ${op.to.notNull ? "SET NOT NULL" : "DROP NOT NULL"}`,
83
84
  params: []
84
85
  });
@@ -99,13 +100,10 @@ else remainder.push(operation);
99
100
  params: []
100
101
  }];
101
102
  }
102
- case InternalOperationKind.INDEX_DROP: {
103
- const conc = op.concurrently ? "CONCURRENTLY " : "";
104
- return [{
105
- sql: `DROP INDEX ${conc}${this.sqlSafety.index(op.name)}`,
106
- params: []
107
- }];
108
- }
103
+ case InternalOperationKind.INDEX_DROP: return [{
104
+ sql: `DROP INDEX ${op.concurrently ? "CONCURRENTLY " : ""}${this.sqlSafety.index(op.name)}`,
105
+ params: []
106
+ }];
109
107
  case InternalOperationKind.FK_CREATE: {
110
108
  const cols = this.sqlSafety.columns(op.columns).join(", ");
111
109
  const refs = this.sqlSafety.columns(op.refColumns).join(", ");
@@ -134,7 +132,7 @@ else remainder.push(operation);
134
132
  * Extracted to flatten the nested conditional logic.
135
133
  */
136
134
  compileDefaultChange(table, column, defaultValue) {
137
- if (defaultValue === undefined) return [];
135
+ if (defaultValue === void 0) return [];
138
136
  if (defaultValue === null) return [{
139
137
  sql: `ALTER TABLE ${this.sqlSafety.table(table)} ALTER COLUMN ${this.sqlSafety.column(column)} DROP DEFAULT`,
140
138
  params: []
@@ -163,7 +161,7 @@ else remainder.push(operation);
163
161
  onDelete: references.onDelete,
164
162
  onUpdate: references.onUpdate
165
163
  });
166
- const { references: _references,...rest } = column;
164
+ const { references: _references, ...rest } = column;
167
165
  return { ...rest };
168
166
  });
169
167
  return {
@@ -218,16 +216,15 @@ else remainder.push(operation);
218
216
  case InternalColumnType.TIMESTAMPTZ: return "TIMESTAMPTZ";
219
217
  case InternalColumnType.JSONB: return "JSONB";
220
218
  case InternalColumnType.UUID: return "UUID";
221
- default: {
222
- const exhaustive = type;
223
- throw new Error(`Unsupported column type: ${exhaustive}`);
224
- }
219
+ default: throw new Error(`Unsupported column type: ${type}`);
225
220
  }
226
221
  }
227
222
  };
228
-
229
223
  //#endregion
230
224
  //#region src/compilers/factories/PostgresCompilerFactory.ts
225
+ /**
226
+ * Factory for PostgreSQL migration compilers.
227
+ */
231
228
  var PostgresCompilerFactory = class PostgresCompilerFactory {
232
229
  static BRAND = "tango.migrations.postgres_compiler_factory";
233
230
  __tangoBrand = PostgresCompilerFactory.BRAND;
@@ -244,9 +241,11 @@ var PostgresCompilerFactory = class PostgresCompilerFactory {
244
241
  return new PostgresCompiler();
245
242
  }
246
243
  };
247
-
248
244
  //#endregion
249
245
  //#region src/compilers/dialects/SqliteCompiler.ts
246
+ /**
247
+ * SQLite SQL compiler for migration operations.
248
+ */
250
249
  var SqliteCompiler = class SqliteCompiler {
251
250
  static BRAND = "tango.migrations.sqlite_compiler";
252
251
  __tangoBrand = SqliteCompiler.BRAND;
@@ -265,7 +264,7 @@ var SqliteCompiler = class SqliteCompiler {
265
264
  const tableCreates = [];
266
265
  const remainder = [];
267
266
  for (const operation of operations) if (operation.kind === InternalOperationKind.TABLE_CREATE) tableCreates.push(operation);
268
- else remainder.push(operation);
267
+ else remainder.push(operation);
269
268
  const preparedRemainder = remainder.flatMap((operation) => operation.kind === InternalOperationKind.COLUMN_ADD ? this.prepareColumnAdd(operation) : [operation]);
270
269
  return [...this.topologicalSortTableCreatesWithReferences(tableCreates), ...preparedRemainder];
271
270
  }
@@ -282,9 +281,8 @@ else remainder.push(operation);
282
281
  const references = column.references;
283
282
  cols.push(`FOREIGN KEY (${this.sqlSafety.column(column.name)}) REFERENCES ${this.sqlSafety.table(references.table)}(${this.sqlSafety.column(references.column)})${references.onDelete ? ` ON DELETE ${references.onDelete}` : ""}${references.onUpdate ? ` ON UPDATE ${references.onUpdate}` : ""}`);
284
283
  });
285
- const sql = `CREATE TABLE ${this.sqlSafety.table(op.table)} (${cols.join(", ")})`;
286
284
  return [{
287
- sql,
285
+ sql: `CREATE TABLE ${this.sqlSafety.table(op.table)} (${cols.join(", ")})`,
288
286
  params: []
289
287
  }];
290
288
  }
@@ -363,33 +361,31 @@ else remainder.push(operation);
363
361
  }
364
362
  prepareColumnAdd(op) {
365
363
  const preparedColumn = op.column;
366
- if (preparedColumn.notNull && preparedColumn.default === undefined && !preparedColumn.primaryKey) throw new Error(`SQLite cannot add NOT NULL column '${preparedColumn.name}' to '${op.table}' without a default or backfill path.`);
364
+ if (preparedColumn.notNull && preparedColumn.default === void 0 && !preparedColumn.primaryKey) throw new Error(`SQLite cannot add NOT NULL column '${preparedColumn.name}' to '${op.table}' without a default or backfill path.`);
367
365
  if (!preparedColumn.unique) return [op];
368
- const addColumn = {
366
+ return [{
369
367
  ...op,
370
368
  column: {
371
369
  ...preparedColumn,
372
370
  unique: false
373
371
  }
374
- };
375
- const createIndex = {
372
+ }, {
376
373
  kind: InternalOperationKind.INDEX_CREATE,
377
374
  name: `${op.table}_${preparedColumn.name}_idx`,
378
375
  table: op.table,
379
376
  on: [preparedColumn.name],
380
377
  unique: true
381
- };
382
- return [addColumn, createIndex];
378
+ }];
383
379
  }
384
380
  topologicalSortTableCreatesWithReferences(creates) {
385
381
  if (creates.length <= 1) return creates;
386
382
  const tableSet = new Set(creates.map((create) => create.table));
387
383
  const byTable = new Map(creates.map((create) => [create.table, create]));
388
- const incoming = new Map();
389
- const dependents = new Map();
384
+ const incoming = /* @__PURE__ */ new Map();
385
+ const dependents = /* @__PURE__ */ new Map();
390
386
  for (const table of tableSet) incoming.set(table, 0);
391
387
  for (const create of creates) {
392
- const seenParents = new Set();
388
+ const seenParents = /* @__PURE__ */ new Set();
393
389
  for (const column of create.columns) {
394
390
  if (!column.references) continue;
395
391
  const refTable = column.references.table;
@@ -397,7 +393,7 @@ else remainder.push(operation);
397
393
  if (seenParents.has(refTable)) continue;
398
394
  seenParents.add(refTable);
399
395
  incoming.set(create.table, incoming.get(create.table) + 1);
400
- if (!dependents.has(refTable)) dependents.set(refTable, new Set());
396
+ if (!dependents.has(refTable)) dependents.set(refTable, /* @__PURE__ */ new Set());
401
397
  dependents.get(refTable).add(create.table);
402
398
  }
403
399
  }
@@ -419,9 +415,11 @@ else remainder.push(operation);
419
415
  return sorted;
420
416
  }
421
417
  };
422
-
423
418
  //#endregion
424
419
  //#region src/compilers/factories/SqliteCompilerFactory.ts
420
+ /**
421
+ * Factory for SQLite migration compilers.
422
+ */
425
423
  var SqliteCompilerFactory = class SqliteCompilerFactory {
426
424
  static BRAND = "tango.migrations.sqlite_compiler_factory";
427
425
  __tangoBrand = SqliteCompilerFactory.BRAND;
@@ -438,7 +436,7 @@ var SqliteCompilerFactory = class SqliteCompilerFactory {
438
436
  return new SqliteCompiler();
439
437
  }
440
438
  };
441
-
442
439
  //#endregion
443
- export { PostgresCompiler, PostgresCompilerFactory, SqliteCompiler, SqliteCompilerFactory };
444
- //# sourceMappingURL=SqliteCompilerFactory-BvdJ0kBl.js.map
440
+ export { PostgresCompiler as i, SqliteCompiler as n, PostgresCompilerFactory as r, SqliteCompilerFactory as t };
441
+
442
+ //# sourceMappingURL=SqliteCompilerFactory-CXlPAclY.js.map