bun-query-builder 0.1.63 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/index.js CHANGED
@@ -11640,9 +11640,18 @@ var init_dist = __esm(() => {
11640
11640
  });
11641
11641
 
11642
11642
  // src/config.ts
11643
+ import process19 from "process";
11643
11644
  function isMysqlLike(dialect = config5.dialect) {
11644
11645
  return dialect === "mysql" || dialect === "singlestore";
11645
11646
  }
11647
+ function resolveDialect(explicit) {
11648
+ if (explicit)
11649
+ return explicit;
11650
+ const fromEnv = process19.env.DB_DIALECT || process19.env.DB_CONNECTION;
11651
+ if (fromEnv)
11652
+ return fromEnv;
11653
+ return config5.dialect || "postgres";
11654
+ }
11646
11655
  function getPlaceholder(index) {
11647
11656
  if (config5.dialect === "postgres") {
11648
11657
  return `$${index}`;
@@ -11801,7 +11810,7 @@ var {SQL } = globalThis.Bun;
11801
11810
  import { Database } from "bun:sqlite";
11802
11811
  import { mkdirSync as mkdirSync5 } from "fs";
11803
11812
  import { dirname as dirname5 } from "path";
11804
- import process19 from "process";
11813
+ import process21 from "process";
11805
11814
 
11806
11815
  class SQLiteWrapper {
11807
11816
  db;
@@ -12079,9 +12088,13 @@ function sqliteFileFromUrl(url) {
12079
12088
  const path = stripped.startsWith("///") ? stripped.slice(2) : stripped.startsWith("//") ? stripped.slice(2) : stripped;
12080
12089
  return path || ":memory:";
12081
12090
  }
12091
+ function resolveDatabaseName(dbConfig = config5.database) {
12092
+ const raw = process21.env.DB_DATABASE || dbConfig?.database || "";
12093
+ return String(raw).replace(/^['"]|['"]$/g, "");
12094
+ }
12082
12095
  function createConnectionString(dialect, dbConfig) {
12083
- if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process19.env.DB_CONNECTION === dialect) {
12084
- const e = process19.env;
12096
+ if ((dialect === "postgres" || dialect === "mysql" || dialect === "singlestore") && process21.env.DB_CONNECTION === dialect) {
12097
+ const e = process21.env;
12085
12098
  const envDb = (e.DB_DATABASE || dbConfig.database || "").replace(/^['"]|['"]$/g, "");
12086
12099
  const envUser = e.DB_USERNAME || dbConfig.username;
12087
12100
  const envPass = e.DB_PASSWORD ?? dbConfig.password ?? "";
@@ -12095,7 +12108,7 @@ function createConnectionString(dialect, dbConfig) {
12095
12108
  return dialect === "sqlite" ? sqliteFileFromUrl(dbConfig.url) : dbConfig.url;
12096
12109
  }
12097
12110
  const { database, username, password, host = "localhost", port, ssl } = dbConfig;
12098
- const sslQ = ssl || process19.env.DB_SSL === "true" || process19.env.DB_SSL === "1" ? "?ssl=true" : "";
12111
+ const sslQ = ssl || process21.env.DB_SSL === "true" || process21.env.DB_SSL === "1" ? "?ssl=true" : "";
12099
12112
  switch (dialect) {
12100
12113
  case "postgres":
12101
12114
  return `postgres://${username}:${password}@${host}${port ? `:${port}` : ""}/${database}${sslQ}`;
@@ -12369,6 +12382,17 @@ var init_benchmark = __esm(() => {
12369
12382
  });
12370
12383
 
12371
12384
  // src/inflect.ts
12385
+ function toTableName(modelName) {
12386
+ const snake = String(modelName).replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
12387
+ if (snake.endsWith("y") && !/[aeou]y$/.test(snake))
12388
+ return `${snake.slice(0, -1)}ies`;
12389
+ if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh"))
12390
+ return `${snake}es`;
12391
+ return `${snake}s`;
12392
+ }
12393
+ function tableNameFor(model) {
12394
+ return typeof model?.table === "string" && model.table.length > 0 ? model.table : toTableName(String(model?.name ?? ""));
12395
+ }
12372
12396
  function stripTrailingS(name) {
12373
12397
  return name.endsWith("s") ? name.slice(0, -1) : name;
12374
12398
  }
@@ -16589,7 +16613,7 @@ var init_cache = __esm(() => {
16589
16613
  });
16590
16614
 
16591
16615
  // src/actions/console.ts
16592
- import process21 from "process";
16616
+ import process22 from "process";
16593
16617
  import { createInterface } from "readline";
16594
16618
  async function startConsole() {
16595
16619
  console.log("-- Query Builder Interactive Console");
@@ -16598,8 +16622,8 @@ async function startConsole() {
16598
16622
  console.log();
16599
16623
  const qb = createQueryBuilder();
16600
16624
  const rl = createInterface({
16601
- input: process21.stdin,
16602
- output: process21.stdout,
16625
+ input: process22.stdin,
16626
+ output: process22.stdout,
16603
16627
  prompt: "qb> "
16604
16628
  });
16605
16629
  let multilineBuffer = "";
@@ -16650,7 +16674,7 @@ Tips:
16650
16674
  if (cmd === ".exit" || cmd === ".quit") {
16651
16675
  console.log("Goodbye!");
16652
16676
  rl.close();
16653
- process21.exit(0);
16677
+ process22.exit(0);
16654
16678
  } else if (cmd === ".help") {
16655
16679
  console.log(helpText);
16656
16680
  } else if (cmd === ".clear") {
@@ -16721,7 +16745,7 @@ Tips:
16721
16745
  rl.on("close", () => {
16722
16746
  console.log(`
16723
16747
  Goodbye!`);
16724
- process21.exit(0);
16748
+ process22.exit(0);
16725
16749
  });
16726
16750
  rl.prompt();
16727
16751
  }
@@ -17099,9 +17123,8 @@ var init_db_info = __esm(() => {
17099
17123
  });
17100
17124
 
17101
17125
  // src/actions/db-optimize.ts
17102
- import process22 from "process";
17103
17126
  async function dbOptimize(options = {}) {
17104
- const dialect = options.dialect || process22.env.DB_DIALECT || config5.dialect || "postgres";
17127
+ const dialect = resolveDialect(options.dialect);
17105
17128
  const aggressive = options.aggressive || false;
17106
17129
  if (options.verbose) {
17107
17130
  console.log(`Optimizing ${dialect} database${aggressive ? " (aggressive mode)" : ""}...`);
@@ -17141,7 +17164,7 @@ async function dbOptimize(options = {}) {
17141
17164
  await bunSql`ANALYZE TABLE ${bunSql(table)}`;
17142
17165
  }
17143
17166
  } else {
17144
- const dbName = process22.env.DB_NAME || "test";
17167
+ const dbName = resolveDatabaseName();
17145
17168
  const tables = await bunSql`
17146
17169
  SELECT table_name
17147
17170
  FROM information_schema.tables
@@ -17194,9 +17217,8 @@ var init_db_optimize = __esm(() => {
17194
17217
  });
17195
17218
 
17196
17219
  // src/actions/db-wipe.ts
17197
- import process23 from "process";
17198
17220
  async function dbWipe(options = {}) {
17199
- const dialect = options.dialect || process23.env.DB_DIALECT || config5.dialect || "postgres";
17221
+ const dialect = resolveDialect(options.dialect);
17200
17222
  if (options.verbose) {
17201
17223
  console.log(`Wiping all tables from ${dialect} database...`);
17202
17224
  }
@@ -17210,7 +17232,7 @@ async function dbWipe(options = {}) {
17210
17232
  `;
17211
17233
  tables = result.map((row) => row.tablename);
17212
17234
  } else if (isMysqlLike(dialect)) {
17213
- const dbName = process23.env.DB_NAME || "test";
17235
+ const dbName = resolveDatabaseName();
17214
17236
  const result = await bunSql`
17215
17237
  SELECT table_name
17216
17238
  FROM information_schema.tables
@@ -17647,6 +17669,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
17647
17669
  return "decimal";
17648
17670
  if (base === "date")
17649
17671
  return "date";
17672
+ if (base === "timestamptz" || /\bwith time zone\b/.test(t))
17673
+ return "timestamptz";
17650
17674
  if (/^(?:timestamp|datetime)/.test(base))
17651
17675
  return "datetime";
17652
17676
  if (/^time/.test(base))
@@ -17902,7 +17926,7 @@ var init_introspect_db = __esm(() => {
17902
17926
  // src/actions/make-model.ts
17903
17927
  import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10 } from "fs";
17904
17928
  import { dirname as dirname7, join as join7 } from "path";
17905
- import process24 from "process";
17929
+ import process23 from "process";
17906
17930
  function findWorkspaceRoot(startPath) {
17907
17931
  let currentPath = startPath;
17908
17932
  while (currentPath !== dirname7(currentPath)) {
@@ -17911,10 +17935,10 @@ function findWorkspaceRoot(startPath) {
17911
17935
  }
17912
17936
  currentPath = dirname7(currentPath);
17913
17937
  }
17914
- return process24.cwd();
17938
+ return process23.cwd();
17915
17939
  }
17916
17940
  async function makeModel(name, options = {}) {
17917
- const workspaceRoot = findWorkspaceRoot(process24.cwd());
17941
+ const workspaceRoot = findWorkspaceRoot(process23.cwd());
17918
17942
  const modelsDir = options.dir || join7(workspaceRoot, "app/Models");
17919
17943
  if (!existsSync14(modelsDir)) {
17920
17944
  mkdirSync7(modelsDir, { recursive: true });
@@ -18110,7 +18134,7 @@ class MySQLDriver {
18110
18134
  )`;
18111
18135
  }
18112
18136
  getExecutedMigrationsQuery() {
18113
- return "SELECT migration FROM migrations ORDER BY executed_at";
18137
+ return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
18114
18138
  }
18115
18139
  recordMigrationQuery() {
18116
18140
  return "INSERT INTO migrations (migration) VALUES (?)";
@@ -18291,7 +18315,7 @@ class PostgresDriver {
18291
18315
  )`;
18292
18316
  }
18293
18317
  getExecutedMigrationsQuery() {
18294
- return "SELECT migration FROM migrations ORDER BY executed_at";
18318
+ return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
18295
18319
  }
18296
18320
  recordMigrationQuery() {
18297
18321
  return "INSERT INTO migrations (migration) VALUES ($1)";
@@ -18536,7 +18560,7 @@ class SQLiteDriver {
18536
18560
  )`;
18537
18561
  }
18538
18562
  getExecutedMigrationsQuery() {
18539
- return "SELECT migration FROM migrations ORDER BY executed_at";
18563
+ return "SELECT migration, executed_at FROM migrations ORDER BY executed_at";
18540
18564
  }
18541
18565
  recordMigrationQuery() {
18542
18566
  return "INSERT INTO migrations (migration) VALUES (?)";
@@ -18589,6 +18613,24 @@ var init_drivers = __esm(() => {
18589
18613
  init_singlestore();
18590
18614
  });
18591
18615
 
18616
+ // src/workspace.ts
18617
+ import { existsSync as existsSync16 } from "fs";
18618
+ import { dirname as dirname8, join as join9 } from "path";
18619
+ import process24 from "process";
18620
+ function findWorkspaceRoot2(startPath = process24.cwd()) {
18621
+ let currentPath = startPath;
18622
+ while (currentPath !== dirname8(currentPath)) {
18623
+ if (existsSync16(join9(currentPath, "package.json")))
18624
+ return currentPath;
18625
+ currentPath = dirname8(currentPath);
18626
+ }
18627
+ return process24.cwd();
18628
+ }
18629
+ function getSqlDirectory(workspaceRoot) {
18630
+ return join9(workspaceRoot ?? findWorkspaceRoot2(), "database", "migrations");
18631
+ }
18632
+ var init_workspace = () => {};
18633
+
18592
18634
  // src/actions/migrate.ts
18593
18635
  var exports_migrate = {};
18594
18636
  __export(exports_migrate, {
@@ -18600,23 +18642,48 @@ __export(exports_migrate, {
18600
18642
  copyModelsToGenerated: () => copyModelsToGenerated,
18601
18643
  clearGeneratedDirectory: () => clearGeneratedDirectory
18602
18644
  });
18603
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
18645
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8, mkdtempSync, readdirSync as readdirSync6, readFileSync as readFileSync3, rmSync, unlinkSync, writeFileSync as writeFileSync11 } from "fs";
18604
18646
  import { tmpdir } from "os";
18605
- import { join as join9 } from "path";
18647
+ import { join as join10 } from "path";
18606
18648
  import process25 from "process";
18649
+ async function settleAppliedFiles(qb, dialect, files) {
18650
+ if (files.length === 0)
18651
+ return;
18652
+ const sqlDir = ensureSqlDirectory(getWorkspaceRoot());
18653
+ try {
18654
+ await createMigrationsTable(qb, dialect);
18655
+ for (const file2 of files) {
18656
+ await recordMigration(qb, file2, dialect);
18657
+ info(`-- \u2713 Recorded applied migration: ${file2}`);
18658
+ }
18659
+ } catch (err) {
18660
+ info(`-- Could not record applied migrations (the schema change itself succeeded): ${err instanceof Error ? err.message : String(err)}`);
18661
+ }
18662
+ }
18663
+ function isGeneratedMigration(sqlDir, file2) {
18664
+ try {
18665
+ return isGeneratedMigrationSql(readFileSync3(join10(sqlDir, file2), "utf8"));
18666
+ } catch {
18667
+ return false;
18668
+ }
18669
+ }
18670
+ function isAlreadyAppliedError(err) {
18671
+ const message = err instanceof Error ? err.message : String(err);
18672
+ return /duplicate column name/i.test(message) || /duplicate key name/i.test(message) || /\balready exists\b/i.test(message);
18673
+ }
18607
18674
  function info(message) {
18608
18675
  if (config5.verbose)
18609
18676
  console.log(message);
18610
18677
  }
18611
18678
  function getSnapshotDir(workspaceRoot) {
18612
- return join9(workspaceRoot, config5.snapshotDir || ".qb");
18679
+ return join10(workspaceRoot, config5.snapshotDir || ".qb");
18613
18680
  }
18614
18681
  function getSnapshotPath(workspaceRoot, dialect) {
18615
- return join9(getSnapshotDir(workspaceRoot), `model-snapshot.${dialect}.json`);
18682
+ return join10(getSnapshotDir(workspaceRoot), `model-snapshot.${dialect}.json`);
18616
18683
  }
18617
18684
  function loadPlanSnapshot(workspaceRoot, dialect) {
18618
18685
  const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
18619
- if (!existsSync16(snapshotPath)) {
18686
+ if (!existsSync17(snapshotPath)) {
18620
18687
  return;
18621
18688
  }
18622
18689
  try {
@@ -18639,7 +18706,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
18639
18706
  const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
18640
18707
  const snapshotDir = getSnapshotDir(workspaceRoot);
18641
18708
  const hash = hashMigrationPlan(plan);
18642
- if (existsSync16(snapshotPath)) {
18709
+ if (existsSync17(snapshotPath)) {
18643
18710
  try {
18644
18711
  const current = JSON.parse(readFileSync3(snapshotPath, "utf8"));
18645
18712
  if (current?.hash === hash && current?.dialect === dialect && current?.plan) {
@@ -18648,7 +18715,7 @@ function savePlanSnapshot(workspaceRoot, dialect, plan) {
18648
18715
  }
18649
18716
  } catch {}
18650
18717
  }
18651
- if (!existsSync16(snapshotDir)) {
18718
+ if (!existsSync17(snapshotDir)) {
18652
18719
  mkdirSync8(snapshotDir, { recursive: true });
18653
18720
  info(`-- Created snapshot directory: ${snapshotDir}`);
18654
18721
  }
@@ -18666,11 +18733,11 @@ function saveMigrationSnapshot(plan, options = {}) {
18666
18733
  savePlanSnapshot(options.workspaceRoot ?? getWorkspaceRoot(), dialect, plan);
18667
18734
  }
18668
18735
  function getWorkspaceRoot() {
18669
- return process25.cwd();
18736
+ return findWorkspaceRoot2();
18670
18737
  }
18671
18738
  function ensureSqlDirectory(workspaceRoot) {
18672
18739
  const sqlDir = getSqlDirectory(workspaceRoot);
18673
- if (!existsSync16(sqlDir)) {
18740
+ if (!existsSync17(sqlDir)) {
18674
18741
  mkdirSync8(sqlDir, { recursive: true });
18675
18742
  info(`-- Created SQL directory: ${sqlDir}`);
18676
18743
  }
@@ -18679,21 +18746,22 @@ function ensureSqlDirectory(workspaceRoot) {
18679
18746
  async function generateMigration(dir, opts = {}) {
18680
18747
  await getConfig();
18681
18748
  if (!dir) {
18682
- dir = join9(process25.cwd(), "app/Models");
18749
+ dir = join10(process25.cwd(), "app/Models");
18683
18750
  }
18684
18751
  const dialect = opts.dialect || config5.dialect || "postgres";
18685
18752
  const workspaceRoot = getWorkspaceRoot();
18686
18753
  const models = await loadModels({ modelsDir: dir });
18687
18754
  const plan = buildMigrationPlan2(models, { dialect });
18688
18755
  let previous;
18756
+ let reconciledFromDatabase = false;
18689
18757
  if (!opts.full) {
18690
18758
  previous = loadPlanSnapshot(workspaceRoot, dialect);
18691
18759
  if (previous) {
18692
18760
  info("-- Comparing with stored model snapshot");
18693
18761
  } else {
18694
- const defaultStatePath = join9(dir, `.qb-migrations.${dialect}.json`);
18762
+ const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
18695
18763
  const statePath = String(opts.state || defaultStatePath);
18696
- if (existsSync16(statePath)) {
18764
+ if (existsSync17(statePath)) {
18697
18765
  try {
18698
18766
  const raw2 = readFileSync3(statePath, "utf8");
18699
18767
  const parsed = JSON.parse(raw2);
@@ -18710,6 +18778,7 @@ async function generateMigration(dir, opts = {}) {
18710
18778
  const scoped = livePlan.tables.filter((t) => modelTables.has(t.table));
18711
18779
  if (scoped.length > 0) {
18712
18780
  previous = { dialect: livePlan.dialect, tables: scoped };
18781
+ reconciledFromDatabase = true;
18713
18782
  info(`-- No snapshot; reconciling against live database (${scoped.length} matching table${scoped.length === 1 ? "" : "s"})`);
18714
18783
  }
18715
18784
  } catch (err) {
@@ -18723,25 +18792,34 @@ async function generateMigration(dir, opts = {}) {
18723
18792
  } else {
18724
18793
  info("-- Full migration requested, ignoring any previous state");
18725
18794
  }
18726
- const diff = opts.full ? { statements: generateSql(plan, { dryRun: opts.dryRun }), operations: plan.tables.map((t) => ({ kind: "create_table", table: t.table, destructive: false, sql: "" })) } : generateDiffOperations(previous, plan, { applyRenames: opts.applyRenames, dryRun: opts.dryRun });
18795
+ const diff = opts.full ? { statements: generateSql(plan, { dryRun: opts.dryRun }), operations: plan.tables.map((t) => ({ kind: "create_table", table: t.table, destructive: false, sql: "" })) } : generateDiffOperations(previous, plan, {
18796
+ applyRenames: opts.applyRenames,
18797
+ dryRun: opts.dryRun,
18798
+ preserveUnknownColumns: reconciledFromDatabase
18799
+ });
18727
18800
  const sqlStatements = diff.statements;
18728
18801
  const operations = diff.operations;
18729
18802
  const sql = sqlStatements.join(`
18730
18803
  `);
18731
18804
  const hasChanges = sqlStatements.some((stmt) => /\b(?:CREATE|ALTER|DROP)\b/i.test(stmt));
18732
18805
  if (opts.apply) {
18733
- const dirPath = mkdtempSync(join9(tmpdir(), "qb-migrate-"));
18734
- const filePath = join9(dirPath, "migration.sql");
18806
+ const dirPath = mkdtempSync(join10(tmpdir(), "qb-migrate-"));
18807
+ const filePath = join10(dirPath, "migration.sql");
18735
18808
  try {
18736
18809
  if (hasChanges) {
18737
18810
  writeFileSync11(filePath, sql);
18811
+ const qb = createQueryBuilder();
18812
+ await qb.file(filePath);
18738
18813
  info("-- Migration applied");
18814
+ await settleAppliedFiles(qb, dialect, lastCreatedMigrationFiles());
18739
18815
  } else {
18740
18816
  info("-- No changes; nothing to apply");
18741
18817
  }
18742
18818
  } catch (err) {
18743
18819
  console.error("-- Migration failed:", err);
18744
18820
  throw err;
18821
+ } finally {
18822
+ rmSync(dirPath, { recursive: true, force: true });
18745
18823
  }
18746
18824
  }
18747
18825
  if (!opts.dryRun)
@@ -18750,9 +18828,6 @@ async function generateMigration(dir, opts = {}) {
18750
18828
  }
18751
18829
  async function executeMigration(dir) {
18752
18830
  await getConfig();
18753
- if (!dir) {
18754
- dir = join9(process25.cwd(), "app/Models");
18755
- }
18756
18831
  const workspaceRoot = getWorkspaceRoot();
18757
18832
  const sqlDir = ensureSqlDirectory(workspaceRoot);
18758
18833
  const dialect = config5.dialect || "postgres";
@@ -18767,42 +18842,25 @@ async function executeMigration(dir) {
18767
18842
  const qb = createQueryBuilder();
18768
18843
  await createMigrationsTable(qb, dialect);
18769
18844
  const executedMigrations = await getExecutedMigrations(qb, dialect);
18770
- const permanentMigrations = [];
18771
- const transientMigrations = [];
18772
- for (const file2 of scriptFiles) {
18773
- if (file2.includes("alter-") && file2.includes("-table")) {
18774
- transientMigrations.push(file2);
18775
- } else if (!executedMigrations.includes(file2)) {
18776
- permanentMigrations.push(file2);
18777
- }
18778
- }
18779
- const totalPending = permanentMigrations.length + transientMigrations.length;
18780
- if (totalPending === 0) {
18845
+ const pending = scriptFiles.filter((file2) => !executedMigrations.includes(file2));
18846
+ if (pending.length === 0) {
18781
18847
  info("-- No pending migrations to execute");
18782
18848
  return true;
18783
18849
  }
18784
- info(`-- Executing ${totalPending} migrations (${permanentMigrations.length} permanent, ${transientMigrations.length} transient)`);
18785
- for (const file2 of permanentMigrations) {
18786
- const filePath = join9(sqlDir, file2);
18850
+ info(`-- Executing ${pending.length} migration${pending.length === 1 ? "" : "s"}`);
18851
+ for (const file2 of pending) {
18852
+ const filePath = join10(sqlDir, file2);
18787
18853
  info(`-- Executing: ${file2}`);
18788
18854
  try {
18789
18855
  await qb.file(filePath);
18790
18856
  await recordMigration(qb, file2, dialect);
18791
18857
  info(`-- \u2713 Migration ${file2} executed and recorded`);
18792
18858
  } catch (err) {
18793
- console.error(`-- \u2717 Migration ${file2} failed:`, err);
18794
- throw err;
18795
- }
18796
- }
18797
- for (const file2 of transientMigrations) {
18798
- const filePath = join9(sqlDir, file2);
18799
- info(`-- Executing: ${file2} (transient)`);
18800
- try {
18801
- await qb.file(filePath);
18802
- info(`-- \u2713 Migration ${file2} executed (not recorded)`);
18803
- unlinkSync(filePath);
18804
- info(`-- \uD83D\uDDD1\uFE0F Deleted transient migration: ${file2}`);
18805
- } catch (err) {
18859
+ if (isGeneratedMigration(sqlDir, file2) && isAlreadyAppliedError(err)) {
18860
+ await recordMigration(qb, file2, dialect);
18861
+ info(`-- \u2713 Migration ${file2} was already applied; recorded it (${err instanceof Error ? err.message : String(err)})`);
18862
+ continue;
18863
+ }
18806
18864
  console.error(`-- \u2717 Migration ${file2} failed:`, err);
18807
18865
  throw err;
18808
18866
  }
@@ -18817,7 +18875,7 @@ async function executeMigration(dir) {
18817
18875
  async function resetDatabase(dir, opts = {}) {
18818
18876
  await getConfig();
18819
18877
  if (!dir) {
18820
- dir = join9(process25.cwd(), "app/Models");
18878
+ dir = join10(process25.cwd(), "app/Models");
18821
18879
  }
18822
18880
  const dialect = opts.dialect || config5.dialect || "postgres";
18823
18881
  const driver = getDialectDriver(dialect);
@@ -18914,42 +18972,50 @@ async function resetDatabase(dir, opts = {}) {
18914
18972
  }
18915
18973
  async function deleteMigrationFiles(dir, workspaceRoot, opts = {}) {
18916
18974
  if (!dir) {
18917
- dir = join9(process25.cwd(), "app/Models");
18975
+ dir = join10(process25.cwd(), "app/Models");
18918
18976
  }
18919
18977
  if (!workspaceRoot) {
18920
18978
  workspaceRoot = getWorkspaceRoot();
18921
18979
  }
18922
18980
  const dialect = String(opts.dialect || config5.dialect || "postgres");
18923
18981
  const snapshotPath = getSnapshotPath(workspaceRoot, dialect);
18924
- if (existsSync16(snapshotPath)) {
18982
+ if (existsSync17(snapshotPath)) {
18925
18983
  unlinkSync(snapshotPath);
18926
18984
  info(`-- Removed model snapshot file: ${snapshotPath}`);
18927
18985
  }
18928
- const defaultStatePath = join9(dir, `.qb-migrations.${dialect}.json`);
18986
+ const defaultStatePath = join10(dir, `.qb-migrations.${dialect}.json`);
18929
18987
  const statePath = String(opts.state || defaultStatePath);
18930
- if (existsSync16(statePath)) {
18988
+ if (existsSync17(statePath)) {
18931
18989
  unlinkSync(statePath);
18932
18990
  info(`-- Removed legacy migration state file: ${statePath}`);
18933
18991
  }
18934
- const sqlDir = getSqlDirectory(workspaceRoot);
18935
- if (existsSync16(sqlDir)) {
18936
- const sqlFiles = readdirSync6(sqlDir);
18937
- const migrationFiles = sqlFiles.filter((file2) => file2.endsWith(".sql"));
18938
- for (const file2 of migrationFiles) {
18939
- const filePath = join9(sqlDir, file2);
18940
- unlinkSync(filePath);
18941
- info(`-- Removed migration file: ${file2}`);
18992
+ removeGeneratedMigrationFiles(getSqlDirectory(workspaceRoot));
18993
+ }
18994
+ function removeGeneratedMigrationFiles(sqlDir) {
18995
+ if (!existsSync17(sqlDir))
18996
+ return;
18997
+ let removed = 0;
18998
+ const kept = [];
18999
+ for (const file2 of readdirSync6(sqlDir).filter((f) => f.endsWith(".sql"))) {
19000
+ if (!isGeneratedMigration(sqlDir, file2)) {
19001
+ kept.push(file2);
19002
+ continue;
18942
19003
  }
18943
- info(`-- Cleaned up ${migrationFiles.length} migration files from migrations directory`);
19004
+ unlinkSync(join10(sqlDir, file2));
19005
+ info(`-- Removed generated migration file: ${file2}`);
19006
+ removed += 1;
18944
19007
  }
19008
+ info(`-- Cleaned up ${removed} generated migration file${removed === 1 ? "" : "s"} from migrations directory`);
19009
+ if (kept.length > 0)
19010
+ info(`-- Kept ${kept.length} hand-written migration${kept.length === 1 ? "" : "s"}: ${kept.slice(0, 5).join(", ")}${kept.length > 5 ? `, +${kept.length - 5} more` : ""}`);
18945
19011
  }
18946
19012
  async function copyModelsToGenerated(_dir, _workspaceRoot) {}
18947
19013
  async function clearGeneratedDirectory(workspaceRoot) {
18948
19014
  if (!workspaceRoot) {
18949
19015
  workspaceRoot = getWorkspaceRoot();
18950
19016
  }
18951
- const generatedDir = join9(workspaceRoot, "generated");
18952
- if (existsSync16(generatedDir)) {
19017
+ const generatedDir = join10(workspaceRoot, "generated");
19018
+ if (existsSync17(generatedDir)) {
18953
19019
  try {
18954
19020
  rmSync(generatedDir, { recursive: true, force: true });
18955
19021
  info("-- Cleared generated directory");
@@ -18958,12 +19024,6 @@ async function clearGeneratedDirectory(workspaceRoot) {
18958
19024
  }
18959
19025
  }
18960
19026
  }
18961
- function getSqlDirectory(workspaceRoot) {
18962
- if (!workspaceRoot) {
18963
- workspaceRoot = getWorkspaceRoot();
18964
- }
18965
- return join9(workspaceRoot, "database", "migrations");
18966
- }
18967
19027
  async function createMigrationsTable(qb, dialect) {
18968
19028
  const driver = getDialectDriver(dialect);
18969
19029
  const createTableSql = driver.createMigrationsTable();
@@ -19002,6 +19062,7 @@ var init_migrate = __esm(() => {
19002
19062
  init_drivers();
19003
19063
  init_src2();
19004
19064
  init_introspect_db();
19065
+ init_workspace();
19005
19066
  });
19006
19067
 
19007
19068
  // src/actions/migrate-generate.ts
@@ -19013,28 +19074,49 @@ var init_migrate_generate = __esm(() => {
19013
19074
  });
19014
19075
 
19015
19076
  // src/actions/migrate-rollback.ts
19016
- import { existsSync as existsSync17, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
19017
- import { dirname as dirname8, join as join10 } from "path";
19018
- import process26 from "process";
19077
+ import { existsSync as existsSync18, readFileSync as readFileSync4, unlinkSync as unlinkSync2 } from "fs";
19078
+ import { join as join11 } from "path";
19019
19079
  function splitSqlStatements2(sql) {
19020
19080
  const out = [];
19021
19081
  let buf = "";
19022
- let inString = false;
19023
- const lines = sql.split(`
19024
- `).filter((l) => !/^\s*--/.test(l));
19025
- const text = lines.join(`
19026
- `);
19027
- for (let i = 0;i < text.length; i++) {
19028
- const ch = text[i];
19029
- if (ch === "'")
19030
- inString = !inString;
19031
- if (ch === ";" && !inString) {
19082
+ let quote = null;
19083
+ for (let i = 0;i < sql.length; i++) {
19084
+ const ch = sql[i];
19085
+ if (quote) {
19086
+ buf += ch;
19087
+ if (ch === quote) {
19088
+ if (sql[i + 1] === quote) {
19089
+ buf += sql[i + 1];
19090
+ i++;
19091
+ } else {
19092
+ quote = null;
19093
+ }
19094
+ }
19095
+ continue;
19096
+ }
19097
+ if (ch === "'" || ch === '"' || ch === "`") {
19098
+ quote = ch;
19099
+ buf += ch;
19100
+ continue;
19101
+ }
19102
+ if (ch === "-" && sql[i + 1] === "-") {
19103
+ const newline = sql.indexOf(`
19104
+ `, i);
19105
+ i = newline === -1 ? sql.length : newline;
19106
+ continue;
19107
+ }
19108
+ if (ch === "/" && sql[i + 1] === "*") {
19109
+ const close = sql.indexOf("*/", i + 2);
19110
+ i = close === -1 ? sql.length : close + 1;
19111
+ continue;
19112
+ }
19113
+ if (ch === ";") {
19032
19114
  if (buf.trim())
19033
19115
  out.push(buf.trim());
19034
19116
  buf = "";
19035
- } else {
19036
- buf += ch;
19117
+ continue;
19037
19118
  }
19119
+ buf += ch;
19038
19120
  }
19039
19121
  if (buf.trim())
19040
19122
  out.push(buf.trim());
@@ -19048,8 +19130,20 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
19048
19130
  let m;
19049
19131
  if (m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
19050
19132
  down.push(`DROP TABLE IF EXISTS ${q(m[1])}`);
19051
- } else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+)?["`']?(\w+)["`']?/i.exec(stmt)) {
19052
- down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(m[2])}`);
19133
+ } else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+CONSTRAINT\s+["`']?(\w+)["`']?([\s\S]*)$/i.exec(stmt)) {
19134
+ if (dialect === "sqlite") {
19135
+ skipped.push(stmt);
19136
+ } else if (isMysqlLike(dialect) && /\bFOREIGN\s+KEY\b/i.test(m[3] ?? "")) {
19137
+ down.push(`ALTER TABLE ${q(m[1])} DROP FOREIGN KEY ${q(m[2])}`);
19138
+ } else {
19139
+ down.push(`ALTER TABLE ${q(m[1])} DROP CONSTRAINT ${q(m[2])}`);
19140
+ }
19141
+ } else if (m = /^ALTER\s+TABLE\s+["`']?(\w+)["`']?\s+ADD\s+(?:COLUMN\s+["`']?(\w+)["`']?|["`'](\w+)["`']|(\w+))/i.exec(stmt)) {
19142
+ const column = m[2] ?? m[3] ?? m[4];
19143
+ if (m[4] && /^(?:PRIMARY|UNIQUE|INDEX|KEY|FOREIGN|CHECK|FULLTEXT|SPATIAL)$/i.test(m[4]))
19144
+ skipped.push(stmt);
19145
+ else
19146
+ down.push(`ALTER TABLE ${q(m[1])} DROP COLUMN ${q(column)}`);
19053
19147
  } else if (m = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`']?(\w+)["`']?(?:\s+ON\s+["`']?(\w+)["`']?)?/i.exec(stmt)) {
19054
19148
  down.push(isMysqlLike(dialect) && m[2] ? `DROP INDEX ${q(m[1])} ON ${q(m[2])}` : `DROP INDEX IF EXISTS ${q(m[1])}`);
19055
19149
  } else {
@@ -19058,22 +19152,6 @@ function deriveDownStatements(forwardSql, dialect = config5.dialect) {
19058
19152
  }
19059
19153
  return { down: down.reverse(), skipped };
19060
19154
  }
19061
- function findWorkspaceRoot2(startPath) {
19062
- let currentPath = startPath;
19063
- while (currentPath !== dirname8(currentPath)) {
19064
- if (existsSync17(join10(currentPath, "package.json"))) {
19065
- return currentPath;
19066
- }
19067
- currentPath = dirname8(currentPath);
19068
- }
19069
- return process26.cwd();
19070
- }
19071
- function getSqlDirectory2(workspaceRoot) {
19072
- if (!workspaceRoot) {
19073
- workspaceRoot = findWorkspaceRoot2(process26.cwd());
19074
- }
19075
- return join10(workspaceRoot, "database", "migrations");
19076
- }
19077
19155
  async function migrateRollback(options = {}) {
19078
19156
  const steps = options.steps || 1;
19079
19157
  const reverseSchema = options.reverseSchema !== false;
@@ -19106,12 +19184,12 @@ async function migrateRollback(options = {}) {
19106
19184
  console.log(` - ${migration.migration}`);
19107
19185
  }
19108
19186
  console.log();
19109
- const sqlDir = getSqlDirectory2();
19187
+ const sqlDir = getSqlDirectory();
19110
19188
  let reversedAny = false;
19111
19189
  for (const migration of migrationsToRollback) {
19112
19190
  try {
19113
- const filePath = join10(sqlDir, migration.migration);
19114
- if (reverseSchema && existsSync17(filePath)) {
19191
+ const filePath = join11(sqlDir, migration.migration);
19192
+ if (reverseSchema && existsSync18(filePath)) {
19115
19193
  const forwardSql = readFileSync4(filePath, "utf8");
19116
19194
  const { down, skipped } = deriveDownStatements(forwardSql);
19117
19195
  for (const stmt of down) {
@@ -19122,10 +19200,10 @@ async function migrateRollback(options = {}) {
19122
19200
  if (skipped.length > 0)
19123
19201
  console.log(`-- \u26A0\uFE0F ${skipped.length} statement(s) in ${migration.migration} could not be auto-reversed (data/complex DDL) \u2014 reverse manually.`);
19124
19202
  }
19125
- const deleteSql = `DELETE FROM migrations WHERE migration = $1`;
19203
+ const deleteSql = `DELETE FROM migrations WHERE migration = ${getPlaceholder(1)}`;
19126
19204
  await qb.unsafe(deleteSql, [migration.migration]);
19127
19205
  console.log(`-- \u2713 Removed migration record: ${migration.migration}`);
19128
- if (existsSync17(filePath)) {
19206
+ if (options.deleteFiles && existsSync18(filePath)) {
19129
19207
  unlinkSync2(filePath);
19130
19208
  console.log(`-- \uD83D\uDDD1\uFE0F Deleted migration file: ${migration.migration}`);
19131
19209
  }
@@ -19148,37 +19226,20 @@ async function migrateRollback(options = {}) {
19148
19226
  var init_migrate_rollback = __esm(() => {
19149
19227
  init_config();
19150
19228
  init_src2();
19229
+ init_workspace();
19151
19230
  });
19152
19231
 
19153
19232
  // src/actions/migrate-status.ts
19154
- import { existsSync as existsSync18, readdirSync as readdirSync8 } from "fs";
19155
- import { dirname as dirname9, join as join11 } from "path";
19156
- import process27 from "process";
19157
- function findWorkspaceRoot3(startPath) {
19158
- let currentPath = startPath;
19159
- while (currentPath !== dirname9(currentPath)) {
19160
- if (existsSync18(join11(currentPath, "package.json"))) {
19161
- return currentPath;
19162
- }
19163
- currentPath = dirname9(currentPath);
19164
- }
19165
- return process27.cwd();
19166
- }
19167
- function getSqlDirectory3(workspaceRoot) {
19168
- if (!workspaceRoot) {
19169
- workspaceRoot = findWorkspaceRoot3(process27.cwd());
19170
- }
19171
- return join11(workspaceRoot, "database", "migrations");
19172
- }
19233
+ import { existsSync as existsSync19, readdirSync as readdirSync8 } from "fs";
19173
19234
  async function migrateStatus() {
19174
19235
  const dialect = config5.dialect || "postgres";
19175
19236
  const driver = getDialectDriver(dialect);
19176
- const sqlDir = getSqlDirectory3();
19237
+ const sqlDir = getSqlDirectory();
19177
19238
  console.log("-- Migration Status");
19178
19239
  console.log(`-- Dialect: ${dialect}`);
19179
19240
  console.log(`-- SQL directory: ${sqlDir}`);
19180
19241
  console.log();
19181
- if (!existsSync18(sqlDir)) {
19242
+ if (!existsSync19(sqlDir)) {
19182
19243
  console.log("-- No SQL directory found. No migrations have been created yet.");
19183
19244
  return [];
19184
19245
  }
@@ -19199,27 +19260,16 @@ async function migrateStatus() {
19199
19260
  console.log();
19200
19261
  }
19201
19262
  const executedMap = new Map(executedMigrations.map((m) => [m.migration, m.executed_at]));
19202
- const statuses = migrationFiles.map((file2) => {
19203
- if (file2.includes("alter-") && file2.includes("-table")) {
19204
- return {
19205
- file: file2,
19206
- status: "transient"
19207
- };
19208
- }
19209
- const executedAt = executedMap.get(file2);
19210
- return {
19211
- file: file2,
19212
- status: executedAt ? "executed" : "pending",
19213
- executedAt
19214
- };
19215
- });
19263
+ const statuses = migrationFiles.map((file2) => ({
19264
+ file: file2,
19265
+ status: executedMap.has(file2) ? "executed" : "pending",
19266
+ executedAt: executedMap.get(file2)
19267
+ }));
19216
19268
  const executed = statuses.filter((s) => s.status === "executed");
19217
19269
  const pending = statuses.filter((s) => s.status === "pending");
19218
- const transient = statuses.filter((s) => s.status === "transient");
19219
19270
  console.log(`-- Total migrations: ${migrationFiles.length}`);
19220
19271
  console.log(`-- Executed: ${executed.length}`);
19221
19272
  console.log(`-- Pending: ${pending.length}`);
19222
- console.log(`-- Transient: ${transient.length}`);
19223
19273
  console.log();
19224
19274
  if (executed.length > 0) {
19225
19275
  console.log("\u2713 Executed Migrations:");
@@ -19235,13 +19285,6 @@ async function migrateStatus() {
19235
19285
  }
19236
19286
  console.log();
19237
19287
  }
19238
- if (transient.length > 0) {
19239
- console.log("\u26A1 Transient Migrations (ALTER TABLE - not tracked):");
19240
- for (const migration of transient) {
19241
- console.log(` - ${migration.file}`);
19242
- }
19243
- console.log();
19244
- }
19245
19288
  return statuses;
19246
19289
  } catch (err) {
19247
19290
  console.error("-- Failed to get migration status:", err);
@@ -19255,14 +19298,15 @@ var init_migrate_status = __esm(() => {
19255
19298
  init_config();
19256
19299
  init_drivers();
19257
19300
  init_src2();
19301
+ init_workspace();
19258
19302
  });
19259
19303
 
19260
19304
  // src/actions/model-show.ts
19261
19305
  import { readdirSync as readdirSync9 } from "fs";
19262
19306
  import { extname as extname2, join as join12 } from "path";
19263
- import process28 from "process";
19307
+ import process26 from "process";
19264
19308
  async function modelShow(modelName, options = {}) {
19265
- const dir = options.dir || join12(process28.cwd(), "app/Models");
19309
+ const dir = options.dir || join12(process26.cwd(), "app/Models");
19266
19310
  try {
19267
19311
  const files = readdirSync9(dir);
19268
19312
  const modelFile = files.find((f) => {
@@ -19476,9 +19520,9 @@ var init_query_explain_all = __esm(() => {
19476
19520
  // src/actions/relation-diagram.ts
19477
19521
  import { writeFileSync as writeFileSync12 } from "fs";
19478
19522
  import { join as join14 } from "path";
19479
- import process29 from "process";
19523
+ import process27 from "process";
19480
19524
  async function relationDiagram(options = {}) {
19481
- const dir = options.dir || join14(process29.cwd(), "app/Models");
19525
+ const dir = options.dir || join14(process27.cwd(), "app/Models");
19482
19526
  const format = options.format || "mermaid";
19483
19527
  try {
19484
19528
  const models = await loadModels({ modelsDir: dir });
@@ -19598,25 +19642,25 @@ var init_relation_diagram = __esm(() => {
19598
19642
  });
19599
19643
 
19600
19644
  // src/actions/seed.ts
19601
- import { existsSync as existsSync19, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
19645
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, readdirSync as readdirSync11, writeFileSync as writeFileSync13 } from "fs";
19602
19646
  import { dirname as dirname10, join as join15 } from "path";
19603
- import process30 from "process";
19604
- function findWorkspaceRoot4(startPath) {
19647
+ import process28 from "process";
19648
+ function findWorkspaceRoot3(startPath) {
19605
19649
  let currentPath = startPath;
19606
19650
  while (currentPath !== dirname10(currentPath)) {
19607
- if (existsSync19(join15(currentPath, "package.json"))) {
19651
+ if (existsSync20(join15(currentPath, "package.json"))) {
19608
19652
  return currentPath;
19609
19653
  }
19610
19654
  currentPath = dirname10(currentPath);
19611
19655
  }
19612
- return process30.cwd();
19656
+ return process28.cwd();
19613
19657
  }
19614
19658
  async function loadSeeders(seedersDir) {
19615
- if (!existsSync19(seedersDir)) {
19659
+ if (!existsSync20(seedersDir)) {
19616
19660
  console.log(`-- Seeders directory not found: ${seedersDir}`);
19617
19661
  return [];
19618
19662
  }
19619
- const files = readdirSync11(seedersDir);
19663
+ const files = readdirSync11(seedersDir).sort((a, b) => a.localeCompare(b));
19620
19664
  const seederFiles = files.filter((file2) => (file2.endsWith(".ts") || file2.endsWith(".js")) && file2 !== "index.ts" && file2 !== "index.js");
19621
19665
  const seeders = [];
19622
19666
  for (const file2 of seederFiles) {
@@ -19629,6 +19673,7 @@ async function loadSeeders(seedersDir) {
19629
19673
  if (instance && typeof instance.run === "function") {
19630
19674
  seeders.push({
19631
19675
  name: file2.replace(/\.(ts|js)$/, ""),
19676
+ className: String(SeederClass.name || ""),
19632
19677
  instance
19633
19678
  });
19634
19679
  }
@@ -19641,7 +19686,7 @@ async function loadSeeders(seedersDir) {
19641
19686
  return seeders;
19642
19687
  }
19643
19688
  async function runSeeders(config6 = {}) {
19644
- const workspaceRoot = findWorkspaceRoot4(process30.cwd());
19689
+ const workspaceRoot = findWorkspaceRoot3(process28.cwd());
19645
19690
  const seedersDir = config6.seedersDir || join15(workspaceRoot, "database/seeders");
19646
19691
  const verbose = config6.verbose ?? true;
19647
19692
  if (verbose) {
@@ -19676,17 +19721,18 @@ async function runSeeders(config6 = {}) {
19676
19721
  }
19677
19722
  }
19678
19723
  async function runSeeder(className, options = {}) {
19679
- const workspaceRoot = findWorkspaceRoot4(process30.cwd());
19724
+ const workspaceRoot = findWorkspaceRoot3(process28.cwd());
19680
19725
  const seedersDir = join15(workspaceRoot, "database/seeders");
19681
19726
  const verbose = options.verbose ?? true;
19682
19727
  if (verbose) {
19683
19728
  console.log(`-- Running seeder: ${className}`);
19684
19729
  }
19685
19730
  const seeders = await loadSeeders(seedersDir);
19686
- const seeder = seeders.find((s) => s.name === className);
19731
+ const seeder = seeders.find((s) => s.className === className) ?? seeders.find((s) => s.name === className);
19687
19732
  if (!seeder) {
19688
- console.error(`-- Seeder not found: ${className}`);
19689
- throw new Error(`Seeder not found: ${className}`);
19733
+ const known = seeders.map((s) => s.className || s.name).join(", ") || "none";
19734
+ console.error(`-- Seeder not found: ${className}. Available: ${known}`);
19735
+ throw new Error(`Seeder not found: ${className}. Available: ${known}`);
19690
19736
  }
19691
19737
  const qb = createQueryBuilder();
19692
19738
  try {
@@ -19700,9 +19746,9 @@ async function runSeeder(className, options = {}) {
19700
19746
  }
19701
19747
  }
19702
19748
  async function makeSeeder(name) {
19703
- const workspaceRoot = findWorkspaceRoot4(process30.cwd());
19749
+ const workspaceRoot = findWorkspaceRoot3(process28.cwd());
19704
19750
  const seedersDir = join15(workspaceRoot, "database/seeders");
19705
- if (!existsSync19(seedersDir)) {
19751
+ if (!existsSync20(seedersDir)) {
19706
19752
  mkdirSync9(seedersDir, { recursive: true });
19707
19753
  console.log(`-- Created seeders directory: ${seedersDir}`);
19708
19754
  }
@@ -19710,7 +19756,7 @@ async function makeSeeder(name) {
19710
19756
  const className = `${baseName}Seeder`;
19711
19757
  const fileName = `${className}.ts`;
19712
19758
  const filePath = join15(seedersDir, fileName);
19713
- if (existsSync19(filePath)) {
19759
+ if (existsSync20(filePath)) {
19714
19760
  console.error(`-- Seeder already exists: ${filePath}`);
19715
19761
  throw new Error(`Seeder already exists: ${filePath}`);
19716
19762
  }
@@ -19764,7 +19810,7 @@ export default class ${className} extends Seeder {
19764
19810
  console.log(`-- \u2713 Created seeder: ${filePath}`);
19765
19811
  }
19766
19812
  async function freshDatabase(options = {}) {
19767
- const workspaceRoot = findWorkspaceRoot4(process30.cwd());
19813
+ const workspaceRoot = findWorkspaceRoot3(process28.cwd());
19768
19814
  const modelsDir = options.modelsDir || join15(workspaceRoot, "app/Models");
19769
19815
  const seedersDir = options.seedersDir || join15(workspaceRoot, "database/seeders");
19770
19816
  const verbose = options.verbose ?? true;
@@ -19824,22 +19870,22 @@ var init_unsafe = __esm(() => {
19824
19870
  });
19825
19871
 
19826
19872
  // src/actions/validate.ts
19827
- import { existsSync as existsSync20 } from "fs";
19873
+ import { existsSync as existsSync21 } from "fs";
19828
19874
  import { dirname as dirname11, join as join16 } from "path";
19829
- import process31 from "process";
19830
- function findWorkspaceRoot5(startPath) {
19875
+ import process29 from "process";
19876
+ function findWorkspaceRoot4(startPath) {
19831
19877
  let currentPath = startPath;
19832
19878
  while (currentPath !== dirname11(currentPath)) {
19833
- if (existsSync20(join16(currentPath, "package.json"))) {
19879
+ if (existsSync21(join16(currentPath, "package.json"))) {
19834
19880
  return currentPath;
19835
19881
  }
19836
19882
  currentPath = dirname11(currentPath);
19837
19883
  }
19838
- return process31.cwd();
19884
+ return process29.cwd();
19839
19885
  }
19840
19886
  async function validateSchema(dir) {
19841
19887
  if (!dir) {
19842
- dir = join16(findWorkspaceRoot5(process31.cwd()), "app/Models");
19888
+ dir = join16(findWorkspaceRoot4(process29.cwd()), "app/Models");
19843
19889
  }
19844
19890
  const dialect = config5.dialect || "postgres";
19845
19891
  console.log("-- Validating Schema");
@@ -25090,18 +25136,11 @@ function toSnakeCase(str) {
25090
25136
  snakeCaseCache.set(str, cached);
25091
25137
  return cached;
25092
25138
  }
25093
- function toTableName(modelName) {
25139
+ function toTableName2(modelName) {
25094
25140
  let cached = tableNameCache.get(modelName);
25095
25141
  if (cached !== undefined)
25096
25142
  return cached;
25097
- const snake = toSnakeCase(modelName);
25098
- if (snake.endsWith("y") && !snake.endsWith("ay") && !snake.endsWith("ey") && !snake.endsWith("oy") && !snake.endsWith("uy")) {
25099
- cached = snake.slice(0, -1) + "ies";
25100
- } else if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("ch") || snake.endsWith("sh")) {
25101
- cached = `${snake}es`;
25102
- } else {
25103
- cached = `${snake}s`;
25104
- }
25143
+ cached = toTableName(modelName);
25105
25144
  tableNameCache.set(modelName, cached);
25106
25145
  return cached;
25107
25146
  }
@@ -25186,14 +25225,14 @@ function resolveRelation(definition, relationName) {
25186
25225
  const hasManyModel = findModelName(definition.hasMany);
25187
25226
  if (hasManyModel) {
25188
25227
  const relatedModel = getModelFromRegistry(hasManyModel);
25189
- const relatedTable = relatedModel?.getTable?.() || toTableName(hasManyModel);
25228
+ const relatedTable = relatedModel?.getTable?.() || toTableName2(hasManyModel);
25190
25229
  const foreignKey = toSnakeCase(parentName) + "_id";
25191
25230
  return { type: "hasMany", relatedModelName: hasManyModel, relatedTable, foreignKey, localKey: parentPk };
25192
25231
  }
25193
25232
  const hasOneModel = findModelName(definition.hasOne);
25194
25233
  if (hasOneModel) {
25195
25234
  const relatedModel = getModelFromRegistry(hasOneModel);
25196
- const relatedTable = relatedModel?.getTable?.() || toTableName(hasOneModel);
25235
+ const relatedTable = relatedModel?.getTable?.() || toTableName2(hasOneModel);
25197
25236
  const foreignKey = toSnakeCase(parentName) + "_id";
25198
25237
  return { type: "hasOne", relatedModelName: hasOneModel, relatedTable, foreignKey, localKey: parentPk };
25199
25238
  }
@@ -25201,7 +25240,7 @@ function resolveRelation(definition, relationName) {
25201
25240
  if (belongsToEntry) {
25202
25241
  const belongsToModel = belongsToEntry.model;
25203
25242
  const relatedModel = getModelFromRegistry(belongsToModel);
25204
- const relatedTable = relatedModel?.getTable?.() || toTableName(belongsToModel);
25243
+ const relatedTable = relatedModel?.getTable?.() || toTableName2(belongsToModel);
25205
25244
  const relatedPk = relatedModel?.getDefinition?.()?.primaryKey || "id";
25206
25245
  const foreignKey = belongsToEntry.foreignKey || `${toSnakeCase(belongsToModel)}_id`;
25207
25246
  return { type: "belongsTo", relatedModelName: belongsToModel, relatedTable, foreignKey, localKey: relatedPk };
@@ -25211,7 +25250,7 @@ function resolveRelation(definition, relationName) {
25211
25250
  const isConfig = typeof found.entry === "object";
25212
25251
  const relatedModelName = isConfig ? found.entry.model : found.entry;
25213
25252
  const relatedModel = getModelFromRegistry(relatedModelName);
25214
- const relatedTable = relatedModel?.getTable?.() || toTableName(relatedModelName);
25253
+ const relatedTable = relatedModel?.getTable?.() || toTableName2(relatedModelName);
25215
25254
  const config6 = isConfig ? found.entry : null;
25216
25255
  let pivotTable;
25217
25256
  let pivotModelName;
@@ -25223,7 +25262,7 @@ function resolveRelation(definition, relationName) {
25223
25262
  if (!throughModel) {
25224
25263
  throw new Error(`[orm] belongsToMany relation '${relationName}' on '${parentName}' references unknown through model '${config6.through}'. Make sure '${config6.through}' is registered.`);
25225
25264
  }
25226
- pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName(config6.through);
25265
+ pivotTable = throughModel.getTable?.() || throughModel.getDefinition?.()?.table || toTableName2(config6.through);
25227
25266
  } else {
25228
25267
  const a2 = singularizeWord(parentTable);
25229
25268
  const b2 = singularizeWord(relatedTable);
@@ -25274,10 +25313,10 @@ function resolveRelation(definition, relationName) {
25274
25313
  return null;
25275
25314
  const throughModel = getModelFromRegistry(throughModelName);
25276
25315
  const throughDef = throughModel?.getDefinition?.() || throughModel?.definition;
25277
- const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName(throughModelName);
25316
+ const throughTable = throughModel?.getTable?.() || throughDef?.table || toTableName2(throughModelName);
25278
25317
  const throughPk = throughDef?.primaryKey || "id";
25279
25318
  const targetModel = getModelFromRegistry(targetModelName);
25280
- const targetTable = targetModel?.getTable?.() || toTableName(targetModelName);
25319
+ const targetTable = targetModel?.getTable?.() || toTableName2(targetModelName);
25281
25320
  return {
25282
25321
  type,
25283
25322
  relatedModelName: targetModelName,
@@ -27874,7 +27913,7 @@ function buildDatabaseSchema(models) {
27874
27913
  for (const modelName of Object.keys(models)) {
27875
27914
  const rawModel = models[modelName];
27876
27915
  const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
27877
- const table = m2.table || `${String(m2.name).toLowerCase()}s`;
27916
+ const table = tableNameFor(m2);
27878
27917
  const attrs = m2.attributes ?? {};
27879
27918
  const columns = {};
27880
27919
  for (const key of Object.keys(attrs))
@@ -27886,30 +27925,53 @@ function buildDatabaseSchema(models) {
27886
27925
  }
27887
27926
  return schema;
27888
27927
  }
27928
+ var init_factory = () => {};
27889
27929
 
27890
27930
  // src/loader.ts
27891
- import { readdirSync as readdirSync12, statSync as statSync5 } from "fs";
27892
- import { basename, extname as extname4 } from "path";
27893
- import process33 from "process";
27894
- async function loadModels(options) {
27895
- const cwd = options.cwd ?? process33.cwd();
27896
- const dir = options.modelsDir.startsWith("/") ? options.modelsDir : `${cwd}/${options.modelsDir}`;
27897
- const result = {};
27898
- const entries = readdirSync12(dir);
27931
+ import { readdirSync as readdirSync12 } from "fs";
27932
+ import { basename, extname as extname4, isAbsolute as isAbsolute3, join as join17 } from "path";
27933
+ import process30 from "process";
27934
+ function isModelFile(name) {
27935
+ const ext = extname4(name);
27936
+ if (!MODEL_EXTENSIONS.has(ext))
27937
+ return false;
27938
+ const base = basename(name, ext);
27939
+ if (base.startsWith("_") || base === "index")
27940
+ return false;
27941
+ return !base.endsWith(".d");
27942
+ }
27943
+ function isModelDefinition(def) {
27944
+ if (!def || typeof def !== "object")
27945
+ return false;
27946
+ const d2 = def;
27947
+ return typeof d2.name === "string" || typeof d2.table === "string";
27948
+ }
27949
+ function collectModelFiles(dir) {
27950
+ const files = [];
27951
+ const entries = readdirSync12(dir, { withFileTypes: true }).sort((a2, b2) => a2.name.localeCompare(b2.name));
27899
27952
  for (const entry of entries) {
27900
- const full = `${dir}/${entry}`;
27901
- const st = statSync5(full);
27902
- if (st.isDirectory())
27903
- continue;
27904
- const ext = extname4(full);
27905
- if (![".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"].includes(ext))
27953
+ const full = join17(dir, entry.name);
27954
+ if (entry.isDirectory()) {
27955
+ files.push(...collectModelFiles(full));
27906
27956
  continue;
27957
+ }
27958
+ if (isModelFile(entry.name))
27959
+ files.push(full);
27960
+ }
27961
+ return files;
27962
+ }
27963
+ async function loadModels(options) {
27964
+ const cwd = options.cwd ?? process30.cwd();
27965
+ const dir = isAbsolute3(options.modelsDir) ? options.modelsDir : join17(cwd, options.modelsDir);
27966
+ const result = {};
27967
+ for (const full of collectModelFiles(dir)) {
27907
27968
  const cacheBuster = `?t=${Date.now()}-${Math.random().toString(36).slice(2)}`;
27908
27969
  const mod = await import(`${full}${cacheBuster}`);
27909
27970
  const rawDef = mod.default ?? mod;
27910
27971
  const def = rawDef.definition ?? rawDef.getDefinition?.() ?? rawDef;
27911
- const fileName = basename(entry, ext);
27912
- const name = def.name ?? fileName;
27972
+ if (!isModelDefinition(def))
27973
+ continue;
27974
+ const name = def.name ?? basename(full, extname4(full));
27913
27975
  result[name] = {
27914
27976
  ...def,
27915
27977
  name
@@ -27917,7 +27979,10 @@ async function loadModels(options) {
27917
27979
  }
27918
27980
  return result;
27919
27981
  }
27920
- var init_loader = () => {};
27982
+ var MODEL_EXTENSIONS;
27983
+ var init_loader = __esm(() => {
27984
+ MODEL_EXTENSIONS = new Set([".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"]);
27985
+ });
27921
27986
 
27922
27987
  // src/meta.ts
27923
27988
  function buildSchemaMeta(models) {
@@ -27929,7 +27994,7 @@ function buildSchemaMeta(models) {
27929
27994
  for (const name of Object.keys(models)) {
27930
27995
  const rawModel = models[name];
27931
27996
  const m2 = rawModel.definition ?? rawModel.getDefinition?.() ?? rawModel;
27932
- const table = m2.table || `${String(m2.name).toLowerCase()}s`;
27997
+ const table = tableNameFor(m2);
27933
27998
  modelToTable[name] = table;
27934
27999
  tableToModel[table] = name;
27935
28000
  primaryKeys[table] = m2.primaryKey ?? "id";
@@ -28003,9 +28068,9 @@ function buildSchemaMeta(models) {
28003
28068
  var init_meta = () => {};
28004
28069
 
28005
28070
  // src/migrations.ts
28006
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync14 } from "fs";
28007
- import { dirname as dirname12, join as join17 } from "path";
28008
- import process35 from "process";
28071
+ import { existsSync as existsSync23, mkdirSync as mkdirSync10, readdirSync as readdirSync13, readFileSync as readFileSync6, writeFileSync as writeFileSync14 } from "fs";
28072
+ import { dirname as dirname12, join as join18 } from "path";
28073
+ import process31 from "process";
28009
28074
  function info2(message) {
28010
28075
  if (config5.verbose)
28011
28076
  console.log(message);
@@ -28016,36 +28081,80 @@ function snakeCase(str) {
28016
28081
  function singularizeTable(table) {
28017
28082
  return singularizerFor(config5.relations?.singularizeStrategy)(table);
28018
28083
  }
28019
- function findWorkspaceRoot6(startPath) {
28084
+ function lastCreatedMigrationFiles() {
28085
+ return [...createdMigrationFiles];
28086
+ }
28087
+ function findWorkspaceRoot5(startPath) {
28020
28088
  let currentPath = startPath;
28021
28089
  while (currentPath !== dirname12(currentPath)) {
28022
- if (existsSync21(join17(currentPath, "package.json"))) {
28090
+ if (existsSync23(join18(currentPath, "package.json"))) {
28023
28091
  return currentPath;
28024
28092
  }
28025
28093
  currentPath = dirname12(currentPath);
28026
28094
  }
28027
- return process35.cwd();
28095
+ return process31.cwd();
28028
28096
  }
28029
28097
  function ensureSqlDirectory2() {
28030
- const workspaceRoot = findWorkspaceRoot6(process35.cwd());
28031
- const sqlDir = join17(workspaceRoot, "database", "migrations");
28032
- if (!existsSync21(sqlDir)) {
28098
+ const workspaceRoot = findWorkspaceRoot5(process31.cwd());
28099
+ const sqlDir = join18(workspaceRoot, "database", "migrations");
28100
+ if (!existsSync23(sqlDir)) {
28033
28101
  mkdirSync10(sqlDir, { recursive: true });
28034
28102
  info2(`-- Created SQL directory: ${sqlDir}`);
28035
28103
  }
28036
28104
  return sqlDir;
28037
28105
  }
28106
+ function isGeneratedMigrationSql(sql2) {
28107
+ return sql2.trimStart().startsWith(GENERATED_MARKER);
28108
+ }
28109
+ function migrationBody(sql2) {
28110
+ return sql2.split(`
28111
+ `).filter((line) => !line.trimStart().startsWith("--")).join(`
28112
+ `).replace(/\s+/g, " ").trim().replace(/;+$/, "");
28113
+ }
28114
+ function existingMigrationBodies(sqlDir) {
28115
+ const bodies = new Set;
28116
+ let files;
28117
+ try {
28118
+ files = readdirSync13(sqlDir).filter((f2) => f2.endsWith(".sql"));
28119
+ } catch {
28120
+ return bodies;
28121
+ }
28122
+ for (const file2 of files) {
28123
+ try {
28124
+ bodies.add(migrationBody(readFileSync6(join18(sqlDir, file2), "utf8")));
28125
+ } catch {}
28126
+ }
28127
+ return bodies;
28128
+ }
28038
28129
  function createMigrationFile(statement, fileName) {
28039
28130
  if (!statement)
28040
28131
  return false;
28041
28132
  const sqlDir = ensureSqlDirectory2();
28133
+ if (existingCorpusBodies === null)
28134
+ existingCorpusBodies = existingMigrationBodies(sqlDir);
28135
+ const body = migrationBody(statement);
28136
+ if (body.length > 0 && existingCorpusBodies.has(body)) {
28137
+ info2(`-- Migration already in the corpus, not writing it again: ${fileName}`);
28138
+ return false;
28139
+ }
28042
28140
  migrationCounter++;
28043
- const sequence = useDeterministicNames ? String(migrationCounter).padStart(10, "0") : String(Math.floor(Date.now() / 1000) + migrationCounter);
28044
- const fullFileName = `${sequence}-${fileName}.sql`;
28045
- const filePath = join17(sqlDir, fullFileName);
28046
- writeFileSync14(filePath, statement);
28141
+ let sequence = useDeterministicNames ? String(migrationCounter).padStart(10, "0") : String(Math.floor(Date.now() / 1000) + migrationCounter);
28142
+ let fullFileName = `${sequence}-${fileName}.sql`;
28143
+ if (!useDeterministicNames) {
28144
+ let next = Number(sequence);
28145
+ while (existsSync23(join18(sqlDir, fullFileName))) {
28146
+ next += 1;
28147
+ sequence = String(next);
28148
+ fullFileName = `${sequence}-${fileName}.sql`;
28149
+ }
28150
+ }
28151
+ const filePath = join18(sqlDir, fullFileName);
28152
+ writeFileSync14(filePath, `${GENERATED_MARKER}
28153
+ ${statement}`);
28047
28154
  info2(`-- Migration file created: ${fullFileName}`);
28048
28155
  migrationsCreatedCount++;
28156
+ createdMigrationFiles.push(fullFileName);
28157
+ existingCorpusBodies?.add(body);
28049
28158
  return true;
28050
28159
  }
28051
28160
  function guessTypeFromName(columnName) {
@@ -28220,7 +28329,7 @@ function buildMigrationPlan2(models, options) {
28220
28329
  const tables = [];
28221
28330
  for (const modelName of Object.keys(models)) {
28222
28331
  const model = models[modelName];
28223
- const table = model.table || `${String(model.name).toLowerCase()}s`;
28332
+ const table = tableNameFor(model);
28224
28333
  const primaryKey = model.primaryKey ?? "id";
28225
28334
  const _autoIncrement = model.autoIncrement !== false;
28226
28335
  const attrs = model.attributes ?? {};
@@ -28312,9 +28421,7 @@ function buildMigrationPlan2(models, options) {
28312
28421
  if (columns.some((c2) => c2.name === fkColumnName))
28313
28422
  continue;
28314
28423
  const refTable = meta.modelToTable[rel.model];
28315
- if (!refTable)
28316
- continue;
28317
- const refPk = meta.primaryKeys[refTable] ?? "id";
28424
+ const refPk = refTable ? meta.primaryKeys[refTable] ?? "id" : undefined;
28318
28425
  columns.push({
28319
28426
  name: fkColumnName,
28320
28427
  type: "bigint",
@@ -28322,7 +28429,7 @@ function buildMigrationPlan2(models, options) {
28322
28429
  isUnique: false,
28323
28430
  isNullable: true,
28324
28431
  hasDefault: false,
28325
- references: { table: refTable, column: refPk, onDelete: rel.onDelete }
28432
+ references: refTable && refPk ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
28326
28433
  });
28327
28434
  }
28328
28435
  const traits = model.traits;
@@ -28403,7 +28510,7 @@ function buildMigrationPlan2(models, options) {
28403
28510
  for (const modelName of Object.keys(models)) {
28404
28511
  const model = models[modelName];
28405
28512
  const traits = model?.traits ?? {};
28406
- const modelTable = model.table || `${String(model.name).toLowerCase()}s`;
28513
+ const modelTable = tableNameFor(model);
28407
28514
  const singular = singularizeTable(modelTable);
28408
28515
  if (traits.likeable) {
28409
28516
  const opts = typeof traits.likeable === "object" ? traits.likeable : {};
@@ -28470,7 +28577,7 @@ function buildMigrationPlan2(models, options) {
28470
28577
  const btm = model?.belongsToMany;
28471
28578
  if (!btm || typeof btm !== "object" || Array.isArray(btm))
28472
28579
  continue;
28473
- const parentTable = model.table || `${String(model.name).toLowerCase()}s`;
28580
+ const parentTable = tableNameFor(model);
28474
28581
  const parentSingular = singularizeTable(parentTable);
28475
28582
  for (const [relKey, value] of Object.entries(btm)) {
28476
28583
  const cfg = value;
@@ -28531,6 +28638,8 @@ function generateSql(plan, opts = {}) {
28531
28638
  migrationCounter = 0;
28532
28639
  migrationsCreatedCount = 0;
28533
28640
  migrationsUpdatedCount = 0;
28641
+ createdMigrationFiles = [];
28642
+ existingCorpusBodies = null;
28534
28643
  useDeterministicNames = true;
28535
28644
  const emit = opts.dryRun ? () => false : createMigrationFile;
28536
28645
  const statements = [];
@@ -28792,12 +28901,13 @@ function referencesAreDifferent(r1, r2) {
28792
28901
  const act = (a2) => (a2 ?? "no action").toLowerCase();
28793
28902
  return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
28794
28903
  }
28904
+ function indexKey(index) {
28905
+ return `${index.type}:${index.name}:${index.columns.join(",")}`;
28906
+ }
28795
28907
  function mapIndexesByKey(indexes) {
28796
28908
  const map = {};
28797
- for (const i2 of indexes) {
28798
- const key = `${i2.type}:${i2.name}:${i2.columns.join(",")}`;
28799
- map[key] = i2;
28800
- }
28909
+ for (const i2 of indexes)
28910
+ map[indexKey(i2)] = i2;
28801
28911
  return map;
28802
28912
  }
28803
28913
  function generateDiffOperations(previous, next, opts = {}) {
@@ -28812,10 +28922,13 @@ function generateDiffOperations(previous, next, opts = {}) {
28812
28922
  return { statements: statements2, operations: operations2 };
28813
28923
  }
28814
28924
  const applyRenames = opts.applyRenames !== false;
28925
+ const preserveUnknownColumns = opts.preserveUnknownColumns === true;
28815
28926
  const emit = opts.dryRun ? () => false : createMigrationFile;
28816
28927
  migrationCounter = 0;
28817
28928
  migrationsCreatedCount = 0;
28818
28929
  migrationsUpdatedCount = 0;
28930
+ createdMigrationFiles = [];
28931
+ existingCorpusBodies = null;
28819
28932
  useDeterministicNames = false;
28820
28933
  const chunks = [];
28821
28934
  const operations = [];
@@ -28914,22 +29027,32 @@ function generateDiffOperations(previous, next, opts = {}) {
28914
29027
  }
28915
29028
  for (const tableName of Object.keys(nextTables)) {
28916
29029
  const prev = prevTables[tableName];
28917
- const curr = nextTables[tableName];
29030
+ let curr = nextTables[tableName];
28918
29031
  if (!prev)
28919
29032
  continue;
28920
29033
  const prevCols = mapColumnsByName(prev.columns);
28921
- const currCols = mapColumnsByName(curr.columns);
28922
29034
  const prevIdx = mapIndexesByKey(prev.indexes);
28923
- const currIdx = mapIndexesByKey(curr.indexes);
29035
+ let currCols = mapColumnsByName(curr.columns);
29036
+ let currIdx = mapIndexesByKey(curr.indexes);
28924
29037
  let renames = [];
28925
29038
  let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
28926
29039
  let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
28927
- if (applyRenames) {
29040
+ if (applyRenames && !preserveUnknownColumns) {
28928
29041
  const detected = detectColumnRenames(prevCols, currCols, dialect);
28929
29042
  renames = detected.renames;
28930
29043
  removedCols = detected.removed;
28931
29044
  addedCols = detected.added;
28932
29045
  }
29046
+ if (preserveUnknownColumns && removedCols.length > 0) {
29047
+ const preserved = removedCols.map((name) => prevCols[name]);
29048
+ const preservedNames = new Set(removedCols);
29049
+ const keptIndexes = prev.indexes.filter((idx) => idx.columns.some((c2) => preservedNames.has(c2)) && !currIdx[indexKey(idx)]);
29050
+ info2(`-- Keeping ${preserved.length} column(s) on "${curr.table}" no model declares: ${removedCols.join(", ")} \u2014 reconciled from the database, where an undeclared column is out of scope rather than removed`);
29051
+ curr = { ...curr, columns: [...curr.columns, ...preserved], indexes: [...curr.indexes, ...keptIndexes] };
29052
+ currCols = mapColumnsByName(curr.columns);
29053
+ currIdx = mapIndexesByKey(curr.indexes);
29054
+ removedCols = [];
29055
+ }
28933
29056
  const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
28934
29057
  const fkChangedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && referencesAreDifferent(prevCols[n2].references, currCols[n2].references));
28935
29058
  if (dialect === "sqlite") {
@@ -29077,11 +29200,12 @@ function generateDiffOperations(previous, next, opts = {}) {
29077
29200
  function generateDiffSql(previous, next, opts = {}) {
29078
29201
  return generateDiffOperations(previous, next, opts).statements;
29079
29202
  }
29080
- var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true;
29203
+ var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0, useDeterministicNames = true, createdMigrationFiles, existingCorpusBodies = null, GENERATED_MARKER = "-- qb:generated";
29081
29204
  var init_migrations = __esm(() => {
29082
29205
  init_config();
29083
29206
  init_drivers();
29084
29207
  init_meta();
29208
+ createdMigrationFiles = [];
29085
29209
  });
29086
29210
 
29087
29211
  // src/schema.ts
@@ -29115,6 +29239,7 @@ var init_src2 = __esm(() => {
29115
29239
  init_dynamodb_single_table();
29116
29240
  init_dynamodb_tooling_adapter();
29117
29241
  init_dynamodb();
29242
+ init_factory();
29118
29243
  init_loader();
29119
29244
  init_meta();
29120
29245
  init_migrations();
@@ -29130,9 +29255,11 @@ export {
29130
29255
  validateSchema,
29131
29256
  unsafe,
29132
29257
  unmarshallItem,
29258
+ toTableName,
29133
29259
  toModelInstance,
29134
29260
  toDynamoDBItem,
29135
29261
  tinker,
29262
+ tableNameFor,
29136
29263
  tableInfo,
29137
29264
  stripTrailingS,
29138
29265
  startConsole,
@@ -29151,6 +29278,7 @@ export {
29151
29278
  resolveSqlitePragmas,
29152
29279
  resolvePivot,
29153
29280
  resolveKeyPattern,
29281
+ resolveDialect,
29154
29282
  resetDatabase,
29155
29283
  resetConnection,
29156
29284
  relationDiagram,
@@ -29163,6 +29291,7 @@ export {
29163
29291
  dbOptimize as optimizeDatabase,
29164
29292
  modelShow,
29165
29293
  modelNameForTable,
29294
+ migrationBody,
29166
29295
  migrateStatus,
29167
29296
  migrateRollback,
29168
29297
  migrateModels,
@@ -29172,8 +29301,10 @@ export {
29172
29301
  makeSeeder,
29173
29302
  makeModel,
29174
29303
  loadModels,
29304
+ lastCreatedMigrationFiles,
29175
29305
  iterateAllPivots,
29176
29306
  isMysqlLike,
29307
+ isGeneratedMigrationSql,
29177
29308
  isDefinitionEqual,
29178
29309
  isBrowser,
29179
29310
  introspectDatabase,
@@ -29268,6 +29399,7 @@ export {
29268
29399
  MySQLDriver,
29269
29400
  Model,
29270
29401
  MIGRATIONS_TABLE,
29402
+ GENERATED_MARKER,
29271
29403
  EntityQueryBuilder,
29272
29404
  DynamoDBToolingAdapter,
29273
29405
  DynamoDBQueryBuilder,