@prisma-next/target-sqlite 0.5.0-dev.4 → 0.5.0-dev.42
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/codec-ids-B1-OiN8Q.mjs +14 -0
- package/dist/codec-ids-B1-OiN8Q.mjs.map +1 -0
- package/dist/codec-ids.d.mts +13 -0
- package/dist/codec-ids.d.mts.map +1 -0
- package/dist/codec-ids.mjs +3 -0
- package/dist/codec-types.d.mts +7 -0
- package/dist/codec-types.d.mts.map +1 -0
- package/dist/codec-types.mjs +3 -0
- package/dist/codecs-5GJysiEg.mjs +95 -0
- package/dist/codecs-5GJysiEg.mjs.map +1 -0
- package/dist/codecs-D4jgBM6T.d.mts +139 -0
- package/dist/codecs-D4jgBM6T.d.mts.map +1 -0
- package/dist/codecs.d.mts +2 -0
- package/dist/codecs.mjs +3 -0
- package/dist/control.d.mts +4 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +343 -1
- package/dist/control.mjs.map +1 -1
- package/dist/default-normalizer-R-sQXAYt.mjs +69 -0
- package/dist/default-normalizer-R-sQXAYt.mjs.map +1 -0
- package/dist/default-normalizer.d.mts +8 -0
- package/dist/default-normalizer.d.mts.map +1 -0
- package/dist/default-normalizer.mjs +3 -0
- package/dist/{descriptor-meta-DbuuziYA.mjs → descriptor-meta-CzGTszoH.mjs} +1 -1
- package/dist/descriptor-meta-CzGTszoH.mjs.map +1 -0
- package/dist/migration.d.mts +76 -0
- package/dist/migration.d.mts.map +1 -0
- package/dist/migration.mjs +38 -0
- package/dist/migration.mjs.map +1 -0
- package/dist/native-type-normalizer-BMovohPm.mjs +14 -0
- package/dist/native-type-normalizer-BMovohPm.mjs.map +1 -0
- package/dist/native-type-normalizer.d.mts +11 -0
- package/dist/native-type-normalizer.d.mts.map +1 -0
- package/dist/native-type-normalizer.mjs +3 -0
- package/dist/op-factory-call-BPPSCdTB.d.mts +134 -0
- package/dist/op-factory-call-BPPSCdTB.d.mts.map +1 -0
- package/dist/op-factory-call-BUVV-W9F.mjs +252 -0
- package/dist/op-factory-call-BUVV-W9F.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +3 -0
- package/dist/op-factory-call.mjs +3 -0
- package/dist/pack.d.mts +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-CuchCrpN.mjs +522 -0
- package/dist/planner-CuchCrpN.mjs.map +1 -0
- package/dist/planner-produced-sqlite-migration-C3AAaQoW.mjs +107 -0
- package/dist/planner-produced-sqlite-migration-C3AAaQoW.mjs.map +1 -0
- package/dist/planner-produced-sqlite-migration-RVneETNy.d.mts +24 -0
- package/dist/planner-produced-sqlite-migration-RVneETNy.d.mts.map +1 -0
- package/dist/planner-produced-sqlite-migration.d.mts +5 -0
- package/dist/planner-produced-sqlite-migration.mjs +3 -0
- package/dist/planner-target-details-BQIWQlBu.mjs +16 -0
- package/dist/planner-target-details-BQIWQlBu.mjs.map +1 -0
- package/dist/planner-target-details-DTIFFx4L.d.mts +12 -0
- package/dist/planner-target-details-DTIFFx4L.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +2 -0
- package/dist/planner-target-details.mjs +3 -0
- package/dist/planner.d.mts +56 -0
- package/dist/planner.d.mts.map +1 -0
- package/dist/planner.mjs +3 -0
- package/dist/render-ops-CXOv7SRC.mjs +8 -0
- package/dist/render-ops-CXOv7SRC.mjs.map +1 -0
- package/dist/render-ops.d.mts +11 -0
- package/dist/render-ops.d.mts.map +1 -0
- package/dist/render-ops.mjs +3 -0
- package/dist/runtime.mjs +1 -1
- package/dist/shared-BNtoZqdo.d.mts +69 -0
- package/dist/shared-BNtoZqdo.d.mts.map +1 -0
- package/dist/sql-utils-D3SMPFDD.mjs +33 -0
- package/dist/sql-utils-D3SMPFDD.mjs.map +1 -0
- package/dist/sql-utils.d.mts +22 -0
- package/dist/sql-utils.d.mts.map +1 -0
- package/dist/sql-utils.mjs +3 -0
- package/dist/sqlite-migration-BYgrMZdR.d.mts +18 -0
- package/dist/sqlite-migration-BYgrMZdR.d.mts.map +1 -0
- package/dist/sqlite-migration-CnLhIrJF.mjs +17 -0
- package/dist/sqlite-migration-CnLhIrJF.mjs.map +1 -0
- package/dist/statement-builders-B3OGOp7n.mjs +148 -0
- package/dist/statement-builders-B3OGOp7n.mjs.map +1 -0
- package/dist/statement-builders.d.mts +48 -0
- package/dist/statement-builders.d.mts.map +1 -0
- package/dist/statement-builders.mjs +3 -0
- package/dist/tables-sKIg_lWE.mjs +408 -0
- package/dist/tables-sKIg_lWE.mjs.map +1 -0
- package/package.json +30 -9
- package/src/core/codec-ids.ts +13 -0
- package/src/core/codecs.ts +119 -0
- package/src/core/control-target.ts +54 -11
- package/src/core/default-normalizer.ts +92 -0
- package/src/core/descriptor-meta.ts +1 -1
- package/src/core/migrations/issue-planner.ts +586 -0
- package/src/core/migrations/op-factory-call.ts +332 -0
- package/src/core/migrations/operations/columns.ts +62 -0
- package/src/core/migrations/operations/data-transform.ts +51 -0
- package/src/core/migrations/operations/indexes.ts +52 -0
- package/src/core/migrations/operations/shared.ts +120 -0
- package/src/core/migrations/operations/tables.ts +388 -0
- package/src/core/migrations/planner-ddl-builders.ts +142 -0
- package/src/core/migrations/planner-produced-sqlite-migration.ts +56 -0
- package/src/core/migrations/planner-strategies.ts +231 -0
- package/src/core/migrations/planner-target-details.ts +33 -0
- package/src/core/migrations/planner.ts +149 -0
- package/src/core/migrations/render-ops.ts +9 -0
- package/src/core/migrations/render-typescript.ts +91 -0
- package/src/core/migrations/runner.ts +593 -0
- package/src/core/migrations/sqlite-migration.ts +13 -0
- package/src/core/migrations/statement-builders.ts +190 -0
- package/src/core/native-type-normalizer.ts +9 -0
- package/src/core/sql-utils.ts +47 -0
- package/src/exports/codec-ids.ts +13 -0
- package/src/exports/codec-types.ts +6 -0
- package/src/exports/codecs.ts +1 -0
- package/src/exports/control.ts +1 -0
- package/src/exports/default-normalizer.ts +1 -0
- package/src/exports/migration.ts +23 -0
- package/src/exports/native-type-normalizer.ts +1 -0
- package/src/exports/op-factory-call.ts +11 -0
- package/src/exports/planner-produced-sqlite-migration.ts +4 -0
- package/src/exports/planner-target-details.ts +2 -0
- package/src/exports/planner.ts +2 -0
- package/src/exports/render-ops.ts +1 -0
- package/src/exports/sql-utils.ts +1 -0
- package/src/exports/statement-builders.ts +11 -0
- package/dist/descriptor-meta-DbuuziYA.mjs.map +0 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
//#region src/core/migrations/statement-builders.ts
|
|
2
|
+
const MARKER_TABLE_NAME = "_prisma_marker";
|
|
3
|
+
const LEDGER_TABLE_NAME = "_prisma_ledger";
|
|
4
|
+
/**
|
|
5
|
+
* Control tables the runner creates/manages. The planner must not drop these
|
|
6
|
+
* when reconciling "extra" tables against the contract.
|
|
7
|
+
*/
|
|
8
|
+
const CONTROL_TABLE_NAMES = new Set([MARKER_TABLE_NAME, LEDGER_TABLE_NAME]);
|
|
9
|
+
const ensureMarkerTableStatement = {
|
|
10
|
+
sql: `CREATE TABLE IF NOT EXISTS _prisma_marker (
|
|
11
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
12
|
+
core_hash TEXT NOT NULL,
|
|
13
|
+
profile_hash TEXT NOT NULL,
|
|
14
|
+
contract_json TEXT,
|
|
15
|
+
canonical_version INTEGER,
|
|
16
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
17
|
+
app_tag TEXT,
|
|
18
|
+
meta TEXT NOT NULL DEFAULT '{}',
|
|
19
|
+
invariants TEXT NOT NULL DEFAULT '[]'
|
|
20
|
+
)`,
|
|
21
|
+
params: []
|
|
22
|
+
};
|
|
23
|
+
const ensureLedgerTableStatement = {
|
|
24
|
+
sql: `CREATE TABLE IF NOT EXISTS _prisma_ledger (
|
|
25
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
26
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
27
|
+
origin_core_hash TEXT,
|
|
28
|
+
origin_profile_hash TEXT,
|
|
29
|
+
destination_core_hash TEXT NOT NULL,
|
|
30
|
+
destination_profile_hash TEXT,
|
|
31
|
+
contract_json_before TEXT,
|
|
32
|
+
contract_json_after TEXT,
|
|
33
|
+
operations TEXT NOT NULL
|
|
34
|
+
)`,
|
|
35
|
+
params: []
|
|
36
|
+
};
|
|
37
|
+
function readMarkerStatement() {
|
|
38
|
+
return {
|
|
39
|
+
sql: `SELECT
|
|
40
|
+
core_hash,
|
|
41
|
+
profile_hash,
|
|
42
|
+
contract_json,
|
|
43
|
+
canonical_version,
|
|
44
|
+
updated_at,
|
|
45
|
+
app_tag,
|
|
46
|
+
meta,
|
|
47
|
+
invariants
|
|
48
|
+
FROM _prisma_marker
|
|
49
|
+
WHERE id = ?`,
|
|
50
|
+
params: [1]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function buildWriteMarkerStatements(input) {
|
|
54
|
+
return {
|
|
55
|
+
insert: {
|
|
56
|
+
sql: `INSERT INTO _prisma_marker (
|
|
57
|
+
id,
|
|
58
|
+
core_hash,
|
|
59
|
+
profile_hash,
|
|
60
|
+
contract_json,
|
|
61
|
+
canonical_version,
|
|
62
|
+
updated_at,
|
|
63
|
+
app_tag,
|
|
64
|
+
meta,
|
|
65
|
+
invariants
|
|
66
|
+
) VALUES (
|
|
67
|
+
?,
|
|
68
|
+
?,
|
|
69
|
+
?,
|
|
70
|
+
?,
|
|
71
|
+
?,
|
|
72
|
+
datetime('now'),
|
|
73
|
+
?,
|
|
74
|
+
?,
|
|
75
|
+
?
|
|
76
|
+
)`,
|
|
77
|
+
params: [
|
|
78
|
+
1,
|
|
79
|
+
input.storageHash,
|
|
80
|
+
input.profileHash,
|
|
81
|
+
jsonParam(input.contractJson),
|
|
82
|
+
input.canonicalVersion ?? null,
|
|
83
|
+
input.appTag ?? null,
|
|
84
|
+
jsonParam(input.meta ?? {}),
|
|
85
|
+
jsonParam(input.invariants)
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
update: {
|
|
89
|
+
sql: `UPDATE _prisma_marker SET
|
|
90
|
+
core_hash = ?,
|
|
91
|
+
profile_hash = ?,
|
|
92
|
+
contract_json = ?,
|
|
93
|
+
canonical_version = ?,
|
|
94
|
+
updated_at = datetime('now'),
|
|
95
|
+
app_tag = ?,
|
|
96
|
+
meta = ?,
|
|
97
|
+
invariants = ?
|
|
98
|
+
WHERE id = ?`,
|
|
99
|
+
params: [
|
|
100
|
+
input.storageHash,
|
|
101
|
+
input.profileHash,
|
|
102
|
+
jsonParam(input.contractJson),
|
|
103
|
+
input.canonicalVersion ?? null,
|
|
104
|
+
input.appTag ?? null,
|
|
105
|
+
jsonParam(input.meta ?? {}),
|
|
106
|
+
jsonParam(input.invariants),
|
|
107
|
+
1
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function buildLedgerInsertStatement(input) {
|
|
113
|
+
return {
|
|
114
|
+
sql: `INSERT INTO _prisma_ledger (
|
|
115
|
+
origin_core_hash,
|
|
116
|
+
origin_profile_hash,
|
|
117
|
+
destination_core_hash,
|
|
118
|
+
destination_profile_hash,
|
|
119
|
+
contract_json_before,
|
|
120
|
+
contract_json_after,
|
|
121
|
+
operations
|
|
122
|
+
) VALUES (
|
|
123
|
+
?,
|
|
124
|
+
?,
|
|
125
|
+
?,
|
|
126
|
+
?,
|
|
127
|
+
?,
|
|
128
|
+
?,
|
|
129
|
+
?
|
|
130
|
+
)`,
|
|
131
|
+
params: [
|
|
132
|
+
input.originStorageHash ?? null,
|
|
133
|
+
input.originProfileHash ?? null,
|
|
134
|
+
input.destinationStorageHash,
|
|
135
|
+
input.destinationProfileHash ?? null,
|
|
136
|
+
jsonParam(input.contractJsonBefore),
|
|
137
|
+
jsonParam(input.contractJsonAfter),
|
|
138
|
+
jsonParam(input.operations)
|
|
139
|
+
]
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function jsonParam(value) {
|
|
143
|
+
return JSON.stringify(value ?? null);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { buildWriteMarkerStatements as a, readMarkerStatement as c, buildLedgerInsertStatement as i, LEDGER_TABLE_NAME as n, ensureLedgerTableStatement as o, MARKER_TABLE_NAME as r, ensureMarkerTableStatement as s, CONTROL_TABLE_NAMES as t };
|
|
148
|
+
//# sourceMappingURL=statement-builders-B3OGOp7n.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statement-builders-B3OGOp7n.mjs","names":["CONTROL_TABLE_NAMES: ReadonlySet<string>","ensureMarkerTableStatement: SqlStatement","ensureLedgerTableStatement: SqlStatement"],"sources":["../src/core/migrations/statement-builders.ts"],"sourcesContent":["export interface SqlStatement {\n readonly sql: string;\n readonly params: readonly unknown[];\n}\n\nexport const MARKER_TABLE_NAME = '_prisma_marker';\nexport const LEDGER_TABLE_NAME = '_prisma_ledger';\n\n/**\n * Control tables the runner creates/manages. The planner must not drop these\n * when reconciling \"extra\" tables against the contract.\n */\nexport const CONTROL_TABLE_NAMES: ReadonlySet<string> = new Set([\n MARKER_TABLE_NAME,\n LEDGER_TABLE_NAME,\n]);\n\nexport const ensureMarkerTableStatement: SqlStatement = {\n sql: `CREATE TABLE IF NOT EXISTS _prisma_marker (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n core_hash TEXT NOT NULL,\n profile_hash TEXT NOT NULL,\n contract_json TEXT,\n canonical_version INTEGER,\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n app_tag TEXT,\n meta TEXT NOT NULL DEFAULT '{}',\n invariants TEXT NOT NULL DEFAULT '[]'\n )`,\n params: [],\n};\n\nexport const ensureLedgerTableStatement: SqlStatement = {\n sql: `CREATE TABLE IF NOT EXISTS _prisma_ledger (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n origin_core_hash TEXT,\n origin_profile_hash TEXT,\n destination_core_hash TEXT NOT NULL,\n destination_profile_hash TEXT,\n contract_json_before TEXT,\n contract_json_after TEXT,\n operations TEXT NOT NULL\n )`,\n params: [],\n};\n\nexport function readMarkerStatement(): SqlStatement {\n return {\n sql: `SELECT\n core_hash,\n profile_hash,\n contract_json,\n canonical_version,\n updated_at,\n app_tag,\n meta,\n invariants\n FROM _prisma_marker\n WHERE id = ?`,\n params: [1],\n };\n}\n\nexport interface WriteMarkerInput {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly contractJson?: unknown;\n readonly canonicalVersion?: number | null;\n readonly appTag?: string | null;\n readonly meta?: Record<string, unknown>;\n /**\n * Invariants to write into `marker.invariants`. Stored as a JSON-encoded\n * TEXT array — SQLite has no native array type. The runner is responsible\n * for merging with the existing column (no SQL-side merge here, unlike\n * Postgres) before passing them in: BEGIN EXCLUSIVE on the migration\n * transaction makes the read-then-merge-then-write sequence safe.\n */\n readonly invariants: readonly string[];\n}\n\nexport function buildWriteMarkerStatements(input: WriteMarkerInput): {\n readonly insert: SqlStatement;\n readonly update: SqlStatement;\n} {\n const params: readonly unknown[] = [\n 1,\n input.storageHash,\n input.profileHash,\n jsonParam(input.contractJson),\n input.canonicalVersion ?? null,\n input.appTag ?? null,\n jsonParam(input.meta ?? {}),\n jsonParam(input.invariants),\n ];\n\n return {\n insert: {\n sql: `INSERT INTO _prisma_marker (\n id,\n core_hash,\n profile_hash,\n contract_json,\n canonical_version,\n updated_at,\n app_tag,\n meta,\n invariants\n ) VALUES (\n ?,\n ?,\n ?,\n ?,\n ?,\n datetime('now'),\n ?,\n ?,\n ?\n )`,\n params,\n },\n update: {\n sql: `UPDATE _prisma_marker SET\n core_hash = ?,\n profile_hash = ?,\n contract_json = ?,\n canonical_version = ?,\n updated_at = datetime('now'),\n app_tag = ?,\n meta = ?,\n invariants = ?\n WHERE id = ?`,\n params: [\n input.storageHash,\n input.profileHash,\n jsonParam(input.contractJson),\n input.canonicalVersion ?? null,\n input.appTag ?? null,\n jsonParam(input.meta ?? {}),\n jsonParam(input.invariants),\n 1,\n ],\n },\n };\n}\n\nexport interface LedgerInsertInput {\n readonly originStorageHash?: string | null;\n readonly originProfileHash?: string | null;\n readonly destinationStorageHash: string;\n readonly destinationProfileHash?: string | null;\n readonly contractJsonBefore?: unknown;\n readonly contractJsonAfter?: unknown;\n readonly operations: unknown;\n}\n\nexport function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStatement {\n return {\n sql: `INSERT INTO _prisma_ledger (\n origin_core_hash,\n origin_profile_hash,\n destination_core_hash,\n destination_profile_hash,\n contract_json_before,\n contract_json_after,\n operations\n ) VALUES (\n ?,\n ?,\n ?,\n ?,\n ?,\n ?,\n ?\n )`,\n params: [\n input.originStorageHash ?? null,\n input.originProfileHash ?? null,\n input.destinationStorageHash,\n input.destinationProfileHash ?? null,\n jsonParam(input.contractJsonBefore),\n jsonParam(input.contractJsonAfter),\n jsonParam(input.operations),\n ],\n };\n}\n\nfunction jsonParam(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":";AAKA,MAAa,oBAAoB;AACjC,MAAa,oBAAoB;;;;;AAMjC,MAAaA,sBAA2C,IAAI,IAAI,CAC9D,mBACA,kBACD,CAAC;AAEF,MAAaC,6BAA2C;CACtD,KAAK;;;;;;;;;;;CAWL,QAAQ,EAAE;CACX;AAED,MAAaC,6BAA2C;CACtD,KAAK;;;;;;;;;;;CAWL,QAAQ,EAAE;CACX;AAED,SAAgB,sBAAoC;AAClD,QAAO;EACL,KAAK;;;;;;;;;;;EAWL,QAAQ,CAAC,EAAE;EACZ;;AAoBH,SAAgB,2BAA2B,OAGzC;AAYA,QAAO;EACL,QAAQ;GACN,KAAK;;;;;;;;;;;;;;;;;;;;;GAqBL,QAlC+B;IACjC;IACA,MAAM;IACN,MAAM;IACN,UAAU,MAAM,aAAa;IAC7B,MAAM,oBAAoB;IAC1B,MAAM,UAAU;IAChB,UAAU,MAAM,QAAQ,EAAE,CAAC;IAC3B,UAAU,MAAM,WAAW;IAC5B;GA0BE;EACD,QAAQ;GACN,KAAK;;;;;;;;;;GAUL,QAAQ;IACN,MAAM;IACN,MAAM;IACN,UAAU,MAAM,aAAa;IAC7B,MAAM,oBAAoB;IAC1B,MAAM,UAAU;IAChB,UAAU,MAAM,QAAQ,EAAE,CAAC;IAC3B,UAAU,MAAM,WAAW;IAC3B;IACD;GACF;EACF;;AAaH,SAAgB,2BAA2B,OAAwC;AACjF,QAAO;EACL,KAAK;;;;;;;;;;;;;;;;;EAiBL,QAAQ;GACN,MAAM,qBAAqB;GAC3B,MAAM,qBAAqB;GAC3B,MAAM;GACN,MAAM,0BAA0B;GAChC,UAAU,MAAM,mBAAmB;GACnC,UAAU,MAAM,kBAAkB;GAClC,UAAU,MAAM,WAAW;GAC5B;EACF;;AAGH,SAAS,UAAU,OAAwB;AACzC,QAAO,KAAK,UAAU,SAAS,KAAK"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/core/migrations/statement-builders.d.ts
|
|
2
|
+
interface SqlStatement {
|
|
3
|
+
readonly sql: string;
|
|
4
|
+
readonly params: readonly unknown[];
|
|
5
|
+
}
|
|
6
|
+
declare const MARKER_TABLE_NAME = "_prisma_marker";
|
|
7
|
+
declare const LEDGER_TABLE_NAME = "_prisma_ledger";
|
|
8
|
+
/**
|
|
9
|
+
* Control tables the runner creates/manages. The planner must not drop these
|
|
10
|
+
* when reconciling "extra" tables against the contract.
|
|
11
|
+
*/
|
|
12
|
+
declare const CONTROL_TABLE_NAMES: ReadonlySet<string>;
|
|
13
|
+
declare const ensureMarkerTableStatement: SqlStatement;
|
|
14
|
+
declare const ensureLedgerTableStatement: SqlStatement;
|
|
15
|
+
declare function readMarkerStatement(): SqlStatement;
|
|
16
|
+
interface WriteMarkerInput {
|
|
17
|
+
readonly storageHash: string;
|
|
18
|
+
readonly profileHash: string;
|
|
19
|
+
readonly contractJson?: unknown;
|
|
20
|
+
readonly canonicalVersion?: number | null;
|
|
21
|
+
readonly appTag?: string | null;
|
|
22
|
+
readonly meta?: Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Invariants to write into `marker.invariants`. Stored as a JSON-encoded
|
|
25
|
+
* TEXT array — SQLite has no native array type. The runner is responsible
|
|
26
|
+
* for merging with the existing column (no SQL-side merge here, unlike
|
|
27
|
+
* Postgres) before passing them in: BEGIN EXCLUSIVE on the migration
|
|
28
|
+
* transaction makes the read-then-merge-then-write sequence safe.
|
|
29
|
+
*/
|
|
30
|
+
readonly invariants: readonly string[];
|
|
31
|
+
}
|
|
32
|
+
declare function buildWriteMarkerStatements(input: WriteMarkerInput): {
|
|
33
|
+
readonly insert: SqlStatement;
|
|
34
|
+
readonly update: SqlStatement;
|
|
35
|
+
};
|
|
36
|
+
interface LedgerInsertInput {
|
|
37
|
+
readonly originStorageHash?: string | null;
|
|
38
|
+
readonly originProfileHash?: string | null;
|
|
39
|
+
readonly destinationStorageHash: string;
|
|
40
|
+
readonly destinationProfileHash?: string | null;
|
|
41
|
+
readonly contractJsonBefore?: unknown;
|
|
42
|
+
readonly contractJsonAfter?: unknown;
|
|
43
|
+
readonly operations: unknown;
|
|
44
|
+
}
|
|
45
|
+
declare function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStatement;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { CONTROL_TABLE_NAMES, LEDGER_TABLE_NAME, MARKER_TABLE_NAME, type SqlStatement, buildLedgerInsertStatement, buildWriteMarkerStatements, ensureLedgerTableStatement, ensureMarkerTableStatement, readMarkerStatement };
|
|
48
|
+
//# sourceMappingURL=statement-builders.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statement-builders.d.mts","names":[],"sources":["../src/core/migrations/statement-builders.ts"],"sourcesContent":[],"mappings":";UAAiB,YAAA;EAAA,SAAA,GAAA,EAAA,MAAY;EAKhB,SAAA,MAAA,EAAA,SAAiB,OAAA,EAAA;AAC9B;AAMa,cAPA,iBAAA,GAOqB,gBAAW;AAKhC,cAXA,iBAAA,GAwBZ,gBAbwC;AAezC;AAeA;AAiBA;AAiBA;AAAkD,cArErC,mBAqEqC,EArEhB,WAqEgB,CAAA,MAAA,CAAA;AAC/B,cAjEN,0BAiEM,EAjEsB,YAiEtB;AACA,cAnDN,0BAmDM,EAnDsB,YAmDtB;AAAY,iBApCf,mBAAA,CAAA,CAoCe,EApCQ,YAoCR;AA+Dd,UAlFA,gBAAA,CAkFiB;EAUlB,SAAA,WAAA,EAAA,MAAA;;;;;kBAtFE;;;;;;;;;;iBAWF,0BAAA,QAAkC;mBAC/B;mBACA;;UA+DF,iBAAA;;;;;;;;;iBAUD,0BAAA,QAAkC,oBAAoB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as buildWriteMarkerStatements, c as readMarkerStatement, i as buildLedgerInsertStatement, n as LEDGER_TABLE_NAME, o as ensureLedgerTableStatement, r as MARKER_TABLE_NAME, s as ensureMarkerTableStatement, t as CONTROL_TABLE_NAMES } from "./statement-builders-B3OGOp7n.mjs";
|
|
2
|
+
|
|
3
|
+
export { CONTROL_TABLE_NAMES, LEDGER_TABLE_NAME, MARKER_TABLE_NAME, buildLedgerInsertStatement, buildWriteMarkerStatements, ensureLedgerTableStatement, ensureMarkerTableStatement, readMarkerStatement };
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { n as stripOuterParens } from "./default-normalizer-R-sQXAYt.mjs";
|
|
2
|
+
import { n as escapeLiteral, r as quoteIdentifier } from "./sql-utils-D3SMPFDD.mjs";
|
|
3
|
+
import { t as buildTargetDetails } from "./planner-target-details-BQIWQlBu.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/core/migrations/operations/shared.ts
|
|
6
|
+
function step(description, sql) {
|
|
7
|
+
return {
|
|
8
|
+
description,
|
|
9
|
+
sql
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const REFERENTIAL_ACTION_SQL = {
|
|
13
|
+
noAction: "NO ACTION",
|
|
14
|
+
restrict: "RESTRICT",
|
|
15
|
+
cascade: "CASCADE",
|
|
16
|
+
setNull: "SET NULL",
|
|
17
|
+
setDefault: "SET DEFAULT"
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Renders a single column's inline DDL fragment within a `CREATE TABLE`
|
|
21
|
+
* statement. Honours the `inlineAutoincrementPrimaryKey` flag — SQLite
|
|
22
|
+
* treats `INTEGER PRIMARY KEY AUTOINCREMENT` as a special form that aliases
|
|
23
|
+
* `rowid`, and the column must not carry a `DEFAULT` or repeat `NOT NULL`.
|
|
24
|
+
*/
|
|
25
|
+
function renderColumnDefinition(column) {
|
|
26
|
+
const parts = [quoteIdentifier(column.name), column.typeSql];
|
|
27
|
+
if (column.inlineAutoincrementPrimaryKey) parts.push("PRIMARY KEY AUTOINCREMENT");
|
|
28
|
+
else {
|
|
29
|
+
if (column.defaultSql) parts.push(column.defaultSql);
|
|
30
|
+
if (!column.nullable) parts.push("NOT NULL");
|
|
31
|
+
}
|
|
32
|
+
return parts.join(" ");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Renders an inline FOREIGN KEY constraint clause for a `CREATE TABLE`
|
|
36
|
+
* body. Returns the empty string when `constraint` is false (the FK is
|
|
37
|
+
* tracked at the contract level for index-creation purposes only and must
|
|
38
|
+
* not produce DDL).
|
|
39
|
+
*/
|
|
40
|
+
function renderForeignKeyClause(fk) {
|
|
41
|
+
if (!fk.constraint) return "";
|
|
42
|
+
let sql = `${fk.name ? `CONSTRAINT ${quoteIdentifier(fk.name)} ` : ""}FOREIGN KEY (${fk.columns.map(quoteIdentifier).join(", ")}) REFERENCES ${quoteIdentifier(fk.references.table)} (${fk.references.columns.map(quoteIdentifier).join(", ")})`;
|
|
43
|
+
if (fk.onDelete !== void 0) sql += ` ON DELETE ${REFERENTIAL_ACTION_SQL[fk.onDelete]}`;
|
|
44
|
+
if (fk.onUpdate !== void 0) sql += ` ON UPDATE ${REFERENTIAL_ACTION_SQL[fk.onUpdate]}`;
|
|
45
|
+
return sql;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/core/migrations/operations/columns.ts
|
|
50
|
+
function addColumn(tableName, column) {
|
|
51
|
+
const addSql = [
|
|
52
|
+
`ALTER TABLE ${quoteIdentifier(tableName)}`,
|
|
53
|
+
`ADD COLUMN ${quoteIdentifier(column.name)} ${column.typeSql}`,
|
|
54
|
+
column.defaultSql,
|
|
55
|
+
column.nullable ? "" : "NOT NULL"
|
|
56
|
+
].filter(Boolean).join(" ");
|
|
57
|
+
return {
|
|
58
|
+
id: `column.${tableName}.${column.name}`,
|
|
59
|
+
label: `Add column ${column.name} on ${tableName}`,
|
|
60
|
+
summary: `Adds column ${column.name} on ${tableName}`,
|
|
61
|
+
operationClass: "additive",
|
|
62
|
+
target: {
|
|
63
|
+
id: "sqlite",
|
|
64
|
+
details: buildTargetDetails("column", column.name, tableName)
|
|
65
|
+
},
|
|
66
|
+
precheck: [step(`ensure column "${column.name}" is missing`, `SELECT COUNT(*) = 0 FROM pragma_table_info('${escapeLiteral(tableName)}') WHERE name = '${escapeLiteral(column.name)}'`)],
|
|
67
|
+
execute: [step(`add column "${column.name}"`, addSql)],
|
|
68
|
+
postcheck: [step(`verify column "${column.name}" exists`, `SELECT COUNT(*) > 0 FROM pragma_table_info('${escapeLiteral(tableName)}') WHERE name = '${escapeLiteral(column.name)}'`)]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function dropColumn(tableName, columnName) {
|
|
72
|
+
return {
|
|
73
|
+
id: `dropColumn.${tableName}.${columnName}`,
|
|
74
|
+
label: `Drop column ${columnName} on ${tableName}`,
|
|
75
|
+
summary: `Drops column ${columnName} on ${tableName} which is not in the contract`,
|
|
76
|
+
operationClass: "destructive",
|
|
77
|
+
target: {
|
|
78
|
+
id: "sqlite",
|
|
79
|
+
details: buildTargetDetails("column", columnName, tableName)
|
|
80
|
+
},
|
|
81
|
+
precheck: [step(`ensure column "${columnName}" exists on "${tableName}"`, `SELECT COUNT(*) > 0 FROM pragma_table_info('${escapeLiteral(tableName)}') WHERE name = '${escapeLiteral(columnName)}'`)],
|
|
82
|
+
execute: [step(`drop column "${columnName}" from "${tableName}"`, `ALTER TABLE ${quoteIdentifier(tableName)} DROP COLUMN ${quoteIdentifier(columnName)}`)],
|
|
83
|
+
postcheck: [step(`verify column "${columnName}" is gone from "${tableName}"`, `SELECT COUNT(*) = 0 FROM pragma_table_info('${escapeLiteral(tableName)}') WHERE name = '${escapeLiteral(columnName)}'`)]
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/core/migrations/planner-ddl-builders.ts
|
|
89
|
+
const SAFE_NATIVE_TYPE_PATTERN = /^[a-zA-Z][a-zA-Z0-9_ ]*$/;
|
|
90
|
+
function assertSafeNativeType(nativeType) {
|
|
91
|
+
if (!SAFE_NATIVE_TYPE_PATTERN.test(nativeType)) throw new Error(`Unsafe native type name in contract: "${nativeType}". Native type names must match /^[a-zA-Z][a-zA-Z0-9_ ]*\$/`);
|
|
92
|
+
}
|
|
93
|
+
function assertSafeDefaultExpression(expression) {
|
|
94
|
+
if (expression.includes(";") || /--|\/\*|\bSELECT\b/i.test(expression)) throw new Error(`Unsafe default expression in contract: "${expression}". Default expressions must not contain semicolons, SQL comment tokens, or subqueries.`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Renders the column's DDL type token (e.g. `"INTEGER"`, `"TEXT"`).
|
|
98
|
+
* Resolves `typeRef` against `storageTypes` and validates the resulting
|
|
99
|
+
* native type against a safe-identifier pattern.
|
|
100
|
+
*/
|
|
101
|
+
function buildColumnTypeSql(column, storageTypes = {}) {
|
|
102
|
+
const resolved = resolveColumnTypeMetadata(column, storageTypes);
|
|
103
|
+
assertSafeNativeType(resolved.nativeType);
|
|
104
|
+
return resolved.nativeType.toUpperCase();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Renders the column's `DEFAULT …` clause. Returns the empty string when
|
|
108
|
+
* there is no default, and also when the default is `autoincrement()` —
|
|
109
|
+
* SQLite encodes that as `INTEGER PRIMARY KEY AUTOINCREMENT` inline on the
|
|
110
|
+
* column definition, not as a separate DEFAULT.
|
|
111
|
+
*/
|
|
112
|
+
function buildColumnDefaultSql(columnDefault) {
|
|
113
|
+
if (!columnDefault) return "";
|
|
114
|
+
switch (columnDefault.kind) {
|
|
115
|
+
case "literal": return `DEFAULT ${renderDefaultLiteral(columnDefault.value)}`;
|
|
116
|
+
case "function":
|
|
117
|
+
if (columnDefault.expression === "autoincrement()") return "";
|
|
118
|
+
if (columnDefault.expression === "now()") return "DEFAULT (datetime('now'))";
|
|
119
|
+
assertSafeDefaultExpression(columnDefault.expression);
|
|
120
|
+
return `DEFAULT (${columnDefault.expression})`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function renderDefaultLiteral(value) {
|
|
124
|
+
if (value instanceof Date) return `'${escapeLiteral(value.toISOString())}'`;
|
|
125
|
+
if (typeof value === "string") return `'${escapeLiteral(value)}'`;
|
|
126
|
+
if (typeof value === "number" || typeof value === "bigint") return String(value);
|
|
127
|
+
if (typeof value === "boolean") return value ? "1" : "0";
|
|
128
|
+
if (value === null) return "NULL";
|
|
129
|
+
return `'${escapeLiteral(JSON.stringify(value))}'`;
|
|
130
|
+
}
|
|
131
|
+
function buildCreateIndexSql(tableName, indexName, columns, unique = false) {
|
|
132
|
+
return `CREATE ${unique ? "UNIQUE " : ""}INDEX ${quoteIdentifier(indexName)} ON ${quoteIdentifier(tableName)} (${columns.map(quoteIdentifier).join(", ")})`;
|
|
133
|
+
}
|
|
134
|
+
function buildDropIndexSql(indexName) {
|
|
135
|
+
return `DROP INDEX IF EXISTS ${quoteIdentifier(indexName)}`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* True when the column is rendered inline as `INTEGER PRIMARY KEY
|
|
139
|
+
* AUTOINCREMENT`. Requires the column's default to be `autoincrement()` and
|
|
140
|
+
* the column to be the sole member of the table's primary key — anything
|
|
141
|
+
* else falls back to a separate PRIMARY KEY constraint with a default
|
|
142
|
+
* AUTOINCREMENT semantics expressed elsewhere.
|
|
143
|
+
*/
|
|
144
|
+
function isInlineAutoincrementPrimaryKey(table, columnName) {
|
|
145
|
+
if (table.primaryKey?.columns.length !== 1) return false;
|
|
146
|
+
if (table.primaryKey.columns[0] !== columnName) return false;
|
|
147
|
+
const column = table.columns[columnName];
|
|
148
|
+
return column?.default?.kind === "function" && column.default.expression === "autoincrement()";
|
|
149
|
+
}
|
|
150
|
+
function resolveColumnTypeMetadata(column, storageTypes) {
|
|
151
|
+
if (!column.typeRef) return column;
|
|
152
|
+
const referencedType = storageTypes[column.typeRef];
|
|
153
|
+
if (!referencedType) throw new Error(`Storage type "${column.typeRef}" referenced by column is not defined in storage.types.`);
|
|
154
|
+
return {
|
|
155
|
+
codecId: referencedType.codecId,
|
|
156
|
+
nativeType: referencedType.nativeType,
|
|
157
|
+
typeParams: referencedType.typeParams
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/core/migrations/operations/indexes.ts
|
|
163
|
+
function createIndex(tableName, indexName, columns) {
|
|
164
|
+
return {
|
|
165
|
+
id: `index.${tableName}.${indexName}`,
|
|
166
|
+
label: `Create index ${indexName} on ${tableName}`,
|
|
167
|
+
summary: `Creates index ${indexName} on ${tableName}`,
|
|
168
|
+
operationClass: "additive",
|
|
169
|
+
target: {
|
|
170
|
+
id: "sqlite",
|
|
171
|
+
details: buildTargetDetails("index", indexName, tableName)
|
|
172
|
+
},
|
|
173
|
+
precheck: [step(`ensure index "${indexName}" is missing`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'index' AND name = '${escapeLiteral(indexName)}'`)],
|
|
174
|
+
execute: [step(`create index "${indexName}"`, buildCreateIndexSql(tableName, indexName, columns))],
|
|
175
|
+
postcheck: [step(`verify index "${indexName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'index' AND name = '${escapeLiteral(indexName)}'`)]
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function dropIndex(tableName, indexName) {
|
|
179
|
+
return {
|
|
180
|
+
id: `dropIndex.${tableName}.${indexName}`,
|
|
181
|
+
label: `Drop index ${indexName} on ${tableName}`,
|
|
182
|
+
summary: `Drops index ${indexName} on ${tableName} which is not in the contract`,
|
|
183
|
+
operationClass: "destructive",
|
|
184
|
+
target: {
|
|
185
|
+
id: "sqlite",
|
|
186
|
+
details: buildTargetDetails("index", indexName, tableName)
|
|
187
|
+
},
|
|
188
|
+
precheck: [step(`ensure index "${indexName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'index' AND name = '${escapeLiteral(indexName)}'`)],
|
|
189
|
+
execute: [step(`drop index "${indexName}"`, buildDropIndexSql(indexName))],
|
|
190
|
+
postcheck: [step(`verify index "${indexName}" is gone`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'index' AND name = '${escapeLiteral(indexName)}'`)]
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/core/migrations/operations/tables.ts
|
|
196
|
+
/**
|
|
197
|
+
* Renders the body of a `CREATE TABLE <name> ( … )` statement from a flat
|
|
198
|
+
* `SqliteTableSpec`. SQLite's `INTEGER PRIMARY KEY AUTOINCREMENT` form is
|
|
199
|
+
* inline on the column; the table-level PRIMARY KEY clause is emitted only
|
|
200
|
+
* when no column carries `inlineAutoincrementPrimaryKey`.
|
|
201
|
+
*/
|
|
202
|
+
function renderCreateTableSql(tableName, spec) {
|
|
203
|
+
const columnDefs = spec.columns.map(renderColumnDefinition);
|
|
204
|
+
const constraintDefs = [];
|
|
205
|
+
const hasInlinePk = spec.columns.some((c) => c.inlineAutoincrementPrimaryKey);
|
|
206
|
+
if (spec.primaryKey && !hasInlinePk) constraintDefs.push(`PRIMARY KEY (${spec.primaryKey.columns.map(quoteIdentifier).join(", ")})`);
|
|
207
|
+
for (const u of spec.uniques ?? []) {
|
|
208
|
+
const name = u.name ? `CONSTRAINT ${quoteIdentifier(u.name)} ` : "";
|
|
209
|
+
constraintDefs.push(`${name}UNIQUE (${u.columns.map(quoteIdentifier).join(", ")})`);
|
|
210
|
+
}
|
|
211
|
+
for (const fk of spec.foreignKeys ?? []) {
|
|
212
|
+
const clause = renderForeignKeyClause(fk);
|
|
213
|
+
if (clause) constraintDefs.push(clause);
|
|
214
|
+
}
|
|
215
|
+
const allDefs = [...columnDefs, ...constraintDefs];
|
|
216
|
+
return `CREATE TABLE ${quoteIdentifier(tableName)} (\n ${allDefs.join(",\n ")}\n)`;
|
|
217
|
+
}
|
|
218
|
+
function createTable(tableName, spec) {
|
|
219
|
+
return {
|
|
220
|
+
id: `table.${tableName}`,
|
|
221
|
+
label: `Create table ${tableName}`,
|
|
222
|
+
summary: `Creates table ${tableName} with required columns`,
|
|
223
|
+
operationClass: "additive",
|
|
224
|
+
target: {
|
|
225
|
+
id: "sqlite",
|
|
226
|
+
details: buildTargetDetails("table", tableName)
|
|
227
|
+
},
|
|
228
|
+
precheck: [step(`ensure table "${tableName}" does not exist`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`)],
|
|
229
|
+
execute: [step(`create table "${tableName}"`, renderCreateTableSql(tableName, spec))],
|
|
230
|
+
postcheck: [step(`verify table "${tableName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`)]
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function dropTable(tableName) {
|
|
234
|
+
return {
|
|
235
|
+
id: `dropTable.${tableName}`,
|
|
236
|
+
label: `Drop table ${tableName}`,
|
|
237
|
+
summary: `Drops table ${tableName} which is not in the contract`,
|
|
238
|
+
operationClass: "destructive",
|
|
239
|
+
target: {
|
|
240
|
+
id: "sqlite",
|
|
241
|
+
details: buildTargetDetails("table", tableName)
|
|
242
|
+
},
|
|
243
|
+
precheck: [step(`ensure table "${tableName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`)],
|
|
244
|
+
execute: [step(`drop table "${tableName}"`, `DROP TABLE ${quoteIdentifier(tableName)}`)],
|
|
245
|
+
postcheck: [step(`verify table "${tableName}" is gone`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`)]
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function recreateTable(args) {
|
|
249
|
+
const { tableName, contractTable, schemaColumnNames, indexes, summary, postchecks, operationClass } = args;
|
|
250
|
+
const tempName = `_prisma_new_${tableName}`;
|
|
251
|
+
const liveSet = new Set(schemaColumnNames);
|
|
252
|
+
const sharedColumns = contractTable.columns.filter((c) => liveSet.has(c.name)).map((c) => c.name);
|
|
253
|
+
const columnList = sharedColumns.map(quoteIdentifier).join(", ");
|
|
254
|
+
const indexStatements = indexes.map((idx) => ({
|
|
255
|
+
description: `recreate index "${idx.name}" on "${tableName}"`,
|
|
256
|
+
sql: buildCreateIndexSql(tableName, idx.name, idx.columns)
|
|
257
|
+
}));
|
|
258
|
+
const copyStep = sharedColumns.length > 0 ? [step(`copy data from "${tableName}" to "${tempName}"`, `INSERT INTO ${quoteIdentifier(tempName)} (${columnList}) SELECT ${columnList} FROM ${quoteIdentifier(tableName)}`)] : [];
|
|
259
|
+
return {
|
|
260
|
+
id: `recreateTable.${tableName}`,
|
|
261
|
+
label: `Recreate table ${tableName}`,
|
|
262
|
+
summary,
|
|
263
|
+
operationClass,
|
|
264
|
+
target: {
|
|
265
|
+
id: "sqlite",
|
|
266
|
+
details: buildTargetDetails("table", tableName)
|
|
267
|
+
},
|
|
268
|
+
precheck: [step(`ensure table "${tableName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`), step(`ensure temp table "${tempName}" does not exist`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tempName)}'`)],
|
|
269
|
+
execute: [
|
|
270
|
+
step(`create new table "${tempName}" with desired schema`, renderCreateTableSql(tempName, contractTable)),
|
|
271
|
+
...copyStep,
|
|
272
|
+
step(`drop old table "${tableName}"`, `DROP TABLE ${quoteIdentifier(tableName)}`),
|
|
273
|
+
step(`rename "${tempName}" to "${tableName}"`, `ALTER TABLE ${quoteIdentifier(tempName)} RENAME TO ${quoteIdentifier(tableName)}`),
|
|
274
|
+
...indexStatements
|
|
275
|
+
],
|
|
276
|
+
postcheck: [
|
|
277
|
+
step(`verify table "${tableName}" exists`, `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tableName)}'`),
|
|
278
|
+
step(`verify temp table "${tempName}" is gone`, `SELECT COUNT(*) = 0 FROM sqlite_master WHERE type = 'table' AND name = '${escapeLiteral(tempName)}'`),
|
|
279
|
+
...postchecks
|
|
280
|
+
]
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Build a one-line summary of a recreate-table operation from the schema
|
|
285
|
+
* issues that triggered it. Lives next to `recreateTable` so the planner
|
|
286
|
+
* (which has the issues) can produce the same description the factory
|
|
287
|
+
* used to build inline. Keeping the formatting target-side keeps
|
|
288
|
+
* `RecreateTableCall` issue-free at the IR layer.
|
|
289
|
+
*/
|
|
290
|
+
function buildRecreateSummary(tableName, issues) {
|
|
291
|
+
return `Recreates table ${tableName} to apply schema changes: ${issues.map((i) => i.message).join("; ")}`;
|
|
292
|
+
}
|
|
293
|
+
const COLUMN_LEVEL_ISSUE_KINDS = new Set([
|
|
294
|
+
"nullability_mismatch",
|
|
295
|
+
"default_mismatch",
|
|
296
|
+
"default_missing",
|
|
297
|
+
"extra_default",
|
|
298
|
+
"type_mismatch"
|
|
299
|
+
]);
|
|
300
|
+
const PK_ISSUE_KINDS = new Set(["primary_key_mismatch", "extra_primary_key"]);
|
|
301
|
+
const UNIQUE_ISSUE_KINDS = new Set(["unique_constraint_mismatch", "extra_unique_constraint"]);
|
|
302
|
+
const FK_ISSUE_KINDS = new Set(["foreign_key_mismatch", "extra_foreign_key"]);
|
|
303
|
+
/**
|
|
304
|
+
* Returns the columns the contract expects as the table's primary key. Picks
|
|
305
|
+
* up SQLite's inline `INTEGER PRIMARY KEY AUTOINCREMENT` form when no
|
|
306
|
+
* explicit `primaryKey` clause is set on the spec.
|
|
307
|
+
*/
|
|
308
|
+
function expectedPrimaryKeyColumns(spec) {
|
|
309
|
+
if (spec.primaryKey) return spec.primaryKey.columns;
|
|
310
|
+
const inlinePk = spec.columns.find((c) => c.inlineAutoincrementPrimaryKey);
|
|
311
|
+
return inlinePk ? [inlinePk.name] : [];
|
|
312
|
+
}
|
|
313
|
+
function quoteSqlList(values) {
|
|
314
|
+
return values.map((v) => `'${escapeLiteral(v)}'`).join(", ");
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Per-issue postchecks verifying the recreated table's shape against the
|
|
318
|
+
* contract spec. Column-level issues (`nullability_mismatch`,
|
|
319
|
+
* `default_mismatch`, …) emit one targeted check each; constraint-level
|
|
320
|
+
* issues (`primary_key_mismatch`, `unique_constraint_mismatch`,
|
|
321
|
+
* `foreign_key_mismatch`, plus their `extra_*` siblings) emit one
|
|
322
|
+
* `pragma_*`-driven check per declared constraint in the contract spec, so
|
|
323
|
+
* a recreated table with the right columns but the wrong PK / unique / FK
|
|
324
|
+
* shape fails the postcheck instead of passing silently. Exported so the
|
|
325
|
+
* planner can pre-build the list at construction time and
|
|
326
|
+
* `RecreateTableCall` doesn't have to carry `SchemaIssue` objects through
|
|
327
|
+
* to render time.
|
|
328
|
+
*/
|
|
329
|
+
function buildRecreatePostchecks(tableName, issues, spec) {
|
|
330
|
+
const checks = [];
|
|
331
|
+
const t = escapeLiteral(tableName);
|
|
332
|
+
const byName = new Map(spec.columns.map((c) => [c.name, c]));
|
|
333
|
+
for (const issue of issues) {
|
|
334
|
+
if (issue.kind === "enum_values_changed") continue;
|
|
335
|
+
if (!COLUMN_LEVEL_ISSUE_KINDS.has(issue.kind)) continue;
|
|
336
|
+
if (!issue.column) continue;
|
|
337
|
+
const c = escapeLiteral(issue.column);
|
|
338
|
+
if (issue.kind === "nullability_mismatch") {
|
|
339
|
+
let wantNotNull;
|
|
340
|
+
if (issue.expected === "false") wantNotNull = true;
|
|
341
|
+
else if (issue.expected === "true") wantNotNull = false;
|
|
342
|
+
if (wantNotNull !== void 0) checks.push({
|
|
343
|
+
description: `verify "${issue.column}" nullability on "${tableName}"`,
|
|
344
|
+
sql: `SELECT COUNT(*) > 0 FROM pragma_table_info('${t}') WHERE name = '${c}' AND "notnull" = ${wantNotNull ? 1 : 0}`
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
if (issue.kind === "default_mismatch" || issue.kind === "default_missing") {
|
|
348
|
+
const colSpec = byName.get(issue.column);
|
|
349
|
+
const expectedRaw = colSpec?.defaultSql.startsWith("DEFAULT ") ? stripOuterParens(colSpec.defaultSql.slice(8)) : null;
|
|
350
|
+
if (expectedRaw) checks.push({
|
|
351
|
+
description: `verify "${issue.column}" default on "${tableName}"`,
|
|
352
|
+
sql: `SELECT COUNT(*) > 0 FROM pragma_table_info('${t}') WHERE name = '${c}' AND dflt_value = '${escapeLiteral(expectedRaw)}'`
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (issue.kind === "type_mismatch") {
|
|
356
|
+
const colSpec = byName.get(issue.column);
|
|
357
|
+
if (colSpec) checks.push({
|
|
358
|
+
description: `verify "${issue.column}" type on "${tableName}"`,
|
|
359
|
+
sql: `SELECT COUNT(*) > 0 FROM pragma_table_info('${t}') WHERE name = '${c}' AND LOWER(type) = '${escapeLiteral(colSpec.typeSql.toLowerCase())}'`
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (issue.kind === "extra_default") checks.push({
|
|
363
|
+
description: `verify "${issue.column}" has no default on "${tableName}"`,
|
|
364
|
+
sql: `SELECT COUNT(*) > 0 FROM pragma_table_info('${t}') WHERE name = '${c}' AND dflt_value IS NULL`
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
const hasPkIssue = issues.some((i) => PK_ISSUE_KINDS.has(i.kind));
|
|
368
|
+
const hasUniqueIssue = issues.some((i) => UNIQUE_ISSUE_KINDS.has(i.kind));
|
|
369
|
+
const hasFkIssue = issues.some((i) => FK_ISSUE_KINDS.has(i.kind));
|
|
370
|
+
if (hasPkIssue) {
|
|
371
|
+
const pkColumns = expectedPrimaryKeyColumns(spec);
|
|
372
|
+
const colCount = pkColumns.length;
|
|
373
|
+
if (colCount === 0) checks.push({
|
|
374
|
+
description: `verify "${tableName}" has no primary key`,
|
|
375
|
+
sql: `SELECT (SELECT COUNT(*) FROM pragma_table_info('${t}') WHERE pk > 0) = 0`
|
|
376
|
+
});
|
|
377
|
+
else checks.push({
|
|
378
|
+
description: `verify primary key on "${tableName}"`,
|
|
379
|
+
sql: `SELECT (SELECT COUNT(*) FROM pragma_table_info('${t}') WHERE pk > 0) = ${colCount} AND (SELECT COUNT(*) FROM pragma_table_info('${t}') WHERE pk > 0 AND name IN (${quoteSqlList(pkColumns)})) = ${colCount}`
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (hasUniqueIssue) for (const u of spec.uniques ?? []) {
|
|
383
|
+
const colCount = u.columns.length;
|
|
384
|
+
const description = u.name ? `verify unique constraint "${u.name}" on "${tableName}"` : `verify unique constraint (${u.columns.join(", ")}) on "${tableName}"`;
|
|
385
|
+
checks.push({
|
|
386
|
+
description,
|
|
387
|
+
sql: `SELECT EXISTS (SELECT 1 FROM pragma_index_list('${t}') l WHERE l."unique" = 1 AND (SELECT COUNT(*) FROM pragma_index_info(l.name)) = ${colCount} AND (SELECT COUNT(*) FROM pragma_index_info(l.name) WHERE name IN (${quoteSqlList(u.columns)})) = ${colCount})`
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (hasFkIssue) for (const fk of spec.foreignKeys ?? []) {
|
|
391
|
+
const refTable = escapeLiteral(fk.references.table);
|
|
392
|
+
const colCount = fk.columns.length;
|
|
393
|
+
const tuples = fk.columns.map((from, i) => {
|
|
394
|
+
const to = fk.references.columns[i] ?? from;
|
|
395
|
+
return `('${escapeLiteral(from)}', '${escapeLiteral(to)}')`;
|
|
396
|
+
}).join(", ");
|
|
397
|
+
const description = `verify foreign key (${fk.columns.join(", ")}) → ${fk.references.table}(${fk.references.columns.join(", ")}) on "${tableName}"`;
|
|
398
|
+
checks.push({
|
|
399
|
+
description,
|
|
400
|
+
sql: `SELECT EXISTS (SELECT 1 FROM pragma_foreign_key_list('${t}') f WHERE f."table" = '${refTable}' GROUP BY f.id HAVING COUNT(*) = ${colCount} AND SUM(CASE WHEN (f."from", f."to") IN (${tuples}) THEN 1 ELSE 0 END) = ${colCount})`
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return checks;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
//#endregion
|
|
407
|
+
export { recreateTable as a, buildColumnDefaultSql as c, renderDefaultLiteral as d, addColumn as f, dropTable as i, buildColumnTypeSql as l, step as m, buildRecreateSummary as n, createIndex as o, dropColumn as p, createTable as r, dropIndex as s, buildRecreatePostchecks as t, isInlineAutoincrementPrimaryKey as u };
|
|
408
|
+
//# sourceMappingURL=tables-sKIg_lWE.mjs.map
|