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.
- package/dist/actions/introspect-db.d.ts +9 -0
- package/dist/bin/cli.js +226 -62
- package/dist/client.d.ts +2 -2
- package/dist/drivers/index-name.d.ts +1 -0
- package/dist/src/index.js +225 -61
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
15685
|
-
|
|
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"
|
|
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()} ${
|
|
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))} ${
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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: "
|
|
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: [
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: [
|
|
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
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
|
|
29018
|
-
|
|
29019
|
-
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
15684
|
-
|
|
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"
|
|
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()} ${
|
|
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))} ${
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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: "
|
|
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: [
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: [
|
|
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
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
|
|
29018
|
-
|
|
29019
|
-
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
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