bun-query-builder 0.2.18 → 0.2.20
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 +2 -0
- package/dist/bin/cli.js +77 -74
- package/dist/drivers/mysql.d.ts +2 -2
- package/dist/drivers/postgres.d.ts +2 -2
- package/dist/migrations.d.ts +7 -1
- package/dist/src/index.js +76 -73
- package/package.json +1 -1
|
@@ -18,6 +18,8 @@ export declare function sqlTypeToNormalized(rawType: string, dialect: SupportedD
|
|
|
18
18
|
* details carried only by COLUMN_TYPE (for example TINYINT(1) and VARCHAR(n)).
|
|
19
19
|
*/
|
|
20
20
|
export declare function mysqlColumnType(dataType: unknown, columnType: unknown, enumValues?: string[]): NormalizedColumnType;
|
|
21
|
+
/** Preserve the physical bound of a MySQL VARCHAR column for round-trip diffs. */
|
|
22
|
+
export declare function mysqlColumnMaxLength(columnType: unknown): number | undefined;
|
|
21
23
|
/**
|
|
22
24
|
* The plan type for one Postgres column, given what the catalogue knows.
|
|
23
25
|
*
|
package/dist/bin/cli.js
CHANGED
|
@@ -17740,6 +17740,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17740
17740
|
if (/^(?:varchar|character varying|nvarchar|nchar|char|character|bpchar)/.test(base)) {
|
|
17741
17741
|
const m = t.match(/\((\d+)\)/);
|
|
17742
17742
|
const len = m ? Number(m[1]) : undefined;
|
|
17743
|
+
if (isMysqlLike(dialect))
|
|
17744
|
+
return "string";
|
|
17743
17745
|
return len !== undefined && len > 255 ? "text" : "string";
|
|
17744
17746
|
}
|
|
17745
17747
|
if (/text|clob/.test(base))
|
|
@@ -17767,6 +17769,13 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17767
17769
|
function mysqlColumnType(dataType, columnType, enumValues) {
|
|
17768
17770
|
return sqlTypeToNormalized(String(columnType || dataType || ""), "mysql", { enumValues });
|
|
17769
17771
|
}
|
|
17772
|
+
function mysqlColumnMaxLength(columnType) {
|
|
17773
|
+
const match = String(columnType || "").trim().match(/^varchar\((\d+)\)/i);
|
|
17774
|
+
if (!match)
|
|
17775
|
+
return;
|
|
17776
|
+
const length = Number(match[1]);
|
|
17777
|
+
return Number.isSafeInteger(length) && length > 0 ? length : undefined;
|
|
17778
|
+
}
|
|
17770
17779
|
function asAction(raw2) {
|
|
17771
17780
|
const v = String(raw2 ?? "").toLowerCase().trim();
|
|
17772
17781
|
if (v === "cascade" || v === "restrict" || v === "set null")
|
|
@@ -17881,7 +17890,10 @@ async function buildPgTable(qb, table, enumLabels) {
|
|
|
17881
17890
|
WHERE t.relname = $1 AND t.relkind = 'r'
|
|
17882
17891
|
ORDER BY i.relname, ord`, [table]);
|
|
17883
17892
|
const fkRows = await qb.unsafe(`SELECT kcu.column_name, ccu.table_name AS ref_table, ccu.column_name AS ref_column,
|
|
17884
|
-
rc.delete_rule, rc.update_rule
|
|
17893
|
+
tc.constraint_name, rc.delete_rule, rc.update_rule,
|
|
17894
|
+
(SELECT COUNT(*) FROM information_schema.key_column_usage count_kcu
|
|
17895
|
+
WHERE count_kcu.constraint_name = tc.constraint_name
|
|
17896
|
+
AND count_kcu.constraint_schema = tc.constraint_schema) AS constraint_column_count
|
|
17885
17897
|
FROM information_schema.table_constraints tc
|
|
17886
17898
|
JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = tc.constraint_name
|
|
17887
17899
|
JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name
|
|
@@ -17889,11 +17901,15 @@ async function buildPgTable(qb, table, enumLabels) {
|
|
|
17889
17901
|
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name = $1 AND tc.table_schema = 'public'`, [table]);
|
|
17890
17902
|
const fkByColumn = new Map;
|
|
17891
17903
|
for (const fk of fkRows) {
|
|
17892
|
-
|
|
17904
|
+
const name = String(fk.column_name);
|
|
17905
|
+
const existing = fkByColumn.get(name);
|
|
17906
|
+
const constraintNames = Number(fk.constraint_column_count) === 1 ? [...new Set([...existing?.constraintNames ?? [], String(fk.constraint_name)])] : existing?.constraintNames;
|
|
17907
|
+
fkByColumn.set(name, existing ? { ...existing, constraintNames } : {
|
|
17893
17908
|
table: String(fk.ref_table),
|
|
17894
17909
|
column: String(fk.ref_column ?? "id"),
|
|
17895
17910
|
onDelete: asAction(fk.delete_rule),
|
|
17896
|
-
onUpdate: asAction(fk.update_rule)
|
|
17911
|
+
onUpdate: asAction(fk.update_rule),
|
|
17912
|
+
constraintNames
|
|
17897
17913
|
});
|
|
17898
17914
|
}
|
|
17899
17915
|
const { indexes, uniqueColumns } = groupPhysicalIndexes(table, idxRows.map((r) => ({
|
|
@@ -17932,18 +17948,27 @@ async function buildMysqlTable(qb, table) {
|
|
|
17932
17948
|
WHERE table_name = ? AND table_schema = DATABASE()
|
|
17933
17949
|
ORDER BY index_name, seq_in_index`, [table]);
|
|
17934
17950
|
const fkRows = await qb.unsafe(`SELECT kcu.column_name, kcu.referenced_table_name AS ref_table, kcu.referenced_column_name AS ref_column,
|
|
17935
|
-
rc.delete_rule, rc.update_rule
|
|
17951
|
+
kcu.constraint_name, rc.delete_rule, rc.update_rule,
|
|
17952
|
+
(SELECT COUNT(*) FROM information_schema.key_column_usage count_kcu
|
|
17953
|
+
WHERE count_kcu.constraint_name = kcu.constraint_name
|
|
17954
|
+
AND count_kcu.constraint_schema = kcu.constraint_schema) AS constraint_column_count
|
|
17936
17955
|
FROM information_schema.key_column_usage kcu
|
|
17937
17956
|
JOIN information_schema.referential_constraints rc
|
|
17938
17957
|
ON rc.constraint_name = kcu.constraint_name AND rc.constraint_schema = kcu.table_schema
|
|
17939
17958
|
WHERE kcu.table_name = ? AND kcu.table_schema = DATABASE() AND kcu.referenced_table_name IS NOT NULL`, [table]);
|
|
17940
17959
|
const fkByColumn = new Map;
|
|
17941
17960
|
for (const fk of fkRows) {
|
|
17942
|
-
|
|
17961
|
+
const name = String(fk.column_name ?? fk.COLUMN_NAME);
|
|
17962
|
+
const existing = fkByColumn.get(name);
|
|
17963
|
+
const columnCount = Number(fk.constraint_column_count ?? fk.CONSTRAINT_COLUMN_COUNT);
|
|
17964
|
+
const constraintName = String(fk.constraint_name ?? fk.CONSTRAINT_NAME);
|
|
17965
|
+
const constraintNames = columnCount === 1 ? [...new Set([...existing?.constraintNames ?? [], constraintName])] : existing?.constraintNames;
|
|
17966
|
+
fkByColumn.set(name, existing ? { ...existing, constraintNames } : {
|
|
17943
17967
|
table: String(fk.ref_table ?? fk.REF_TABLE),
|
|
17944
17968
|
column: String(fk.ref_column ?? fk.REF_COLUMN ?? "id"),
|
|
17945
17969
|
onDelete: asAction(fk.delete_rule ?? fk.DELETE_RULE),
|
|
17946
|
-
onUpdate: asAction(fk.update_rule ?? fk.UPDATE_RULE)
|
|
17970
|
+
onUpdate: asAction(fk.update_rule ?? fk.UPDATE_RULE),
|
|
17971
|
+
constraintNames
|
|
17947
17972
|
});
|
|
17948
17973
|
}
|
|
17949
17974
|
const { indexes, uniqueColumns } = groupPhysicalIndexes(table, idxRows.map((r) => ({
|
|
@@ -17969,6 +17994,7 @@ async function buildMysqlTable(qb, table) {
|
|
|
17969
17994
|
hasDefault,
|
|
17970
17995
|
defaultValue: hasDefault ? normalizeRawDefault(rawDefault) : undefined,
|
|
17971
17996
|
enumValues,
|
|
17997
|
+
maxLength: mysqlColumnMaxLength(columnType),
|
|
17972
17998
|
references: fkByColumn.get(name)
|
|
17973
17999
|
};
|
|
17974
18000
|
});
|
|
@@ -18203,49 +18229,17 @@ class MySQLDriver {
|
|
|
18203
18229
|
const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
|
|
18204
18230
|
return `CREATE ${kind}INDEX ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns});`;
|
|
18205
18231
|
}
|
|
18206
|
-
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate) {
|
|
18232
|
+
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate, existingConstraintNames = []) {
|
|
18207
18233
|
const fkName = `${tableName}_${columnName}_fk`;
|
|
18208
18234
|
let sql = `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD CONSTRAINT ${this.quoteIdentifier(fkName)} FOREIGN KEY (${this.quoteIdentifier(columnName)}) REFERENCES ${this.quoteIdentifier(refTable)}(${this.quoteIdentifier(refColumn)})`;
|
|
18209
18235
|
if (onDelete)
|
|
18210
18236
|
sql += ` ON DELETE ${onDelete.toUpperCase()}`;
|
|
18211
18237
|
if (onUpdate)
|
|
18212
18238
|
sql += ` ON UPDATE ${onUpdate.toUpperCase()}`;
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
|
|
18217
|
-
const table = this.quoteLiteral(tableName);
|
|
18218
|
-
const column = this.quoteLiteral(columnName);
|
|
18219
|
-
return `SET @drop_fks := (
|
|
18220
|
-
SELECT CONCAT(
|
|
18221
|
-
'ALTER TABLE \`', ${table}, '\` DROP FOREIGN KEY \`',
|
|
18222
|
-
GROUP_CONCAT(kcu.CONSTRAINT_NAME SEPARATOR '\`, DROP FOREIGN KEY \`'),
|
|
18223
|
-
'\`'
|
|
18224
|
-
)
|
|
18225
|
-
FROM information_schema.KEY_COLUMN_USAGE kcu
|
|
18226
|
-
WHERE kcu.TABLE_SCHEMA = DATABASE()
|
|
18227
|
-
AND kcu.TABLE_NAME = ${table}
|
|
18228
|
-
AND kcu.COLUMN_NAME = ${column}
|
|
18229
|
-
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
18230
|
-
AND kcu.CONSTRAINT_NAME IN (
|
|
18231
|
-
SELECT single.CONSTRAINT_NAME FROM (
|
|
18232
|
-
SELECT inner_kcu.CONSTRAINT_NAME
|
|
18233
|
-
FROM information_schema.KEY_COLUMN_USAGE inner_kcu
|
|
18234
|
-
WHERE inner_kcu.TABLE_SCHEMA = DATABASE()
|
|
18235
|
-
AND inner_kcu.TABLE_NAME = ${table}
|
|
18236
|
-
AND inner_kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
18237
|
-
GROUP BY inner_kcu.CONSTRAINT_NAME
|
|
18238
|
-
HAVING COUNT(*) = 1
|
|
18239
|
-
) AS single
|
|
18240
|
-
)
|
|
18241
|
-
);
|
|
18242
|
-
SET @drop_fks := IFNULL(@drop_fks, 'SELECT 1');
|
|
18243
|
-
PREPARE drop_fks_stmt FROM @drop_fks;
|
|
18244
|
-
EXECUTE drop_fks_stmt;
|
|
18245
|
-
DEALLOCATE PREPARE drop_fks_stmt;`;
|
|
18246
|
-
}
|
|
18247
|
-
quoteLiteral(value) {
|
|
18248
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
18239
|
+
const drops = [...new Set(existingConstraintNames)].map((name) => `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP FOREIGN KEY ${this.quoteIdentifier(name)};`).join(`
|
|
18240
|
+
`);
|
|
18241
|
+
return drops ? `${drops}
|
|
18242
|
+
${sql};` : `${sql};`;
|
|
18249
18243
|
}
|
|
18250
18244
|
addColumn(tableName, column) {
|
|
18251
18245
|
const typeSql = this.getColumnType(column);
|
|
@@ -18428,41 +18422,17 @@ class PostgresDriver {
|
|
|
18428
18422
|
const where = index.where ? ` WHERE ${index.where}` : "";
|
|
18429
18423
|
return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
|
|
18430
18424
|
}
|
|
18431
|
-
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate) {
|
|
18425
|
+
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate, existingConstraintNames = []) {
|
|
18432
18426
|
const fkName = `${tableName}_${columnName}_fk`;
|
|
18433
18427
|
let sql = `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD CONSTRAINT ${this.quoteIdentifier(fkName)} FOREIGN KEY (${this.quoteIdentifier(columnName)}) REFERENCES ${this.quoteIdentifier(refTable)}(${this.quoteIdentifier(refColumn)})`;
|
|
18434
18428
|
if (onDelete)
|
|
18435
18429
|
sql += ` ON DELETE ${onDelete.toUpperCase()}`;
|
|
18436
18430
|
if (onUpdate)
|
|
18437
18431
|
sql += ` ON UPDATE ${onUpdate.toUpperCase()}`;
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
const table = this.quoteLiteral(tableName);
|
|
18443
|
-
const column = this.quoteLiteral(columnName);
|
|
18444
|
-
return `DO $$
|
|
18445
|
-
DECLARE existing_name text;
|
|
18446
|
-
BEGIN
|
|
18447
|
-
FOR existing_name IN
|
|
18448
|
-
SELECT con.conname
|
|
18449
|
-
FROM pg_constraint con
|
|
18450
|
-
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
18451
|
-
JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
|
|
18452
|
-
WHERE con.contype = 'f'
|
|
18453
|
-
AND rel.relname = ${table}
|
|
18454
|
-
AND nsp.nspname = current_schema()
|
|
18455
|
-
AND con.conkey = ARRAY[(
|
|
18456
|
-
SELECT att.attnum FROM pg_attribute att
|
|
18457
|
-
WHERE att.attrelid = rel.oid AND att.attname = ${column} AND att.attnum > 0
|
|
18458
|
-
)]::smallint[]
|
|
18459
|
-
LOOP
|
|
18460
|
-
EXECUTE format('ALTER TABLE %I DROP CONSTRAINT %I', ${table}, existing_name);
|
|
18461
|
-
END LOOP;
|
|
18462
|
-
END $$;`;
|
|
18463
|
-
}
|
|
18464
|
-
quoteLiteral(value) {
|
|
18465
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
18432
|
+
const drops = [...new Set(existingConstraintNames)].map((name) => `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP CONSTRAINT ${this.quoteIdentifier(name)};`).join(`
|
|
18433
|
+
`);
|
|
18434
|
+
return drops ? `${drops}
|
|
18435
|
+
${sql};` : `${sql};`;
|
|
18466
18436
|
}
|
|
18467
18437
|
addColumn(tableName, column) {
|
|
18468
18438
|
const typeSql = this.getColumnType(column);
|
|
@@ -29124,6 +29094,37 @@ function canonicalStorageType(col, dialect) {
|
|
|
29124
29094
|
return "TEXT";
|
|
29125
29095
|
}
|
|
29126
29096
|
}
|
|
29097
|
+
if (dialect === "mysql" || dialect === "vitess" || dialect === "singlestore") {
|
|
29098
|
+
switch (col.type) {
|
|
29099
|
+
case "string":
|
|
29100
|
+
return `VARCHAR(${col.maxLength ?? 255})`;
|
|
29101
|
+
case "text":
|
|
29102
|
+
return "TEXT";
|
|
29103
|
+
case "boolean":
|
|
29104
|
+
return "TINYINT(1)";
|
|
29105
|
+
case "integer":
|
|
29106
|
+
return "INTEGER";
|
|
29107
|
+
case "bigint":
|
|
29108
|
+
return "BIGINT";
|
|
29109
|
+
case "float":
|
|
29110
|
+
return "REAL";
|
|
29111
|
+
case "double":
|
|
29112
|
+
return "DOUBLE";
|
|
29113
|
+
case "decimal":
|
|
29114
|
+
return "DECIMAL";
|
|
29115
|
+
case "date":
|
|
29116
|
+
return "DATE";
|
|
29117
|
+
case "datetime":
|
|
29118
|
+
case "timestamptz":
|
|
29119
|
+
return "DATETIME";
|
|
29120
|
+
case "json":
|
|
29121
|
+
return "JSON";
|
|
29122
|
+
case "enum":
|
|
29123
|
+
return "ENUM";
|
|
29124
|
+
default:
|
|
29125
|
+
return col.type;
|
|
29126
|
+
}
|
|
29127
|
+
}
|
|
29127
29128
|
return col.type;
|
|
29128
29129
|
}
|
|
29129
29130
|
function canonicalizeDefault(col) {
|
|
@@ -29230,6 +29231,8 @@ function referencesAreDifferent(r1, r2) {
|
|
|
29230
29231
|
return true;
|
|
29231
29232
|
if (!r1 || !r2)
|
|
29232
29233
|
return false;
|
|
29234
|
+
if ((r1.constraintNames?.length ?? 0) > 1)
|
|
29235
|
+
return true;
|
|
29233
29236
|
const act = (a2) => (a2 ?? "no action").toLowerCase();
|
|
29234
29237
|
return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
|
|
29235
29238
|
}
|
|
@@ -29477,7 +29480,7 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
29477
29480
|
const currCol = currCols[colName];
|
|
29478
29481
|
if (!currCol.references)
|
|
29479
29482
|
continue;
|
|
29480
|
-
const addFkStatement = driver.addForeignKey(curr.table, currCol.name, currCol.references.table, currCol.references.column, currCol.references.onDelete, currCol.references.onUpdate);
|
|
29483
|
+
const addFkStatement = driver.addForeignKey(curr.table, currCol.name, currCol.references.table, currCol.references.column, currCol.references.onDelete, currCol.references.onUpdate, prevCols[colName].references?.constraintNames);
|
|
29481
29484
|
if (!addFkStatement)
|
|
29482
29485
|
continue;
|
|
29483
29486
|
tableChanges.push(addFkStatement);
|
|
@@ -31627,7 +31630,7 @@ function getPrefix() {
|
|
|
31627
31630
|
}
|
|
31628
31631
|
var prefix = getPrefix();
|
|
31629
31632
|
// package.json
|
|
31630
|
-
var version2 = "0.2.
|
|
31633
|
+
var version2 = "0.2.20";
|
|
31631
31634
|
|
|
31632
31635
|
// bin/cli.ts
|
|
31633
31636
|
init_actions();
|
package/dist/drivers/mysql.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export declare interface DialectDriver {
|
|
|
3
3
|
createEnumType: (enumTypeName: string, values: string[]) => string
|
|
4
4
|
createTable: (table: TablePlan) => string
|
|
5
5
|
createIndex: (tableName: string, index: IndexPlan) => string
|
|
6
|
-
addForeignKey: (tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string) => string
|
|
6
|
+
addForeignKey: (tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string, existingConstraintNames?: string[]) => string
|
|
7
7
|
addColumn: (tableName: string, column: ColumnPlan) => string
|
|
8
8
|
modifyColumn: (tableName: string, column: ColumnPlan) => string
|
|
9
9
|
renameColumn: (tableName: string, from: string, to: string) => string
|
|
@@ -26,7 +26,7 @@ export declare class MySQLDriver implements DialectDriver {
|
|
|
26
26
|
createEnumType(_enumTypeName: string, _values: string[]): string;
|
|
27
27
|
createTable(table: TablePlan): string;
|
|
28
28
|
createIndex(tableName: string, index: IndexPlan): string;
|
|
29
|
-
addForeignKey(tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string): string;
|
|
29
|
+
addForeignKey(tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string, existingConstraintNames?: string[]): string;
|
|
30
30
|
addColumn(tableName: string, column: ColumnPlan): string;
|
|
31
31
|
modifyColumn(tableName: string, column: ColumnPlan): string;
|
|
32
32
|
renameColumn(tableName: string, from: string, to: string): string;
|
|
@@ -3,7 +3,7 @@ export declare interface DialectDriver {
|
|
|
3
3
|
createEnumType: (enumTypeName: string, values: string[]) => string
|
|
4
4
|
createTable: (table: TablePlan) => string
|
|
5
5
|
createIndex: (tableName: string, index: IndexPlan) => string
|
|
6
|
-
addForeignKey: (tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string) => string
|
|
6
|
+
addForeignKey: (tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string, existingConstraintNames?: string[]) => string
|
|
7
7
|
addColumn: (tableName: string, column: ColumnPlan) => string
|
|
8
8
|
modifyColumn: (tableName: string, column: ColumnPlan) => string
|
|
9
9
|
renameColumn: (tableName: string, from: string, to: string) => string
|
|
@@ -21,7 +21,7 @@ export declare class PostgresDriver implements DialectDriver {
|
|
|
21
21
|
createEnumType(enumTypeName: string, values: string[]): string;
|
|
22
22
|
createTable(table: TablePlan): string;
|
|
23
23
|
createIndex(tableName: string, index: IndexPlan): string;
|
|
24
|
-
addForeignKey(tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string): string;
|
|
24
|
+
addForeignKey(tableName: string, columnName: string, refTable: string, refColumn: string, onDelete?: string, onUpdate?: string, existingConstraintNames?: string[]): string;
|
|
25
25
|
addColumn(tableName: string, column: ColumnPlan): string;
|
|
26
26
|
modifyColumn(tableName: string, column: ColumnPlan): string;
|
|
27
27
|
renameColumn(tableName: string, from: string, to: string): string;
|
package/dist/migrations.d.ts
CHANGED
|
@@ -91,7 +91,13 @@ export declare interface ColumnPlan {
|
|
|
91
91
|
isNullable: boolean
|
|
92
92
|
hasDefault: boolean
|
|
93
93
|
defaultValue?: PrimitiveDefault
|
|
94
|
-
references?: {
|
|
94
|
+
references?: {
|
|
95
|
+
table: string
|
|
96
|
+
column: string
|
|
97
|
+
onDelete?: OnForeignKeyAction
|
|
98
|
+
onUpdate?: OnForeignKeyAction
|
|
99
|
+
constraintNames?: string[]
|
|
100
|
+
}
|
|
95
101
|
enumValues?: string[]
|
|
96
102
|
maxLength?: number
|
|
97
103
|
enumTypeName?: string
|
package/dist/src/index.js
CHANGED
|
@@ -17739,6 +17739,8 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17739
17739
|
if (/^(?:varchar|character varying|nvarchar|nchar|char|character|bpchar)/.test(base)) {
|
|
17740
17740
|
const m = t.match(/\((\d+)\)/);
|
|
17741
17741
|
const len = m ? Number(m[1]) : undefined;
|
|
17742
|
+
if (isMysqlLike(dialect))
|
|
17743
|
+
return "string";
|
|
17742
17744
|
return len !== undefined && len > 255 ? "text" : "string";
|
|
17743
17745
|
}
|
|
17744
17746
|
if (/text|clob/.test(base))
|
|
@@ -17766,6 +17768,13 @@ function sqlTypeToNormalized(rawType, dialect, ctx) {
|
|
|
17766
17768
|
function mysqlColumnType(dataType, columnType, enumValues) {
|
|
17767
17769
|
return sqlTypeToNormalized(String(columnType || dataType || ""), "mysql", { enumValues });
|
|
17768
17770
|
}
|
|
17771
|
+
function mysqlColumnMaxLength(columnType) {
|
|
17772
|
+
const match = String(columnType || "").trim().match(/^varchar\((\d+)\)/i);
|
|
17773
|
+
if (!match)
|
|
17774
|
+
return;
|
|
17775
|
+
const length = Number(match[1]);
|
|
17776
|
+
return Number.isSafeInteger(length) && length > 0 ? length : undefined;
|
|
17777
|
+
}
|
|
17769
17778
|
function asAction(raw2) {
|
|
17770
17779
|
const v = String(raw2 ?? "").toLowerCase().trim();
|
|
17771
17780
|
if (v === "cascade" || v === "restrict" || v === "set null")
|
|
@@ -17880,7 +17889,10 @@ async function buildPgTable(qb, table, enumLabels) {
|
|
|
17880
17889
|
WHERE t.relname = $1 AND t.relkind = 'r'
|
|
17881
17890
|
ORDER BY i.relname, ord`, [table]);
|
|
17882
17891
|
const fkRows = await qb.unsafe(`SELECT kcu.column_name, ccu.table_name AS ref_table, ccu.column_name AS ref_column,
|
|
17883
|
-
rc.delete_rule, rc.update_rule
|
|
17892
|
+
tc.constraint_name, rc.delete_rule, rc.update_rule,
|
|
17893
|
+
(SELECT COUNT(*) FROM information_schema.key_column_usage count_kcu
|
|
17894
|
+
WHERE count_kcu.constraint_name = tc.constraint_name
|
|
17895
|
+
AND count_kcu.constraint_schema = tc.constraint_schema) AS constraint_column_count
|
|
17884
17896
|
FROM information_schema.table_constraints tc
|
|
17885
17897
|
JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = tc.constraint_name
|
|
17886
17898
|
JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name
|
|
@@ -17888,11 +17900,15 @@ async function buildPgTable(qb, table, enumLabels) {
|
|
|
17888
17900
|
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name = $1 AND tc.table_schema = 'public'`, [table]);
|
|
17889
17901
|
const fkByColumn = new Map;
|
|
17890
17902
|
for (const fk of fkRows) {
|
|
17891
|
-
|
|
17903
|
+
const name = String(fk.column_name);
|
|
17904
|
+
const existing = fkByColumn.get(name);
|
|
17905
|
+
const constraintNames = Number(fk.constraint_column_count) === 1 ? [...new Set([...existing?.constraintNames ?? [], String(fk.constraint_name)])] : existing?.constraintNames;
|
|
17906
|
+
fkByColumn.set(name, existing ? { ...existing, constraintNames } : {
|
|
17892
17907
|
table: String(fk.ref_table),
|
|
17893
17908
|
column: String(fk.ref_column ?? "id"),
|
|
17894
17909
|
onDelete: asAction(fk.delete_rule),
|
|
17895
|
-
onUpdate: asAction(fk.update_rule)
|
|
17910
|
+
onUpdate: asAction(fk.update_rule),
|
|
17911
|
+
constraintNames
|
|
17896
17912
|
});
|
|
17897
17913
|
}
|
|
17898
17914
|
const { indexes, uniqueColumns } = groupPhysicalIndexes(table, idxRows.map((r) => ({
|
|
@@ -17931,18 +17947,27 @@ async function buildMysqlTable(qb, table) {
|
|
|
17931
17947
|
WHERE table_name = ? AND table_schema = DATABASE()
|
|
17932
17948
|
ORDER BY index_name, seq_in_index`, [table]);
|
|
17933
17949
|
const fkRows = await qb.unsafe(`SELECT kcu.column_name, kcu.referenced_table_name AS ref_table, kcu.referenced_column_name AS ref_column,
|
|
17934
|
-
rc.delete_rule, rc.update_rule
|
|
17950
|
+
kcu.constraint_name, rc.delete_rule, rc.update_rule,
|
|
17951
|
+
(SELECT COUNT(*) FROM information_schema.key_column_usage count_kcu
|
|
17952
|
+
WHERE count_kcu.constraint_name = kcu.constraint_name
|
|
17953
|
+
AND count_kcu.constraint_schema = kcu.constraint_schema) AS constraint_column_count
|
|
17935
17954
|
FROM information_schema.key_column_usage kcu
|
|
17936
17955
|
JOIN information_schema.referential_constraints rc
|
|
17937
17956
|
ON rc.constraint_name = kcu.constraint_name AND rc.constraint_schema = kcu.table_schema
|
|
17938
17957
|
WHERE kcu.table_name = ? AND kcu.table_schema = DATABASE() AND kcu.referenced_table_name IS NOT NULL`, [table]);
|
|
17939
17958
|
const fkByColumn = new Map;
|
|
17940
17959
|
for (const fk of fkRows) {
|
|
17941
|
-
|
|
17960
|
+
const name = String(fk.column_name ?? fk.COLUMN_NAME);
|
|
17961
|
+
const existing = fkByColumn.get(name);
|
|
17962
|
+
const columnCount = Number(fk.constraint_column_count ?? fk.CONSTRAINT_COLUMN_COUNT);
|
|
17963
|
+
const constraintName = String(fk.constraint_name ?? fk.CONSTRAINT_NAME);
|
|
17964
|
+
const constraintNames = columnCount === 1 ? [...new Set([...existing?.constraintNames ?? [], constraintName])] : existing?.constraintNames;
|
|
17965
|
+
fkByColumn.set(name, existing ? { ...existing, constraintNames } : {
|
|
17942
17966
|
table: String(fk.ref_table ?? fk.REF_TABLE),
|
|
17943
17967
|
column: String(fk.ref_column ?? fk.REF_COLUMN ?? "id"),
|
|
17944
17968
|
onDelete: asAction(fk.delete_rule ?? fk.DELETE_RULE),
|
|
17945
|
-
onUpdate: asAction(fk.update_rule ?? fk.UPDATE_RULE)
|
|
17969
|
+
onUpdate: asAction(fk.update_rule ?? fk.UPDATE_RULE),
|
|
17970
|
+
constraintNames
|
|
17946
17971
|
});
|
|
17947
17972
|
}
|
|
17948
17973
|
const { indexes, uniqueColumns } = groupPhysicalIndexes(table, idxRows.map((r) => ({
|
|
@@ -17968,6 +17993,7 @@ async function buildMysqlTable(qb, table) {
|
|
|
17968
17993
|
hasDefault,
|
|
17969
17994
|
defaultValue: hasDefault ? normalizeRawDefault(rawDefault) : undefined,
|
|
17970
17995
|
enumValues,
|
|
17996
|
+
maxLength: mysqlColumnMaxLength(columnType),
|
|
17971
17997
|
references: fkByColumn.get(name)
|
|
17972
17998
|
};
|
|
17973
17999
|
});
|
|
@@ -18202,49 +18228,17 @@ class MySQLDriver {
|
|
|
18202
18228
|
const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
|
|
18203
18229
|
return `CREATE ${kind}INDEX ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns});`;
|
|
18204
18230
|
}
|
|
18205
|
-
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate) {
|
|
18231
|
+
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate, existingConstraintNames = []) {
|
|
18206
18232
|
const fkName = `${tableName}_${columnName}_fk`;
|
|
18207
18233
|
let sql = `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD CONSTRAINT ${this.quoteIdentifier(fkName)} FOREIGN KEY (${this.quoteIdentifier(columnName)}) REFERENCES ${this.quoteIdentifier(refTable)}(${this.quoteIdentifier(refColumn)})`;
|
|
18208
18234
|
if (onDelete)
|
|
18209
18235
|
sql += ` ON DELETE ${onDelete.toUpperCase()}`;
|
|
18210
18236
|
if (onUpdate)
|
|
18211
18237
|
sql += ` ON UPDATE ${onUpdate.toUpperCase()}`;
|
|
18212
|
-
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
const table = this.quoteLiteral(tableName);
|
|
18217
|
-
const column = this.quoteLiteral(columnName);
|
|
18218
|
-
return `SET @drop_fks := (
|
|
18219
|
-
SELECT CONCAT(
|
|
18220
|
-
'ALTER TABLE \`', ${table}, '\` DROP FOREIGN KEY \`',
|
|
18221
|
-
GROUP_CONCAT(kcu.CONSTRAINT_NAME SEPARATOR '\`, DROP FOREIGN KEY \`'),
|
|
18222
|
-
'\`'
|
|
18223
|
-
)
|
|
18224
|
-
FROM information_schema.KEY_COLUMN_USAGE kcu
|
|
18225
|
-
WHERE kcu.TABLE_SCHEMA = DATABASE()
|
|
18226
|
-
AND kcu.TABLE_NAME = ${table}
|
|
18227
|
-
AND kcu.COLUMN_NAME = ${column}
|
|
18228
|
-
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
18229
|
-
AND kcu.CONSTRAINT_NAME IN (
|
|
18230
|
-
SELECT single.CONSTRAINT_NAME FROM (
|
|
18231
|
-
SELECT inner_kcu.CONSTRAINT_NAME
|
|
18232
|
-
FROM information_schema.KEY_COLUMN_USAGE inner_kcu
|
|
18233
|
-
WHERE inner_kcu.TABLE_SCHEMA = DATABASE()
|
|
18234
|
-
AND inner_kcu.TABLE_NAME = ${table}
|
|
18235
|
-
AND inner_kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
18236
|
-
GROUP BY inner_kcu.CONSTRAINT_NAME
|
|
18237
|
-
HAVING COUNT(*) = 1
|
|
18238
|
-
) AS single
|
|
18239
|
-
)
|
|
18240
|
-
);
|
|
18241
|
-
SET @drop_fks := IFNULL(@drop_fks, 'SELECT 1');
|
|
18242
|
-
PREPARE drop_fks_stmt FROM @drop_fks;
|
|
18243
|
-
EXECUTE drop_fks_stmt;
|
|
18244
|
-
DEALLOCATE PREPARE drop_fks_stmt;`;
|
|
18245
|
-
}
|
|
18246
|
-
quoteLiteral(value) {
|
|
18247
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
18238
|
+
const drops = [...new Set(existingConstraintNames)].map((name) => `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP FOREIGN KEY ${this.quoteIdentifier(name)};`).join(`
|
|
18239
|
+
`);
|
|
18240
|
+
return drops ? `${drops}
|
|
18241
|
+
${sql};` : `${sql};`;
|
|
18248
18242
|
}
|
|
18249
18243
|
addColumn(tableName, column) {
|
|
18250
18244
|
const typeSql = this.getColumnType(column);
|
|
@@ -18427,41 +18421,17 @@ class PostgresDriver {
|
|
|
18427
18421
|
const where = index.where ? ` WHERE ${index.where}` : "";
|
|
18428
18422
|
return `CREATE ${kind}INDEX IF NOT EXISTS ${this.quoteIdentifier(idxName)} ON ${this.quoteIdentifier(tableName)} (${columns})${where};`;
|
|
18429
18423
|
}
|
|
18430
|
-
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate) {
|
|
18424
|
+
addForeignKey(tableName, columnName, refTable, refColumn, onDelete, onUpdate, existingConstraintNames = []) {
|
|
18431
18425
|
const fkName = `${tableName}_${columnName}_fk`;
|
|
18432
18426
|
let sql = `ALTER TABLE ${this.quoteIdentifier(tableName)} ADD CONSTRAINT ${this.quoteIdentifier(fkName)} FOREIGN KEY (${this.quoteIdentifier(columnName)}) REFERENCES ${this.quoteIdentifier(refTable)}(${this.quoteIdentifier(refColumn)})`;
|
|
18433
18427
|
if (onDelete)
|
|
18434
18428
|
sql += ` ON DELETE ${onDelete.toUpperCase()}`;
|
|
18435
18429
|
if (onUpdate)
|
|
18436
18430
|
sql += ` ON UPDATE ${onUpdate.toUpperCase()}`;
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
const table = this.quoteLiteral(tableName);
|
|
18442
|
-
const column = this.quoteLiteral(columnName);
|
|
18443
|
-
return `DO $$
|
|
18444
|
-
DECLARE existing_name text;
|
|
18445
|
-
BEGIN
|
|
18446
|
-
FOR existing_name IN
|
|
18447
|
-
SELECT con.conname
|
|
18448
|
-
FROM pg_constraint con
|
|
18449
|
-
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
18450
|
-
JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
|
|
18451
|
-
WHERE con.contype = 'f'
|
|
18452
|
-
AND rel.relname = ${table}
|
|
18453
|
-
AND nsp.nspname = current_schema()
|
|
18454
|
-
AND con.conkey = ARRAY[(
|
|
18455
|
-
SELECT att.attnum FROM pg_attribute att
|
|
18456
|
-
WHERE att.attrelid = rel.oid AND att.attname = ${column} AND att.attnum > 0
|
|
18457
|
-
)]::smallint[]
|
|
18458
|
-
LOOP
|
|
18459
|
-
EXECUTE format('ALTER TABLE %I DROP CONSTRAINT %I', ${table}, existing_name);
|
|
18460
|
-
END LOOP;
|
|
18461
|
-
END $$;`;
|
|
18462
|
-
}
|
|
18463
|
-
quoteLiteral(value) {
|
|
18464
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
18431
|
+
const drops = [...new Set(existingConstraintNames)].map((name) => `ALTER TABLE ${this.quoteIdentifier(tableName)} DROP CONSTRAINT ${this.quoteIdentifier(name)};`).join(`
|
|
18432
|
+
`);
|
|
18433
|
+
return drops ? `${drops}
|
|
18434
|
+
${sql};` : `${sql};`;
|
|
18465
18435
|
}
|
|
18466
18436
|
addColumn(tableName, column) {
|
|
18467
18437
|
const typeSql = this.getColumnType(column);
|
|
@@ -29123,6 +29093,37 @@ function canonicalStorageType(col, dialect) {
|
|
|
29123
29093
|
return "TEXT";
|
|
29124
29094
|
}
|
|
29125
29095
|
}
|
|
29096
|
+
if (dialect === "mysql" || dialect === "vitess" || dialect === "singlestore") {
|
|
29097
|
+
switch (col.type) {
|
|
29098
|
+
case "string":
|
|
29099
|
+
return `VARCHAR(${col.maxLength ?? 255})`;
|
|
29100
|
+
case "text":
|
|
29101
|
+
return "TEXT";
|
|
29102
|
+
case "boolean":
|
|
29103
|
+
return "TINYINT(1)";
|
|
29104
|
+
case "integer":
|
|
29105
|
+
return "INTEGER";
|
|
29106
|
+
case "bigint":
|
|
29107
|
+
return "BIGINT";
|
|
29108
|
+
case "float":
|
|
29109
|
+
return "REAL";
|
|
29110
|
+
case "double":
|
|
29111
|
+
return "DOUBLE";
|
|
29112
|
+
case "decimal":
|
|
29113
|
+
return "DECIMAL";
|
|
29114
|
+
case "date":
|
|
29115
|
+
return "DATE";
|
|
29116
|
+
case "datetime":
|
|
29117
|
+
case "timestamptz":
|
|
29118
|
+
return "DATETIME";
|
|
29119
|
+
case "json":
|
|
29120
|
+
return "JSON";
|
|
29121
|
+
case "enum":
|
|
29122
|
+
return "ENUM";
|
|
29123
|
+
default:
|
|
29124
|
+
return col.type;
|
|
29125
|
+
}
|
|
29126
|
+
}
|
|
29126
29127
|
return col.type;
|
|
29127
29128
|
}
|
|
29128
29129
|
function canonicalizeDefault(col) {
|
|
@@ -29229,6 +29230,8 @@ function referencesAreDifferent(r1, r2) {
|
|
|
29229
29230
|
return true;
|
|
29230
29231
|
if (!r1 || !r2)
|
|
29231
29232
|
return false;
|
|
29233
|
+
if ((r1.constraintNames?.length ?? 0) > 1)
|
|
29234
|
+
return true;
|
|
29232
29235
|
const act = (a2) => (a2 ?? "no action").toLowerCase();
|
|
29233
29236
|
return r1.table !== r2.table || r1.column !== r2.column || act(r1.onDelete) !== act(r2.onDelete) || act(r1.onUpdate) !== act(r2.onUpdate);
|
|
29234
29237
|
}
|
|
@@ -29476,7 +29479,7 @@ function generateDiffOperations(previous, next, opts = {}) {
|
|
|
29476
29479
|
const currCol = currCols[colName];
|
|
29477
29480
|
if (!currCol.references)
|
|
29478
29481
|
continue;
|
|
29479
|
-
const addFkStatement = driver.addForeignKey(curr.table, currCol.name, currCol.references.table, currCol.references.column, currCol.references.onDelete, currCol.references.onUpdate);
|
|
29482
|
+
const addFkStatement = driver.addForeignKey(curr.table, currCol.name, currCol.references.table, currCol.references.column, currCol.references.onDelete, currCol.references.onUpdate, prevCols[colName].references?.constraintNames);
|
|
29480
29483
|
if (!addFkStatement)
|
|
29481
29484
|
continue;
|
|
29482
29485
|
tableChanges.push(addFkStatement);
|
package/package.json
CHANGED