nexusql 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/bin/nexusql.js +0 -0
- package/dist/cli.js +61 -38
- package/dist/cli.js.map +1 -1
- package/dist/index.js +60 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# nexusql
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/nexusql)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
3
6
|
Database migration toolkit for PostgreSQL with DBML schema support.
|
|
4
7
|
|
|
5
8
|
Generate migration SQL by comparing your DBML schema against your live database using [migra](https://github.com/djrobstep/migra).
|
package/bin/nexusql.js
CHANGED
|
File without changes
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Command } from "commander";
|
|
|
7
7
|
import { readFileSync, writeFileSync } from "fs";
|
|
8
8
|
import { resolve } from "path";
|
|
9
9
|
import ora from "ora";
|
|
10
|
-
import
|
|
10
|
+
import chalk2 from "chalk";
|
|
11
11
|
|
|
12
12
|
// src/lib/database.ts
|
|
13
13
|
import pg from "pg";
|
|
@@ -274,8 +274,30 @@ export default {
|
|
|
274
274
|
`;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
// src/utils/check-migra.ts
|
|
278
|
+
import { execSync } from "child_process";
|
|
279
|
+
import chalk from "chalk";
|
|
280
|
+
function checkMigra() {
|
|
281
|
+
try {
|
|
282
|
+
execSync("migra --help", { stdio: "ignore" });
|
|
283
|
+
return true;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function ensureMigraOrExit() {
|
|
289
|
+
if (!checkMigra()) {
|
|
290
|
+
console.error(chalk.red("\nError: 'migra' is not installed or not found in PATH."));
|
|
291
|
+
console.error(chalk.yellow("\nPlease install it using pip:"));
|
|
292
|
+
console.error(chalk.cyan(" pip install migra"));
|
|
293
|
+
console.error(chalk.dim("\nDocumentation: https://github.com/djrobstep/migra\n"));
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
277
298
|
// src/commands/gen.ts
|
|
278
299
|
async function gen(options = {}) {
|
|
300
|
+
ensureMigraOrExit();
|
|
279
301
|
const config = await loadConfig();
|
|
280
302
|
const databaseUrl = getDatabaseUrl(config);
|
|
281
303
|
const db = new Database(databaseUrl);
|
|
@@ -313,7 +335,7 @@ async function gen(options = {}) {
|
|
|
313
335
|
spinner.succeed("Loaded schema into temp database");
|
|
314
336
|
if (options.verbose) {
|
|
315
337
|
const tables = await tempDb.listTables();
|
|
316
|
-
console.log(
|
|
338
|
+
console.log(chalk2.dim(`
|
|
317
339
|
Tables in temp database: ${tables.join(", ")}`));
|
|
318
340
|
}
|
|
319
341
|
spinner.start("Generating migration diff...");
|
|
@@ -350,10 +372,10 @@ ${commentSql}`;
|
|
|
350
372
|
const finalSql = migrationSql || "-- No changes detected";
|
|
351
373
|
if (options.output) {
|
|
352
374
|
writeFileSync(options.output, finalSql, "utf-8");
|
|
353
|
-
console.log(
|
|
375
|
+
console.log(chalk2.green(`
|
|
354
376
|
Migration SQL written to: ${options.output}`));
|
|
355
377
|
} else {
|
|
356
|
-
console.log(
|
|
378
|
+
console.log(chalk2.cyan("\n=== Migration SQL ===\n"));
|
|
357
379
|
console.log(finalSql);
|
|
358
380
|
}
|
|
359
381
|
return finalSql;
|
|
@@ -406,7 +428,7 @@ async function getCommentChanges(currentDb, targetDb) {
|
|
|
406
428
|
|
|
407
429
|
// src/commands/migrate.ts
|
|
408
430
|
import { mkdirSync, existsSync as existsSync2 } from "fs";
|
|
409
|
-
import
|
|
431
|
+
import chalk3 from "chalk";
|
|
410
432
|
import ora2 from "ora";
|
|
411
433
|
|
|
412
434
|
// src/lib/migrations.ts
|
|
@@ -670,32 +692,33 @@ async function confirm(query) {
|
|
|
670
692
|
|
|
671
693
|
// src/commands/migrate.ts
|
|
672
694
|
async function migrate(options = {}) {
|
|
695
|
+
ensureMigraOrExit();
|
|
673
696
|
const config = await loadConfig();
|
|
674
697
|
const databaseUrl = getDatabaseUrl(config);
|
|
675
698
|
const db = new Database(databaseUrl);
|
|
676
699
|
const runner = new MigrationRunner(db, config.migrations);
|
|
677
|
-
console.log(
|
|
700
|
+
console.log(chalk3.bold("\nInteractive Database Migration\n"));
|
|
678
701
|
console.log("This will:");
|
|
679
702
|
console.log(" 1. Generate migration diff from DBML");
|
|
680
703
|
console.log(" 2. Create a new migration file");
|
|
681
704
|
console.log(" 3. Optionally apply the migration\n");
|
|
682
705
|
try {
|
|
683
|
-
console.log(
|
|
706
|
+
console.log(chalk3.cyan("Step 1: Generating migration diff...\n"));
|
|
684
707
|
const migrationSql = await gen({ verbose: false });
|
|
685
708
|
const noChanges = !migrationSql || migrationSql === "-- No changes detected";
|
|
686
709
|
if (noChanges) {
|
|
687
|
-
console.log(
|
|
710
|
+
console.log(chalk3.yellow("\nNo schema changes detected.\n"));
|
|
688
711
|
if (!options.yes) {
|
|
689
712
|
const proceed = await confirm(
|
|
690
713
|
"Do you still want to create an empty migration?"
|
|
691
714
|
);
|
|
692
715
|
if (!proceed) {
|
|
693
|
-
console.log(
|
|
716
|
+
console.log(chalk3.red("\nMigration cancelled."));
|
|
694
717
|
return;
|
|
695
718
|
}
|
|
696
719
|
}
|
|
697
720
|
}
|
|
698
|
-
console.log(
|
|
721
|
+
console.log(chalk3.cyan("\n--- Step 2: Create Migration File ---\n"));
|
|
699
722
|
let migrationName = options.name;
|
|
700
723
|
if (!migrationName) {
|
|
701
724
|
migrationName = await question(
|
|
@@ -703,16 +726,16 @@ async function migrate(options = {}) {
|
|
|
703
726
|
);
|
|
704
727
|
}
|
|
705
728
|
if (!migrationName || migrationName.trim() === "") {
|
|
706
|
-
console.log(
|
|
729
|
+
console.log(chalk3.red("\nMigration name cannot be empty. Exiting..."));
|
|
707
730
|
return;
|
|
708
731
|
}
|
|
709
732
|
const sanitizedName = migrationName.trim().replace(/\s+/g, "_");
|
|
710
|
-
console.log(
|
|
733
|
+
console.log(chalk3.green(`
|
|
711
734
|
Using migration name: ${sanitizedName}`));
|
|
712
735
|
if (!options.yes) {
|
|
713
736
|
const proceed = await confirm("\nCreate this migration?");
|
|
714
737
|
if (!proceed) {
|
|
715
|
-
console.log(
|
|
738
|
+
console.log(chalk3.red("\nMigration cancelled."));
|
|
716
739
|
return;
|
|
717
740
|
}
|
|
718
741
|
}
|
|
@@ -726,7 +749,7 @@ Using migration name: ${sanitizedName}`));
|
|
|
726
749
|
noChanges ? "" : migrationSql
|
|
727
750
|
);
|
|
728
751
|
spinner.succeed(`Created migration file: ${filepath}`);
|
|
729
|
-
console.log(
|
|
752
|
+
console.log(chalk3.cyan("\n--- Step 3: Apply Migration ---\n"));
|
|
730
753
|
let shouldApply = options.apply;
|
|
731
754
|
if (shouldApply === void 0 && !options.yes) {
|
|
732
755
|
shouldApply = await confirm("Apply this migration now?");
|
|
@@ -747,10 +770,10 @@ Using migration name: ${sanitizedName}`));
|
|
|
747
770
|
throw error;
|
|
748
771
|
}
|
|
749
772
|
} else {
|
|
750
|
-
console.log(
|
|
751
|
-
console.log(
|
|
773
|
+
console.log(chalk3.dim("\nMigration created but not applied."));
|
|
774
|
+
console.log(chalk3.dim(`Run "nexusql up" to apply pending migrations.`));
|
|
752
775
|
}
|
|
753
|
-
console.log(
|
|
776
|
+
console.log(chalk3.green(`
|
|
754
777
|
Migration file: ${filepath}
|
|
755
778
|
`));
|
|
756
779
|
} finally {
|
|
@@ -772,14 +795,14 @@ async function up(options = {}) {
|
|
|
772
795
|
if (options.dryRun) {
|
|
773
796
|
spinner.info(`found ${pending.length} pending migration(s):`);
|
|
774
797
|
for (const m of pending) {
|
|
775
|
-
console.log(
|
|
798
|
+
console.log(chalk3.cyan(` \u25CB ${m.name}`));
|
|
776
799
|
}
|
|
777
800
|
return;
|
|
778
801
|
}
|
|
779
802
|
spinner.text = "Applying migrations...";
|
|
780
803
|
for (const migration of pending) {
|
|
781
804
|
await runner.applyMigration(migration);
|
|
782
|
-
console.log(
|
|
805
|
+
console.log(chalk3.green(` \u2713 ${migration.name}`));
|
|
783
806
|
}
|
|
784
807
|
spinner.succeed(`Applied ${pending.length} migration(s)`);
|
|
785
808
|
} catch (error) {
|
|
@@ -829,14 +852,14 @@ async function down(options = {}) {
|
|
|
829
852
|
if (options.dryRun) {
|
|
830
853
|
spinner.info(`Would rollback ${toRollback.length} migration(s):`);
|
|
831
854
|
for (const m of toRollback) {
|
|
832
|
-
console.log(
|
|
855
|
+
console.log(chalk3.yellow(` \u25CB ${m.name}`));
|
|
833
856
|
}
|
|
834
857
|
return;
|
|
835
858
|
}
|
|
836
859
|
spinner.text = "Rolling back migrations...";
|
|
837
860
|
for (const migration of toRollback) {
|
|
838
861
|
await runner.rollbackMigration(migration);
|
|
839
|
-
console.log(
|
|
862
|
+
console.log(chalk3.yellow(` reverted ${migration.name}`));
|
|
840
863
|
}
|
|
841
864
|
spinner.succeed(`Rolled back ${toRollback.length} migration(s)`);
|
|
842
865
|
} catch (error) {
|
|
@@ -852,33 +875,33 @@ async function status() {
|
|
|
852
875
|
const spinner = ora2("Checking migration status...").start();
|
|
853
876
|
const { applied, pending } = await runner.status();
|
|
854
877
|
spinner.stop();
|
|
855
|
-
console.log(
|
|
878
|
+
console.log(chalk3.bold("\nMigration Status\n"));
|
|
856
879
|
if (applied.length > 0) {
|
|
857
|
-
console.log(
|
|
880
|
+
console.log(chalk3.green("Applied:"));
|
|
858
881
|
for (const m of applied) {
|
|
859
|
-
console.log(
|
|
882
|
+
console.log(chalk3.green(` \u2713 ${m.name}`));
|
|
860
883
|
}
|
|
861
884
|
}
|
|
862
885
|
if (pending.length > 0) {
|
|
863
|
-
console.log(
|
|
886
|
+
console.log(chalk3.yellow("\nPending:"));
|
|
864
887
|
for (const m of pending) {
|
|
865
|
-
console.log(
|
|
888
|
+
console.log(chalk3.yellow(` \u25CB ${m.name}`));
|
|
866
889
|
}
|
|
867
890
|
}
|
|
868
891
|
if (applied.length === 0 && pending.length === 0) {
|
|
869
|
-
console.log(
|
|
892
|
+
console.log(chalk3.dim("No migrations found."));
|
|
870
893
|
}
|
|
871
894
|
console.log();
|
|
872
895
|
}
|
|
873
896
|
|
|
874
897
|
// src/commands/mark-applied.ts
|
|
875
|
-
import
|
|
898
|
+
import chalk4 from "chalk";
|
|
876
899
|
import ora3 from "ora";
|
|
877
900
|
async function markApplied(version) {
|
|
878
901
|
if (!version) {
|
|
879
|
-
console.error(
|
|
880
|
-
console.log(
|
|
881
|
-
console.log(
|
|
902
|
+
console.error(chalk4.red("Error: Migration version is required"));
|
|
903
|
+
console.log(chalk4.dim("\nUsage: nexusql mark-applied <version>"));
|
|
904
|
+
console.log(chalk4.dim("Example: nexusql mark-applied 20251209153535"));
|
|
882
905
|
process.exit(1);
|
|
883
906
|
}
|
|
884
907
|
const config = await loadConfig();
|
|
@@ -898,21 +921,21 @@ async function markApplied(version) {
|
|
|
898
921
|
// src/commands/init.ts
|
|
899
922
|
import { writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
900
923
|
import { join as join3 } from "path";
|
|
901
|
-
import
|
|
924
|
+
import chalk5 from "chalk";
|
|
902
925
|
async function init(options = {}) {
|
|
903
926
|
const cwd = process.cwd();
|
|
904
927
|
const configPath = join3(cwd, "nexusql.config.js");
|
|
905
928
|
if (existsSync3(configPath) && !options.force) {
|
|
906
|
-
console.log(
|
|
907
|
-
console.log(
|
|
929
|
+
console.log(chalk5.yellow("nexusql.config.js already exists."));
|
|
930
|
+
console.log(chalk5.dim("Use --force to overwrite."));
|
|
908
931
|
return;
|
|
909
932
|
}
|
|
910
933
|
writeFileSync3(configPath, generateConfigTemplate(), "utf-8");
|
|
911
|
-
console.log(
|
|
934
|
+
console.log(chalk5.green("Created nexusql.config.js"));
|
|
912
935
|
const migrationsDir = join3(cwd, "db", "migrations");
|
|
913
936
|
if (!existsSync3(migrationsDir)) {
|
|
914
937
|
mkdirSync2(migrationsDir, { recursive: true });
|
|
915
|
-
console.log(
|
|
938
|
+
console.log(chalk5.green("Created db/migrations/"));
|
|
916
939
|
}
|
|
917
940
|
const envExamplePath = join3(cwd, ".env.example");
|
|
918
941
|
if (!existsSync3(envExamplePath)) {
|
|
@@ -921,9 +944,9 @@ async function init(options = {}) {
|
|
|
921
944
|
"DATABASE_URL=postgres://user:password@localhost:5432/database\n",
|
|
922
945
|
"utf-8"
|
|
923
946
|
);
|
|
924
|
-
console.log(
|
|
947
|
+
console.log(chalk5.green("Created .env.example"));
|
|
925
948
|
}
|
|
926
|
-
console.log(
|
|
949
|
+
console.log(chalk5.bold("\nNext steps:"));
|
|
927
950
|
console.log(" 1. Copy .env.example to .env and set your DATABASE_URL");
|
|
928
951
|
console.log(" 2. Create your schema.dbml file");
|
|
929
952
|
console.log(' 3. Run "nexusql gen" to generate migration SQL');
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/gen.ts","../src/lib/database.ts","../src/lib/db-url.ts","../src/lib/dbml.ts","../src/lib/migra.ts","../src/lib/config.ts","../src/commands/migrate.ts","../src/lib/migrations.ts","../src/lib/reverse.ts","../src/lib/runner.ts","../src/utils/prompts.ts","../src/commands/mark-applied.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { gen } from \"./commands/gen.js\";\nimport { migrate, up, down, status } from \"./commands/migrate.js\";\nimport { markApplied } from \"./commands/mark-applied.js\";\nimport { init } from \"./commands/init.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"nexusql\")\n .description(\n \"Database migration toolkit for PostgreSQL with DBML schema support\"\n )\n .version(\"0.1.0\");\n\nprogram\n .command(\"init\")\n .description(\"Initialize nexusql configuration\")\n .option(\"-f, --force\", \"Overwrite existing config\")\n .action(async (options) => {\n try {\n await init(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"gen\")\n .description(\"Generate migration SQL from DBML schema\")\n .option(\"-o, --output <file>\", \"Write SQL to file instead of stdout\")\n .option(\"-v, --verbose\", \"Show verbose output\")\n .action(async (options) => {\n try {\n await gen(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"migrate\")\n .description(\"Interactive migration: generate, create file, apply\")\n .option(\"-n, --name <name>\", \"Migration name\")\n .option(\"-a, --apply\", \"Apply migration after creating\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (options) => {\n try {\n await migrate(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"up\")\n .description(\"Apply all pending migrations\")\n .option(\"--dry-run\", \"Preview migrations without applying\")\n .action(async (options) => {\n try {\n await up(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"down\")\n .description(\"Rollback applied migrations\")\n .option(\"-s, --steps <number>\", \"Number of migrations to rollback\", (v) =>\n parseInt(v)\n )\n .option(\"--to <version>\", \"Rollback to specific version\")\n .option(\"--dry-run\", \"Preview rollback without applying\")\n .action(async (options) => {\n try {\n await down(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"status\")\n .description(\"Show migration status\")\n .action(async () => {\n try {\n await status();\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"mark-applied <version>\")\n .description(\"Mark a migration as applied without running it\")\n .action(async (version) => {\n try {\n await markApplied(version);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { readFileSync, writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { Database } from '../lib/database.js';\nimport { dbmlToSql } from '../lib/dbml.js';\nimport { runMigra, filterSchemaMigrations } from '../lib/migra.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\nexport interface GenOptions {\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Generate migration SQL by diffing current DB against DBML schema.\n */\nexport async function gen(options: GenOptions = {}): Promise<string> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n\n const spinner = ora();\n\n // Read DBML schema\n spinner.start('Reading DBML schema...');\n const schemaPath = resolve(config.schema);\n let dbmlContent: string;\n try {\n dbmlContent = readFileSync(schemaPath, 'utf-8');\n spinner.succeed('Read DBML schema');\n } catch {\n spinner.fail(`Failed to read schema: ${schemaPath}`);\n throw new Error(`Schema file not found: ${schemaPath}`);\n }\n\n // Convert DBML to SQL\n spinner.start('Converting DBML to SQL...');\n const { sql: targetSql } = dbmlToSql(dbmlContent);\n spinner.succeed('Converted DBML to SQL');\n\n // Create temp database\n const tempDbName = `nexusql_temp_${Date.now()}`;\n spinner.start(`Creating temp database: ${tempDbName}`);\n try {\n await db.createDatabase(tempDbName);\n spinner.succeed(`Created temp database: ${tempDbName}`);\n } catch (error) {\n spinner.fail('Failed to create temp database');\n throw error;\n }\n\n const tempDb = db.withDatabase(tempDbName);\n let migrationSql = '';\n\n try {\n // Install extensions\n spinner.start('Installing extensions...');\n await tempDb.installExtensions(config.extensions);\n spinner.succeed('Installed extensions');\n\n // Load schema into temp database\n spinner.start('Loading schema into temp database...');\n await tempDb.exec(targetSql);\n spinner.succeed('Loaded schema into temp database');\n\n // Debug: List tables\n if (options.verbose) {\n const tables = await tempDb.listTables();\n console.log(chalk.dim(`\\nTables in temp database: ${tables.join(', ')}`));\n }\n\n // Run migra to generate diff\n spinner.start('Generating migration diff...');\n const migraResult = runMigra(\n db.getConnectionUrl(),\n tempDb.getConnectionUrl(),\n { unsafe: true }\n );\n\n migrationSql = filterSchemaMigrations(migraResult.sql);\n\n if (migraResult.hasChanges) {\n spinner.succeed('Generated migration diff');\n } else {\n spinner.info('No schema changes detected');\n }\n\n // Get comment changes\n spinner.start('Checking comment changes...');\n const commentSql = await getCommentChanges(db, tempDb);\n if (commentSql) {\n migrationSql = migrationSql\n ? `${migrationSql}\\n\\n-- Comment changes\\n${commentSql}`\n : `-- Comment changes\\n${commentSql}`;\n }\n spinner.succeed('Checked comment changes');\n } finally {\n // Cleanup temp database\n spinner.start('Cleaning up temp database...');\n try {\n await db.dropDatabase(tempDbName);\n spinner.succeed('Cleaned up temp database');\n } catch {\n spinner.warn('Failed to cleanup temp database');\n }\n }\n\n // Output result\n const finalSql = migrationSql || '-- No changes detected';\n\n if (options.output) {\n writeFileSync(options.output, finalSql, 'utf-8');\n console.log(chalk.green(`\\nMigration SQL written to: ${options.output}`));\n } else {\n console.log(chalk.cyan('\\n=== Migration SQL ===\\n'));\n console.log(finalSql);\n }\n\n return finalSql;\n}\n\n/**\n * Get comment changes between two databases.\n * migra doesn't support COMMENT ON statements.\n */\nasync function getCommentChanges(\n currentDb: Database,\n targetDb: Database\n): Promise<string> {\n const commentQuery = `\n SELECT\n format('COMMENT ON COLUMN %I.%I IS %L;',\n c.table_name,\n c.column_name,\n pgd.description\n ) as comment_sql,\n c.table_name,\n c.column_name,\n pgd.description\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name\n JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace AND pn.nspname = c.table_schema\n LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = pc.oid AND pgd.objsubid = c.ordinal_position\n WHERE c.table_schema = 'public'\n AND c.table_name != 'schema_migrations'\n ORDER BY c.table_name, c.ordinal_position;\n `;\n\n const [currentComments, targetComments] = await Promise.all([\n currentDb.query(commentQuery),\n targetDb.query(commentQuery),\n ]);\n\n const currentMap = new Map<string, string | null>();\n const targetMap = new Map<string, { sql: string; description: string | null }>();\n\n for (const row of currentComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n currentMap.set(key, row.description as string | null);\n }\n\n for (const row of targetComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n targetMap.set(key, {\n sql: row.comment_sql as string,\n description: row.description as string | null,\n });\n }\n\n const commentDiffs: string[] = [];\n\n for (const [key, target] of targetMap) {\n const current = currentMap.get(key);\n if (current !== target.description && target.sql) {\n commentDiffs.push(target.sql);\n }\n }\n\n return commentDiffs.join('\\n');\n}\n","import pg from \"pg\";\nimport { parseAndEncodeDbUrl, buildDbUrl, type DbUrlParts } from \"./db-url.js\";\n\nconst { Client } = pg;\n\nexport interface QueryResult {\n rows: Record<string, unknown>[];\n rowCount: number;\n}\n\nexport class Database {\n private connectionString: string;\n private dbParts: DbUrlParts;\n\n constructor(connectionString: string) {\n this.dbParts = parseAndEncodeDbUrl(connectionString);\n this.connectionString = this.dbParts.url;\n }\n\n /**\n * Execute a query and return results.\n */\n async query(sql: string): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query and return results.\n */\n async queryParams(sql: string, params: unknown[]): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql, params);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query without returning results.\n */\n async execParams(sql: string, params: unknown[]): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql, params);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a query without returning results (for DDL/DML).\n */\n async exec(sql: string): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute operations within a transaction.\n * Automatically commits on success, rolls back on error.\n */\n async withTransaction<T>(fn: (client: pg.Client) => Promise<T>): Promise<T> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(\"BEGIN\");\n const result = await fn(client);\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n await client.end();\n }\n }\n\n /**\n * Create a new database.\n */\n async createDatabase(name: string): Promise<void> {\n await this.exec(`CREATE DATABASE \"${name}\";`);\n }\n\n /**\n * Drop a database if it exists.\n */\n async dropDatabase(name: string): Promise<void> {\n await this.exec(`DROP DATABASE IF EXISTS \"${name}\";`);\n }\n\n /**\n * Create a Database instance connected to a different database.\n */\n withDatabase(name: string): Database {\n const newUrl = buildDbUrl(this.dbParts, name);\n return new Database(newUrl);\n }\n\n /**\n * Get connection URL for external tools (like migra).\n */\n getConnectionUrl(): string {\n return this.connectionString;\n }\n\n /**\n * Get parsed database URL parts.\n */\n getParts(): DbUrlParts {\n return this.dbParts;\n }\n\n /**\n * Install PostgreSQL extensions.\n */\n async installExtensions(extensions: string[]): Promise<void> {\n for (const ext of extensions) {\n try {\n await this.exec(`CREATE EXTENSION IF NOT EXISTS \"${ext}\";`);\n } catch {\n // Ignore extension errors - some might not be available\n }\n }\n }\n\n /**\n * Get column information for a table.\n */\n async getTableColumns(\n tableName: string\n ): Promise<{ column_name: string; ordinal_position: number }[]> {\n const result = await this.query(`\n SELECT column_name, ordinal_position\n FROM information_schema.columns\n WHERE table_name = '${tableName}'\n ORDER BY ordinal_position;\n `);\n return result.rows as { column_name: string; ordinal_position: number }[];\n }\n\n /**\n * List all tables in the public schema.\n */\n async listTables(): Promise<string[]> {\n const result = await this.query(`\n SELECT tablename FROM pg_tables WHERE schemaname = 'public';\n `);\n return result.rows.map((row) => row.tablename as string);\n }\n}\n","export interface DbUrlParts {\n url: string;\n protocol: string;\n user: string;\n password: string;\n host: string;\n port: string;\n database: string;\n params: string;\n}\n\n/**\n * Parse a PostgreSQL connection URL and encode special characters in password.\n * Handles URLs like: postgres://user:password@host:port/database?params\n */\nexport function parseAndEncodeDbUrl(rawUrl: string): DbUrlParts {\n const match = rawUrl.match(\n /^(postgres(?:ql)?):\\/\\/([^:]+):(.+)@([^:]+):(\\d+)\\/([^?]+)(\\?.*)?$/\n );\n\n if (!match) {\n throw new Error(\n 'Invalid DATABASE_URL format. Expected: postgres://user:password@host:port/database'\n );\n }\n\n const [, protocol, user, password, host, port, database, params = ''] = match;\n const encodedPassword = encodeURIComponent(password);\n\n return {\n url: `${protocol}://${user}:${encodedPassword}@${host}:${port}/${database}${params}`,\n protocol,\n user,\n password: encodedPassword,\n host,\n port,\n database,\n params,\n };\n}\n\n/**\n * Build a connection URL with a different database name.\n */\nexport function buildDbUrl(parts: DbUrlParts, database: string): string {\n return `${parts.protocol}://${parts.user}:${parts.password}@${parts.host}:${parts.port}/${database}${parts.params}`;\n}\n","import { Parser, ModelExporter } from '@dbml/core';\n\nexport interface DbmlResult {\n sql: string;\n}\n\n/**\n * Convert DBML schema to PostgreSQL SQL.\n */\nexport function dbmlToSql(dbmlContent: string): DbmlResult {\n const database = new Parser().parse(dbmlContent, 'dbml');\n const sql = ModelExporter.export(database, 'postgres');\n return { sql };\n}\n","import { execFileSync } from 'child_process';\n\nexport interface MigraResult {\n sql: string;\n hasChanges: boolean;\n}\n\n/**\n * Run migra to generate schema diff between two databases.\n *\n * Exit codes:\n * - 0: No differences\n * - 2: Differences found (SQL output on stdout)\n * - 1: Error\n */\nexport function runMigra(\n fromUrl: string,\n toUrl: string,\n options: { unsafe?: boolean } = {}\n): MigraResult {\n const args = [fromUrl, toUrl];\n if (options.unsafe) {\n args.push('--unsafe');\n }\n\n try {\n const output = execFileSync('migra', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Exit code 0 = no changes\n return { sql: output || '', hasChanges: false };\n } catch (error) {\n const err = error as { status?: number; stdout?: string; stderr?: string };\n\n if (err.status === 2 && err.stdout) {\n // Exit code 2 = changes found\n return { sql: err.stdout, hasChanges: true };\n }\n\n if (err.status === 1) {\n throw new Error(`migra error: ${err.stderr || 'Unknown error'}`);\n }\n\n // Other exit codes - might still have output\n return { sql: err.stdout || '', hasChanges: Boolean(err.stdout) };\n }\n}\n\n/**\n * Filter out schema_migrations table from migration SQL.\n */\nexport function filterSchemaMigrations(sql: string): string {\n return sql\n .split('\\n')\n .filter((line) => !line.includes('schema_migrations'))\n .join('\\n')\n .trim();\n}\n","import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { pathToFileURL } from 'url';\nimport { config as loadDotenv } from 'dotenv';\n\nexport interface NexusqlConfig {\n schema: string;\n migrations: string;\n extensions: string[];\n databaseUrl?: string;\n}\n\nconst DEFAULT_CONFIG: NexusqlConfig = {\n schema: './schema.dbml',\n migrations: './db/migrations',\n extensions: ['uuid-ossp'],\n};\n\n/**\n * Load configuration from nexusql.config.js or defaults.\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<NexusqlConfig> {\n // Load .env file\n loadDotenv();\n\n const configPath = join(cwd, 'nexusql.config.js');\n let userConfig: Partial<NexusqlConfig> = {};\n\n if (existsSync(configPath)) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(configUrl);\n userConfig = module.default || module;\n } catch {\n // Ignore config load errors, use defaults\n }\n }\n\n return {\n ...DEFAULT_CONFIG,\n ...userConfig,\n databaseUrl: process.env.DATABASE_URL || userConfig.databaseUrl,\n };\n}\n\n/**\n * Get database URL from config or environment.\n */\nexport function getDatabaseUrl(config: NexusqlConfig): string {\n const url = config.databaseUrl || process.env.DATABASE_URL;\n if (!url) {\n throw new Error('DATABASE_URL not set. Set it in .env or nexusql.config.js');\n }\n return url;\n}\n\n/**\n * Generate default config file content.\n */\nexport function generateConfigTemplate(): string {\n return `/** @type {import('nexusql').NexusqlConfig} */\nexport default {\n // Path to your DBML schema file\n schema: './schema.dbml',\n\n // Directory for migration files\n migrations: './db/migrations',\n\n // PostgreSQL extensions to install in temp database\n extensions: ['uuid-ossp'],\n};\n`;\n}\n","import { mkdirSync, existsSync } from \"fs\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { gen } from \"./gen.js\";\nimport { Database } from \"../lib/database.js\";\nimport { MigrationRunner } from \"../lib/runner.js\";\nimport { createMigrationFile } from \"../lib/migrations.js\";\nimport { loadConfig, getDatabaseUrl } from \"../lib/config.js\";\nimport { question, confirm, closePrompts } from \"../utils/prompts.js\";\n\nexport interface MigrateOptions {\n name?: string;\n apply?: boolean;\n yes?: boolean;\n}\n\n/**\n * Interactive migration workflow.\n */\nexport async function migrate(options: MigrateOptions = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n console.log(chalk.bold(\"\\nInteractive Database Migration\\n\"));\n console.log(\"This will:\");\n console.log(\" 1. Generate migration diff from DBML\");\n console.log(\" 2. Create a new migration file\");\n console.log(\" 3. Optionally apply the migration\\n\");\n\n try {\n // Step 1: Generate diff\n console.log(chalk.cyan(\"Step 1: Generating migration diff...\\n\"));\n const migrationSql = await gen({ verbose: false });\n\n const noChanges =\n !migrationSql || migrationSql === \"-- No changes detected\";\n\n if (noChanges) {\n console.log(chalk.yellow(\"\\nNo schema changes detected.\\n\"));\n\n if (!options.yes) {\n const proceed = await confirm(\n \"Do you still want to create an empty migration?\"\n );\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n }\n\n // Step 2: Get migration name\n console.log(chalk.cyan(\"\\n--- Step 2: Create Migration File ---\\n\"));\n\n let migrationName = options.name;\n if (!migrationName) {\n migrationName = await question(\n 'Enter migration name (e.g., \"add_users_table\"): '\n );\n }\n\n if (!migrationName || migrationName.trim() === \"\") {\n console.log(chalk.red(\"\\nMigration name cannot be empty. Exiting...\"));\n return;\n }\n\n const sanitizedName = migrationName.trim().replace(/\\s+/g, \"_\");\n console.log(chalk.green(`\\nUsing migration name: ${sanitizedName}`));\n\n // Confirm before creating\n if (!options.yes) {\n const proceed = await confirm(\"\\nCreate this migration?\");\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n\n // Create migrations directory if needed\n if (!existsSync(config.migrations)) {\n mkdirSync(config.migrations, { recursive: true });\n }\n\n // Create migration file\n const spinner = ora(\"Creating migration file...\").start();\n const filepath = createMigrationFile(\n config.migrations,\n sanitizedName,\n noChanges ? \"\" : migrationSql\n );\n spinner.succeed(`Created migration file: ${filepath}`);\n\n // Step 3: Apply migration\n console.log(chalk.cyan(\"\\n--- Step 3: Apply Migration ---\\n\"));\n\n let shouldApply = options.apply;\n if (shouldApply === undefined && !options.yes) {\n shouldApply = await confirm(\"Apply this migration now?\");\n }\n\n if (shouldApply) {\n const applySpinner = ora(\"Applying migration...\").start();\n try {\n const applied = await runner.migrateUp();\n if (applied.length > 0) {\n applySpinner.succeed(\n `Applied ${applied.length} migration(s) successfully`\n );\n } else {\n applySpinner.info(\"No pending migrations to apply\");\n }\n } catch (error) {\n applySpinner.fail(\"Failed to apply migration\");\n throw error;\n }\n } else {\n console.log(chalk.dim(\"\\nMigration created but not applied.\"));\n console.log(chalk.dim(`Run \"nexusql up\" to apply pending migrations.`));\n }\n\n console.log(chalk.green(`\\nMigration file: ${filepath}\\n`));\n } finally {\n closePrompts();\n }\n}\n\n/**\n * Apply all pending migrations.\n */\nexport async function up(options: { dryRun?: boolean } = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n const pending = await runner.getPendingMigrations();\n\n if (pending.length === 0) {\n spinner.info(\"No pending migrations\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`found ${pending.length} pending migration(s):`);\n for (const m of pending) {\n console.log(chalk.cyan(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Applying migrations...\";\n for (const migration of pending) {\n await runner.applyMigration(migration);\n console.log(chalk.green(` ✓ ${migration.name}`));\n }\n spinner.succeed(`Applied ${pending.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Migration failed\");\n throw error;\n }\n}\n\n/**\n * Rollback applied migrations.\n */\nexport async function down(\n options: { steps?: number; to?: string; dryRun?: boolean } = {}\n): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n // Optimization: status() reads all files. A more efficient way to get ordered applied migrations is needed if history is huge.\n // For now, sorting 'applied' from status() works.\n const { applied } = await runner.status();\n const sortedApplied = applied.sort((a, b) =>\n b.version.localeCompare(a.version)\n ); // Newest first\n\n if (sortedApplied.length === 0) {\n spinner.info(\"No applied migrations to rollback\");\n return;\n }\n\n let toRollback: typeof applied = [];\n\n if (options.to) {\n const targetIndex = sortedApplied.findIndex(\n (m) => m.version === options.to\n );\n if (targetIndex === -1) {\n // If options.to is \"rollback to version X\", we want to rollback everything > X.\n // Let's assume options.to is the target version we want to KEEP.\n // So we rollback everything where version > options.to\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n if (toRollback.length === 0) {\n spinner.info(\n `Version ${options.to} is already the latest applied or doesn't exist in future history.`\n );\n return;\n }\n } else {\n // Rollback migrations newer than X.\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n }\n } else {\n const steps = options.steps ?? 1;\n toRollback = sortedApplied.slice(0, steps);\n }\n\n if (toRollback.length === 0) {\n spinner.info(\"No migrations to rollback\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`Would rollback ${toRollback.length} migration(s):`);\n for (const m of toRollback) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Rolling back migrations...\";\n for (const migration of toRollback) {\n await runner.rollbackMigration(migration);\n console.log(chalk.yellow(` reverted ${migration.name}`));\n }\n spinner.succeed(`Rolled back ${toRollback.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Rollback failed\");\n throw error;\n }\n}\n\n/**\n * Show migration status.\n */\nexport async function status(): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migration status...\").start();\n const { applied, pending } = await runner.status();\n spinner.stop();\n\n console.log(chalk.bold(\"\\nMigration Status\\n\"));\n\n if (applied.length > 0) {\n console.log(chalk.green(\"Applied:\"));\n for (const m of applied) {\n console.log(chalk.green(` ✓ ${m.name}`));\n }\n }\n\n if (pending.length > 0) {\n console.log(chalk.yellow(\"\\nPending:\"));\n for (const m of pending) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n }\n\n if (applied.length === 0 && pending.length === 0) {\n console.log(chalk.dim(\"No migrations found.\"));\n }\n\n console.log();\n}\n","import { readdirSync, statSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { generateReverseSql } from \"./reverse.js\";\n\nexport interface MigrationFile {\n name: string;\n path: string;\n version: string;\n mtime: number;\n}\n\n/**\n * List all migration files in a directory.\n */\nexport function listMigrations(migrationsDir: string): MigrationFile[] {\n try {\n const files = readdirSync(migrationsDir);\n return files\n .filter((f) => f.endsWith(\".sql\"))\n .map((f) => {\n const path = join(migrationsDir, f);\n const match = f.match(/^(\\d+)/);\n return {\n name: f,\n path,\n version: match ? match[1] : f,\n mtime: statSync(path).mtime.getTime(),\n };\n })\n .sort((a, b) => a.version.localeCompare(b.version));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the most recently created migration file.\n */\nexport function getMostRecentMigration(\n migrationsDir: string\n): MigrationFile | null {\n const migrations = listMigrations(migrationsDir);\n if (migrations.length === 0) return null;\n\n return migrations.reduce((most, current) =>\n current.mtime > most.mtime ? current : most\n );\n}\n\n/**\n * Generate a new migration filename with timestamp.\n */\nexport function generateMigrationFilename(name: string): string {\n const timestamp = new Date().toISOString().replace(/[-:T]/g, \"\").slice(0, 14);\n const sanitized = name.replace(/\\s+/g, \"_\").toLowerCase();\n return `${timestamp}_${sanitized}.sql`;\n}\n\n/**\n * Create a new migration file with dbmate format.\n */\nexport function createMigrationFile(\n migrationsDir: string,\n name: string,\n upSql: string = \"\",\n downSql: string = \"\"\n): string {\n const filename = generateMigrationFilename(name);\n const filepath = join(migrationsDir, filename);\n\n // Auto-generate down SQL if not provided and up SQL exists\n if (!downSql && upSql) {\n downSql = generateReverseSql(upSql);\n }\n\n const content = `-- migrate:up\n${upSql}\n\n-- migrate:down\n${downSql}\n`;\n\n writeFileSync(filepath, content, \"utf-8\");\n return filepath;\n}\n\n/**\n * Update an existing migration file with SQL.\n */\nexport function updateMigrationFile(filepath: string, upSql: string): void {\n const content = readFileSync(filepath, \"utf-8\");\n const updated = content.replace(\n /-- migrate:up\\n/,\n `-- migrate:up\\n${upSql}\\n\\n`\n );\n writeFileSync(filepath, updated, \"utf-8\");\n}\n\n/**\n * Parse a migration file into up and down sections.\n */\nexport function parseMigrationFile(filepath: string): {\n up: string;\n down: string;\n} {\n const content = readFileSync(filepath, \"utf-8\");\n const upMatch = content.match(\n /-- migrate:up\\n([\\s\\S]*?)(?=-- migrate:down|$)/\n );\n const downMatch = content.match(/-- migrate:down\\n([\\s\\S]*?)$/);\n\n return {\n up: upMatch ? upMatch[1].trim() : \"\",\n down: downMatch ? downMatch[1].trim() : \"\",\n };\n}\n","/**\n * Generate reverse SQL for simple DDL statements.\n * LIMITATION: Only supports basic CREATE/DROP TABLE/INDEX and ADD/DROP COLUMN.\n * Complex changes (ALTER COLUMN type, constraints) need manual intervention.\n */\nexport function generateReverseSql(upSql: string): string {\n if (!upSql) return \"\";\n\n const downStatements: string[] = [];\n const lines = upSql\n .split(\";\")\n .map((l) => l.trim())\n .filter((l) => l);\n\n for (const line of lines) {\n // CREATE TABLE x -> DROP TABLE x\n const createTableMatch = line.match(\n /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s(]+)/i\n );\n if (createTableMatch) {\n const tableName = createTableMatch[1];\n downStatements.push(`DROP TABLE ${tableName};`);\n continue;\n }\n\n // DROP TABLE x -> Manual\n const dropTableMatch = line.match(\n /DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropTableMatch) {\n const tableName = dropTableMatch[1];\n downStatements.push(`-- Manual: Recreate table ${tableName}`);\n continue;\n }\n\n // ALTER TABLE x ADD COLUMN y -> ALTER TABLE x DROP COLUMN y\n const addColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+ADD\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (addColumnMatch) {\n const [, tableName, colName] = addColumnMatch;\n downStatements.push(`ALTER TABLE ${tableName} DROP COLUMN ${colName};`);\n continue;\n }\n\n // ALTER TABLE x DROP COLUMN y -> Manual\n const dropColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+DROP\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (dropColumnMatch) {\n const [, tableName, colName] = dropColumnMatch;\n downStatements.push(\n `-- Manual: Add column ${colName} back to table ${tableName}`\n );\n continue;\n }\n\n // CREATE INDEX x -> DROP INDEX x\n const createIndexMatch = line.match(\n /CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s]+)\\s+ON/i\n );\n if (createIndexMatch) {\n const indexName = createIndexMatch[1];\n downStatements.push(`DROP INDEX ${indexName};`);\n continue;\n }\n\n // DROP INDEX x -> Manual\n const dropIndexMatch = line.match(\n /DROP\\s+INDEX\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropIndexMatch) {\n const indexName = dropIndexMatch[1];\n downStatements.push(`-- Manual: Recreate index ${indexName}`);\n continue;\n }\n\n // Fallback\n downStatements.push(`-- Manual: Revert ${line.substring(0, 50)}...`);\n }\n\n // Reverse the order of down statements\n return downStatements.reverse().join(\"\\n\");\n}\n","import { Database } from \"./database.js\";\nimport {\n listMigrations,\n parseMigrationFile,\n type MigrationFile,\n} from \"./migrations.js\";\n\nconst SCHEMA_MIGRATIONS_TABLE = \"schema_migrations\";\n\n/**\n * Migration runner - replaces dbmate functionality.\n */\nexport class MigrationRunner {\n private db: Database;\n private migrationsDir: string;\n\n constructor(db: Database, migrationsDir: string) {\n this.db = db;\n this.migrationsDir = migrationsDir;\n }\n\n /**\n * Ensure schema_migrations table exists.\n */\n async ensureTable(): Promise<void> {\n await this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_MIGRATIONS_TABLE} (\n version VARCHAR(255) PRIMARY KEY\n );\n `);\n }\n\n /**\n * Get list of applied migration versions.\n */\n async getAppliedVersions(): Promise<Set<string>> {\n await this.ensureTable();\n const result = await this.db.query(\n `SELECT version FROM ${SCHEMA_MIGRATIONS_TABLE};`\n );\n return new Set(result.rows.map((row) => row.version as string));\n }\n\n /**\n * Mark a migration as applied.\n */\n async markApplied(version: string, client?: any): Promise<void> {\n await this.ensureTable();\n const sql = `\n INSERT INTO ${SCHEMA_MIGRATIONS_TABLE} (version)\n VALUES ($1)\n ON CONFLICT DO NOTHING;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Mark a migration as not applied (for rollback).\n */\n async markUnapplied(version: string, client?: any): Promise<void> {\n const sql = `\n DELETE FROM ${SCHEMA_MIGRATIONS_TABLE}\n WHERE version = $1;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Get pending migrations (not yet applied).\n */\n async getPendingMigrations(): Promise<MigrationFile[]> {\n const all = listMigrations(this.migrationsDir);\n const applied = await this.getAppliedVersions();\n return all.filter((m) => !applied.has(m.version));\n }\n\n /**\n * Apply a single migration.\n */\n async applyMigration(migration: MigrationFile): Promise<void> {\n const { up } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (up) {\n await client.query(up);\n }\n await this.markApplied(migration.version, client);\n });\n }\n\n /**\n * Roll back a single migration.\n */\n async rollbackMigration(migration: MigrationFile): Promise<void> {\n const { down } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (down) {\n await client.query(down);\n }\n await this.markUnapplied(migration.version, client);\n });\n }\n\n /**\n * Apply all pending migrations.\n */\n async migrateUp(): Promise<MigrationFile[]> {\n const pending = await this.getPendingMigrations();\n for (const migration of pending) {\n await this.applyMigration(migration);\n }\n return pending;\n }\n\n /**\n * Get migration status.\n */\n async status(): Promise<{\n applied: MigrationFile[];\n pending: MigrationFile[];\n }> {\n const all = listMigrations(this.migrationsDir);\n const appliedVersions = await this.getAppliedVersions();\n\n return {\n applied: all.filter((m) => appliedVersions.has(m.version)),\n pending: all.filter((m) => !appliedVersions.has(m.version)),\n };\n }\n}\n","import * as readline from 'readline';\n\nlet rl: readline.Interface | null = null;\n\n/**\n * Get or create readline interface.\n */\nfunction getReadline(): readline.Interface {\n if (!rl) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n }\n return rl;\n}\n\n/**\n * Close readline interface.\n */\nexport function closePrompts(): void {\n if (rl) {\n rl.close();\n rl = null;\n }\n}\n\n/**\n * Ask user a question and return their answer.\n */\nexport function question(query: string): Promise<string> {\n return new Promise((resolve) => {\n getReadline().question(query, (answer) => {\n resolve(answer);\n });\n });\n}\n\n/**\n * Ask a yes/no question.\n */\nexport async function confirm(query: string): Promise<boolean> {\n const answer = await question(`${query} (yes/no): `);\n return answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { Database } from '../lib/database.js';\nimport { MigrationRunner } from '../lib/runner.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\n/**\n * Mark a migration as applied without running it.\n */\nexport async function markApplied(version: string): Promise<void> {\n if (!version) {\n console.error(chalk.red('Error: Migration version is required'));\n console.log(chalk.dim('\\nUsage: nexusql mark-applied <version>'));\n console.log(chalk.dim('Example: nexusql mark-applied 20251209153535'));\n process.exit(1);\n }\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(`Marking migration ${version} as applied...`).start();\n\n try {\n await runner.markApplied(version);\n spinner.succeed(`Migration ${version} marked as applied`);\n } catch (error) {\n spinner.fail('Failed to mark migration as applied');\n throw error;\n }\n}\n","import { writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport chalk from 'chalk';\nimport { generateConfigTemplate } from '../lib/config.js';\n\nexport interface InitOptions {\n force?: boolean;\n}\n\n/**\n * Initialize nexusql configuration.\n */\nexport async function init(options: InitOptions = {}): Promise<void> {\n const cwd = process.cwd();\n\n // Create config file\n const configPath = join(cwd, 'nexusql.config.js');\n\n if (existsSync(configPath) && !options.force) {\n console.log(chalk.yellow('nexusql.config.js already exists.'));\n console.log(chalk.dim('Use --force to overwrite.'));\n return;\n }\n\n writeFileSync(configPath, generateConfigTemplate(), 'utf-8');\n console.log(chalk.green('Created nexusql.config.js'));\n\n // Create migrations directory\n const migrationsDir = join(cwd, 'db', 'migrations');\n if (!existsSync(migrationsDir)) {\n mkdirSync(migrationsDir, { recursive: true });\n console.log(chalk.green('Created db/migrations/'));\n }\n\n // Create .env.example if it doesn't exist\n const envExamplePath = join(cwd, '.env.example');\n if (!existsSync(envExamplePath)) {\n writeFileSync(\n envExamplePath,\n 'DATABASE_URL=postgres://user:password@localhost:5432/database\\n',\n 'utf-8'\n );\n console.log(chalk.green('Created .env.example'));\n }\n\n console.log(chalk.bold('\\nNext steps:'));\n console.log(' 1. Copy .env.example to .env and set your DATABASE_URL');\n console.log(' 2. Create your schema.dbml file');\n console.log(' 3. Run \"nexusql gen\" to generate migration SQL');\n console.log(' 4. Run \"nexusql migrate\" to create and apply migrations\\n');\n}\n"],"mappings":";;;AACA,SAAS,eAAe;;;ACDxB,SAAS,cAAc,qBAAqB;AAC5C,SAAS,eAAe;AACxB,OAAO,SAAS;AAChB,OAAO,WAAW;;;ACHlB,OAAO,QAAQ;;;ACeR,SAAS,oBAAoB,QAA4B;AAC9D,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,CAAC,EAAE,UAAU,MAAM,UAAU,MAAM,MAAM,UAAU,SAAS,EAAE,IAAI;AACxE,QAAM,kBAAkB,mBAAmB,QAAQ;AAEnD,SAAO;AAAA,IACL,KAAK,GAAG,QAAQ,MAAM,IAAI,IAAI,eAAe,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,GAAG,MAAM;AAAA,IAClF;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKO,SAAS,WAAW,OAAmB,UAA0B;AACtE,SAAO,GAAG,MAAM,QAAQ,MAAM,MAAM,IAAI,IAAI,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,QAAQ,GAAG,MAAM,MAAM;AACnH;;;AD3CA,IAAM,EAAE,OAAO,IAAI;AAOZ,IAAM,WAAN,MAAM,UAAS;AAAA,EACZ;AAAA,EACA;AAAA,EAER,YAAY,kBAA0B;AACpC,SAAK,UAAU,oBAAoB,gBAAgB;AACnD,SAAK,mBAAmB,KAAK,QAAQ;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,KAAmC;AAC7C,UAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AACrE,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,MAAM,OAAO,MAAM,GAAG;AACrC,aAAO;AAAA,QACL,MAAM,OAAO;AAAA,QACb,UAAU,OAAO,YAAY;AAAA,MAC/B;AAAA,IACF,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,KAAa,QAAyC;AACtE,UAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AACrE,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,MAAM,OAAO,MAAM,KAAK,MAAM;AAC7C,aAAO;AAAA,QACL,MAAM,OAAO;AAAA,QACb,UAAU,OAAO,YAAY;AAAA,MAC/B;AAAA,IACF,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,KAAa,QAAkC;AAC9D,UAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AACrE,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,YAAM,OAAO,MAAM,KAAK,MAAM;AAAA,IAChC,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,KAA4B;AACrC,UAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AACrE,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,YAAM,OAAO,MAAM,GAAG;AAAA,IACxB,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAmB,IAAmD;AAC1E,UAAM,SAAS,IAAI,OAAO,EAAE,kBAAkB,KAAK,iBAAiB,CAAC;AACrE,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,YAAM,OAAO,MAAM,OAAO;AAC1B,YAAM,SAAS,MAAM,GAAG,MAAM;AAC9B,YAAM,OAAO,MAAM,QAAQ;AAC3B,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,OAAO,MAAM,UAAU;AAC7B,YAAM;AAAA,IACR,UAAE;AACA,YAAM,OAAO,IAAI;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,MAA6B;AAChD,UAAM,KAAK,KAAK,oBAAoB,IAAI,IAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,MAA6B;AAC9C,UAAM,KAAK,KAAK,4BAA4B,IAAI,IAAI;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAAwB;AACnC,UAAM,SAAS,WAAW,KAAK,SAAS,IAAI;AAC5C,WAAO,IAAI,UAAS,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,YAAqC;AAC3D,eAAW,OAAO,YAAY;AAC5B,UAAI;AACF,cAAM,KAAK,KAAK,mCAAmC,GAAG,IAAI;AAAA,MAC5D,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,WAC8D;AAC9D,UAAM,SAAS,MAAM,KAAK,MAAM;AAAA;AAAA;AAAA,4BAGR,SAAS;AAAA;AAAA,KAEhC;AACD,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAgC;AACpC,UAAM,SAAS,MAAM,KAAK,MAAM;AAAA;AAAA,KAE/B;AACD,WAAO,OAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,SAAmB;AAAA,EACzD;AACF;;;AE5KA,SAAS,QAAQ,qBAAqB;AAS/B,SAAS,UAAU,aAAiC;AACzD,QAAM,WAAW,IAAI,OAAO,EAAE,MAAM,aAAa,MAAM;AACvD,QAAM,MAAM,cAAc,OAAO,UAAU,UAAU;AACrD,SAAO,EAAE,IAAI;AACf;;;ACbA,SAAS,oBAAoB;AAetB,SAAS,SACd,SACA,OACA,UAAgC,CAAC,GACpB;AACb,QAAM,OAAO,CAAC,SAAS,KAAK;AAC5B,MAAI,QAAQ,QAAQ;AAClB,SAAK,KAAK,UAAU;AAAA,EACtB;AAEA,MAAI;AACF,UAAM,SAAS,aAAa,SAAS,MAAM;AAAA,MACzC,UAAU;AAAA,MACV,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,WAAO,EAAE,KAAK,UAAU,IAAI,YAAY,MAAM;AAAA,EAChD,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,WAAW,KAAK,IAAI,QAAQ;AAElC,aAAO,EAAE,KAAK,IAAI,QAAQ,YAAY,KAAK;AAAA,IAC7C;AAEA,QAAI,IAAI,WAAW,GAAG;AACpB,YAAM,IAAI,MAAM,gBAAgB,IAAI,UAAU,eAAe,EAAE;AAAA,IACjE;AAGA,WAAO,EAAE,KAAK,IAAI,UAAU,IAAI,YAAY,QAAQ,IAAI,MAAM,EAAE;AAAA,EAClE;AACF;AAKO,SAAS,uBAAuB,KAAqB;AAC1D,SAAO,IACJ,MAAM,IAAI,EACV,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,mBAAmB,CAAC,EACpD,KAAK,IAAI,EACT,KAAK;AACV;;;AC1DA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AACrB,SAAS,qBAAqB;AAC9B,SAAS,UAAU,kBAAkB;AASrC,IAAM,iBAAgC;AAAA,EACpC,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,YAAY,CAAC,WAAW;AAC1B;AAKA,eAAsB,WAAW,MAAc,QAAQ,IAAI,GAA2B;AAEpF,aAAW;AAEX,QAAM,aAAa,KAAK,KAAK,mBAAmB;AAChD,MAAI,aAAqC,CAAC;AAE1C,MAAI,WAAW,UAAU,GAAG;AAC1B,QAAI;AACF,YAAM,YAAY,cAAc,UAAU,EAAE;AAC5C,YAAM,SAAS,MAAM,OAAO;AAC5B,mBAAa,OAAO,WAAW;AAAA,IACjC,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,aAAa,QAAQ,IAAI,gBAAgB,WAAW;AAAA,EACtD;AACF;AAKO,SAAS,eAAe,QAA+B;AAC5D,QAAM,MAAM,OAAO,eAAe,QAAQ,IAAI;AAC9C,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AACA,SAAO;AACT;AAKO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYT;;;ALvDA,eAAsB,IAAI,UAAsB,CAAC,GAAoB;AACnE,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AAEnC,QAAM,UAAU,IAAI;AAGpB,UAAQ,MAAM,wBAAwB;AACtC,QAAM,aAAa,QAAQ,OAAO,MAAM;AACxC,MAAI;AACJ,MAAI;AACF,kBAAc,aAAa,YAAY,OAAO;AAC9C,YAAQ,QAAQ,kBAAkB;AAAA,EACpC,QAAQ;AACN,YAAQ,KAAK,0BAA0B,UAAU,EAAE;AACnD,UAAM,IAAI,MAAM,0BAA0B,UAAU,EAAE;AAAA,EACxD;AAGA,UAAQ,MAAM,2BAA2B;AACzC,QAAM,EAAE,KAAK,UAAU,IAAI,UAAU,WAAW;AAChD,UAAQ,QAAQ,uBAAuB;AAGvC,QAAM,aAAa,gBAAgB,KAAK,IAAI,CAAC;AAC7C,UAAQ,MAAM,2BAA2B,UAAU,EAAE;AACrD,MAAI;AACF,UAAM,GAAG,eAAe,UAAU;AAClC,YAAQ,QAAQ,0BAA0B,UAAU,EAAE;AAAA,EACxD,SAAS,OAAO;AACd,YAAQ,KAAK,gCAAgC;AAC7C,UAAM;AAAA,EACR;AAEA,QAAM,SAAS,GAAG,aAAa,UAAU;AACzC,MAAI,eAAe;AAEnB,MAAI;AAEF,YAAQ,MAAM,0BAA0B;AACxC,UAAM,OAAO,kBAAkB,OAAO,UAAU;AAChD,YAAQ,QAAQ,sBAAsB;AAGtC,YAAQ,MAAM,sCAAsC;AACpD,UAAM,OAAO,KAAK,SAAS;AAC3B,YAAQ,QAAQ,kCAAkC;AAGlD,QAAI,QAAQ,SAAS;AACnB,YAAM,SAAS,MAAM,OAAO,WAAW;AACvC,cAAQ,IAAI,MAAM,IAAI;AAAA,2BAA8B,OAAO,KAAK,IAAI,CAAC,EAAE,CAAC;AAAA,IAC1E;AAGA,YAAQ,MAAM,8BAA8B;AAC5C,UAAM,cAAc;AAAA,MAClB,GAAG,iBAAiB;AAAA,MACpB,OAAO,iBAAiB;AAAA,MACxB,EAAE,QAAQ,KAAK;AAAA,IACjB;AAEA,mBAAe,uBAAuB,YAAY,GAAG;AAErD,QAAI,YAAY,YAAY;AAC1B,cAAQ,QAAQ,0BAA0B;AAAA,IAC5C,OAAO;AACL,cAAQ,KAAK,4BAA4B;AAAA,IAC3C;AAGA,YAAQ,MAAM,6BAA6B;AAC3C,UAAM,aAAa,MAAM,kBAAkB,IAAI,MAAM;AACrD,QAAI,YAAY;AACd,qBAAe,eACX,GAAG,YAAY;AAAA;AAAA;AAAA,EAA2B,UAAU,KACpD;AAAA,EAAuB,UAAU;AAAA,IACvC;AACA,YAAQ,QAAQ,yBAAyB;AAAA,EAC3C,UAAE;AAEA,YAAQ,MAAM,8BAA8B;AAC5C,QAAI;AACF,YAAM,GAAG,aAAa,UAAU;AAChC,cAAQ,QAAQ,0BAA0B;AAAA,IAC5C,QAAQ;AACN,cAAQ,KAAK,iCAAiC;AAAA,IAChD;AAAA,EACF;AAGA,QAAM,WAAW,gBAAgB;AAEjC,MAAI,QAAQ,QAAQ;AAClB,kBAAc,QAAQ,QAAQ,UAAU,OAAO;AAC/C,YAAQ,IAAI,MAAM,MAAM;AAAA,4BAA+B,QAAQ,MAAM,EAAE,CAAC;AAAA,EAC1E,OAAO;AACL,YAAQ,IAAI,MAAM,KAAK,2BAA2B,CAAC;AACnD,YAAQ,IAAI,QAAQ;AAAA,EACtB;AAEA,SAAO;AACT;AAMA,eAAe,kBACb,WACA,UACiB;AACjB,QAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBrB,QAAM,CAAC,iBAAiB,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC1D,UAAU,MAAM,YAAY;AAAA,IAC5B,SAAS,MAAM,YAAY;AAAA,EAC7B,CAAC;AAED,QAAM,aAAa,oBAAI,IAA2B;AAClD,QAAM,YAAY,oBAAI,IAAyD;AAE/E,aAAW,OAAO,gBAAgB,MAAM;AACtC,UAAM,MAAM,GAAG,IAAI,UAAU,IAAI,IAAI,WAAW;AAChD,eAAW,IAAI,KAAK,IAAI,WAA4B;AAAA,EACtD;AAEA,aAAW,OAAO,eAAe,MAAM;AACrC,UAAM,MAAM,GAAG,IAAI,UAAU,IAAI,IAAI,WAAW;AAChD,cAAU,IAAI,KAAK;AAAA,MACjB,KAAK,IAAI;AAAA,MACT,aAAa,IAAI;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,QAAM,eAAyB,CAAC;AAEhC,aAAW,CAAC,KAAK,MAAM,KAAK,WAAW;AACrC,UAAM,UAAU,WAAW,IAAI,GAAG;AAClC,QAAI,YAAY,OAAO,eAAe,OAAO,KAAK;AAChD,mBAAa,KAAK,OAAO,GAAG;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,aAAa,KAAK,IAAI;AAC/B;;;AMpLA,SAAS,WAAW,cAAAA,mBAAkB;AACtC,OAAOC,YAAW;AAClB,OAAOC,UAAS;;;ACFhB,SAAS,aAAa,UAAU,gBAAAC,eAAc,iBAAAC,sBAAqB;AACnE,SAAS,QAAAC,aAAY;;;ACId,SAAS,mBAAmB,OAAuB;AACxD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,iBAA2B,CAAC;AAClC,QAAM,QAAQ,MACX,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,CAAC;AAElB,aAAW,QAAQ,OAAO;AAExB,UAAM,mBAAmB,KAAK;AAAA,MAC5B;AAAA,IACF;AACA,QAAI,kBAAkB;AACpB,YAAM,YAAY,iBAAiB,CAAC;AACpC,qBAAe,KAAK,cAAc,SAAS,GAAG;AAC9C;AAAA,IACF;AAGA,UAAM,iBAAiB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,gBAAgB;AAClB,YAAM,YAAY,eAAe,CAAC;AAClC,qBAAe,KAAK,6BAA6B,SAAS,EAAE;AAC5D;AAAA,IACF;AAGA,UAAM,iBAAiB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,gBAAgB;AAClB,YAAM,CAAC,EAAE,WAAW,OAAO,IAAI;AAC/B,qBAAe,KAAK,eAAe,SAAS,gBAAgB,OAAO,GAAG;AACtE;AAAA,IACF;AAGA,UAAM,kBAAkB,KAAK;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,iBAAiB;AACnB,YAAM,CAAC,EAAE,WAAW,OAAO,IAAI;AAC/B,qBAAe;AAAA,QACb,yBAAyB,OAAO,kBAAkB,SAAS;AAAA,MAC7D;AACA;AAAA,IACF;AAGA,UAAM,mBAAmB,KAAK;AAAA,MAC5B;AAAA,IACF;AACA,QAAI,kBAAkB;AACpB,YAAM,YAAY,iBAAiB,CAAC;AACpC,qBAAe,KAAK,cAAc,SAAS,GAAG;AAC9C;AAAA,IACF;AAGA,UAAM,iBAAiB,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,gBAAgB;AAClB,YAAM,YAAY,eAAe,CAAC;AAClC,qBAAe,KAAK,6BAA6B,SAAS,EAAE;AAC5D;AAAA,IACF;AAGA,mBAAe,KAAK,qBAAqB,KAAK,UAAU,GAAG,EAAE,CAAC,KAAK;AAAA,EACrE;AAGA,SAAO,eAAe,QAAQ,EAAE,KAAK,IAAI;AAC3C;;;ADrEO,SAAS,eAAe,eAAwC;AACrE,MAAI;AACF,UAAM,QAAQ,YAAY,aAAa;AACvC,WAAO,MACJ,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,CAAC,EAChC,IAAI,CAAC,MAAM;AACV,YAAM,OAAOC,MAAK,eAAe,CAAC;AAClC,YAAM,QAAQ,EAAE,MAAM,QAAQ;AAC9B,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,SAAS,QAAQ,MAAM,CAAC,IAAI;AAAA,QAC5B,OAAO,SAAS,IAAI,EAAE,MAAM,QAAQ;AAAA,MACtC;AAAA,IACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,OAAO,CAAC;AAAA,EACtD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAmBO,SAAS,0BAA0B,MAAsB;AAC9D,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,UAAU,EAAE,EAAE,MAAM,GAAG,EAAE;AAC5E,QAAM,YAAY,KAAK,QAAQ,QAAQ,GAAG,EAAE,YAAY;AACxD,SAAO,GAAG,SAAS,IAAI,SAAS;AAClC;AAKO,SAAS,oBACd,eACA,MACA,QAAgB,IAChB,UAAkB,IACV;AACR,QAAM,WAAW,0BAA0B,IAAI;AAC/C,QAAM,WAAWC,MAAK,eAAe,QAAQ;AAG7C,MAAI,CAAC,WAAW,OAAO;AACrB,cAAU,mBAAmB,KAAK;AAAA,EACpC;AAEA,QAAM,UAAU;AAAA,EAChB,KAAK;AAAA;AAAA;AAAA,EAGL,OAAO;AAAA;AAGP,EAAAC,eAAc,UAAU,SAAS,OAAO;AACxC,SAAO;AACT;AAiBO,SAAS,mBAAmB,UAGjC;AACA,QAAM,UAAUC,cAAa,UAAU,OAAO;AAC9C,QAAM,UAAU,QAAQ;AAAA,IACtB;AAAA,EACF;AACA,QAAM,YAAY,QAAQ,MAAM,8BAA8B;AAE9D,SAAO;AAAA,IACL,IAAI,UAAU,QAAQ,CAAC,EAAE,KAAK,IAAI;AAAA,IAClC,MAAM,YAAY,UAAU,CAAC,EAAE,KAAK,IAAI;AAAA,EAC1C;AACF;;;AE5GA,IAAM,0BAA0B;AAKzB,IAAM,kBAAN,MAAsB;AAAA,EACnB;AAAA,EACA;AAAA,EAER,YAAY,IAAc,eAAuB;AAC/C,SAAK,KAAK;AACV,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAA6B;AACjC,UAAM,KAAK,GAAG,KAAK;AAAA,mCACY,uBAAuB;AAAA;AAAA;AAAA,KAGrD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAA2C;AAC/C,UAAM,KAAK,YAAY;AACvB,UAAM,SAAS,MAAM,KAAK,GAAG;AAAA,MAC3B,uBAAuB,uBAAuB;AAAA,IAChD;AACA,WAAO,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAiB,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,SAAiB,QAA6B;AAC9D,UAAM,KAAK,YAAY;AACvB,UAAM,MAAM;AAAA,oBACI,uBAAuB;AAAA;AAAA;AAAA;AAKvC,QAAI,QAAQ;AACV,YAAM,OAAO,MAAM,KAAK,CAAC,OAAO,CAAC;AAAA,IACnC,OAAO;AACL,YAAM,KAAK,GAAG,WAAW,KAAK,CAAC,OAAO,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,SAAiB,QAA6B;AAChE,UAAM,MAAM;AAAA,oBACI,uBAAuB;AAAA;AAAA;AAIvC,QAAI,QAAQ;AACV,YAAM,OAAO,MAAM,KAAK,CAAC,OAAO,CAAC;AAAA,IACnC,OAAO;AACL,YAAM,KAAK,GAAG,WAAW,KAAK,CAAC,OAAO,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,uBAAiD;AACrD,UAAM,MAAM,eAAe,KAAK,aAAa;AAC7C,UAAM,UAAU,MAAM,KAAK,mBAAmB;AAC9C,WAAO,IAAI,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,OAAO,CAAC;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,WAAyC;AAC5D,UAAM,EAAE,IAAAC,IAAG,IAAI,mBAAmB,UAAU,IAAI;AAEhD,UAAM,KAAK,GAAG,gBAAgB,OAAO,WAAW;AAC9C,UAAIA,KAAI;AACN,cAAM,OAAO,MAAMA,GAAE;AAAA,MACvB;AACA,YAAM,KAAK,YAAY,UAAU,SAAS,MAAM;AAAA,IAClD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,WAAyC;AAC/D,UAAM,EAAE,MAAAC,MAAK,IAAI,mBAAmB,UAAU,IAAI;AAElD,UAAM,KAAK,GAAG,gBAAgB,OAAO,WAAW;AAC9C,UAAIA,OAAM;AACR,cAAM,OAAO,MAAMA,KAAI;AAAA,MACzB;AACA,YAAM,KAAK,cAAc,UAAU,SAAS,MAAM;AAAA,IACpD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAsC;AAC1C,UAAM,UAAU,MAAM,KAAK,qBAAqB;AAChD,eAAW,aAAa,SAAS;AAC/B,YAAM,KAAK,eAAe,SAAS;AAAA,IACrC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAGH;AACD,UAAM,MAAM,eAAe,KAAK,aAAa;AAC7C,UAAM,kBAAkB,MAAM,KAAK,mBAAmB;AAEtD,WAAO;AAAA,MACL,SAAS,IAAI,OAAO,CAAC,MAAM,gBAAgB,IAAI,EAAE,OAAO,CAAC;AAAA,MACzD,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,OAAO,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;;;AC5IA,YAAY,cAAc;AAE1B,IAAI,KAAgC;AAKpC,SAAS,cAAkC;AACzC,MAAI,CAAC,IAAI;AACP,SAAc,yBAAgB;AAAA,MAC5B,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAKO,SAAS,eAAqB;AACnC,MAAI,IAAI;AACN,OAAG,MAAM;AACT,SAAK;AAAA,EACP;AACF;AAKO,SAAS,SAAS,OAAgC;AACvD,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,gBAAY,EAAE,SAAS,OAAO,CAAC,WAAW;AACxC,MAAAA,SAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACH;AAKA,eAAsB,QAAQ,OAAiC;AAC7D,QAAM,SAAS,MAAM,SAAS,GAAG,KAAK,aAAa;AACnD,SAAO,OAAO,YAAY,MAAM,SAAS,OAAO,YAAY,MAAM;AACpE;;;AJzBA,eAAsB,QAAQ,UAA0B,CAAC,GAAkB;AACzE,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AACnC,QAAM,SAAS,IAAI,gBAAgB,IAAI,OAAO,UAAU;AAExD,UAAQ,IAAIC,OAAM,KAAK,oCAAoC,CAAC;AAC5D,UAAQ,IAAI,YAAY;AACxB,UAAQ,IAAI,wCAAwC;AACpD,UAAQ,IAAI,kCAAkC;AAC9C,UAAQ,IAAI,uCAAuC;AAEnD,MAAI;AAEF,YAAQ,IAAIA,OAAM,KAAK,wCAAwC,CAAC;AAChE,UAAM,eAAe,MAAM,IAAI,EAAE,SAAS,MAAM,CAAC;AAEjD,UAAM,YACJ,CAAC,gBAAgB,iBAAiB;AAEpC,QAAI,WAAW;AACb,cAAQ,IAAIA,OAAM,OAAO,iCAAiC,CAAC;AAE3D,UAAI,CAAC,QAAQ,KAAK;AAChB,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,QACF;AACA,YAAI,CAAC,SAAS;AACZ,kBAAQ,IAAIA,OAAM,IAAI,wBAAwB,CAAC;AAC/C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,YAAQ,IAAIA,OAAM,KAAK,2CAA2C,CAAC;AAEnE,QAAI,gBAAgB,QAAQ;AAC5B,QAAI,CAAC,eAAe;AAClB,sBAAgB,MAAM;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB,cAAc,KAAK,MAAM,IAAI;AACjD,cAAQ,IAAIA,OAAM,IAAI,8CAA8C,CAAC;AACrE;AAAA,IACF;AAEA,UAAM,gBAAgB,cAAc,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAC9D,YAAQ,IAAIA,OAAM,MAAM;AAAA,wBAA2B,aAAa,EAAE,CAAC;AAGnE,QAAI,CAAC,QAAQ,KAAK;AAChB,YAAM,UAAU,MAAM,QAAQ,0BAA0B;AACxD,UAAI,CAAC,SAAS;AACZ,gBAAQ,IAAIA,OAAM,IAAI,wBAAwB,CAAC;AAC/C;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAACC,YAAW,OAAO,UAAU,GAAG;AAClC,gBAAU,OAAO,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAClD;AAGA,UAAM,UAAUC,KAAI,4BAA4B,EAAE,MAAM;AACxD,UAAM,WAAW;AAAA,MACf,OAAO;AAAA,MACP;AAAA,MACA,YAAY,KAAK;AAAA,IACnB;AACA,YAAQ,QAAQ,2BAA2B,QAAQ,EAAE;AAGrD,YAAQ,IAAIF,OAAM,KAAK,qCAAqC,CAAC;AAE7D,QAAI,cAAc,QAAQ;AAC1B,QAAI,gBAAgB,UAAa,CAAC,QAAQ,KAAK;AAC7C,oBAAc,MAAM,QAAQ,2BAA2B;AAAA,IACzD;AAEA,QAAI,aAAa;AACf,YAAM,eAAeE,KAAI,uBAAuB,EAAE,MAAM;AACxD,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,UAAU;AACvC,YAAI,QAAQ,SAAS,GAAG;AACtB,uBAAa;AAAA,YACX,WAAW,QAAQ,MAAM;AAAA,UAC3B;AAAA,QACF,OAAO;AACL,uBAAa,KAAK,gCAAgC;AAAA,QACpD;AAAA,MACF,SAAS,OAAO;AACd,qBAAa,KAAK,2BAA2B;AAC7C,cAAM;AAAA,MACR;AAAA,IACF,OAAO;AACL,cAAQ,IAAIF,OAAM,IAAI,sCAAsC,CAAC;AAC7D,cAAQ,IAAIA,OAAM,IAAI,+CAA+C,CAAC;AAAA,IACxE;AAEA,YAAQ,IAAIA,OAAM,MAAM;AAAA,kBAAqB,QAAQ;AAAA,CAAI,CAAC;AAAA,EAC5D,UAAE;AACA,iBAAa;AAAA,EACf;AACF;AAKA,eAAsB,GAAG,UAAgC,CAAC,GAAkB;AAC1E,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AACnC,QAAM,SAAS,IAAI,gBAAgB,IAAI,OAAO,UAAU;AAExD,QAAM,UAAUE,KAAI,wBAAwB,EAAE,MAAM;AAEpD,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,qBAAqB;AAElD,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,KAAK,uBAAuB;AACpC;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,cAAQ,KAAK,SAAS,QAAQ,MAAM,wBAAwB;AAC5D,iBAAW,KAAK,SAAS;AACvB,gBAAQ,IAAIF,OAAM,KAAK,YAAO,EAAE,IAAI,EAAE,CAAC;AAAA,MACzC;AACA;AAAA,IACF;AAEA,YAAQ,OAAO;AACf,eAAW,aAAa,SAAS;AAC/B,YAAM,OAAO,eAAe,SAAS;AACrC,cAAQ,IAAIA,OAAM,MAAM,YAAO,UAAU,IAAI,EAAE,CAAC;AAAA,IAClD;AACA,YAAQ,QAAQ,WAAW,QAAQ,MAAM,eAAe;AAAA,EAC1D,SAAS,OAAO;AACd,YAAQ,KAAK,kBAAkB;AAC/B,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,KACpB,UAA6D,CAAC,GAC/C;AACf,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AACnC,QAAM,SAAS,IAAI,gBAAgB,IAAI,OAAO,UAAU;AAExD,QAAM,UAAUE,KAAI,wBAAwB,EAAE,MAAM;AAEpD,MAAI;AAGF,UAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,OAAO;AACxC,UAAM,gBAAgB,QAAQ;AAAA,MAAK,CAAC,GAAG,MACrC,EAAE,QAAQ,cAAc,EAAE,OAAO;AAAA,IACnC;AAEA,QAAI,cAAc,WAAW,GAAG;AAC9B,cAAQ,KAAK,mCAAmC;AAChD;AAAA,IACF;AAEA,QAAI,aAA6B,CAAC;AAElC,QAAI,QAAQ,IAAI;AACd,YAAM,cAAc,cAAc;AAAA,QAChC,CAAC,MAAM,EAAE,YAAY,QAAQ;AAAA,MAC/B;AACA,UAAI,gBAAgB,IAAI;AAItB,qBAAa,cAAc,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAG;AAChE,YAAI,WAAW,WAAW,GAAG;AAC3B,kBAAQ;AAAA,YACN,WAAW,QAAQ,EAAE;AAAA,UACvB;AACA;AAAA,QACF;AAAA,MACF,OAAO;AAEL,qBAAa,cAAc,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAG;AAAA,MAClE;AAAA,IACF,OAAO;AACL,YAAM,QAAQ,QAAQ,SAAS;AAC/B,mBAAa,cAAc,MAAM,GAAG,KAAK;AAAA,IAC3C;AAEA,QAAI,WAAW,WAAW,GAAG;AAC3B,cAAQ,KAAK,2BAA2B;AACxC;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,cAAQ,KAAK,kBAAkB,WAAW,MAAM,gBAAgB;AAChE,iBAAW,KAAK,YAAY;AAC1B,gBAAQ,IAAIF,OAAM,OAAO,YAAO,EAAE,IAAI,EAAE,CAAC;AAAA,MAC3C;AACA;AAAA,IACF;AAEA,YAAQ,OAAO;AACf,eAAW,aAAa,YAAY;AAClC,YAAM,OAAO,kBAAkB,SAAS;AACxC,cAAQ,IAAIA,OAAM,OAAO,cAAc,UAAU,IAAI,EAAE,CAAC;AAAA,IAC1D;AACA,YAAQ,QAAQ,eAAe,WAAW,MAAM,eAAe;AAAA,EACjE,SAAS,OAAO;AACd,YAAQ,KAAK,iBAAiB;AAC9B,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,SAAwB;AAC5C,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AACnC,QAAM,SAAS,IAAI,gBAAgB,IAAI,OAAO,UAAU;AAExD,QAAM,UAAUE,KAAI,8BAA8B,EAAE,MAAM;AAC1D,QAAM,EAAE,SAAS,QAAQ,IAAI,MAAM,OAAO,OAAO;AACjD,UAAQ,KAAK;AAEb,UAAQ,IAAIF,OAAM,KAAK,sBAAsB,CAAC;AAE9C,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,IAAIA,OAAM,MAAM,UAAU,CAAC;AACnC,eAAW,KAAK,SAAS;AACvB,cAAQ,IAAIA,OAAM,MAAM,YAAO,EAAE,IAAI,EAAE,CAAC;AAAA,IAC1C;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,IAAIA,OAAM,OAAO,YAAY,CAAC;AACtC,eAAW,KAAK,SAAS;AACvB,cAAQ,IAAIA,OAAM,OAAO,YAAO,EAAE,IAAI,EAAE,CAAC;AAAA,IAC3C;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,KAAK,QAAQ,WAAW,GAAG;AAChD,YAAQ,IAAIA,OAAM,IAAI,sBAAsB,CAAC;AAAA,EAC/C;AAEA,UAAQ,IAAI;AACd;;;AKtRA,OAAOG,YAAW;AAClB,OAAOC,UAAS;AAQhB,eAAsB,YAAY,SAAgC;AAChE,MAAI,CAAC,SAAS;AACZ,YAAQ,MAAMC,OAAM,IAAI,sCAAsC,CAAC;AAC/D,YAAQ,IAAIA,OAAM,IAAI,yCAAyC,CAAC;AAChE,YAAQ,IAAIA,OAAM,IAAI,8CAA8C,CAAC;AACrE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,cAAc,eAAe,MAAM;AACzC,QAAM,KAAK,IAAI,SAAS,WAAW;AACnC,QAAM,SAAS,IAAI,gBAAgB,IAAI,OAAO,UAAU;AAExD,QAAM,UAAUC,KAAI,qBAAqB,OAAO,gBAAgB,EAAE,MAAM;AAExE,MAAI;AACF,UAAM,OAAO,YAAY,OAAO;AAChC,YAAQ,QAAQ,aAAa,OAAO,oBAAoB;AAAA,EAC1D,SAAS,OAAO;AACd,YAAQ,KAAK,qCAAqC;AAClD,UAAM;AAAA,EACR;AACF;;;AC/BA,SAAS,iBAAAC,gBAAe,cAAAC,aAAY,aAAAC,kBAAiB;AACrD,SAAS,QAAAC,aAAY;AACrB,OAAOC,YAAW;AAUlB,eAAsB,KAAK,UAAuB,CAAC,GAAkB;AACnE,QAAM,MAAM,QAAQ,IAAI;AAGxB,QAAM,aAAaC,MAAK,KAAK,mBAAmB;AAEhD,MAAIC,YAAW,UAAU,KAAK,CAAC,QAAQ,OAAO;AAC5C,YAAQ,IAAIC,OAAM,OAAO,mCAAmC,CAAC;AAC7D,YAAQ,IAAIA,OAAM,IAAI,2BAA2B,CAAC;AAClD;AAAA,EACF;AAEA,EAAAC,eAAc,YAAY,uBAAuB,GAAG,OAAO;AAC3D,UAAQ,IAAID,OAAM,MAAM,2BAA2B,CAAC;AAGpD,QAAM,gBAAgBF,MAAK,KAAK,MAAM,YAAY;AAClD,MAAI,CAACC,YAAW,aAAa,GAAG;AAC9B,IAAAG,WAAU,eAAe,EAAE,WAAW,KAAK,CAAC;AAC5C,YAAQ,IAAIF,OAAM,MAAM,wBAAwB,CAAC;AAAA,EACnD;AAGA,QAAM,iBAAiBF,MAAK,KAAK,cAAc;AAC/C,MAAI,CAACC,YAAW,cAAc,GAAG;AAC/B,IAAAE;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,YAAQ,IAAID,OAAM,MAAM,sBAAsB,CAAC;AAAA,EACjD;AAEA,UAAQ,IAAIA,OAAM,KAAK,eAAe,CAAC;AACvC,UAAQ,IAAI,0DAA0D;AACtE,UAAQ,IAAI,mCAAmC;AAC/C,UAAQ,IAAI,kDAAkD;AAC9D,UAAQ,IAAI,6DAA6D;AAC3E;;;Ab3CA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,SAAS,EACd;AAAA,EACC;AACF,EACC,QAAQ,OAAO;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,kCAAkC,EAC9C,OAAO,eAAe,2BAA2B,EACjD,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,KAAK,OAAO;AAAA,EACpB,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,KAAK,EACb,YAAY,yCAAyC,EACrD,OAAO,uBAAuB,qCAAqC,EACnE,OAAO,iBAAiB,qBAAqB,EAC7C,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,IAAI,OAAO;AAAA,EACnB,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,SAAS,EACjB,YAAY,qDAAqD,EACjE,OAAO,qBAAqB,gBAAgB,EAC5C,OAAO,eAAe,gCAAgC,EACtD,OAAO,aAAa,2BAA2B,EAC/C,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,QAAQ,OAAO;AAAA,EACvB,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,IAAI,EACZ,YAAY,8BAA8B,EAC1C,OAAO,aAAa,qCAAqC,EACzD,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,GAAG,OAAO;AAAA,EAClB,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,6BAA6B,EACzC;AAAA,EAAO;AAAA,EAAwB;AAAA,EAAoC,CAAC,MACnE,SAAS,CAAC;AACZ,EACC,OAAO,kBAAkB,8BAA8B,EACvD,OAAO,aAAa,mCAAmC,EACvD,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,KAAK,OAAO;AAAA,EACpB,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,uBAAuB,EACnC,OAAO,YAAY;AAClB,MAAI;AACF,UAAM,OAAO;AAAA,EACf,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,wBAAwB,EAChC,YAAY,gDAAgD,EAC5D,OAAO,OAAO,YAAY;AACzB,MAAI;AACF,UAAM,YAAY,OAAO;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,UAAW,MAAgB,OAAO;AAChD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["existsSync","chalk","ora","readFileSync","writeFileSync","join","join","join","writeFileSync","readFileSync","up","down","resolve","chalk","existsSync","ora","chalk","ora","chalk","ora","writeFileSync","existsSync","mkdirSync","join","chalk","join","existsSync","chalk","writeFileSync","mkdirSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/gen.ts","../src/lib/database.ts","../src/lib/db-url.ts","../src/lib/dbml.ts","../src/lib/migra.ts","../src/lib/config.ts","../src/utils/check-migra.ts","../src/commands/migrate.ts","../src/lib/migrations.ts","../src/lib/reverse.ts","../src/lib/runner.ts","../src/utils/prompts.ts","../src/commands/mark-applied.ts","../src/commands/init.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { gen } from \"./commands/gen.js\";\nimport { migrate, up, down, status } from \"./commands/migrate.js\";\nimport { markApplied } from \"./commands/mark-applied.js\";\nimport { init } from \"./commands/init.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"nexusql\")\n .description(\n \"Database migration toolkit for PostgreSQL with DBML schema support\"\n )\n .version(\"0.1.0\");\n\nprogram\n .command(\"init\")\n .description(\"Initialize nexusql configuration\")\n .option(\"-f, --force\", \"Overwrite existing config\")\n .action(async (options) => {\n try {\n await init(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"gen\")\n .description(\"Generate migration SQL from DBML schema\")\n .option(\"-o, --output <file>\", \"Write SQL to file instead of stdout\")\n .option(\"-v, --verbose\", \"Show verbose output\")\n .action(async (options) => {\n try {\n await gen(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"migrate\")\n .description(\"Interactive migration: generate, create file, apply\")\n .option(\"-n, --name <name>\", \"Migration name\")\n .option(\"-a, --apply\", \"Apply migration after creating\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (options) => {\n try {\n await migrate(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"up\")\n .description(\"Apply all pending migrations\")\n .option(\"--dry-run\", \"Preview migrations without applying\")\n .action(async (options) => {\n try {\n await up(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"down\")\n .description(\"Rollback applied migrations\")\n .option(\"-s, --steps <number>\", \"Number of migrations to rollback\", (v) =>\n parseInt(v)\n )\n .option(\"--to <version>\", \"Rollback to specific version\")\n .option(\"--dry-run\", \"Preview rollback without applying\")\n .action(async (options) => {\n try {\n await down(options);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"status\")\n .description(\"Show migration status\")\n .action(async () => {\n try {\n await status();\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"mark-applied <version>\")\n .description(\"Mark a migration as applied without running it\")\n .action(async (version) => {\n try {\n await markApplied(version);\n } catch (error) {\n console.error(\"Error:\", (error as Error).message);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { readFileSync, writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { Database } from '../lib/database.js';\nimport { dbmlToSql } from '../lib/dbml.js';\nimport { runMigra, filterSchemaMigrations } from '../lib/migra.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\nimport { ensureMigraOrExit } from '../utils/check-migra.js';\n\nexport interface GenOptions {\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Generate migration SQL by diffing current DB against DBML schema.\n */\nexport async function gen(options: GenOptions = {}): Promise<string> {\n ensureMigraOrExit();\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n\n const spinner = ora();\n\n // Read DBML schema\n spinner.start('Reading DBML schema...');\n const schemaPath = resolve(config.schema);\n let dbmlContent: string;\n try {\n dbmlContent = readFileSync(schemaPath, 'utf-8');\n spinner.succeed('Read DBML schema');\n } catch {\n spinner.fail(`Failed to read schema: ${schemaPath}`);\n throw new Error(`Schema file not found: ${schemaPath}`);\n }\n\n // Convert DBML to SQL\n spinner.start('Converting DBML to SQL...');\n const { sql: targetSql } = dbmlToSql(dbmlContent);\n spinner.succeed('Converted DBML to SQL');\n\n // Create temp database\n const tempDbName = `nexusql_temp_${Date.now()}`;\n spinner.start(`Creating temp database: ${tempDbName}`);\n try {\n await db.createDatabase(tempDbName);\n spinner.succeed(`Created temp database: ${tempDbName}`);\n } catch (error) {\n spinner.fail('Failed to create temp database');\n throw error;\n }\n\n const tempDb = db.withDatabase(tempDbName);\n let migrationSql = '';\n\n try {\n // Install extensions\n spinner.start('Installing extensions...');\n await tempDb.installExtensions(config.extensions);\n spinner.succeed('Installed extensions');\n\n // Load schema into temp database\n spinner.start('Loading schema into temp database...');\n await tempDb.exec(targetSql);\n spinner.succeed('Loaded schema into temp database');\n\n // Debug: List tables\n if (options.verbose) {\n const tables = await tempDb.listTables();\n console.log(chalk.dim(`\\nTables in temp database: ${tables.join(', ')}`));\n }\n\n // Run migra to generate diff\n spinner.start('Generating migration diff...');\n const migraResult = runMigra(\n db.getConnectionUrl(),\n tempDb.getConnectionUrl(),\n { unsafe: true }\n );\n\n migrationSql = filterSchemaMigrations(migraResult.sql);\n\n if (migraResult.hasChanges) {\n spinner.succeed('Generated migration diff');\n } else {\n spinner.info('No schema changes detected');\n }\n\n // Get comment changes\n spinner.start('Checking comment changes...');\n const commentSql = await getCommentChanges(db, tempDb);\n if (commentSql) {\n migrationSql = migrationSql\n ? `${migrationSql}\\n\\n-- Comment changes\\n${commentSql}`\n : `-- Comment changes\\n${commentSql}`;\n }\n spinner.succeed('Checked comment changes');\n } finally {\n // Cleanup temp database\n spinner.start('Cleaning up temp database...');\n try {\n await db.dropDatabase(tempDbName);\n spinner.succeed('Cleaned up temp database');\n } catch {\n spinner.warn('Failed to cleanup temp database');\n }\n }\n\n // Output result\n const finalSql = migrationSql || '-- No changes detected';\n\n if (options.output) {\n writeFileSync(options.output, finalSql, 'utf-8');\n console.log(chalk.green(`\\nMigration SQL written to: ${options.output}`));\n } else {\n console.log(chalk.cyan('\\n=== Migration SQL ===\\n'));\n console.log(finalSql);\n }\n\n return finalSql;\n}\n\n/**\n * Get comment changes between two databases.\n * migra doesn't support COMMENT ON statements.\n */\nasync function getCommentChanges(\n currentDb: Database,\n targetDb: Database\n): Promise<string> {\n const commentQuery = `\n SELECT\n format('COMMENT ON COLUMN %I.%I IS %L;',\n c.table_name,\n c.column_name,\n pgd.description\n ) as comment_sql,\n c.table_name,\n c.column_name,\n pgd.description\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name\n JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace AND pn.nspname = c.table_schema\n LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = pc.oid AND pgd.objsubid = c.ordinal_position\n WHERE c.table_schema = 'public'\n AND c.table_name != 'schema_migrations'\n ORDER BY c.table_name, c.ordinal_position;\n `;\n\n const [currentComments, targetComments] = await Promise.all([\n currentDb.query(commentQuery),\n targetDb.query(commentQuery),\n ]);\n\n const currentMap = new Map<string, string | null>();\n const targetMap = new Map<string, { sql: string; description: string | null }>();\n\n for (const row of currentComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n currentMap.set(key, row.description as string | null);\n }\n\n for (const row of targetComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n targetMap.set(key, {\n sql: row.comment_sql as string,\n description: row.description as string | null,\n });\n }\n\n const commentDiffs: string[] = [];\n\n for (const [key, target] of targetMap) {\n const current = currentMap.get(key);\n if (current !== target.description && target.sql) {\n commentDiffs.push(target.sql);\n }\n }\n\n return commentDiffs.join('\\n');\n}\n","import pg from \"pg\";\nimport { parseAndEncodeDbUrl, buildDbUrl, type DbUrlParts } from \"./db-url.js\";\n\nconst { Client } = pg;\n\nexport interface QueryResult {\n rows: Record<string, unknown>[];\n rowCount: number;\n}\n\nexport class Database {\n private connectionString: string;\n private dbParts: DbUrlParts;\n\n constructor(connectionString: string) {\n this.dbParts = parseAndEncodeDbUrl(connectionString);\n this.connectionString = this.dbParts.url;\n }\n\n /**\n * Execute a query and return results.\n */\n async query(sql: string): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query and return results.\n */\n async queryParams(sql: string, params: unknown[]): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql, params);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query without returning results.\n */\n async execParams(sql: string, params: unknown[]): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql, params);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a query without returning results (for DDL/DML).\n */\n async exec(sql: string): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute operations within a transaction.\n * Automatically commits on success, rolls back on error.\n */\n async withTransaction<T>(fn: (client: pg.Client) => Promise<T>): Promise<T> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(\"BEGIN\");\n const result = await fn(client);\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n await client.end();\n }\n }\n\n /**\n * Create a new database.\n */\n async createDatabase(name: string): Promise<void> {\n await this.exec(`CREATE DATABASE \"${name}\";`);\n }\n\n /**\n * Drop a database if it exists.\n */\n async dropDatabase(name: string): Promise<void> {\n await this.exec(`DROP DATABASE IF EXISTS \"${name}\";`);\n }\n\n /**\n * Create a Database instance connected to a different database.\n */\n withDatabase(name: string): Database {\n const newUrl = buildDbUrl(this.dbParts, name);\n return new Database(newUrl);\n }\n\n /**\n * Get connection URL for external tools (like migra).\n */\n getConnectionUrl(): string {\n return this.connectionString;\n }\n\n /**\n * Get parsed database URL parts.\n */\n getParts(): DbUrlParts {\n return this.dbParts;\n }\n\n /**\n * Install PostgreSQL extensions.\n */\n async installExtensions(extensions: string[]): Promise<void> {\n for (const ext of extensions) {\n try {\n await this.exec(`CREATE EXTENSION IF NOT EXISTS \"${ext}\";`);\n } catch {\n // Ignore extension errors - some might not be available\n }\n }\n }\n\n /**\n * Get column information for a table.\n */\n async getTableColumns(\n tableName: string\n ): Promise<{ column_name: string; ordinal_position: number }[]> {\n const result = await this.query(`\n SELECT column_name, ordinal_position\n FROM information_schema.columns\n WHERE table_name = '${tableName}'\n ORDER BY ordinal_position;\n `);\n return result.rows as { column_name: string; ordinal_position: number }[];\n }\n\n /**\n * List all tables in the public schema.\n */\n async listTables(): Promise<string[]> {\n const result = await this.query(`\n SELECT tablename FROM pg_tables WHERE schemaname = 'public';\n `);\n return result.rows.map((row) => row.tablename as string);\n }\n}\n","export interface DbUrlParts {\n url: string;\n protocol: string;\n user: string;\n password: string;\n host: string;\n port: string;\n database: string;\n params: string;\n}\n\n/**\n * Parse a PostgreSQL connection URL and encode special characters in password.\n * Handles URLs like: postgres://user:password@host:port/database?params\n */\nexport function parseAndEncodeDbUrl(rawUrl: string): DbUrlParts {\n const match = rawUrl.match(\n /^(postgres(?:ql)?):\\/\\/([^:]+):(.+)@([^:]+):(\\d+)\\/([^?]+)(\\?.*)?$/\n );\n\n if (!match) {\n throw new Error(\n 'Invalid DATABASE_URL format. Expected: postgres://user:password@host:port/database'\n );\n }\n\n const [, protocol, user, password, host, port, database, params = ''] = match;\n const encodedPassword = encodeURIComponent(password);\n\n return {\n url: `${protocol}://${user}:${encodedPassword}@${host}:${port}/${database}${params}`,\n protocol,\n user,\n password: encodedPassword,\n host,\n port,\n database,\n params,\n };\n}\n\n/**\n * Build a connection URL with a different database name.\n */\nexport function buildDbUrl(parts: DbUrlParts, database: string): string {\n return `${parts.protocol}://${parts.user}:${parts.password}@${parts.host}:${parts.port}/${database}${parts.params}`;\n}\n","import { Parser, ModelExporter } from '@dbml/core';\n\nexport interface DbmlResult {\n sql: string;\n}\n\n/**\n * Convert DBML schema to PostgreSQL SQL.\n */\nexport function dbmlToSql(dbmlContent: string): DbmlResult {\n const database = new Parser().parse(dbmlContent, 'dbml');\n const sql = ModelExporter.export(database, 'postgres');\n return { sql };\n}\n","import { execFileSync } from 'child_process';\n\nexport interface MigraResult {\n sql: string;\n hasChanges: boolean;\n}\n\n/**\n * Run migra to generate schema diff between two databases.\n *\n * Exit codes:\n * - 0: No differences\n * - 2: Differences found (SQL output on stdout)\n * - 1: Error\n */\nexport function runMigra(\n fromUrl: string,\n toUrl: string,\n options: { unsafe?: boolean } = {}\n): MigraResult {\n const args = [fromUrl, toUrl];\n if (options.unsafe) {\n args.push('--unsafe');\n }\n\n try {\n const output = execFileSync('migra', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Exit code 0 = no changes\n return { sql: output || '', hasChanges: false };\n } catch (error) {\n const err = error as { status?: number; stdout?: string; stderr?: string };\n\n if (err.status === 2 && err.stdout) {\n // Exit code 2 = changes found\n return { sql: err.stdout, hasChanges: true };\n }\n\n if (err.status === 1) {\n throw new Error(`migra error: ${err.stderr || 'Unknown error'}`);\n }\n\n // Other exit codes - might still have output\n return { sql: err.stdout || '', hasChanges: Boolean(err.stdout) };\n }\n}\n\n/**\n * Filter out schema_migrations table from migration SQL.\n */\nexport function filterSchemaMigrations(sql: string): string {\n return sql\n .split('\\n')\n .filter((line) => !line.includes('schema_migrations'))\n .join('\\n')\n .trim();\n}\n","import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { pathToFileURL } from 'url';\nimport { config as loadDotenv } from 'dotenv';\n\nexport interface NexusqlConfig {\n schema: string;\n migrations: string;\n extensions: string[];\n databaseUrl?: string;\n}\n\nconst DEFAULT_CONFIG: NexusqlConfig = {\n schema: './schema.dbml',\n migrations: './db/migrations',\n extensions: ['uuid-ossp'],\n};\n\n/**\n * Load configuration from nexusql.config.js or defaults.\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<NexusqlConfig> {\n // Load .env file\n loadDotenv();\n\n const configPath = join(cwd, 'nexusql.config.js');\n let userConfig: Partial<NexusqlConfig> = {};\n\n if (existsSync(configPath)) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(configUrl);\n userConfig = module.default || module;\n } catch {\n // Ignore config load errors, use defaults\n }\n }\n\n return {\n ...DEFAULT_CONFIG,\n ...userConfig,\n databaseUrl: process.env.DATABASE_URL || userConfig.databaseUrl,\n };\n}\n\n/**\n * Get database URL from config or environment.\n */\nexport function getDatabaseUrl(config: NexusqlConfig): string {\n const url = config.databaseUrl || process.env.DATABASE_URL;\n if (!url) {\n throw new Error('DATABASE_URL not set. Set it in .env or nexusql.config.js');\n }\n return url;\n}\n\n/**\n * Generate default config file content.\n */\nexport function generateConfigTemplate(): string {\n return `/** @type {import('nexusql').NexusqlConfig} */\nexport default {\n // Path to your DBML schema file\n schema: './schema.dbml',\n\n // Directory for migration files\n migrations: './db/migrations',\n\n // PostgreSQL extensions to install in temp database\n extensions: ['uuid-ossp'],\n};\n`;\n}\n","import { execSync } from \"child_process\";\nimport chalk from \"chalk\";\n\n/**\n * Check if migra is installed and available in the PATH.\n */\nexport function checkMigra(): boolean {\n try {\n // We redirect output to ignore standard output/error\n execSync(\"migra --help\", { stdio: \"ignore\" });\n return true;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Verify migra is installed, print error and exit if not.\n */\nexport function ensureMigraOrExit(): void {\n if (!checkMigra()) {\n console.error(chalk.red(\"\\nError: 'migra' is not installed or not found in PATH.\"));\n console.error(chalk.yellow(\"\\nPlease install it using pip:\"));\n console.error(chalk.cyan(\" pip install migra\"));\n console.error(chalk.dim(\"\\nDocumentation: https://github.com/djrobstep/migra\\n\"));\n process.exit(1);\n }\n}\n","import { mkdirSync, existsSync } from \"fs\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { gen } from \"./gen.js\";\nimport { Database } from \"../lib/database.js\";\nimport { MigrationRunner } from \"../lib/runner.js\";\nimport { createMigrationFile } from \"../lib/migrations.js\";\nimport { loadConfig, getDatabaseUrl } from \"../lib/config.js\";\nimport { question, confirm, closePrompts } from \"../utils/prompts.js\";\nimport { ensureMigraOrExit } from \"../utils/check-migra.js\";\n\nexport interface MigrateOptions {\n name?: string;\n apply?: boolean;\n yes?: boolean;\n}\n\n/**\n * Interactive migration workflow.\n */\nexport async function migrate(options: MigrateOptions = {}): Promise<void> {\n ensureMigraOrExit();\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n console.log(chalk.bold(\"\\nInteractive Database Migration\\n\"));\n console.log(\"This will:\");\n console.log(\" 1. Generate migration diff from DBML\");\n console.log(\" 2. Create a new migration file\");\n console.log(\" 3. Optionally apply the migration\\n\");\n\n try {\n // Step 1: Generate diff\n console.log(chalk.cyan(\"Step 1: Generating migration diff...\\n\"));\n const migrationSql = await gen({ verbose: false });\n\n const noChanges =\n !migrationSql || migrationSql === \"-- No changes detected\";\n\n if (noChanges) {\n console.log(chalk.yellow(\"\\nNo schema changes detected.\\n\"));\n\n if (!options.yes) {\n const proceed = await confirm(\n \"Do you still want to create an empty migration?\"\n );\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n }\n\n // Step 2: Get migration name\n console.log(chalk.cyan(\"\\n--- Step 2: Create Migration File ---\\n\"));\n\n let migrationName = options.name;\n if (!migrationName) {\n migrationName = await question(\n 'Enter migration name (e.g., \"add_users_table\"): '\n );\n }\n\n if (!migrationName || migrationName.trim() === \"\") {\n console.log(chalk.red(\"\\nMigration name cannot be empty. Exiting...\"));\n return;\n }\n\n const sanitizedName = migrationName.trim().replace(/\\s+/g, \"_\");\n console.log(chalk.green(`\\nUsing migration name: ${sanitizedName}`));\n\n // Confirm before creating\n if (!options.yes) {\n const proceed = await confirm(\"\\nCreate this migration?\");\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n\n // Create migrations directory if needed\n if (!existsSync(config.migrations)) {\n mkdirSync(config.migrations, { recursive: true });\n }\n\n // Create migration file\n const spinner = ora(\"Creating migration file...\").start();\n const filepath = createMigrationFile(\n config.migrations,\n sanitizedName,\n noChanges ? \"\" : migrationSql\n );\n spinner.succeed(`Created migration file: ${filepath}`);\n\n // Step 3: Apply migration\n console.log(chalk.cyan(\"\\n--- Step 3: Apply Migration ---\\n\"));\n\n let shouldApply = options.apply;\n if (shouldApply === undefined && !options.yes) {\n shouldApply = await confirm(\"Apply this migration now?\");\n }\n\n if (shouldApply) {\n const applySpinner = ora(\"Applying migration...\").start();\n try {\n const applied = await runner.migrateUp();\n if (applied.length > 0) {\n applySpinner.succeed(\n `Applied ${applied.length} migration(s) successfully`\n );\n } else {\n applySpinner.info(\"No pending migrations to apply\");\n }\n } catch (error) {\n applySpinner.fail(\"Failed to apply migration\");\n throw error;\n }\n } else {\n console.log(chalk.dim(\"\\nMigration created but not applied.\"));\n console.log(chalk.dim(`Run \"nexusql up\" to apply pending migrations.`));\n }\n\n console.log(chalk.green(`\\nMigration file: ${filepath}\\n`));\n } finally {\n closePrompts();\n }\n}\n\n/**\n * Apply all pending migrations.\n */\nexport async function up(options: { dryRun?: boolean } = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n const pending = await runner.getPendingMigrations();\n\n if (pending.length === 0) {\n spinner.info(\"No pending migrations\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`found ${pending.length} pending migration(s):`);\n for (const m of pending) {\n console.log(chalk.cyan(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Applying migrations...\";\n for (const migration of pending) {\n await runner.applyMigration(migration);\n console.log(chalk.green(` ✓ ${migration.name}`));\n }\n spinner.succeed(`Applied ${pending.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Migration failed\");\n throw error;\n }\n}\n\n/**\n * Rollback applied migrations.\n */\nexport async function down(\n options: { steps?: number; to?: string; dryRun?: boolean } = {}\n): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n // Optimization: status() reads all files. A more efficient way to get ordered applied migrations is needed if history is huge.\n // For now, sorting 'applied' from status() works.\n const { applied } = await runner.status();\n const sortedApplied = applied.sort((a, b) =>\n b.version.localeCompare(a.version)\n ); // Newest first\n\n if (sortedApplied.length === 0) {\n spinner.info(\"No applied migrations to rollback\");\n return;\n }\n\n let toRollback: typeof applied = [];\n\n if (options.to) {\n const targetIndex = sortedApplied.findIndex(\n (m) => m.version === options.to\n );\n if (targetIndex === -1) {\n // If options.to is \"rollback to version X\", we want to rollback everything > X.\n // Let's assume options.to is the target version we want to KEEP.\n // So we rollback everything where version > options.to\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n if (toRollback.length === 0) {\n spinner.info(\n `Version ${options.to} is already the latest applied or doesn't exist in future history.`\n );\n return;\n }\n } else {\n // Rollback migrations newer than X.\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n }\n } else {\n const steps = options.steps ?? 1;\n toRollback = sortedApplied.slice(0, steps);\n }\n\n if (toRollback.length === 0) {\n spinner.info(\"No migrations to rollback\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`Would rollback ${toRollback.length} migration(s):`);\n for (const m of toRollback) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Rolling back migrations...\";\n for (const migration of toRollback) {\n await runner.rollbackMigration(migration);\n console.log(chalk.yellow(` reverted ${migration.name}`));\n }\n spinner.succeed(`Rolled back ${toRollback.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Rollback failed\");\n throw error;\n }\n}\n\n/**\n * Show migration status.\n */\nexport async function status(): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migration status...\").start();\n const { applied, pending } = await runner.status();\n spinner.stop();\n\n console.log(chalk.bold(\"\\nMigration Status\\n\"));\n\n if (applied.length > 0) {\n console.log(chalk.green(\"Applied:\"));\n for (const m of applied) {\n console.log(chalk.green(` ✓ ${m.name}`));\n }\n }\n\n if (pending.length > 0) {\n console.log(chalk.yellow(\"\\nPending:\"));\n for (const m of pending) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n }\n\n if (applied.length === 0 && pending.length === 0) {\n console.log(chalk.dim(\"No migrations found.\"));\n }\n\n console.log();\n}\n","import { readdirSync, statSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { generateReverseSql } from \"./reverse.js\";\n\nexport interface MigrationFile {\n name: string;\n path: string;\n version: string;\n mtime: number;\n}\n\n/**\n * List all migration files in a directory.\n */\nexport function listMigrations(migrationsDir: string): MigrationFile[] {\n try {\n const files = readdirSync(migrationsDir);\n return files\n .filter((f) => f.endsWith(\".sql\"))\n .map((f) => {\n const path = join(migrationsDir, f);\n const match = f.match(/^(\\d+)/);\n return {\n name: f,\n path,\n version: match ? match[1] : f,\n mtime: statSync(path).mtime.getTime(),\n };\n })\n .sort((a, b) => a.version.localeCompare(b.version));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the most recently created migration file.\n */\nexport function getMostRecentMigration(\n migrationsDir: string\n): MigrationFile | null {\n const migrations = listMigrations(migrationsDir);\n if (migrations.length === 0) return null;\n\n return migrations.reduce((most, current) =>\n current.mtime > most.mtime ? current : most\n );\n}\n\n/**\n * Generate a new migration filename with timestamp.\n */\nexport function generateMigrationFilename(name: string): string {\n const timestamp = new Date().toISOString().replace(/[-:T]/g, \"\").slice(0, 14);\n const sanitized = name.replace(/\\s+/g, \"_\").toLowerCase();\n return `${timestamp}_${sanitized}.sql`;\n}\n\n/**\n * Create a new migration file with dbmate format.\n */\nexport function createMigrationFile(\n migrationsDir: string,\n name: string,\n upSql: string = \"\",\n downSql: string = \"\"\n): string {\n const filename = generateMigrationFilename(name);\n const filepath = join(migrationsDir, filename);\n\n // Auto-generate down SQL if not provided and up SQL exists\n if (!downSql && upSql) {\n downSql = generateReverseSql(upSql);\n }\n\n const content = `-- migrate:up\n${upSql}\n\n-- migrate:down\n${downSql}\n`;\n\n writeFileSync(filepath, content, \"utf-8\");\n return filepath;\n}\n\n/**\n * Update an existing migration file with SQL.\n */\nexport function updateMigrationFile(filepath: string, upSql: string): void {\n const content = readFileSync(filepath, \"utf-8\");\n const updated = content.replace(\n /-- migrate:up\\n/,\n `-- migrate:up\\n${upSql}\\n\\n`\n );\n writeFileSync(filepath, updated, \"utf-8\");\n}\n\n/**\n * Parse a migration file into up and down sections.\n */\nexport function parseMigrationFile(filepath: string): {\n up: string;\n down: string;\n} {\n const content = readFileSync(filepath, \"utf-8\");\n const upMatch = content.match(\n /-- migrate:up\\n([\\s\\S]*?)(?=-- migrate:down|$)/\n );\n const downMatch = content.match(/-- migrate:down\\n([\\s\\S]*?)$/);\n\n return {\n up: upMatch ? upMatch[1].trim() : \"\",\n down: downMatch ? downMatch[1].trim() : \"\",\n };\n}\n","/**\n * Generate reverse SQL for simple DDL statements.\n * LIMITATION: Only supports basic CREATE/DROP TABLE/INDEX and ADD/DROP COLUMN.\n * Complex changes (ALTER COLUMN type, constraints) need manual intervention.\n */\nexport function generateReverseSql(upSql: string): string {\n if (!upSql) return \"\";\n\n const downStatements: string[] = [];\n const lines = upSql\n .split(\";\")\n .map((l) => l.trim())\n .filter((l) => l);\n\n for (const line of lines) {\n // CREATE TABLE x -> DROP TABLE x\n const createTableMatch = line.match(\n /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s(]+)/i\n );\n if (createTableMatch) {\n const tableName = createTableMatch[1];\n downStatements.push(`DROP TABLE ${tableName};`);\n continue;\n }\n\n // DROP TABLE x -> Manual\n const dropTableMatch = line.match(\n /DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropTableMatch) {\n const tableName = dropTableMatch[1];\n downStatements.push(`-- Manual: Recreate table ${tableName}`);\n continue;\n }\n\n // ALTER TABLE x ADD COLUMN y -> ALTER TABLE x DROP COLUMN y\n const addColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+ADD\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (addColumnMatch) {\n const [, tableName, colName] = addColumnMatch;\n downStatements.push(`ALTER TABLE ${tableName} DROP COLUMN ${colName};`);\n continue;\n }\n\n // ALTER TABLE x DROP COLUMN y -> Manual\n const dropColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+DROP\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (dropColumnMatch) {\n const [, tableName, colName] = dropColumnMatch;\n downStatements.push(\n `-- Manual: Add column ${colName} back to table ${tableName}`\n );\n continue;\n }\n\n // CREATE INDEX x -> DROP INDEX x\n const createIndexMatch = line.match(\n /CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s]+)\\s+ON/i\n );\n if (createIndexMatch) {\n const indexName = createIndexMatch[1];\n downStatements.push(`DROP INDEX ${indexName};`);\n continue;\n }\n\n // DROP INDEX x -> Manual\n const dropIndexMatch = line.match(\n /DROP\\s+INDEX\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropIndexMatch) {\n const indexName = dropIndexMatch[1];\n downStatements.push(`-- Manual: Recreate index ${indexName}`);\n continue;\n }\n\n // Fallback\n downStatements.push(`-- Manual: Revert ${line.substring(0, 50)}...`);\n }\n\n // Reverse the order of down statements\n return downStatements.reverse().join(\"\\n\");\n}\n","import { Database } from \"./database.js\";\nimport {\n listMigrations,\n parseMigrationFile,\n type MigrationFile,\n} from \"./migrations.js\";\n\nconst SCHEMA_MIGRATIONS_TABLE = \"schema_migrations\";\n\n/**\n * Migration runner - replaces dbmate functionality.\n */\nexport class MigrationRunner {\n private db: Database;\n private migrationsDir: string;\n\n constructor(db: Database, migrationsDir: string) {\n this.db = db;\n this.migrationsDir = migrationsDir;\n }\n\n /**\n * Ensure schema_migrations table exists.\n */\n async ensureTable(): Promise<void> {\n await this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_MIGRATIONS_TABLE} (\n version VARCHAR(255) PRIMARY KEY\n );\n `);\n }\n\n /**\n * Get list of applied migration versions.\n */\n async getAppliedVersions(): Promise<Set<string>> {\n await this.ensureTable();\n const result = await this.db.query(\n `SELECT version FROM ${SCHEMA_MIGRATIONS_TABLE};`\n );\n return new Set(result.rows.map((row) => row.version as string));\n }\n\n /**\n * Mark a migration as applied.\n */\n async markApplied(version: string, client?: any): Promise<void> {\n await this.ensureTable();\n const sql = `\n INSERT INTO ${SCHEMA_MIGRATIONS_TABLE} (version)\n VALUES ($1)\n ON CONFLICT DO NOTHING;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Mark a migration as not applied (for rollback).\n */\n async markUnapplied(version: string, client?: any): Promise<void> {\n const sql = `\n DELETE FROM ${SCHEMA_MIGRATIONS_TABLE}\n WHERE version = $1;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Get pending migrations (not yet applied).\n */\n async getPendingMigrations(): Promise<MigrationFile[]> {\n const all = listMigrations(this.migrationsDir);\n const applied = await this.getAppliedVersions();\n return all.filter((m) => !applied.has(m.version));\n }\n\n /**\n * Apply a single migration.\n */\n async applyMigration(migration: MigrationFile): Promise<void> {\n const { up } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (up) {\n await client.query(up);\n }\n await this.markApplied(migration.version, client);\n });\n }\n\n /**\n * Roll back a single migration.\n */\n async rollbackMigration(migration: MigrationFile): Promise<void> {\n const { down } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (down) {\n await client.query(down);\n }\n await this.markUnapplied(migration.version, client);\n });\n }\n\n /**\n * Apply all pending migrations.\n */\n async migrateUp(): Promise<MigrationFile[]> {\n const pending = await this.getPendingMigrations();\n for (const migration of pending) {\n await this.applyMigration(migration);\n }\n return pending;\n }\n\n /**\n * Get migration status.\n */\n async status(): Promise<{\n applied: MigrationFile[];\n pending: MigrationFile[];\n }> {\n const all = listMigrations(this.migrationsDir);\n const appliedVersions = await this.getAppliedVersions();\n\n return {\n applied: all.filter((m) => appliedVersions.has(m.version)),\n pending: all.filter((m) => !appliedVersions.has(m.version)),\n };\n }\n}\n","import * as readline from 'readline';\n\nlet rl: readline.Interface | null = null;\n\n/**\n * Get or create readline interface.\n */\nfunction getReadline(): readline.Interface {\n if (!rl) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n }\n return rl;\n}\n\n/**\n * Close readline interface.\n */\nexport function closePrompts(): void {\n if (rl) {\n rl.close();\n rl = null;\n }\n}\n\n/**\n * Ask user a question and return their answer.\n */\nexport function question(query: string): Promise<string> {\n return new Promise((resolve) => {\n getReadline().question(query, (answer) => {\n resolve(answer);\n });\n });\n}\n\n/**\n * Ask a yes/no question.\n */\nexport async function confirm(query: string): Promise<boolean> {\n const answer = await question(`${query} (yes/no): `);\n return answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { Database } from '../lib/database.js';\nimport { MigrationRunner } from '../lib/runner.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\n/**\n * Mark a migration as applied without running it.\n */\nexport async function markApplied(version: string): Promise<void> {\n if (!version) {\n console.error(chalk.red('Error: Migration version is required'));\n console.log(chalk.dim('\\nUsage: nexusql mark-applied <version>'));\n console.log(chalk.dim('Example: nexusql mark-applied 20251209153535'));\n process.exit(1);\n }\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(`Marking migration ${version} as applied...`).start();\n\n try {\n await runner.markApplied(version);\n spinner.succeed(`Migration ${version} marked as applied`);\n } catch (error) {\n spinner.fail('Failed to mark migration as applied');\n throw error;\n }\n}\n","import { writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport chalk from 'chalk';\nimport { generateConfigTemplate } from '../lib/config.js';\n\nexport interface InitOptions {\n force?: boolean;\n}\n\n/**\n * Initialize nexusql configuration.\n */\nexport async function init(options: InitOptions = {}): Promise<void> {\n const cwd = process.cwd();\n\n // Create config file\n const configPath = join(cwd, 'nexusql.config.js');\n\n if (existsSync(configPath) && !options.force) {\n console.log(chalk.yellow('nexusql.config.js already exists.'));\n console.log(chalk.dim('Use --force to overwrite.'));\n return;\n }\n\n writeFileSync(configPath, generateConfigTemplate(), 'utf-8');\n console.log(chalk.green('Created nexusql.config.js'));\n\n // Create migrations directory\n const migrationsDir = join(cwd, 'db', 'migrations');\n if (!existsSync(migrationsDir)) {\n mkdirSync(migrationsDir, { recursive: true });\n console.log(chalk.green('Created db/migrations/'));\n }\n\n // Create .env.example if it doesn't exist\n const envExamplePath = join(cwd, '.env.example');\n if (!existsSync(envExamplePath)) {\n writeFileSync(\n envExamplePath,\n 'DATABASE_URL=postgres://user:password@localhost:5432/database\\n',\n 'utf-8'\n );\n console.log(chalk.green('Created .env.example'));\n }\n\n console.log(chalk.bold('\\nNext steps:'));\n console.log(' 1. Copy .env.example to .env and set your DATABASE_URL');\n console.log(' 2. Create your schema.dbml file');\n console.log(' 3. Run \"nexusql gen\" to generate migration SQL');\n console.log(' 4. Run \"nexusql migrate\" to create and apply migrations\\n');\n}\n"],"mappings":"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","names":["chalk","chalk","existsSync","chalk","ora","readFileSync","writeFileSync","join","join","join","writeFileSync","readFileSync","up","down","resolve","chalk","existsSync","ora","chalk","ora","chalk","ora","writeFileSync","existsSync","mkdirSync","join","chalk","join","existsSync","chalk","writeFileSync","mkdirSync"]}
|
package/dist/index.js
CHANGED
|
@@ -514,8 +514,32 @@ export default {
|
|
|
514
514
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
515
515
|
import { resolve } from "path";
|
|
516
516
|
import ora from "ora";
|
|
517
|
+
import chalk2 from "chalk";
|
|
518
|
+
|
|
519
|
+
// src/utils/check-migra.ts
|
|
520
|
+
import { execSync } from "child_process";
|
|
517
521
|
import chalk from "chalk";
|
|
522
|
+
function checkMigra() {
|
|
523
|
+
try {
|
|
524
|
+
execSync("migra --help", { stdio: "ignore" });
|
|
525
|
+
return true;
|
|
526
|
+
} catch (error) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function ensureMigraOrExit() {
|
|
531
|
+
if (!checkMigra()) {
|
|
532
|
+
console.error(chalk.red("\nError: 'migra' is not installed or not found in PATH."));
|
|
533
|
+
console.error(chalk.yellow("\nPlease install it using pip:"));
|
|
534
|
+
console.error(chalk.cyan(" pip install migra"));
|
|
535
|
+
console.error(chalk.dim("\nDocumentation: https://github.com/djrobstep/migra\n"));
|
|
536
|
+
process.exit(1);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// src/commands/gen.ts
|
|
518
541
|
async function gen(options = {}) {
|
|
542
|
+
ensureMigraOrExit();
|
|
519
543
|
const config = await loadConfig();
|
|
520
544
|
const databaseUrl = getDatabaseUrl(config);
|
|
521
545
|
const db = new Database(databaseUrl);
|
|
@@ -553,7 +577,7 @@ async function gen(options = {}) {
|
|
|
553
577
|
spinner.succeed("Loaded schema into temp database");
|
|
554
578
|
if (options.verbose) {
|
|
555
579
|
const tables = await tempDb.listTables();
|
|
556
|
-
console.log(
|
|
580
|
+
console.log(chalk2.dim(`
|
|
557
581
|
Tables in temp database: ${tables.join(", ")}`));
|
|
558
582
|
}
|
|
559
583
|
spinner.start("Generating migration diff...");
|
|
@@ -590,10 +614,10 @@ ${commentSql}`;
|
|
|
590
614
|
const finalSql = migrationSql || "-- No changes detected";
|
|
591
615
|
if (options.output) {
|
|
592
616
|
writeFileSync2(options.output, finalSql, "utf-8");
|
|
593
|
-
console.log(
|
|
617
|
+
console.log(chalk2.green(`
|
|
594
618
|
Migration SQL written to: ${options.output}`));
|
|
595
619
|
} else {
|
|
596
|
-
console.log(
|
|
620
|
+
console.log(chalk2.cyan("\n=== Migration SQL ===\n"));
|
|
597
621
|
console.log(finalSql);
|
|
598
622
|
}
|
|
599
623
|
return finalSql;
|
|
@@ -646,7 +670,7 @@ async function getCommentChanges(currentDb, targetDb) {
|
|
|
646
670
|
|
|
647
671
|
// src/commands/migrate.ts
|
|
648
672
|
import { mkdirSync, existsSync as existsSync2 } from "fs";
|
|
649
|
-
import
|
|
673
|
+
import chalk3 from "chalk";
|
|
650
674
|
import ora2 from "ora";
|
|
651
675
|
|
|
652
676
|
// src/utils/prompts.ts
|
|
@@ -681,32 +705,33 @@ async function confirm(query) {
|
|
|
681
705
|
|
|
682
706
|
// src/commands/migrate.ts
|
|
683
707
|
async function migrate(options = {}) {
|
|
708
|
+
ensureMigraOrExit();
|
|
684
709
|
const config = await loadConfig();
|
|
685
710
|
const databaseUrl = getDatabaseUrl(config);
|
|
686
711
|
const db = new Database(databaseUrl);
|
|
687
712
|
const runner = new MigrationRunner(db, config.migrations);
|
|
688
|
-
console.log(
|
|
713
|
+
console.log(chalk3.bold("\nInteractive Database Migration\n"));
|
|
689
714
|
console.log("This will:");
|
|
690
715
|
console.log(" 1. Generate migration diff from DBML");
|
|
691
716
|
console.log(" 2. Create a new migration file");
|
|
692
717
|
console.log(" 3. Optionally apply the migration\n");
|
|
693
718
|
try {
|
|
694
|
-
console.log(
|
|
719
|
+
console.log(chalk3.cyan("Step 1: Generating migration diff...\n"));
|
|
695
720
|
const migrationSql = await gen({ verbose: false });
|
|
696
721
|
const noChanges = !migrationSql || migrationSql === "-- No changes detected";
|
|
697
722
|
if (noChanges) {
|
|
698
|
-
console.log(
|
|
723
|
+
console.log(chalk3.yellow("\nNo schema changes detected.\n"));
|
|
699
724
|
if (!options.yes) {
|
|
700
725
|
const proceed = await confirm(
|
|
701
726
|
"Do you still want to create an empty migration?"
|
|
702
727
|
);
|
|
703
728
|
if (!proceed) {
|
|
704
|
-
console.log(
|
|
729
|
+
console.log(chalk3.red("\nMigration cancelled."));
|
|
705
730
|
return;
|
|
706
731
|
}
|
|
707
732
|
}
|
|
708
733
|
}
|
|
709
|
-
console.log(
|
|
734
|
+
console.log(chalk3.cyan("\n--- Step 2: Create Migration File ---\n"));
|
|
710
735
|
let migrationName = options.name;
|
|
711
736
|
if (!migrationName) {
|
|
712
737
|
migrationName = await question(
|
|
@@ -714,16 +739,16 @@ async function migrate(options = {}) {
|
|
|
714
739
|
);
|
|
715
740
|
}
|
|
716
741
|
if (!migrationName || migrationName.trim() === "") {
|
|
717
|
-
console.log(
|
|
742
|
+
console.log(chalk3.red("\nMigration name cannot be empty. Exiting..."));
|
|
718
743
|
return;
|
|
719
744
|
}
|
|
720
745
|
const sanitizedName = migrationName.trim().replace(/\s+/g, "_");
|
|
721
|
-
console.log(
|
|
746
|
+
console.log(chalk3.green(`
|
|
722
747
|
Using migration name: ${sanitizedName}`));
|
|
723
748
|
if (!options.yes) {
|
|
724
749
|
const proceed = await confirm("\nCreate this migration?");
|
|
725
750
|
if (!proceed) {
|
|
726
|
-
console.log(
|
|
751
|
+
console.log(chalk3.red("\nMigration cancelled."));
|
|
727
752
|
return;
|
|
728
753
|
}
|
|
729
754
|
}
|
|
@@ -737,7 +762,7 @@ Using migration name: ${sanitizedName}`));
|
|
|
737
762
|
noChanges ? "" : migrationSql
|
|
738
763
|
);
|
|
739
764
|
spinner.succeed(`Created migration file: ${filepath}`);
|
|
740
|
-
console.log(
|
|
765
|
+
console.log(chalk3.cyan("\n--- Step 3: Apply Migration ---\n"));
|
|
741
766
|
let shouldApply = options.apply;
|
|
742
767
|
if (shouldApply === void 0 && !options.yes) {
|
|
743
768
|
shouldApply = await confirm("Apply this migration now?");
|
|
@@ -758,10 +783,10 @@ Using migration name: ${sanitizedName}`));
|
|
|
758
783
|
throw error;
|
|
759
784
|
}
|
|
760
785
|
} else {
|
|
761
|
-
console.log(
|
|
762
|
-
console.log(
|
|
786
|
+
console.log(chalk3.dim("\nMigration created but not applied."));
|
|
787
|
+
console.log(chalk3.dim(`Run "nexusql up" to apply pending migrations.`));
|
|
763
788
|
}
|
|
764
|
-
console.log(
|
|
789
|
+
console.log(chalk3.green(`
|
|
765
790
|
Migration file: ${filepath}
|
|
766
791
|
`));
|
|
767
792
|
} finally {
|
|
@@ -783,14 +808,14 @@ async function up(options = {}) {
|
|
|
783
808
|
if (options.dryRun) {
|
|
784
809
|
spinner.info(`found ${pending.length} pending migration(s):`);
|
|
785
810
|
for (const m of pending) {
|
|
786
|
-
console.log(
|
|
811
|
+
console.log(chalk3.cyan(` \u25CB ${m.name}`));
|
|
787
812
|
}
|
|
788
813
|
return;
|
|
789
814
|
}
|
|
790
815
|
spinner.text = "Applying migrations...";
|
|
791
816
|
for (const migration of pending) {
|
|
792
817
|
await runner.applyMigration(migration);
|
|
793
|
-
console.log(
|
|
818
|
+
console.log(chalk3.green(` \u2713 ${migration.name}`));
|
|
794
819
|
}
|
|
795
820
|
spinner.succeed(`Applied ${pending.length} migration(s)`);
|
|
796
821
|
} catch (error) {
|
|
@@ -806,33 +831,33 @@ async function status() {
|
|
|
806
831
|
const spinner = ora2("Checking migration status...").start();
|
|
807
832
|
const { applied, pending } = await runner.status();
|
|
808
833
|
spinner.stop();
|
|
809
|
-
console.log(
|
|
834
|
+
console.log(chalk3.bold("\nMigration Status\n"));
|
|
810
835
|
if (applied.length > 0) {
|
|
811
|
-
console.log(
|
|
836
|
+
console.log(chalk3.green("Applied:"));
|
|
812
837
|
for (const m of applied) {
|
|
813
|
-
console.log(
|
|
838
|
+
console.log(chalk3.green(` \u2713 ${m.name}`));
|
|
814
839
|
}
|
|
815
840
|
}
|
|
816
841
|
if (pending.length > 0) {
|
|
817
|
-
console.log(
|
|
842
|
+
console.log(chalk3.yellow("\nPending:"));
|
|
818
843
|
for (const m of pending) {
|
|
819
|
-
console.log(
|
|
844
|
+
console.log(chalk3.yellow(` \u25CB ${m.name}`));
|
|
820
845
|
}
|
|
821
846
|
}
|
|
822
847
|
if (applied.length === 0 && pending.length === 0) {
|
|
823
|
-
console.log(
|
|
848
|
+
console.log(chalk3.dim("No migrations found."));
|
|
824
849
|
}
|
|
825
850
|
console.log();
|
|
826
851
|
}
|
|
827
852
|
|
|
828
853
|
// src/commands/mark-applied.ts
|
|
829
|
-
import
|
|
854
|
+
import chalk4 from "chalk";
|
|
830
855
|
import ora3 from "ora";
|
|
831
856
|
async function markApplied(version) {
|
|
832
857
|
if (!version) {
|
|
833
|
-
console.error(
|
|
834
|
-
console.log(
|
|
835
|
-
console.log(
|
|
858
|
+
console.error(chalk4.red("Error: Migration version is required"));
|
|
859
|
+
console.log(chalk4.dim("\nUsage: nexusql mark-applied <version>"));
|
|
860
|
+
console.log(chalk4.dim("Example: nexusql mark-applied 20251209153535"));
|
|
836
861
|
process.exit(1);
|
|
837
862
|
}
|
|
838
863
|
const config = await loadConfig();
|
|
@@ -852,21 +877,21 @@ async function markApplied(version) {
|
|
|
852
877
|
// src/commands/init.ts
|
|
853
878
|
import { writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
854
879
|
import { join as join3 } from "path";
|
|
855
|
-
import
|
|
880
|
+
import chalk5 from "chalk";
|
|
856
881
|
async function init(options = {}) {
|
|
857
882
|
const cwd = process.cwd();
|
|
858
883
|
const configPath = join3(cwd, "nexusql.config.js");
|
|
859
884
|
if (existsSync3(configPath) && !options.force) {
|
|
860
|
-
console.log(
|
|
861
|
-
console.log(
|
|
885
|
+
console.log(chalk5.yellow("nexusql.config.js already exists."));
|
|
886
|
+
console.log(chalk5.dim("Use --force to overwrite."));
|
|
862
887
|
return;
|
|
863
888
|
}
|
|
864
889
|
writeFileSync3(configPath, generateConfigTemplate(), "utf-8");
|
|
865
|
-
console.log(
|
|
890
|
+
console.log(chalk5.green("Created nexusql.config.js"));
|
|
866
891
|
const migrationsDir = join3(cwd, "db", "migrations");
|
|
867
892
|
if (!existsSync3(migrationsDir)) {
|
|
868
893
|
mkdirSync2(migrationsDir, { recursive: true });
|
|
869
|
-
console.log(
|
|
894
|
+
console.log(chalk5.green("Created db/migrations/"));
|
|
870
895
|
}
|
|
871
896
|
const envExamplePath = join3(cwd, ".env.example");
|
|
872
897
|
if (!existsSync3(envExamplePath)) {
|
|
@@ -875,9 +900,9 @@ async function init(options = {}) {
|
|
|
875
900
|
"DATABASE_URL=postgres://user:password@localhost:5432/database\n",
|
|
876
901
|
"utf-8"
|
|
877
902
|
);
|
|
878
|
-
console.log(
|
|
903
|
+
console.log(chalk5.green("Created .env.example"));
|
|
879
904
|
}
|
|
880
|
-
console.log(
|
|
905
|
+
console.log(chalk5.bold("\nNext steps:"));
|
|
881
906
|
console.log(" 1. Copy .env.example to .env and set your DATABASE_URL");
|
|
882
907
|
console.log(" 2. Create your schema.dbml file");
|
|
883
908
|
console.log(' 3. Run "nexusql gen" to generate migration SQL');
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/database.ts","../src/lib/db-url.ts","../src/lib/migrations.ts","../src/lib/reverse.ts","../src/lib/runner.ts","../src/lib/dbml.ts","../src/lib/migra.ts","../src/lib/config.ts","../src/commands/gen.ts","../src/commands/migrate.ts","../src/utils/prompts.ts","../src/commands/mark-applied.ts","../src/commands/init.ts"],"sourcesContent":["import pg from \"pg\";\nimport { parseAndEncodeDbUrl, buildDbUrl, type DbUrlParts } from \"./db-url.js\";\n\nconst { Client } = pg;\n\nexport interface QueryResult {\n rows: Record<string, unknown>[];\n rowCount: number;\n}\n\nexport class Database {\n private connectionString: string;\n private dbParts: DbUrlParts;\n\n constructor(connectionString: string) {\n this.dbParts = parseAndEncodeDbUrl(connectionString);\n this.connectionString = this.dbParts.url;\n }\n\n /**\n * Execute a query and return results.\n */\n async query(sql: string): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query and return results.\n */\n async queryParams(sql: string, params: unknown[]): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql, params);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query without returning results.\n */\n async execParams(sql: string, params: unknown[]): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql, params);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a query without returning results (for DDL/DML).\n */\n async exec(sql: string): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute operations within a transaction.\n * Automatically commits on success, rolls back on error.\n */\n async withTransaction<T>(fn: (client: pg.Client) => Promise<T>): Promise<T> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(\"BEGIN\");\n const result = await fn(client);\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n await client.end();\n }\n }\n\n /**\n * Create a new database.\n */\n async createDatabase(name: string): Promise<void> {\n await this.exec(`CREATE DATABASE \"${name}\";`);\n }\n\n /**\n * Drop a database if it exists.\n */\n async dropDatabase(name: string): Promise<void> {\n await this.exec(`DROP DATABASE IF EXISTS \"${name}\";`);\n }\n\n /**\n * Create a Database instance connected to a different database.\n */\n withDatabase(name: string): Database {\n const newUrl = buildDbUrl(this.dbParts, name);\n return new Database(newUrl);\n }\n\n /**\n * Get connection URL for external tools (like migra).\n */\n getConnectionUrl(): string {\n return this.connectionString;\n }\n\n /**\n * Get parsed database URL parts.\n */\n getParts(): DbUrlParts {\n return this.dbParts;\n }\n\n /**\n * Install PostgreSQL extensions.\n */\n async installExtensions(extensions: string[]): Promise<void> {\n for (const ext of extensions) {\n try {\n await this.exec(`CREATE EXTENSION IF NOT EXISTS \"${ext}\";`);\n } catch {\n // Ignore extension errors - some might not be available\n }\n }\n }\n\n /**\n * Get column information for a table.\n */\n async getTableColumns(\n tableName: string\n ): Promise<{ column_name: string; ordinal_position: number }[]> {\n const result = await this.query(`\n SELECT column_name, ordinal_position\n FROM information_schema.columns\n WHERE table_name = '${tableName}'\n ORDER BY ordinal_position;\n `);\n return result.rows as { column_name: string; ordinal_position: number }[];\n }\n\n /**\n * List all tables in the public schema.\n */\n async listTables(): Promise<string[]> {\n const result = await this.query(`\n SELECT tablename FROM pg_tables WHERE schemaname = 'public';\n `);\n return result.rows.map((row) => row.tablename as string);\n }\n}\n","export interface DbUrlParts {\n url: string;\n protocol: string;\n user: string;\n password: string;\n host: string;\n port: string;\n database: string;\n params: string;\n}\n\n/**\n * Parse a PostgreSQL connection URL and encode special characters in password.\n * Handles URLs like: postgres://user:password@host:port/database?params\n */\nexport function parseAndEncodeDbUrl(rawUrl: string): DbUrlParts {\n const match = rawUrl.match(\n /^(postgres(?:ql)?):\\/\\/([^:]+):(.+)@([^:]+):(\\d+)\\/([^?]+)(\\?.*)?$/\n );\n\n if (!match) {\n throw new Error(\n 'Invalid DATABASE_URL format. Expected: postgres://user:password@host:port/database'\n );\n }\n\n const [, protocol, user, password, host, port, database, params = ''] = match;\n const encodedPassword = encodeURIComponent(password);\n\n return {\n url: `${protocol}://${user}:${encodedPassword}@${host}:${port}/${database}${params}`,\n protocol,\n user,\n password: encodedPassword,\n host,\n port,\n database,\n params,\n };\n}\n\n/**\n * Build a connection URL with a different database name.\n */\nexport function buildDbUrl(parts: DbUrlParts, database: string): string {\n return `${parts.protocol}://${parts.user}:${parts.password}@${parts.host}:${parts.port}/${database}${parts.params}`;\n}\n","import { readdirSync, statSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { generateReverseSql } from \"./reverse.js\";\n\nexport interface MigrationFile {\n name: string;\n path: string;\n version: string;\n mtime: number;\n}\n\n/**\n * List all migration files in a directory.\n */\nexport function listMigrations(migrationsDir: string): MigrationFile[] {\n try {\n const files = readdirSync(migrationsDir);\n return files\n .filter((f) => f.endsWith(\".sql\"))\n .map((f) => {\n const path = join(migrationsDir, f);\n const match = f.match(/^(\\d+)/);\n return {\n name: f,\n path,\n version: match ? match[1] : f,\n mtime: statSync(path).mtime.getTime(),\n };\n })\n .sort((a, b) => a.version.localeCompare(b.version));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the most recently created migration file.\n */\nexport function getMostRecentMigration(\n migrationsDir: string\n): MigrationFile | null {\n const migrations = listMigrations(migrationsDir);\n if (migrations.length === 0) return null;\n\n return migrations.reduce((most, current) =>\n current.mtime > most.mtime ? current : most\n );\n}\n\n/**\n * Generate a new migration filename with timestamp.\n */\nexport function generateMigrationFilename(name: string): string {\n const timestamp = new Date().toISOString().replace(/[-:T]/g, \"\").slice(0, 14);\n const sanitized = name.replace(/\\s+/g, \"_\").toLowerCase();\n return `${timestamp}_${sanitized}.sql`;\n}\n\n/**\n * Create a new migration file with dbmate format.\n */\nexport function createMigrationFile(\n migrationsDir: string,\n name: string,\n upSql: string = \"\",\n downSql: string = \"\"\n): string {\n const filename = generateMigrationFilename(name);\n const filepath = join(migrationsDir, filename);\n\n // Auto-generate down SQL if not provided and up SQL exists\n if (!downSql && upSql) {\n downSql = generateReverseSql(upSql);\n }\n\n const content = `-- migrate:up\n${upSql}\n\n-- migrate:down\n${downSql}\n`;\n\n writeFileSync(filepath, content, \"utf-8\");\n return filepath;\n}\n\n/**\n * Update an existing migration file with SQL.\n */\nexport function updateMigrationFile(filepath: string, upSql: string): void {\n const content = readFileSync(filepath, \"utf-8\");\n const updated = content.replace(\n /-- migrate:up\\n/,\n `-- migrate:up\\n${upSql}\\n\\n`\n );\n writeFileSync(filepath, updated, \"utf-8\");\n}\n\n/**\n * Parse a migration file into up and down sections.\n */\nexport function parseMigrationFile(filepath: string): {\n up: string;\n down: string;\n} {\n const content = readFileSync(filepath, \"utf-8\");\n const upMatch = content.match(\n /-- migrate:up\\n([\\s\\S]*?)(?=-- migrate:down|$)/\n );\n const downMatch = content.match(/-- migrate:down\\n([\\s\\S]*?)$/);\n\n return {\n up: upMatch ? upMatch[1].trim() : \"\",\n down: downMatch ? downMatch[1].trim() : \"\",\n };\n}\n","/**\n * Generate reverse SQL for simple DDL statements.\n * LIMITATION: Only supports basic CREATE/DROP TABLE/INDEX and ADD/DROP COLUMN.\n * Complex changes (ALTER COLUMN type, constraints) need manual intervention.\n */\nexport function generateReverseSql(upSql: string): string {\n if (!upSql) return \"\";\n\n const downStatements: string[] = [];\n const lines = upSql\n .split(\";\")\n .map((l) => l.trim())\n .filter((l) => l);\n\n for (const line of lines) {\n // CREATE TABLE x -> DROP TABLE x\n const createTableMatch = line.match(\n /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s(]+)/i\n );\n if (createTableMatch) {\n const tableName = createTableMatch[1];\n downStatements.push(`DROP TABLE ${tableName};`);\n continue;\n }\n\n // DROP TABLE x -> Manual\n const dropTableMatch = line.match(\n /DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropTableMatch) {\n const tableName = dropTableMatch[1];\n downStatements.push(`-- Manual: Recreate table ${tableName}`);\n continue;\n }\n\n // ALTER TABLE x ADD COLUMN y -> ALTER TABLE x DROP COLUMN y\n const addColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+ADD\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (addColumnMatch) {\n const [, tableName, colName] = addColumnMatch;\n downStatements.push(`ALTER TABLE ${tableName} DROP COLUMN ${colName};`);\n continue;\n }\n\n // ALTER TABLE x DROP COLUMN y -> Manual\n const dropColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+DROP\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (dropColumnMatch) {\n const [, tableName, colName] = dropColumnMatch;\n downStatements.push(\n `-- Manual: Add column ${colName} back to table ${tableName}`\n );\n continue;\n }\n\n // CREATE INDEX x -> DROP INDEX x\n const createIndexMatch = line.match(\n /CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s]+)\\s+ON/i\n );\n if (createIndexMatch) {\n const indexName = createIndexMatch[1];\n downStatements.push(`DROP INDEX ${indexName};`);\n continue;\n }\n\n // DROP INDEX x -> Manual\n const dropIndexMatch = line.match(\n /DROP\\s+INDEX\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropIndexMatch) {\n const indexName = dropIndexMatch[1];\n downStatements.push(`-- Manual: Recreate index ${indexName}`);\n continue;\n }\n\n // Fallback\n downStatements.push(`-- Manual: Revert ${line.substring(0, 50)}...`);\n }\n\n // Reverse the order of down statements\n return downStatements.reverse().join(\"\\n\");\n}\n","import { Database } from \"./database.js\";\nimport {\n listMigrations,\n parseMigrationFile,\n type MigrationFile,\n} from \"./migrations.js\";\n\nconst SCHEMA_MIGRATIONS_TABLE = \"schema_migrations\";\n\n/**\n * Migration runner - replaces dbmate functionality.\n */\nexport class MigrationRunner {\n private db: Database;\n private migrationsDir: string;\n\n constructor(db: Database, migrationsDir: string) {\n this.db = db;\n this.migrationsDir = migrationsDir;\n }\n\n /**\n * Ensure schema_migrations table exists.\n */\n async ensureTable(): Promise<void> {\n await this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_MIGRATIONS_TABLE} (\n version VARCHAR(255) PRIMARY KEY\n );\n `);\n }\n\n /**\n * Get list of applied migration versions.\n */\n async getAppliedVersions(): Promise<Set<string>> {\n await this.ensureTable();\n const result = await this.db.query(\n `SELECT version FROM ${SCHEMA_MIGRATIONS_TABLE};`\n );\n return new Set(result.rows.map((row) => row.version as string));\n }\n\n /**\n * Mark a migration as applied.\n */\n async markApplied(version: string, client?: any): Promise<void> {\n await this.ensureTable();\n const sql = `\n INSERT INTO ${SCHEMA_MIGRATIONS_TABLE} (version)\n VALUES ($1)\n ON CONFLICT DO NOTHING;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Mark a migration as not applied (for rollback).\n */\n async markUnapplied(version: string, client?: any): Promise<void> {\n const sql = `\n DELETE FROM ${SCHEMA_MIGRATIONS_TABLE}\n WHERE version = $1;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Get pending migrations (not yet applied).\n */\n async getPendingMigrations(): Promise<MigrationFile[]> {\n const all = listMigrations(this.migrationsDir);\n const applied = await this.getAppliedVersions();\n return all.filter((m) => !applied.has(m.version));\n }\n\n /**\n * Apply a single migration.\n */\n async applyMigration(migration: MigrationFile): Promise<void> {\n const { up } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (up) {\n await client.query(up);\n }\n await this.markApplied(migration.version, client);\n });\n }\n\n /**\n * Roll back a single migration.\n */\n async rollbackMigration(migration: MigrationFile): Promise<void> {\n const { down } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (down) {\n await client.query(down);\n }\n await this.markUnapplied(migration.version, client);\n });\n }\n\n /**\n * Apply all pending migrations.\n */\n async migrateUp(): Promise<MigrationFile[]> {\n const pending = await this.getPendingMigrations();\n for (const migration of pending) {\n await this.applyMigration(migration);\n }\n return pending;\n }\n\n /**\n * Get migration status.\n */\n async status(): Promise<{\n applied: MigrationFile[];\n pending: MigrationFile[];\n }> {\n const all = listMigrations(this.migrationsDir);\n const appliedVersions = await this.getAppliedVersions();\n\n return {\n applied: all.filter((m) => appliedVersions.has(m.version)),\n pending: all.filter((m) => !appliedVersions.has(m.version)),\n };\n }\n}\n","import { Parser, ModelExporter } from '@dbml/core';\n\nexport interface DbmlResult {\n sql: string;\n}\n\n/**\n * Convert DBML schema to PostgreSQL SQL.\n */\nexport function dbmlToSql(dbmlContent: string): DbmlResult {\n const database = new Parser().parse(dbmlContent, 'dbml');\n const sql = ModelExporter.export(database, 'postgres');\n return { sql };\n}\n","import { execFileSync } from 'child_process';\n\nexport interface MigraResult {\n sql: string;\n hasChanges: boolean;\n}\n\n/**\n * Run migra to generate schema diff between two databases.\n *\n * Exit codes:\n * - 0: No differences\n * - 2: Differences found (SQL output on stdout)\n * - 1: Error\n */\nexport function runMigra(\n fromUrl: string,\n toUrl: string,\n options: { unsafe?: boolean } = {}\n): MigraResult {\n const args = [fromUrl, toUrl];\n if (options.unsafe) {\n args.push('--unsafe');\n }\n\n try {\n const output = execFileSync('migra', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Exit code 0 = no changes\n return { sql: output || '', hasChanges: false };\n } catch (error) {\n const err = error as { status?: number; stdout?: string; stderr?: string };\n\n if (err.status === 2 && err.stdout) {\n // Exit code 2 = changes found\n return { sql: err.stdout, hasChanges: true };\n }\n\n if (err.status === 1) {\n throw new Error(`migra error: ${err.stderr || 'Unknown error'}`);\n }\n\n // Other exit codes - might still have output\n return { sql: err.stdout || '', hasChanges: Boolean(err.stdout) };\n }\n}\n\n/**\n * Filter out schema_migrations table from migration SQL.\n */\nexport function filterSchemaMigrations(sql: string): string {\n return sql\n .split('\\n')\n .filter((line) => !line.includes('schema_migrations'))\n .join('\\n')\n .trim();\n}\n","import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { pathToFileURL } from 'url';\nimport { config as loadDotenv } from 'dotenv';\n\nexport interface NexusqlConfig {\n schema: string;\n migrations: string;\n extensions: string[];\n databaseUrl?: string;\n}\n\nconst DEFAULT_CONFIG: NexusqlConfig = {\n schema: './schema.dbml',\n migrations: './db/migrations',\n extensions: ['uuid-ossp'],\n};\n\n/**\n * Load configuration from nexusql.config.js or defaults.\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<NexusqlConfig> {\n // Load .env file\n loadDotenv();\n\n const configPath = join(cwd, 'nexusql.config.js');\n let userConfig: Partial<NexusqlConfig> = {};\n\n if (existsSync(configPath)) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(configUrl);\n userConfig = module.default || module;\n } catch {\n // Ignore config load errors, use defaults\n }\n }\n\n return {\n ...DEFAULT_CONFIG,\n ...userConfig,\n databaseUrl: process.env.DATABASE_URL || userConfig.databaseUrl,\n };\n}\n\n/**\n * Get database URL from config or environment.\n */\nexport function getDatabaseUrl(config: NexusqlConfig): string {\n const url = config.databaseUrl || process.env.DATABASE_URL;\n if (!url) {\n throw new Error('DATABASE_URL not set. Set it in .env or nexusql.config.js');\n }\n return url;\n}\n\n/**\n * Generate default config file content.\n */\nexport function generateConfigTemplate(): string {\n return `/** @type {import('nexusql').NexusqlConfig} */\nexport default {\n // Path to your DBML schema file\n schema: './schema.dbml',\n\n // Directory for migration files\n migrations: './db/migrations',\n\n // PostgreSQL extensions to install in temp database\n extensions: ['uuid-ossp'],\n};\n`;\n}\n","import { readFileSync, writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { Database } from '../lib/database.js';\nimport { dbmlToSql } from '../lib/dbml.js';\nimport { runMigra, filterSchemaMigrations } from '../lib/migra.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\nexport interface GenOptions {\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Generate migration SQL by diffing current DB against DBML schema.\n */\nexport async function gen(options: GenOptions = {}): Promise<string> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n\n const spinner = ora();\n\n // Read DBML schema\n spinner.start('Reading DBML schema...');\n const schemaPath = resolve(config.schema);\n let dbmlContent: string;\n try {\n dbmlContent = readFileSync(schemaPath, 'utf-8');\n spinner.succeed('Read DBML schema');\n } catch {\n spinner.fail(`Failed to read schema: ${schemaPath}`);\n throw new Error(`Schema file not found: ${schemaPath}`);\n }\n\n // Convert DBML to SQL\n spinner.start('Converting DBML to SQL...');\n const { sql: targetSql } = dbmlToSql(dbmlContent);\n spinner.succeed('Converted DBML to SQL');\n\n // Create temp database\n const tempDbName = `nexusql_temp_${Date.now()}`;\n spinner.start(`Creating temp database: ${tempDbName}`);\n try {\n await db.createDatabase(tempDbName);\n spinner.succeed(`Created temp database: ${tempDbName}`);\n } catch (error) {\n spinner.fail('Failed to create temp database');\n throw error;\n }\n\n const tempDb = db.withDatabase(tempDbName);\n let migrationSql = '';\n\n try {\n // Install extensions\n spinner.start('Installing extensions...');\n await tempDb.installExtensions(config.extensions);\n spinner.succeed('Installed extensions');\n\n // Load schema into temp database\n spinner.start('Loading schema into temp database...');\n await tempDb.exec(targetSql);\n spinner.succeed('Loaded schema into temp database');\n\n // Debug: List tables\n if (options.verbose) {\n const tables = await tempDb.listTables();\n console.log(chalk.dim(`\\nTables in temp database: ${tables.join(', ')}`));\n }\n\n // Run migra to generate diff\n spinner.start('Generating migration diff...');\n const migraResult = runMigra(\n db.getConnectionUrl(),\n tempDb.getConnectionUrl(),\n { unsafe: true }\n );\n\n migrationSql = filterSchemaMigrations(migraResult.sql);\n\n if (migraResult.hasChanges) {\n spinner.succeed('Generated migration diff');\n } else {\n spinner.info('No schema changes detected');\n }\n\n // Get comment changes\n spinner.start('Checking comment changes...');\n const commentSql = await getCommentChanges(db, tempDb);\n if (commentSql) {\n migrationSql = migrationSql\n ? `${migrationSql}\\n\\n-- Comment changes\\n${commentSql}`\n : `-- Comment changes\\n${commentSql}`;\n }\n spinner.succeed('Checked comment changes');\n } finally {\n // Cleanup temp database\n spinner.start('Cleaning up temp database...');\n try {\n await db.dropDatabase(tempDbName);\n spinner.succeed('Cleaned up temp database');\n } catch {\n spinner.warn('Failed to cleanup temp database');\n }\n }\n\n // Output result\n const finalSql = migrationSql || '-- No changes detected';\n\n if (options.output) {\n writeFileSync(options.output, finalSql, 'utf-8');\n console.log(chalk.green(`\\nMigration SQL written to: ${options.output}`));\n } else {\n console.log(chalk.cyan('\\n=== Migration SQL ===\\n'));\n console.log(finalSql);\n }\n\n return finalSql;\n}\n\n/**\n * Get comment changes between two databases.\n * migra doesn't support COMMENT ON statements.\n */\nasync function getCommentChanges(\n currentDb: Database,\n targetDb: Database\n): Promise<string> {\n const commentQuery = `\n SELECT\n format('COMMENT ON COLUMN %I.%I IS %L;',\n c.table_name,\n c.column_name,\n pgd.description\n ) as comment_sql,\n c.table_name,\n c.column_name,\n pgd.description\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name\n JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace AND pn.nspname = c.table_schema\n LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = pc.oid AND pgd.objsubid = c.ordinal_position\n WHERE c.table_schema = 'public'\n AND c.table_name != 'schema_migrations'\n ORDER BY c.table_name, c.ordinal_position;\n `;\n\n const [currentComments, targetComments] = await Promise.all([\n currentDb.query(commentQuery),\n targetDb.query(commentQuery),\n ]);\n\n const currentMap = new Map<string, string | null>();\n const targetMap = new Map<string, { sql: string; description: string | null }>();\n\n for (const row of currentComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n currentMap.set(key, row.description as string | null);\n }\n\n for (const row of targetComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n targetMap.set(key, {\n sql: row.comment_sql as string,\n description: row.description as string | null,\n });\n }\n\n const commentDiffs: string[] = [];\n\n for (const [key, target] of targetMap) {\n const current = currentMap.get(key);\n if (current !== target.description && target.sql) {\n commentDiffs.push(target.sql);\n }\n }\n\n return commentDiffs.join('\\n');\n}\n","import { mkdirSync, existsSync } from \"fs\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { gen } from \"./gen.js\";\nimport { Database } from \"../lib/database.js\";\nimport { MigrationRunner } from \"../lib/runner.js\";\nimport { createMigrationFile } from \"../lib/migrations.js\";\nimport { loadConfig, getDatabaseUrl } from \"../lib/config.js\";\nimport { question, confirm, closePrompts } from \"../utils/prompts.js\";\n\nexport interface MigrateOptions {\n name?: string;\n apply?: boolean;\n yes?: boolean;\n}\n\n/**\n * Interactive migration workflow.\n */\nexport async function migrate(options: MigrateOptions = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n console.log(chalk.bold(\"\\nInteractive Database Migration\\n\"));\n console.log(\"This will:\");\n console.log(\" 1. Generate migration diff from DBML\");\n console.log(\" 2. Create a new migration file\");\n console.log(\" 3. Optionally apply the migration\\n\");\n\n try {\n // Step 1: Generate diff\n console.log(chalk.cyan(\"Step 1: Generating migration diff...\\n\"));\n const migrationSql = await gen({ verbose: false });\n\n const noChanges =\n !migrationSql || migrationSql === \"-- No changes detected\";\n\n if (noChanges) {\n console.log(chalk.yellow(\"\\nNo schema changes detected.\\n\"));\n\n if (!options.yes) {\n const proceed = await confirm(\n \"Do you still want to create an empty migration?\"\n );\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n }\n\n // Step 2: Get migration name\n console.log(chalk.cyan(\"\\n--- Step 2: Create Migration File ---\\n\"));\n\n let migrationName = options.name;\n if (!migrationName) {\n migrationName = await question(\n 'Enter migration name (e.g., \"add_users_table\"): '\n );\n }\n\n if (!migrationName || migrationName.trim() === \"\") {\n console.log(chalk.red(\"\\nMigration name cannot be empty. Exiting...\"));\n return;\n }\n\n const sanitizedName = migrationName.trim().replace(/\\s+/g, \"_\");\n console.log(chalk.green(`\\nUsing migration name: ${sanitizedName}`));\n\n // Confirm before creating\n if (!options.yes) {\n const proceed = await confirm(\"\\nCreate this migration?\");\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n\n // Create migrations directory if needed\n if (!existsSync(config.migrations)) {\n mkdirSync(config.migrations, { recursive: true });\n }\n\n // Create migration file\n const spinner = ora(\"Creating migration file...\").start();\n const filepath = createMigrationFile(\n config.migrations,\n sanitizedName,\n noChanges ? \"\" : migrationSql\n );\n spinner.succeed(`Created migration file: ${filepath}`);\n\n // Step 3: Apply migration\n console.log(chalk.cyan(\"\\n--- Step 3: Apply Migration ---\\n\"));\n\n let shouldApply = options.apply;\n if (shouldApply === undefined && !options.yes) {\n shouldApply = await confirm(\"Apply this migration now?\");\n }\n\n if (shouldApply) {\n const applySpinner = ora(\"Applying migration...\").start();\n try {\n const applied = await runner.migrateUp();\n if (applied.length > 0) {\n applySpinner.succeed(\n `Applied ${applied.length} migration(s) successfully`\n );\n } else {\n applySpinner.info(\"No pending migrations to apply\");\n }\n } catch (error) {\n applySpinner.fail(\"Failed to apply migration\");\n throw error;\n }\n } else {\n console.log(chalk.dim(\"\\nMigration created but not applied.\"));\n console.log(chalk.dim(`Run \"nexusql up\" to apply pending migrations.`));\n }\n\n console.log(chalk.green(`\\nMigration file: ${filepath}\\n`));\n } finally {\n closePrompts();\n }\n}\n\n/**\n * Apply all pending migrations.\n */\nexport async function up(options: { dryRun?: boolean } = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n const pending = await runner.getPendingMigrations();\n\n if (pending.length === 0) {\n spinner.info(\"No pending migrations\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`found ${pending.length} pending migration(s):`);\n for (const m of pending) {\n console.log(chalk.cyan(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Applying migrations...\";\n for (const migration of pending) {\n await runner.applyMigration(migration);\n console.log(chalk.green(` ✓ ${migration.name}`));\n }\n spinner.succeed(`Applied ${pending.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Migration failed\");\n throw error;\n }\n}\n\n/**\n * Rollback applied migrations.\n */\nexport async function down(\n options: { steps?: number; to?: string; dryRun?: boolean } = {}\n): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n // Optimization: status() reads all files. A more efficient way to get ordered applied migrations is needed if history is huge.\n // For now, sorting 'applied' from status() works.\n const { applied } = await runner.status();\n const sortedApplied = applied.sort((a, b) =>\n b.version.localeCompare(a.version)\n ); // Newest first\n\n if (sortedApplied.length === 0) {\n spinner.info(\"No applied migrations to rollback\");\n return;\n }\n\n let toRollback: typeof applied = [];\n\n if (options.to) {\n const targetIndex = sortedApplied.findIndex(\n (m) => m.version === options.to\n );\n if (targetIndex === -1) {\n // If options.to is \"rollback to version X\", we want to rollback everything > X.\n // Let's assume options.to is the target version we want to KEEP.\n // So we rollback everything where version > options.to\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n if (toRollback.length === 0) {\n spinner.info(\n `Version ${options.to} is already the latest applied or doesn't exist in future history.`\n );\n return;\n }\n } else {\n // Rollback migrations newer than X.\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n }\n } else {\n const steps = options.steps ?? 1;\n toRollback = sortedApplied.slice(0, steps);\n }\n\n if (toRollback.length === 0) {\n spinner.info(\"No migrations to rollback\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`Would rollback ${toRollback.length} migration(s):`);\n for (const m of toRollback) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Rolling back migrations...\";\n for (const migration of toRollback) {\n await runner.rollbackMigration(migration);\n console.log(chalk.yellow(` reverted ${migration.name}`));\n }\n spinner.succeed(`Rolled back ${toRollback.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Rollback failed\");\n throw error;\n }\n}\n\n/**\n * Show migration status.\n */\nexport async function status(): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migration status...\").start();\n const { applied, pending } = await runner.status();\n spinner.stop();\n\n console.log(chalk.bold(\"\\nMigration Status\\n\"));\n\n if (applied.length > 0) {\n console.log(chalk.green(\"Applied:\"));\n for (const m of applied) {\n console.log(chalk.green(` ✓ ${m.name}`));\n }\n }\n\n if (pending.length > 0) {\n console.log(chalk.yellow(\"\\nPending:\"));\n for (const m of pending) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n }\n\n if (applied.length === 0 && pending.length === 0) {\n console.log(chalk.dim(\"No migrations found.\"));\n }\n\n console.log();\n}\n","import * as readline from 'readline';\n\nlet rl: readline.Interface | null = null;\n\n/**\n * Get or create readline interface.\n */\nfunction getReadline(): readline.Interface {\n if (!rl) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n }\n return rl;\n}\n\n/**\n * Close readline interface.\n */\nexport function closePrompts(): void {\n if (rl) {\n rl.close();\n rl = null;\n }\n}\n\n/**\n * Ask user a question and return their answer.\n */\nexport function question(query: string): Promise<string> {\n return new Promise((resolve) => {\n getReadline().question(query, (answer) => {\n resolve(answer);\n });\n });\n}\n\n/**\n * Ask a yes/no question.\n */\nexport async function confirm(query: string): Promise<boolean> {\n const answer = await question(`${query} (yes/no): `);\n return answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { Database } from '../lib/database.js';\nimport { MigrationRunner } from '../lib/runner.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\n/**\n * Mark a migration as applied without running it.\n */\nexport async function markApplied(version: string): Promise<void> {\n if (!version) {\n console.error(chalk.red('Error: Migration version is required'));\n console.log(chalk.dim('\\nUsage: nexusql mark-applied <version>'));\n console.log(chalk.dim('Example: nexusql mark-applied 20251209153535'));\n process.exit(1);\n }\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(`Marking migration ${version} as applied...`).start();\n\n try {\n await runner.markApplied(version);\n spinner.succeed(`Migration ${version} marked as applied`);\n } catch (error) {\n spinner.fail('Failed to mark migration as applied');\n throw error;\n }\n}\n","import { writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport chalk from 'chalk';\nimport { generateConfigTemplate } from '../lib/config.js';\n\nexport interface InitOptions {\n force?: boolean;\n}\n\n/**\n * Initialize nexusql configuration.\n */\nexport async function init(options: InitOptions = {}): Promise<void> {\n const cwd = process.cwd();\n\n // Create config file\n const configPath = join(cwd, 'nexusql.config.js');\n\n if (existsSync(configPath) && !options.force) {\n console.log(chalk.yellow('nexusql.config.js already exists.'));\n console.log(chalk.dim('Use --force to overwrite.'));\n return;\n }\n\n writeFileSync(configPath, generateConfigTemplate(), 'utf-8');\n console.log(chalk.green('Created nexusql.config.js'));\n\n // Create migrations directory\n const migrationsDir = join(cwd, 'db', 'migrations');\n if (!existsSync(migrationsDir)) {\n mkdirSync(migrationsDir, { recursive: true });\n console.log(chalk.green('Created db/migrations/'));\n }\n\n // Create .env.example if it doesn't exist\n const envExamplePath = join(cwd, '.env.example');\n if (!existsSync(envExamplePath)) {\n writeFileSync(\n envExamplePath,\n 'DATABASE_URL=postgres://user:password@localhost:5432/database\\n',\n 'utf-8'\n );\n console.log(chalk.green('Created .env.example'));\n }\n\n console.log(chalk.bold('\\nNext steps:'));\n console.log(' 1. Copy .env.example to .env and set your DATABASE_URL');\n console.log(' 2. Create your schema.dbml file');\n console.log(' 3. Run \"nexusql gen\" to generate migration SQL');\n console.log(' 4. Run \"nexusql migrate\" to create and apply migrations\\n');\n}\n"],"mappings":"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","names":["up","join","readFileSync","writeFileSync","readFileSync","writeFileSync","existsSync","chalk","ora","resolve","chalk","existsSync","ora","ora","chalk","chalk","ora","chalk","ora","writeFileSync","existsSync","mkdirSync","join","chalk","join","existsSync","chalk","writeFileSync","mkdirSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/database.ts","../src/lib/db-url.ts","../src/lib/migrations.ts","../src/lib/reverse.ts","../src/lib/runner.ts","../src/lib/dbml.ts","../src/lib/migra.ts","../src/lib/config.ts","../src/commands/gen.ts","../src/utils/check-migra.ts","../src/commands/migrate.ts","../src/utils/prompts.ts","../src/commands/mark-applied.ts","../src/commands/init.ts"],"sourcesContent":["import pg from \"pg\";\nimport { parseAndEncodeDbUrl, buildDbUrl, type DbUrlParts } from \"./db-url.js\";\n\nconst { Client } = pg;\n\nexport interface QueryResult {\n rows: Record<string, unknown>[];\n rowCount: number;\n}\n\nexport class Database {\n private connectionString: string;\n private dbParts: DbUrlParts;\n\n constructor(connectionString: string) {\n this.dbParts = parseAndEncodeDbUrl(connectionString);\n this.connectionString = this.dbParts.url;\n }\n\n /**\n * Execute a query and return results.\n */\n async query(sql: string): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query and return results.\n */\n async queryParams(sql: string, params: unknown[]): Promise<QueryResult> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n const result = await client.query(sql, params);\n return {\n rows: result.rows,\n rowCount: result.rowCount ?? 0,\n };\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a parameterized query without returning results.\n */\n async execParams(sql: string, params: unknown[]): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql, params);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute a query without returning results (for DDL/DML).\n */\n async exec(sql: string): Promise<void> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(sql);\n } finally {\n await client.end();\n }\n }\n\n /**\n * Execute operations within a transaction.\n * Automatically commits on success, rolls back on error.\n */\n async withTransaction<T>(fn: (client: pg.Client) => Promise<T>): Promise<T> {\n const client = new Client({ connectionString: this.connectionString });\n try {\n await client.connect();\n await client.query(\"BEGIN\");\n const result = await fn(client);\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n await client.end();\n }\n }\n\n /**\n * Create a new database.\n */\n async createDatabase(name: string): Promise<void> {\n await this.exec(`CREATE DATABASE \"${name}\";`);\n }\n\n /**\n * Drop a database if it exists.\n */\n async dropDatabase(name: string): Promise<void> {\n await this.exec(`DROP DATABASE IF EXISTS \"${name}\";`);\n }\n\n /**\n * Create a Database instance connected to a different database.\n */\n withDatabase(name: string): Database {\n const newUrl = buildDbUrl(this.dbParts, name);\n return new Database(newUrl);\n }\n\n /**\n * Get connection URL for external tools (like migra).\n */\n getConnectionUrl(): string {\n return this.connectionString;\n }\n\n /**\n * Get parsed database URL parts.\n */\n getParts(): DbUrlParts {\n return this.dbParts;\n }\n\n /**\n * Install PostgreSQL extensions.\n */\n async installExtensions(extensions: string[]): Promise<void> {\n for (const ext of extensions) {\n try {\n await this.exec(`CREATE EXTENSION IF NOT EXISTS \"${ext}\";`);\n } catch {\n // Ignore extension errors - some might not be available\n }\n }\n }\n\n /**\n * Get column information for a table.\n */\n async getTableColumns(\n tableName: string\n ): Promise<{ column_name: string; ordinal_position: number }[]> {\n const result = await this.query(`\n SELECT column_name, ordinal_position\n FROM information_schema.columns\n WHERE table_name = '${tableName}'\n ORDER BY ordinal_position;\n `);\n return result.rows as { column_name: string; ordinal_position: number }[];\n }\n\n /**\n * List all tables in the public schema.\n */\n async listTables(): Promise<string[]> {\n const result = await this.query(`\n SELECT tablename FROM pg_tables WHERE schemaname = 'public';\n `);\n return result.rows.map((row) => row.tablename as string);\n }\n}\n","export interface DbUrlParts {\n url: string;\n protocol: string;\n user: string;\n password: string;\n host: string;\n port: string;\n database: string;\n params: string;\n}\n\n/**\n * Parse a PostgreSQL connection URL and encode special characters in password.\n * Handles URLs like: postgres://user:password@host:port/database?params\n */\nexport function parseAndEncodeDbUrl(rawUrl: string): DbUrlParts {\n const match = rawUrl.match(\n /^(postgres(?:ql)?):\\/\\/([^:]+):(.+)@([^:]+):(\\d+)\\/([^?]+)(\\?.*)?$/\n );\n\n if (!match) {\n throw new Error(\n 'Invalid DATABASE_URL format. Expected: postgres://user:password@host:port/database'\n );\n }\n\n const [, protocol, user, password, host, port, database, params = ''] = match;\n const encodedPassword = encodeURIComponent(password);\n\n return {\n url: `${protocol}://${user}:${encodedPassword}@${host}:${port}/${database}${params}`,\n protocol,\n user,\n password: encodedPassword,\n host,\n port,\n database,\n params,\n };\n}\n\n/**\n * Build a connection URL with a different database name.\n */\nexport function buildDbUrl(parts: DbUrlParts, database: string): string {\n return `${parts.protocol}://${parts.user}:${parts.password}@${parts.host}:${parts.port}/${database}${parts.params}`;\n}\n","import { readdirSync, statSync, readFileSync, writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { generateReverseSql } from \"./reverse.js\";\n\nexport interface MigrationFile {\n name: string;\n path: string;\n version: string;\n mtime: number;\n}\n\n/**\n * List all migration files in a directory.\n */\nexport function listMigrations(migrationsDir: string): MigrationFile[] {\n try {\n const files = readdirSync(migrationsDir);\n return files\n .filter((f) => f.endsWith(\".sql\"))\n .map((f) => {\n const path = join(migrationsDir, f);\n const match = f.match(/^(\\d+)/);\n return {\n name: f,\n path,\n version: match ? match[1] : f,\n mtime: statSync(path).mtime.getTime(),\n };\n })\n .sort((a, b) => a.version.localeCompare(b.version));\n } catch {\n return [];\n }\n}\n\n/**\n * Get the most recently created migration file.\n */\nexport function getMostRecentMigration(\n migrationsDir: string\n): MigrationFile | null {\n const migrations = listMigrations(migrationsDir);\n if (migrations.length === 0) return null;\n\n return migrations.reduce((most, current) =>\n current.mtime > most.mtime ? current : most\n );\n}\n\n/**\n * Generate a new migration filename with timestamp.\n */\nexport function generateMigrationFilename(name: string): string {\n const timestamp = new Date().toISOString().replace(/[-:T]/g, \"\").slice(0, 14);\n const sanitized = name.replace(/\\s+/g, \"_\").toLowerCase();\n return `${timestamp}_${sanitized}.sql`;\n}\n\n/**\n * Create a new migration file with dbmate format.\n */\nexport function createMigrationFile(\n migrationsDir: string,\n name: string,\n upSql: string = \"\",\n downSql: string = \"\"\n): string {\n const filename = generateMigrationFilename(name);\n const filepath = join(migrationsDir, filename);\n\n // Auto-generate down SQL if not provided and up SQL exists\n if (!downSql && upSql) {\n downSql = generateReverseSql(upSql);\n }\n\n const content = `-- migrate:up\n${upSql}\n\n-- migrate:down\n${downSql}\n`;\n\n writeFileSync(filepath, content, \"utf-8\");\n return filepath;\n}\n\n/**\n * Update an existing migration file with SQL.\n */\nexport function updateMigrationFile(filepath: string, upSql: string): void {\n const content = readFileSync(filepath, \"utf-8\");\n const updated = content.replace(\n /-- migrate:up\\n/,\n `-- migrate:up\\n${upSql}\\n\\n`\n );\n writeFileSync(filepath, updated, \"utf-8\");\n}\n\n/**\n * Parse a migration file into up and down sections.\n */\nexport function parseMigrationFile(filepath: string): {\n up: string;\n down: string;\n} {\n const content = readFileSync(filepath, \"utf-8\");\n const upMatch = content.match(\n /-- migrate:up\\n([\\s\\S]*?)(?=-- migrate:down|$)/\n );\n const downMatch = content.match(/-- migrate:down\\n([\\s\\S]*?)$/);\n\n return {\n up: upMatch ? upMatch[1].trim() : \"\",\n down: downMatch ? downMatch[1].trim() : \"\",\n };\n}\n","/**\n * Generate reverse SQL for simple DDL statements.\n * LIMITATION: Only supports basic CREATE/DROP TABLE/INDEX and ADD/DROP COLUMN.\n * Complex changes (ALTER COLUMN type, constraints) need manual intervention.\n */\nexport function generateReverseSql(upSql: string): string {\n if (!upSql) return \"\";\n\n const downStatements: string[] = [];\n const lines = upSql\n .split(\";\")\n .map((l) => l.trim())\n .filter((l) => l);\n\n for (const line of lines) {\n // CREATE TABLE x -> DROP TABLE x\n const createTableMatch = line.match(\n /CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s(]+)/i\n );\n if (createTableMatch) {\n const tableName = createTableMatch[1];\n downStatements.push(`DROP TABLE ${tableName};`);\n continue;\n }\n\n // DROP TABLE x -> Manual\n const dropTableMatch = line.match(\n /DROP\\s+TABLE\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropTableMatch) {\n const tableName = dropTableMatch[1];\n downStatements.push(`-- Manual: Recreate table ${tableName}`);\n continue;\n }\n\n // ALTER TABLE x ADD COLUMN y -> ALTER TABLE x DROP COLUMN y\n const addColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+ADD\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (addColumnMatch) {\n const [, tableName, colName] = addColumnMatch;\n downStatements.push(`ALTER TABLE ${tableName} DROP COLUMN ${colName};`);\n continue;\n }\n\n // ALTER TABLE x DROP COLUMN y -> Manual\n const dropColumnMatch = line.match(\n /ALTER\\s+TABLE\\s+([^\\s]+)\\s+DROP\\s+(?:COLUMN\\s+)?([^\\s;]+)/i\n );\n if (dropColumnMatch) {\n const [, tableName, colName] = dropColumnMatch;\n downStatements.push(\n `-- Manual: Add column ${colName} back to table ${tableName}`\n );\n continue;\n }\n\n // CREATE INDEX x -> DROP INDEX x\n const createIndexMatch = line.match(\n /CREATE\\s+(?:UNIQUE\\s+)?INDEX\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([^\\s]+)\\s+ON/i\n );\n if (createIndexMatch) {\n const indexName = createIndexMatch[1];\n downStatements.push(`DROP INDEX ${indexName};`);\n continue;\n }\n\n // DROP INDEX x -> Manual\n const dropIndexMatch = line.match(\n /DROP\\s+INDEX\\s+(?:IF\\s+EXISTS\\s+)?([^\\s;]+)/i\n );\n if (dropIndexMatch) {\n const indexName = dropIndexMatch[1];\n downStatements.push(`-- Manual: Recreate index ${indexName}`);\n continue;\n }\n\n // Fallback\n downStatements.push(`-- Manual: Revert ${line.substring(0, 50)}...`);\n }\n\n // Reverse the order of down statements\n return downStatements.reverse().join(\"\\n\");\n}\n","import { Database } from \"./database.js\";\nimport {\n listMigrations,\n parseMigrationFile,\n type MigrationFile,\n} from \"./migrations.js\";\n\nconst SCHEMA_MIGRATIONS_TABLE = \"schema_migrations\";\n\n/**\n * Migration runner - replaces dbmate functionality.\n */\nexport class MigrationRunner {\n private db: Database;\n private migrationsDir: string;\n\n constructor(db: Database, migrationsDir: string) {\n this.db = db;\n this.migrationsDir = migrationsDir;\n }\n\n /**\n * Ensure schema_migrations table exists.\n */\n async ensureTable(): Promise<void> {\n await this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_MIGRATIONS_TABLE} (\n version VARCHAR(255) PRIMARY KEY\n );\n `);\n }\n\n /**\n * Get list of applied migration versions.\n */\n async getAppliedVersions(): Promise<Set<string>> {\n await this.ensureTable();\n const result = await this.db.query(\n `SELECT version FROM ${SCHEMA_MIGRATIONS_TABLE};`\n );\n return new Set(result.rows.map((row) => row.version as string));\n }\n\n /**\n * Mark a migration as applied.\n */\n async markApplied(version: string, client?: any): Promise<void> {\n await this.ensureTable();\n const sql = `\n INSERT INTO ${SCHEMA_MIGRATIONS_TABLE} (version)\n VALUES ($1)\n ON CONFLICT DO NOTHING;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Mark a migration as not applied (for rollback).\n */\n async markUnapplied(version: string, client?: any): Promise<void> {\n const sql = `\n DELETE FROM ${SCHEMA_MIGRATIONS_TABLE}\n WHERE version = $1;\n `;\n\n if (client) {\n await client.query(sql, [version]);\n } else {\n await this.db.execParams(sql, [version]);\n }\n }\n\n /**\n * Get pending migrations (not yet applied).\n */\n async getPendingMigrations(): Promise<MigrationFile[]> {\n const all = listMigrations(this.migrationsDir);\n const applied = await this.getAppliedVersions();\n return all.filter((m) => !applied.has(m.version));\n }\n\n /**\n * Apply a single migration.\n */\n async applyMigration(migration: MigrationFile): Promise<void> {\n const { up } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (up) {\n await client.query(up);\n }\n await this.markApplied(migration.version, client);\n });\n }\n\n /**\n * Roll back a single migration.\n */\n async rollbackMigration(migration: MigrationFile): Promise<void> {\n const { down } = parseMigrationFile(migration.path);\n\n await this.db.withTransaction(async (client) => {\n if (down) {\n await client.query(down);\n }\n await this.markUnapplied(migration.version, client);\n });\n }\n\n /**\n * Apply all pending migrations.\n */\n async migrateUp(): Promise<MigrationFile[]> {\n const pending = await this.getPendingMigrations();\n for (const migration of pending) {\n await this.applyMigration(migration);\n }\n return pending;\n }\n\n /**\n * Get migration status.\n */\n async status(): Promise<{\n applied: MigrationFile[];\n pending: MigrationFile[];\n }> {\n const all = listMigrations(this.migrationsDir);\n const appliedVersions = await this.getAppliedVersions();\n\n return {\n applied: all.filter((m) => appliedVersions.has(m.version)),\n pending: all.filter((m) => !appliedVersions.has(m.version)),\n };\n }\n}\n","import { Parser, ModelExporter } from '@dbml/core';\n\nexport interface DbmlResult {\n sql: string;\n}\n\n/**\n * Convert DBML schema to PostgreSQL SQL.\n */\nexport function dbmlToSql(dbmlContent: string): DbmlResult {\n const database = new Parser().parse(dbmlContent, 'dbml');\n const sql = ModelExporter.export(database, 'postgres');\n return { sql };\n}\n","import { execFileSync } from 'child_process';\n\nexport interface MigraResult {\n sql: string;\n hasChanges: boolean;\n}\n\n/**\n * Run migra to generate schema diff between two databases.\n *\n * Exit codes:\n * - 0: No differences\n * - 2: Differences found (SQL output on stdout)\n * - 1: Error\n */\nexport function runMigra(\n fromUrl: string,\n toUrl: string,\n options: { unsafe?: boolean } = {}\n): MigraResult {\n const args = [fromUrl, toUrl];\n if (options.unsafe) {\n args.push('--unsafe');\n }\n\n try {\n const output = execFileSync('migra', args, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Exit code 0 = no changes\n return { sql: output || '', hasChanges: false };\n } catch (error) {\n const err = error as { status?: number; stdout?: string; stderr?: string };\n\n if (err.status === 2 && err.stdout) {\n // Exit code 2 = changes found\n return { sql: err.stdout, hasChanges: true };\n }\n\n if (err.status === 1) {\n throw new Error(`migra error: ${err.stderr || 'Unknown error'}`);\n }\n\n // Other exit codes - might still have output\n return { sql: err.stdout || '', hasChanges: Boolean(err.stdout) };\n }\n}\n\n/**\n * Filter out schema_migrations table from migration SQL.\n */\nexport function filterSchemaMigrations(sql: string): string {\n return sql\n .split('\\n')\n .filter((line) => !line.includes('schema_migrations'))\n .join('\\n')\n .trim();\n}\n","import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { pathToFileURL } from 'url';\nimport { config as loadDotenv } from 'dotenv';\n\nexport interface NexusqlConfig {\n schema: string;\n migrations: string;\n extensions: string[];\n databaseUrl?: string;\n}\n\nconst DEFAULT_CONFIG: NexusqlConfig = {\n schema: './schema.dbml',\n migrations: './db/migrations',\n extensions: ['uuid-ossp'],\n};\n\n/**\n * Load configuration from nexusql.config.js or defaults.\n */\nexport async function loadConfig(cwd: string = process.cwd()): Promise<NexusqlConfig> {\n // Load .env file\n loadDotenv();\n\n const configPath = join(cwd, 'nexusql.config.js');\n let userConfig: Partial<NexusqlConfig> = {};\n\n if (existsSync(configPath)) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(configUrl);\n userConfig = module.default || module;\n } catch {\n // Ignore config load errors, use defaults\n }\n }\n\n return {\n ...DEFAULT_CONFIG,\n ...userConfig,\n databaseUrl: process.env.DATABASE_URL || userConfig.databaseUrl,\n };\n}\n\n/**\n * Get database URL from config or environment.\n */\nexport function getDatabaseUrl(config: NexusqlConfig): string {\n const url = config.databaseUrl || process.env.DATABASE_URL;\n if (!url) {\n throw new Error('DATABASE_URL not set. Set it in .env or nexusql.config.js');\n }\n return url;\n}\n\n/**\n * Generate default config file content.\n */\nexport function generateConfigTemplate(): string {\n return `/** @type {import('nexusql').NexusqlConfig} */\nexport default {\n // Path to your DBML schema file\n schema: './schema.dbml',\n\n // Directory for migration files\n migrations: './db/migrations',\n\n // PostgreSQL extensions to install in temp database\n extensions: ['uuid-ossp'],\n};\n`;\n}\n","import { readFileSync, writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { Database } from '../lib/database.js';\nimport { dbmlToSql } from '../lib/dbml.js';\nimport { runMigra, filterSchemaMigrations } from '../lib/migra.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\nimport { ensureMigraOrExit } from '../utils/check-migra.js';\n\nexport interface GenOptions {\n output?: string;\n verbose?: boolean;\n}\n\n/**\n * Generate migration SQL by diffing current DB against DBML schema.\n */\nexport async function gen(options: GenOptions = {}): Promise<string> {\n ensureMigraOrExit();\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n\n const spinner = ora();\n\n // Read DBML schema\n spinner.start('Reading DBML schema...');\n const schemaPath = resolve(config.schema);\n let dbmlContent: string;\n try {\n dbmlContent = readFileSync(schemaPath, 'utf-8');\n spinner.succeed('Read DBML schema');\n } catch {\n spinner.fail(`Failed to read schema: ${schemaPath}`);\n throw new Error(`Schema file not found: ${schemaPath}`);\n }\n\n // Convert DBML to SQL\n spinner.start('Converting DBML to SQL...');\n const { sql: targetSql } = dbmlToSql(dbmlContent);\n spinner.succeed('Converted DBML to SQL');\n\n // Create temp database\n const tempDbName = `nexusql_temp_${Date.now()}`;\n spinner.start(`Creating temp database: ${tempDbName}`);\n try {\n await db.createDatabase(tempDbName);\n spinner.succeed(`Created temp database: ${tempDbName}`);\n } catch (error) {\n spinner.fail('Failed to create temp database');\n throw error;\n }\n\n const tempDb = db.withDatabase(tempDbName);\n let migrationSql = '';\n\n try {\n // Install extensions\n spinner.start('Installing extensions...');\n await tempDb.installExtensions(config.extensions);\n spinner.succeed('Installed extensions');\n\n // Load schema into temp database\n spinner.start('Loading schema into temp database...');\n await tempDb.exec(targetSql);\n spinner.succeed('Loaded schema into temp database');\n\n // Debug: List tables\n if (options.verbose) {\n const tables = await tempDb.listTables();\n console.log(chalk.dim(`\\nTables in temp database: ${tables.join(', ')}`));\n }\n\n // Run migra to generate diff\n spinner.start('Generating migration diff...');\n const migraResult = runMigra(\n db.getConnectionUrl(),\n tempDb.getConnectionUrl(),\n { unsafe: true }\n );\n\n migrationSql = filterSchemaMigrations(migraResult.sql);\n\n if (migraResult.hasChanges) {\n spinner.succeed('Generated migration diff');\n } else {\n spinner.info('No schema changes detected');\n }\n\n // Get comment changes\n spinner.start('Checking comment changes...');\n const commentSql = await getCommentChanges(db, tempDb);\n if (commentSql) {\n migrationSql = migrationSql\n ? `${migrationSql}\\n\\n-- Comment changes\\n${commentSql}`\n : `-- Comment changes\\n${commentSql}`;\n }\n spinner.succeed('Checked comment changes');\n } finally {\n // Cleanup temp database\n spinner.start('Cleaning up temp database...');\n try {\n await db.dropDatabase(tempDbName);\n spinner.succeed('Cleaned up temp database');\n } catch {\n spinner.warn('Failed to cleanup temp database');\n }\n }\n\n // Output result\n const finalSql = migrationSql || '-- No changes detected';\n\n if (options.output) {\n writeFileSync(options.output, finalSql, 'utf-8');\n console.log(chalk.green(`\\nMigration SQL written to: ${options.output}`));\n } else {\n console.log(chalk.cyan('\\n=== Migration SQL ===\\n'));\n console.log(finalSql);\n }\n\n return finalSql;\n}\n\n/**\n * Get comment changes between two databases.\n * migra doesn't support COMMENT ON statements.\n */\nasync function getCommentChanges(\n currentDb: Database,\n targetDb: Database\n): Promise<string> {\n const commentQuery = `\n SELECT\n format('COMMENT ON COLUMN %I.%I IS %L;',\n c.table_name,\n c.column_name,\n pgd.description\n ) as comment_sql,\n c.table_name,\n c.column_name,\n pgd.description\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name\n JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace AND pn.nspname = c.table_schema\n LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = pc.oid AND pgd.objsubid = c.ordinal_position\n WHERE c.table_schema = 'public'\n AND c.table_name != 'schema_migrations'\n ORDER BY c.table_name, c.ordinal_position;\n `;\n\n const [currentComments, targetComments] = await Promise.all([\n currentDb.query(commentQuery),\n targetDb.query(commentQuery),\n ]);\n\n const currentMap = new Map<string, string | null>();\n const targetMap = new Map<string, { sql: string; description: string | null }>();\n\n for (const row of currentComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n currentMap.set(key, row.description as string | null);\n }\n\n for (const row of targetComments.rows) {\n const key = `${row.table_name}.${row.column_name}`;\n targetMap.set(key, {\n sql: row.comment_sql as string,\n description: row.description as string | null,\n });\n }\n\n const commentDiffs: string[] = [];\n\n for (const [key, target] of targetMap) {\n const current = currentMap.get(key);\n if (current !== target.description && target.sql) {\n commentDiffs.push(target.sql);\n }\n }\n\n return commentDiffs.join('\\n');\n}\n","import { execSync } from \"child_process\";\nimport chalk from \"chalk\";\n\n/**\n * Check if migra is installed and available in the PATH.\n */\nexport function checkMigra(): boolean {\n try {\n // We redirect output to ignore standard output/error\n execSync(\"migra --help\", { stdio: \"ignore\" });\n return true;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Verify migra is installed, print error and exit if not.\n */\nexport function ensureMigraOrExit(): void {\n if (!checkMigra()) {\n console.error(chalk.red(\"\\nError: 'migra' is not installed or not found in PATH.\"));\n console.error(chalk.yellow(\"\\nPlease install it using pip:\"));\n console.error(chalk.cyan(\" pip install migra\"));\n console.error(chalk.dim(\"\\nDocumentation: https://github.com/djrobstep/migra\\n\"));\n process.exit(1);\n }\n}\n","import { mkdirSync, existsSync } from \"fs\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { gen } from \"./gen.js\";\nimport { Database } from \"../lib/database.js\";\nimport { MigrationRunner } from \"../lib/runner.js\";\nimport { createMigrationFile } from \"../lib/migrations.js\";\nimport { loadConfig, getDatabaseUrl } from \"../lib/config.js\";\nimport { question, confirm, closePrompts } from \"../utils/prompts.js\";\nimport { ensureMigraOrExit } from \"../utils/check-migra.js\";\n\nexport interface MigrateOptions {\n name?: string;\n apply?: boolean;\n yes?: boolean;\n}\n\n/**\n * Interactive migration workflow.\n */\nexport async function migrate(options: MigrateOptions = {}): Promise<void> {\n ensureMigraOrExit();\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n console.log(chalk.bold(\"\\nInteractive Database Migration\\n\"));\n console.log(\"This will:\");\n console.log(\" 1. Generate migration diff from DBML\");\n console.log(\" 2. Create a new migration file\");\n console.log(\" 3. Optionally apply the migration\\n\");\n\n try {\n // Step 1: Generate diff\n console.log(chalk.cyan(\"Step 1: Generating migration diff...\\n\"));\n const migrationSql = await gen({ verbose: false });\n\n const noChanges =\n !migrationSql || migrationSql === \"-- No changes detected\";\n\n if (noChanges) {\n console.log(chalk.yellow(\"\\nNo schema changes detected.\\n\"));\n\n if (!options.yes) {\n const proceed = await confirm(\n \"Do you still want to create an empty migration?\"\n );\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n }\n\n // Step 2: Get migration name\n console.log(chalk.cyan(\"\\n--- Step 2: Create Migration File ---\\n\"));\n\n let migrationName = options.name;\n if (!migrationName) {\n migrationName = await question(\n 'Enter migration name (e.g., \"add_users_table\"): '\n );\n }\n\n if (!migrationName || migrationName.trim() === \"\") {\n console.log(chalk.red(\"\\nMigration name cannot be empty. Exiting...\"));\n return;\n }\n\n const sanitizedName = migrationName.trim().replace(/\\s+/g, \"_\");\n console.log(chalk.green(`\\nUsing migration name: ${sanitizedName}`));\n\n // Confirm before creating\n if (!options.yes) {\n const proceed = await confirm(\"\\nCreate this migration?\");\n if (!proceed) {\n console.log(chalk.red(\"\\nMigration cancelled.\"));\n return;\n }\n }\n\n // Create migrations directory if needed\n if (!existsSync(config.migrations)) {\n mkdirSync(config.migrations, { recursive: true });\n }\n\n // Create migration file\n const spinner = ora(\"Creating migration file...\").start();\n const filepath = createMigrationFile(\n config.migrations,\n sanitizedName,\n noChanges ? \"\" : migrationSql\n );\n spinner.succeed(`Created migration file: ${filepath}`);\n\n // Step 3: Apply migration\n console.log(chalk.cyan(\"\\n--- Step 3: Apply Migration ---\\n\"));\n\n let shouldApply = options.apply;\n if (shouldApply === undefined && !options.yes) {\n shouldApply = await confirm(\"Apply this migration now?\");\n }\n\n if (shouldApply) {\n const applySpinner = ora(\"Applying migration...\").start();\n try {\n const applied = await runner.migrateUp();\n if (applied.length > 0) {\n applySpinner.succeed(\n `Applied ${applied.length} migration(s) successfully`\n );\n } else {\n applySpinner.info(\"No pending migrations to apply\");\n }\n } catch (error) {\n applySpinner.fail(\"Failed to apply migration\");\n throw error;\n }\n } else {\n console.log(chalk.dim(\"\\nMigration created but not applied.\"));\n console.log(chalk.dim(`Run \"nexusql up\" to apply pending migrations.`));\n }\n\n console.log(chalk.green(`\\nMigration file: ${filepath}\\n`));\n } finally {\n closePrompts();\n }\n}\n\n/**\n * Apply all pending migrations.\n */\nexport async function up(options: { dryRun?: boolean } = {}): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n const pending = await runner.getPendingMigrations();\n\n if (pending.length === 0) {\n spinner.info(\"No pending migrations\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`found ${pending.length} pending migration(s):`);\n for (const m of pending) {\n console.log(chalk.cyan(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Applying migrations...\";\n for (const migration of pending) {\n await runner.applyMigration(migration);\n console.log(chalk.green(` ✓ ${migration.name}`));\n }\n spinner.succeed(`Applied ${pending.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Migration failed\");\n throw error;\n }\n}\n\n/**\n * Rollback applied migrations.\n */\nexport async function down(\n options: { steps?: number; to?: string; dryRun?: boolean } = {}\n): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migrations...\").start();\n\n try {\n // Optimization: status() reads all files. A more efficient way to get ordered applied migrations is needed if history is huge.\n // For now, sorting 'applied' from status() works.\n const { applied } = await runner.status();\n const sortedApplied = applied.sort((a, b) =>\n b.version.localeCompare(a.version)\n ); // Newest first\n\n if (sortedApplied.length === 0) {\n spinner.info(\"No applied migrations to rollback\");\n return;\n }\n\n let toRollback: typeof applied = [];\n\n if (options.to) {\n const targetIndex = sortedApplied.findIndex(\n (m) => m.version === options.to\n );\n if (targetIndex === -1) {\n // If options.to is \"rollback to version X\", we want to rollback everything > X.\n // Let's assume options.to is the target version we want to KEEP.\n // So we rollback everything where version > options.to\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n if (toRollback.length === 0) {\n spinner.info(\n `Version ${options.to} is already the latest applied or doesn't exist in future history.`\n );\n return;\n }\n } else {\n // Rollback migrations newer than X.\n toRollback = sortedApplied.filter((m) => m.version > options.to!);\n }\n } else {\n const steps = options.steps ?? 1;\n toRollback = sortedApplied.slice(0, steps);\n }\n\n if (toRollback.length === 0) {\n spinner.info(\"No migrations to rollback\");\n return;\n }\n\n if (options.dryRun) {\n spinner.info(`Would rollback ${toRollback.length} migration(s):`);\n for (const m of toRollback) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n return;\n }\n\n spinner.text = \"Rolling back migrations...\";\n for (const migration of toRollback) {\n await runner.rollbackMigration(migration);\n console.log(chalk.yellow(` reverted ${migration.name}`));\n }\n spinner.succeed(`Rolled back ${toRollback.length} migration(s)`);\n } catch (error) {\n spinner.fail(\"Rollback failed\");\n throw error;\n }\n}\n\n/**\n * Show migration status.\n */\nexport async function status(): Promise<void> {\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(\"Checking migration status...\").start();\n const { applied, pending } = await runner.status();\n spinner.stop();\n\n console.log(chalk.bold(\"\\nMigration Status\\n\"));\n\n if (applied.length > 0) {\n console.log(chalk.green(\"Applied:\"));\n for (const m of applied) {\n console.log(chalk.green(` ✓ ${m.name}`));\n }\n }\n\n if (pending.length > 0) {\n console.log(chalk.yellow(\"\\nPending:\"));\n for (const m of pending) {\n console.log(chalk.yellow(` ○ ${m.name}`));\n }\n }\n\n if (applied.length === 0 && pending.length === 0) {\n console.log(chalk.dim(\"No migrations found.\"));\n }\n\n console.log();\n}\n","import * as readline from 'readline';\n\nlet rl: readline.Interface | null = null;\n\n/**\n * Get or create readline interface.\n */\nfunction getReadline(): readline.Interface {\n if (!rl) {\n rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n }\n return rl;\n}\n\n/**\n * Close readline interface.\n */\nexport function closePrompts(): void {\n if (rl) {\n rl.close();\n rl = null;\n }\n}\n\n/**\n * Ask user a question and return their answer.\n */\nexport function question(query: string): Promise<string> {\n return new Promise((resolve) => {\n getReadline().question(query, (answer) => {\n resolve(answer);\n });\n });\n}\n\n/**\n * Ask a yes/no question.\n */\nexport async function confirm(query: string): Promise<boolean> {\n const answer = await question(`${query} (yes/no): `);\n return answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y';\n}\n","import chalk from 'chalk';\nimport ora from 'ora';\nimport { Database } from '../lib/database.js';\nimport { MigrationRunner } from '../lib/runner.js';\nimport { loadConfig, getDatabaseUrl } from '../lib/config.js';\n\n/**\n * Mark a migration as applied without running it.\n */\nexport async function markApplied(version: string): Promise<void> {\n if (!version) {\n console.error(chalk.red('Error: Migration version is required'));\n console.log(chalk.dim('\\nUsage: nexusql mark-applied <version>'));\n console.log(chalk.dim('Example: nexusql mark-applied 20251209153535'));\n process.exit(1);\n }\n\n const config = await loadConfig();\n const databaseUrl = getDatabaseUrl(config);\n const db = new Database(databaseUrl);\n const runner = new MigrationRunner(db, config.migrations);\n\n const spinner = ora(`Marking migration ${version} as applied...`).start();\n\n try {\n await runner.markApplied(version);\n spinner.succeed(`Migration ${version} marked as applied`);\n } catch (error) {\n spinner.fail('Failed to mark migration as applied');\n throw error;\n }\n}\n","import { writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport chalk from 'chalk';\nimport { generateConfigTemplate } from '../lib/config.js';\n\nexport interface InitOptions {\n force?: boolean;\n}\n\n/**\n * Initialize nexusql configuration.\n */\nexport async function init(options: InitOptions = {}): Promise<void> {\n const cwd = process.cwd();\n\n // Create config file\n const configPath = join(cwd, 'nexusql.config.js');\n\n if (existsSync(configPath) && !options.force) {\n console.log(chalk.yellow('nexusql.config.js already exists.'));\n console.log(chalk.dim('Use --force to overwrite.'));\n return;\n }\n\n writeFileSync(configPath, generateConfigTemplate(), 'utf-8');\n console.log(chalk.green('Created nexusql.config.js'));\n\n // Create migrations directory\n const migrationsDir = join(cwd, 'db', 'migrations');\n if (!existsSync(migrationsDir)) {\n mkdirSync(migrationsDir, { recursive: true });\n console.log(chalk.green('Created db/migrations/'));\n }\n\n // Create .env.example if it doesn't exist\n const envExamplePath = join(cwd, '.env.example');\n if (!existsSync(envExamplePath)) {\n writeFileSync(\n envExamplePath,\n 'DATABASE_URL=postgres://user:password@localhost:5432/database\\n',\n 'utf-8'\n );\n console.log(chalk.green('Created .env.example'));\n }\n\n console.log(chalk.bold('\\nNext steps:'));\n console.log(' 1. Copy .env.example to .env and set your DATABASE_URL');\n console.log(' 2. Create your schema.dbml file');\n console.log(' 3. Run \"nexusql gen\" to generate migration SQL');\n console.log(' 4. Run \"nexusql migrate\" to create and apply migrations\\n');\n}\n"],"mappings":"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","names":["up","join","readFileSync","writeFileSync","chalk","readFileSync","chalk","writeFileSync","existsSync","chalk","ora","resolve","chalk","existsSync","ora","ora","chalk","chalk","ora","chalk","ora","writeFileSync","existsSync","mkdirSync","join","chalk","join","existsSync","chalk","writeFileSync","mkdirSync"]}
|