@prisma-next/target-postgres 0.3.0-dev.40 → 0.3.0-dev.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +149 -53
- package/dist/control.mjs.map +1 -1
- package/package.json +14 -14
- package/src/core/migrations/planner.ts +80 -10
- package/src/core/migrations/statement-builders.ts +3 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ This package spans multiple planes:
|
|
|
34
34
|
|
|
35
35
|
This package provides the Postgres implementation of the SQL migration planner/runner used by `prisma-next db init`:
|
|
36
36
|
|
|
37
|
-
- **Planner** (`src/core/migrations/planner.ts`): produces an additive-only `MigrationPlan` to bring the database schema in line with a destination contract. Extra unrelated schema is tolerated; non-additive mismatches (type/nullability/constraint incompatibilities) surface as structured conflicts. Storage type operations (from codec-owned hooks) are emitted before table operations when `storage.types` are present. The planner respects the contract's `foreignKeys` configuration: when `foreignKeys.constraints` is `false`, FK constraint operations are skipped; when `foreignKeys.indexes` is `false`, FK-backing indexes are omitted. See [ADR 161](../../../docs/architecture%20docs/adrs/ADR%20161%20-%20Explicit%20foreign%20key%20constraint%20and%20index%20configuration.md).
|
|
37
|
+
- **Planner** (`src/core/migrations/planner.ts`): produces an additive-only `MigrationPlan` to bring the database schema in line with a destination contract. Extra unrelated schema is tolerated; non-additive mismatches (type/nullability/constraint incompatibilities) surface as structured conflicts. Storage type operations (from codec-owned hooks) are emitted before table operations when `storage.types` are present. The planner respects the contract's `foreignKeys` configuration: when `foreignKeys.constraints` is `false`, FK constraint operations are skipped; when `foreignKeys.indexes` is `false`, FK-backing indexes are omitted. See [ADR 161](../../../docs/architecture%20docs/adrs/ADR%20161%20-%20Explicit%20foreign%20key%20constraint%20and%20index%20configuration.md). The planner also emits `ON DELETE` and `ON UPDATE` referential action clauses when specified on foreign keys (see [ADR 162](../../../docs/architecture%20docs/adrs/ADR%20162%20-%20Referential%20actions%20for%20foreign%20keys.md)).
|
|
38
38
|
- **Runner** (`src/core/migrations/runner.ts`): executes a plan under an advisory lock, verifies the post-state schema, then writes the contract marker and appends a ledger entry in the `prisma_contract` schema.
|
|
39
39
|
|
|
40
40
|
For the CLI orchestration, see `packages/1-framework/3-tooling/cli/src/commands/db-init.ts`.
|
|
@@ -154,6 +154,7 @@ This package ships a mix of fast planner unit tests and slower runner integratio
|
|
|
154
154
|
- **Test files**:
|
|
155
155
|
- `test/migrations/planner.behavior.test.ts`: Planner unit tests (classification, conflicts, dependency ops)
|
|
156
156
|
- `test/migrations/planner.fk-config.test.ts`: Planner unit tests for FK constraint/index configuration combinations
|
|
157
|
+
- `test/migrations/planner.referential-actions.test.ts`: Planner unit tests for ON DELETE/ON UPDATE DDL emission
|
|
157
158
|
- `test/migrations/planner.integration.test.ts`: Planner integration tests
|
|
158
159
|
- `test/migrations/runner.*.integration.test.ts`: Runner integration tests (basic, errors, idempotency, policy)
|
|
159
160
|
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/migrations/planner.ts","../src/exports/control.ts"],"sourcesContent":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/migrations/planner.ts","../src/exports/control.ts"],"sourcesContent":[],"mappings":";;;KAyCK,cAAA;UAuBY,yBAAA;EAvBZ,SAAA,MAAA,EAAc,MAAA;EAuBF,SAAA,UAAA,EAEM,cAFmB;;;;;;cClDpC,0BAA0B,uCAAuC"}
|
package/dist/control.mjs
CHANGED
|
@@ -2,37 +2,13 @@ import { t as postgresTargetDescriptorMeta } from "./descriptor-meta-DxB8oZzB.mj
|
|
|
2
2
|
import { SQL_CHAR_CODEC_ID, SQL_FLOAT_CODEC_ID, SQL_INT_CODEC_ID, SQL_VARCHAR_CODEC_ID } from "@prisma-next/sql-relational-core/ast";
|
|
3
3
|
import { arraysEqual, isIndexSatisfied, isUniqueConstraintSatisfied, verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
4
4
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
|
+
import { bigintJsonReplacer, isTaggedBigInt } from "@prisma-next/contract/types";
|
|
5
6
|
import { createMigrationPlan, extractCodecControlHooks, plannerFailure, plannerSuccess, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
|
|
6
7
|
import { readMarker } from "@prisma-next/family-sql/verify";
|
|
7
8
|
import { SqlQueryError } from "@prisma-next/sql-errors";
|
|
8
9
|
import { ok, okVoid } from "@prisma-next/utils/result";
|
|
9
10
|
|
|
10
|
-
//#region ../../6-adapters/postgres/dist/
|
|
11
|
-
const PG_TEXT_CODEC_ID = "pg/text@1";
|
|
12
|
-
const PG_ENUM_CODEC_ID = "pg/enum@1";
|
|
13
|
-
const PG_CHAR_CODEC_ID = "pg/char@1";
|
|
14
|
-
const PG_VARCHAR_CODEC_ID = "pg/varchar@1";
|
|
15
|
-
const PG_INT_CODEC_ID = "pg/int@1";
|
|
16
|
-
const PG_INT2_CODEC_ID = "pg/int2@1";
|
|
17
|
-
const PG_INT4_CODEC_ID = "pg/int4@1";
|
|
18
|
-
const PG_INT8_CODEC_ID = "pg/int8@1";
|
|
19
|
-
const PG_FLOAT_CODEC_ID = "pg/float@1";
|
|
20
|
-
const PG_FLOAT4_CODEC_ID = "pg/float4@1";
|
|
21
|
-
const PG_FLOAT8_CODEC_ID = "pg/float8@1";
|
|
22
|
-
const PG_NUMERIC_CODEC_ID = "pg/numeric@1";
|
|
23
|
-
const PG_BOOL_CODEC_ID = "pg/bool@1";
|
|
24
|
-
const PG_BIT_CODEC_ID = "pg/bit@1";
|
|
25
|
-
const PG_VARBIT_CODEC_ID = "pg/varbit@1";
|
|
26
|
-
const PG_TIMESTAMP_CODEC_ID = "pg/timestamp@1";
|
|
27
|
-
const PG_TIMESTAMPTZ_CODEC_ID = "pg/timestamptz@1";
|
|
28
|
-
const PG_TIME_CODEC_ID = "pg/time@1";
|
|
29
|
-
const PG_TIMETZ_CODEC_ID = "pg/timetz@1";
|
|
30
|
-
const PG_INTERVAL_CODEC_ID = "pg/interval@1";
|
|
31
|
-
const PG_JSON_CODEC_ID = "pg/json@1";
|
|
32
|
-
const PG_JSONB_CODEC_ID = "pg/jsonb@1";
|
|
33
|
-
|
|
34
|
-
//#endregion
|
|
35
|
-
//#region ../../6-adapters/postgres/dist/descriptor-meta-D7pxo-wo.mjs
|
|
11
|
+
//#region ../../6-adapters/postgres/dist/sql-utils-CSfAGEwF.mjs
|
|
36
12
|
/**
|
|
37
13
|
* Shared SQL utility functions for the Postgres adapter.
|
|
38
14
|
*
|
|
@@ -106,6 +82,34 @@ function qualifyName(schemaName, objectName) {
|
|
|
106
82
|
function validateEnumValueLength(value, enumTypeName) {
|
|
107
83
|
if (value.length > MAX_IDENTIFIER_LENGTH$1) throw new SqlEscapeError(`Enum value "${value.slice(0, 20)}..." for type "${enumTypeName}" exceeds PostgreSQL's ${MAX_IDENTIFIER_LENGTH$1}-character label limit`, value, "literal");
|
|
108
84
|
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region ../../6-adapters/postgres/dist/codec-ids-Bsm9c7ns.mjs
|
|
88
|
+
const PG_TEXT_CODEC_ID = "pg/text@1";
|
|
89
|
+
const PG_ENUM_CODEC_ID = "pg/enum@1";
|
|
90
|
+
const PG_CHAR_CODEC_ID = "pg/char@1";
|
|
91
|
+
const PG_VARCHAR_CODEC_ID = "pg/varchar@1";
|
|
92
|
+
const PG_INT_CODEC_ID = "pg/int@1";
|
|
93
|
+
const PG_INT2_CODEC_ID = "pg/int2@1";
|
|
94
|
+
const PG_INT4_CODEC_ID = "pg/int4@1";
|
|
95
|
+
const PG_INT8_CODEC_ID = "pg/int8@1";
|
|
96
|
+
const PG_FLOAT_CODEC_ID = "pg/float@1";
|
|
97
|
+
const PG_FLOAT4_CODEC_ID = "pg/float4@1";
|
|
98
|
+
const PG_FLOAT8_CODEC_ID = "pg/float8@1";
|
|
99
|
+
const PG_NUMERIC_CODEC_ID = "pg/numeric@1";
|
|
100
|
+
const PG_BOOL_CODEC_ID = "pg/bool@1";
|
|
101
|
+
const PG_BIT_CODEC_ID = "pg/bit@1";
|
|
102
|
+
const PG_VARBIT_CODEC_ID = "pg/varbit@1";
|
|
103
|
+
const PG_TIMESTAMP_CODEC_ID = "pg/timestamp@1";
|
|
104
|
+
const PG_TIMESTAMPTZ_CODEC_ID = "pg/timestamptz@1";
|
|
105
|
+
const PG_TIME_CODEC_ID = "pg/time@1";
|
|
106
|
+
const PG_TIMETZ_CODEC_ID = "pg/timetz@1";
|
|
107
|
+
const PG_INTERVAL_CODEC_ID = "pg/interval@1";
|
|
108
|
+
const PG_JSON_CODEC_ID = "pg/json@1";
|
|
109
|
+
const PG_JSONB_CODEC_ID = "pg/jsonb@1";
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region ../../6-adapters/postgres/dist/descriptor-meta-ilnFI7bx.mjs
|
|
109
113
|
const ENUM_INTROSPECT_QUERY = `
|
|
110
114
|
SELECT
|
|
111
115
|
n.nspname AS schema_name,
|
|
@@ -1037,6 +1041,8 @@ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d
|
|
|
1037
1041
|
*/
|
|
1038
1042
|
function parsePostgresDefault(rawDefault, _nativeType) {
|
|
1039
1043
|
const trimmed = rawDefault.trim();
|
|
1044
|
+
const normalizedType = _nativeType?.toLowerCase();
|
|
1045
|
+
const isBigInt = normalizedType === "bigint" || normalizedType === "int8";
|
|
1040
1046
|
if (NEXTVAL_PATTERN.test(trimmed)) return {
|
|
1041
1047
|
kind: "function",
|
|
1042
1048
|
expression: "autoincrement()"
|
|
@@ -1055,21 +1061,39 @@ function parsePostgresDefault(rawDefault, _nativeType) {
|
|
|
1055
1061
|
};
|
|
1056
1062
|
if (TRUE_PATTERN.test(trimmed)) return {
|
|
1057
1063
|
kind: "literal",
|
|
1058
|
-
|
|
1064
|
+
value: true
|
|
1059
1065
|
};
|
|
1060
1066
|
if (FALSE_PATTERN.test(trimmed)) return {
|
|
1061
1067
|
kind: "literal",
|
|
1062
|
-
|
|
1063
|
-
};
|
|
1064
|
-
if (NUMERIC_PATTERN.test(trimmed)) return {
|
|
1065
|
-
kind: "literal",
|
|
1066
|
-
expression: trimmed
|
|
1068
|
+
value: false
|
|
1067
1069
|
};
|
|
1070
|
+
if (NUMERIC_PATTERN.test(trimmed)) {
|
|
1071
|
+
if (isBigInt) return {
|
|
1072
|
+
kind: "literal",
|
|
1073
|
+
value: {
|
|
1074
|
+
$type: "bigint",
|
|
1075
|
+
value: trimmed
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
return {
|
|
1079
|
+
kind: "literal",
|
|
1080
|
+
value: Number(trimmed)
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1068
1083
|
const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
|
|
1069
|
-
if (stringMatch?.[1] !== void 0)
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1084
|
+
if (stringMatch?.[1] !== void 0) {
|
|
1085
|
+
const unescaped = stringMatch[1].replace(/''/g, "'");
|
|
1086
|
+
if (normalizedType === "json" || normalizedType === "jsonb") try {
|
|
1087
|
+
return {
|
|
1088
|
+
kind: "literal",
|
|
1089
|
+
value: JSON.parse(unescaped)
|
|
1090
|
+
};
|
|
1091
|
+
} catch {}
|
|
1092
|
+
return {
|
|
1093
|
+
kind: "literal",
|
|
1094
|
+
value: unescaped
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1073
1097
|
return {
|
|
1074
1098
|
kind: "function",
|
|
1075
1099
|
expression: trimmed
|
|
@@ -1160,17 +1184,31 @@ var PostgresControlAdapter = class {
|
|
|
1160
1184
|
tc.constraint_name,
|
|
1161
1185
|
kcu.column_name,
|
|
1162
1186
|
kcu.ordinal_position,
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1187
|
+
ref_ns.nspname AS referenced_table_schema,
|
|
1188
|
+
ref_cl.relname AS referenced_table_name,
|
|
1189
|
+
ref_att.attname AS referenced_column_name,
|
|
1190
|
+
rc.delete_rule,
|
|
1191
|
+
rc.update_rule
|
|
1166
1192
|
FROM information_schema.table_constraints tc
|
|
1167
1193
|
JOIN information_schema.key_column_usage kcu
|
|
1168
1194
|
ON tc.constraint_name = kcu.constraint_name
|
|
1169
1195
|
AND tc.table_schema = kcu.table_schema
|
|
1170
1196
|
AND tc.table_name = kcu.table_name
|
|
1171
|
-
JOIN
|
|
1172
|
-
ON
|
|
1173
|
-
AND
|
|
1197
|
+
JOIN pg_catalog.pg_constraint pgc
|
|
1198
|
+
ON pgc.conname = tc.constraint_name
|
|
1199
|
+
AND pgc.connamespace = (
|
|
1200
|
+
SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = tc.table_schema
|
|
1201
|
+
)
|
|
1202
|
+
JOIN pg_catalog.pg_class ref_cl
|
|
1203
|
+
ON ref_cl.oid = pgc.confrelid
|
|
1204
|
+
JOIN pg_catalog.pg_namespace ref_ns
|
|
1205
|
+
ON ref_ns.oid = ref_cl.relnamespace
|
|
1206
|
+
JOIN pg_catalog.pg_attribute ref_att
|
|
1207
|
+
ON ref_att.attrelid = pgc.confrelid
|
|
1208
|
+
AND ref_att.attnum = pgc.confkey[kcu.ordinal_position]
|
|
1209
|
+
JOIN information_schema.referential_constraints rc
|
|
1210
|
+
ON rc.constraint_name = tc.constraint_name
|
|
1211
|
+
AND rc.constraint_schema = tc.table_schema
|
|
1174
1212
|
WHERE tc.table_schema = $1
|
|
1175
1213
|
AND tc.constraint_type = 'FOREIGN KEY'
|
|
1176
1214
|
ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema]),
|
|
@@ -1264,14 +1302,18 @@ var PostgresControlAdapter = class {
|
|
|
1264
1302
|
columns: [fkRow.column_name],
|
|
1265
1303
|
referencedTable: fkRow.referenced_table_name,
|
|
1266
1304
|
referencedColumns: [fkRow.referenced_column_name],
|
|
1267
|
-
name: fkRow.constraint_name
|
|
1305
|
+
name: fkRow.constraint_name,
|
|
1306
|
+
deleteRule: fkRow.delete_rule,
|
|
1307
|
+
updateRule: fkRow.update_rule
|
|
1268
1308
|
});
|
|
1269
1309
|
}
|
|
1270
1310
|
const foreignKeys = Array.from(foreignKeysMap.values()).map((fk) => ({
|
|
1271
1311
|
columns: Object.freeze([...fk.columns]),
|
|
1272
1312
|
referencedTable: fk.referencedTable,
|
|
1273
1313
|
referencedColumns: Object.freeze([...fk.referencedColumns]),
|
|
1274
|
-
name: fk.name
|
|
1314
|
+
name: fk.name,
|
|
1315
|
+
...ifDefined("onDelete", mapReferentialAction(fk.deleteRule)),
|
|
1316
|
+
...ifDefined("onUpdate", mapReferentialAction(fk.updateRule))
|
|
1275
1317
|
}));
|
|
1276
1318
|
const pkConstraints = pkConstraintsByTable.get(tableName) ?? /* @__PURE__ */ new Set();
|
|
1277
1319
|
const uniquesMap = /* @__PURE__ */ new Map();
|
|
@@ -1378,6 +1420,24 @@ function normalizeFormattedType(formattedType, dataType, udtName) {
|
|
|
1378
1420
|
if (formattedType.startsWith("\"") && formattedType.endsWith("\"")) return formattedType.slice(1, -1);
|
|
1379
1421
|
return formattedType;
|
|
1380
1422
|
}
|
|
1423
|
+
const PG_REFERENTIAL_ACTION_MAP = {
|
|
1424
|
+
"NO ACTION": "noAction",
|
|
1425
|
+
RESTRICT: "restrict",
|
|
1426
|
+
CASCADE: "cascade",
|
|
1427
|
+
"SET NULL": "setNull",
|
|
1428
|
+
"SET DEFAULT": "setDefault"
|
|
1429
|
+
};
|
|
1430
|
+
/**
|
|
1431
|
+
* Maps a Postgres referential action rule to the canonical SqlReferentialAction.
|
|
1432
|
+
* Returns undefined for 'NO ACTION' (the database default) to keep the IR sparse.
|
|
1433
|
+
* Throws for unrecognized rules to prevent silent data loss.
|
|
1434
|
+
*/
|
|
1435
|
+
function mapReferentialAction(rule) {
|
|
1436
|
+
const mapped = PG_REFERENTIAL_ACTION_MAP[rule];
|
|
1437
|
+
if (mapped === void 0) throw new Error(`Unknown PostgreSQL referential action rule: "${rule}". Expected one of: NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT.`);
|
|
1438
|
+
if (mapped === "noAction") return void 0;
|
|
1439
|
+
return mapped;
|
|
1440
|
+
}
|
|
1381
1441
|
/**
|
|
1382
1442
|
* Groups an array of objects by a specified key.
|
|
1383
1443
|
* Returns a Map for O(1) lookup by group key.
|
|
@@ -1782,10 +1842,7 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
1782
1842
|
}],
|
|
1783
1843
|
execute: [{
|
|
1784
1844
|
description: `add foreign key "${fkName}"`,
|
|
1785
|
-
sql:
|
|
1786
|
-
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
1787
|
-
FOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(", ")})
|
|
1788
|
-
REFERENCES ${qualifyTableName(schemaName, foreignKey.references.table)} (${foreignKey.references.columns.map(quoteIdentifier).join(", ")})`
|
|
1845
|
+
sql: buildForeignKeySql(schemaName, tableName, fkName, foreignKey)
|
|
1789
1846
|
}],
|
|
1790
1847
|
postcheck: [{
|
|
1791
1848
|
description: `verify foreign key "${fkName}" exists`,
|
|
@@ -1875,7 +1932,7 @@ function buildCreateTableSql(qualifiedTableName, table) {
|
|
|
1875
1932
|
return [
|
|
1876
1933
|
quoteIdentifier(columnName),
|
|
1877
1934
|
buildColumnTypeSql(column),
|
|
1878
|
-
buildColumnDefaultSql(column.default),
|
|
1935
|
+
buildColumnDefaultSql(column.default, column),
|
|
1879
1936
|
column.nullable ? "" : "NOT NULL"
|
|
1880
1937
|
].filter(Boolean).join(" ");
|
|
1881
1938
|
});
|
|
@@ -1919,16 +1976,31 @@ function renderParameterizedTypeSql(column) {
|
|
|
1919
1976
|
*
|
|
1920
1977
|
* Note: autoincrement is handled specially via SERIAL types, so we skip it here.
|
|
1921
1978
|
*/
|
|
1922
|
-
function buildColumnDefaultSql(columnDefault) {
|
|
1979
|
+
function buildColumnDefaultSql(columnDefault, column) {
|
|
1923
1980
|
if (!columnDefault) return "";
|
|
1924
1981
|
switch (columnDefault.kind) {
|
|
1925
|
-
case "literal": return `DEFAULT ${columnDefault.
|
|
1982
|
+
case "literal": return `DEFAULT ${renderDefaultLiteral(columnDefault.value, column)}`;
|
|
1926
1983
|
case "function":
|
|
1927
1984
|
if (columnDefault.expression === "autoincrement()") return "";
|
|
1928
1985
|
return `DEFAULT ${columnDefault.expression}`;
|
|
1929
1986
|
case "sequence": return `DEFAULT nextval(${quoteIdentifier(columnDefault.name)}::regclass)`;
|
|
1930
1987
|
}
|
|
1931
1988
|
}
|
|
1989
|
+
function renderDefaultLiteral(value, column) {
|
|
1990
|
+
const isJsonColumn = column?.nativeType === "json" || column?.nativeType === "jsonb";
|
|
1991
|
+
if (value instanceof Date) return `'${escapeLiteral(value.toISOString())}'`;
|
|
1992
|
+
if (!isJsonColumn && isTaggedBigInt(value)) {
|
|
1993
|
+
if (!/^-?\d+$/.test(value.value)) throw new Error(`Invalid tagged bigint value: "${value.value}" is not a valid integer`);
|
|
1994
|
+
return value.value;
|
|
1995
|
+
}
|
|
1996
|
+
if (typeof value === "bigint") return value.toString();
|
|
1997
|
+
if (typeof value === "string") return `'${escapeLiteral(value)}'`;
|
|
1998
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1999
|
+
if (value === null) return "NULL";
|
|
2000
|
+
const json = JSON.stringify(value);
|
|
2001
|
+
if (isJsonColumn) return `'${escapeLiteral(json)}'::${column.nativeType}`;
|
|
2002
|
+
return `'${escapeLiteral(json)}'`;
|
|
2003
|
+
}
|
|
1932
2004
|
function qualifyTableName(schema, table) {
|
|
1933
2005
|
return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
|
|
1934
2006
|
}
|
|
@@ -1970,7 +2042,7 @@ function tableIsEmptyCheck(qualifiedTableName) {
|
|
|
1970
2042
|
}
|
|
1971
2043
|
function buildAddColumnSql(qualifiedTableName, columnName, column) {
|
|
1972
2044
|
const typeSql = buildColumnTypeSql(column);
|
|
1973
|
-
const defaultSql = buildColumnDefaultSql(column.default);
|
|
2045
|
+
const defaultSql = buildColumnDefaultSql(column.default, column);
|
|
1974
2046
|
return [
|
|
1975
2047
|
`ALTER TABLE ${qualifiedTableName}`,
|
|
1976
2048
|
`ADD COLUMN ${quoteIdentifier(columnName)} ${typeSql}`,
|
|
@@ -2049,6 +2121,30 @@ function compareStrings(a, b) {
|
|
|
2049
2121
|
if (b === void 0) return 1;
|
|
2050
2122
|
return a < b ? -1 : 1;
|
|
2051
2123
|
}
|
|
2124
|
+
const REFERENTIAL_ACTION_SQL = {
|
|
2125
|
+
noAction: "NO ACTION",
|
|
2126
|
+
restrict: "RESTRICT",
|
|
2127
|
+
cascade: "CASCADE",
|
|
2128
|
+
setNull: "SET NULL",
|
|
2129
|
+
setDefault: "SET DEFAULT"
|
|
2130
|
+
};
|
|
2131
|
+
function buildForeignKeySql(schemaName, tableName, fkName, foreignKey) {
|
|
2132
|
+
let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
2133
|
+
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
2134
|
+
FOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(", ")})
|
|
2135
|
+
REFERENCES ${qualifyTableName(schemaName, foreignKey.references.table)} (${foreignKey.references.columns.map(quoteIdentifier).join(", ")})`;
|
|
2136
|
+
if (foreignKey.onDelete !== void 0) {
|
|
2137
|
+
const action = REFERENTIAL_ACTION_SQL[foreignKey.onDelete];
|
|
2138
|
+
if (!action) throw new Error(`Unknown referential action for onDelete: ${String(foreignKey.onDelete)}`);
|
|
2139
|
+
sql += `\nON DELETE ${action}`;
|
|
2140
|
+
}
|
|
2141
|
+
if (foreignKey.onUpdate !== void 0) {
|
|
2142
|
+
const action = REFERENTIAL_ACTION_SQL[foreignKey.onUpdate];
|
|
2143
|
+
if (!action) throw new Error(`Unknown referential action for onUpdate: ${String(foreignKey.onUpdate)}`);
|
|
2144
|
+
sql += `\nON UPDATE ${action}`;
|
|
2145
|
+
}
|
|
2146
|
+
return sql;
|
|
2147
|
+
}
|
|
2052
2148
|
|
|
2053
2149
|
//#endregion
|
|
2054
2150
|
//#region src/core/migrations/statement-builders.ts
|
|
@@ -2161,7 +2257,7 @@ function buildLedgerInsertStatement(input) {
|
|
|
2161
2257
|
};
|
|
2162
2258
|
}
|
|
2163
2259
|
function jsonParam(value) {
|
|
2164
|
-
return JSON.stringify(value ?? null);
|
|
2260
|
+
return JSON.stringify(value ?? null, bigintJsonReplacer);
|
|
2165
2261
|
}
|
|
2166
2262
|
|
|
2167
2263
|
//#endregion
|