@danceroutine/tango-migrations 0.1.0 → 1.0.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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/{CollectingBuilder-C6qnwyrb.js → CollectingBuilder--4fqDQdE.js} +17 -2
  4. package/dist/CollectingBuilder--4fqDQdE.js.map +1 -0
  5. package/dist/{CompilerStrategy-Cv1woBmO.js → CompilerStrategy-yKw-Egxv.js} +19 -8
  6. package/dist/CompilerStrategy-yKw-Egxv.js.map +1 -0
  7. package/dist/InternalColumnType-G9zV9StN.js +16 -0
  8. package/dist/InternalColumnType-G9zV9StN.js.map +1 -0
  9. package/dist/InternalOperationKind-Bt6Weuon.js +19 -0
  10. package/dist/InternalOperationKind-Bt6Weuon.js.map +1 -0
  11. package/dist/{IntrospectorStrategy-BM1Eizfc.js → IntrospectorStrategy-blvwSU3_.js} +13 -4
  12. package/dist/IntrospectorStrategy-blvwSU3_.js.map +1 -0
  13. package/dist/Migration-DYQ0hUG7.js +30 -0
  14. package/dist/Migration-DYQ0hUG7.js.map +1 -0
  15. package/dist/{MigrationGenerator-Z39LTKmC.js → MigrationGenerator-B1p0jHnx.js} +20 -12
  16. package/dist/MigrationGenerator-B1p0jHnx.js.map +1 -0
  17. package/dist/{MigrationRunner-CCFuPUlr.js → MigrationRunner-D1ZfbbS-.js} +52 -9
  18. package/dist/MigrationRunner-D1ZfbbS-.js.map +1 -0
  19. package/dist/MigrationSqlSafetyAdapter-CGRbB2k2.js +62 -0
  20. package/dist/MigrationSqlSafetyAdapter-CGRbB2k2.js.map +1 -0
  21. package/dist/{SqliteCompilerFactory-DwMwO7xY.js → SqliteCompilerFactory-BAodJW9n.js} +73 -51
  22. package/dist/SqliteCompilerFactory-BAodJW9n.js.map +1 -0
  23. package/dist/{SqliteIntrospector-BRdNt6KG.js → SqliteIntrospector-CWwPWhmA.js} +49 -5
  24. package/dist/SqliteIntrospector-CWwPWhmA.js.map +1 -0
  25. package/dist/builder/contracts/ColumnSpec.d.ts +2 -1
  26. package/dist/builder/contracts/UpdateReferentialAction.d.ts +1 -1
  27. package/dist/builder/index.js +4 -4
  28. package/dist/builder/ops/OpBuilder.d.ts +48 -7
  29. package/dist/builder/runtime/CollectingBuilder.d.ts +19 -1
  30. package/dist/{builder-Dtk8oP_Y.js → builder-xJ-Bq2pk.js} +51 -21
  31. package/dist/builder-xJ-Bq2pk.js.map +1 -0
  32. package/dist/cli-DhCn8xiS.js +313 -0
  33. package/dist/cli-DhCn8xiS.js.map +1 -0
  34. package/dist/cli.js +17 -169
  35. package/dist/cli.js.map +1 -1
  36. package/dist/commands/cli.d.ts +5 -0
  37. package/dist/commands/index.d.ts +4 -0
  38. package/dist/commands/index.js +17 -0
  39. package/dist/commands-DIJepqNg.js +10 -0
  40. package/dist/commands-DIJepqNg.js.map +1 -0
  41. package/dist/compilers/contracts/CompilerFactory.d.ts +4 -0
  42. package/dist/compilers/contracts/SQLCompiler.d.ts +4 -0
  43. package/dist/compilers/dialects/PostgresCompiler.d.ts +10 -1
  44. package/dist/compilers/dialects/SqliteCompiler.d.ts +10 -0
  45. package/dist/compilers/factories/PostgresCompilerFactory.d.ts +9 -0
  46. package/dist/compilers/factories/SqliteCompilerFactory.d.ts +9 -0
  47. package/dist/compilers/index.js +5 -4
  48. package/dist/{compilers-D8DJuTnQ.js → compilers-dRN0Hzev.js} +2 -2
  49. package/dist/{compilers-D8DJuTnQ.js.map → compilers-dRN0Hzev.js.map} +1 -1
  50. package/dist/diff/diffSchema.d.ts +6 -1
  51. package/dist/diff/index.js +6 -6
  52. package/dist/{diff-Cs0TPEGR.js → diff-CZZbXAPN.js} +2 -2
  53. package/dist/{diff-Cs0TPEGR.js.map → diff-CZZbXAPN.js.map} +1 -1
  54. package/dist/{diffSchema-KgGHP-s3.js → diffSchema-D4oemTWS.js} +5 -4
  55. package/dist/diffSchema-D4oemTWS.js.map +1 -0
  56. package/dist/domain/Migration.d.ts +17 -0
  57. package/dist/domain/MigrationOperation.d.ts +14 -13
  58. package/dist/domain/index.js +2 -2
  59. package/dist/domain/internal/InternalColumnType.d.ts +11 -10
  60. package/dist/domain/internal/InternalDialect.d.ts +5 -4
  61. package/dist/domain/internal/InternalMigrationMode.d.ts +5 -4
  62. package/dist/domain/internal/InternalOperationKind.d.ts +14 -13
  63. package/dist/domain/internal/InternalReferentialAction.d.ts +7 -6
  64. package/dist/{domain-BXVlG0C0.js → domain-CwR-kUNS.js} +2 -2
  65. package/dist/{domain-BXVlG0C0.js.map → domain-CwR-kUNS.js.map} +1 -1
  66. package/dist/generator/MigrationGenerator.d.ts +13 -0
  67. package/dist/generator/index.js +3 -3
  68. package/dist/{generator-3yC60b1u.js → generator-DK-_f-PF.js} +2 -2
  69. package/dist/{generator-3yC60b1u.js.map → generator-DK-_f-PF.js.map} +1 -1
  70. package/dist/index.d.ts +4 -0
  71. package/dist/index.js +24 -20
  72. package/dist/internal/MigrationSqlSafetyAdapter.d.ts +24 -0
  73. package/dist/introspect/DatabaseIntrospector.d.ts +8 -0
  74. package/dist/introspect/PostgresIntrospector.d.ts +14 -0
  75. package/dist/introspect/SqliteIntrospector.d.ts +13 -0
  76. package/dist/introspect/index.js +3 -2
  77. package/dist/{introspect-ks-QSodq.js → introspect-TPv_jeD6.js} +2 -2
  78. package/dist/{introspect-ks-QSodq.js.map → introspect-TPv_jeD6.js.map} +1 -1
  79. package/dist/runner/MigrationRunner.d.ts +7 -1
  80. package/dist/runner/index.js +9 -8
  81. package/dist/{runner-BOs-tItW.js → runner-C97xT8_W.js} +2 -2
  82. package/dist/{runner-BOs-tItW.js.map → runner-C97xT8_W.js.map} +1 -1
  83. package/dist/runtime/loadModule.d.ts +15 -0
  84. package/dist/strategies/CompilerStrategy.d.ts +19 -1
  85. package/dist/strategies/IntrospectorStrategy.d.ts +16 -1
  86. package/dist/strategies/index.js +8 -7
  87. package/dist/{strategies-BvHwf4as.js → strategies-D9ymSvbG.js} +3 -3
  88. package/dist/{strategies-BvHwf4as.js.map → strategies-D9ymSvbG.js.map} +1 -1
  89. package/package.json +98 -92
  90. package/dist/CollectingBuilder-C6qnwyrb.js.map +0 -1
  91. package/dist/CompilerStrategy-Cv1woBmO.js.map +0 -1
  92. package/dist/InternalColumnType-_YAz7RqI.js +0 -17
  93. package/dist/InternalColumnType-_YAz7RqI.js.map +0 -1
  94. package/dist/InternalOperationKind-BPVoOQwD.js +0 -20
  95. package/dist/InternalOperationKind-BPVoOQwD.js.map +0 -1
  96. package/dist/IntrospectorStrategy-BM1Eizfc.js.map +0 -1
  97. package/dist/Migration-D9J6ZbLP.js +0 -25
  98. package/dist/Migration-D9J6ZbLP.js.map +0 -1
  99. package/dist/MigrationGenerator-Z39LTKmC.js.map +0 -1
  100. package/dist/MigrationRunner-CCFuPUlr.js.map +0 -1
  101. package/dist/SqliteCompilerFactory-DwMwO7xY.js.map +0 -1
  102. package/dist/SqliteIntrospector-BRdNt6KG.js.map +0 -1
  103. package/dist/builder/ops/OpBuilder.js +0 -173
  104. package/dist/builder-Dtk8oP_Y.js.map +0 -1
  105. package/dist/diffSchema-KgGHP-s3.js.map +0 -1
  106. package/dist/domain/MigrationOperation.js +0 -1
@@ -0,0 +1,313 @@
1
+ import { InternalDialect } from "./CompilerStrategy-yKw-Egxv.js";
2
+ import { MigrationRunner, loadModule } from "./MigrationRunner-D1ZfbbS-.js";
3
+ import { MigrationGenerator } from "./MigrationGenerator-B1p0jHnx.js";
4
+ import { diffSchema } from "./diffSchema-D4oemTWS.js";
5
+ import { createDefaultIntrospectorStrategy } from "./IntrospectorStrategy-blvwSU3_.js";
6
+ import { access, mkdir } from "node:fs/promises";
7
+ import { constants as fsConstants } from "node:fs";
8
+ import { dirname, resolve } from "node:path";
9
+ import { getLogger } from "@danceroutine/tango-core";
10
+ import { loadConfig } from "@danceroutine/tango-config";
11
+
12
+ //#region src/commands/cli.ts
13
+ const logger = getLogger("tango.migrations");
14
+ async function importModule(modulePath) {
15
+ return loadModule(modulePath, { projectRoot: process.cwd() });
16
+ }
17
+ async function tryLoadMigrationDefaults(configPathArg, configEnvArg) {
18
+ const explicitConfigPath = typeof configPathArg === "string" && configPathArg.trim().length > 0;
19
+ const resolvedPath = resolve(process.cwd(), configPathArg?.trim() || "./tango.config.ts");
20
+ try {
21
+ await access(resolvedPath, fsConstants.F_OK);
22
+ } catch (error) {
23
+ if (explicitConfigPath) throw new Error(`Config file not found: ${resolvedPath}`, { cause: error });
24
+ return {};
25
+ }
26
+ const module = await importModule(resolvedPath);
27
+ const fileConfig = module.default ?? module;
28
+ const loaded = loadConfig(() => ({
29
+ ...fileConfig,
30
+ ...configEnvArg ? { current: configEnvArg } : {}
31
+ }));
32
+ const { db, migrations } = loaded.current;
33
+ const inferredDialect = db.adapter;
34
+ const inferredDb = resolveDbTarget(db);
35
+ return {
36
+ dialect: inferredDialect,
37
+ db: inferredDb,
38
+ dir: migrations.dir,
39
+ autoApply: migrations.autoApply
40
+ };
41
+ }
42
+ function resolveDbTarget(db) {
43
+ if (db.adapter === InternalDialect.SQLITE) return db.filename ?? db.url;
44
+ if (db.url) return db.url;
45
+ if (!db.database) return undefined;
46
+ const host = db.host ?? "localhost";
47
+ const port = db.port ?? 5432;
48
+ const encodedUser = db.user ? encodeURIComponent(db.user) : "";
49
+ const encodedPassword = db.password ? encodeURIComponent(db.password) : "";
50
+ const userInfo = encodedUser.length > 0 ? encodedPassword.length > 0 ? `${encodedUser}:${encodedPassword}@` : `${encodedUser}@` : "";
51
+ return `postgres://${userInfo}${host}:${String(port)}/${db.database}`;
52
+ }
53
+ async function resolveCommandInputs(argv) {
54
+ const defaults = await tryLoadMigrationDefaults(argv.config, argv.env);
55
+ const resolvedDialect = argv.dialect ?? defaults.dialect ?? InternalDialect.POSTGRES;
56
+ const resolvedDir = argv.dir ?? defaults.dir ?? "migrations";
57
+ const resolvedDb = argv.db ?? defaults.db;
58
+ return {
59
+ dialect: resolvedDialect,
60
+ dir: resolvedDir,
61
+ db: resolvedDb,
62
+ autoApply: defaults.autoApply ?? true
63
+ };
64
+ }
65
+ async function loadModels(modelsPath) {
66
+ const mod = await importModule(modelsPath);
67
+ const moduleValue = mod.default ?? mod;
68
+ const models = [];
69
+ if (moduleValue && typeof moduleValue === "object" && "metadata" in moduleValue) {
70
+ const direct = moduleValue;
71
+ models.push(direct.metadata);
72
+ }
73
+ const exportedValues = moduleValue && typeof moduleValue === "object" ? Object.values(moduleValue) : [];
74
+ for (const value of exportedValues) if (value && typeof value === "object" && "metadata" in value) {
75
+ const model = value;
76
+ models.push(model.metadata);
77
+ }
78
+ if (models.length === 0) throw new Error(`No models found in '${modelsPath}'. Ensure the module exports Model() definitions.`);
79
+ return models;
80
+ }
81
+ async function connectAndIntrospect(dbUrl, dialect) {
82
+ const dbClient = await connectDbClient(dbUrl, dialect);
83
+ try {
84
+ const strategy = createDefaultIntrospectorStrategy();
85
+ return await strategy.introspect(dialect, dbClient);
86
+ } finally {
87
+ await dbClient.close();
88
+ }
89
+ }
90
+ async function connectDbClient(db, dialect) {
91
+ if (dialect === InternalDialect.POSTGRES) {
92
+ const pg = await import("pg");
93
+ const client = new pg.default.Client({ connectionString: db });
94
+ await client.connect();
95
+ return {
96
+ async query(sql, params) {
97
+ const result = await client.query(sql, params);
98
+ return { rows: result.rows };
99
+ },
100
+ async close() {
101
+ await client.end();
102
+ }
103
+ };
104
+ }
105
+ if (dialect === InternalDialect.SQLITE) {
106
+ const sqlite = await import("better-sqlite3");
107
+ const DatabaseCtor = sqlite.default ?? sqlite;
108
+ const filename = normalizeSqliteFilename(db);
109
+ await ensureSqliteParentDirectory(filename);
110
+ const connection = new DatabaseCtor(filename);
111
+ return {
112
+ async query(sql, params) {
113
+ const statement = connection.prepare(sql);
114
+ const values = [...params ?? []];
115
+ const isSelectLike = /^\s*(SELECT|PRAGMA|WITH)\b/i.test(sql);
116
+ if (isSelectLike) return { rows: statement.all(...values) };
117
+ statement.run(...values);
118
+ return { rows: [] };
119
+ },
120
+ async close() {
121
+ connection.close();
122
+ }
123
+ };
124
+ }
125
+ throw new Error(`Unsupported dialect: ${dialect}`);
126
+ }
127
+ async function ensureSqliteParentDirectory(filename) {
128
+ if (filename === ":memory:" || filename === "file::memory:") return;
129
+ const directory = dirname(filename);
130
+ if (directory === "." || directory.length === 0) return;
131
+ await mkdir(directory, { recursive: true });
132
+ }
133
+ function normalizeSqliteFilename(db) {
134
+ if (db.startsWith("sqlite://")) return db.slice("sqlite://".length);
135
+ return db;
136
+ }
137
+ function registerMigrationsCommands(yargsBuilder) {
138
+ return yargsBuilder.command("migrate", "Apply pending migrations to the database", (builder) => builder.option("dir", {
139
+ type: "string",
140
+ describe: "Migrations directory"
141
+ }).option("db", {
142
+ type: "string",
143
+ describe: "Database connection URL"
144
+ }).option("dialect", {
145
+ type: "string",
146
+ choices: ["postgres", "sqlite"],
147
+ describe: "Database dialect"
148
+ }).option("config", {
149
+ type: "string",
150
+ describe: "Path to tango.config.ts (auto-loads ./tango.config.ts when present)"
151
+ }).option("env", {
152
+ type: "string",
153
+ choices: [
154
+ "development",
155
+ "test",
156
+ "production"
157
+ ],
158
+ describe: "Config environment override"
159
+ }).option("to", {
160
+ type: "string",
161
+ describe: "Target migration ID (apply up to this migration)"
162
+ }), async (argv) => {
163
+ const resolved = await resolveCommandInputs({
164
+ dialect: argv.dialect,
165
+ dir: argv.dir,
166
+ db: argv.db,
167
+ config: argv.config,
168
+ env: argv.env
169
+ });
170
+ if (!resolved.autoApply) {
171
+ logger.info("Auto-migration disabled (autoApply: false). Skipping.");
172
+ return;
173
+ }
174
+ if (!resolved.db) throw new Error("No database target provided. Pass --db or define db settings in tango.config.ts.");
175
+ const dbClient = await connectDbClient(resolved.db, resolved.dialect);
176
+ const runner = new MigrationRunner(dbClient, resolved.dialect, resolved.dir);
177
+ await runner.apply(argv.to);
178
+ await dbClient.close();
179
+ logger.info("Migrations applied successfully");
180
+ }).command("make:migrations", "Generate migration file by comparing models to database", (builder) => builder.option("dir", {
181
+ type: "string",
182
+ describe: "Migrations directory"
183
+ }).option("name", {
184
+ type: "string",
185
+ demandOption: true,
186
+ describe: "Migration name (e.g. \"create_users\")"
187
+ }).option("models", {
188
+ type: "string",
189
+ demandOption: true,
190
+ describe: "Path to module exporting Model definitions (e.g. \"./src/models.ts\")"
191
+ }).option("db", {
192
+ type: "string",
193
+ describe: "Database connection URL for introspection (omit for initial migration)"
194
+ }).option("dialect", {
195
+ type: "string",
196
+ choices: ["postgres", "sqlite"],
197
+ describe: "Database dialect"
198
+ }).option("config", {
199
+ type: "string",
200
+ describe: "Path to tango.config.ts (auto-loads ./tango.config.ts when present)"
201
+ }).option("env", {
202
+ type: "string",
203
+ choices: [
204
+ "development",
205
+ "test",
206
+ "production"
207
+ ],
208
+ describe: "Config environment override"
209
+ }), async (argv) => {
210
+ const resolved = await resolveCommandInputs({
211
+ dialect: argv.dialect,
212
+ dir: argv.dir,
213
+ db: argv.db,
214
+ config: argv.config,
215
+ env: argv.env
216
+ });
217
+ const models = await loadModels(argv.models);
218
+ logger.info(`Found ${models.length} model(s): ${models.map((m) => m.table).join(", ")}`);
219
+ let dbState;
220
+ if (resolved.db) {
221
+ logger.info("Introspecting database...");
222
+ dbState = await connectAndIntrospect(resolved.db, resolved.dialect);
223
+ } else dbState = { tables: {} };
224
+ const operations = diffSchema(dbState, models);
225
+ if (operations.length === 0) {
226
+ logger.info("No changes detected — models and database are in sync");
227
+ return;
228
+ }
229
+ const generator = new MigrationGenerator();
230
+ const filepath = await generator.generate({
231
+ name: argv.name,
232
+ operations,
233
+ directory: resolved.dir
234
+ });
235
+ logger.info(`Generated migration: ${filepath}`);
236
+ logger.info(` ${operations.length} operation(s)`);
237
+ }).command("plan", "Print migration SQL without applying", (builder) => builder.option("dir", {
238
+ type: "string",
239
+ describe: "Migrations directory"
240
+ }).option("dialect", {
241
+ type: "string",
242
+ choices: ["postgres", "sqlite"],
243
+ describe: "Database dialect"
244
+ }).option("config", {
245
+ type: "string",
246
+ describe: "Path to tango.config.ts (auto-loads ./tango.config.ts when present)"
247
+ }).option("env", {
248
+ type: "string",
249
+ choices: [
250
+ "development",
251
+ "test",
252
+ "production"
253
+ ],
254
+ describe: "Config environment override"
255
+ }), async (argv) => {
256
+ const resolved = await resolveCommandInputs({
257
+ dialect: argv.dialect,
258
+ dir: argv.dir,
259
+ db: argv.db,
260
+ config: argv.config,
261
+ env: argv.env
262
+ });
263
+ const runner = new MigrationRunner({
264
+ query: async () => ({ rows: [] }),
265
+ close: async () => {}
266
+ }, resolved.dialect, resolved.dir);
267
+ const output = await runner.plan();
268
+ logger.info(output);
269
+ }).command("status", "Show applied/pending status of all migrations", (builder) => builder.option("dir", {
270
+ type: "string",
271
+ describe: "Migrations directory"
272
+ }).option("db", {
273
+ type: "string",
274
+ describe: "Database connection URL"
275
+ }).option("dialect", {
276
+ type: "string",
277
+ choices: ["postgres", "sqlite"],
278
+ describe: "Database dialect"
279
+ }).option("config", {
280
+ type: "string",
281
+ describe: "Path to tango.config.ts (auto-loads ./tango.config.ts when present)"
282
+ }).option("env", {
283
+ type: "string",
284
+ choices: [
285
+ "development",
286
+ "test",
287
+ "production"
288
+ ],
289
+ describe: "Config environment override"
290
+ }), async (argv) => {
291
+ const resolved = await resolveCommandInputs({
292
+ dialect: argv.dialect,
293
+ dir: argv.dir,
294
+ db: argv.db,
295
+ config: argv.config,
296
+ env: argv.env
297
+ });
298
+ if (!resolved.db) throw new Error("No database target provided. Pass --db or define db settings in tango.config.ts.");
299
+ const dbClient = await connectDbClient(resolved.db, resolved.dialect);
300
+ const runner = new MigrationRunner(dbClient, resolved.dialect, resolved.dir);
301
+ const statuses = await runner.status();
302
+ if (statuses.length === 0) logger.info("No migrations found");
303
+ else statuses.forEach((statusItem) => {
304
+ const marker = statusItem.applied ? "[x]" : "[ ]";
305
+ logger.info(` ${marker} ${statusItem.id}`);
306
+ });
307
+ await dbClient.close();
308
+ });
309
+ }
310
+
311
+ //#endregion
312
+ export { registerMigrationsCommands };
313
+ //# sourceMappingURL=cli-DhCn8xiS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-DhCn8xiS.js","names":["modulePath: string","configPathArg: string | undefined","configEnvArg: ConfigEnvironment | undefined","db: {\n adapter: string;\n url?: string;\n filename?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n}","argv: {\n dialect?: string;\n dir?: string;\n db?: string;\n config?: string;\n env?: ConfigEnvironment;\n}","modelsPath: string","models: ModelMetadataLike[]","dbUrl: string","dialect: string","db: string","dialect: Dialect","sql: string","params?: readonly unknown[]","filename: string","yargsBuilder: Argv","dbState: DbSchema"],"sources":["../src/commands/cli.ts"],"sourcesContent":["import { access, mkdir } from 'node:fs/promises';\nimport { constants as fsConstants } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport type { Argv } from 'yargs';\nimport { MigrationRunner } from '../runner/MigrationRunner';\nimport { MigrationGenerator } from '../generator/MigrationGenerator';\nimport { diffSchema } from '../diff/diffSchema';\nimport type { DbSchema } from '../introspect/PostgresIntrospector';\nimport type { Dialect } from '../domain/Dialect';\nimport type { ColumnType } from '../builder/contracts/ColumnType';\nimport type { DeleteReferentialAction } from '../builder/contracts/DeleteReferentialAction';\nimport type { UpdateReferentialAction } from '../builder/contracts/UpdateReferentialAction';\nimport { createDefaultIntrospectorStrategy } from '../strategies/IntrospectorStrategy';\nimport { InternalDialect } from '../domain/internal/InternalDialect';\nimport { loadConfig } from '@danceroutine/tango-config';\nimport { getLogger } from '@danceroutine/tango-core';\nimport { loadModule } from '../runtime/loadModule';\n\nconst logger = getLogger('tango.migrations');\n\ntype ConfigEnvironment = 'development' | 'test' | 'production';\n\ntype OptionalMigrationDefaults = {\n dialect?: Dialect;\n db?: string;\n dir?: string;\n autoApply?: boolean;\n};\n\ntype ModelMetadataLike = {\n table: string;\n fields: Array<{\n name: string;\n type: ColumnType;\n notNull?: boolean;\n default?: string | { now: true } | null;\n primaryKey?: boolean;\n unique?: boolean;\n references?: {\n table: string;\n column: string;\n onDelete?: DeleteReferentialAction;\n onUpdate?: UpdateReferentialAction;\n };\n }>;\n indexes?: Array<{ name: string; on: string[]; unique?: boolean }>;\n};\n\ntype CliDbClient = {\n query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }>;\n close(): Promise<void>;\n};\n\nasync function importModule(modulePath: string): Promise<Record<string, unknown>> {\n return loadModule(modulePath, { projectRoot: process.cwd() });\n}\n\nasync function tryLoadMigrationDefaults(\n configPathArg: string | undefined,\n configEnvArg: ConfigEnvironment | undefined\n): Promise<OptionalMigrationDefaults> {\n const explicitConfigPath = typeof configPathArg === 'string' && configPathArg.trim().length > 0;\n const resolvedPath = resolve(process.cwd(), configPathArg?.trim() || './tango.config.ts');\n\n try {\n await access(resolvedPath, fsConstants.F_OK);\n } catch (error) {\n if (explicitConfigPath) {\n throw new Error(`Config file not found: ${resolvedPath}`, { cause: error });\n }\n return {};\n }\n\n const module = await importModule(resolvedPath);\n const fileConfig = (module.default ?? module) as { current?: ConfigEnvironment } & Record<string, unknown>;\n\n const loaded = loadConfig(() => ({\n ...fileConfig,\n ...(configEnvArg ? { current: configEnvArg } : {}),\n }));\n\n const { db, migrations } = loaded.current;\n const inferredDialect = db.adapter as Dialect;\n const inferredDb = resolveDbTarget(db);\n\n return {\n dialect: inferredDialect,\n db: inferredDb,\n dir: migrations.dir,\n autoApply: (migrations as { autoApply?: boolean }).autoApply,\n };\n}\n\nfunction resolveDbTarget(db: {\n adapter: string;\n url?: string;\n filename?: string;\n host?: string;\n port?: number;\n database?: string;\n user?: string;\n password?: string;\n}): string | undefined {\n if (db.adapter === InternalDialect.SQLITE) {\n return db.filename ?? db.url;\n }\n\n if (db.url) {\n return db.url;\n }\n\n if (!db.database) {\n return undefined;\n }\n\n const host = db.host ?? 'localhost';\n const port = db.port ?? 5432;\n const encodedUser = db.user ? encodeURIComponent(db.user) : '';\n const encodedPassword = db.password ? encodeURIComponent(db.password) : '';\n const userInfo =\n encodedUser.length > 0\n ? encodedPassword.length > 0\n ? `${encodedUser}:${encodedPassword}@`\n : `${encodedUser}@`\n : '';\n\n return `postgres://${userInfo}${host}:${String(port)}/${db.database}`;\n}\n\nasync function resolveCommandInputs(argv: {\n dialect?: string;\n dir?: string;\n db?: string;\n config?: string;\n env?: ConfigEnvironment;\n}): Promise<{ dialect: Dialect; dir: string; db?: string; autoApply: boolean }> {\n const defaults = await tryLoadMigrationDefaults(argv.config, argv.env);\n\n const resolvedDialect = (argv.dialect as Dialect | undefined) ?? defaults.dialect ?? InternalDialect.POSTGRES;\n const resolvedDir = argv.dir ?? defaults.dir ?? 'migrations';\n const resolvedDb = argv.db ?? defaults.db;\n\n return {\n dialect: resolvedDialect,\n dir: resolvedDir,\n db: resolvedDb,\n autoApply: defaults.autoApply ?? true,\n };\n}\n\nasync function loadModels(modelsPath: string): Promise<ModelMetadataLike[]> {\n const mod = await importModule(modelsPath);\n const moduleValue = (mod.default ?? mod) as unknown;\n\n const models: ModelMetadataLike[] = [];\n if (moduleValue && typeof moduleValue === 'object' && 'metadata' in moduleValue) {\n const direct = moduleValue as { metadata: ModelMetadataLike };\n models.push(direct.metadata);\n }\n const exportedValues =\n moduleValue && typeof moduleValue === 'object' ? Object.values(moduleValue as Record<string, unknown>) : [];\n\n for (const value of exportedValues) {\n if (value && typeof value === 'object' && 'metadata' in value) {\n const model = value as { metadata: ModelMetadataLike };\n models.push(model.metadata);\n }\n }\n\n if (models.length === 0) {\n throw new Error(`No models found in '${modelsPath}'. Ensure the module exports Model() definitions.`);\n }\n\n return models;\n}\n\nasync function connectAndIntrospect(dbUrl: string, dialect: string): Promise<DbSchema> {\n const dbClient = await connectDbClient(dbUrl, dialect as Dialect);\n\n try {\n const strategy = createDefaultIntrospectorStrategy();\n return await strategy.introspect(dialect as Dialect, dbClient);\n } finally {\n await dbClient.close();\n }\n}\n\nasync function connectDbClient(db: string, dialect: Dialect): Promise<CliDbClient> {\n if (dialect === InternalDialect.POSTGRES) {\n const pg = await import('pg');\n const client = new pg.default.Client({ connectionString: db });\n await client.connect();\n\n return {\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const result = await client.query(sql, params as unknown[] | undefined);\n return { rows: result.rows as T[] };\n },\n async close(): Promise<void> {\n await client.end();\n },\n };\n }\n\n if (dialect === InternalDialect.SQLITE) {\n const sqlite = await import('better-sqlite3');\n const DatabaseCtor = (sqlite.default ?? sqlite) as new (filename: string) => {\n prepare(sql: string): {\n all(...params: unknown[]): unknown[];\n run(...params: unknown[]): unknown;\n };\n close(): void;\n };\n\n const filename = normalizeSqliteFilename(db);\n await ensureSqliteParentDirectory(filename);\n const connection = new DatabaseCtor(filename);\n\n return {\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const statement = connection.prepare(sql);\n const values = [...(params ?? [])];\n const isSelectLike = /^\\s*(SELECT|PRAGMA|WITH)\\b/i.test(sql);\n if (isSelectLike) {\n return { rows: statement.all(...values) as T[] };\n }\n\n statement.run(...values);\n return { rows: [] as T[] };\n },\n async close(): Promise<void> {\n connection.close();\n },\n };\n }\n\n throw new Error(`Unsupported dialect: ${dialect}`);\n}\n\nasync function ensureSqliteParentDirectory(filename: string): Promise<void> {\n if (filename === ':memory:' || filename === 'file::memory:') {\n return;\n }\n const directory = dirname(filename);\n if (directory === '.' || directory.length === 0) {\n return;\n }\n await mkdir(directory, { recursive: true });\n}\n\nfunction normalizeSqliteFilename(db: string): string {\n if (db.startsWith('sqlite://')) {\n return db.slice('sqlite://'.length);\n }\n return db;\n}\n\n/**\n * Register Tango's migration commands on an existing yargs parser.\n */\nexport function registerMigrationsCommands(yargsBuilder: Argv): Argv {\n return yargsBuilder\n .command(\n 'migrate',\n 'Apply pending migrations to the database',\n (builder) =>\n builder\n .option('dir', {\n type: 'string',\n describe: 'Migrations directory',\n })\n .option('db', {\n type: 'string',\n describe: 'Database connection URL',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n describe: 'Database dialect',\n })\n .option('config', {\n type: 'string',\n describe: 'Path to tango.config.ts (auto-loads ./tango.config.ts when present)',\n })\n .option('env', {\n type: 'string',\n choices: ['development', 'test', 'production'] as const,\n describe: 'Config environment override',\n })\n .option('to', {\n type: 'string',\n describe: 'Target migration ID (apply up to this migration)',\n }),\n async (argv) => {\n const resolved = await resolveCommandInputs({\n dialect: argv.dialect as string | undefined,\n dir: argv.dir as string | undefined,\n db: argv.db as string | undefined,\n config: argv.config as string | undefined,\n env: argv.env as ConfigEnvironment | undefined,\n });\n\n if (!resolved.autoApply) {\n logger.info('Auto-migration disabled (autoApply: false). Skipping.');\n return;\n }\n\n if (!resolved.db) {\n throw new Error('No database target provided. Pass --db or define db settings in tango.config.ts.');\n }\n\n const dbClient = await connectDbClient(resolved.db, resolved.dialect);\n\n const runner = new MigrationRunner(dbClient, resolved.dialect, resolved.dir);\n await runner.apply(argv.to);\n\n await dbClient.close();\n logger.info('Migrations applied successfully');\n }\n )\n .command(\n 'make:migrations',\n 'Generate migration file by comparing models to database',\n (builder) =>\n builder\n .option('dir', {\n type: 'string',\n describe: 'Migrations directory',\n })\n .option('name', {\n type: 'string',\n demandOption: true,\n describe: 'Migration name (e.g. \"create_users\")',\n })\n .option('models', {\n type: 'string',\n demandOption: true,\n describe: 'Path to module exporting Model definitions (e.g. \"./src/models.ts\")',\n })\n .option('db', {\n type: 'string',\n describe: 'Database connection URL for introspection (omit for initial migration)',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n describe: 'Database dialect',\n })\n .option('config', {\n type: 'string',\n describe: 'Path to tango.config.ts (auto-loads ./tango.config.ts when present)',\n })\n .option('env', {\n type: 'string',\n choices: ['development', 'test', 'production'] as const,\n describe: 'Config environment override',\n }),\n async (argv) => {\n const resolved = await resolveCommandInputs({\n dialect: argv.dialect as string | undefined,\n dir: argv.dir as string | undefined,\n db: argv.db as string | undefined,\n config: argv.config as string | undefined,\n env: argv.env as ConfigEnvironment | undefined,\n });\n const models = await loadModels(argv.models);\n logger.info(`Found ${models.length} model(s): ${models.map((m) => m.table).join(', ')}`);\n\n let dbState: DbSchema;\n if (resolved.db) {\n logger.info('Introspecting database...');\n dbState = await connectAndIntrospect(resolved.db, resolved.dialect);\n } else {\n dbState = { tables: {} };\n }\n\n const operations = diffSchema(dbState, models);\n\n if (operations.length === 0) {\n logger.info('No changes detected — models and database are in sync');\n return;\n }\n\n const generator = new MigrationGenerator();\n const filepath = await generator.generate({\n name: argv.name,\n operations,\n directory: resolved.dir,\n });\n\n logger.info(`Generated migration: ${filepath}`);\n logger.info(` ${operations.length} operation(s)`);\n }\n )\n .command(\n 'plan',\n 'Print migration SQL without applying',\n (builder) =>\n builder\n .option('dir', {\n type: 'string',\n describe: 'Migrations directory',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n describe: 'Database dialect',\n })\n .option('config', {\n type: 'string',\n describe: 'Path to tango.config.ts (auto-loads ./tango.config.ts when present)',\n })\n .option('env', {\n type: 'string',\n choices: ['development', 'test', 'production'] as const,\n describe: 'Config environment override',\n }),\n async (argv) => {\n const resolved = await resolveCommandInputs({\n dialect: argv.dialect as string | undefined,\n dir: argv.dir as string | undefined,\n db: argv.db as string | undefined,\n config: argv.config as string | undefined,\n env: argv.env as ConfigEnvironment | undefined,\n });\n const runner = new MigrationRunner(\n { query: async () => ({ rows: [] }), close: async () => {} },\n resolved.dialect,\n resolved.dir\n );\n const output = await runner.plan();\n logger.info(output);\n }\n )\n .command(\n 'status',\n 'Show applied/pending status of all migrations',\n (builder) =>\n builder\n .option('dir', {\n type: 'string',\n describe: 'Migrations directory',\n })\n .option('db', {\n type: 'string',\n describe: 'Database connection URL',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n describe: 'Database dialect',\n })\n .option('config', {\n type: 'string',\n describe: 'Path to tango.config.ts (auto-loads ./tango.config.ts when present)',\n })\n .option('env', {\n type: 'string',\n choices: ['development', 'test', 'production'] as const,\n describe: 'Config environment override',\n }),\n async (argv) => {\n const resolved = await resolveCommandInputs({\n dialect: argv.dialect as string | undefined,\n dir: argv.dir as string | undefined,\n db: argv.db as string | undefined,\n config: argv.config as string | undefined,\n env: argv.env as ConfigEnvironment | undefined,\n });\n if (!resolved.db) {\n throw new Error('No database target provided. Pass --db or define db settings in tango.config.ts.');\n }\n\n const dbClient = await connectDbClient(resolved.db, resolved.dialect);\n\n const runner = new MigrationRunner(dbClient, resolved.dialect, resolved.dir);\n const statuses = await runner.status();\n\n if (statuses.length === 0) {\n logger.info('No migrations found');\n } else {\n statuses.forEach((statusItem) => {\n const marker = statusItem.applied ? '[x]' : '[ ]';\n logger.info(` ${marker} ${statusItem.id}`);\n });\n }\n\n await dbClient.close();\n }\n );\n}\n"],"mappings":";;;;;;;;;;;;AAkBA,MAAM,SAAS,UAAU,mBAAmB;AAmC5C,eAAe,aAAaA,YAAsD;AAC9E,QAAO,WAAW,YAAY,EAAE,aAAa,QAAQ,KAAK,CAAE,EAAC;AAChE;AAED,eAAe,yBACXC,eACAC,cACkC;CAClC,MAAM,4BAA4B,kBAAkB,YAAY,cAAc,MAAM,CAAC,SAAS;CAC9F,MAAM,eAAe,QAAQ,QAAQ,KAAK,EAAE,eAAe,MAAM,IAAI,oBAAoB;AAEzF,KAAI;AACA,QAAM,OAAO,cAAc,YAAY,KAAK;CAC/C,SAAQ,OAAO;AACZ,MAAI,mBACA,OAAM,IAAI,OAAO,yBAAyB,aAAa,GAAG,EAAE,OAAO,MAAO;AAE9E,SAAO,CAAE;CACZ;CAED,MAAM,SAAS,MAAM,aAAa,aAAa;CAC/C,MAAM,aAAc,OAAO,WAAW;CAEtC,MAAM,SAAS,WAAW,OAAO;EAC7B,GAAG;EACH,GAAI,eAAe,EAAE,SAAS,aAAc,IAAG,CAAE;CACpD,GAAE;CAEH,MAAM,EAAE,IAAI,YAAY,GAAG,OAAO;CAClC,MAAM,kBAAkB,GAAG;CAC3B,MAAM,aAAa,gBAAgB,GAAG;AAEtC,QAAO;EACH,SAAS;EACT,IAAI;EACJ,KAAK,WAAW;EAChB,WAAY,WAAuC;CACtD;AACJ;AAED,SAAS,gBAAgBC,IASF;AACnB,KAAI,GAAG,YAAY,gBAAgB,OAC/B,QAAO,GAAG,YAAY,GAAG;AAG7B,KAAI,GAAG,IACH,QAAO,GAAG;AAGd,MAAK,GAAG,SACJ,QAAO;CAGX,MAAM,OAAO,GAAG,QAAQ;CACxB,MAAM,OAAO,GAAG,QAAQ;CACxB,MAAM,cAAc,GAAG,OAAO,mBAAmB,GAAG,KAAK,GAAG;CAC5D,MAAM,kBAAkB,GAAG,WAAW,mBAAmB,GAAG,SAAS,GAAG;CACxE,MAAM,WACF,YAAY,SAAS,IACf,gBAAgB,SAAS,KACpB,EAAE,YAAY,GAAG,gBAAgB,MACjC,EAAE,YAAY,KACnB;AAEV,SAAQ,aAAa,SAAS,EAAE,KAAK,GAAG,OAAO,KAAK,CAAC,GAAG,GAAG,SAAS;AACvE;AAED,eAAe,qBAAqBC,MAM4C;CAC5E,MAAM,WAAW,MAAM,yBAAyB,KAAK,QAAQ,KAAK,IAAI;CAEtE,MAAM,kBAAmB,KAAK,WAAmC,SAAS,WAAW,gBAAgB;CACrG,MAAM,cAAc,KAAK,OAAO,SAAS,OAAO;CAChD,MAAM,aAAa,KAAK,MAAM,SAAS;AAEvC,QAAO;EACH,SAAS;EACT,KAAK;EACL,IAAI;EACJ,WAAW,SAAS,aAAa;CACpC;AACJ;AAED,eAAe,WAAWC,YAAkD;CACxE,MAAM,MAAM,MAAM,aAAa,WAAW;CAC1C,MAAM,cAAe,IAAI,WAAW;CAEpC,MAAMC,SAA8B,CAAE;AACtC,KAAI,sBAAsB,gBAAgB,YAAY,cAAc,aAAa;EAC7E,MAAM,SAAS;AACf,SAAO,KAAK,OAAO,SAAS;CAC/B;CACD,MAAM,iBACF,sBAAsB,gBAAgB,WAAW,OAAO,OAAO,YAAuC,GAAG,CAAE;AAE/G,MAAK,MAAM,SAAS,eAChB,KAAI,gBAAgB,UAAU,YAAY,cAAc,OAAO;EAC3D,MAAM,QAAQ;AACd,SAAO,KAAK,MAAM,SAAS;CAC9B;AAGL,KAAI,OAAO,WAAW,EAClB,OAAM,IAAI,OAAO,sBAAsB,WAAW;AAGtD,QAAO;AACV;AAED,eAAe,qBAAqBC,OAAeC,SAAoC;CACnF,MAAM,WAAW,MAAM,gBAAgB,OAAO,QAAmB;AAEjE,KAAI;EACA,MAAM,WAAW,mCAAmC;AACpD,SAAO,MAAM,SAAS,WAAW,SAAoB,SAAS;CACjE,UAAS;AACN,QAAM,SAAS,OAAO;CACzB;AACJ;AAED,eAAe,gBAAgBC,IAAYC,SAAwC;AAC/E,KAAI,YAAY,gBAAgB,UAAU;EACtC,MAAM,KAAK,MAAM,OAAO;EACxB,MAAM,SAAS,IAAI,GAAG,QAAQ,OAAO,EAAE,kBAAkB,GAAI;AAC7D,QAAM,OAAO,SAAS;AAEtB,SAAO;GACH,MAAM,MAAmBC,KAAaC,QAAqD;IACvF,MAAM,SAAS,MAAM,OAAO,MAAM,KAAK,OAAgC;AACvE,WAAO,EAAE,MAAM,OAAO,KAAa;GACtC;GACD,MAAM,QAAuB;AACzB,UAAM,OAAO,KAAK;GACrB;EACJ;CACJ;AAED,KAAI,YAAY,gBAAgB,QAAQ;EACpC,MAAM,SAAS,MAAM,OAAO;EAC5B,MAAM,eAAgB,OAAO,WAAW;EAQxC,MAAM,WAAW,wBAAwB,GAAG;AAC5C,QAAM,4BAA4B,SAAS;EAC3C,MAAM,aAAa,IAAI,aAAa;AAEpC,SAAO;GACH,MAAM,MAAmBD,KAAaC,QAAqD;IACvF,MAAM,YAAY,WAAW,QAAQ,IAAI;IACzC,MAAM,SAAS,CAAC,GAAI,UAAU,CAAI,CAAA;IAClC,MAAM,eAAe,8BAA8B,KAAK,IAAI;AAC5D,QAAI,aACA,QAAO,EAAE,MAAM,UAAU,IAAI,GAAG,OAAO,CAAS;AAGpD,cAAU,IAAI,GAAG,OAAO;AACxB,WAAO,EAAE,MAAM,CAAE,EAAS;GAC7B;GACD,MAAM,QAAuB;AACzB,eAAW,OAAO;GACrB;EACJ;CACJ;AAED,OAAM,IAAI,OAAO,uBAAuB,QAAQ;AACnD;AAED,eAAe,4BAA4BC,UAAiC;AACxE,KAAI,aAAa,cAAc,aAAa,gBACxC;CAEJ,MAAM,YAAY,QAAQ,SAAS;AACnC,KAAI,cAAc,OAAO,UAAU,WAAW,EAC1C;AAEJ,OAAM,MAAM,WAAW,EAAE,WAAW,KAAM,EAAC;AAC9C;AAED,SAAS,wBAAwBJ,IAAoB;AACjD,KAAI,GAAG,WAAW,YAAY,CAC1B,QAAO,GAAG,MAAM,YAAY,OAAO;AAEvC,QAAO;AACV;AAKM,SAAS,2BAA2BK,cAA0B;AACjE,QAAO,aACF,QACG,WACA,4CACA,CAAC,YACG,QACK,OAAO,OAAO;EACX,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,MAAM;EACV,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,WAAW;EACf,MAAM;EACN,SAAS,CAAC,YAAY,QAAS;EAC/B,UAAU;CACb,EAAC,CACD,OAAO,UAAU;EACd,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,OAAO;EACX,MAAM;EACN,SAAS;GAAC;GAAe;GAAQ;EAAa;EAC9C,UAAU;CACb,EAAC,CACD,OAAO,MAAM;EACV,MAAM;EACN,UAAU;CACb,EAAC,EACV,OAAO,SAAS;EACZ,MAAM,WAAW,MAAM,qBAAqB;GACxC,SAAS,KAAK;GACd,KAAK,KAAK;GACV,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,KAAK,KAAK;EACb,EAAC;AAEF,OAAK,SAAS,WAAW;AACrB,UAAO,KAAK,wDAAwD;AACpE;EACH;AAED,OAAK,SAAS,GACV,OAAM,IAAI,MAAM;EAGpB,MAAM,WAAW,MAAM,gBAAgB,SAAS,IAAI,SAAS,QAAQ;EAErE,MAAM,SAAS,IAAI,gBAAgB,UAAU,SAAS,SAAS,SAAS;AACxE,QAAM,OAAO,MAAM,KAAK,GAAG;AAE3B,QAAM,SAAS,OAAO;AACtB,SAAO,KAAK,kCAAkC;CACjD,EACJ,CACA,QACG,mBACA,2DACA,CAAC,YACG,QACK,OAAO,OAAO;EACX,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,QAAQ;EACZ,MAAM;EACN,cAAc;EACd,UAAU;CACb,EAAC,CACD,OAAO,UAAU;EACd,MAAM;EACN,cAAc;EACd,UAAU;CACb,EAAC,CACD,OAAO,MAAM;EACV,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,WAAW;EACf,MAAM;EACN,SAAS,CAAC,YAAY,QAAS;EAC/B,UAAU;CACb,EAAC,CACD,OAAO,UAAU;EACd,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,OAAO;EACX,MAAM;EACN,SAAS;GAAC;GAAe;GAAQ;EAAa;EAC9C,UAAU;CACb,EAAC,EACV,OAAO,SAAS;EACZ,MAAM,WAAW,MAAM,qBAAqB;GACxC,SAAS,KAAK;GACd,KAAK,KAAK;GACV,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,KAAK,KAAK;EACb,EAAC;EACF,MAAM,SAAS,MAAM,WAAW,KAAK,OAAO;AAC5C,SAAO,MAAM,QAAQ,OAAO,OAAO,aAAa,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE;EAExF,IAAIC;AACJ,MAAI,SAAS,IAAI;AACb,UAAO,KAAK,4BAA4B;AACxC,aAAU,MAAM,qBAAqB,SAAS,IAAI,SAAS,QAAQ;EACtE,MACG,WAAU,EAAE,QAAQ,CAAE,EAAE;EAG5B,MAAM,aAAa,WAAW,SAAS,OAAO;AAE9C,MAAI,WAAW,WAAW,GAAG;AACzB,UAAO,KAAK,wDAAwD;AACpE;EACH;EAED,MAAM,YAAY,IAAI;EACtB,MAAM,WAAW,MAAM,UAAU,SAAS;GACtC,MAAM,KAAK;GACX;GACA,WAAW,SAAS;EACvB,EAAC;AAEF,SAAO,MAAM,uBAAuB,SAAS,EAAE;AAC/C,SAAO,MAAM,IAAI,WAAW,OAAO,eAAe;CACrD,EACJ,CACA,QACG,QACA,wCACA,CAAC,YACG,QACK,OAAO,OAAO;EACX,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,WAAW;EACf,MAAM;EACN,SAAS,CAAC,YAAY,QAAS;EAC/B,UAAU;CACb,EAAC,CACD,OAAO,UAAU;EACd,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,OAAO;EACX,MAAM;EACN,SAAS;GAAC;GAAe;GAAQ;EAAa;EAC9C,UAAU;CACb,EAAC,EACV,OAAO,SAAS;EACZ,MAAM,WAAW,MAAM,qBAAqB;GACxC,SAAS,KAAK;GACd,KAAK,KAAK;GACV,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,KAAK,KAAK;EACb,EAAC;EACF,MAAM,SAAS,IAAI,gBACf;GAAE,OAAO,aAAa,EAAE,MAAM,CAAE,EAAE;GAAG,OAAO,YAAY,CAAE;EAAE,GAC5D,SAAS,SACT,SAAS;EAEb,MAAM,SAAS,MAAM,OAAO,MAAM;AAClC,SAAO,KAAK,OAAO;CACtB,EACJ,CACA,QACG,UACA,iDACA,CAAC,YACG,QACK,OAAO,OAAO;EACX,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,MAAM;EACV,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,WAAW;EACf,MAAM;EACN,SAAS,CAAC,YAAY,QAAS;EAC/B,UAAU;CACb,EAAC,CACD,OAAO,UAAU;EACd,MAAM;EACN,UAAU;CACb,EAAC,CACD,OAAO,OAAO;EACX,MAAM;EACN,SAAS;GAAC;GAAe;GAAQ;EAAa;EAC9C,UAAU;CACb,EAAC,EACV,OAAO,SAAS;EACZ,MAAM,WAAW,MAAM,qBAAqB;GACxC,SAAS,KAAK;GACd,KAAK,KAAK;GACV,IAAI,KAAK;GACT,QAAQ,KAAK;GACb,KAAK,KAAK;EACb,EAAC;AACF,OAAK,SAAS,GACV,OAAM,IAAI,MAAM;EAGpB,MAAM,WAAW,MAAM,gBAAgB,SAAS,IAAI,SAAS,QAAQ;EAErE,MAAM,SAAS,IAAI,gBAAgB,UAAU,SAAS,SAAS,SAAS;EACxE,MAAM,WAAW,MAAM,OAAO,QAAQ;AAEtC,MAAI,SAAS,WAAW,EACpB,QAAO,KAAK,sBAAsB;IAElC,UAAS,QAAQ,CAAC,eAAe;GAC7B,MAAM,SAAS,WAAW,UAAU,QAAQ;AAC5C,UAAO,MAAM,IAAI,OAAO,GAAG,WAAW,GAAG,EAAE;EAC9C,EAAC;AAGN,QAAM,SAAS,OAAO;CACzB,EACJ;AACR"}
package/dist/cli.js CHANGED
@@ -1,178 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import "./CollectingBuilder-C6qnwyrb.js";
3
- import "./Migration-D9J6ZbLP.js";
4
- import "./InternalOperationKind-BPVoOQwD.js";
5
- import "./InternalColumnType-_YAz7RqI.js";
6
- import "./SqliteCompilerFactory-DwMwO7xY.js";
7
- import "./CompilerStrategy-Cv1woBmO.js";
8
- import { MigrationRunner } from "./MigrationRunner-CCFuPUlr.js";
9
- import { MigrationGenerator } from "./MigrationGenerator-Z39LTKmC.js";
10
- import "./builder-Dtk8oP_Y.js";
11
- import { diffSchema } from "./diffSchema-KgGHP-s3.js";
12
- import "./SqliteIntrospector-BRdNt6KG.js";
13
- import { createDefaultIntrospectorStrategy } from "./IntrospectorStrategy-BM1Eizfc.js";
2
+ import "./CollectingBuilder--4fqDQdE.js";
3
+ import "./Migration-DYQ0hUG7.js";
4
+ import "./InternalOperationKind-Bt6Weuon.js";
5
+ import "./InternalColumnType-G9zV9StN.js";
6
+ import "./MigrationSqlSafetyAdapter-CGRbB2k2.js";
7
+ import "./SqliteCompilerFactory-BAodJW9n.js";
8
+ import "./CompilerStrategy-yKw-Egxv.js";
9
+ import "./MigrationRunner-D1ZfbbS-.js";
10
+ import "./MigrationGenerator-B1p0jHnx.js";
11
+ import "./builder-xJ-Bq2pk.js";
12
+ import "./diffSchema-D4oemTWS.js";
13
+ import "./SqliteIntrospector-CWwPWhmA.js";
14
+ import "./IntrospectorStrategy-blvwSU3_.js";
15
+ import { registerMigrationsCommands } from "./cli-DhCn8xiS.js";
14
16
  import yargs from "yargs";
15
17
  import { hideBin } from "yargs/helpers";
16
- import { resolve } from "node:path";
17
18
 
18
19
  //#region src/cli.ts
19
- async function loadModels(modelsPath) {
20
- const absolutePath = resolve(process.cwd(), modelsPath);
21
- const mod = await import(absolutePath);
22
- const models = [];
23
- for (const value of Object.values(mod)) if (value && typeof value === "object" && "metadata" in value) {
24
- const model = value;
25
- models.push(model.metadata);
26
- }
27
- if (models.length === 0) throw new Error(`No models found in '${modelsPath}'. ` + `Ensure the module exports Model() definitions.`);
28
- return models;
20
+ function runMigrationsCli() {
21
+ registerMigrationsCommands(yargs(hideBin(process.argv))).scriptName("tango").demandCommand(1, "You must specify a command").strict().help().alias("help", "h").alias("version", "v").parse();
29
22
  }
30
- async function connectAndIntrospect(dbUrl, dialect) {
31
- if (dialect !== "postgres") throw new Error(`Introspection for '${dialect}' is not yet supported. Omit --db to generate from scratch.`);
32
- const pg = await import("pg");
33
- const client = new pg.default.Client({ connectionString: dbUrl });
34
- await client.connect();
35
- const dbClient = {
36
- async query(sql) {
37
- const result = await client.query(sql);
38
- return { rows: result.rows };
39
- },
40
- async close() {
41
- await client.end();
42
- }
43
- };
44
- try {
45
- const strategy = createDefaultIntrospectorStrategy();
46
- return await strategy.introspect("postgres", dbClient);
47
- } finally {
48
- await dbClient.close();
49
- }
50
- }
51
- yargs(hideBin(process.argv)).command("migrate", "Apply pending migrations to the database", (yargsBuilder) => yargsBuilder.option("dir", {
52
- type: "string",
53
- default: "migrations",
54
- describe: "Migrations directory"
55
- }).option("db", {
56
- type: "string",
57
- demandOption: true,
58
- describe: "Database connection URL"
59
- }).option("dialect", {
60
- type: "string",
61
- choices: ["postgres", "sqlite"],
62
- default: "postgres",
63
- describe: "Database dialect"
64
- }).option("to", {
65
- type: "string",
66
- describe: "Target migration ID (apply up to this migration)"
67
- }), async (argv) => {
68
- const pg = await import("pg");
69
- const client = new pg.default.Client({ connectionString: argv.db });
70
- await client.connect();
71
- const dbClient = {
72
- async query(sql, params) {
73
- const result = await client.query(sql, params);
74
- return { rows: result.rows };
75
- },
76
- async close() {
77
- await client.end();
78
- }
79
- };
80
- const runner = new MigrationRunner(dbClient, argv.dialect, argv.dir);
81
- await runner.apply(argv.to);
82
- await dbClient.close();
83
- console.log("Migrations applied successfully");
84
- }).command("make:migrations", "Generate migration file by comparing models to database", (yargsBuilder) => yargsBuilder.option("dir", {
85
- type: "string",
86
- default: "migrations",
87
- describe: "Migrations directory"
88
- }).option("name", {
89
- type: "string",
90
- demandOption: true,
91
- describe: "Migration name (e.g. \"create_users\")"
92
- }).option("models", {
93
- type: "string",
94
- demandOption: true,
95
- describe: "Path to module exporting Model definitions (e.g. \"./src/models.ts\")"
96
- }).option("db", {
97
- type: "string",
98
- describe: "Database connection URL for introspection (omit for initial migration)"
99
- }).option("dialect", {
100
- type: "string",
101
- choices: ["postgres", "sqlite"],
102
- default: "postgres",
103
- describe: "Database dialect"
104
- }), async (argv) => {
105
- const models = await loadModels(argv.models);
106
- console.log(`Found ${models.length} model(s): ${models.map((m) => m.table).join(", ")}`);
107
- let dbState;
108
- if (argv.db) {
109
- console.log("Introspecting database...");
110
- dbState = await connectAndIntrospect(argv.db, argv.dialect);
111
- } else dbState = { tables: {} };
112
- const operations = diffSchema(dbState, models);
113
- if (operations.length === 0) {
114
- console.log("No changes detected — models and database are in sync");
115
- return;
116
- }
117
- const generator = new MigrationGenerator();
118
- const filepath = await generator.generate({
119
- name: argv.name,
120
- operations,
121
- directory: argv.dir
122
- });
123
- console.log(`Generated migration: ${filepath}`);
124
- console.log(` ${operations.length} operation(s)`);
125
- }).command("plan", "Print migration SQL without applying", (yargsBuilder) => yargsBuilder.option("dir", {
126
- type: "string",
127
- default: "migrations",
128
- describe: "Migrations directory"
129
- }).option("dialect", {
130
- type: "string",
131
- choices: ["postgres", "sqlite"],
132
- default: "postgres",
133
- describe: "Database dialect"
134
- }), async (argv) => {
135
- const runner = new MigrationRunner({
136
- query: async () => ({ rows: [] }),
137
- close: async () => {}
138
- }, argv.dialect, argv.dir);
139
- const output = await runner.plan();
140
- console.log(output);
141
- }).command("status", "Show applied/pending status of all migrations", (yargsBuilder) => yargsBuilder.option("dir", {
142
- type: "string",
143
- default: "migrations",
144
- describe: "Migrations directory"
145
- }).option("db", {
146
- type: "string",
147
- demandOption: true,
148
- describe: "Database connection URL"
149
- }).option("dialect", {
150
- type: "string",
151
- choices: ["postgres", "sqlite"],
152
- default: "postgres",
153
- describe: "Database dialect"
154
- }), async (argv) => {
155
- const pg = await import("pg");
156
- const client = new pg.default.Client({ connectionString: argv.db });
157
- await client.connect();
158
- const dbClient = {
159
- async query(sql, params) {
160
- const result = await client.query(sql, params);
161
- return { rows: result.rows };
162
- },
163
- async close() {
164
- await client.end();
165
- }
166
- };
167
- const runner = new MigrationRunner(dbClient, argv.dialect, argv.dir);
168
- const statuses = await runner.status();
169
- if (statuses.length === 0) console.log("No migrations found");
170
- else statuses.forEach((s) => {
171
- const marker = s.applied ? "[x]" : "[ ]";
172
- console.log(` ${marker} ${s.id}`);
173
- });
174
- await dbClient.close();
175
- }).demandCommand(1, "You must specify a command").strict().help().alias("help", "h").alias("version", "v").parse();
23
+ runMigrationsCli();
176
24
 
177
25
  //#endregion
178
26
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":["modelsPath: string","models: ModelMetadataLike[]","dbUrl: string","dialect: string","sql: string","params?: readonly unknown[]","dbState: DbSchema"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { resolve } from 'node:path';\nimport { MigrationRunner } from './runner/MigrationRunner';\nimport { MigrationGenerator } from './generator/MigrationGenerator';\nimport { diffSchema } from './diff/diffSchema';\nimport type { DbSchema } from './introspect/PostgresIntrospector';\nimport type { Dialect } from './domain/Dialect';\nimport type { ColumnType } from './builder/contracts/ColumnType';\nimport type { DeleteReferentialAction } from './builder/contracts/DeleteReferentialAction';\nimport type { UpdateReferentialAction } from './builder/contracts/UpdateReferentialAction';\nimport { createDefaultIntrospectorStrategy } from './strategies/IntrospectorStrategy';\n\ntype ModelMetadataLike = {\n table: string;\n fields: Array<{\n name: string;\n type: ColumnType;\n notNull?: boolean;\n default?: string | { now: true } | null;\n primaryKey?: boolean;\n unique?: boolean;\n references?: {\n table: string;\n column: string;\n onDelete?: DeleteReferentialAction;\n onUpdate?: UpdateReferentialAction;\n };\n }>;\n indexes?: Array<{ name: string; on: string[]; unique?: boolean }>;\n};\n\nasync function loadModels(modelsPath: string): Promise<ModelMetadataLike[]> {\n const absolutePath = resolve(process.cwd(), modelsPath);\n const mod = await import(absolutePath);\n\n const models: ModelMetadataLike[] = [];\n\n for (const value of Object.values(mod)) {\n if (value && typeof value === 'object' && 'metadata' in value) {\n const model = value as { metadata: ModelMetadataLike };\n models.push(model.metadata);\n }\n }\n\n if (models.length === 0) {\n throw new Error(`No models found in '${modelsPath}'. ` + `Ensure the module exports Model() definitions.`);\n }\n\n return models;\n}\n\nasync function connectAndIntrospect(dbUrl: string, dialect: string): Promise<DbSchema> {\n if (dialect !== 'postgres') {\n throw new Error(`Introspection for '${dialect}' is not yet supported. Omit --db to generate from scratch.`);\n }\n\n const pg = await import('pg');\n const client = new pg.default.Client({ connectionString: dbUrl });\n await client.connect();\n\n const dbClient = {\n async query<T = unknown>(sql: string): Promise<{ rows: T[] }> {\n const result = await client.query(sql);\n return { rows: result.rows as T[] };\n },\n async close() {\n await client.end();\n },\n };\n\n try {\n const strategy = createDefaultIntrospectorStrategy();\n return await strategy.introspect('postgres' as Dialect, dbClient);\n } finally {\n await dbClient.close();\n }\n}\n\nyargs(hideBin(process.argv))\n .command(\n 'migrate',\n 'Apply pending migrations to the database',\n (yargsBuilder) =>\n yargsBuilder\n .option('dir', {\n type: 'string',\n default: 'migrations',\n describe: 'Migrations directory',\n })\n .option('db', {\n type: 'string',\n demandOption: true,\n describe: 'Database connection URL',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n default: 'postgres' as const,\n describe: 'Database dialect',\n })\n .option('to', {\n type: 'string',\n describe: 'Target migration ID (apply up to this migration)',\n }),\n async (argv) => {\n const pg = await import('pg');\n const client = new pg.default.Client({ connectionString: argv.db });\n await client.connect();\n\n const dbClient = {\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const result = await client.query(sql, params as unknown[] | undefined);\n return { rows: result.rows as T[] };\n },\n async close() {\n await client.end();\n },\n };\n\n const runner = new MigrationRunner(dbClient, argv.dialect as Dialect, argv.dir);\n await runner.apply(argv.to);\n\n await dbClient.close();\n console.log('Migrations applied successfully');\n }\n )\n .command(\n 'make:migrations',\n 'Generate migration file by comparing models to database',\n (yargsBuilder) =>\n yargsBuilder\n .option('dir', {\n type: 'string',\n default: 'migrations',\n describe: 'Migrations directory',\n })\n .option('name', {\n type: 'string',\n demandOption: true,\n describe: 'Migration name (e.g. \"create_users\")',\n })\n .option('models', {\n type: 'string',\n demandOption: true,\n describe: 'Path to module exporting Model definitions (e.g. \"./src/models.ts\")',\n })\n .option('db', {\n type: 'string',\n describe: 'Database connection URL for introspection (omit for initial migration)',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n default: 'postgres' as const,\n describe: 'Database dialect',\n }),\n async (argv) => {\n const models = await loadModels(argv.models);\n console.log(`Found ${models.length} model(s): ${models.map((m) => m.table).join(', ')}`);\n\n let dbState: DbSchema;\n if (argv.db) {\n console.log('Introspecting database...');\n dbState = await connectAndIntrospect(argv.db, argv.dialect);\n } else {\n dbState = { tables: {} };\n }\n\n const operations = diffSchema(dbState, models);\n\n if (operations.length === 0) {\n console.log('No changes detected — models and database are in sync');\n return;\n }\n\n const generator = new MigrationGenerator();\n const filepath = await generator.generate({\n name: argv.name,\n operations,\n directory: argv.dir,\n });\n\n console.log(`Generated migration: ${filepath}`);\n console.log(` ${operations.length} operation(s)`);\n }\n )\n .command(\n 'plan',\n 'Print migration SQL without applying',\n (yargsBuilder) =>\n yargsBuilder\n .option('dir', {\n type: 'string',\n default: 'migrations',\n describe: 'Migrations directory',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n default: 'postgres' as const,\n describe: 'Database dialect',\n }),\n async (argv) => {\n const runner = new MigrationRunner(\n { query: async () => ({ rows: [] }), close: async () => {} },\n argv.dialect as Dialect,\n argv.dir\n );\n const output = await runner.plan();\n console.log(output);\n }\n )\n .command(\n 'status',\n 'Show applied/pending status of all migrations',\n (yargsBuilder) =>\n yargsBuilder\n .option('dir', {\n type: 'string',\n default: 'migrations',\n describe: 'Migrations directory',\n })\n .option('db', {\n type: 'string',\n demandOption: true,\n describe: 'Database connection URL',\n })\n .option('dialect', {\n type: 'string',\n choices: ['postgres', 'sqlite'] as const,\n default: 'postgres' as const,\n describe: 'Database dialect',\n }),\n async (argv) => {\n const pg = await import('pg');\n const client = new pg.default.Client({ connectionString: argv.db });\n await client.connect();\n\n const dbClient = {\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const result = await client.query(sql, params as unknown[] | undefined);\n return { rows: result.rows as T[] };\n },\n async close() {\n await client.end();\n },\n };\n\n const runner = new MigrationRunner(dbClient, argv.dialect as Dialect, argv.dir);\n const statuses = await runner.status();\n\n if (statuses.length === 0) {\n console.log('No migrations found');\n } else {\n statuses.forEach((s) => {\n const marker = s.applied ? '[x]' : '[ ]';\n console.log(` ${marker} ${s.id}`);\n });\n }\n\n await dbClient.close();\n }\n )\n .demandCommand(1, 'You must specify a command')\n .strict()\n .help()\n .alias('help', 'h')\n .alias('version', 'v')\n .parse();\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { registerMigrationsCommands } from './commands/cli';\n\nfunction runMigrationsCli(): void {\n registerMigrationsCommands(yargs(hideBin(process.argv)))\n .scriptName('tango')\n .demandCommand(1, 'You must specify a command')\n .strict()\n .help()\n .alias('help', 'h')\n .alias('version', 'v')\n .parse();\n}\n\nrunMigrationsCli();\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAKA,SAAS,mBAAyB;AAC9B,4BAA2B,MAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC,CACnD,WAAW,QAAQ,CACnB,cAAc,GAAG,6BAA6B,CAC9C,QAAQ,CACR,MAAM,CACN,MAAM,QAAQ,IAAI,CAClB,MAAM,WAAW,IAAI,CACrB,OAAO;AACf;AAED,kBAAkB"}
@@ -0,0 +1,5 @@
1
+ import type { Argv } from 'yargs';
2
+ /**
3
+ * Register Tango's migration commands on an existing yargs parser.
4
+ */
5
+ export declare function registerMigrationsCommands(yargsBuilder: Argv): Argv;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Domain boundary barrel: centralizes this subdomain's public contract.
3
+ */
4
+ export { registerMigrationsCommands } from './cli';
@@ -0,0 +1,17 @@
1
+ import "../CollectingBuilder--4fqDQdE.js";
2
+ import "../Migration-DYQ0hUG7.js";
3
+ import "../InternalOperationKind-Bt6Weuon.js";
4
+ import "../InternalColumnType-G9zV9StN.js";
5
+ import "../MigrationSqlSafetyAdapter-CGRbB2k2.js";
6
+ import "../SqliteCompilerFactory-BAodJW9n.js";
7
+ import "../CompilerStrategy-yKw-Egxv.js";
8
+ import "../MigrationRunner-D1ZfbbS-.js";
9
+ import "../MigrationGenerator-B1p0jHnx.js";
10
+ import "../builder-xJ-Bq2pk.js";
11
+ import "../diffSchema-D4oemTWS.js";
12
+ import "../SqliteIntrospector-CWwPWhmA.js";
13
+ import "../IntrospectorStrategy-blvwSU3_.js";
14
+ import { registerMigrationsCommands } from "../cli-DhCn8xiS.js";
15
+ import "../commands-DIJepqNg.js";
16
+
17
+ export { registerMigrationsCommands };
@@ -0,0 +1,10 @@
1
+ import { __export } from "./chunk-BkvOhyD0.js";
2
+ import { registerMigrationsCommands } from "./cli-DhCn8xiS.js";
3
+
4
+ //#region src/commands/index.ts
5
+ var commands_exports = {};
6
+ __export(commands_exports, { registerMigrationsCommands: () => registerMigrationsCommands });
7
+
8
+ //#endregion
9
+ export { commands_exports };
10
+ //# sourceMappingURL=commands-DIJepqNg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-DIJepqNg.js","names":[],"sources":["../src/commands/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { registerMigrationsCommands } from './cli';\n"],"mappings":""}