bun-query-builder 0.2.0 → 0.2.2

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.
@@ -13,6 +13,15 @@ export declare function generateModelSource(table: string, columns: Introspected
13
13
  export declare function introspectDatabase(opts?: { tables?: string[] }): Promise<IntrospectedModel[]>;
14
14
  /** Map a raw SQL column type back to a normalized model column type. */
15
15
  export declare function sqlTypeToNormalized(rawType: string, dialect: SupportedDialect, ctx?: { enumValues?: string[] }): NormalizedColumnType;
16
+ /**
17
+ * The plan type for one Postgres column, given what the catalogue knows.
18
+ *
19
+ * Separated from the query so the enum case can be tested without a live
20
+ * database: `USER-DEFINED` is the whole of what `information_schema` says about
21
+ * an enum column, and getting this wrong is invisible until a diff proposes a
22
+ * type change for a column nobody touched.
23
+ */
24
+ export declare function pgColumnType(dataType: string, udtName: string, enums: Map<string, string[]>): { type: NormalizedColumnType, enumValues?: string[], enumTypeName?: string };
16
25
  /**
17
26
  * Read the live database into a full `MigrationPlan`. Tables are read in the
18
27
  * dialect-native way (PRAGMA / information_schema / pg_catalog). The internal
package/dist/bin/cli.js CHANGED
@@ -12508,6 +12508,24 @@ var init_pivot = __esm(() => {
12508
12508
  function isRawExpression(expr) {
12509
12509
  return typeof expr === "object" && expr !== null && "raw" in expr && typeof expr.raw === "string";
12510
12510
  }
12511
+ function isBoundSqlExpression(expr) {
12512
+ return typeof expr === "object" && expr !== null && "sql" in expr && typeof expr.sql === "string" && (!("parameters" in expr) || Array.isArray(expr.parameters));
12513
+ }
12514
+ function renderBoundSqlExpression(expression, startIndex) {
12515
+ const parameters = expression.parameters ?? [];
12516
+ if (config5.dialect !== "postgres" || parameters.length === 0)
12517
+ return { text: expression.sql, parameters };
12518
+ let parameterIndex = 0;
12519
+ const text = expression.sql.replace(/\?/g, (placeholder) => {
12520
+ if (parameterIndex >= parameters.length)
12521
+ return placeholder;
12522
+ return getPlaceholder(startIndex + parameterIndex++);
12523
+ });
12524
+ if (parameterIndex !== parameters.length) {
12525
+ throw new TypeError(`[query-builder] SQL expression declares ${parameters.length} parameters but contains only ${parameterIndex} placeholders`);
12526
+ }
12527
+ return { text, parameters };
12528
+ }
12511
12529
  function raw(strings, ...values) {
12512
12530
  if (typeof strings === "string")
12513
12531
  return { raw: strings };
@@ -12981,6 +12999,31 @@ function createQueryBuilder(state) {
12981
12999
  throw err;
12982
13000
  });
12983
13001
  }
13002
+ function mutationCount(result) {
13003
+ if (typeof result === "number")
13004
+ return Number.isFinite(result) ? result : 0;
13005
+ if (typeof result === "bigint")
13006
+ return Number(result);
13007
+ if (!result || typeof result !== "object")
13008
+ return 0;
13009
+ const record = result;
13010
+ for (const key of [
13011
+ "changes",
13012
+ "affectedRows",
13013
+ "count",
13014
+ "rowCount",
13015
+ "numAffectedRows",
13016
+ "numUpdatedRows",
13017
+ "numDeletedRows",
13018
+ "numInsertedOrUpdatedRows"
13019
+ ]) {
13020
+ if (record[key] !== undefined && record[key] !== null)
13021
+ return mutationCount(record[key]);
13022
+ }
13023
+ if (Array.isArray(result))
13024
+ return result.reduce((total, item) => total + mutationCount(item), 0);
13025
+ return 0;
13026
+ }
12984
13027
  function makeExecutableQuery(q, text) {
12985
13028
  const sqlText = text ?? computeSqlText(q);
12986
13029
  return {
@@ -14076,7 +14119,16 @@ function createQueryBuilder(state) {
14076
14119
  built = null;
14077
14120
  return this;
14078
14121
  }
14079
- return this;
14122
+ if (typeof expr === "function") {
14123
+ throw new TypeError("where(callback) is not supported. This builder has no expression callback, and " + "ignoring one silently would leave the query matching every row the filter was " + "meant to exclude. Use whereNested(subquery), whereAny(...), or the orWhere* " + "helpers to build a grouped condition.");
14124
+ }
14125
+ if (expr === undefined || expr === null) {
14126
+ throw new TypeError("where() was called with no condition.");
14127
+ }
14128
+ if (typeof expr === "string") {
14129
+ throw new TypeError(`where(${JSON.stringify(expr)}) is missing an operator and a value. Pass ` + "where(column, operator, value), or whereRaw() for a raw fragment.");
14130
+ }
14131
+ throw new TypeError(`where() does not understand a condition of type ${typeof expr}.`);
14080
14132
  },
14081
14133
  whereNull(column) {
14082
14134
  validateIdentifier(String(column), "whereNull(column)");
@@ -15681,8 +15733,17 @@ function createQueryBuilder(state) {
15681
15733
  const setClauses = Array.from({ length: len });
15682
15734
  for (let i = 0;i < len; i++) {
15683
15735
  const key = keys[i];
15684
- setClauses[i] = `${quoteId(key)} = ${getPlaceholder(i + 1)}`;
15685
- params.push(values[key]);
15736
+ const value = values[key];
15737
+ if (isRawExpression(value)) {
15738
+ setClauses[i] = `${quoteId(key)} = ${value.raw}`;
15739
+ } else if (isBoundSqlExpression(value)) {
15740
+ const expression = renderBoundSqlExpression(value, params.length + 1);
15741
+ setClauses[i] = `${quoteId(key)} = ${expression.text}`;
15742
+ params.push(...expression.parameters);
15743
+ } else {
15744
+ setClauses[i] = `${quoteId(key)} = ${getPlaceholder(params.length + 1)}`;
15745
+ params.push(value);
15746
+ }
15686
15747
  }
15687
15748
  sqlText = `${sqlText} SET ${setClauses.join(", ")}`;
15688
15749
  built = _sql.unsafe(sqlText, params);
@@ -15690,17 +15751,29 @@ function createQueryBuilder(state) {
15690
15751
  },
15691
15752
  where(expr, op, value) {
15692
15753
  const getWhereKeyword = () => SQL_PATTERNS.WHERE.test(sqlText) ? "AND" : "WHERE";
15693
- if (typeof expr === "string" && op !== undefined) {
15754
+ if (op !== undefined && (typeof expr === "string" || isRawExpression(expr) || isBoundSqlExpression(expr))) {
15755
+ const safeOperator = assertSafeWhereOperator(op, "updateTable.where");
15756
+ let left;
15757
+ if (typeof expr === "string") {
15758
+ left = quoteId(expr);
15759
+ } else if (isRawExpression(expr)) {
15760
+ left = expr.raw;
15761
+ } else {
15762
+ const expression = renderBoundSqlExpression(expr, params.length + 1);
15763
+ left = expression.text;
15764
+ params.push(...expression.parameters);
15765
+ }
15694
15766
  const paramIndex = params.length + 1;
15695
- sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(expr)} ${op} ${getPlaceholder(paramIndex)}`;
15767
+ sqlText = `${sqlText} ${getWhereKeyword()} ${left} ${safeOperator} ${getPlaceholder(paramIndex)}`;
15696
15768
  params.push(value);
15697
15769
  built = _sql.unsafe(sqlText, params);
15698
15770
  return this;
15699
15771
  }
15700
15772
  if (Array.isArray(expr)) {
15701
15773
  const [col, op2, val] = expr;
15774
+ const safeOperator = assertSafeWhereOperator(op2, "updateTable.where");
15702
15775
  const paramIndex = params.length + 1;
15703
- sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${String(op2)} ${getPlaceholder(paramIndex)}`;
15776
+ sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${safeOperator} ${getPlaceholder(paramIndex)}`;
15704
15777
  params.push(val);
15705
15778
  built = _sql.unsafe(sqlText, params);
15706
15779
  return this;
@@ -15759,15 +15832,16 @@ function createQueryBuilder(state) {
15759
15832
  }
15760
15833
  return makeExecutableQuery(built, sqlText);
15761
15834
  },
15762
- execute() {
15763
- return runWithHooks(built, "update");
15835
+ async execute() {
15836
+ const result = await runWithHooks(built, "update");
15837
+ return mutationCount(result);
15764
15838
  },
15765
15839
  async executeTakeFirst() {
15766
- const result = await runWithHooks(built, "update");
15840
+ const result = mutationCount(await runWithHooks(built, "update"));
15767
15841
  return { numUpdatedRows: result };
15768
15842
  },
15769
15843
  async executeTakeFirstOrThrow() {
15770
- const result = await runWithHooks(built, "update");
15844
+ const result = mutationCount(await runWithHooks(built, "update"));
15771
15845
  if (result === 0)
15772
15846
  throw new Error("No rows updated");
15773
15847
  return { numUpdatedRows: result };
@@ -15888,18 +15962,18 @@ function createQueryBuilder(state) {
15888
15962
  } catch (err) {
15889
15963
  throw err;
15890
15964
  }
15891
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15965
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15892
15966
  try {
15893
15967
  await config5.hooks?.afterDelete?.({ table: String(table), where: whereCondition, result });
15894
15968
  } catch {}
15895
15969
  return result;
15896
15970
  },
15897
15971
  async executeTakeFirst() {
15898
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15972
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15899
15973
  return { numDeletedRows: result };
15900
15974
  },
15901
15975
  async executeTakeFirstOrThrow() {
15902
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15976
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15903
15977
  if (result === 0)
15904
15978
  throw new Error("No rows deleted");
15905
15979
  return { numDeletedRows: result };
@@ -17682,10 +17756,6 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
17682
17756
  return "enum";
17683
17757
  return "string";
17684
17758
  }
17685
- function stripIndexPrefix(physicalName, table) {
17686
- const prefix = `${table}_`;
17687
- return physicalName.startsWith(prefix) ? physicalName.slice(prefix.length) : physicalName;
17688
- }
17689
17759
  function asAction(raw2) {
17690
17760
  const v = String(raw2 ?? "").toLowerCase().trim();
17691
17761
  if (v === "cascade" || v === "restrict" || v === "set null")
@@ -17721,7 +17791,7 @@ async function buildSqliteTable(qb, table) {
17721
17791
  const isUnique = Number(idx.unique) === 1;
17722
17792
  if (isUnique && columns2.length === 1)
17723
17793
  uniqueColumns.add(columns2[0]);
17724
- indexes.push({ name: stripIndexPrefix(physName, table), columns: columns2, type: isUnique ? "unique" : "index" });
17794
+ indexes.push({ name: physName, columns: columns2, type: isUnique ? "unique" : "index" });
17725
17795
  }
17726
17796
  const columns = colRows.map((r) => {
17727
17797
  const name = String(r.name);
@@ -17758,7 +17828,31 @@ function normalizeRawDefault(raw2) {
17758
17828
  return raw2;
17759
17829
  return String(raw2);
17760
17830
  }
17761
- async function buildPgTable(qb, table) {
17831
+ async function pgEnumLabels(qb) {
17832
+ const rows = await qb.unsafe(`SELECT t.typname AS type_name, e.enumlabel AS label
17833
+ FROM pg_type t
17834
+ JOIN pg_enum e ON e.enumtypid = t.oid
17835
+ JOIN pg_namespace n ON n.oid = t.typnamespace
17836
+ WHERE n.nspname = 'public'
17837
+ ORDER BY t.typname, e.enumsortorder`);
17838
+ const labels = new Map;
17839
+ for (const row of rows) {
17840
+ const name = String(row.type_name);
17841
+ const existing = labels.get(name);
17842
+ if (existing)
17843
+ existing.push(String(row.label));
17844
+ else
17845
+ labels.set(name, [String(row.label)]);
17846
+ }
17847
+ return labels;
17848
+ }
17849
+ function pgColumnType(dataType, udtName, enums) {
17850
+ const enumValues = enums.get(udtName);
17851
+ const type = sqlTypeToNormalized(String(dataType || udtName || ""), "postgres", { enumValues });
17852
+ return enumValues ? { type, enumValues, enumTypeName: udtName } : { type };
17853
+ }
17854
+ async function buildPgTable(qb, table, enumLabels) {
17855
+ const enums = enumLabels ?? await pgEnumLabels(qb);
17762
17856
  const colRows = await qb.unsafe(`SELECT c.column_name, c.data_type, c.udt_name, c.is_nullable, c.column_default, c.character_maximum_length,
17763
17857
  (SELECT COUNT(*) FROM information_schema.table_constraints tc
17764
17858
  JOIN information_schema.key_column_usage k ON k.constraint_name = tc.constraint_name
@@ -17806,7 +17900,7 @@ async function buildPgTable(qb, table) {
17806
17900
  const hasDefault = rawDefault != null && !isSerial;
17807
17901
  return {
17808
17902
  name,
17809
- type: sqlTypeToNormalized(String(r.data_type ?? r.udt_name ?? ""), "postgres"),
17903
+ ...pgColumnType(String(r.data_type ?? ""), r.udt_name == null ? "" : String(r.udt_name), enums),
17810
17904
  isPrimaryKey,
17811
17905
  isUnique: uniqueColumns.has(name),
17812
17906
  isNullable: isPrimaryKey ? false : String(r.is_nullable).toUpperCase() === "YES",
@@ -17892,7 +17986,7 @@ function groupPhysicalIndexes(table, rows) {
17892
17986
  if (entry.isUnique && entry.columns.length === 1)
17893
17987
  uniqueColumns.add(entry.columns[0]);
17894
17988
  indexes.push({
17895
- name: stripIndexPrefix(physName, table),
17989
+ name: physName,
17896
17990
  columns: entry.columns,
17897
17991
  type: entry.isUnique ? "unique" : "index",
17898
17992
  where: entry.where
@@ -17905,13 +17999,14 @@ async function buildPlanFromDatabase(dialect, opts = {}) {
17905
17999
  const qb = createQueryBuilder();
17906
18000
  const allTables = opts.tables?.length ? opts.tables : await listTables(qb, d);
17907
18001
  const tables = allTables.filter((t) => t !== "migrations");
18002
+ const enumLabels = d === "postgres" ? await pgEnumLabels(qb) : undefined;
17908
18003
  const out = [];
17909
18004
  for (const table of tables) {
17910
18005
  let plan;
17911
18006
  if (d === "sqlite")
17912
18007
  plan = await buildSqliteTable(qb, table);
17913
18008
  else if (d === "postgres")
17914
- plan = await buildPgTable(qb, table);
18009
+ plan = await buildPgTable(qb, table, enumLabels);
17915
18010
  else
17916
18011
  plan = await buildMysqlTable(qb, table);
17917
18012
  if (plan.columns.length > 0)
@@ -17982,6 +18077,12 @@ export default model
17982
18077
  }
17983
18078
  var init_make_model = () => {};
17984
18079
 
18080
+ // src/drivers/index-name.ts
18081
+ function qualifiedIndexName(tableName, indexName) {
18082
+ const prefix = `${tableName}_`;
18083
+ return indexName.startsWith(prefix) ? indexName : `${prefix}${indexName}`;
18084
+ }
18085
+
17985
18086
  // src/drivers/mysql.ts
17986
18087
  class MySQLDriver {
17987
18088
  quoteIdentifier(id) {
@@ -18068,7 +18169,7 @@ class MySQLDriver {
18068
18169
  throw new Error(`[migrations] Partial indexes (CompositeIndex.where) are not supported on MySQL. Index '${index.name}' on table '${tableName}' uses WHERE clause: ${index.where}`);
18069
18170
  }
18070
18171
  const kind = index.type === "unique" ? "UNIQUE " : "";
18071
- const idxName = `${tableName}_${index.name}`;
18172
+ const idxName = qualifiedIndexName(tableName, index.name);
18072
18173
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18073
18174
  return `CREATE ${kind}INDEX ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns});`;
18074
18175
  }
@@ -18121,7 +18222,7 @@ class MySQLDriver {
18121
18222
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18122
18223
  }
18123
18224
  dropIndex(tableName, indexName) {
18124
- const fullIndexName = `${tableName}_${indexName}`;
18225
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18125
18226
  return `DROP INDEX ${this.quoteIdentifier(fullIndexName)} ON ${this.quoteIdentifier(tableName)};`;
18126
18227
  }
18127
18228
  dropEnumType(_enumTypeName) {
@@ -18168,6 +18269,7 @@ class MySQLDriver {
18168
18269
  return parts.join(" ");
18169
18270
  }
18170
18271
  }
18272
+ var init_mysql = () => {};
18171
18273
 
18172
18274
  // src/drivers/postgres.ts
18173
18275
  class PostgresDriver {
@@ -18202,7 +18304,7 @@ class PostgresDriver {
18202
18304
  return "jsonb";
18203
18305
  case "enum":
18204
18306
  if (column.enumValues && column.enumValues.length > 0) {
18205
- return this.quoteIdentifier(column.enumTypeName ?? `${column.name}_type`);
18307
+ return column.enumTypeName ? this.quoteIdentifier(column.enumTypeName) : "text";
18206
18308
  }
18207
18309
  return "text";
18208
18310
  default:
@@ -18256,7 +18358,7 @@ class PostgresDriver {
18256
18358
  }
18257
18359
  createIndex(tableName, index) {
18258
18360
  const kind = index.type === "unique" ? "UNIQUE " : "";
18259
- const idxName = `${tableName}_${index.name}`;
18361
+ const idxName = qualifiedIndexName(tableName, index.name);
18260
18362
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18261
18363
  const where = index.where ? ` WHERE ${index.where}` : "";
18262
18364
  return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
@@ -18284,7 +18386,17 @@ class PostgresDriver {
18284
18386
  }
18285
18387
  modifyColumn(tableName, column) {
18286
18388
  const typeSql = this.getColumnType(column);
18287
- return `ALTER TABLE ${this.quoteIdentifier(tableName)} ALTER COLUMN ${this.quoteIdentifier(column.name)} TYPE ${typeSql} USING ${this.quoteIdentifier(column.name)}::${typeSql};`;
18389
+ const table = this.quoteIdentifier(tableName);
18390
+ const name = this.quoteIdentifier(column.name);
18391
+ const statements = [
18392
+ `ALTER TABLE ${table} ALTER COLUMN ${name} TYPE ${typeSql} USING ${name}::${typeSql};`
18393
+ ];
18394
+ if (!column.isPrimaryKey)
18395
+ statements.push(`ALTER TABLE ${table} ALTER COLUMN ${name} ${column.isNullable ? "DROP NOT NULL" : "SET NOT NULL"};`);
18396
+ const defaultValue = this.getDefaultValue(column);
18397
+ statements.push(defaultValue ? `ALTER TABLE ${table} ALTER COLUMN ${name} SET ${defaultValue};` : `ALTER TABLE ${table} ALTER COLUMN ${name} DROP DEFAULT;`);
18398
+ return statements.join(`
18399
+ `);
18288
18400
  }
18289
18401
  renameColumn(tableName, from, to) {
18290
18402
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} RENAME COLUMN ${this.quoteIdentifier(from)} TO ${this.quoteIdentifier(to)};`;
@@ -18302,7 +18414,7 @@ class PostgresDriver {
18302
18414
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18303
18415
  }
18304
18416
  dropIndex(tableName, indexName) {
18305
- const fullIndexName = `${tableName}_${indexName}`;
18417
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18306
18418
  return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
18307
18419
  }
18308
18420
  dropEnumType(enumTypeName) {
@@ -18345,10 +18457,12 @@ class PostgresDriver {
18345
18457
  return parts.join(" ");
18346
18458
  }
18347
18459
  }
18460
+ var init_postgres = () => {};
18348
18461
 
18349
18462
  // src/drivers/singlestore.ts
18350
18463
  var SingleStoreDriver;
18351
18464
  var init_singlestore = __esm(() => {
18465
+ init_mysql();
18352
18466
  SingleStoreDriver = class SingleStoreDriver extends MySQLDriver {
18353
18467
  createTable(table) {
18354
18468
  const columns = table.columns.map((c) => this.renderColumn(c)).join(`,
@@ -18482,7 +18596,7 @@ class SQLiteDriver {
18482
18596
  }
18483
18597
  createIndex(tableName, index) {
18484
18598
  const kind = index.type === "unique" ? "UNIQUE " : "";
18485
- const idxName = `${tableName}_${index.name}`;
18599
+ const idxName = qualifiedIndexName(tableName, index.name);
18486
18600
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18487
18601
  const where = index.where ? ` WHERE ${index.where}` : "";
18488
18602
  return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
@@ -18547,7 +18661,7 @@ class SQLiteDriver {
18547
18661
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18548
18662
  }
18549
18663
  dropIndex(tableName, indexName) {
18550
- const fullIndexName = `${tableName}_${indexName}`;
18664
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18551
18665
  return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
18552
18666
  }
18553
18667
  dropEnumType(_enumTypeName) {
@@ -18593,6 +18707,7 @@ class SQLiteDriver {
18593
18707
  return parts.join(" ");
18594
18708
  }
18595
18709
  }
18710
+ var init_sqlite = () => {};
18596
18711
 
18597
18712
  // src/drivers/index.ts
18598
18713
  function getDialectDriver(dialect) {
@@ -18610,8 +18725,14 @@ function getDialectDriver(dialect) {
18610
18725
  }
18611
18726
  }
18612
18727
  var init_drivers = __esm(() => {
18728
+ init_mysql();
18729
+ init_postgres();
18613
18730
  init_singlestore();
18731
+ init_sqlite();
18732
+ init_mysql();
18733
+ init_postgres();
18614
18734
  init_singlestore();
18735
+ init_sqlite();
18615
18736
  });
18616
18737
 
18617
18738
  // src/workspace.ts
@@ -28346,6 +28467,23 @@ function buildMigrationPlan2(models, options) {
28346
28467
  hasDefault: false
28347
28468
  });
28348
28469
  }
28470
+ const declaredFkTargets = new Map;
28471
+ const declaresBelongsTo = normalizeRelationList(model.belongsTo).length > 0;
28472
+ const columnNames = new Set(Object.keys(attrs).map((name) => snakeCase(name)));
28473
+ const polymorphicColumns = new Set;
28474
+ for (const column of columnNames) {
28475
+ if (!column.endsWith("_type"))
28476
+ continue;
28477
+ const idColumn = `${column.slice(0, -"_type".length)}_id`;
28478
+ if (columnNames.has(idColumn))
28479
+ polymorphicColumns.add(idColumn);
28480
+ }
28481
+ for (const rel of normalizeRelationList(model.belongsTo)) {
28482
+ const column = rel.foreignKey ?? `${snakeCase(rel.model)}_id`;
28483
+ const table2 = meta.modelToTable[rel.model];
28484
+ if (table2)
28485
+ declaredFkTargets.set(column, table2);
28486
+ }
28349
28487
  for (const attrName of Object.keys(attrs)) {
28350
28488
  const attr = attrs[attrName];
28351
28489
  const columnName = snakeCase(attrName);
@@ -28393,7 +28531,7 @@ function buildMigrationPlan2(models, options) {
28393
28531
  enumValues,
28394
28532
  maxLength: typeof maxLen === "number" && maxLen > 0 && maxLen <= 255 ? maxLen : undefined
28395
28533
  };
28396
- if (columnName.endsWith("_id") && attr.foreignKey !== false) {
28534
+ if (columnName.endsWith("_id") && attr.foreignKey !== false && !polymorphicColumns.has(columnName)) {
28397
28535
  if (typeof attr.foreignKey === "object" && attr.foreignKey !== null) {
28398
28536
  const fkConfig = attr.foreignKey;
28399
28537
  col.references = {
@@ -28405,9 +28543,10 @@ function buildMigrationPlan2(models, options) {
28405
28543
  if (fkConfig.nullable !== undefined)
28406
28544
  col.isNullable = fkConfig.nullable;
28407
28545
  } else {
28546
+ const declared = declaredFkTargets.get(columnName);
28408
28547
  const base = columnName.replace(/_id$/, "");
28409
28548
  const maybeModel = base.replace(/(^|_)([a-z])/g, (_2, __, c2) => c2.toUpperCase());
28410
- const refTable = meta.modelToTable[maybeModel];
28549
+ const refTable = declared ?? (declaresBelongsTo ? undefined : meta.modelToTable[maybeModel]);
28411
28550
  if (refTable) {
28412
28551
  const refPk = meta.primaryKeys[refTable] ?? "id";
28413
28552
  col.references = { table: refTable, column: refPk };
@@ -28430,7 +28569,7 @@ function buildMigrationPlan2(models, options) {
28430
28569
  isUnique: false,
28431
28570
  isNullable: true,
28432
28571
  hasDefault: false,
28433
- references: refTable && refPk ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
28572
+ references: refTable && refPk && !polymorphicColumns.has(fkColumnName) ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
28434
28573
  });
28435
28574
  }
28436
28575
  const traits = model.traits;
@@ -28531,7 +28670,7 @@ function buildMigrationPlan2(models, options) {
28531
28670
  }
28532
28671
  if (traits.taggable) {
28533
28672
  ensureTable({
28534
- table: "taggable",
28673
+ table: "taggables",
28535
28674
  columns: [
28536
28675
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28537
28676
  { name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
@@ -28539,37 +28678,61 @@ function buildMigrationPlan2(models, options) {
28539
28678
  { name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28540
28679
  { name: "order", type: "integer", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: 0 },
28541
28680
  { name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
28681
+ { name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28682
+ { name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28683
+ { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28684
+ { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28685
+ ],
28686
+ indexes: [
28687
+ { name: "taggables_target_index", columns: ["taggable_id", "taggable_type"], type: "index" },
28688
+ { name: "taggables_type_slug_unique", columns: ["taggable_type", "slug"], type: "unique" }
28689
+ ]
28690
+ });
28691
+ ensureTable({
28692
+ table: "taggable_models",
28693
+ columns: [
28694
+ { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28695
+ { name: "tag_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "taggables", column: "id" } },
28542
28696
  { name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28543
28697
  { name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28544
28698
  { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28545
28699
  { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28546
28700
  ],
28547
- indexes: [{ name: "taggable_target_index", columns: ["taggable_id", "taggable_type"], type: "index" }]
28701
+ indexes: [
28702
+ { name: "taggable_models_owner_unique", columns: ["tag_id", "taggable_id", "taggable_type"], type: "unique" },
28703
+ { name: "taggable_models_target_index", columns: ["taggable_id", "taggable_type"], type: "index" }
28704
+ ]
28548
28705
  });
28549
28706
  }
28550
28707
  if (traits.categorizable) {
28551
28708
  ensureTable({
28552
- table: "categorizable",
28709
+ table: "categorizables",
28553
28710
  columns: [
28554
28711
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28555
28712
  { name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28556
28713
  { name: "slug", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28557
28714
  { name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28715
+ { name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
28716
+ { name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28558
28717
  { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28559
28718
  { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28560
28719
  ],
28561
- indexes: [{ name: "categorizable_slug_unique", columns: ["slug"], type: "unique" }]
28720
+ indexes: [{ name: "categorizables_type_slug_unique", columns: ["categorizable_type", "slug"], type: "unique" }]
28562
28721
  });
28563
28722
  ensureTable({
28564
28723
  table: "categorizable_models",
28565
28724
  columns: [
28566
28725
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28567
- { name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "categorizable", column: "id" } },
28726
+ { name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "categorizables", column: "id" } },
28568
28727
  { name: "categorizable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28569
28728
  { name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28570
- { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" }
28729
+ { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28730
+ { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28571
28731
  ],
28572
- indexes: [{ name: "categorizable_models_target_index", columns: ["categorizable_id", "categorizable_type"], type: "index" }]
28732
+ indexes: [
28733
+ { name: "categorizable_models_owner_unique", columns: ["category_id", "categorizable_id", "categorizable_type"], type: "unique" },
28734
+ { name: "categorizable_models_target_index", columns: ["categorizable_id", "categorizable_type"], type: "index" }
28735
+ ]
28573
28736
  });
28574
28737
  }
28575
28738
  }
@@ -28902,13 +29065,13 @@ function referencesAreDifferent(r1, r2) {
28902
29065
  const act = (a2) => (a2 ?? "no action").toLowerCase();
28903
29066
  return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
28904
29067
  }
28905
- function indexKey(index) {
28906
- return `${index.type}:${index.name}:${index.columns.join(",")}`;
29068
+ function indexKey(index, table) {
29069
+ return `${index.type}:${qualifiedIndexName(table, index.name)}:${index.columns.join(",")}`;
28907
29070
  }
28908
- function mapIndexesByKey(indexes) {
29071
+ function mapIndexesByKey(indexes, table) {
28909
29072
  const map = {};
28910
29073
  for (const i2 of indexes)
28911
- map[indexKey(i2)] = i2;
29074
+ map[indexKey(i2, table)] = i2;
28912
29075
  return map;
28913
29076
  }
28914
29077
  function generateDiffOperations(previous, next, opts = {}) {
@@ -29008,21 +29171,21 @@ function generateDiffOperations(previous, next, opts = {}) {
29008
29171
  const prevCols = mapColumnsByName(prev.columns);
29009
29172
  const currCols = mapColumnsByName(curr.columns);
29010
29173
  for (const colName of Object.keys(currCols)) {
29011
- if (!prevCols[colName]) {
29012
- const c2 = currCols[colName];
29013
- if (c2.type === "enum" && c2.enumValues && c2.enumValues.length > 0) {
29014
- const enumTypeName = `${curr.table}_${c2.name}_type`;
29015
- c2.enumTypeName = enumTypeName;
29016
- if (!enumTypes.has(enumTypeName)) {
29017
- const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
29018
- if (createEnumStatement) {
29019
- chunks.push(createEnumStatement);
29020
- operations.push({ kind: "create_enum", table: curr.table, column: c2.name, destructive: false, sql: createEnumStatement });
29021
- emit(createEnumStatement, `create-${enumTypeName}-enum`);
29022
- }
29023
- enumTypes.add(enumTypeName);
29024
- }
29174
+ const c2 = currCols[colName];
29175
+ if (c2.type !== "enum" || !c2.enumValues || c2.enumValues.length === 0)
29176
+ continue;
29177
+ const enumTypeName = `${curr.table}_${c2.name}_type`;
29178
+ c2.enumTypeName = enumTypeName;
29179
+ if (prevCols[colName])
29180
+ continue;
29181
+ if (!enumTypes.has(enumTypeName)) {
29182
+ const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
29183
+ if (createEnumStatement) {
29184
+ chunks.push(createEnumStatement);
29185
+ operations.push({ kind: "create_enum", table: curr.table, column: c2.name, destructive: false, sql: createEnumStatement });
29186
+ emit(createEnumStatement, `create-${enumTypeName}-enum`);
29025
29187
  }
29188
+ enumTypes.add(enumTypeName);
29026
29189
  }
29027
29190
  }
29028
29191
  }
@@ -29032,9 +29195,9 @@ function generateDiffOperations(previous, next, opts = {}) {
29032
29195
  if (!prev)
29033
29196
  continue;
29034
29197
  const prevCols = mapColumnsByName(prev.columns);
29035
- const prevIdx = mapIndexesByKey(prev.indexes);
29198
+ const prevIdx = mapIndexesByKey(prev.indexes, prev.table);
29036
29199
  let currCols = mapColumnsByName(curr.columns);
29037
- let currIdx = mapIndexesByKey(curr.indexes);
29200
+ let currIdx = mapIndexesByKey(curr.indexes, curr.table);
29038
29201
  let renames = [];
29039
29202
  let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
29040
29203
  let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
@@ -29051,7 +29214,7 @@ function generateDiffOperations(previous, next, opts = {}) {
29051
29214
  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`);
29052
29215
  curr = { ...curr, columns: [...curr.columns, ...preserved], indexes: [...curr.indexes, ...keptIndexes] };
29053
29216
  currCols = mapColumnsByName(curr.columns);
29054
- currIdx = mapIndexesByKey(curr.indexes);
29217
+ currIdx = mapIndexesByKey(curr.indexes, curr.table);
29055
29218
  removedCols = [];
29056
29219
  }
29057
29220
  const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
@@ -29205,6 +29368,7 @@ var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0
29205
29368
  var init_migrations = __esm(() => {
29206
29369
  init_config();
29207
29370
  init_drivers();
29371
+ init_sqlite();
29208
29372
  init_meta();
29209
29373
  createdMigrationFiles = [];
29210
29374
  });
@@ -31288,7 +31452,7 @@ function getPrefix() {
31288
31452
  }
31289
31453
  var prefix = getPrefix();
31290
31454
  // package.json
31291
- var version2 = "0.2.0";
31455
+ var version2 = "0.2.2";
31292
31456
 
31293
31457
  // bin/cli.ts
31294
31458
  init_actions();
package/dist/client.d.ts CHANGED
@@ -236,8 +236,8 @@ export declare interface InsertQueryBuilder<DB extends DatabaseSchema<any>, TTab
236
236
  executeTakeFirstOrThrow: () => Promise<DB[TTable]['columns']>
237
237
  }
238
238
  export declare interface UpdateQueryBuilder<DB extends DatabaseSchema<any>, TTable extends keyof DB & string> {
239
- set: (values: Partial<DB[TTable]['columns']>) => UpdateQueryBuilder<DB, TTable>
240
- where: (expr: WhereExpression<DB[TTable]['columns']> | string, op?: WhereOperator, value?: any) => UpdateQueryBuilder<DB, TTable>
239
+ set: (values: Partial<{ [K in keyof DB[TTable]['columns']]: DB[TTable]['columns'][K] | SqlFragment }>) => UpdateQueryBuilder<DB, TTable>
240
+ where: (expr: WhereExpression<DB[TTable]['columns']> | string | SqlFragment, op?: WhereOperator, value?: any) => UpdateQueryBuilder<DB, TTable>
241
241
  returning: <K extends keyof DB[TTable]['columns'] & string>(...cols: K[]) => SelectQueryBuilder<DB, TTable, Pick<DB[TTable]['columns'], K>>
242
242
  toSQL: () => string
243
243
  execute: () => Promise<number>
@@ -0,0 +1 @@
1
+ export declare function qualifiedIndexName(tableName: string, indexName: string): string;
package/dist/src/index.js CHANGED
@@ -12507,6 +12507,24 @@ var init_pivot = __esm(() => {
12507
12507
  function isRawExpression(expr) {
12508
12508
  return typeof expr === "object" && expr !== null && "raw" in expr && typeof expr.raw === "string";
12509
12509
  }
12510
+ function isBoundSqlExpression(expr) {
12511
+ return typeof expr === "object" && expr !== null && "sql" in expr && typeof expr.sql === "string" && (!("parameters" in expr) || Array.isArray(expr.parameters));
12512
+ }
12513
+ function renderBoundSqlExpression(expression, startIndex) {
12514
+ const parameters = expression.parameters ?? [];
12515
+ if (config5.dialect !== "postgres" || parameters.length === 0)
12516
+ return { text: expression.sql, parameters };
12517
+ let parameterIndex = 0;
12518
+ const text = expression.sql.replace(/\?/g, (placeholder) => {
12519
+ if (parameterIndex >= parameters.length)
12520
+ return placeholder;
12521
+ return getPlaceholder(startIndex + parameterIndex++);
12522
+ });
12523
+ if (parameterIndex !== parameters.length) {
12524
+ throw new TypeError(`[query-builder] SQL expression declares ${parameters.length} parameters but contains only ${parameterIndex} placeholders`);
12525
+ }
12526
+ return { text, parameters };
12527
+ }
12510
12528
  function raw(strings, ...values) {
12511
12529
  if (typeof strings === "string")
12512
12530
  return { raw: strings };
@@ -12980,6 +12998,31 @@ function createQueryBuilder(state) {
12980
12998
  throw err;
12981
12999
  });
12982
13000
  }
13001
+ function mutationCount(result) {
13002
+ if (typeof result === "number")
13003
+ return Number.isFinite(result) ? result : 0;
13004
+ if (typeof result === "bigint")
13005
+ return Number(result);
13006
+ if (!result || typeof result !== "object")
13007
+ return 0;
13008
+ const record = result;
13009
+ for (const key of [
13010
+ "changes",
13011
+ "affectedRows",
13012
+ "count",
13013
+ "rowCount",
13014
+ "numAffectedRows",
13015
+ "numUpdatedRows",
13016
+ "numDeletedRows",
13017
+ "numInsertedOrUpdatedRows"
13018
+ ]) {
13019
+ if (record[key] !== undefined && record[key] !== null)
13020
+ return mutationCount(record[key]);
13021
+ }
13022
+ if (Array.isArray(result))
13023
+ return result.reduce((total, item) => total + mutationCount(item), 0);
13024
+ return 0;
13025
+ }
12983
13026
  function makeExecutableQuery(q, text) {
12984
13027
  const sqlText = text ?? computeSqlText(q);
12985
13028
  return {
@@ -14075,7 +14118,16 @@ function createQueryBuilder(state) {
14075
14118
  built = null;
14076
14119
  return this;
14077
14120
  }
14078
- return this;
14121
+ if (typeof expr === "function") {
14122
+ throw new TypeError("where(callback) is not supported. This builder has no expression callback, and " + "ignoring one silently would leave the query matching every row the filter was " + "meant to exclude. Use whereNested(subquery), whereAny(...), or the orWhere* " + "helpers to build a grouped condition.");
14123
+ }
14124
+ if (expr === undefined || expr === null) {
14125
+ throw new TypeError("where() was called with no condition.");
14126
+ }
14127
+ if (typeof expr === "string") {
14128
+ throw new TypeError(`where(${JSON.stringify(expr)}) is missing an operator and a value. Pass ` + "where(column, operator, value), or whereRaw() for a raw fragment.");
14129
+ }
14130
+ throw new TypeError(`where() does not understand a condition of type ${typeof expr}.`);
14079
14131
  },
14080
14132
  whereNull(column) {
14081
14133
  validateIdentifier(String(column), "whereNull(column)");
@@ -15680,8 +15732,17 @@ function createQueryBuilder(state) {
15680
15732
  const setClauses = Array.from({ length: len });
15681
15733
  for (let i = 0;i < len; i++) {
15682
15734
  const key = keys[i];
15683
- setClauses[i] = `${quoteId(key)} = ${getPlaceholder(i + 1)}`;
15684
- params.push(values[key]);
15735
+ const value = values[key];
15736
+ if (isRawExpression(value)) {
15737
+ setClauses[i] = `${quoteId(key)} = ${value.raw}`;
15738
+ } else if (isBoundSqlExpression(value)) {
15739
+ const expression = renderBoundSqlExpression(value, params.length + 1);
15740
+ setClauses[i] = `${quoteId(key)} = ${expression.text}`;
15741
+ params.push(...expression.parameters);
15742
+ } else {
15743
+ setClauses[i] = `${quoteId(key)} = ${getPlaceholder(params.length + 1)}`;
15744
+ params.push(value);
15745
+ }
15685
15746
  }
15686
15747
  sqlText = `${sqlText} SET ${setClauses.join(", ")}`;
15687
15748
  built = _sql.unsafe(sqlText, params);
@@ -15689,17 +15750,29 @@ function createQueryBuilder(state) {
15689
15750
  },
15690
15751
  where(expr, op, value) {
15691
15752
  const getWhereKeyword = () => SQL_PATTERNS.WHERE.test(sqlText) ? "AND" : "WHERE";
15692
- if (typeof expr === "string" && op !== undefined) {
15753
+ if (op !== undefined && (typeof expr === "string" || isRawExpression(expr) || isBoundSqlExpression(expr))) {
15754
+ const safeOperator = assertSafeWhereOperator(op, "updateTable.where");
15755
+ let left;
15756
+ if (typeof expr === "string") {
15757
+ left = quoteId(expr);
15758
+ } else if (isRawExpression(expr)) {
15759
+ left = expr.raw;
15760
+ } else {
15761
+ const expression = renderBoundSqlExpression(expr, params.length + 1);
15762
+ left = expression.text;
15763
+ params.push(...expression.parameters);
15764
+ }
15693
15765
  const paramIndex = params.length + 1;
15694
- sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(expr)} ${op} ${getPlaceholder(paramIndex)}`;
15766
+ sqlText = `${sqlText} ${getWhereKeyword()} ${left} ${safeOperator} ${getPlaceholder(paramIndex)}`;
15695
15767
  params.push(value);
15696
15768
  built = _sql.unsafe(sqlText, params);
15697
15769
  return this;
15698
15770
  }
15699
15771
  if (Array.isArray(expr)) {
15700
15772
  const [col, op2, val] = expr;
15773
+ const safeOperator = assertSafeWhereOperator(op2, "updateTable.where");
15701
15774
  const paramIndex = params.length + 1;
15702
- sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${String(op2)} ${getPlaceholder(paramIndex)}`;
15775
+ sqlText = `${sqlText} ${getWhereKeyword()} ${quoteId(String(col))} ${safeOperator} ${getPlaceholder(paramIndex)}`;
15703
15776
  params.push(val);
15704
15777
  built = _sql.unsafe(sqlText, params);
15705
15778
  return this;
@@ -15758,15 +15831,16 @@ function createQueryBuilder(state) {
15758
15831
  }
15759
15832
  return makeExecutableQuery(built, sqlText);
15760
15833
  },
15761
- execute() {
15762
- return runWithHooks(built, "update");
15834
+ async execute() {
15835
+ const result = await runWithHooks(built, "update");
15836
+ return mutationCount(result);
15763
15837
  },
15764
15838
  async executeTakeFirst() {
15765
- const result = await runWithHooks(built, "update");
15839
+ const result = mutationCount(await runWithHooks(built, "update"));
15766
15840
  return { numUpdatedRows: result };
15767
15841
  },
15768
15842
  async executeTakeFirstOrThrow() {
15769
- const result = await runWithHooks(built, "update");
15843
+ const result = mutationCount(await runWithHooks(built, "update"));
15770
15844
  if (result === 0)
15771
15845
  throw new Error("No rows updated");
15772
15846
  return { numUpdatedRows: result };
@@ -15887,18 +15961,18 @@ function createQueryBuilder(state) {
15887
15961
  } catch (err) {
15888
15962
  throw err;
15889
15963
  }
15890
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15964
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15891
15965
  try {
15892
15966
  await config5.hooks?.afterDelete?.({ table: String(table), where: whereCondition, result });
15893
15967
  } catch {}
15894
15968
  return result;
15895
15969
  },
15896
15970
  async executeTakeFirst() {
15897
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15971
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15898
15972
  return { numDeletedRows: result };
15899
15973
  },
15900
15974
  async executeTakeFirstOrThrow() {
15901
- const result = await runWithHooks(ensureDelBuilt(), "delete");
15975
+ const result = mutationCount(await runWithHooks(ensureDelBuilt(), "delete"));
15902
15976
  if (result === 0)
15903
15977
  throw new Error("No rows deleted");
15904
15978
  return { numDeletedRows: result };
@@ -17681,10 +17755,6 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
17681
17755
  return "enum";
17682
17756
  return "string";
17683
17757
  }
17684
- function stripIndexPrefix(physicalName, table) {
17685
- const prefix = `${table}_`;
17686
- return physicalName.startsWith(prefix) ? physicalName.slice(prefix.length) : physicalName;
17687
- }
17688
17758
  function asAction(raw2) {
17689
17759
  const v = String(raw2 ?? "").toLowerCase().trim();
17690
17760
  if (v === "cascade" || v === "restrict" || v === "set null")
@@ -17720,7 +17790,7 @@ async function buildSqliteTable(qb, table) {
17720
17790
  const isUnique = Number(idx.unique) === 1;
17721
17791
  if (isUnique && columns2.length === 1)
17722
17792
  uniqueColumns.add(columns2[0]);
17723
- indexes.push({ name: stripIndexPrefix(physName, table), columns: columns2, type: isUnique ? "unique" : "index" });
17793
+ indexes.push({ name: physName, columns: columns2, type: isUnique ? "unique" : "index" });
17724
17794
  }
17725
17795
  const columns = colRows.map((r) => {
17726
17796
  const name = String(r.name);
@@ -17757,7 +17827,31 @@ function normalizeRawDefault(raw2) {
17757
17827
  return raw2;
17758
17828
  return String(raw2);
17759
17829
  }
17760
- async function buildPgTable(qb, table) {
17830
+ async function pgEnumLabels(qb) {
17831
+ const rows = await qb.unsafe(`SELECT t.typname AS type_name, e.enumlabel AS label
17832
+ FROM pg_type t
17833
+ JOIN pg_enum e ON e.enumtypid = t.oid
17834
+ JOIN pg_namespace n ON n.oid = t.typnamespace
17835
+ WHERE n.nspname = 'public'
17836
+ ORDER BY t.typname, e.enumsortorder`);
17837
+ const labels = new Map;
17838
+ for (const row of rows) {
17839
+ const name = String(row.type_name);
17840
+ const existing = labels.get(name);
17841
+ if (existing)
17842
+ existing.push(String(row.label));
17843
+ else
17844
+ labels.set(name, [String(row.label)]);
17845
+ }
17846
+ return labels;
17847
+ }
17848
+ function pgColumnType(dataType, udtName, enums) {
17849
+ const enumValues = enums.get(udtName);
17850
+ const type = sqlTypeToNormalized(String(dataType || udtName || ""), "postgres", { enumValues });
17851
+ return enumValues ? { type, enumValues, enumTypeName: udtName } : { type };
17852
+ }
17853
+ async function buildPgTable(qb, table, enumLabels) {
17854
+ const enums = enumLabels ?? await pgEnumLabels(qb);
17761
17855
  const colRows = await qb.unsafe(`SELECT c.column_name, c.data_type, c.udt_name, c.is_nullable, c.column_default, c.character_maximum_length,
17762
17856
  (SELECT COUNT(*) FROM information_schema.table_constraints tc
17763
17857
  JOIN information_schema.key_column_usage k ON k.constraint_name = tc.constraint_name
@@ -17805,7 +17899,7 @@ async function buildPgTable(qb, table) {
17805
17899
  const hasDefault = rawDefault != null && !isSerial;
17806
17900
  return {
17807
17901
  name,
17808
- type: sqlTypeToNormalized(String(r.data_type ?? r.udt_name ?? ""), "postgres"),
17902
+ ...pgColumnType(String(r.data_type ?? ""), r.udt_name == null ? "" : String(r.udt_name), enums),
17809
17903
  isPrimaryKey,
17810
17904
  isUnique: uniqueColumns.has(name),
17811
17905
  isNullable: isPrimaryKey ? false : String(r.is_nullable).toUpperCase() === "YES",
@@ -17891,7 +17985,7 @@ function groupPhysicalIndexes(table, rows) {
17891
17985
  if (entry.isUnique && entry.columns.length === 1)
17892
17986
  uniqueColumns.add(entry.columns[0]);
17893
17987
  indexes.push({
17894
- name: stripIndexPrefix(physName, table),
17988
+ name: physName,
17895
17989
  columns: entry.columns,
17896
17990
  type: entry.isUnique ? "unique" : "index",
17897
17991
  where: entry.where
@@ -17904,13 +17998,14 @@ async function buildPlanFromDatabase(dialect, opts = {}) {
17904
17998
  const qb = createQueryBuilder();
17905
17999
  const allTables = opts.tables?.length ? opts.tables : await listTables(qb, d);
17906
18000
  const tables = allTables.filter((t) => t !== "migrations");
18001
+ const enumLabels = d === "postgres" ? await pgEnumLabels(qb) : undefined;
17907
18002
  const out = [];
17908
18003
  for (const table of tables) {
17909
18004
  let plan;
17910
18005
  if (d === "sqlite")
17911
18006
  plan = await buildSqliteTable(qb, table);
17912
18007
  else if (d === "postgres")
17913
- plan = await buildPgTable(qb, table);
18008
+ plan = await buildPgTable(qb, table, enumLabels);
17914
18009
  else
17915
18010
  plan = await buildMysqlTable(qb, table);
17916
18011
  if (plan.columns.length > 0)
@@ -17981,6 +18076,12 @@ export default model
17981
18076
  }
17982
18077
  var init_make_model = () => {};
17983
18078
 
18079
+ // src/drivers/index-name.ts
18080
+ function qualifiedIndexName(tableName, indexName) {
18081
+ const prefix = `${tableName}_`;
18082
+ return indexName.startsWith(prefix) ? indexName : `${prefix}${indexName}`;
18083
+ }
18084
+
17984
18085
  // src/drivers/mysql.ts
17985
18086
  class MySQLDriver {
17986
18087
  quoteIdentifier(id) {
@@ -18067,7 +18168,7 @@ class MySQLDriver {
18067
18168
  throw new Error(`[migrations] Partial indexes (CompositeIndex.where) are not supported on MySQL. Index '${index.name}' on table '${tableName}' uses WHERE clause: ${index.where}`);
18068
18169
  }
18069
18170
  const kind = index.type === "unique" ? "UNIQUE " : "";
18070
- const idxName = `${tableName}_${index.name}`;
18171
+ const idxName = qualifiedIndexName(tableName, index.name);
18071
18172
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18072
18173
  return `CREATE ${kind}INDEX ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns});`;
18073
18174
  }
@@ -18120,7 +18221,7 @@ class MySQLDriver {
18120
18221
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18121
18222
  }
18122
18223
  dropIndex(tableName, indexName) {
18123
- const fullIndexName = `${tableName}_${indexName}`;
18224
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18124
18225
  return `DROP INDEX ${this.quoteIdentifier(fullIndexName)} ON ${this.quoteIdentifier(tableName)};`;
18125
18226
  }
18126
18227
  dropEnumType(_enumTypeName) {
@@ -18167,6 +18268,7 @@ class MySQLDriver {
18167
18268
  return parts.join(" ");
18168
18269
  }
18169
18270
  }
18271
+ var init_mysql = () => {};
18170
18272
 
18171
18273
  // src/drivers/postgres.ts
18172
18274
  class PostgresDriver {
@@ -18201,7 +18303,7 @@ class PostgresDriver {
18201
18303
  return "jsonb";
18202
18304
  case "enum":
18203
18305
  if (column.enumValues && column.enumValues.length > 0) {
18204
- return this.quoteIdentifier(column.enumTypeName ?? `${column.name}_type`);
18306
+ return column.enumTypeName ? this.quoteIdentifier(column.enumTypeName) : "text";
18205
18307
  }
18206
18308
  return "text";
18207
18309
  default:
@@ -18255,7 +18357,7 @@ class PostgresDriver {
18255
18357
  }
18256
18358
  createIndex(tableName, index) {
18257
18359
  const kind = index.type === "unique" ? "UNIQUE " : "";
18258
- const idxName = `${tableName}_${index.name}`;
18360
+ const idxName = qualifiedIndexName(tableName, index.name);
18259
18361
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18260
18362
  const where = index.where ? ` WHERE ${index.where}` : "";
18261
18363
  return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
@@ -18283,7 +18385,17 @@ class PostgresDriver {
18283
18385
  }
18284
18386
  modifyColumn(tableName, column) {
18285
18387
  const typeSql = this.getColumnType(column);
18286
- return `ALTER TABLE ${this.quoteIdentifier(tableName)} ALTER COLUMN ${this.quoteIdentifier(column.name)} TYPE ${typeSql} USING ${this.quoteIdentifier(column.name)}::${typeSql};`;
18388
+ const table = this.quoteIdentifier(tableName);
18389
+ const name = this.quoteIdentifier(column.name);
18390
+ const statements = [
18391
+ `ALTER TABLE ${table} ALTER COLUMN ${name} TYPE ${typeSql} USING ${name}::${typeSql};`
18392
+ ];
18393
+ if (!column.isPrimaryKey)
18394
+ statements.push(`ALTER TABLE ${table} ALTER COLUMN ${name} ${column.isNullable ? "DROP NOT NULL" : "SET NOT NULL"};`);
18395
+ const defaultValue = this.getDefaultValue(column);
18396
+ statements.push(defaultValue ? `ALTER TABLE ${table} ALTER COLUMN ${name} SET ${defaultValue};` : `ALTER TABLE ${table} ALTER COLUMN ${name} DROP DEFAULT;`);
18397
+ return statements.join(`
18398
+ `);
18287
18399
  }
18288
18400
  renameColumn(tableName, from, to) {
18289
18401
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} RENAME COLUMN ${this.quoteIdentifier(from)} TO ${this.quoteIdentifier(to)};`;
@@ -18301,7 +18413,7 @@ class PostgresDriver {
18301
18413
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18302
18414
  }
18303
18415
  dropIndex(tableName, indexName) {
18304
- const fullIndexName = `${tableName}_${indexName}`;
18416
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18305
18417
  return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
18306
18418
  }
18307
18419
  dropEnumType(enumTypeName) {
@@ -18344,10 +18456,12 @@ class PostgresDriver {
18344
18456
  return parts.join(" ");
18345
18457
  }
18346
18458
  }
18459
+ var init_postgres = () => {};
18347
18460
 
18348
18461
  // src/drivers/singlestore.ts
18349
18462
  var SingleStoreDriver;
18350
18463
  var init_singlestore = __esm(() => {
18464
+ init_mysql();
18351
18465
  SingleStoreDriver = class SingleStoreDriver extends MySQLDriver {
18352
18466
  createTable(table) {
18353
18467
  const columns = table.columns.map((c) => this.renderColumn(c)).join(`,
@@ -18481,7 +18595,7 @@ class SQLiteDriver {
18481
18595
  }
18482
18596
  createIndex(tableName, index) {
18483
18597
  const kind = index.type === "unique" ? "UNIQUE " : "";
18484
- const idxName = `${tableName}_${index.name}`;
18598
+ const idxName = qualifiedIndexName(tableName, index.name);
18485
18599
  const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
18486
18600
  const where = index.where ? ` WHERE ${index.where}` : "";
18487
18601
  return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
@@ -18546,7 +18660,7 @@ class SQLiteDriver {
18546
18660
  return `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP COLUMN ${this.quoteIdentifier(columnName)};`;
18547
18661
  }
18548
18662
  dropIndex(tableName, indexName) {
18549
- const fullIndexName = `${tableName}_${indexName}`;
18663
+ const fullIndexName = qualifiedIndexName(tableName, indexName);
18550
18664
  return `DROP INDEX IF EXISTS ${this.quoteIdentifier(fullIndexName)};`;
18551
18665
  }
18552
18666
  dropEnumType(_enumTypeName) {
@@ -18592,6 +18706,7 @@ class SQLiteDriver {
18592
18706
  return parts.join(" ");
18593
18707
  }
18594
18708
  }
18709
+ var init_sqlite = () => {};
18595
18710
 
18596
18711
  // src/drivers/index.ts
18597
18712
  function getDialectDriver(dialect) {
@@ -18609,8 +18724,14 @@ function getDialectDriver(dialect) {
18609
18724
  }
18610
18725
  }
18611
18726
  var init_drivers = __esm(() => {
18727
+ init_mysql();
18728
+ init_postgres();
18612
18729
  init_singlestore();
18730
+ init_sqlite();
18731
+ init_mysql();
18732
+ init_postgres();
18613
18733
  init_singlestore();
18734
+ init_sqlite();
18614
18735
  });
18615
18736
 
18616
18737
  // src/workspace.ts
@@ -28345,6 +28466,23 @@ function buildMigrationPlan2(models, options) {
28345
28466
  hasDefault: false
28346
28467
  });
28347
28468
  }
28469
+ const declaredFkTargets = new Map;
28470
+ const declaresBelongsTo = normalizeRelationList(model.belongsTo).length > 0;
28471
+ const columnNames = new Set(Object.keys(attrs).map((name) => snakeCase(name)));
28472
+ const polymorphicColumns = new Set;
28473
+ for (const column of columnNames) {
28474
+ if (!column.endsWith("_type"))
28475
+ continue;
28476
+ const idColumn = `${column.slice(0, -"_type".length)}_id`;
28477
+ if (columnNames.has(idColumn))
28478
+ polymorphicColumns.add(idColumn);
28479
+ }
28480
+ for (const rel of normalizeRelationList(model.belongsTo)) {
28481
+ const column = rel.foreignKey ?? `${snakeCase(rel.model)}_id`;
28482
+ const table2 = meta.modelToTable[rel.model];
28483
+ if (table2)
28484
+ declaredFkTargets.set(column, table2);
28485
+ }
28348
28486
  for (const attrName of Object.keys(attrs)) {
28349
28487
  const attr = attrs[attrName];
28350
28488
  const columnName = snakeCase(attrName);
@@ -28392,7 +28530,7 @@ function buildMigrationPlan2(models, options) {
28392
28530
  enumValues,
28393
28531
  maxLength: typeof maxLen === "number" && maxLen > 0 && maxLen <= 255 ? maxLen : undefined
28394
28532
  };
28395
- if (columnName.endsWith("_id") && attr.foreignKey !== false) {
28533
+ if (columnName.endsWith("_id") && attr.foreignKey !== false && !polymorphicColumns.has(columnName)) {
28396
28534
  if (typeof attr.foreignKey === "object" && attr.foreignKey !== null) {
28397
28535
  const fkConfig = attr.foreignKey;
28398
28536
  col.references = {
@@ -28404,9 +28542,10 @@ function buildMigrationPlan2(models, options) {
28404
28542
  if (fkConfig.nullable !== undefined)
28405
28543
  col.isNullable = fkConfig.nullable;
28406
28544
  } else {
28545
+ const declared = declaredFkTargets.get(columnName);
28407
28546
  const base = columnName.replace(/_id$/, "");
28408
28547
  const maybeModel = base.replace(/(^|_)([a-z])/g, (_2, __, c2) => c2.toUpperCase());
28409
- const refTable = meta.modelToTable[maybeModel];
28548
+ const refTable = declared ?? (declaresBelongsTo ? undefined : meta.modelToTable[maybeModel]);
28410
28549
  if (refTable) {
28411
28550
  const refPk = meta.primaryKeys[refTable] ?? "id";
28412
28551
  col.references = { table: refTable, column: refPk };
@@ -28429,7 +28568,7 @@ function buildMigrationPlan2(models, options) {
28429
28568
  isUnique: false,
28430
28569
  isNullable: true,
28431
28570
  hasDefault: false,
28432
- references: refTable && refPk ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
28571
+ references: refTable && refPk && !polymorphicColumns.has(fkColumnName) ? { table: refTable, column: refPk, onDelete: rel.onDelete } : undefined
28433
28572
  });
28434
28573
  }
28435
28574
  const traits = model.traits;
@@ -28530,7 +28669,7 @@ function buildMigrationPlan2(models, options) {
28530
28669
  }
28531
28670
  if (traits.taggable) {
28532
28671
  ensureTable({
28533
- table: "taggable",
28672
+ table: "taggables",
28534
28673
  columns: [
28535
28674
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28536
28675
  { name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
@@ -28538,37 +28677,61 @@ function buildMigrationPlan2(models, options) {
28538
28677
  { name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28539
28678
  { name: "order", type: "integer", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: 0 },
28540
28679
  { name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
28680
+ { name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28681
+ { name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28682
+ { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28683
+ { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28684
+ ],
28685
+ indexes: [
28686
+ { name: "taggables_target_index", columns: ["taggable_id", "taggable_type"], type: "index" },
28687
+ { name: "taggables_type_slug_unique", columns: ["taggable_type", "slug"], type: "unique" }
28688
+ ]
28689
+ });
28690
+ ensureTable({
28691
+ table: "taggable_models",
28692
+ columns: [
28693
+ { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28694
+ { name: "tag_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "taggables", column: "id" } },
28541
28695
  { name: "taggable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28542
28696
  { name: "taggable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28543
28697
  { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28544
28698
  { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28545
28699
  ],
28546
- indexes: [{ name: "taggable_target_index", columns: ["taggable_id", "taggable_type"], type: "index" }]
28700
+ indexes: [
28701
+ { name: "taggable_models_owner_unique", columns: ["tag_id", "taggable_id", "taggable_type"], type: "unique" },
28702
+ { name: "taggable_models_target_index", columns: ["taggable_id", "taggable_type"], type: "index" }
28703
+ ]
28547
28704
  });
28548
28705
  }
28549
28706
  if (traits.categorizable) {
28550
28707
  ensureTable({
28551
- table: "categorizable",
28708
+ table: "categorizables",
28552
28709
  columns: [
28553
28710
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28554
28711
  { name: "name", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28555
28712
  { name: "slug", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28556
28713
  { name: "description", type: "text", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false },
28714
+ { name: "is_active", type: "boolean", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: true },
28715
+ { name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28557
28716
  { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28558
28717
  { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28559
28718
  ],
28560
- indexes: [{ name: "categorizable_slug_unique", columns: ["slug"], type: "unique" }]
28719
+ indexes: [{ name: "categorizables_type_slug_unique", columns: ["categorizable_type", "slug"], type: "unique" }]
28561
28720
  });
28562
28721
  ensureTable({
28563
28722
  table: "categorizable_models",
28564
28723
  columns: [
28565
28724
  { name: "id", type: "bigint", isPrimaryKey: true, isUnique: false, isNullable: false, hasDefault: false },
28566
- { name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "categorizable", column: "id" } },
28725
+ { name: "category_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false, references: { table: "categorizables", column: "id" } },
28567
28726
  { name: "categorizable_id", type: "bigint", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28568
28727
  { name: "categorizable_type", type: "string", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: false },
28569
- { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" }
28728
+ { name: "created_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: false, hasDefault: true, defaultValue: "CURRENT_TIMESTAMP" },
28729
+ { name: "updated_at", type: "datetime", isPrimaryKey: false, isUnique: false, isNullable: true, hasDefault: false }
28570
28730
  ],
28571
- indexes: [{ name: "categorizable_models_target_index", columns: ["categorizable_id", "categorizable_type"], type: "index" }]
28731
+ indexes: [
28732
+ { name: "categorizable_models_owner_unique", columns: ["category_id", "categorizable_id", "categorizable_type"], type: "unique" },
28733
+ { name: "categorizable_models_target_index", columns: ["categorizable_id", "categorizable_type"], type: "index" }
28734
+ ]
28572
28735
  });
28573
28736
  }
28574
28737
  }
@@ -28901,13 +29064,13 @@ function referencesAreDifferent(r1, r2) {
28901
29064
  const act = (a2) => (a2 ?? "no action").toLowerCase();
28902
29065
  return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
28903
29066
  }
28904
- function indexKey(index) {
28905
- return `${index.type}:${index.name}:${index.columns.join(",")}`;
29067
+ function indexKey(index, table) {
29068
+ return `${index.type}:${qualifiedIndexName(table, index.name)}:${index.columns.join(",")}`;
28906
29069
  }
28907
- function mapIndexesByKey(indexes) {
29070
+ function mapIndexesByKey(indexes, table) {
28908
29071
  const map = {};
28909
29072
  for (const i2 of indexes)
28910
- map[indexKey(i2)] = i2;
29073
+ map[indexKey(i2, table)] = i2;
28911
29074
  return map;
28912
29075
  }
28913
29076
  function generateDiffOperations(previous, next, opts = {}) {
@@ -29007,21 +29170,21 @@ function generateDiffOperations(previous, next, opts = {}) {
29007
29170
  const prevCols = mapColumnsByName(prev.columns);
29008
29171
  const currCols = mapColumnsByName(curr.columns);
29009
29172
  for (const colName of Object.keys(currCols)) {
29010
- if (!prevCols[colName]) {
29011
- const c2 = currCols[colName];
29012
- if (c2.type === "enum" && c2.enumValues && c2.enumValues.length > 0) {
29013
- const enumTypeName = `${curr.table}_${c2.name}_type`;
29014
- c2.enumTypeName = enumTypeName;
29015
- if (!enumTypes.has(enumTypeName)) {
29016
- const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
29017
- if (createEnumStatement) {
29018
- chunks.push(createEnumStatement);
29019
- operations.push({ kind: "create_enum", table: curr.table, column: c2.name, destructive: false, sql: createEnumStatement });
29020
- emit(createEnumStatement, `create-${enumTypeName}-enum`);
29021
- }
29022
- enumTypes.add(enumTypeName);
29023
- }
29173
+ const c2 = currCols[colName];
29174
+ if (c2.type !== "enum" || !c2.enumValues || c2.enumValues.length === 0)
29175
+ continue;
29176
+ const enumTypeName = `${curr.table}_${c2.name}_type`;
29177
+ c2.enumTypeName = enumTypeName;
29178
+ if (prevCols[colName])
29179
+ continue;
29180
+ if (!enumTypes.has(enumTypeName)) {
29181
+ const createEnumStatement = driver.createEnumType(enumTypeName, c2.enumValues);
29182
+ if (createEnumStatement) {
29183
+ chunks.push(createEnumStatement);
29184
+ operations.push({ kind: "create_enum", table: curr.table, column: c2.name, destructive: false, sql: createEnumStatement });
29185
+ emit(createEnumStatement, `create-${enumTypeName}-enum`);
29024
29186
  }
29187
+ enumTypes.add(enumTypeName);
29025
29188
  }
29026
29189
  }
29027
29190
  }
@@ -29031,9 +29194,9 @@ function generateDiffOperations(previous, next, opts = {}) {
29031
29194
  if (!prev)
29032
29195
  continue;
29033
29196
  const prevCols = mapColumnsByName(prev.columns);
29034
- const prevIdx = mapIndexesByKey(prev.indexes);
29197
+ const prevIdx = mapIndexesByKey(prev.indexes, prev.table);
29035
29198
  let currCols = mapColumnsByName(curr.columns);
29036
- let currIdx = mapIndexesByKey(curr.indexes);
29199
+ let currIdx = mapIndexesByKey(curr.indexes, curr.table);
29037
29200
  let renames = [];
29038
29201
  let removedCols = Object.keys(prevCols).filter((n2) => !currCols[n2]);
29039
29202
  let addedCols = Object.keys(currCols).filter((n2) => !prevCols[n2]);
@@ -29050,7 +29213,7 @@ function generateDiffOperations(previous, next, opts = {}) {
29050
29213
  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
29214
  curr = { ...curr, columns: [...curr.columns, ...preserved], indexes: [...curr.indexes, ...keptIndexes] };
29052
29215
  currCols = mapColumnsByName(curr.columns);
29053
- currIdx = mapIndexesByKey(curr.indexes);
29216
+ currIdx = mapIndexesByKey(curr.indexes, curr.table);
29054
29217
  removedCols = [];
29055
29218
  }
29056
29219
  const modifiedCols = Object.keys(currCols).filter((n2) => prevCols[n2] && columnsAreDifferent(prevCols[n2], currCols[n2], dialect));
@@ -29204,6 +29367,7 @@ var migrationCounter = 0, migrationsCreatedCount = 0, migrationsUpdatedCount = 0
29204
29367
  var init_migrations = __esm(() => {
29205
29368
  init_config();
29206
29369
  init_drivers();
29370
+ init_sqlite();
29207
29371
  init_meta();
29208
29372
  createdMigrationFiles = [];
29209
29373
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-query-builder",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.2",
5
5
  "description": "A simple yet performant query builder for TypeScript. Built with Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",