@voltro/database 0.70.0 → 0.71.1
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/CHANGELOG.md +1341 -111
- package/dist/{frameworkLiveTables-CWbTSnjk.js → frameworkLiveTables-D53uncZH.js} +3 -3
- package/dist/index.d.ts +35 -31
- package/dist/index.js +326 -308
- package/dist/sql.d.ts +41 -7
- package/dist/sql.js +1106 -913
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
|
-
import { C as e, Jt as t, Ot as n, St as r, a as i, an as a, at as o, b as s, c, ct as l, d as u, f as d, h as f, i as p, it as m, lt as h, m as g, o as _, on as v, qt as y, rt as b, s as x, u as S, y as C } from "./frameworkLiveTables-
|
|
2
|
-
import {
|
|
3
|
-
import { createHash as
|
|
4
|
-
import { createLogger as
|
|
1
|
+
import { C as e, Jt as t, Ot as n, St as r, a as i, an as a, at as o, b as s, c, ct as l, d as u, f as d, h as f, i as p, it as m, lt as h, m as g, o as _, on as v, qt as y, rt as b, s as x, u as S, y as C } from "./frameworkLiveTables-D53uncZH.js";
|
|
2
|
+
import { Cause as w, Effect as T, Equal as ee, Exit as te, Schedule as ne, Scope as re } from "effect";
|
|
3
|
+
import { createHash as ie } from "node:crypto";
|
|
4
|
+
import { createLogger as ae } from "@voltro/logger";
|
|
5
5
|
import { SqlClient as E } from "@effect/sql";
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
9
|
-
//#region src/
|
|
10
|
-
var
|
|
6
|
+
import { promises as oe } from "node:fs";
|
|
7
|
+
import { join as se } from "node:path";
|
|
8
|
+
import { pathToFileURL as ce } from "node:url";
|
|
9
|
+
//#region src/indexStorage.ts
|
|
10
|
+
var le = (e, t = "float32") => {
|
|
11
|
+
let n = e?.hnsw, r = n?.m ?? 16, i = n?.efConstruction ?? 64;
|
|
12
|
+
for (let [e, t] of Object.entries({
|
|
13
|
+
m: r,
|
|
14
|
+
efConstruction: i
|
|
15
|
+
})) if (!Number.isSafeInteger(t) || t <= 0) throw Error(`HNSW ${e} must be a positive safe integer`);
|
|
16
|
+
let a = n?.opclass ?? h(n?.distance, t);
|
|
17
|
+
if (!/^[a-z_][a-z0-9_$]*(?:\.[a-z_][a-z0-9_$]*)?$/i.test(a)) throw Error("HNSW opclass must be an unquoted, optionally schema-qualified identifier");
|
|
18
|
+
return {
|
|
19
|
+
m: r,
|
|
20
|
+
efConstruction: i,
|
|
21
|
+
opclass: a.toLowerCase().replace(/^public\./, "")
|
|
22
|
+
};
|
|
23
|
+
}, ue = (e, t) => t === void 0 || t === "postgres" ? e ?? "btree" : e === "hnsw" || e === "gin" && (t === "mysql" || t === "mariadb") ? null : "btree", de = (e, t) => ({
|
|
24
|
+
...e !== void 0 && e !== "btree" ? { kind: e } : {},
|
|
25
|
+
...e === "hnsw" ? { kindOptions: { hnsw: le(t) } } : {}
|
|
26
|
+
}), fe = (e, t, n = "float32") => {
|
|
27
|
+
if (e === void 0 || e === "btree") return {
|
|
28
|
+
using: "",
|
|
29
|
+
withSuffix: "",
|
|
30
|
+
skip: !1
|
|
31
|
+
};
|
|
32
|
+
if (!/^[a-z_][a-z0-9_]*$/i.test(e)) throw Error("Index kind must be an SQL access-method identifier");
|
|
33
|
+
if (e !== "hnsw") return {
|
|
34
|
+
using: ` USING ${e.toUpperCase()}`,
|
|
35
|
+
withSuffix: "",
|
|
36
|
+
skip: !1
|
|
37
|
+
};
|
|
38
|
+
let r = le(t, n);
|
|
39
|
+
return {
|
|
40
|
+
using: " USING hnsw",
|
|
41
|
+
withSuffix: ` WITH (m = ${r.m}, ef_construction = ${r.efConstruction})`,
|
|
42
|
+
opclass: r.opclass,
|
|
43
|
+
skip: !1
|
|
44
|
+
};
|
|
45
|
+
}, pe = (e, t, n, r = 400) => {
|
|
11
46
|
let i = n, a = i.cause ?? {}, o = (e) => {
|
|
12
47
|
let t = a[e];
|
|
13
48
|
return t == null || t === "" ? void 0 : String(t);
|
|
@@ -38,21 +73,21 @@ var se = (e, t, n, r = 400) => {
|
|
|
38
73
|
let t = o(e);
|
|
39
74
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
40
75
|
}
|
|
41
|
-
let c =
|
|
76
|
+
let c = me(o("code"));
|
|
42
77
|
return c !== void 0 && s.push("", c), s.push(""), s.join("\n");
|
|
43
|
-
},
|
|
44
|
-
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(
|
|
78
|
+
}, me = (e) => e === "3F000" ? "remedy: the connection's search_path names a schema that does not exist. Voltro sets it from DB_SCHEMA — create the schema (`CREATE SCHEMA \"<name>\"`) or unset DB_SCHEMA to use the connection default. Voltro creates TABLES, never the schema itself: that is a namespace decision, and inventing one from a typo is how a migration lands somewhere nobody is looking." : void 0, he = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, ge = (e) => e.replace(/"/g, "`"), _e = (e) => typeof e == "string" ? e : e.name ?? String(e), ve = (e, t) => `_ua_${t}_${e}`.slice(0, 64), ye = (e, t) => {
|
|
79
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(he)) return e;
|
|
45
80
|
let n = { ...e.fields }, r = [], i = [];
|
|
46
81
|
for (let t of e.appliedIndexes) {
|
|
47
|
-
if (!
|
|
82
|
+
if (!he(t)) {
|
|
48
83
|
r.push(t);
|
|
49
84
|
continue;
|
|
50
85
|
}
|
|
51
|
-
let a =
|
|
86
|
+
let a = ge(t.where), o = [];
|
|
52
87
|
for (let r of t.fields) {
|
|
53
|
-
let i =
|
|
88
|
+
let i = _e(r);
|
|
54
89
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
55
|
-
let s =
|
|
90
|
+
let s = ve(t.name, i);
|
|
56
91
|
o.push(s), n[s] = {
|
|
57
92
|
type: "text",
|
|
58
93
|
nullable: !0,
|
|
@@ -75,7 +110,7 @@ var se = (e, t, n, r = 400) => {
|
|
|
75
110
|
appliedIndexes: r,
|
|
76
111
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
77
112
|
};
|
|
78
|
-
}, D = (e, t) => `${e}::${t}`,
|
|
113
|
+
}, D = (e, t) => `${e}::${t}`, be = (e, t) => {
|
|
79
114
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
80
115
|
n.add(e);
|
|
81
116
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
@@ -84,73 +119,73 @@ var se = (e, t, n, r = 400) => {
|
|
|
84
119
|
};
|
|
85
120
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
86
121
|
return i;
|
|
87
|
-
}, O = (e, t) => e.executeUnprepared(t, [], void 0),
|
|
122
|
+
}, O = (e, t) => e.executeUnprepared(t, [], void 0), xe = 6322741009312437n, Se = (e) => {
|
|
88
123
|
let t = e?.trim();
|
|
89
124
|
return t === void 0 || t === "" || t === "public" ? void 0 : t;
|
|
90
|
-
},
|
|
91
|
-
let t =
|
|
92
|
-
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t *
|
|
125
|
+
}, Ce = (e) => e?.schema === void 0 ? Se(process.env.DB_SCHEMA) : Se(e.schema), we = 14695981039346656037n, Te = 1099511628211n, Ee = 18446744073709551615n, De = (e) => {
|
|
126
|
+
let t = we;
|
|
127
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * Te & Ee;
|
|
93
128
|
return t;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
return t === void 0 ?
|
|
97
|
-
},
|
|
98
|
-
let t = `voltro_migration_${
|
|
129
|
+
}, Oe = (e) => {
|
|
130
|
+
let t = Se(e);
|
|
131
|
+
return t === void 0 ? xe : De(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
132
|
+
}, ke = (e) => {
|
|
133
|
+
let t = `voltro_migration_${xe.toString(36)}`, n = Se(e);
|
|
99
134
|
if (n === void 0) return t;
|
|
100
135
|
let r = `${t}_${n}`;
|
|
101
|
-
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(
|
|
102
|
-
},
|
|
136
|
+
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(De(`voltro_migration_lock:${n}`) & Ee).toString(16)}`;
|
|
137
|
+
}, Ae = 250, je = () => {
|
|
103
138
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
104
139
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
105
|
-
},
|
|
106
|
-
let n =
|
|
140
|
+
}, Me = (e, t) => T.gen(function* () {
|
|
141
|
+
let n = je(), r = Date.now();
|
|
107
142
|
for (;;) {
|
|
108
143
|
if ((yield* O(e, `SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`))[0]?.got) return;
|
|
109
|
-
Date.now() - r >= n && (yield*
|
|
144
|
+
Date.now() - r >= n && (yield* T.die(/* @__PURE__ */ Error(`could not acquire the postgres migration advisory lock within ${Math.round(n / 1e3)}s. Another migration is in progress, or a prior boot crashed while holding it. (A crashed process's session-level advisory lock is released once its DB connection closes; if this persists, find + terminate the holder via pg_stat_activity, or raise VOLTRO_MIGRATION_LOCK_TIMEOUT_MS.)`))), yield* T.sleep(`${Ae} millis`);
|
|
110
145
|
}
|
|
111
|
-
}),
|
|
112
|
-
(yield* O(e, `SELECT GET_LOCK('${t}', ${String(
|
|
113
|
-
}),
|
|
146
|
+
}), Ne = (e, t) => T.asVoid(O(e, `SELECT pg_advisory_unlock(${t.toString()}::bigint)`)), Pe = 30, Fe = (e, t) => T.gen(function* () {
|
|
147
|
+
(yield* O(e, `SELECT GET_LOCK('${t}', ${String(Pe)}) AS got`))[0]?.got !== 1 && (yield* T.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${Pe}s (another migration is in progress, or a prior one left it held).`)));
|
|
148
|
+
}), Ie = (e, t) => T.asVoid(O(e, `SELECT RELEASE_LOCK('${t}')`)), Le = 3e4, Re = (e, t) => T.gen(function* () {
|
|
114
149
|
let n = yield* O(e, `
|
|
115
150
|
DECLARE @res int;
|
|
116
151
|
EXEC @res = sp_getapplock @Resource = '${t}', @LockMode = 'Exclusive',
|
|
117
|
-
@LockOwner = 'Session', @LockTimeout = ${String(
|
|
152
|
+
@LockOwner = 'Session', @LockTimeout = ${String(Le)};
|
|
118
153
|
SELECT @res AS res`);
|
|
119
|
-
(n[0]?.res ?? -999) < 0 && (yield*
|
|
120
|
-
}),
|
|
121
|
-
let n =
|
|
154
|
+
(n[0]?.res ?? -999) < 0 && (yield* T.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
155
|
+
}), ze = (e, t) => T.asVoid(O(e, `EXEC sp_releaseapplock @Resource = '${t}', @LockOwner = 'Session'`)), Be = T.void, Ve = (e, t) => T.gen(function* () {
|
|
156
|
+
let n = Ce(t), r = ke(n), i = Oe(n);
|
|
122
157
|
if (!e.onDialectOrElse({
|
|
123
158
|
mysql: () => !0,
|
|
124
159
|
mssql: () => !0,
|
|
125
160
|
sqlite: () => !1,
|
|
126
161
|
orElse: () => !0
|
|
127
|
-
})) return { release:
|
|
128
|
-
let a = yield*
|
|
162
|
+
})) return { release: Be };
|
|
163
|
+
let a = yield* re.make(), o = yield* T.provideService(e.reserve, re.Scope, a), s = re.close(a, te.void);
|
|
129
164
|
return yield* e.onDialectOrElse({
|
|
130
|
-
mysql: () =>
|
|
131
|
-
mssql: () =>
|
|
132
|
-
sqlite: () =>
|
|
133
|
-
orElse: () =>
|
|
134
|
-
}).pipe(
|
|
135
|
-
mysql: () =>
|
|
136
|
-
mssql: () =>
|
|
137
|
-
sqlite: () =>
|
|
138
|
-
orElse: () =>
|
|
139
|
-
}).pipe(
|
|
140
|
-
}),
|
|
165
|
+
mysql: () => Fe(o, r),
|
|
166
|
+
mssql: () => Re(o, r),
|
|
167
|
+
sqlite: () => Be,
|
|
168
|
+
orElse: () => Me(o, i)
|
|
169
|
+
}).pipe(T.onExit((e) => te.isSuccess(e) ? T.void : s)), { release: e.onDialectOrElse({
|
|
170
|
+
mysql: () => Ie(o, r),
|
|
171
|
+
mssql: () => ze(o, r),
|
|
172
|
+
sqlite: () => Be,
|
|
173
|
+
orElse: () => Ne(o, i)
|
|
174
|
+
}).pipe(T.ensuring(s)) };
|
|
175
|
+
}), He = (e, t, n) => T.acquireUseRelease(Ve(e, n), () => t, (e) => e.release.pipe(T.orDie)), Ue = (e) => e.onDialectOrElse({
|
|
141
176
|
pg: () => "postgres",
|
|
142
177
|
mysql: () => "mysql",
|
|
143
178
|
mssql: () => "mssql",
|
|
144
179
|
sqlite: () => "sqlite",
|
|
145
180
|
orElse: () => "sqlite"
|
|
146
|
-
}),
|
|
181
|
+
}), We = {
|
|
147
182
|
postgres: "plan-transactional",
|
|
148
183
|
mssql: "plan-transactional",
|
|
149
184
|
mysql: "per-operation",
|
|
150
185
|
mariadb: "per-operation",
|
|
151
186
|
sqlite: "per-operation",
|
|
152
187
|
turso: "per-operation"
|
|
153
|
-
},
|
|
188
|
+
}, Ge = (e) => We[e], k = "_voltro_migration_ops", Ke = l(k, {
|
|
154
189
|
id: y({ prefix: "mop" }),
|
|
155
190
|
runId: a(),
|
|
156
191
|
planFingerprint: a(),
|
|
@@ -163,7 +198,7 @@ var se = (e, t, n, r = 400) => {
|
|
|
163
198
|
appliedAt: v().nullable(),
|
|
164
199
|
durationMs: t().nullable(),
|
|
165
200
|
createdAt: v().default("now")
|
|
166
|
-
}),
|
|
201
|
+
}), qe = (e) => {
|
|
167
202
|
switch (e.kind) {
|
|
168
203
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
169
204
|
`table:${e.table}`,
|
|
@@ -183,18 +218,19 @@ var se = (e, t, n, r = 400) => {
|
|
|
183
218
|
case "add-foreign-key":
|
|
184
219
|
case "drop-foreign-key":
|
|
185
220
|
case "add-check":
|
|
186
|
-
case "drop-check":
|
|
221
|
+
case "drop-check":
|
|
222
|
+
case "reconcile-json-check": return /* @__PURE__ */ new Set([`column:${e.table}.${e.column}`]);
|
|
187
223
|
case "add-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index.name}`]);
|
|
188
224
|
case "drop-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index}`]);
|
|
189
225
|
case "rename-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.from}`, `index:${e.table}.${e.to}`]);
|
|
190
226
|
case "add-unique-composite":
|
|
191
227
|
case "drop-unique-composite": return /* @__PURE__ */ new Set([`unique:${e.table}.${e.name}`]);
|
|
192
228
|
}
|
|
193
|
-
},
|
|
194
|
-
let n =
|
|
195
|
-
for (let t of
|
|
229
|
+
}, Je = (e) => [...qe(e)].join(" "), Ye = (e, t) => {
|
|
230
|
+
let n = qe(t);
|
|
231
|
+
for (let t of qe(e)) if (n.has(t)) return !0;
|
|
196
232
|
return !1;
|
|
197
|
-
},
|
|
233
|
+
}, Xe = (e, t) => e.operations.some((e) => Ye(e.op, t)), Ze = "__voltro_rebuild", Qe = "__shadow", $e = "__old", et = /* @__PURE__ */ new Set([
|
|
198
234
|
"add-unique",
|
|
199
235
|
"drop-unique",
|
|
200
236
|
"add-unique-composite",
|
|
@@ -206,20 +242,58 @@ var se = (e, t, n, r = 400) => {
|
|
|
206
242
|
"alter-column-nullability",
|
|
207
243
|
"alter-column-type",
|
|
208
244
|
"alter-column-default"
|
|
209
|
-
]),
|
|
245
|
+
]), tt = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), nt = (e, t, n) => {
|
|
210
246
|
let r = n === "sqlite" || n === "turso";
|
|
211
|
-
return e.kind === "alter-column-type" && t === "online-required" || r &&
|
|
247
|
+
return e.kind === "alter-column-type" && t === "online-required" || r && et.has(e.kind) ? "artefact-repair" : tt.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
212
248
|
};
|
|
213
|
-
Object.keys(
|
|
249
|
+
Object.keys(We);
|
|
214
250
|
//#endregion
|
|
215
|
-
//#region src/
|
|
216
|
-
var
|
|
251
|
+
//#region src/mssqlJsonValueCheck.ts
|
|
252
|
+
var rt = (e) => {
|
|
253
|
+
let t = `(N'{"v":' + ${e} + N'}')`, n = `ISJSON(${t}) = 1`, r = `JSON_MODIFY(CASE WHEN ${n} THEN ${t} ELSE N'{}' END, '$.v', NULL)`;
|
|
254
|
+
return `(${e} IS NULL OR (${n} AND ${[
|
|
255
|
+
32,
|
|
256
|
+
9,
|
|
257
|
+
10,
|
|
258
|
+
13
|
|
259
|
+
].reduce((e, t) => `REPLACE(${e}, NCHAR(${t}), N'')`, r)} = N'{}'))`;
|
|
260
|
+
}, it = (e) => {
|
|
261
|
+
let t = [], n = /\s+|N?'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|[A-Za-z_][A-Za-z_0-9]*|[0-9]+|[()+,=]/giy, r = 0;
|
|
262
|
+
for (; r < e.length;) {
|
|
263
|
+
n.lastIndex = r;
|
|
264
|
+
let i = n.exec(e);
|
|
265
|
+
if (!i) return;
|
|
266
|
+
let a = i[0];
|
|
267
|
+
/^\s+$/.test(a) || t.push(/^(?:N?')|^\[/i.test(a) ? a.replace(/^n'/, "N'") : a.toLowerCase()), r = n.lastIndex;
|
|
268
|
+
}
|
|
269
|
+
return t;
|
|
270
|
+
}, at = (e, t) => {
|
|
271
|
+
let n = `[${e.replaceAll("]", "]]")}]`, r = `(N'{"v":'+${n})+N'}'`, i = `isjson(${r})=(1)`, a = `json_modify(case when ${i} then ${r} else N'{}' end,'$.v',NULL)`, o = [
|
|
272
|
+
32,
|
|
273
|
+
9,
|
|
274
|
+
10,
|
|
275
|
+
13
|
|
276
|
+
].reduce((e, t) => `replace(${e},nchar((${t})),N'')`, a), s = [
|
|
277
|
+
["value", rt(n)],
|
|
278
|
+
["value", `(${n} IS NULL OR ${i} AND ${o}=N'{}')`],
|
|
279
|
+
["container", `(${n} IS NULL OR ISJSON(${n}) = 1)`],
|
|
280
|
+
["container", `(${n} IS NULL OR isjson(${n})=(1))`]
|
|
281
|
+
], c = it(t);
|
|
282
|
+
if (c) return s.find(([, e]) => {
|
|
283
|
+
let t = it(e);
|
|
284
|
+
return t?.length === c.length && t.every((e, t) => e === c[t]);
|
|
285
|
+
})?.[0];
|
|
286
|
+
}, ot = (e) => {
|
|
287
|
+
if (e.length === 0) return;
|
|
288
|
+
let t = e.filter((e) => e.enabled);
|
|
289
|
+
return t.some((e) => e.validation === "container") ? t.some((e) => e.validation === "container" && e.trusted) ? "container" : "unverified" : t.some((e) => e.validation === "value" && e.trusted) ? "value" : "unverified";
|
|
290
|
+
}, A = "framework_changes", st = "framework_changes_", ct = (e, t) => t === "framework_changes" ? `${st}${e}` : `${st}${t}_${e}`, lt = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, ut = "voltro:notify:v2", dt = (e, t) => {
|
|
217
291
|
if (e.type === "text" && e.generatedAs === void 0) {
|
|
218
292
|
if (e.maxLength !== void 0) return e.maxLength;
|
|
219
293
|
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
220
294
|
}
|
|
221
|
-
},
|
|
222
|
-
|
|
295
|
+
}, ft = ae({ scope: "voltro:migrate" }), j = (e) => {
|
|
296
|
+
ft.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
223
297
|
}, M = (e, t) => {
|
|
224
298
|
let n = e.type;
|
|
225
299
|
if (e.spatial) {
|
|
@@ -302,7 +376,7 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
302
376
|
if (t === "mssql") switch (n) {
|
|
303
377
|
case "id": return "NVARCHAR(64)";
|
|
304
378
|
case "text": {
|
|
305
|
-
let t =
|
|
379
|
+
let t = dt(e, !1);
|
|
306
380
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
307
381
|
}
|
|
308
382
|
case "integer": return "INT";
|
|
@@ -334,11 +408,11 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
334
408
|
case "array": return "TEXT[]";
|
|
335
409
|
case "interval": return "INTERVAL";
|
|
336
410
|
}
|
|
337
|
-
},
|
|
411
|
+
}, pt = (e, t) => {
|
|
338
412
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
339
413
|
let n = e.defaultValue;
|
|
340
|
-
return n === "now" ? m(t) ? "DEFAULT CURRENT_TIMESTAMP" : t === "mssql" ? "DEFAULT SYSUTCDATETIME()" : t === "mysql" || t === "mariadb" ? "DEFAULT CURRENT_TIMESTAMP(6)" : "DEFAULT now()" : typeof n == "boolean" ? t === "postgres" ? `DEFAULT ${n}` : `DEFAULT ${+!!n}` : typeof n == "number" ? `DEFAULT ${n}` : typeof n == "string" ? `DEFAULT '${n.replace(/'/g, "''")}'` : Array.isArray(n) ?
|
|
341
|
-
},
|
|
414
|
+
return n === "now" ? m(t) ? "DEFAULT CURRENT_TIMESTAMP" : t === "mssql" ? "DEFAULT SYSUTCDATETIME()" : t === "mysql" || t === "mariadb" ? "DEFAULT CURRENT_TIMESTAMP(6)" : "DEFAULT now()" : typeof n == "boolean" ? t === "postgres" ? `DEFAULT ${n}` : `DEFAULT ${+!!n}` : typeof n == "number" ? `DEFAULT ${n}` : typeof n == "string" ? `DEFAULT '${n.replace(/'/g, "''")}'` : Array.isArray(n) ? mt(n, e, t) : typeof n == "object" && n ? N(n, t) : null;
|
|
415
|
+
}, mt = (e, t, n) => {
|
|
342
416
|
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return N(e, n);
|
|
343
417
|
let r = M({
|
|
344
418
|
...t,
|
|
@@ -366,18 +440,18 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
366
440
|
case "setNull": return "SET NULL";
|
|
367
441
|
case "noAction": return "NO ACTION";
|
|
368
442
|
}
|
|
369
|
-
},
|
|
443
|
+
}, ht = (e, t, n) => n === null ? o(e, t) : `${o(n, t)}.${o(e, t)}`, gt = 191, _t = (e, t) => {
|
|
370
444
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
371
445
|
let n = M(e, t).toUpperCase();
|
|
372
446
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
373
|
-
},
|
|
447
|
+
}, vt = (e, t, n) => {
|
|
374
448
|
let r = o(e, n);
|
|
375
449
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
376
450
|
let i = t[e];
|
|
377
451
|
if (!i) return r;
|
|
378
452
|
let a = M(i, n).toUpperCase();
|
|
379
|
-
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${
|
|
380
|
-
},
|
|
453
|
+
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${gt})` : r;
|
|
454
|
+
}, yt = (e, t) => {
|
|
381
455
|
if (!e.generatedAs) return null;
|
|
382
456
|
let { expr: n, stored: r } = e.generatedAs;
|
|
383
457
|
if (t === "postgres") return r || j("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
@@ -385,15 +459,15 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
385
459
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
386
460
|
if (t === "turso") throw Error("@voltro/sql-turso: generated columns (.generatedAs(...)) are not supported — Turso's MVCC mode (journal_mode=experimental_mvcc) rejects them. Drop the generated column, or use the 'sqlite' / 'postgres' dialect for this table.");
|
|
387
461
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
388
|
-
},
|
|
462
|
+
}, bt = (e, t, n, r, i = !1, a = !1) => {
|
|
389
463
|
if (t.type === "id" && t.idScheme?.kind === "numeric") return P(e, n);
|
|
390
|
-
let s = n === "mssql" ?
|
|
464
|
+
let s = n === "mssql" ? dt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? M(t, n) : `NVARCHAR(${s})`, l = [o(e, n), c];
|
|
391
465
|
t.type === "id" && !a && l.push("PRIMARY KEY");
|
|
392
|
-
let u =
|
|
466
|
+
let u = yt(t, n);
|
|
393
467
|
if (u) l.push(u);
|
|
394
468
|
else {
|
|
395
|
-
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !
|
|
396
|
-
let e =
|
|
469
|
+
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !_t(t, n) && l.push("UNIQUE");
|
|
470
|
+
let e = pt(t, n);
|
|
397
471
|
e && l.push(e);
|
|
398
472
|
}
|
|
399
473
|
if (t.type === "reference" && t.references && !i && !b(n)) {
|
|
@@ -414,30 +488,30 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
414
488
|
l.push(`CHECK (${o(e, n)} IN (${r}))`);
|
|
415
489
|
}
|
|
416
490
|
if (t.type === "json" || t.type === "array") {
|
|
417
|
-
let
|
|
418
|
-
m(n) ? l.push(`CHECK (${
|
|
491
|
+
let r = o(e, n);
|
|
492
|
+
m(n) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : n === "mssql" && l.push(t.type === "json" ? `CHECK ${rt(r)}` : `CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
|
|
419
493
|
}
|
|
420
494
|
return l.join(" ");
|
|
421
|
-
},
|
|
495
|
+
}, xt = (e, t, n = null, r) => {
|
|
422
496
|
let i = /* @__PURE__ */ new Set();
|
|
423
497
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
424
498
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
425
499
|
for (let [t, n] of Object.entries(e.fields)) n.unique && i.add(t);
|
|
426
500
|
let a = e.appliedPrimaryKey ?? [];
|
|
427
501
|
for (let e of a) i.add(e);
|
|
428
|
-
let s = a.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${
|
|
429
|
-
let r = n.fields.map((n) =>
|
|
502
|
+
let s = a.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${bt(e, n, t, i, r?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((n) => {
|
|
503
|
+
let r = n.fields.map((n) => vt(n, e.fields, t)).join(", ");
|
|
430
504
|
return ` CONSTRAINT ${o(n.name, t)} UNIQUE (${r})`;
|
|
431
|
-
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${o(e.name, t)} CHECK (${e.expr})`), d = s ? [` PRIMARY KEY (${a.map((n) =>
|
|
505
|
+
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${o(e.name, t)} CHECK (${e.expr})`), d = s ? [` PRIMARY KEY (${a.map((n) => vt(n, e.fields, t)).join(", ")})`] : [], f = b(t) ? Object.entries(e.fields).flatMap(([i, a]) => {
|
|
432
506
|
if (a.type !== "reference" || !a.references || (r?.has(i) ?? !1)) return [];
|
|
433
507
|
let s = a.references(), c = F(a.onDelete ?? "restrict", t), l = F(a.refOnUpdate ?? "noAction", t);
|
|
434
|
-
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${
|
|
508
|
+
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${ht(s.tableName, t, n)} (${o(a.referenceColumn ?? "id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
435
509
|
}) : [], p = [
|
|
436
510
|
...d,
|
|
437
511
|
...l,
|
|
438
512
|
...u,
|
|
439
513
|
...f
|
|
440
|
-
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h =
|
|
514
|
+
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h = ht(e.tableName, t, n);
|
|
441
515
|
if (t === "mssql") {
|
|
442
516
|
let t = n === null ? e.tableName : `${n}.${e.tableName}`, r = `CREATE TABLE ${h} (\n${m}\n)`;
|
|
443
517
|
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${r.replace(/'/g, "''")}');`;
|
|
@@ -447,56 +521,29 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
447
521
|
m,
|
|
448
522
|
");"
|
|
449
523
|
].join("\n");
|
|
450
|
-
},
|
|
524
|
+
}, St = (e, t, n) => {
|
|
451
525
|
let r = `${e}_${t.name}_fts`, i = (e) => o(e, n), a = t.columns.map(i).join(", "), s = t.columns.map((e) => `new.${i(e)}`).join(", "), c = [];
|
|
452
526
|
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${i(r)} USING fts5(${a}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ai`)} AFTER INSERT ON ${i(e)} BEGIN\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${s}, new.${i("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ad`)} AFTER DELETE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_au`)} AFTER UPDATE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${s}, new.${i("id")});\nEND;`), c;
|
|
453
|
-
},
|
|
454
|
-
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"), s = (e, n, r, i) => {
|
|
455
|
-
|
|
527
|
+
}, Ct = (e, t, n = null) => {
|
|
528
|
+
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"), s = (e, n, r, i, a) => {
|
|
529
|
+
if (t === "postgres") return fe(r, i, a);
|
|
530
|
+
let o = {
|
|
456
531
|
using: "",
|
|
457
532
|
withSuffix: "",
|
|
458
533
|
skip: !1
|
|
459
534
|
};
|
|
460
|
-
|
|
461
|
-
if (r === "gist") return t === "postgres" ? {
|
|
462
|
-
using: " USING GIST",
|
|
463
|
-
withSuffix: "",
|
|
464
|
-
skip: !1
|
|
465
|
-
} : (j(`[voltro:migrate] index '${e}' on '${n}': ${t} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), a);
|
|
466
|
-
if (r === "gin") return t === "postgres" ? {
|
|
467
|
-
using: " USING GIN",
|
|
468
|
-
withSuffix: "",
|
|
469
|
-
skip: !1
|
|
470
|
-
} : t === "mysql" || t === "mariadb" ? (j(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
535
|
+
return r === void 0 || r === "btree" ? o : r === "gist" ? (j(`[voltro:migrate] index '${e}' on '${n}': ${t} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), o) : r === "gin" ? t === "mysql" || t === "mariadb" ? (j(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
471
536
|
using: "",
|
|
472
537
|
withSuffix: "",
|
|
473
538
|
skip: !0
|
|
474
|
-
}) : (j(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), a)
|
|
475
|
-
|
|
476
|
-
using: " USING BRIN",
|
|
539
|
+
}) : (j(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), o) : r === "brin" ? (j(`[voltro:migrate] brin index '${e}' on '${n}': ${t} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), o) : r === "hnsw" ? (j(`[voltro:migrate] hnsw index '${e}' on '${n}': ${t} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
540
|
+
using: "",
|
|
477
541
|
withSuffix: "",
|
|
478
|
-
skip: !
|
|
479
|
-
} :
|
|
480
|
-
if (r === "hnsw") {
|
|
481
|
-
if (t === "postgres") {
|
|
482
|
-
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? h(i?.hnsw?.distance);
|
|
483
|
-
return {
|
|
484
|
-
using: " USING hnsw",
|
|
485
|
-
withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
|
|
486
|
-
opclass: n,
|
|
487
|
-
skip: !1
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
return j(`[voltro:migrate] hnsw index '${e}' on '${n}': ${t} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
491
|
-
using: "",
|
|
492
|
-
withSuffix: "",
|
|
493
|
-
skip: !0
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
return a;
|
|
542
|
+
skip: !0
|
|
543
|
+
}) : o;
|
|
497
544
|
}, c = (n, r) => {
|
|
498
545
|
let i = n.map((n) => {
|
|
499
|
-
if (typeof n == "string") return
|
|
546
|
+
if (typeof n == "string") return vt(n, e.fields, t);
|
|
500
547
|
if ("jsonPath" in n) {
|
|
501
548
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
502
549
|
return `(${C(e, r, t, { numeric: i })})`;
|
|
@@ -504,14 +551,14 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
504
551
|
return `(${n.expr})`;
|
|
505
552
|
});
|
|
506
553
|
return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
|
|
507
|
-
}, l = (
|
|
508
|
-
let
|
|
509
|
-
if (
|
|
510
|
-
let
|
|
511
|
-
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${
|
|
554
|
+
}, l = (r, i, a, l, u, d = "", f = !1) => {
|
|
555
|
+
let p = a[0], m = typeof p == "string" ? e.fields[p]?.vectorPrecision : void 0, h = s(r, i, l, u, m);
|
|
556
|
+
if (h.skip) return "";
|
|
557
|
+
let g = c(a, h.opclass), _ = `${h.withSuffix}${d}`, v = ht(i, t, n), y = f ? "UNIQUE " : "";
|
|
558
|
+
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${r}') CREATE ${y}INDEX ${o(r, t)} ON ${v}${h.using} (${g})${_};` : t === "mysql" ? `CREATE ${y}INDEX ${o(r, t)} ON ${v}${h.using} (${g})${_};` : `CREATE ${y}INDEX IF NOT EXISTS ${o(r, t)} ON ${v}${h.using} (${g})${_};`;
|
|
512
559
|
};
|
|
513
560
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
514
|
-
if (!i.unique || i.type === "id" || !
|
|
561
|
+
if (!i.unique || i.type === "id" || !_t(i, t)) continue;
|
|
515
562
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
516
563
|
a && r.push(a);
|
|
517
564
|
}
|
|
@@ -525,7 +572,7 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
525
572
|
let i = n.columns.map((e) => o(e, t)).join(", ");
|
|
526
573
|
r.push(`CREATE FULLTEXT INDEX ${o(n.name, t)} ON ${o(e.tableName, t)} (${i});`);
|
|
527
574
|
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${n.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
|
|
528
|
-
else t === "sqlite" ? r.push(...
|
|
575
|
+
else t === "sqlite" ? r.push(...St(e.tableName, n, t)) : j(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
529
576
|
for (let n of e.appliedIndexes) {
|
|
530
577
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
531
578
|
j(`[voltro:migrate] json-path index '${n.name}' on '${e.tableName}': ${t} cannot index a JSON expression directly — skipping. For an indexed JSON path on ${t}, add a generated column for the path (text().generatedAs(...) / .stored()) and .index([...]) it, then filter on that column instead of jsonField(...).`);
|
|
@@ -543,17 +590,17 @@ var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "fr
|
|
|
543
590
|
r.push(l(o, e.tableName, [t])), i.add(a([t]));
|
|
544
591
|
}
|
|
545
592
|
return r.join("\n");
|
|
546
|
-
},
|
|
593
|
+
}, wt = (e, t, n = A) => {
|
|
547
594
|
if (t !== "postgres") return [];
|
|
548
595
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
549
|
-
return r.length === 0 ? [] : [
|
|
550
|
-
},
|
|
551
|
-
CREATE OR REPLACE FUNCTION ${
|
|
596
|
+
return r.length === 0 ? [] : [Tt(n), ...r.map((e) => Dt(e, n))];
|
|
597
|
+
}, Tt = (e) => `
|
|
598
|
+
CREATE OR REPLACE FUNCTION ${lt(e)}() RETURNS trigger AS $$
|
|
552
599
|
DECLARE
|
|
553
600
|
payload TEXT;
|
|
554
601
|
pk JSONB;
|
|
555
602
|
BEGIN
|
|
556
|
-
-- ${
|
|
603
|
+
-- ${ut}
|
|
557
604
|
payload := json_build_object(
|
|
558
605
|
'table', TG_TABLE_NAME,
|
|
559
606
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -607,22 +654,22 @@ BEGIN
|
|
|
607
654
|
RETURN COALESCE(NEW, OLD);
|
|
608
655
|
END;
|
|
609
656
|
$$ LANGUAGE plpgsql;
|
|
610
|
-
`.trim(),
|
|
611
|
-
let n =
|
|
657
|
+
`.trim(), Et = (e, t) => {
|
|
658
|
+
let n = ct(e.tableName, t);
|
|
612
659
|
return [
|
|
613
660
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
614
661
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
615
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
662
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${lt(t)}()`
|
|
616
663
|
];
|
|
617
|
-
},
|
|
664
|
+
}, Dt = (e, t) => Et(e, t).map((e) => `${e};`).join("\n"), Ot = (e) => {
|
|
618
665
|
if (e.dialect !== "postgres") return [];
|
|
619
666
|
let t = e.channel ?? "framework_changes", n = new Map(e.tables.map((e) => [e.tableName, e])), r = [], i = e.missing.filter((e) => n.has(e));
|
|
620
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
621
|
-
for (let e of i) r.push(...
|
|
622
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
667
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(Tt(t));
|
|
668
|
+
for (let e of i) r.push(...Et(n.get(e), t));
|
|
669
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${ct(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
623
670
|
return r;
|
|
624
|
-
},
|
|
625
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
671
|
+
}, kt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), At = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), jt = (e) => {
|
|
672
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = be(e.map((e) => e.tableName), (e) => {
|
|
626
673
|
let n = t.get(e);
|
|
627
674
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
628
675
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -659,7 +706,7 @@ $$ LANGUAGE plpgsql;
|
|
|
659
706
|
sorted: o,
|
|
660
707
|
cyclic: r
|
|
661
708
|
};
|
|
662
|
-
},
|
|
709
|
+
}, Mt = (e, t, n = null) => {
|
|
663
710
|
let r = (e) => n ? `${o(n, t)}.${o(e, t)}` : o(e, t), i = `${e.table}_${e.column}_fkey`, a = F(e.onDelete, t), s = F(e.onUpdate, t), c = ` ON DELETE ${a}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (n) => `ADD CONSTRAINT ${o(i, t)} FOREIGN KEY ${n ? "IF NOT EXISTS " : ""}(${o(e.column, t)}) REFERENCES ${r(e.targetTable)} (${o(e.targetColumn, t)})${c}`;
|
|
664
711
|
switch (t) {
|
|
665
712
|
case "postgres": return [
|
|
@@ -674,7 +721,7 @@ $$ LANGUAGE plpgsql;
|
|
|
674
721
|
case "mariadb": return `ALTER TABLE ${r(e.table)} ${l(!0)};`;
|
|
675
722
|
default: return `ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
676
723
|
}
|
|
677
|
-
},
|
|
724
|
+
}, Nt = (e, t) => {
|
|
678
725
|
let n = /* @__PURE__ */ new Map();
|
|
679
726
|
if (m(t)) return n;
|
|
680
727
|
for (let t of e) {
|
|
@@ -682,7 +729,7 @@ $$ LANGUAGE plpgsql;
|
|
|
682
729
|
e.add(t.column), n.set(t.table, e);
|
|
683
730
|
}
|
|
684
731
|
return n;
|
|
685
|
-
},
|
|
732
|
+
}, Pt = (e, t) => {
|
|
686
733
|
if (t !== "postgres") return "";
|
|
687
734
|
let n = /* @__PURE__ */ new Map();
|
|
688
735
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -698,7 +745,7 @@ $$ LANGUAGE plpgsql;
|
|
|
698
745
|
r.push(`DO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${e.replace(/'/g, "''")}') THEN\n CREATE TYPE "${e}" AS ENUM (${n});\n END IF;\nEND $$;`);
|
|
699
746
|
}
|
|
700
747
|
return r.join("\n\n");
|
|
701
|
-
},
|
|
748
|
+
}, Ft = (e, t) => {
|
|
702
749
|
if (t !== "postgres") return "";
|
|
703
750
|
let r = /* @__PURE__ */ new Set();
|
|
704
751
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && r.add(e.enumName);
|
|
@@ -712,30 +759,30 @@ BEGIN
|
|
|
712
759
|
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${n}';\n IF type_oid IS NOT NULL\n AND EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${a}')\n AND NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${o}') THEN\n IF current_setting('server_version_num')::int >= 140000 THEN\n EXECUTE format('ALTER TYPE %I RENAME VALUE %L TO %L', '${n}', '${a}', '${o}');\n ELSE\n UPDATE pg_enum SET enumlabel = '${o}' WHERE enumtypid = type_oid AND enumlabel = '${a}';\n END IF;\n END IF;\nEND $$;`);
|
|
713
760
|
}
|
|
714
761
|
return i.join("\n\n");
|
|
715
|
-
},
|
|
762
|
+
}, It = (e) => {
|
|
716
763
|
let t = [], n = [];
|
|
717
764
|
for (let r of e) s(r) ? n.push(r) : t.push(r);
|
|
718
765
|
return {
|
|
719
766
|
tables: t,
|
|
720
767
|
views: n
|
|
721
768
|
};
|
|
722
|
-
},
|
|
723
|
-
let { tables: i, views: a } =
|
|
724
|
-
n === "postgres" &&
|
|
725
|
-
let u =
|
|
769
|
+
}, Lt = (t, n, r = A) => {
|
|
770
|
+
let { tables: i, views: a } = It(t), { sorted: o, cyclic: s } = jt(i.map((e) => ye(e, n))), c = Nt(s, n), l = [];
|
|
771
|
+
n === "postgres" && kt(o) && l.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && At(o) && l.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
772
|
+
let u = Ft(o, n);
|
|
726
773
|
u && l.push(u);
|
|
727
|
-
let d =
|
|
774
|
+
let d = Pt(o, n);
|
|
728
775
|
d && l.push(d);
|
|
729
|
-
for (let e of o) l.push(
|
|
730
|
-
if (!m(n)) for (let e of s) l.push(
|
|
776
|
+
for (let e of o) l.push(xt(e, n, null, c.get(e.tableName)));
|
|
777
|
+
if (!m(n)) for (let e of s) l.push(Mt(e, n));
|
|
731
778
|
for (let e of o) {
|
|
732
|
-
let t =
|
|
779
|
+
let t = Ct(e, n);
|
|
733
780
|
t && l.push(t);
|
|
734
781
|
}
|
|
735
|
-
l.push(...
|
|
782
|
+
l.push(...wt(o, n, r));
|
|
736
783
|
for (let t of a) l.push(e(t, n));
|
|
737
784
|
return l.join("\n\n") + "\n";
|
|
738
|
-
},
|
|
785
|
+
}, Rt = (e, t, n) => {
|
|
739
786
|
let r = o(e, t);
|
|
740
787
|
switch (t) {
|
|
741
788
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${r};`;
|
|
@@ -745,62 +792,62 @@ BEGIN
|
|
|
745
792
|
case "turso":
|
|
746
793
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${r};`;
|
|
747
794
|
}
|
|
748
|
-
},
|
|
749
|
-
let i =
|
|
750
|
-
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${
|
|
751
|
-
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${
|
|
752
|
-
let { sorted: s, cyclic: c } =
|
|
753
|
-
for (let e of s) u.push(
|
|
754
|
-
if (!m(t)) for (let e of c) u.push(
|
|
795
|
+
}, zt = (e, t, n, r) => {
|
|
796
|
+
let i = Rt(n, t, r), a = o(n, t);
|
|
797
|
+
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${Lt(e, t)}`;
|
|
798
|
+
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${Lt(e, t)}`;
|
|
799
|
+
let { sorted: s, cyclic: c } = jt(e), l = Nt(c, t), u = [i];
|
|
800
|
+
for (let e of s) u.push(xt(e, t, n, l.get(e.tableName)));
|
|
801
|
+
if (!m(t)) for (let e of c) u.push(Mt(e, t, n));
|
|
755
802
|
for (let e of s) {
|
|
756
|
-
let r =
|
|
803
|
+
let r = Ct(e, t, n);
|
|
757
804
|
r && u.push(r);
|
|
758
805
|
}
|
|
759
806
|
return u.join("\n\n") + "\n";
|
|
760
|
-
},
|
|
761
|
-
let { sorted: r, cyclic: i } =
|
|
807
|
+
}, Bt = (e, t, n = A) => {
|
|
808
|
+
let { sorted: r, cyclic: i } = jt(e), a = Nt(i, t), o = [], s = Ft(r, t);
|
|
762
809
|
s && o.push(s);
|
|
763
|
-
let c =
|
|
810
|
+
let c = Pt(r, t);
|
|
764
811
|
c && o.push(c);
|
|
765
|
-
for (let e of r) o.push(
|
|
766
|
-
for (let e of i) o.push(
|
|
767
|
-
return o.push(...
|
|
768
|
-
},
|
|
812
|
+
for (let e of r) o.push(xt(e, t, null, a.get(e.tableName)));
|
|
813
|
+
for (let e of i) o.push(Mt(e, t));
|
|
814
|
+
return o.push(...wt(r, t, n)), o.join("\n\n") + "\n";
|
|
815
|
+
}, Vt = (e, t = "postgres", n = A, r = {}) => T.gen(function* () {
|
|
769
816
|
let i = yield* E.SqlClient;
|
|
770
|
-
yield*
|
|
771
|
-
}),
|
|
817
|
+
yield* He(i, Jt(i, Lt(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(T.orDie);
|
|
818
|
+
}), Ht = (e, t) => {
|
|
772
819
|
let n = t.cause ?? {};
|
|
773
820
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
774
|
-
},
|
|
821
|
+
}, Ut = (e, t) => {
|
|
775
822
|
let n = e.trimStart();
|
|
776
823
|
return !!(/\bIF NOT EXISTS\b/i.test(n) || /^CREATE OR REPLACE\b/i.test(n) || /^DROP\s[\s\S]*?\bIF EXISTS\b/i.test(n) || /^SET search_path\b/i.test(n) || /^USE[\s`"[]/i.test(n) || /^IF\s/i.test(n) || (t === "mysql" || t === "mariadb") && /^CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(n));
|
|
777
|
-
},
|
|
824
|
+
}, Wt = () => {
|
|
778
825
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
779
826
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
780
|
-
},
|
|
827
|
+
}, Gt = (e) => ({
|
|
781
828
|
while: e,
|
|
782
|
-
times:
|
|
783
|
-
schedule:
|
|
784
|
-
}),
|
|
829
|
+
times: Wt(),
|
|
830
|
+
schedule: ne.jittered(ne.exponential("50 millis"))
|
|
831
|
+
}), Kt = class {
|
|
785
832
|
statement;
|
|
786
833
|
error;
|
|
787
834
|
_tag = "DdlStatementFailed";
|
|
788
835
|
constructor(e, t) {
|
|
789
836
|
this.statement = e, this.error = t;
|
|
790
837
|
}
|
|
791
|
-
},
|
|
792
|
-
let r = yield* E.SqlClient, i = n !== void 0 &&
|
|
793
|
-
for (let a of
|
|
794
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
795
|
-
let e = r.unsafe(a).pipe(
|
|
796
|
-
|
|
838
|
+
}, qt = (e, t, n) => T.gen(function* () {
|
|
839
|
+
let r = yield* E.SqlClient, i = n !== void 0 && Ge(t) === "per-operation";
|
|
840
|
+
for (let a of Yt(e)) {
|
|
841
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && ft.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
842
|
+
let e = r.unsafe(a).pipe(T.catchIf((e) => Ht(a, e), () => T.succeed([])), T.tapError((e) => T.sync(() => {
|
|
843
|
+
ft.error(pe("migrate: statement failed", a, e, 200));
|
|
797
844
|
})));
|
|
798
|
-
yield* (i && n !== void 0 &&
|
|
845
|
+
yield* (i && n !== void 0 && Ut(a, t) ? e.pipe(T.retry(Gt((e) => n(e) === "retry"))) : e).pipe(T.mapError((e) => new Kt(a, e)));
|
|
799
846
|
}
|
|
800
|
-
}),
|
|
801
|
-
let i = n === "turso" ?
|
|
802
|
-
return (r !== void 0 &&
|
|
803
|
-
},
|
|
847
|
+
}), Jt = (e, t, n, r) => {
|
|
848
|
+
let i = n === "turso" ? qt(t, n, r) : e.withTransaction(qt(t, n, r)), a = (e) => e instanceof Kt ? e.error : e;
|
|
849
|
+
return (r !== void 0 && Ge(n) === "plan-transactional" ? i.pipe(T.retry(Gt((e) => r(a(e)) === "retry"))) : i).pipe(T.orDieWith((e) => e instanceof Kt ? Error(pe("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
850
|
+
}, Yt = (e) => {
|
|
804
851
|
let t = [], n = "", r = !1;
|
|
805
852
|
for (let i = 0; i < e.length; i++) {
|
|
806
853
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -815,27 +862,27 @@ BEGIN
|
|
|
815
862
|
}
|
|
816
863
|
let i = n.trim();
|
|
817
864
|
return i.length > 0 && t.push(i), t;
|
|
818
|
-
},
|
|
819
|
-
await
|
|
820
|
-
},
|
|
821
|
-
let i =
|
|
822
|
-
yield*
|
|
823
|
-
}),
|
|
824
|
-
await
|
|
865
|
+
}, Xt = async (e, t, n = "postgres", r = {}) => {
|
|
866
|
+
await T.runPromise(Vt(e, n, void 0, r).pipe(T.provide(t)));
|
|
867
|
+
}, Zt = (e, t, n = "postgres", r = {}) => T.gen(function* () {
|
|
868
|
+
let i = zt(e, n, t), a = yield* E.SqlClient;
|
|
869
|
+
yield* He(a, Jt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(T.orDie);
|
|
870
|
+
}), Qt = async (e, t, n, r = "postgres", i = {}) => {
|
|
871
|
+
await T.runPromise(Zt(e, t, r, i).pipe(T.provide(n))), await f({
|
|
825
872
|
namespace: t,
|
|
826
873
|
dialect: r
|
|
827
874
|
});
|
|
828
|
-
},
|
|
829
|
-
await
|
|
830
|
-
let t =
|
|
831
|
-
yield*
|
|
832
|
-
}).pipe(
|
|
833
|
-
}, I = (e) => {
|
|
875
|
+
}, $t = async (e, t, n = "postgres", r = {}) => {
|
|
876
|
+
await T.runPromise(T.gen(function* () {
|
|
877
|
+
let t = Bt(e, n), i = yield* E.SqlClient;
|
|
878
|
+
yield* He(i, Jt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(T.orDie);
|
|
879
|
+
}).pipe(T.provide(t)));
|
|
880
|
+
}, en = (e, t) => t.name === "id" && e.primaryKey?.length === 1 && e.primaryKey[0] === "id", tn = (e, t, n) => n && t.type === "id" && (e.type === "text" || e.type === "id"), I = (e) => {
|
|
834
881
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
835
882
|
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
836
883
|
let t = e;
|
|
837
884
|
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
838
|
-
},
|
|
885
|
+
}, nn = (e) => {
|
|
839
886
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
840
887
|
let t = e.defaultValue;
|
|
841
888
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
@@ -855,10 +902,10 @@ BEGIN
|
|
|
855
902
|
return I(JSON.parse(a));
|
|
856
903
|
} catch {}
|
|
857
904
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
858
|
-
},
|
|
859
|
-
let t =
|
|
905
|
+
}, rn = (e) => {
|
|
906
|
+
let t = nn(e);
|
|
860
907
|
return t === "1" || t === "true" ? "__BOOL_TRUE__" : t === "0" || t === "false" ? "__BOOL_FALSE__" : t;
|
|
861
|
-
},
|
|
908
|
+
}, an = (e) => typeof e.defaultValue == "string" && /^nextval\(.+::regclass\)$/i.test(e.defaultValue.trim()), L = (e) => {
|
|
862
909
|
if (!e) return null;
|
|
863
910
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
864
911
|
return {
|
|
@@ -867,9 +914,9 @@ BEGIN
|
|
|
867
914
|
onDelete: t(e.onDelete),
|
|
868
915
|
onUpdate: t(e.onUpdate)
|
|
869
916
|
};
|
|
870
|
-
},
|
|
917
|
+
}, on = (e, t, n) => {
|
|
871
918
|
if (t === "mssql") {
|
|
872
|
-
let t =
|
|
919
|
+
let t = dt(e, n);
|
|
873
920
|
if (t !== void 0) return t;
|
|
874
921
|
}
|
|
875
922
|
try {
|
|
@@ -878,15 +925,15 @@ BEGIN
|
|
|
878
925
|
} catch {
|
|
879
926
|
return;
|
|
880
927
|
}
|
|
881
|
-
},
|
|
928
|
+
}, sn = /'(?:''|[^'])*'|"(?:""|[^"])*"|\[(?:\]\]|[^\]])*\]|`(?:``|[^`])*`|[A-Za-z_][A-Za-z_0-9$]*|\d+(?:\.\d+)?|::|<>|!=|<=|>=|\|\||[^\s]/g, cn = (e) => {
|
|
882
929
|
let t = 0;
|
|
883
|
-
for (let n of e.matchAll(
|
|
884
|
-
},
|
|
930
|
+
for (let n of e.matchAll(sn)) if (n[0] === "(" && t++, n[0] === ")" && t--, t === 0 && n[0].toLowerCase() === "where") return e.slice(n.index + n[0].length).trim().replace(/;$/, "").trim();
|
|
931
|
+
}, ln = (e) => {
|
|
885
932
|
if (e === void 0) return;
|
|
886
|
-
let t = e.match(
|
|
933
|
+
let t = e.match(sn) ?? [], n = "(?:'(?:''|[^'])*'(?:\\s*::\\s*text)?|[0-9]+)", r = RegExp(`^\\s*${n}(?:\\s*,\\s*${n})*\\s*$`, "i");
|
|
887
934
|
for (let e = 0; e < t.length - 5; e++) {
|
|
888
935
|
let n = t[e + 4];
|
|
889
|
-
t[e] === "=" && t[e + 1]?.toLowerCase() === "any" && t[e + 2] === "(" && t[e + 3]?.toLowerCase() === "array" && n.startsWith("[") && n.endsWith("]") && t[e + 5] === ")" && r.test(n.slice(1, -1)) && t.splice(e, 6, "in", "(", ...n.slice(1, -1).match(
|
|
936
|
+
t[e] === "=" && t[e + 1]?.toLowerCase() === "any" && t[e + 2] === "(" && t[e + 3]?.toLowerCase() === "array" && n.startsWith("[") && n.endsWith("]") && t[e + 5] === ")" && r.test(n.slice(1, -1)) && t.splice(e, 6, "in", "(", ...n.slice(1, -1).match(sn) ?? [], ")");
|
|
890
937
|
}
|
|
891
938
|
let i = t.filter((e, n) => !(e === "::" && t[n - 1]?.startsWith("'") && t[n + 1]?.toLowerCase() === "text" || e.toLowerCase() === "text" && t[n - 1] === "::" && t[n - 2]?.startsWith("'"))).map((e) => {
|
|
892
939
|
if (e.startsWith("'")) return e;
|
|
@@ -924,22 +971,22 @@ BEGIN
|
|
|
924
971
|
return r;
|
|
925
972
|
};
|
|
926
973
|
return JSON.stringify(a(i));
|
|
927
|
-
},
|
|
974
|
+
}, un = (e) => {
|
|
928
975
|
if (e == null) return e;
|
|
929
|
-
if (Array.isArray(e)) return e.map(
|
|
976
|
+
if (Array.isArray(e)) return e.map(un);
|
|
930
977
|
if (typeof e != "object") return e;
|
|
931
978
|
let t = {};
|
|
932
979
|
for (let n of Object.keys(e).sort()) {
|
|
933
980
|
let r = e[n];
|
|
934
|
-
r !== void 0 && (t[n] =
|
|
981
|
+
r !== void 0 && (t[n] = un(r));
|
|
935
982
|
}
|
|
936
983
|
return t;
|
|
937
|
-
},
|
|
938
|
-
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs) return e;
|
|
939
|
-
let { idScheme: t, sensitive: n, safe: r, generatedAs: i,
|
|
940
|
-
return
|
|
941
|
-
},
|
|
942
|
-
let t =
|
|
984
|
+
}, dn = (e) => {
|
|
985
|
+
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs && !e.jsonChecks) return e;
|
|
986
|
+
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, jsonChecks: a, ...o } = e;
|
|
987
|
+
return o;
|
|
988
|
+
}, fn = (e) => {
|
|
989
|
+
let t = dn(e), { references: n, defaultValue: r, hasDefault: i, oneOf: a, ...o } = t, s = t.type === "id" && an(t) ? null : rn(t), c = L(t.references);
|
|
943
990
|
return {
|
|
944
991
|
...o,
|
|
945
992
|
hasDefault: s !== null,
|
|
@@ -947,17 +994,22 @@ BEGIN
|
|
|
947
994
|
...c === null ? {} : { references: c },
|
|
948
995
|
...t.oneOf !== void 0 && t.oneOf.length > 0 ? { oneOf: [...t.oneOf].sort() } : {}
|
|
949
996
|
};
|
|
950
|
-
},
|
|
951
|
-
...
|
|
952
|
-
|
|
953
|
-
|
|
997
|
+
}, pn = (e, t) => en(e, t) && (t.type === "text" || t.type === "id") ? {
|
|
998
|
+
...t,
|
|
999
|
+
type: "id",
|
|
1000
|
+
unique: !0
|
|
1001
|
+
} : t, mn = (e) => e.columns.filter((e) => !x(e.name)).map((t) => fn(pn(e, t))).sort((e, t) => e.name.localeCompare(t.name)), hn = (e) => [...e].map(({ kind: e, kindOptions: t, ...n }) => ({
|
|
1002
|
+
...n,
|
|
1003
|
+
...de(e, t),
|
|
1004
|
+
...n.where === void 0 ? {} : { where: ln(n.where) }
|
|
1005
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), gn = (e) => [...e].map((e) => ({
|
|
954
1006
|
name: e.name,
|
|
955
|
-
columns:
|
|
956
|
-
indexes:
|
|
957
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
958
|
-
let t = { tables:
|
|
959
|
-
return
|
|
960
|
-
},
|
|
1007
|
+
columns: mn(e),
|
|
1008
|
+
indexes: hn(e.indexes)
|
|
1009
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), R = (e) => {
|
|
1010
|
+
let t = { tables: gn(e.tables) }, n = JSON.stringify(un(t));
|
|
1011
|
+
return ie("sha256").update(n).digest("hex");
|
|
1012
|
+
}, _n = (e) => e.slice(0, 16), vn = (e, t) => {
|
|
961
1013
|
let n = t.references ? {
|
|
962
1014
|
table: t.references().tableName,
|
|
963
1015
|
column: t.referenceColumn ?? "id",
|
|
@@ -997,105 +1049,111 @@ BEGIN
|
|
|
997
1049
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
998
1050
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
999
1051
|
};
|
|
1000
|
-
},
|
|
1001
|
-
let
|
|
1002
|
-
|
|
1003
|
-
},
|
|
1004
|
-
|
|
1052
|
+
}, yn = (e, t) => {
|
|
1053
|
+
let n = [], i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
1054
|
+
i.has(e.name) || (i.add(e.name), n.push(e));
|
|
1055
|
+
}, o = e.appliedPrimaryKey ?? [];
|
|
1056
|
+
o.length > 0 ? a({
|
|
1005
1057
|
name: `${e.tableName}_pkey`,
|
|
1006
1058
|
table: e.tableName,
|
|
1007
|
-
columns: [...
|
|
1059
|
+
columns: [...o],
|
|
1008
1060
|
unique: !0
|
|
1009
|
-
}) : e.fields.id &&
|
|
1061
|
+
}) : e.fields.id && a({
|
|
1010
1062
|
name: `${e.tableName}_pkey`,
|
|
1011
1063
|
table: e.tableName,
|
|
1012
1064
|
columns: ["id"],
|
|
1013
1065
|
unique: !0
|
|
1014
1066
|
});
|
|
1015
|
-
let
|
|
1016
|
-
for (let
|
|
1017
|
-
let
|
|
1018
|
-
|
|
1019
|
-
|
|
1067
|
+
let s = e.appliedIndexes ?? [];
|
|
1068
|
+
for (let n of s) {
|
|
1069
|
+
let r = ue(n.kind, t);
|
|
1070
|
+
if (r === null) continue;
|
|
1071
|
+
let i = n.fields[0], o = typeof i == "string" ? e.fields[i]?.vectorPrecision : void 0, s = r === "hnsw" ? { hnsw: le(n.kindOptions, o) } : void 0, c = n.fields.map((e) => typeof e == "string" ? e : "jsonPath" in e ? `(json:${e.jsonPath.column}->${e.jsonPath.path.join(".")}${e.jsonPath.numeric ? "::num" : ""})` : `(${e.expr})`), l = n.fields.some((e) => typeof e != "string");
|
|
1072
|
+
a({
|
|
1073
|
+
name: n.name,
|
|
1020
1074
|
table: e.tableName,
|
|
1021
|
-
columns:
|
|
1022
|
-
unique:
|
|
1023
|
-
...
|
|
1024
|
-
...
|
|
1075
|
+
columns: c,
|
|
1076
|
+
unique: n.unique ?? !1,
|
|
1077
|
+
...de(r, s),
|
|
1078
|
+
...n.where === void 0 ? {} : { where: n.where },
|
|
1079
|
+
...l ? { expression: !0 } : {}
|
|
1025
1080
|
});
|
|
1026
1081
|
}
|
|
1027
|
-
let
|
|
1028
|
-
for (let t of
|
|
1082
|
+
let c = e.appliedUniques ?? [];
|
|
1083
|
+
for (let t of c) t.fields.length < 2 || a({
|
|
1029
1084
|
name: t.name,
|
|
1030
1085
|
table: e.tableName,
|
|
1031
1086
|
columns: t.fields,
|
|
1032
1087
|
unique: !0
|
|
1033
1088
|
});
|
|
1034
|
-
let
|
|
1035
|
-
for (let e of
|
|
1089
|
+
let l = /* @__PURE__ */ new Set();
|
|
1090
|
+
for (let e of s) e.fields.every((e) => typeof e == "string") && l.add(e.fields.join("\0"));
|
|
1036
1091
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
1037
|
-
let
|
|
1038
|
-
if (
|
|
1092
|
+
let i = n;
|
|
1093
|
+
if (i.dropped || !i.references || i.fkAutoIndex === !1 || l.has(t)) continue;
|
|
1039
1094
|
let o = `${e.tableName}_${t}_idx`;
|
|
1040
|
-
r(e.tableName, o, !0, [t]),
|
|
1095
|
+
r(e.tableName, o, !0, [t]), a({
|
|
1041
1096
|
name: o,
|
|
1042
1097
|
table: e.tableName,
|
|
1043
1098
|
columns: [t],
|
|
1044
1099
|
unique: !1
|
|
1045
1100
|
});
|
|
1046
1101
|
}
|
|
1047
|
-
return
|
|
1048
|
-
},
|
|
1049
|
-
let
|
|
1050
|
-
for (let [
|
|
1102
|
+
return n;
|
|
1103
|
+
}, bn = (e, t) => {
|
|
1104
|
+
let n = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), r = [];
|
|
1105
|
+
for (let [t, i] of Object.entries(e.fields)) {
|
|
1051
1106
|
if (i.dropped) continue;
|
|
1052
|
-
let e =
|
|
1053
|
-
|
|
1107
|
+
let e = vn(t, i);
|
|
1108
|
+
r.push(n.has(t) ? {
|
|
1054
1109
|
...e,
|
|
1055
1110
|
unique: !0
|
|
1056
1111
|
} : e);
|
|
1057
1112
|
}
|
|
1058
|
-
let
|
|
1113
|
+
let i = e.appliedPrimaryKey ?? [], a = e.previousTableName;
|
|
1059
1114
|
return {
|
|
1060
1115
|
name: e.tableName,
|
|
1061
|
-
columns:
|
|
1062
|
-
indexes:
|
|
1063
|
-
...
|
|
1064
|
-
...
|
|
1116
|
+
columns: r,
|
|
1117
|
+
indexes: yn(e, t),
|
|
1118
|
+
...i.length > 0 ? { primaryKey: [...i] } : {},
|
|
1119
|
+
...a === void 0 ? {} : { renamedFrom: a }
|
|
1065
1120
|
};
|
|
1066
|
-
},
|
|
1121
|
+
}, xn = (e) => {
|
|
1067
1122
|
let t = /* @__PURE__ */ new Map();
|
|
1068
1123
|
for (let n of e) for (let e of n.indexes) {
|
|
1069
1124
|
let r = t.get(e.name);
|
|
1070
1125
|
if (r !== void 0 && r !== n.name) throw Error(`duplicate index name '${e.name}' across tables '${r}' and '${n.name}'. Index names must be unique per SCHEMA, not just per table — the DB creates only one, so the other never applies and 'db plan' re-emits it forever. Give each an explicit, table-prefixed name (e.g. '${n.name}_${e.name}').`);
|
|
1071
1126
|
t.set(e.name, n.name);
|
|
1072
1127
|
}
|
|
1073
|
-
},
|
|
1074
|
-
let n = e.filter((e) => !c(e.tableName)).map((e) =>
|
|
1128
|
+
}, z = (e, t) => {
|
|
1129
|
+
let n = e.filter((e) => !c(e.tableName)).map((e) => bn(ye(e, t), t));
|
|
1075
1130
|
if (t === "mysql" || t === "mariadb") {
|
|
1076
1131
|
for (let e of n) for (let n of e.indexes) if (n.where !== void 0) throw Error(`Partial index '${n.name}' on '${e.name}' is not supported by ${t}. Use uniqueActive for portable conditional uniqueness.`);
|
|
1077
1132
|
}
|
|
1078
|
-
return
|
|
1079
|
-
},
|
|
1133
|
+
return xn(n), { tables: t === void 0 ? n : n.map((e) => Sn(e, t)) };
|
|
1134
|
+
}, Sn = (e, t) => {
|
|
1080
1135
|
let n = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1081
1136
|
return {
|
|
1082
1137
|
...e,
|
|
1083
1138
|
columns: e.columns.map((e) => {
|
|
1084
|
-
if (e.
|
|
1085
|
-
|
|
1139
|
+
if (t === "mssql" && !e.generatedAs && (e.type === "json" || e.type === "array") && (e = {
|
|
1140
|
+
...e,
|
|
1141
|
+
jsonValidation: e.type === "json" ? "value" : "container"
|
|
1142
|
+
}), e.maxLength !== void 0) return e;
|
|
1143
|
+
let r = on(e, t, n.has(e.name) || e.unique);
|
|
1086
1144
|
return r === void 0 ? e : {
|
|
1087
1145
|
...e,
|
|
1088
1146
|
maxLength: r
|
|
1089
1147
|
};
|
|
1090
1148
|
})
|
|
1091
1149
|
};
|
|
1092
|
-
},
|
|
1150
|
+
}, Cn = (e, t, n = A) => T.gen(function* () {
|
|
1093
1151
|
let r = (yield* e`
|
|
1094
1152
|
SELECT p.prosrc
|
|
1095
1153
|
FROM pg_proc p
|
|
1096
1154
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
1097
1155
|
WHERE n.nspname = current_schema()
|
|
1098
|
-
AND p.proname = ${
|
|
1156
|
+
AND p.proname = ${lt(n)}
|
|
1099
1157
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
1100
1158
|
if (a.length === 0) return {
|
|
1101
1159
|
missing: [],
|
|
@@ -1109,10 +1167,10 @@ BEGIN
|
|
|
1109
1167
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1110
1168
|
WHERE NOT t.tgisinternal
|
|
1111
1169
|
AND n.nspname = current_schema()
|
|
1112
|
-
AND t.tgname LIKE ${`${
|
|
1170
|
+
AND t.tgname LIKE ${`${st}%`}
|
|
1113
1171
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
1114
1172
|
for (let e of a) {
|
|
1115
|
-
let t = s.has(
|
|
1173
|
+
let t = s.has(ct(e.tableName, n)), r = e.isReactive !== !1;
|
|
1116
1174
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
1117
1175
|
}
|
|
1118
1176
|
return {
|
|
@@ -1120,7 +1178,7 @@ BEGIN
|
|
|
1120
1178
|
stale: l.sort(),
|
|
1121
1179
|
functionOutdated: i
|
|
1122
1180
|
};
|
|
1123
|
-
}),
|
|
1181
|
+
}), wn = (e) => {
|
|
1124
1182
|
let t = [];
|
|
1125
1183
|
if (e.missing.length > 0) {
|
|
1126
1184
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -1131,19 +1189,19 @@ BEGIN
|
|
|
1131
1189
|
t.push(`${e.stale.length} .nonReactive() table(s) still carry a change trigger — ${n}. They keep paying REPLICA IDENTITY FULL and a NOTIFY on every write for a subscription nobody receives. \`voltro db apply\` removes them.`);
|
|
1132
1190
|
}
|
|
1133
1191
|
return e.functionOutdated && t.push("The change-notify function in this database is OLDER than the framework installed here. Its triggers fire, so nothing looks wrong — but a row too large for a NOTIFY payload (postgres caps it at 8000 bytes) is emitted without its primary key, and a change that carries no key cannot be re-read: it reaches subscriptions as a re-query and reaches every TAP — search index, analytics mirror, cdc-out, row history — as nothing at all. Run `voltro db apply` to replace it."), t.length > 0 ? t.join("\n") : void 0;
|
|
1134
|
-
},
|
|
1192
|
+
}, Tn = {
|
|
1135
1193
|
postgres: !0,
|
|
1136
1194
|
mysql: !0,
|
|
1137
1195
|
mariadb: !0,
|
|
1138
1196
|
mssql: !0,
|
|
1139
1197
|
sqlite: !0
|
|
1140
|
-
},
|
|
1198
|
+
}, En = {
|
|
1141
1199
|
postgres: !0,
|
|
1142
1200
|
mysql: !1,
|
|
1143
1201
|
mariadb: !1,
|
|
1144
1202
|
mssql: !0,
|
|
1145
1203
|
sqlite: !0
|
|
1146
|
-
},
|
|
1204
|
+
}, Dn = (e) => {
|
|
1147
1205
|
switch (e) {
|
|
1148
1206
|
case "add-column":
|
|
1149
1207
|
case "drop-column":
|
|
@@ -1153,43 +1211,43 @@ BEGIN
|
|
|
1153
1211
|
case "add-foreign-key":
|
|
1154
1212
|
case "add-unique":
|
|
1155
1213
|
case "add-unique-composite":
|
|
1156
|
-
case "add-check": return
|
|
1157
|
-
default: return
|
|
1214
|
+
case "add-check": return En;
|
|
1215
|
+
default: return Tn;
|
|
1158
1216
|
}
|
|
1159
|
-
},
|
|
1217
|
+
}, On = (e, t) => {
|
|
1160
1218
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1161
1219
|
return new Map(e.map((e) => [e.tableName, {
|
|
1162
1220
|
table: e,
|
|
1163
1221
|
snapshot: n.get(e.tableName),
|
|
1164
1222
|
columnDefs: e.fields
|
|
1165
1223
|
}]));
|
|
1166
|
-
},
|
|
1167
|
-
let n =
|
|
1224
|
+
}, kn = (e, t) => {
|
|
1225
|
+
let n = nn(e), r = nn(t);
|
|
1168
1226
|
if (n === r) return !0;
|
|
1169
|
-
let i =
|
|
1170
|
-
return e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e)) ? !0 :
|
|
1171
|
-
},
|
|
1227
|
+
let i = an, a = (e) => e.type === "id" && e.idScheme?.kind === "numeric";
|
|
1228
|
+
return e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e)) ? !0 : rn(e) === rn(t);
|
|
1229
|
+
}, An = (e, t) => {
|
|
1172
1230
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1173
1231
|
if (!n && !r) return !0;
|
|
1174
1232
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1175
1233
|
let i = [...n].sort(), a = [...r].sort();
|
|
1176
1234
|
return i.every((e, t) => e === a[t]);
|
|
1177
|
-
},
|
|
1235
|
+
}, jn = (e, t, n, r) => n === void 0 || m(n) ? !0 : e.type !== "text" || t.type !== "text" || on(e, n, r) === t.maxLength, Mn = (e, t, n, r, i = !1) => (e.type === t.type || tn(e, t, i)) && e.nullable === t.nullable && (e.unique === t.unique || tn(e, t, i)) && e.jsonValidation === t.jsonValidation && kn(e, t) && jn(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(L(e.references)) === JSON.stringify(L(t.references)) && An(e.oneOf, t.oneOf), Nn = (e, t) => t.oneOf && t.oneOf.length > 0 ? B({
|
|
1178
1236
|
kind: "add-check",
|
|
1179
1237
|
table: e,
|
|
1180
1238
|
column: t.name,
|
|
1181
1239
|
values: t.oneOf
|
|
1182
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1240
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, Pn = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && ln(e.where) === ln(t.where) && JSON.stringify(de(e.kind, e.kindOptions)) === JSON.stringify(de(t.kind, t.kindOptions)) && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), Fn = (e, t, n) => {
|
|
1183
1241
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [], c = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1184
1242
|
for (let t of e.columns) {
|
|
1185
|
-
let
|
|
1186
|
-
if (!
|
|
1243
|
+
let i = r.get(t.name);
|
|
1244
|
+
if (!i) {
|
|
1187
1245
|
a.push(t);
|
|
1188
1246
|
continue;
|
|
1189
1247
|
}
|
|
1190
|
-
|
|
1248
|
+
Mn(t, i, n, c.has(t.name) || t.unique, en(e, t)) || s.push({
|
|
1191
1249
|
declared: t,
|
|
1192
|
-
live:
|
|
1250
|
+
live: i
|
|
1193
1251
|
});
|
|
1194
1252
|
}
|
|
1195
1253
|
for (let e of t.columns) i.has(e.name) || o.push(e);
|
|
@@ -1198,50 +1256,50 @@ BEGIN
|
|
|
1198
1256
|
removed: o,
|
|
1199
1257
|
changed: s
|
|
1200
1258
|
};
|
|
1201
|
-
},
|
|
1259
|
+
}, In = (e, t, n) => {
|
|
1202
1260
|
let r = (e) => n === "turso" || n === "sqlite" ? e.toLowerCase() : e, i = new Map(t.indexes.map((e) => [r(e.name), e])), a = new Map(e.indexes.map((e) => [r(e.name), e])), o = [], s = [];
|
|
1203
1261
|
for (let t of e.indexes) {
|
|
1204
1262
|
let e = i.get(r(t.name));
|
|
1205
|
-
(!e || !
|
|
1263
|
+
(!e || !Pn(t, e)) && o.push(t);
|
|
1206
1264
|
}
|
|
1207
1265
|
for (let e of t.indexes) {
|
|
1208
1266
|
let t = a.get(r(e.name));
|
|
1209
|
-
(!t ||
|
|
1267
|
+
(!t || !Pn(t, e)) && s.push(e);
|
|
1210
1268
|
}
|
|
1211
1269
|
return {
|
|
1212
1270
|
added: o,
|
|
1213
1271
|
removed: s
|
|
1214
1272
|
};
|
|
1215
|
-
},
|
|
1273
|
+
}, B = (e, t, n, r) => ({
|
|
1216
1274
|
op: e,
|
|
1217
1275
|
classification: t,
|
|
1218
|
-
atomicByDialect:
|
|
1276
|
+
atomicByDialect: Dn(e.kind),
|
|
1219
1277
|
...n ? { reason: n } : {},
|
|
1220
1278
|
...r ? { blocked: r } : {}
|
|
1221
|
-
}),
|
|
1279
|
+
}), Ln = (e, t, n) => {
|
|
1222
1280
|
let r = {
|
|
1223
1281
|
kind: "add-column",
|
|
1224
1282
|
table: e,
|
|
1225
1283
|
column: t
|
|
1226
1284
|
};
|
|
1227
|
-
return t.nullable ?
|
|
1228
|
-
},
|
|
1285
|
+
return t.nullable ? B(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? B(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? B(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : B(r, "needs-backfill", "NOT NULL column on a table whose row count is unknown", { fix: `declare \`${t.name}: <type>().backfill(sql\`...\`)\` OR \`.default(value)\` so existing rows survive the migration` });
|
|
1286
|
+
}, Rn = (e, t, n) => {
|
|
1229
1287
|
let r = {
|
|
1230
1288
|
kind: "drop-column",
|
|
1231
1289
|
table: e,
|
|
1232
1290
|
column: t.name
|
|
1233
1291
|
};
|
|
1234
|
-
return n?.dropped ?
|
|
1235
|
-
},
|
|
1292
|
+
return n?.dropped ? B(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : B(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1293
|
+
}, zn = (e, t, n, r, i) => B({
|
|
1236
1294
|
kind: "create-table",
|
|
1237
1295
|
table: e,
|
|
1238
1296
|
columns: t,
|
|
1239
1297
|
indexes: n,
|
|
1240
1298
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1241
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1299
|
+
}, "safe", i ?? "new table — no data to preserve"), Bn = (e) => B({
|
|
1242
1300
|
kind: "drop-table",
|
|
1243
1301
|
table: e
|
|
1244
|
-
}, "lossy", "table missing from declared schema", { fix: "if intentional, set VOLTRO_DESTRUCTIVE_OK=1 OR add a file-based migration. If a typo, restore the table declaration" }),
|
|
1302
|
+
}, "lossy", "table missing from declared schema", { fix: "if intentional, set VOLTRO_DESTRUCTIVE_OK=1 OR add a file-based migration. If a typo, restore the table declaration" }), Vn = 5e4, Hn = (e, t, n, r) => {
|
|
1245
1303
|
let i = (n ?? 0) >= r, a;
|
|
1246
1304
|
return a = !t.unique || t.where !== void 0 ? {
|
|
1247
1305
|
kind: "add-index",
|
|
@@ -1256,28 +1314,28 @@ BEGIN
|
|
|
1256
1314
|
table: e,
|
|
1257
1315
|
name: t.name,
|
|
1258
1316
|
fields: t.columns
|
|
1259
|
-
}, i ?
|
|
1260
|
-
},
|
|
1317
|
+
}, i ? B(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : B(a, "safe", t.where === void 0 ? t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : `add ${t.kind === void 0 || t.kind === "btree" ? "B-tree" : t.kind.toUpperCase()} index` : `add ${t.unique ? "unique " : ""}partial index`);
|
|
1318
|
+
}, Un = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ? B({
|
|
1261
1319
|
kind: "drop-unique-composite",
|
|
1262
1320
|
table: e,
|
|
1263
1321
|
name: t.name
|
|
1264
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1322
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : B({
|
|
1265
1323
|
kind: "drop-index",
|
|
1266
1324
|
table: e,
|
|
1267
1325
|
index: t.name
|
|
1268
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1326
|
+
}, "safe", "drop index (no data loss — index is derived data)"), Wn = (e, t) => {
|
|
1269
1327
|
let n = e.type;
|
|
1270
1328
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
1271
1329
|
switch (t) {
|
|
1272
1330
|
case "sqlite":
|
|
1273
1331
|
case "turso": return n === "timestamp" || n === "date" || n === "json" ? "text" : n === "boolean" ? "integer" : n === "decimal" ? "text" : n === "bigint" ? "integer" : n;
|
|
1274
|
-
case "mssql": return n === "json" ? "text" : n;
|
|
1332
|
+
case "mssql": return n === "json" || n === "array" ? "text" : n;
|
|
1275
1333
|
default: return n;
|
|
1276
1334
|
}
|
|
1277
|
-
},
|
|
1335
|
+
}, Gn = (e, t, n) => {
|
|
1278
1336
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1279
1337
|
return n === "postgres" ? `${r} — add \`{ using: '${t.name}::${t.type}' }\` when the cast is not implicit, or use a file-based migration` : `${r} — ${n === void 0 ? "this dialect" : n} converts in place (\`using\` is postgres-only and is ignored here), so verify the conversion is value-preserving for your data, or use a file-based migration`;
|
|
1280
|
-
},
|
|
1338
|
+
}, Kn = (e, t, n, r, i, a) => {
|
|
1281
1339
|
let o = [];
|
|
1282
1340
|
if (t.nullable !== n.nullable) {
|
|
1283
1341
|
let n = {
|
|
@@ -1286,7 +1344,7 @@ BEGIN
|
|
|
1286
1344
|
column: t.name,
|
|
1287
1345
|
toNullable: t.nullable
|
|
1288
1346
|
};
|
|
1289
|
-
o.push(t.nullable ?
|
|
1347
|
+
o.push(t.nullable ? B(n, "safe", `loosen ${e}.${t.name} to nullable`) : B(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1290
1348
|
}
|
|
1291
1349
|
if (t.unique !== n.unique) {
|
|
1292
1350
|
if (t.unique) {
|
|
@@ -1295,14 +1353,14 @@ BEGIN
|
|
|
1295
1353
|
table: e,
|
|
1296
1354
|
column: t.name
|
|
1297
1355
|
}, r = (i ?? 0) >= a;
|
|
1298
|
-
o.push(r ?
|
|
1299
|
-
} else o.push(
|
|
1356
|
+
o.push(r ? B(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : B(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1357
|
+
} else o.push(B({
|
|
1300
1358
|
kind: "drop-unique",
|
|
1301
1359
|
table: e,
|
|
1302
1360
|
column: t.name
|
|
1303
1361
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1304
1362
|
}
|
|
1305
|
-
if (
|
|
1363
|
+
if (Wn(t, r) !== Wn(n, r)) {
|
|
1306
1364
|
let i = t.narrowedFrom;
|
|
1307
1365
|
if (i && i.from === n.type) {
|
|
1308
1366
|
let r = {
|
|
@@ -1313,7 +1371,7 @@ BEGIN
|
|
|
1313
1371
|
to: t.type,
|
|
1314
1372
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1315
1373
|
};
|
|
1316
|
-
o.push(
|
|
1374
|
+
o.push(B(r, "needs-backfill", `type change ${n.type} → ${t.type} on ${e}.${t.name} — narrowedFrom('${i.from}') declared` + (i.using ? ` with USING ${i.using}` : " (implicit cast)")));
|
|
1317
1375
|
} else {
|
|
1318
1376
|
let i = {
|
|
1319
1377
|
kind: "alter-column-type",
|
|
@@ -1322,12 +1380,12 @@ BEGIN
|
|
|
1322
1380
|
from: n.type,
|
|
1323
1381
|
to: t.type
|
|
1324
1382
|
};
|
|
1325
|
-
o.push(
|
|
1383
|
+
o.push(B(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: Gn(n.type, t, r) }));
|
|
1326
1384
|
}
|
|
1327
1385
|
}
|
|
1328
1386
|
if (t.type === "text" && n.type === "text" && !m(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1329
1387
|
let r = t.maxLength === void 0 || n.maxLength !== void 0 && t.maxLength > n.maxLength, i = n.maxLength === void 0 ? "unbounded" : `varchar(${n.maxLength})`, a = t.maxLength === void 0 ? "unbounded" : `varchar(${t.maxLength})`;
|
|
1330
|
-
o.push(
|
|
1388
|
+
o.push(B({
|
|
1331
1389
|
kind: "alter-column-type",
|
|
1332
1390
|
table: e,
|
|
1333
1391
|
column: t.name,
|
|
@@ -1335,7 +1393,7 @@ BEGIN
|
|
|
1335
1393
|
to: "text"
|
|
1336
1394
|
}, r ? "safe" : "needs-backfill", r ? `text length ${i} → ${a} on ${e}.${t.name} — widening, no data can be lost` : `text length ${i} → ${a} on ${e}.${t.name} — NARROWING; the ALTER fails if any existing value is longer than ${String(t.maxLength)}. Check first: SELECT COUNT(*) FROM ${e} WHERE LENGTH(${t.name}) > ${String(t.maxLength)}`));
|
|
1337
1395
|
}
|
|
1338
|
-
if (!
|
|
1396
|
+
if (!kn(t, n)) {
|
|
1339
1397
|
let n = {
|
|
1340
1398
|
kind: "alter-column-default",
|
|
1341
1399
|
table: e,
|
|
@@ -1343,23 +1401,34 @@ BEGIN
|
|
|
1343
1401
|
hasDefault: t.hasDefault,
|
|
1344
1402
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1345
1403
|
};
|
|
1346
|
-
o.push(
|
|
1404
|
+
o.push(B(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1347
1405
|
}
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1406
|
+
if (r === "mssql" && t.jsonValidation !== void 0 && t.jsonValidation !== "unverified" && t.jsonValidation !== n.jsonValidation) {
|
|
1407
|
+
let r = t.jsonValidation === "value" && n.jsonValidation === "container";
|
|
1408
|
+
o.push(B({
|
|
1409
|
+
kind: "reconcile-json-check",
|
|
1410
|
+
table: e,
|
|
1411
|
+
column: t.name,
|
|
1412
|
+
validation: t.jsonValidation,
|
|
1413
|
+
previousValidation: n.jsonValidation ?? "absent",
|
|
1414
|
+
dropConstraints: (n.jsonChecks ?? []).map((e) => e.name).sort()
|
|
1415
|
+
}, r ? "safe" : "needs-backfill", r ? `allow every JSON value on ${e}.${t.name}; preserve existing rows` : `validate existing JSON on ${e}.${t.name}; invalid rows refuse the migration without being rewritten`));
|
|
1416
|
+
}
|
|
1417
|
+
if (!An(t.oneOf, n.oneOf)) {
|
|
1418
|
+
n.oneOf && n.oneOf.length > 0 && o.push(B({
|
|
1350
1419
|
kind: "drop-check",
|
|
1351
1420
|
table: e,
|
|
1352
1421
|
column: t.name
|
|
1353
1422
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1354
|
-
let r =
|
|
1423
|
+
let r = Nn(e, t);
|
|
1355
1424
|
r && o.push(r);
|
|
1356
1425
|
}
|
|
1357
|
-
return JSON.stringify(
|
|
1426
|
+
return JSON.stringify(L(t.references)) !== JSON.stringify(L(n.references)) && (n.references && o.push(B({
|
|
1358
1427
|
kind: "drop-foreign-key",
|
|
1359
1428
|
table: e,
|
|
1360
1429
|
column: t.name
|
|
1361
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1362
|
-
},
|
|
1430
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...qn(e, t))), o;
|
|
1431
|
+
}, qn = (e, t) => {
|
|
1363
1432
|
let n = [];
|
|
1364
1433
|
if (!t.references) return n;
|
|
1365
1434
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1371,15 +1440,15 @@ BEGIN
|
|
|
1371
1440
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1372
1441
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1373
1442
|
};
|
|
1374
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1443
|
+
return i === "null" && !t.nullable ? n.push(B(a, "lossy", `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' needs a nullable column (the NULL-out would violate NOT NULL)`, { fix: `make ${t.name} \`.nullable()\`, OR use \`orphanPolicy: 'delete'\`, OR clean the orphans and drop the policy` })) : i === "null" || i === "delete" ? n.push(B({
|
|
1375
1444
|
...a,
|
|
1376
1445
|
orphanPolicy: i
|
|
1377
|
-
}, "lossy", i === "delete" ? `add FK ${e}.${t.name} → ${r}: orphanPolicy 'delete' first DELETES rows whose ${t.name} points at a missing ${r}` : `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' first NULLs ${t.name} where it points at a missing ${r}`)) : n.push(
|
|
1378
|
-
},
|
|
1446
|
+
}, "lossy", i === "delete" ? `add FK ${e}.${t.name} → ${r}: orphanPolicy 'delete' first DELETES rows whose ${t.name} points at a missing ${r}` : `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' first NULLs ${t.name} where it points at a missing ${r}`)) : n.push(B(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1447
|
+
}, Jn = (e, t, n) => {
|
|
1379
1448
|
let r = [], i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), o = new Set(n.removed.map((e) => e.name)), s = new Set(n.added.map((e) => e.name));
|
|
1380
1449
|
for (let [n, c] of Object.entries(t)) {
|
|
1381
1450
|
let t = c.renamedFrom;
|
|
1382
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1451
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(B({
|
|
1383
1452
|
kind: "rename-column",
|
|
1384
1453
|
table: e.tableName,
|
|
1385
1454
|
from: t,
|
|
@@ -1391,30 +1460,30 @@ BEGIN
|
|
|
1391
1460
|
consumedAddedNames: i,
|
|
1392
1461
|
consumedRemovedNames: a
|
|
1393
1462
|
};
|
|
1394
|
-
},
|
|
1463
|
+
}, Yn = /* @__PURE__ */ new Set([
|
|
1395
1464
|
"postgres",
|
|
1396
1465
|
"mysql",
|
|
1397
1466
|
"mariadb",
|
|
1398
1467
|
"mssql"
|
|
1399
|
-
]),
|
|
1468
|
+
]), Xn = {
|
|
1400
1469
|
ops: [],
|
|
1401
1470
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1402
1471
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1403
|
-
},
|
|
1404
|
-
if (i === void 0 || !
|
|
1405
|
-
let a = t.added.filter((e) =>
|
|
1406
|
-
if (a.length === 0) return
|
|
1472
|
+
}, Zn = (e) => !e.unique && !e.expression && e.where === void 0 && (e.kind === void 0 || e.kind === "btree"), Qn = (e, t, n, r, i) => {
|
|
1473
|
+
if (i === void 0 || !Yn.has(i)) return Xn;
|
|
1474
|
+
let a = t.added.filter((e) => Zn(e) && !r.has(e.name));
|
|
1475
|
+
if (a.length === 0) return Xn;
|
|
1407
1476
|
let o = (e) => e.columns.map((e) => n.get(e) ?? e).join("\0"), s = (e) => e.columns.join("\0"), c = [], l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set();
|
|
1408
1477
|
for (let n of t.removed) {
|
|
1409
|
-
if (!
|
|
1410
|
-
let
|
|
1411
|
-
if (
|
|
1412
|
-
let
|
|
1413
|
-
|
|
1478
|
+
if (!Zn(n) || t.added.some((e) => e.name === n.name)) continue;
|
|
1479
|
+
let r = o(n), i = a.filter((e) => !l.has(e.name) && s(e) === r);
|
|
1480
|
+
if (i.length !== 1) continue;
|
|
1481
|
+
let d = i[0];
|
|
1482
|
+
d.name !== n.name && (l.add(d.name), u.add(n.name), c.push(B({
|
|
1414
1483
|
kind: "rename-index",
|
|
1415
1484
|
table: e,
|
|
1416
1485
|
from: n.name,
|
|
1417
|
-
to:
|
|
1486
|
+
to: d.name
|
|
1418
1487
|
}, "safe", "rename index in place — catalog-only, no rebuild")));
|
|
1419
1488
|
}
|
|
1420
1489
|
return {
|
|
@@ -1422,7 +1491,7 @@ BEGIN
|
|
|
1422
1491
|
consumedAddedNames: l,
|
|
1423
1492
|
consumedRemovedNames: u
|
|
1424
1493
|
};
|
|
1425
|
-
},
|
|
1494
|
+
}, $n = (e, t, n) => {
|
|
1426
1495
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1427
1496
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1428
1497
|
for (let c of e.tables) {
|
|
@@ -1433,7 +1502,7 @@ BEGIN
|
|
|
1433
1502
|
continue;
|
|
1434
1503
|
}
|
|
1435
1504
|
if (t.has(c.name)) {
|
|
1436
|
-
r.push(
|
|
1505
|
+
r.push(B({
|
|
1437
1506
|
kind: "rename-table",
|
|
1438
1507
|
from: e,
|
|
1439
1508
|
to: c.name
|
|
@@ -1441,14 +1510,14 @@ BEGIN
|
|
|
1441
1510
|
continue;
|
|
1442
1511
|
}
|
|
1443
1512
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1444
|
-
r.push(
|
|
1513
|
+
r.push(B({
|
|
1445
1514
|
kind: "rename-table",
|
|
1446
1515
|
from: e,
|
|
1447
1516
|
to: c.name
|
|
1448
1517
|
}, "needs-rename-annotation", `.renamedFrom('${e}') is claimed by ${s.get(e)} tables — nothing says which receives its rows`, { fix: `remove the \`.renamedFrom('${e}')\` marker from all but one of them.` }));
|
|
1449
1518
|
continue;
|
|
1450
1519
|
}
|
|
1451
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1520
|
+
i.set(c.name, e), a.add(e), r.push(B({
|
|
1452
1521
|
kind: "rename-table",
|
|
1453
1522
|
from: e,
|
|
1454
1523
|
to: c.name
|
|
@@ -1462,19 +1531,19 @@ BEGIN
|
|
|
1462
1531
|
claimedOldNames: c,
|
|
1463
1532
|
refusals: o
|
|
1464
1533
|
};
|
|
1465
|
-
},
|
|
1534
|
+
}, er = (e, t, n, r) => {
|
|
1466
1535
|
if (t === void 0) return {
|
|
1467
1536
|
live: e,
|
|
1468
1537
|
ops: []
|
|
1469
1538
|
};
|
|
1470
|
-
let i = r !== void 0 &&
|
|
1539
|
+
let i = r !== void 0 && Yn.has(r), a = [], o = e.indexes.map((e) => {
|
|
1471
1540
|
if (!e.name.startsWith(t)) return e;
|
|
1472
1541
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1473
1542
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1474
1543
|
...e,
|
|
1475
1544
|
name: r,
|
|
1476
1545
|
table: n
|
|
1477
|
-
} : i ? (a.push(
|
|
1546
|
+
} : i ? (a.push(B({
|
|
1478
1547
|
kind: "rename-index",
|
|
1479
1548
|
table: n,
|
|
1480
1549
|
from: e.name,
|
|
@@ -1493,7 +1562,7 @@ BEGIN
|
|
|
1493
1562
|
},
|
|
1494
1563
|
ops: a
|
|
1495
1564
|
};
|
|
1496
|
-
},
|
|
1565
|
+
}, tr = (e) => {
|
|
1497
1566
|
let t = {
|
|
1498
1567
|
safe: 0,
|
|
1499
1568
|
needsDefault: 0,
|
|
@@ -1526,13 +1595,13 @@ BEGIN
|
|
|
1526
1595
|
case "multi-step": t.multiStep++;
|
|
1527
1596
|
}
|
|
1528
1597
|
return t;
|
|
1529
|
-
},
|
|
1530
|
-
let t =
|
|
1598
|
+
}, nr = (e) => {
|
|
1599
|
+
let t = z(e.declared, e.dialect), n = On(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? Vn, a = [], o = $n(t, r, n);
|
|
1531
1600
|
a.push(...o.ops);
|
|
1532
1601
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1533
|
-
a.push(
|
|
1602
|
+
a.push(zn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1534
1603
|
for (let t of e.columns) {
|
|
1535
|
-
let n =
|
|
1604
|
+
let n = Nn(e.name, t);
|
|
1536
1605
|
n && a.push(n);
|
|
1537
1606
|
}
|
|
1538
1607
|
}
|
|
@@ -1554,32 +1623,40 @@ BEGIN
|
|
|
1554
1623
|
c.push(t.name);
|
|
1555
1624
|
continue;
|
|
1556
1625
|
}
|
|
1557
|
-
a.push(
|
|
1626
|
+
a.push(Bn(t.name));
|
|
1558
1627
|
}
|
|
1559
1628
|
for (let s of t.tables) {
|
|
1560
1629
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1561
1630
|
if (!c) continue;
|
|
1562
|
-
let l =
|
|
1631
|
+
let l = er(c, t, s.name, e.dialect);
|
|
1563
1632
|
a.push(...l.ops);
|
|
1564
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1633
|
+
let u = l.live, d = n.get(s.name), f = Fn(s, u, e.dialect), p = In(s, u, e.dialect), m = Jn(d.table, d.columnDefs, f);
|
|
1565
1634
|
a.push(...m.ops);
|
|
1635
|
+
for (let { op: t } of m.ops) {
|
|
1636
|
+
if (t.kind !== "rename-column") continue;
|
|
1637
|
+
let n = s.columns.find((e) => e.name === t.to), r = u.columns.find((e) => e.name === t.from);
|
|
1638
|
+
n && r && a.push(...Kn(s.name, n, {
|
|
1639
|
+
...r,
|
|
1640
|
+
name: t.to
|
|
1641
|
+
}, e.dialect, u.rowCount, i));
|
|
1642
|
+
}
|
|
1566
1643
|
for (let e of f.removed) {
|
|
1567
1644
|
if (m.consumedRemovedNames.has(e.name) || x(e.name)) continue;
|
|
1568
1645
|
let t = d.columnDefs[e.name];
|
|
1569
|
-
a.push(
|
|
1646
|
+
a.push(Rn(s.name, e, t));
|
|
1570
1647
|
}
|
|
1571
1648
|
for (let e of f.added) {
|
|
1572
1649
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1573
1650
|
let t = d.columnDefs[e.name];
|
|
1574
|
-
a.push(
|
|
1575
|
-
let n =
|
|
1576
|
-
n && a.push(n), a.push(...
|
|
1651
|
+
a.push(Ln(s.name, e, t));
|
|
1652
|
+
let n = Nn(s.name, e);
|
|
1653
|
+
n && a.push(n), a.push(...qn(s.name, e));
|
|
1577
1654
|
}
|
|
1578
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1655
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Qn(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1579
1656
|
a.push(...g.ops);
|
|
1580
|
-
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(
|
|
1581
|
-
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(
|
|
1582
|
-
for (let { declared: t, live: n } of f.changed) a.push(...
|
|
1657
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(Hn(s.name, e, u.rowCount, i));
|
|
1658
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(Un(s.name, e));
|
|
1659
|
+
for (let { declared: t, live: n } of f.changed) a.push(...Kn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1583
1660
|
}
|
|
1584
1661
|
let l = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), u = new Map(t.tables.map((e) => [e.name, e])), d = (e) => {
|
|
1585
1662
|
let t = u.get(e);
|
|
@@ -1587,8 +1664,8 @@ BEGIN
|
|
|
1587
1664
|
column: e.name,
|
|
1588
1665
|
target: e.references.table
|
|
1589
1666
|
}] : []) : [];
|
|
1590
|
-
}, f =
|
|
1591
|
-
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) t.references && f.has(D(e.name, t.name)) && p.push(
|
|
1667
|
+
}, f = be([...l], d), p = [];
|
|
1668
|
+
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) t.references && f.has(D(e.name, t.name)) && p.push(B({
|
|
1592
1669
|
kind: "add-foreign-key",
|
|
1593
1670
|
table: e.name,
|
|
1594
1671
|
column: t.name,
|
|
@@ -1647,7 +1724,8 @@ BEGIN
|
|
|
1647
1724
|
"add-unique": 5,
|
|
1648
1725
|
"add-unique-composite": 5,
|
|
1649
1726
|
"add-foreign-key": 5,
|
|
1650
|
-
"add-check": 5
|
|
1727
|
+
"add-check": 5,
|
|
1728
|
+
"reconcile-json-check": 5
|
|
1651
1729
|
}, S = (e) => b[e] ?? 9, C = [...a].sort((e, t) => {
|
|
1652
1730
|
let n = v(e.op.kind), r = v(t.op.kind);
|
|
1653
1731
|
if (n !== r) return n - r;
|
|
@@ -1663,19 +1741,34 @@ BEGIN
|
|
|
1663
1741
|
for (let e of t.tables) {
|
|
1664
1742
|
if (w.has(e.name) || o.renamedInto.has(e.name)) continue;
|
|
1665
1743
|
let t = r.get(e.name);
|
|
1666
|
-
t !== void 0 &&
|
|
1744
|
+
t !== void 0 && R({ tables: [t] }) !== R({ tables: [e] }) && T.push(e.name);
|
|
1667
1745
|
}
|
|
1668
1746
|
return {
|
|
1669
1747
|
operations: C,
|
|
1670
|
-
fromFingerprint:
|
|
1671
|
-
toFingerprint:
|
|
1672
|
-
summary:
|
|
1748
|
+
fromFingerprint: R(e.live),
|
|
1749
|
+
toFingerprint: R(t),
|
|
1750
|
+
summary: tr(C),
|
|
1673
1751
|
fingerprintDivergence: {
|
|
1674
1752
|
outsideDiff: c,
|
|
1675
1753
|
diffEquivalent: T
|
|
1676
1754
|
}
|
|
1677
1755
|
};
|
|
1678
|
-
},
|
|
1756
|
+
}, rr = (e, t) => {
|
|
1757
|
+
let n = (e.match(/'(?:''|[^'])*'|"(?:""|[^"])*"|::|[A-Za-z_][A-Za-z_0-9$]*|[^\s]/g) ?? []).filter((e) => e !== "(" && e !== ")"), r = 0, i = (e) => n[r]?.toLowerCase() === e && (r++, !0);
|
|
1758
|
+
if (!i("check")) return null;
|
|
1759
|
+
let a = n[r++];
|
|
1760
|
+
if (a === void 0 || (a.startsWith("\"") ? a.slice(1, -1).replace(/""/g, "\"") : a.toLowerCase()) !== t) return null;
|
|
1761
|
+
let o = () => !i("::") || i("text") || i("character") && i("varying");
|
|
1762
|
+
if (!o() || !i("=")) return null;
|
|
1763
|
+
let s = i("any");
|
|
1764
|
+
if (s && (!i("array") || !i("["))) return null;
|
|
1765
|
+
let c = [];
|
|
1766
|
+
do {
|
|
1767
|
+
let e = n[r++];
|
|
1768
|
+
if (e === void 0 || !/^'(?:''|[^'])*'$/.test(e) || (c.push(e.slice(1, -1).replace(/''/g, "'")), !o())) return null;
|
|
1769
|
+
} while (s && i(","));
|
|
1770
|
+
return s && (!i("]") || i("::") && (!i("text") || !i("[") || !i("]"))) ? null : r === n.length ? c : null;
|
|
1771
|
+
}, ir = (e) => {
|
|
1679
1772
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1680
1773
|
if (!t) return null;
|
|
1681
1774
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -1683,8 +1776,8 @@ BEGIN
|
|
|
1683
1776
|
column: t[1],
|
|
1684
1777
|
values: n
|
|
1685
1778
|
};
|
|
1686
|
-
},
|
|
1687
|
-
if (t === "vector") return "vector";
|
|
1779
|
+
}, ar = (e, t) => {
|
|
1780
|
+
if (t === "vector" || t === "halfvec") return "vector";
|
|
1688
1781
|
switch (e) {
|
|
1689
1782
|
case "text":
|
|
1690
1783
|
case "character varying":
|
|
@@ -1710,10 +1803,10 @@ BEGIN
|
|
|
1710
1803
|
case "USER-DEFINED": return "text";
|
|
1711
1804
|
default: return "text";
|
|
1712
1805
|
}
|
|
1713
|
-
},
|
|
1806
|
+
}, or = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1714
1807
|
expr: e,
|
|
1715
1808
|
stored: t
|
|
1716
|
-
} },
|
|
1809
|
+
} }, V = (e) => {
|
|
1717
1810
|
switch (e.toUpperCase()) {
|
|
1718
1811
|
case "CASCADE": return "cascade";
|
|
1719
1812
|
case "RESTRICT": return "restrict";
|
|
@@ -1721,25 +1814,25 @@ BEGIN
|
|
|
1721
1814
|
case "SET DEFAULT": return "noAction";
|
|
1722
1815
|
default: return "noAction";
|
|
1723
1816
|
}
|
|
1724
|
-
},
|
|
1817
|
+
}, sr = (e, t) => {
|
|
1725
1818
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1726
1819
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1727
|
-
},
|
|
1820
|
+
}, cr = () => sr(process.env.VOLTRO_INTROSPECT_BATCH, 20), lr = 300, ur = () => {
|
|
1728
1821
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1729
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1730
|
-
},
|
|
1822
|
+
return e !== void 0 && e.trim() === "0" ? 0 : sr(e, 3e4);
|
|
1823
|
+
}, dr = (e, t) => {
|
|
1731
1824
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1732
1825
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1733
1826
|
return r;
|
|
1734
|
-
},
|
|
1735
|
-
let t =
|
|
1827
|
+
}, fr = (e) => {
|
|
1828
|
+
let t = ur(), n = T.gen(function* () {
|
|
1736
1829
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1737
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
1830
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = cr(), a = (e, t) => T.gen(function* () {
|
|
1738
1831
|
let r = [];
|
|
1739
|
-
for (let a of
|
|
1832
|
+
for (let a of dr(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1740
1833
|
return r;
|
|
1741
1834
|
}), o = [];
|
|
1742
|
-
for (let t = 0;; t +=
|
|
1835
|
+
for (let t = 0;; t += lr) {
|
|
1743
1836
|
let n = yield* e`
|
|
1744
1837
|
SELECT c.relname AS table_name,
|
|
1745
1838
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1747,16 +1840,21 @@ BEGIN
|
|
|
1747
1840
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1748
1841
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1749
1842
|
ORDER BY c.relname
|
|
1750
|
-
LIMIT ${r(
|
|
1843
|
+
LIMIT ${r(lr)} OFFSET ${r(t)}
|
|
1751
1844
|
`;
|
|
1752
|
-
if (o.push(...n), n.length <
|
|
1845
|
+
if (o.push(...n), n.length < lr) break;
|
|
1753
1846
|
}
|
|
1754
1847
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1755
1848
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
1756
1849
|
let l = c.map((e) => e.table_name), u = yield* a(l, (t) => e`
|
|
1757
1850
|
SELECT table_name, column_name, data_type, udt_name, is_nullable, column_default,
|
|
1758
|
-
character_maximum_length, is_generated, generation_expression
|
|
1759
|
-
|
|
1851
|
+
character_maximum_length, is_generated, generation_expression,
|
|
1852
|
+
(SELECT a.atttypmod FROM pg_attribute a
|
|
1853
|
+
JOIN pg_class c ON c.oid = a.attrelid
|
|
1854
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1855
|
+
WHERE n.nspname = col.table_schema AND c.relname = col.table_name
|
|
1856
|
+
AND a.attname = col.column_name) AS type_modifier
|
|
1857
|
+
FROM information_schema.columns col
|
|
1760
1858
|
WHERE table_schema = current_schema() AND table_name IN ${t}
|
|
1761
1859
|
ORDER BY table_name, ordinal_position
|
|
1762
1860
|
`), d = yield* a(l, (t) => e`
|
|
@@ -1786,8 +1884,8 @@ BEGIN
|
|
|
1786
1884
|
AND rel.relname IN ${t}
|
|
1787
1885
|
`), m = /* @__PURE__ */ new Map();
|
|
1788
1886
|
for (let e of p) {
|
|
1789
|
-
let t =
|
|
1790
|
-
t
|
|
1887
|
+
let t = rr(e.def, e.column_name);
|
|
1888
|
+
t !== null && m.set(`${e.table_name}.${e.column_name}`, t);
|
|
1791
1889
|
}
|
|
1792
1890
|
let h = yield* a(l, (t) => e`
|
|
1793
1891
|
SELECT
|
|
@@ -1820,6 +1918,10 @@ BEGIN
|
|
|
1820
1918
|
c.relname AS table_name,
|
|
1821
1919
|
i.relname AS index_name,
|
|
1822
1920
|
ix2.indisunique AS is_unique,
|
|
1921
|
+
am.amname AS access_method,
|
|
1922
|
+
CASE WHEN opn.nspname IN ('public', 'pg_catalog') THEN opc.opcname
|
|
1923
|
+
ELSE opn.nspname || '.' || opc.opcname END AS operator_class,
|
|
1924
|
+
i.reloptions AS reloptions,
|
|
1823
1925
|
pg_get_expr(ix2.indpred, ix2.indrelid) AS predicate,
|
|
1824
1926
|
ix2.indisvalid AS is_valid,
|
|
1825
1927
|
(0 = ANY (ix2.indkey::int[])) AS has_expression,
|
|
@@ -1827,6 +1929,9 @@ BEGIN
|
|
|
1827
1929
|
array_position(ix2.indkey::int[], a.attnum) + 1 AS position
|
|
1828
1930
|
FROM pg_index ix2
|
|
1829
1931
|
JOIN pg_class i ON i.oid = ix2.indexrelid
|
|
1932
|
+
JOIN pg_am am ON am.oid = i.relam
|
|
1933
|
+
LEFT JOIN pg_opclass opc ON opc.oid = ix2.indclass[0]
|
|
1934
|
+
LEFT JOIN pg_namespace opn ON opn.oid = opc.opcnamespace
|
|
1830
1935
|
JOIN pg_class c ON c.oid = ix2.indrelid
|
|
1831
1936
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1832
1937
|
LEFT JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY (ix2.indkey)
|
|
@@ -1882,27 +1987,31 @@ BEGIN
|
|
|
1882
1987
|
let n = t.get(e.index_name);
|
|
1883
1988
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1884
1989
|
}
|
|
1885
|
-
let
|
|
1990
|
+
let w = [];
|
|
1886
1991
|
for (let e of c) {
|
|
1887
1992
|
let t = /* @__PURE__ */ new Set(), n = (_.get(e.table_name) ?? []).filter((e) => !t.has(e.column_name) && (t.add(e.column_name), !0)), r = v.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = y.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = x.get(e.table_name) ?? [], o = new Map(a.map((e) => [e.source_column, e])), s = new Set(n.filter((e) => e.udt_name === "tsvector").map((e) => e.column_name)), c = n.filter((e) => !s.has(e.column_name)).map((t) => {
|
|
1888
|
-
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" :
|
|
1993
|
+
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" : ar(t.data_type, t.udt_name), c = a ? {
|
|
1889
1994
|
table: a.target_table,
|
|
1890
1995
|
column: a.target_column,
|
|
1891
|
-
onDelete:
|
|
1892
|
-
onUpdate:
|
|
1996
|
+
onDelete: V(a.delete_rule),
|
|
1997
|
+
onUpdate: V(a.update_rule)
|
|
1893
1998
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1894
1999
|
return {
|
|
1895
2000
|
name: t.column_name,
|
|
1896
2001
|
type: s,
|
|
1897
|
-
...
|
|
2002
|
+
...s === "vector" ? {
|
|
2003
|
+
vectorPrecision: t.udt_name === "halfvec" ? "half" : "float32",
|
|
2004
|
+
...t.type_modifier !== void 0 && t.type_modifier > 0 ? { vectorDim: t.type_modifier } : {}
|
|
2005
|
+
} : {},
|
|
2006
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
1898
2007
|
nullable: t.is_nullable === "YES",
|
|
1899
2008
|
unique: i.has(t.column_name) || n && t.column_name === "id",
|
|
1900
2009
|
hasDefault: t.column_default !== null,
|
|
1901
2010
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
1902
2011
|
...c ? { references: c } : {},
|
|
1903
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2012
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(ar(t.data_type, t.udt_name)) ? "numeric" : "text" } : {},
|
|
1904
2013
|
...l ? { oneOf: l } : {},
|
|
1905
|
-
...
|
|
2014
|
+
...or(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
1906
2015
|
};
|
|
1907
2016
|
}), l = [], u = S.get(e.table_name);
|
|
1908
2017
|
if (u) for (let [t, n] of u) {
|
|
@@ -1911,12 +2020,21 @@ BEGIN
|
|
|
1911
2020
|
return !r.has(t) && (r.add(t), !0);
|
|
1912
2021
|
});
|
|
1913
2022
|
if (i.some((e) => s.has(e.column_name))) continue;
|
|
1914
|
-
let a = n.some((e) => e.has_expression)
|
|
2023
|
+
let a = n.some((e) => e.has_expression), o = n[0], c = new Map((o?.reloptions ?? []).map((e) => {
|
|
2024
|
+
let [t, n] = e.split("=");
|
|
2025
|
+
return [t, Number(n)];
|
|
2026
|
+
}));
|
|
2027
|
+
if (o?.access_method === "hnsw" && !o.operator_class) throw Error(`Cannot read HNSW operator class for index ${t}`);
|
|
1915
2028
|
l.push({
|
|
1916
2029
|
name: t,
|
|
1917
2030
|
table: e.table_name,
|
|
1918
2031
|
columns: i.map((e) => e.column_name),
|
|
1919
2032
|
unique: n[0]?.is_unique ?? !1,
|
|
2033
|
+
...de(o?.access_method, o?.access_method === "hnsw" ? { hnsw: {
|
|
2034
|
+
opclass: o.operator_class,
|
|
2035
|
+
m: c.get("m") ?? 16,
|
|
2036
|
+
efConstruction: c.get("ef_construction") ?? 64
|
|
2037
|
+
} } : void 0),
|
|
1920
2038
|
...n[0]?.predicate == null ? {} : { where: n[0].predicate },
|
|
1921
2039
|
...n[0]?.is_valid === !1 ? { valid: !1 } : {},
|
|
1922
2040
|
...a ? { expression: !0 } : {}
|
|
@@ -1930,20 +2048,20 @@ BEGIN
|
|
|
1930
2048
|
unique: !0
|
|
1931
2049
|
});
|
|
1932
2050
|
let d = Number(e.row_count ?? 0);
|
|
1933
|
-
|
|
2051
|
+
w.push({
|
|
1934
2052
|
name: e.table_name,
|
|
1935
2053
|
columns: c,
|
|
1936
2054
|
indexes: l,
|
|
1937
2055
|
...d > 0 ? { rowCount: d } : {}
|
|
1938
2056
|
});
|
|
1939
2057
|
}
|
|
1940
|
-
return { tables:
|
|
2058
|
+
return { tables: w };
|
|
1941
2059
|
});
|
|
1942
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
2060
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(T.catchAll((e) => {
|
|
1943
2061
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1944
|
-
return n.includes("statement timeout") || n.includes("57014") ?
|
|
2062
|
+
return n.includes("statement timeout") || n.includes("57014") ? T.die(/* @__PURE__ */ Error(`schema introspection exceeded VOLTRO_INTROSPECT_TIMEOUT_MS (${t}ms) — the schema is very large / FK-dense or the database is slow. Raise VOLTRO_INTROSPECT_TIMEOUT_MS, set it to 0 to disable the ceiling, or use DB_DIRECT_URL for a non-pooler connection.`)) : T.fail(e);
|
|
1945
2063
|
}));
|
|
1946
|
-
},
|
|
2064
|
+
}, pr = (e, t) => {
|
|
1947
2065
|
switch (e.toLowerCase()) {
|
|
1948
2066
|
case "varchar":
|
|
1949
2067
|
case "char":
|
|
@@ -1975,21 +2093,21 @@ BEGIN
|
|
|
1975
2093
|
case "json": return "json";
|
|
1976
2094
|
default: return "text";
|
|
1977
2095
|
}
|
|
1978
|
-
},
|
|
2096
|
+
}, mr = (e) => e.map((e) => {
|
|
1979
2097
|
let t = e, n = {};
|
|
1980
2098
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1981
2099
|
return n;
|
|
1982
|
-
}),
|
|
1983
|
-
let t =
|
|
2100
|
+
}), hr = (e) => T.gen(function* () {
|
|
2101
|
+
let t = mr(yield* e`
|
|
1984
2102
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1985
2103
|
FROM information_schema.tables
|
|
1986
2104
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1987
|
-
ORDER BY table_name`), n =
|
|
2105
|
+
ORDER BY table_name`), n = mr(yield* e`
|
|
1988
2106
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1989
2107
|
character_maximum_length, generation_expression, extra
|
|
1990
2108
|
FROM information_schema.columns
|
|
1991
2109
|
WHERE table_schema = DATABASE()
|
|
1992
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
2110
|
+
ORDER BY table_name, ordinal_position`), r = mr(yield* e`
|
|
1993
2111
|
SELECT k.table_name AS source_table,
|
|
1994
2112
|
k.column_name AS source_column,
|
|
1995
2113
|
k.referenced_table_name AS target_table,
|
|
@@ -1999,7 +2117,7 @@ BEGIN
|
|
|
1999
2117
|
JOIN information_schema.referential_constraints r
|
|
2000
2118
|
ON k.constraint_name = r.constraint_name
|
|
2001
2119
|
AND k.table_schema = r.constraint_schema
|
|
2002
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
2120
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = mr(yield* e`
|
|
2003
2121
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
2004
2122
|
FROM information_schema.statistics
|
|
2005
2123
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -2012,14 +2130,14 @@ BEGIN
|
|
|
2012
2130
|
JOIN information_schema.table_constraints tc
|
|
2013
2131
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2014
2132
|
AND tc.constraint_name = cc.constraint_name
|
|
2015
|
-
WHERE cc.constraint_schema = DATABASE()`.unprepared, s =
|
|
2133
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared, s = mr(yield* a.pipe(T.orElse(() => o), T.orElseSucceed(() => []))), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map();
|
|
2016
2134
|
for (let e of s) {
|
|
2017
2135
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
2018
2136
|
if (t) {
|
|
2019
2137
|
c.add(`${e.table_name}.${t[1]}`);
|
|
2020
2138
|
continue;
|
|
2021
2139
|
}
|
|
2022
|
-
let n =
|
|
2140
|
+
let n = ir(e.check_clause);
|
|
2023
2141
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
2024
2142
|
}
|
|
2025
2143
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -2042,24 +2160,24 @@ BEGIN
|
|
|
2042
2160
|
let t = u.get(e.table_name) ?? [], n = d.get(e.table_name) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = t.filter((e) => e.column_key === "PRI").map((e) => e.column_name), a = /* @__PURE__ */ new Set(), o = f.get(e.table_name);
|
|
2043
2161
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
2044
2162
|
let s = t.map((t) => {
|
|
2045
|
-
let n = i.includes(t.column_name) && i.length === 1, o = r.get(t.column_name), s = o ? "reference" : n && t.column_name === "id" ? "id" : c.has(`${e.table_name}.${t.column_name}`) ? "json" :
|
|
2163
|
+
let n = i.includes(t.column_name) && i.length === 1, o = r.get(t.column_name), s = o ? "reference" : n && t.column_name === "id" ? "id" : c.has(`${e.table_name}.${t.column_name}`) ? "json" : pr(t.data_type, t.column_type), u = o ? {
|
|
2046
2164
|
table: o.target_table,
|
|
2047
2165
|
column: o.target_column,
|
|
2048
|
-
onDelete:
|
|
2049
|
-
onUpdate:
|
|
2166
|
+
onDelete: V(o.delete_rule),
|
|
2167
|
+
onUpdate: V(o.update_rule)
|
|
2050
2168
|
} : void 0, d = a.has(t.column_name) || n && t.column_name === "id", f = t.column_default === "NULL" ? null : t.column_default, p = l.get(`${e.table_name}.${t.column_name}`);
|
|
2051
2169
|
return {
|
|
2052
2170
|
name: t.column_name,
|
|
2053
2171
|
type: s,
|
|
2054
2172
|
nullable: t.is_nullable === "YES",
|
|
2055
|
-
...
|
|
2173
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
2056
2174
|
unique: d,
|
|
2057
2175
|
hasDefault: f !== null,
|
|
2058
2176
|
...f === null ? {} : { defaultValue: f },
|
|
2059
2177
|
...u ? { references: u } : {},
|
|
2060
|
-
...o ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2178
|
+
...o ? { referenceStorage: ["integer", "bigint"].includes(pr(t.data_type, t.column_type)) ? "numeric" : "text" } : {},
|
|
2061
2179
|
...p ? { oneOf: p } : {},
|
|
2062
|
-
...
|
|
2180
|
+
...or(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {}
|
|
2063
2181
|
};
|
|
2064
2182
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
2065
2183
|
if (o) for (let [t, n] of o) {
|
|
@@ -2086,10 +2204,10 @@ BEGIN
|
|
|
2086
2204
|
});
|
|
2087
2205
|
}
|
|
2088
2206
|
return { tables: p };
|
|
2089
|
-
}),
|
|
2207
|
+
}), gr = (e) => {
|
|
2090
2208
|
let t = e.toUpperCase();
|
|
2091
2209
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
2092
|
-
},
|
|
2210
|
+
}, _r = (e) => e === 1 || e === !0, vr = (e) => T.gen(function* () {
|
|
2093
2211
|
let t = yield* e`
|
|
2094
2212
|
SELECT name, sql FROM sqlite_master
|
|
2095
2213
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -2103,18 +2221,18 @@ BEGIN
|
|
|
2103
2221
|
let o = yield* e.unsafe(`PRAGMA table_xinfo(${n(i)})`), s = yield* e.unsafe(`PRAGMA foreign_key_list(${n(i)})`), c = yield* e.unsafe(`PRAGMA index_list(${n(i)})`), l = new Map(s.map((e) => [e.from, e])), u = o.filter((e) => e.pk > 0).sort((e, t) => e.pk - t.pk).map((e) => e.name), d = new Map(o.map((e) => [e.name.toLowerCase(), e.name])), f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set();
|
|
2104
2222
|
for (let t of c) {
|
|
2105
2223
|
let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null).map((e) => d.get(e.toLowerCase()) ?? e);
|
|
2106
|
-
if (f.set(t.name, r), t.partial !== void 0 &&
|
|
2107
|
-
let n =
|
|
2224
|
+
if (f.set(t.name, r), t.partial !== void 0 && _r(t.partial)) {
|
|
2225
|
+
let n = cn((yield* e`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${t.name}`)[0]?.sql ?? "");
|
|
2108
2226
|
n !== void 0 && p.set(t.name, n);
|
|
2109
2227
|
}
|
|
2110
|
-
!p.has(t.name) &&
|
|
2228
|
+
!p.has(t.name) && _r(t.unique) && r.length === 1 && m.add(r[0]);
|
|
2111
2229
|
}
|
|
2112
2230
|
let h = o.map((e) => {
|
|
2113
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
2231
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : gr(e.type), a = r ? {
|
|
2114
2232
|
table: r.table,
|
|
2115
2233
|
column: r.to,
|
|
2116
|
-
onDelete:
|
|
2117
|
-
onUpdate:
|
|
2234
|
+
onDelete: V(r.on_delete),
|
|
2235
|
+
onUpdate: V(r.on_update)
|
|
2118
2236
|
} : void 0, o = t.get(e.name);
|
|
2119
2237
|
return {
|
|
2120
2238
|
name: e.name,
|
|
@@ -2124,19 +2242,19 @@ BEGIN
|
|
|
2124
2242
|
hasDefault: e.dflt_value !== null,
|
|
2125
2243
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
2126
2244
|
...a ? { references: a } : {},
|
|
2127
|
-
...r ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2245
|
+
...r ? { referenceStorage: ["integer", "bigint"].includes(gr(e.type)) ? "numeric" : "text" } : {},
|
|
2128
2246
|
...o ? { oneOf: o } : {},
|
|
2129
|
-
...
|
|
2247
|
+
...or(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
2130
2248
|
};
|
|
2131
2249
|
}), g = new Set(s.map((e) => e.from)), _ = [];
|
|
2132
2250
|
for (let e of c) {
|
|
2133
2251
|
if (e.origin === "pk") continue;
|
|
2134
2252
|
let t = f.get(e.name) ?? [], n = p.get(e.name);
|
|
2135
|
-
n === void 0 && t.length === 1 &&
|
|
2253
|
+
n === void 0 && t.length === 1 && _r(e.unique) || (n !== void 0 || t.length !== 1 || _r(e.unique) || !g.has(t[0]) || e.name === `${i}_${t[0]}_idx`) && _.push({
|
|
2136
2254
|
name: e.name,
|
|
2137
2255
|
table: i,
|
|
2138
2256
|
columns: t,
|
|
2139
|
-
unique:
|
|
2257
|
+
unique: _r(e.unique),
|
|
2140
2258
|
...n === void 0 ? {} : { where: n }
|
|
2141
2259
|
});
|
|
2142
2260
|
}
|
|
@@ -2152,7 +2270,7 @@ BEGIN
|
|
|
2152
2270
|
});
|
|
2153
2271
|
}
|
|
2154
2272
|
return { tables: r };
|
|
2155
|
-
}),
|
|
2273
|
+
}), yr = (e) => {
|
|
2156
2274
|
switch (e.toLowerCase()) {
|
|
2157
2275
|
case "int":
|
|
2158
2276
|
case "smallint":
|
|
@@ -2174,14 +2292,14 @@ BEGIN
|
|
|
2174
2292
|
case "image": return "bytes";
|
|
2175
2293
|
default: return "text";
|
|
2176
2294
|
}
|
|
2177
|
-
},
|
|
2295
|
+
}, H = (e) => e === !0 || e === 1, br = (e) => T.gen(function* () {
|
|
2178
2296
|
let t = yield* e`
|
|
2179
2297
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2180
2298
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
2181
2299
|
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
|
|
2182
2300
|
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
2183
2301
|
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length
|
|
2184
|
-
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield*
|
|
2302
|
+
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield* T.orElseSucceed(e`
|
|
2185
2303
|
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS definition,
|
|
2186
2304
|
cc.is_persisted AS is_persisted
|
|
2187
2305
|
FROM sys.computed_columns cc
|
|
@@ -2206,14 +2324,14 @@ BEGIN
|
|
|
2206
2324
|
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
|
2207
2325
|
WHERE i.type > 0 AND ic.is_included_column = 0
|
|
2208
2326
|
ORDER BY t.name, i.name, ic.key_ordinal`, s = yield* e`
|
|
2209
|
-
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS def
|
|
2327
|
+
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS def,
|
|
2328
|
+
cc.name AS constraint_name, cc.is_disabled, cc.is_not_trusted
|
|
2210
2329
|
FROM sys.check_constraints cc
|
|
2211
2330
|
JOIN sys.tables t ON t.object_id = cc.parent_object_id
|
|
2212
|
-
JOIN sys.columns c ON c.object_id = cc.parent_object_id AND c.column_id = cc.parent_column_id
|
|
2213
|
-
WHERE cc.parent_column_id <> 0`, c = /* @__PURE__ */ new Map();
|
|
2331
|
+
LEFT JOIN sys.columns c ON c.object_id = cc.parent_object_id AND c.column_id = cc.parent_column_id`, c = /* @__PURE__ */ new Map();
|
|
2214
2332
|
for (let e of s) {
|
|
2215
|
-
let t =
|
|
2216
|
-
t
|
|
2333
|
+
let t = ir(e.def);
|
|
2334
|
+
t?.column === e.column_name && c.set(`${e.table_name}.${e.column_name}`, t.values);
|
|
2217
2335
|
}
|
|
2218
2336
|
let l = /* @__PURE__ */ new Map();
|
|
2219
2337
|
for (let e of n) {
|
|
@@ -2234,141 +2352,173 @@ BEGIN
|
|
|
2234
2352
|
}
|
|
2235
2353
|
let f = [];
|
|
2236
2354
|
for (let { table_name: e } of t) {
|
|
2237
|
-
let t = l.get(e) ?? [], n = u.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), a = new Set(n.map((e) => e.source_column)), o = d.get(e),
|
|
2355
|
+
let t = l.get(e) ?? [], n = u.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), a = new Set(n.map((e) => e.source_column)), o = d.get(e), p = [], m = /* @__PURE__ */ new Set();
|
|
2238
2356
|
if (o) for (let [, e] of o) {
|
|
2239
2357
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2240
|
-
if (
|
|
2241
|
-
else t[0].predicate == null &&
|
|
2358
|
+
if (H(t[0].is_primary)) for (let e of t) p.push(e.column_name);
|
|
2359
|
+
else t[0].predicate == null && H(t[0].is_unique) && t.length === 1 && m.add(t[0].column_name);
|
|
2242
2360
|
}
|
|
2243
|
-
let
|
|
2244
|
-
let n =
|
|
2361
|
+
let h = t.map((t) => {
|
|
2362
|
+
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o = a ? "reference" : n && t.column_name === "id" ? "id" : yr(t.data_type), l = a ? {
|
|
2245
2363
|
table: a.target_table,
|
|
2246
2364
|
column: a.target_column,
|
|
2247
|
-
onDelete:
|
|
2248
|
-
onUpdate:
|
|
2249
|
-
} : void 0, u = t.column_default === null ? null :
|
|
2365
|
+
onDelete: xr(a.delete_rule),
|
|
2366
|
+
onUpdate: xr(a.update_rule)
|
|
2367
|
+
} : void 0, u = t.column_default === null ? null : Sr(t.column_default), d = c.get(`${e}.${t.column_name}`), f = s.flatMap((n) => {
|
|
2368
|
+
if (n.table_name !== e || n.column_name !== null && n.column_name !== t.column_name) return [];
|
|
2369
|
+
let r = at(t.column_name, n.def);
|
|
2370
|
+
return r ? [{
|
|
2371
|
+
name: n.constraint_name,
|
|
2372
|
+
validation: r,
|
|
2373
|
+
enabled: !H(n.is_disabled),
|
|
2374
|
+
trusted: !H(n.is_not_trusted)
|
|
2375
|
+
}] : [];
|
|
2376
|
+
}).sort((e, t) => e.name.localeCompare(t.name)), h = ot(f);
|
|
2250
2377
|
return {
|
|
2251
2378
|
name: t.column_name,
|
|
2252
2379
|
type: o,
|
|
2253
2380
|
nullable: t.is_nullable === "YES",
|
|
2254
|
-
...
|
|
2255
|
-
unique:
|
|
2381
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
2382
|
+
unique: m.has(t.column_name) || n && t.column_name === "id",
|
|
2256
2383
|
hasDefault: u !== null,
|
|
2257
2384
|
...u === null ? {} : { defaultValue: u },
|
|
2258
2385
|
...l ? { references: l } : {},
|
|
2259
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2386
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(yr(t.data_type)) ? "numeric" : "text" } : {},
|
|
2260
2387
|
...d ? { oneOf: d } : {},
|
|
2261
|
-
...
|
|
2388
|
+
...f.length > 0 ? { jsonChecks: f } : {},
|
|
2389
|
+
...h ? { jsonValidation: h } : {},
|
|
2390
|
+
...or(i.get(`${e}.${t.column_name}`)?.definition ?? null, H(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2262
2391
|
};
|
|
2263
|
-
}),
|
|
2392
|
+
}), g = [];
|
|
2264
2393
|
if (o) for (let [t, n] of o) {
|
|
2265
2394
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2266
|
-
if (
|
|
2395
|
+
if (H(r[0].is_primary)) continue;
|
|
2267
2396
|
let i = r[0].predicate ?? void 0;
|
|
2268
|
-
i === void 0 && r.length === 1 &&
|
|
2397
|
+
i === void 0 && r.length === 1 && H(r[0].is_unique) || (i !== void 0 || r.length !== 1 || H(r[0].is_unique) || !a.has(r[0].column_name) || t === `${e}_${r[0].column_name}_idx`) && g.push({
|
|
2269
2398
|
name: t,
|
|
2270
2399
|
table: e,
|
|
2271
2400
|
columns: r.map((e) => e.column_name),
|
|
2272
|
-
unique:
|
|
2401
|
+
unique: H(r[0].is_unique),
|
|
2273
2402
|
...i === void 0 ? {} : { where: i }
|
|
2274
2403
|
});
|
|
2275
2404
|
}
|
|
2276
|
-
|
|
2405
|
+
p.length > 0 && g.push({
|
|
2277
2406
|
name: `${e}_pkey`,
|
|
2278
2407
|
table: e,
|
|
2279
|
-
columns:
|
|
2408
|
+
columns: p,
|
|
2280
2409
|
unique: !0
|
|
2281
2410
|
}), f.push({
|
|
2282
2411
|
name: e,
|
|
2283
|
-
columns:
|
|
2284
|
-
indexes:
|
|
2412
|
+
columns: h,
|
|
2413
|
+
indexes: g
|
|
2285
2414
|
});
|
|
2286
2415
|
}
|
|
2287
2416
|
return { tables: f };
|
|
2288
|
-
}),
|
|
2417
|
+
}), xr = (e) => {
|
|
2289
2418
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2290
2419
|
case "CASCADE": return "cascade";
|
|
2291
2420
|
case "SET NULL": return "setNull";
|
|
2292
2421
|
case "SET DEFAULT": return "noAction";
|
|
2293
2422
|
default: return "noAction";
|
|
2294
2423
|
}
|
|
2295
|
-
},
|
|
2424
|
+
}, Sr = (e) => {
|
|
2296
2425
|
let t = e.trim();
|
|
2297
2426
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2298
2427
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2299
|
-
},
|
|
2428
|
+
}, Cr = /* @__PURE__ */ new Set([
|
|
2300
2429
|
"character varying",
|
|
2301
2430
|
"varchar",
|
|
2302
2431
|
"nvarchar",
|
|
2303
2432
|
"char",
|
|
2304
2433
|
"character",
|
|
2305
2434
|
"nchar"
|
|
2306
|
-
]),
|
|
2307
|
-
if (!
|
|
2435
|
+
]), U = (e, t) => {
|
|
2436
|
+
if (!Cr.has(e.toLowerCase())) return;
|
|
2308
2437
|
let n = Number(t);
|
|
2309
2438
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2310
|
-
},
|
|
2311
|
-
mysql: () =>
|
|
2312
|
-
mssql: () =>
|
|
2313
|
-
sqlite: () =>
|
|
2314
|
-
orElse: () =>
|
|
2315
|
-
}).pipe(
|
|
2439
|
+
}, wr = /* @__PURE__ */ new Set([k]), Tr = (e) => e.onDialectOrElse({
|
|
2440
|
+
mysql: () => hr(e),
|
|
2441
|
+
mssql: () => br(e),
|
|
2442
|
+
sqlite: () => vr(e),
|
|
2443
|
+
orElse: () => fr(e)
|
|
2444
|
+
}).pipe(T.map((e) => ({
|
|
2316
2445
|
...e,
|
|
2317
|
-
tables: e.tables.filter((e) => !
|
|
2318
|
-
}))),
|
|
2319
|
-
let t =
|
|
2320
|
-
return t === void 0 ?
|
|
2321
|
-
}),
|
|
2446
|
+
tables: e.tables.filter((e) => !wr.has(e.name))
|
|
2447
|
+
}))), Er = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", Dr = /* @__PURE__ */ new WeakMap(), Or = (e) => T.suspend(() => {
|
|
2448
|
+
let t = Dr.get(e);
|
|
2449
|
+
return t === void 0 ? kr(e).pipe(T.tap((t) => T.sync(() => Dr.set(e, t)))) : T.succeed(t);
|
|
2450
|
+
}), kr = (e) => e.unsafe("SELECT VERSION() AS v").pipe(T.map((e) => {
|
|
2322
2451
|
let t = e[0]?.v;
|
|
2323
|
-
return typeof t == "string" ?
|
|
2324
|
-
}),
|
|
2452
|
+
return typeof t == "string" ? Er(t) : "mysql";
|
|
2453
|
+
}), T.catchAll(() => T.succeed("mysql"))), Ar = (e) => {
|
|
2325
2454
|
let t = e;
|
|
2326
2455
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2327
2456
|
let e = t;
|
|
2328
2457
|
if (typeof e.errno == "number") return e.errno;
|
|
2329
2458
|
t = e.cause;
|
|
2330
2459
|
}
|
|
2331
|
-
},
|
|
2460
|
+
}, jr = (e) => {
|
|
2332
2461
|
let t = [], n = e;
|
|
2333
2462
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2334
2463
|
let e = n;
|
|
2335
2464
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2336
2465
|
}
|
|
2337
2466
|
return t.join(" | ");
|
|
2338
|
-
},
|
|
2467
|
+
}, Mr = (e, t) => {
|
|
2339
2468
|
if (t.length === 0) return !1;
|
|
2340
|
-
let n =
|
|
2469
|
+
let n = Ar(e), r = jr(e);
|
|
2341
2470
|
return t.some((e) => e.errno !== void 0 && n !== void 0 && e.errno.includes(n) || e.messageIncludes !== void 0 && e.messageIncludes.some((e) => r.includes(e)));
|
|
2342
|
-
},
|
|
2471
|
+
}, Nr = {
|
|
2343
2472
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2344
2473
|
errno: [1061]
|
|
2345
|
-
},
|
|
2474
|
+
}, Pr = {
|
|
2346
2475
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2347
2476
|
errno: [1091]
|
|
2348
|
-
},
|
|
2477
|
+
}, Fr = {
|
|
2349
2478
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2350
2479
|
messageIncludes: ["no such column"]
|
|
2351
|
-
},
|
|
2480
|
+
}, Ir = {
|
|
2352
2481
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2353
2482
|
errno: [1091, 3940]
|
|
2354
|
-
},
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2483
|
+
}, Lr = (e, t) => T.suspend(() => {
|
|
2484
|
+
let n;
|
|
2485
|
+
return e.withTransaction(t.pipe(T.tapErrorCause((e) => T.sync(() => {
|
|
2486
|
+
n = e;
|
|
2487
|
+
})))).pipe(T.catchAllCause((e) => T.failCause(n !== void 0 && !ee.equals(n, e) ? w.sequential(n, e) : e)));
|
|
2488
|
+
}), Rr = (e, t, n) => {
|
|
2489
|
+
let r = e.match(/'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|\s+|[^'\[\s]+/g) ?? [];
|
|
2490
|
+
if (r.join("") !== e || r.some((e) => !e.startsWith("'") && !e.startsWith("[") && /"|\/\*|--/.test(e))) throw Error("Cannot safely rename CHECK: unsupported catalog SQL; use an explicit migration");
|
|
2491
|
+
let i = r.map((e, t) => ({
|
|
2492
|
+
value: e,
|
|
2493
|
+
index: t
|
|
2494
|
+
})).filter((e) => e.value.trim() !== ""), a = 0;
|
|
2495
|
+
for (let e = 0; e < i.length; e++) {
|
|
2496
|
+
let s = i[e];
|
|
2497
|
+
if (s.value !== o(t, "mssql")) continue;
|
|
2498
|
+
let c = i[e - 1]?.value ?? "", l = i[e + 1]?.value ?? "";
|
|
2499
|
+
if (c.endsWith(".") || l.startsWith(".") || l.startsWith("(")) throw Error(`Cannot safely rename CHECK reference '${t}': qualified or callable identifier; use an explicit migration`);
|
|
2500
|
+
r[s.index] = o(n, "mssql"), a++;
|
|
2501
|
+
}
|
|
2502
|
+
if (a === 0 || r.join("").length === 0) throw Error(`Cannot safely rename CHECK reference '${t}': no exact catalog column token; use an explicit migration`);
|
|
2503
|
+
return r.join("");
|
|
2504
|
+
}, W = (e, t) => e.onDialectOrElse({
|
|
2505
|
+
mysql: () => T.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2506
|
+
orElse: () => T.succeed(t)
|
|
2507
|
+
}), zr = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, Br = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), Vr = (e, t) => {
|
|
2508
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !Br(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2359
2509
|
let n = e.type === "vector" && e.vectorDim === void 0 ? "vector dimension" : e.type === "array" && e.arrayElement === void 0 ? "array element type" : e.type === "enum" && e.enumName === void 0 && e.enumValues === void 0 ? "enum name/values" : void 0;
|
|
2360
2510
|
if (n !== void 0) throw Error(`migration applier: cannot render '${e.name}' (${e.type}) — the schema snapshot carries no ${n}. Rendering it as 'text' would emit DDL that applies successfully and changes nothing, so this fails instead. This is a framework bug: declaredSchema.ts must carry the parameter into the ColumnSnapshot.`);
|
|
2361
2511
|
return M(e, t);
|
|
2362
|
-
},
|
|
2363
|
-
let t =
|
|
2364
|
-
return t === void 0 ?
|
|
2365
|
-
},
|
|
2512
|
+
}, Hr = (e) => {
|
|
2513
|
+
let t = Vr(e, "postgres");
|
|
2514
|
+
return t === void 0 ? Ur(e) : t;
|
|
2515
|
+
}, Ur = (e) => {
|
|
2366
2516
|
switch (e.type) {
|
|
2367
2517
|
case "id": return "text";
|
|
2368
2518
|
case "text": return "text";
|
|
2369
2519
|
case "integer": return "integer";
|
|
2370
2520
|
case "real": return "double precision";
|
|
2371
|
-
case "decimal": return
|
|
2521
|
+
case "decimal": return zr(e, "NUMERIC");
|
|
2372
2522
|
case "bigint": return "bigint";
|
|
2373
2523
|
case "boolean": return "boolean";
|
|
2374
2524
|
case "timestamp": return "timestamptz";
|
|
@@ -2382,15 +2532,15 @@ BEGIN
|
|
|
2382
2532
|
case "interval": return "interval";
|
|
2383
2533
|
case "raw": return e.rawDdl ?? "text";
|
|
2384
2534
|
}
|
|
2385
|
-
},
|
|
2386
|
-
let t =
|
|
2535
|
+
}, Wr = (e) => {
|
|
2536
|
+
let t = Vr(e, "mariadb");
|
|
2387
2537
|
if (t !== void 0) return t;
|
|
2388
2538
|
switch (e.type) {
|
|
2389
2539
|
case "id": return "VARCHAR(64)";
|
|
2390
2540
|
case "text": return "LONGTEXT";
|
|
2391
2541
|
case "integer": return "INT";
|
|
2392
2542
|
case "real": return "DOUBLE";
|
|
2393
|
-
case "decimal": return
|
|
2543
|
+
case "decimal": return zr(e, "DECIMAL");
|
|
2394
2544
|
case "bigint": return "BIGINT";
|
|
2395
2545
|
case "boolean": return "TINYINT(1)";
|
|
2396
2546
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2404,64 +2554,68 @@ BEGIN
|
|
|
2404
2554
|
case "interval": return "BIGINT";
|
|
2405
2555
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2406
2556
|
}
|
|
2407
|
-
},
|
|
2557
|
+
}, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``, Gr = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", Kr = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, qr = (e, t = "mariadb") => `ALTER TABLE ${K(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${K(e.column)}, ALGORITHM=COPY;`, Jr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Yr = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${Ti(t)}`)};`, Xr = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Qr(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, Zr = (e, t) => {
|
|
2408
2558
|
let { defaultFactory: n, ...r } = e;
|
|
2409
2559
|
return M(e, t) !== M({
|
|
2410
2560
|
...r,
|
|
2411
2561
|
hasDefault: !1
|
|
2412
2562
|
}, t);
|
|
2413
|
-
},
|
|
2563
|
+
}, Qr = (e, t) => {
|
|
2414
2564
|
let n = t(e.defaultValue);
|
|
2415
2565
|
if (n === null) throw Error(`migration applier: cannot render the declared default for '${e.table}.${e.column}' (${JSON.stringify(e.defaultValue)}). Emitting 'DEFAULT NULL' would apply cleanly and drop the default silently, so this fails instead. This is a framework bug — report the column type + default.`);
|
|
2416
2566
|
return n;
|
|
2417
|
-
},
|
|
2418
|
-
let r =
|
|
2419
|
-
return r ?
|
|
2420
|
-
},
|
|
2421
|
-
let r = n ?? e.nullable, i =
|
|
2567
|
+
}, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], $r = (e, t, n) => {
|
|
2568
|
+
let r = q(e, t, n);
|
|
2569
|
+
return r ? vn(n, r) : void 0;
|
|
2570
|
+
}, ei = (e, t, n) => {
|
|
2571
|
+
let r = n ?? e.nullable, i = pt(e, "mariadb");
|
|
2422
2572
|
return [
|
|
2423
|
-
|
|
2573
|
+
K(t),
|
|
2424
2574
|
M(e, "mariadb"),
|
|
2425
2575
|
r ? null : "NOT NULL",
|
|
2426
2576
|
i
|
|
2427
2577
|
].filter(Boolean).join(" ");
|
|
2428
|
-
},
|
|
2578
|
+
}, ti = (e, t) => e == null ? null : Array.isArray(e) ? ni(e, t, "mariadb") : e === "now" ? "DEFAULT CURRENT_TIMESTAMP(6)" : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? N(e, "mariadb") : null, ni = (e, t, n) => mt(e, t ?? { type: "json" }, n), ri = (e, t) => e == null ? null : Array.isArray(e) ? ni(e, t, "postgres") : e === "now" ? "DEFAULT now()" : typeof e == "boolean" || typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|::|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? N(e, "postgres") : null, ii = (e, t) => {
|
|
2429
2579
|
if (!e.generatedAs) return null;
|
|
2430
2580
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2431
2581
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2432
|
-
},
|
|
2582
|
+
}, ai = (e, t = !1) => {
|
|
2433
2583
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "postgres");
|
|
2434
|
-
let
|
|
2435
|
-
if (
|
|
2436
|
-
let
|
|
2437
|
-
if (e.type === "id" &&
|
|
2438
|
-
let t =
|
|
2439
|
-
t &&
|
|
2440
|
-
}
|
|
2441
|
-
return e.references && (
|
|
2584
|
+
let n = ii(e, "postgres");
|
|
2585
|
+
if (n) return `${G(e.name)} ${Hr(e)} ${n}`;
|
|
2586
|
+
let r = [G(e.name), Hr(e)];
|
|
2587
|
+
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
2588
|
+
let t = ri(e.defaultValue, e);
|
|
2589
|
+
t && r.push(t);
|
|
2590
|
+
}
|
|
2591
|
+
return e.references && (r.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${{
|
|
2442
2592
|
cascade: "CASCADE",
|
|
2443
2593
|
restrict: "RESTRICT",
|
|
2444
2594
|
setNull: "SET NULL",
|
|
2445
2595
|
noAction: "NO ACTION"
|
|
2446
|
-
}[e.references.onDelete]}`)),
|
|
2447
|
-
},
|
|
2448
|
-
let t = e.columns.map((
|
|
2449
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(
|
|
2596
|
+
}[e.references.onDelete]}`)), r.join(" ");
|
|
2597
|
+
}, oi = (e) => (e.primaryKey?.length ?? 0) > 0, si = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", ci = (e) => {
|
|
2598
|
+
let t = e.columns.map((t) => ` ${ai(t, oi(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${si(e, G)}\n)`];
|
|
2599
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(Mi({
|
|
2600
|
+
kind: "add-index",
|
|
2601
|
+
table: e.table,
|
|
2602
|
+
index: t
|
|
2603
|
+
}, !1));
|
|
2450
2604
|
return n;
|
|
2451
|
-
},
|
|
2452
|
-
let t =
|
|
2605
|
+
}, li = 191, ui = (e) => {
|
|
2606
|
+
let t = Wr(e).toUpperCase();
|
|
2453
2607
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2454
|
-
},
|
|
2608
|
+
}, di = (e, t = !1) => {
|
|
2455
2609
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "mariadb");
|
|
2456
|
-
let
|
|
2457
|
-
if (
|
|
2458
|
-
let
|
|
2459
|
-
if (e.type === "id" &&
|
|
2460
|
-
let t =
|
|
2461
|
-
t &&
|
|
2462
|
-
}
|
|
2463
|
-
return
|
|
2464
|
-
},
|
|
2610
|
+
let n = ii(e, "mariadb");
|
|
2611
|
+
if (n) return `${K(e.name)} ${Wr(e)} ${n}`;
|
|
2612
|
+
let r = [K(e.name), Wr(e)];
|
|
2613
|
+
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && !ui(e) && r.push("UNIQUE"), e.hasDefault) {
|
|
2614
|
+
let t = ti(e.defaultValue, e);
|
|
2615
|
+
t && r.push(t);
|
|
2616
|
+
}
|
|
2617
|
+
return r.join(" ");
|
|
2618
|
+
}, fi = (e) => e.columns.flatMap((t) => {
|
|
2465
2619
|
if (!t.references) return [];
|
|
2466
2620
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2467
2621
|
cascade: "CASCADE",
|
|
@@ -2469,28 +2623,28 @@ BEGIN
|
|
|
2469
2623
|
setNull: "SET NULL",
|
|
2470
2624
|
noAction: "NO ACTION"
|
|
2471
2625
|
}[t.references.onDelete]}` : "";
|
|
2472
|
-
return [` CONSTRAINT ${
|
|
2473
|
-
}),
|
|
2474
|
-
for (let n of e.indexes)
|
|
2626
|
+
return [` CONSTRAINT ${K(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${K(t.name)}) REFERENCES ${K(t.references.table)} (${K(t.references.column)})${n}`];
|
|
2627
|
+
}), pi = (e, t = "mariadb") => {
|
|
2628
|
+
for (let n of e.indexes) Pi(n, t);
|
|
2475
2629
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2476
|
-
let t =
|
|
2477
|
-
return t === void 0 ?
|
|
2478
|
-
}, i = e.columns.map((
|
|
2479
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
2480
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2630
|
+
let t = Oi(n.get(e));
|
|
2631
|
+
return t === void 0 ? K(e) : `${K(e)}(${t})`;
|
|
2632
|
+
}, i = e.columns.map((t) => ` ${di(t, oi(e))}`).join(",\n"), a = fi(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${o}${si(e, r)}\n)`];
|
|
2633
|
+
for (let n of e.columns) n.unique && n.type !== "id" && ui(n) && s.push(`CREATE UNIQUE INDEX ${Gr(t)}${K(`${e.table}_${n.name}_key`)} ON ${K(e.table)} (${r(n.name)})`);
|
|
2634
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Gr(t)}${K(n.name)} ON ${K(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2481
2635
|
return s;
|
|
2482
|
-
},
|
|
2636
|
+
}, mi = {
|
|
2483
2637
|
cascade: "CASCADE",
|
|
2484
2638
|
restrict: "RESTRICT",
|
|
2485
2639
|
setNull: "SET NULL",
|
|
2486
2640
|
noAction: "NO ACTION"
|
|
2487
|
-
},
|
|
2641
|
+
}, hi = {
|
|
2488
2642
|
cascade: "CASCADE",
|
|
2489
2643
|
restrict: "NO ACTION",
|
|
2490
2644
|
setNull: "SET NULL",
|
|
2491
2645
|
noAction: "NO ACTION"
|
|
2492
|
-
},
|
|
2493
|
-
let t =
|
|
2646
|
+
}, gi = (e) => {
|
|
2647
|
+
let t = Vr(e, "sqlite");
|
|
2494
2648
|
if (t !== void 0) return t;
|
|
2495
2649
|
switch (e.type) {
|
|
2496
2650
|
case "integer":
|
|
@@ -2502,60 +2656,60 @@ BEGIN
|
|
|
2502
2656
|
case "bytes": return "BLOB";
|
|
2503
2657
|
default: return "TEXT";
|
|
2504
2658
|
}
|
|
2505
|
-
},
|
|
2659
|
+
}, _i = (e, t) => e == null ? null : e === "now" ? `DEFAULT ${t}` : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? N(e, "sqlite") : null, vi = (e, t = !1) => {
|
|
2506
2660
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "sqlite");
|
|
2507
|
-
let
|
|
2508
|
-
if (
|
|
2509
|
-
let
|
|
2510
|
-
if (e.type === "id" &&
|
|
2511
|
-
let t =
|
|
2512
|
-
t &&
|
|
2513
|
-
}
|
|
2514
|
-
if (e.references && (
|
|
2661
|
+
let n = ii(e, "sqlite");
|
|
2662
|
+
if (n) return `${G(e.name)} ${gi(e)} ${n}`;
|
|
2663
|
+
let r = [G(e.name), gi(e)];
|
|
2664
|
+
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
2665
|
+
let t = _i(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2666
|
+
t && r.push(t);
|
|
2667
|
+
}
|
|
2668
|
+
if (e.references && (r.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${mi[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2515
2669
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2516
|
-
|
|
2670
|
+
r.push(`CHECK (${G(e.name)} IN (${t}))`);
|
|
2517
2671
|
}
|
|
2518
|
-
return
|
|
2519
|
-
},
|
|
2520
|
-
let t = e.columns.map((
|
|
2521
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2672
|
+
return r.join(" ");
|
|
2673
|
+
}, yi = (e) => {
|
|
2674
|
+
let t = e.columns.map((t) => ` ${vi(t, oi(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${si(e, G)}\n)`];
|
|
2675
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e.table)} (${t.columns.map(G).join(", ")})${ji(t)}`);
|
|
2522
2676
|
return n;
|
|
2523
|
-
},
|
|
2677
|
+
}, J = (e, t) => {
|
|
2524
2678
|
let n = t.find((t) => t.tableName === e);
|
|
2525
2679
|
if (!n) return [];
|
|
2526
|
-
let r =
|
|
2527
|
-
...
|
|
2680
|
+
let r = z([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => G(e.name)).join(", "), o = [
|
|
2681
|
+
...yi({
|
|
2528
2682
|
kind: "create-table",
|
|
2529
2683
|
table: i,
|
|
2530
2684
|
columns: r.columns,
|
|
2531
2685
|
indexes: [],
|
|
2532
2686
|
...r.primaryKey ? { primaryKey: r.primaryKey } : {}
|
|
2533
2687
|
}),
|
|
2534
|
-
`INSERT INTO ${
|
|
2535
|
-
`DROP TABLE ${
|
|
2536
|
-
`ALTER TABLE ${
|
|
2688
|
+
`INSERT INTO ${G(i)} (${a}) SELECT ${a} FROM ${G(e)}`,
|
|
2689
|
+
`DROP TABLE ${G(e)}`,
|
|
2690
|
+
`ALTER TABLE ${G(i)} RENAME TO ${G(e)}`
|
|
2537
2691
|
];
|
|
2538
|
-
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2692
|
+
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e)} (${t.columns.map(G).join(", ")})${ji(t)}`);
|
|
2539
2693
|
return o;
|
|
2540
|
-
},
|
|
2694
|
+
}, bi = (e, t, n, r) => {
|
|
2541
2695
|
let i = r ?? e.nullable;
|
|
2542
|
-
return `ALTER TABLE ${
|
|
2543
|
-
},
|
|
2544
|
-
let n = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${
|
|
2696
|
+
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${M(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2697
|
+
}, xi = (e, t) => {
|
|
2698
|
+
let n = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${Y(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
2545
2699
|
if (!e.hasDefault) return n;
|
|
2546
|
-
let r =
|
|
2700
|
+
let r = _i(e.defaultValue, "SYSUTCDATETIME()");
|
|
2547
2701
|
if (!r) return n;
|
|
2548
2702
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2549
|
-
return `${n} ALTER TABLE ${
|
|
2550
|
-
},
|
|
2551
|
-
let t =
|
|
2703
|
+
return `${n} ALTER TABLE ${Y(e.table)} ADD DEFAULT ${i} FOR ${Y(e.column)};`;
|
|
2704
|
+
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`, Si = (e) => {
|
|
2705
|
+
let t = Vr(e, "mssql");
|
|
2552
2706
|
if (t !== void 0) return t;
|
|
2553
2707
|
switch (e.type) {
|
|
2554
2708
|
case "id": return "NVARCHAR(64)";
|
|
2555
2709
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
2556
2710
|
case "integer": return "INT";
|
|
2557
2711
|
case "real": return "FLOAT";
|
|
2558
|
-
case "decimal": return
|
|
2712
|
+
case "decimal": return zr(e, "DECIMAL");
|
|
2559
2713
|
case "bigint": return "BIGINT";
|
|
2560
2714
|
case "boolean": return "BIT";
|
|
2561
2715
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2563,61 +2717,68 @@ BEGIN
|
|
|
2563
2717
|
case "bytes": return "VARBINARY(MAX)";
|
|
2564
2718
|
default: return "NVARCHAR(MAX)";
|
|
2565
2719
|
}
|
|
2566
|
-
},
|
|
2720
|
+
}, Ci = (e, t, n = !1) => {
|
|
2567
2721
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "mssql");
|
|
2568
|
-
let
|
|
2569
|
-
if (
|
|
2570
|
-
let
|
|
2571
|
-
if (e.type === "id" &&
|
|
2572
|
-
let t =
|
|
2573
|
-
t &&
|
|
2574
|
-
}
|
|
2575
|
-
return e.references && (
|
|
2576
|
-
},
|
|
2577
|
-
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((
|
|
2722
|
+
let r = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Si(e), i = ii(e, "mssql");
|
|
2723
|
+
if (i) return `${Y(e.name)} ${i}`;
|
|
2724
|
+
let a = [Y(e.name), r];
|
|
2725
|
+
if (e.type === "json" && a.push(`CHECK ${rt(Y(e.name))}`), e.type === "array" && a.push(`CHECK (${Y(e.name)} IS NULL OR ISJSON(${Y(e.name)}) = 1)`), e.type === "id" && !n && a.push("PRIMARY KEY"), e.nullable || a.push("NOT NULL"), e.unique && e.type !== "id" && a.push("UNIQUE"), e.hasDefault) {
|
|
2726
|
+
let t = _i(e.defaultValue, "SYSUTCDATETIME()");
|
|
2727
|
+
t && a.push(t);
|
|
2728
|
+
}
|
|
2729
|
+
return e.references && (a.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${hi[e.references.onDelete]}`)), a.join(" ");
|
|
2730
|
+
}, wi = (e) => {
|
|
2731
|
+
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((t) => ` ${Ci(t, n, oi(e))}`).join(",\n"), i = `CREATE TABLE ${Y(e.table)} (\n${r}${si(e, Y)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2578
2732
|
for (let n of e.indexes) {
|
|
2579
2733
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2580
|
-
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2734
|
+
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Y(n.name)} ON ${Y(e.table)} (${n.columns.map(Y).join(", ")})${ji(n)}`;
|
|
2581
2735
|
a.push(`IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'${t(n.name)}' AND object_id = OBJECT_ID(N'${t(e.table)}')) EXEC(N'${t(r)}')`);
|
|
2582
2736
|
}
|
|
2583
2737
|
return a;
|
|
2584
|
-
},
|
|
2585
|
-
let r = `${e.table}${
|
|
2738
|
+
}, Ti = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Ei = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Di = (e, t, n) => {
|
|
2739
|
+
let r = `${e.table}${Ti(t)}`;
|
|
2586
2740
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2587
|
-
},
|
|
2588
|
-
if (e === void 0 || !
|
|
2741
|
+
}, Oi = (e) => {
|
|
2742
|
+
if (e === void 0 || !ui(e)) return;
|
|
2589
2743
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2590
|
-
return t === void 0 ?
|
|
2591
|
-
},
|
|
2592
|
-
let r =
|
|
2593
|
-
return r === void 0 ?
|
|
2594
|
-
},
|
|
2744
|
+
return t === void 0 ? li : Math.min(li, t);
|
|
2745
|
+
}, ki = (e, t, n) => {
|
|
2746
|
+
let r = Oi($r(e, t, n));
|
|
2747
|
+
return r === void 0 ? K(n) : `${K(n)}(${r})`;
|
|
2748
|
+
}, Ai = (e) => e.startsWith("(") ? e : G(e), ji = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, Mi = (e, t) => {
|
|
2749
|
+
let n = fe(e.index.kind, e.index.kindOptions), r = e.index.columns.map(Ai);
|
|
2750
|
+
if (n.opclass !== void 0) {
|
|
2751
|
+
if (r.length !== 1) throw Error("HNSW index requires exactly one column");
|
|
2752
|
+
r[0] = `${r[0]} ${n.opclass}`;
|
|
2753
|
+
}
|
|
2754
|
+
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${G(e.index.name)} ON ${G(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${ji(e.index)};`;
|
|
2755
|
+
}, Ni = (e, t, n = "mariadb") => (Pi(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Gr(n)}${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map((n) => ki(t, e.table, n)).join(", ")});`), Pi = (e, t) => {
|
|
2595
2756
|
if (e.where !== void 0) throw Error(`Partial index '${e.name}' is not supported by ${t}; uniqueActive must be lowered before applying the plan.`);
|
|
2596
|
-
},
|
|
2757
|
+
}, Fi = (e) => `DROP INDEX IF EXISTS ${G(e.index)};`, Ii = (e) => `DROP INDEX ${K(e.index)} ON ${K(e.table)};`, Li = (e) => `DROP INDEX IF EXISTS ${Y(e.index)} ON ${Y(e.table)};`, Ri = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, zi = (e) => {
|
|
2597
2758
|
let t = (e) => e.replace(/'/g, "''");
|
|
2598
2759
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2599
|
-
},
|
|
2760
|
+
}, Bi = (e) => `ALTER INDEX ${G(e.from)} RENAME TO ${G(e.to)};`, Vi = (e) => `ALTER TABLE ${K(e.table)} RENAME INDEX ${K(e.from)} TO ${K(e.to)};`, Hi = (e) => {
|
|
2600
2761
|
let t = (e) => e.replace(/'/g, "''");
|
|
2601
2762
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2602
|
-
},
|
|
2603
|
-
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${
|
|
2763
|
+
}, Ui = (e) => {
|
|
2764
|
+
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Y(e.index.name)} ON ${Y(e.table)} (${e.index.columns.map(Y).join(", ")})${ji(e.index)}`;
|
|
2604
2765
|
return `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'${t(e.index.name)}' AND object_id = OBJECT_ID(N'${t(e.table)}')) EXEC(N'${t(n)}');`;
|
|
2605
|
-
},
|
|
2766
|
+
}, Wi = (e, t, n) => {
|
|
2606
2767
|
let r = n.find((t) => t.tableName === e);
|
|
2607
2768
|
if (!r) return [];
|
|
2608
2769
|
let i = [];
|
|
2609
2770
|
for (let n of t) {
|
|
2610
2771
|
let t = r.fields[n];
|
|
2611
|
-
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${
|
|
2772
|
+
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Y(e)} ALTER COLUMN ${Y(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2612
2773
|
}
|
|
2613
2774
|
return i;
|
|
2614
|
-
},
|
|
2615
|
-
let t = e.fields.map((e) =>
|
|
2616
|
-
return `ALTER TABLE ${
|
|
2617
|
-
},
|
|
2618
|
-
let n = e.fields.map((n) =>
|
|
2619
|
-
return `ALTER TABLE ${
|
|
2620
|
-
},
|
|
2775
|
+
}, Gi = (e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${G(e.column)});`, Ki = (e, t) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${ki(t, e.table, e.column)});`, qi = (e) => {
|
|
2776
|
+
let t = e.fields.map((e) => G(e)).join(", ");
|
|
2777
|
+
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${t});`;
|
|
2778
|
+
}, Ji = (e, t) => {
|
|
2779
|
+
let n = e.fields.map((n) => ki(t, e.table, n)).join(", ");
|
|
2780
|
+
return `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(e.name)} UNIQUE (${n});`;
|
|
2781
|
+
}, Yi = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(e.name)};`, Xi = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(e.name)};`, Zi = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_key`)};`, Qi = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(`${e.table}_${e.column}_key`)};`, $i = (e, t) => {
|
|
2621
2782
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2622
2783
|
if (e.orphanPolicy) {
|
|
2623
2784
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2635,36 +2796,36 @@ BEGIN
|
|
|
2635
2796
|
setNull: "SET NULL",
|
|
2636
2797
|
noAction: "NO ACTION"
|
|
2637
2798
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2638
|
-
},
|
|
2799
|
+
}, ea = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_fkey`)};`, ta = (e) => `ALTER TABLE ${K(e.table)} DROP FOREIGN KEY ${K(`${e.table}_${e.column}_fkey`)};`, na = (e, t) => {
|
|
2639
2800
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2640
2801
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2641
|
-
},
|
|
2802
|
+
}, ra = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_check`)};`, ia = (e, t) => T.gen(function* () {
|
|
2642
2803
|
let n = yield* e`
|
|
2643
2804
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2644
2805
|
FROM information_schema.check_constraints cc
|
|
2645
|
-
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(
|
|
2806
|
+
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(T.orElse(() => e`
|
|
2646
2807
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2647
2808
|
FROM information_schema.check_constraints cc
|
|
2648
2809
|
JOIN information_schema.table_constraints tc
|
|
2649
2810
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2650
2811
|
AND tc.constraint_name = cc.constraint_name
|
|
2651
|
-
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`),
|
|
2812
|
+
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`), T.orElseSucceed(() => []));
|
|
2652
2813
|
for (let e of n) {
|
|
2653
2814
|
let n = String(e.n ?? "");
|
|
2654
|
-
if (n !== "" &&
|
|
2815
|
+
if (n !== "" && ir(String(e.c ?? ""))?.column === t.column) return n;
|
|
2655
2816
|
}
|
|
2656
|
-
}),
|
|
2657
|
-
let r = yield*
|
|
2658
|
-
r !== void 0 && (yield* X(e, `ALTER TABLE ${
|
|
2659
|
-
let i = yield*
|
|
2817
|
+
}), aa = (e, t, n) => T.gen(function* () {
|
|
2818
|
+
let r = yield* ia(e, t);
|
|
2819
|
+
r !== void 0 && (yield* X(e, `ALTER TABLE ${K(t.table)} DROP CONSTRAINT ${K(r)};`, t.kind, [Ir]));
|
|
2820
|
+
let i = yield* ia(e, t);
|
|
2660
2821
|
if (i === void 0) return;
|
|
2661
|
-
let a =
|
|
2662
|
-
if (!a) return yield*
|
|
2663
|
-
yield* X(e, `ALTER TABLE ${
|
|
2664
|
-
}),
|
|
2665
|
-
let i = e.column, a = r === "mariadb", o = a ?
|
|
2666
|
-
if (
|
|
2667
|
-
let t = r === "mssql" ? `${o(i.name)} ${
|
|
2822
|
+
let a = q(n, t.table, t.column);
|
|
2823
|
+
if (!a) return yield* T.die(/* @__PURE__ */ Error(`applier: cannot drop the CHECK on '${t.table}.${t.column}' — it is column-level (catalog name '${i}'), which this family removes only by redefining the column, and the declared column is not available to redefine it from.`));
|
|
2824
|
+
yield* X(e, `ALTER TABLE ${K(t.table)} MODIFY COLUMN ${ei(a, t.column)};`, t.kind);
|
|
2825
|
+
}), oa = (e, t, n, r) => {
|
|
2826
|
+
let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? Y : G, s = a ? Wr(i) : r === "mssql" ? Si(i) : r === "sqlite" ? gi(i) : Hr(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = r === "mssql" ? i.type === "json" ? ` CHECK ${rt(o(i.name))}` : i.type === "array" ? ` CHECK (${o(i.name)} IS NULL OR ISJSON(${o(i.name)}) = 1)` : "" : "", u = (e) => a ? ti(e, i) : r === "mssql" ? _i(e, "SYSUTCDATETIME()") : r === "sqlite" ? _i(e, "CURRENT_TIMESTAMP") : ri(e, i), d = ii(i, r);
|
|
2827
|
+
if (d) {
|
|
2828
|
+
let t = r === "mssql" ? `${o(i.name)} ${d}` : `${o(i.name)} ${s} ${d}`;
|
|
2668
2829
|
return {
|
|
2669
2830
|
pre: [`ALTER TABLE ${o(e.table)} ${c} ${t};`],
|
|
2670
2831
|
post: []
|
|
@@ -2673,24 +2834,24 @@ BEGIN
|
|
|
2673
2834
|
if (t.classification === "safe") {
|
|
2674
2835
|
let t = [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s}`];
|
|
2675
2836
|
return i.unique && t.push("UNIQUE"), {
|
|
2676
|
-
pre: [`${t.join(" ")};`],
|
|
2837
|
+
pre: [`${t.join(" ")}${l};`],
|
|
2677
2838
|
post: []
|
|
2678
2839
|
};
|
|
2679
2840
|
}
|
|
2680
2841
|
if (t.classification === "needs-default") {
|
|
2681
|
-
let t =
|
|
2842
|
+
let t = u(i.defaultValue);
|
|
2682
2843
|
if (t === null) throw Error(`migration applier: cannot render the declared default for '${e.table}.${i.name}' (${JSON.stringify(i.defaultValue)}) while adding it NOT NULL to a populated table. This is a framework bug — report the column type + default.`);
|
|
2683
2844
|
return {
|
|
2684
|
-
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s} NOT NULL ${t};`],
|
|
2845
|
+
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s} NOT NULL ${t}${l};`],
|
|
2685
2846
|
post: []
|
|
2686
2847
|
};
|
|
2687
2848
|
}
|
|
2688
|
-
let
|
|
2689
|
-
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s};`],
|
|
2690
|
-
post:
|
|
2849
|
+
let f = n(e.table, i.name), p = a ? `ALTER TABLE ${o(e.table)} MODIFY COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "mssql" ? `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "sqlite" ? null : `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} SET NOT NULL;`, m = {
|
|
2850
|
+
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s}${l};`],
|
|
2851
|
+
post: p ? [p] : []
|
|
2691
2852
|
};
|
|
2692
|
-
return
|
|
2693
|
-
},
|
|
2853
|
+
return f?.sql && (m.backfillKind = "sql", m.backfillSql = f.sql), f?.js && (m.backfillKind = "js", m.backfillJs = f.js), f?.batchSize !== void 0 && (m.batchSize = f.batchSize), f?.sleepMs !== void 0 && (m.sleepMs = f.sleepMs), m;
|
|
2854
|
+
}, sa = (e) => {
|
|
2694
2855
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2695
2856
|
return (e, n) => {
|
|
2696
2857
|
let r = t.get(e);
|
|
@@ -2710,44 +2871,44 @@ BEGIN
|
|
|
2710
2871
|
...o
|
|
2711
2872
|
};
|
|
2712
2873
|
};
|
|
2713
|
-
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(
|
|
2714
|
-
process.stderr.write(
|
|
2715
|
-
})),
|
|
2716
|
-
let r =
|
|
2874
|
+
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(T.catchIf((e) => Mr(e, r), () => T.void), T.tapError((e) => T.sync(() => {
|
|
2875
|
+
process.stderr.write(pe(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2876
|
+
})), T.mapError((e) => {
|
|
2877
|
+
let r = pe(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2717
2878
|
return Object.assign(e, { message: r });
|
|
2718
|
-
}),
|
|
2719
|
-
let n =
|
|
2720
|
-
if (!n) return yield*
|
|
2879
|
+
}), T.map(() => void 0)), Z = (e, t, n) => T.forEach(t, (t) => X(e, t, n), { discard: !0 }), Q = (e, t) => e.literal(`LIMIT ${Math.max(1, Math.floor(Number.isFinite(t) ? t : 1))}`), $ = (e, t, n, r) => e.unsafe(`SELECT ${r === void 0 ? "*" : o(r, t)} FROM ${o(n, t)} WHERE 1=0`).pipe(T.as(!0), T.catchAll(() => T.succeed(!1))), ca = (e, t) => T.gen(function* () {
|
|
2880
|
+
let n = z([Ke], t).tables[0];
|
|
2881
|
+
if (!n) return yield* T.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2721
2882
|
let r = {
|
|
2722
2883
|
kind: "create-table",
|
|
2723
2884
|
table: k,
|
|
2724
2885
|
columns: n.columns,
|
|
2725
2886
|
indexes: []
|
|
2726
2887
|
}, i = yield* e.onDialectOrElse({
|
|
2727
|
-
mysql: () =>
|
|
2728
|
-
mssql: () =>
|
|
2729
|
-
sqlite: () =>
|
|
2730
|
-
orElse: () =>
|
|
2888
|
+
mysql: () => Or(e).pipe(T.map((e) => pi(r, e))),
|
|
2889
|
+
mssql: () => T.succeed(wi(r)),
|
|
2890
|
+
sqlite: () => T.succeed(yi(r)),
|
|
2891
|
+
orElse: () => T.succeed(ci(r))
|
|
2731
2892
|
});
|
|
2732
|
-
yield*
|
|
2733
|
-
}),
|
|
2893
|
+
yield* T.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2894
|
+
}), la = (e) => e`
|
|
2734
2895
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2735
2896
|
${e("status")}, ${e("payload")}
|
|
2736
2897
|
FROM ${e(k)}
|
|
2737
|
-
`,
|
|
2738
|
-
let i = yield*
|
|
2739
|
-
yield*
|
|
2898
|
+
`, ua = (e, t, n, r) => T.gen(function* () {
|
|
2899
|
+
let i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2900
|
+
yield* T.forEach(r, ({ index: r, planned: a }) => e`
|
|
2740
2901
|
INSERT INTO ${e(k)}
|
|
2741
2902
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2742
2903
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2743
2904
|
${e("createdAt")})
|
|
2744
2905
|
VALUES
|
|
2745
2906
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2746
|
-
${a.op.kind}, ${
|
|
2907
|
+
${a.op.kind}, ${Je(a.op)}, ${"pending"},
|
|
2747
2908
|
${JSON.stringify(a)}, ${i})
|
|
2748
2909
|
`, { discard: !0 });
|
|
2749
|
-
}),
|
|
2750
|
-
let a = yield*
|
|
2910
|
+
}), da = (e, t, n, r, i) => T.gen(function* () {
|
|
2911
|
+
let a = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2751
2912
|
if (r === "applied") {
|
|
2752
2913
|
yield* e`
|
|
2753
2914
|
UPDATE ${e(k)}
|
|
@@ -2762,8 +2923,8 @@ BEGIN
|
|
|
2762
2923
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2763
2924
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2764
2925
|
`;
|
|
2765
|
-
}),
|
|
2766
|
-
let i = yield*
|
|
2926
|
+
}), fa = (e, t, n, r) => T.gen(function* () {
|
|
2927
|
+
let i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2767
2928
|
r.length > 0 && (yield* e`
|
|
2768
2929
|
UPDATE ${e(k)}
|
|
2769
2930
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
@@ -2773,280 +2934,307 @@ BEGIN
|
|
|
2773
2934
|
SET ${e("status")} = ${"pending"}
|
|
2774
2935
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2775
2936
|
`);
|
|
2776
|
-
}),
|
|
2777
|
-
if (
|
|
2937
|
+
}), pa = (e, t) => t === void 0 ? e`DELETE FROM ${e(k)}`.pipe(T.asVoid) : e`DELETE FROM ${e(k)} WHERE ${e("runId")} = ${t}`.pipe(T.asVoid), ma = (e, t, n) => T.gen(function* () {
|
|
2938
|
+
if (nt(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
2778
2939
|
let r = n.op, i = (e) => o(e, t);
|
|
2779
2940
|
if (t === "sqlite" || t === "turso") {
|
|
2780
2941
|
if (!("table" in r)) return "clean";
|
|
2781
|
-
let n = `${r.table}${
|
|
2782
|
-
return (yield* $(e, t, n)) ? ((yield* $(e, t, r.table)) ? yield* X(e, `DROP TABLE ${i(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${i(n)} RENAME TO ${i(r.table)}`, "resume-repair"), yield*
|
|
2942
|
+
let n = `${r.table}${Ze}`;
|
|
2943
|
+
return (yield* $(e, t, n)) ? ((yield* $(e, t, r.table)) ? yield* X(e, `DROP TABLE ${i(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${i(n)} RENAME TO ${i(r.table)}`, "resume-repair"), yield* T.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(T.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
2783
2944
|
}
|
|
2784
2945
|
if (r.kind !== "alter-column-type") return "clean";
|
|
2785
|
-
let a = `${r.column}${
|
|
2786
|
-
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(a)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${r.table}.${a}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} RENAME COLUMN ${i(a)} TO ${i(r.column)}`, "resume-repair"), yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : c && !l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${r.table}.${s}'`), "applied") : yield*
|
|
2787
|
-
}),
|
|
2788
|
-
let i = process.hrtime.bigint(), a =
|
|
2789
|
-
switch (
|
|
2946
|
+
let a = `${r.column}${Qe}`, s = `${r.column}${$e}`, c = yield* $(e, t, r.table, r.column), l = yield* $(e, t, r.table, a), u = yield* $(e, t, r.table, s), d = (e) => T.logWarning(`migration resume: ${e}`).pipe(T.annotateLogs({ scope: "voltro:migrate" }));
|
|
2947
|
+
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(a)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${r.table}.${a}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} RENAME COLUMN ${i(a)} TO ${i(r.column)}`, "resume-repair"), yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : c && !l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${r.table}.${s}'`), "applied") : yield* T.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${r.table}.${r.column}' left a shadow-swap state this resume cannot classify (column=${c}, ${a}=${l}, ${s}=${u}).\nNothing was changed. Inspect those three columns and reconcile them by hand — the data is in whichever of them is populated — then re-run the migration.`));
|
|
2948
|
+
}), ha = (e, t, n, r = "fresh") => T.gen(function* () {
|
|
2949
|
+
let i = process.hrtime.bigint(), a = sa(n.declared), s = t.op;
|
|
2950
|
+
switch (s.kind) {
|
|
2790
2951
|
case "create-table": {
|
|
2791
2952
|
let t = yield* e.onDialectOrElse({
|
|
2792
|
-
mysql: () =>
|
|
2793
|
-
mssql: () =>
|
|
2794
|
-
sqlite: () =>
|
|
2795
|
-
orElse: () =>
|
|
2953
|
+
mysql: () => Or(e).pipe(T.map((e) => pi(s, e))),
|
|
2954
|
+
mssql: () => T.succeed(wi(s)),
|
|
2955
|
+
sqlite: () => T.succeed(yi(s)),
|
|
2956
|
+
orElse: () => T.succeed(ci(s))
|
|
2796
2957
|
}), n = yield* e.onDialectOrElse({
|
|
2797
|
-
mysql: () =>
|
|
2798
|
-
orElse: () =>
|
|
2958
|
+
mysql: () => T.succeed([Nr]),
|
|
2959
|
+
orElse: () => T.succeed([])
|
|
2799
2960
|
});
|
|
2800
|
-
for (let r of t) yield* X(e, r,
|
|
2961
|
+
for (let r of t) yield* X(e, r, s.kind, n);
|
|
2801
2962
|
break;
|
|
2802
2963
|
}
|
|
2803
2964
|
case "drop-table": {
|
|
2804
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2965
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Di(s, n, e) : Ei(s, e);
|
|
2805
2966
|
yield* e.onDialectOrElse({
|
|
2806
|
-
mysql: () => X(e, r(
|
|
2807
|
-
orElse: () => X(e, r(
|
|
2967
|
+
mysql: () => X(e, r(K), s.kind),
|
|
2968
|
+
orElse: () => X(e, r(G), s.kind)
|
|
2808
2969
|
});
|
|
2809
2970
|
break;
|
|
2810
2971
|
}
|
|
2811
2972
|
case "drop-column": {
|
|
2812
2973
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2813
2974
|
yield* e.onDialectOrElse({
|
|
2814
|
-
mysql: () =>
|
|
2815
|
-
sqlite: () => X(e, t ?
|
|
2816
|
-
orElse: () => X(e, t ?
|
|
2975
|
+
mysql: () => Or(e).pipe(T.flatMap((r) => X(e, t ? Yr(s, n, K) : qr(s, r), s.kind, t ? [] : [Pr]))),
|
|
2976
|
+
sqlite: () => X(e, t ? Yr(s, n, G) : Kr(s, G, !1), s.kind, t ? [] : [Fr]),
|
|
2977
|
+
orElse: () => X(e, t ? Yr(s, n, G) : Kr(s, G), s.kind)
|
|
2817
2978
|
});
|
|
2818
2979
|
break;
|
|
2819
2980
|
}
|
|
2820
2981
|
case "rename-column":
|
|
2821
2982
|
yield* e.onDialectOrElse({
|
|
2822
|
-
mysql: () => X(e,
|
|
2823
|
-
mssql: () =>
|
|
2824
|
-
|
|
2983
|
+
mysql: () => X(e, Jr(s, K), s.kind),
|
|
2984
|
+
mssql: () => T.gen(function* () {
|
|
2985
|
+
let t = (yield* e`
|
|
2986
|
+
SELECT ck.name, ck.definition, ck.is_disabled AS disabled,
|
|
2987
|
+
ck.is_not_trusted AS untrusted, ck.is_not_for_replication AS notForReplication
|
|
2988
|
+
FROM sys.check_constraints ck
|
|
2989
|
+
WHERE ck.parent_object_id = OBJECT_ID(${s.table}) AND EXISTS (
|
|
2990
|
+
SELECT 1 FROM sys.sql_expression_dependencies dep
|
|
2991
|
+
JOIN sys.columns col ON col.object_id = dep.referenced_id AND col.column_id = dep.referenced_minor_id
|
|
2992
|
+
WHERE dep.referencing_id = ck.object_id AND col.object_id = ck.parent_object_id AND col.name = ${s.from}
|
|
2993
|
+
) ORDER BY ck.name
|
|
2994
|
+
`).map((e) => ({
|
|
2995
|
+
...e,
|
|
2996
|
+
definition: Rr(e.definition, s.from, s.to)
|
|
2997
|
+
})), n = (e) => o(e, "mssql"), r = (e) => e.replace(/'/g, "''");
|
|
2998
|
+
return yield* Z(e, [
|
|
2999
|
+
...t.map((e) => `ALTER TABLE ${n(s.table)} DROP CONSTRAINT ${n(e.name)}`),
|
|
3000
|
+
`EXEC sp_rename N'${r(`${n(s.table)}.${n(s.from)}`)}', N'${r(s.to)}', 'COLUMN';`,
|
|
3001
|
+
...t.flatMap((e) => [`ALTER TABLE ${n(s.table)} WITH ${e.untrusted ? "NOCHECK" : "CHECK"} ADD CONSTRAINT ${n(e.name)} CHECK ${e.notForReplication ? "NOT FOR REPLICATION " : ""}${e.definition}`, ...e.disabled ? [`ALTER TABLE ${n(s.table)} NOCHECK CONSTRAINT ${n(e.name)}`] : []])
|
|
3002
|
+
], s.kind);
|
|
3003
|
+
}),
|
|
3004
|
+
orElse: () => X(e, Jr(s, G), s.kind)
|
|
2825
3005
|
});
|
|
2826
3006
|
break;
|
|
2827
3007
|
case "add-index":
|
|
2828
3008
|
yield* e.onDialectOrElse({
|
|
2829
|
-
sqlite: () => X(e,
|
|
2830
|
-
mysql: () =>
|
|
2831
|
-
mssql: () => Z(e, [...
|
|
2832
|
-
orElse: () => X(e,
|
|
3009
|
+
sqlite: () => X(e, Mi(s, !1), s.kind),
|
|
3010
|
+
mysql: () => Or(e).pipe(T.flatMap((t) => X(e, Ni(s, n.declared, t), s.kind, [Nr]))),
|
|
3011
|
+
mssql: () => Z(e, [...Wi(s.table, s.index.columns, n.declared), Ui(s)], s.kind),
|
|
3012
|
+
orElse: () => X(e, Mi(s, t.classification === "online-required"), s.kind)
|
|
2833
3013
|
});
|
|
2834
3014
|
break;
|
|
2835
3015
|
case "drop-index":
|
|
2836
3016
|
yield* e.onDialectOrElse({
|
|
2837
|
-
mysql: () => X(e,
|
|
2838
|
-
mssql: () => X(e,
|
|
2839
|
-
orElse: () => X(e,
|
|
3017
|
+
mysql: () => X(e, Ii(s), s.kind),
|
|
3018
|
+
mssql: () => X(e, Li(s), s.kind),
|
|
3019
|
+
orElse: () => X(e, Fi(s), s.kind)
|
|
2840
3020
|
});
|
|
2841
3021
|
break;
|
|
2842
3022
|
case "rename-table":
|
|
2843
3023
|
yield* e.onDialectOrElse({
|
|
2844
|
-
mysql: () => X(e,
|
|
2845
|
-
mssql: () => X(e,
|
|
2846
|
-
orElse: () => X(e,
|
|
3024
|
+
mysql: () => X(e, Ri(s, K), s.kind),
|
|
3025
|
+
mssql: () => X(e, zi(s), s.kind),
|
|
3026
|
+
orElse: () => X(e, Ri(s, G), s.kind)
|
|
2847
3027
|
});
|
|
2848
3028
|
break;
|
|
2849
3029
|
case "rename-index":
|
|
2850
3030
|
yield* e.onDialectOrElse({
|
|
2851
|
-
mysql: () => X(e,
|
|
2852
|
-
mssql: () => X(e,
|
|
2853
|
-
orElse: () => X(e,
|
|
3031
|
+
mysql: () => X(e, Vi(s), s.kind),
|
|
3032
|
+
mssql: () => X(e, Hi(s), s.kind),
|
|
3033
|
+
orElse: () => X(e, Bi(s), s.kind)
|
|
2854
3034
|
});
|
|
2855
3035
|
break;
|
|
2856
3036
|
case "add-unique":
|
|
2857
3037
|
yield* e.onDialectOrElse({
|
|
2858
|
-
mysql: () => X(e,
|
|
2859
|
-
sqlite: () => Z(e,
|
|
2860
|
-
mssql: () => Z(e, [...
|
|
2861
|
-
orElse: () => X(e,
|
|
3038
|
+
mysql: () => X(e, Ki(s, n.declared), s.kind),
|
|
3039
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3040
|
+
mssql: () => Z(e, [...Wi(s.table, [s.column], n.declared), Gi(s)], s.kind),
|
|
3041
|
+
orElse: () => X(e, Gi(s), s.kind)
|
|
2862
3042
|
});
|
|
2863
3043
|
break;
|
|
2864
3044
|
case "drop-unique":
|
|
2865
3045
|
yield* e.onDialectOrElse({
|
|
2866
|
-
mysql: () => X(e,
|
|
2867
|
-
sqlite: () => Z(e,
|
|
2868
|
-
orElse: () => X(e,
|
|
3046
|
+
mysql: () => X(e, Qi(s), s.kind),
|
|
3047
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3048
|
+
orElse: () => X(e, Zi(s), s.kind)
|
|
2869
3049
|
});
|
|
2870
3050
|
break;
|
|
2871
3051
|
case "add-unique-composite":
|
|
2872
3052
|
yield* e.onDialectOrElse({
|
|
2873
|
-
mysql: () => X(e,
|
|
2874
|
-
sqlite: () => Z(e,
|
|
2875
|
-
mssql: () => Z(e, [...
|
|
2876
|
-
orElse: () => X(e,
|
|
3053
|
+
mysql: () => X(e, Ji(s, n.declared), s.kind),
|
|
3054
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3055
|
+
mssql: () => Z(e, [...Wi(s.table, s.fields, n.declared), qi(s)], s.kind),
|
|
3056
|
+
orElse: () => X(e, qi(s), s.kind)
|
|
2877
3057
|
});
|
|
2878
3058
|
break;
|
|
2879
3059
|
case "drop-unique-composite":
|
|
2880
3060
|
yield* e.onDialectOrElse({
|
|
2881
|
-
mysql: () => X(e,
|
|
2882
|
-
sqlite: () => Z(e,
|
|
2883
|
-
orElse: () => X(e,
|
|
3061
|
+
mysql: () => X(e, Xi(s), s.kind),
|
|
3062
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3063
|
+
orElse: () => X(e, Yi(s), s.kind)
|
|
2884
3064
|
});
|
|
2885
3065
|
break;
|
|
2886
3066
|
case "add-foreign-key":
|
|
2887
3067
|
yield* e.onDialectOrElse({
|
|
2888
|
-
mysql: () => Z(e,
|
|
2889
|
-
sqlite: () => Z(e,
|
|
2890
|
-
orElse: () => Z(e,
|
|
3068
|
+
mysql: () => Z(e, $i(s, K), s.kind),
|
|
3069
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3070
|
+
orElse: () => Z(e, $i(s, G), s.kind)
|
|
2891
3071
|
});
|
|
2892
3072
|
break;
|
|
2893
3073
|
case "add-column": {
|
|
2894
|
-
let n =
|
|
2895
|
-
mysql: () =>
|
|
2896
|
-
mssql: () =>
|
|
2897
|
-
sqlite: () =>
|
|
2898
|
-
orElse: () =>
|
|
3074
|
+
let n = oa(s, t, a, yield* e.onDialectOrElse({
|
|
3075
|
+
mysql: () => T.succeed("mariadb"),
|
|
3076
|
+
mssql: () => T.succeed("mssql"),
|
|
3077
|
+
sqlite: () => T.succeed("sqlite"),
|
|
3078
|
+
orElse: () => T.succeed("postgres")
|
|
2899
3079
|
}));
|
|
2900
|
-
if (!(r === "resume" && (yield* $(e,
|
|
3080
|
+
if (!(r === "resume" && (yield* $(e, Ue(e), s.table, s.column.name)))) for (let t of n.pre) yield* X(e, t, s.kind);
|
|
2901
3081
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2902
|
-
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(
|
|
3082
|
+
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${n.backfillSql}`;
|
|
2903
3083
|
else {
|
|
2904
3084
|
let t = n.batchSize ?? 5e3, r = n.sleepMs ?? 0, i, a = 0;
|
|
2905
3085
|
for (;;) {
|
|
2906
|
-
let
|
|
2907
|
-
if (
|
|
2908
|
-
let c =
|
|
2909
|
-
yield* e`UPDATE ${e(
|
|
3086
|
+
let o = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
3087
|
+
if (o.length === 0) break;
|
|
3088
|
+
let c = o.map((e) => e.id);
|
|
3089
|
+
yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += o.length, yield* T.logInfo(`backfill ${s.table}.${s.column.name}: ${a} rows`).pipe(T.annotateLogs({
|
|
2910
3090
|
scope: "voltro:migrate",
|
|
2911
3091
|
mode: "sql-batched"
|
|
2912
|
-
})), i =
|
|
3092
|
+
})), i = o[o.length - 1].id, r > 0 && (yield* T.sleep(`${r} millis`));
|
|
2913
3093
|
}
|
|
2914
3094
|
}
|
|
2915
3095
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
2916
3096
|
let t = n.batchSize ?? 1e3, r = n.sleepMs ?? 0, i, a = 0;
|
|
2917
3097
|
for (;;) {
|
|
2918
|
-
let
|
|
2919
|
-
if (
|
|
2920
|
-
for (let t of
|
|
2921
|
-
let r = yield*
|
|
3098
|
+
let o = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
3099
|
+
if (o.length === 0) break;
|
|
3100
|
+
for (let t of o) {
|
|
3101
|
+
let r = yield* T.tryPromise({
|
|
2922
3102
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2923
3103
|
catch: (e) => e
|
|
2924
|
-
}).pipe(
|
|
2925
|
-
yield* e`UPDATE ${e(
|
|
3104
|
+
}).pipe(T.orDie);
|
|
3105
|
+
yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2926
3106
|
}
|
|
2927
|
-
a +=
|
|
3107
|
+
a += o.length, yield* T.logInfo(`backfill ${s.table}.${s.column.name}: ${a} rows processed`).pipe(T.annotateLogs({
|
|
2928
3108
|
scope: "voltro:migrate",
|
|
2929
|
-
table:
|
|
2930
|
-
column:
|
|
2931
|
-
})), i =
|
|
3109
|
+
table: s.table,
|
|
3110
|
+
column: s.column.name
|
|
3111
|
+
})), i = o[o.length - 1].id, r > 0 && (yield* T.sleep(`${r} millis`));
|
|
2932
3112
|
}
|
|
2933
3113
|
}
|
|
2934
|
-
for (let t of n.post) yield* X(e, t,
|
|
3114
|
+
for (let t of n.post) yield* X(e, t, s.kind);
|
|
2935
3115
|
break;
|
|
2936
3116
|
}
|
|
2937
3117
|
case "alter-column-nullability":
|
|
2938
3118
|
yield* e.onDialectOrElse({
|
|
2939
3119
|
mysql: () => {
|
|
2940
|
-
let t =
|
|
2941
|
-
return t ? X(e, `ALTER TABLE ${
|
|
3120
|
+
let t = q(n.declared, s.table, s.column);
|
|
3121
|
+
return t ? X(e, `ALTER TABLE ${K(s.table)} MODIFY COLUMN ${ei(t, s.column, s.toNullable)};`, s.kind) : T.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${s.table}.${s.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2942
3122
|
},
|
|
2943
3123
|
mssql: () => {
|
|
2944
|
-
let t =
|
|
2945
|
-
return t ? X(e,
|
|
3124
|
+
let t = q(n.declared, s.table, s.column);
|
|
3125
|
+
return t ? X(e, bi(t, s.column, s.table, s.toNullable), s.kind) : T.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${s.table}.${s.column}'.`));
|
|
2946
3126
|
},
|
|
2947
|
-
sqlite: () => Z(e,
|
|
2948
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
3127
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3128
|
+
orElse: () => X(e, `ALTER TABLE ${G(s.table)} ALTER COLUMN ${G(s.column)} ${s.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, s.kind)
|
|
2949
3129
|
});
|
|
2950
3130
|
break;
|
|
2951
3131
|
case "alter-column-default": {
|
|
2952
|
-
let t =
|
|
3132
|
+
let t = $r(n.declared, s.table, s.column), r = q(n.declared, s.table, s.column), i = (e) => s.hasDefault && r !== void 0 && Zr(r, e) ? r : void 0;
|
|
2953
3133
|
yield* e.onDialectOrElse({
|
|
2954
3134
|
mysql: () => {
|
|
2955
3135
|
let n = i("mariadb");
|
|
2956
|
-
return X(e, n ? `ALTER TABLE ${
|
|
3136
|
+
return X(e, n ? `ALTER TABLE ${K(s.table)} MODIFY COLUMN ${ei(n, s.column)};` : Xr(s, K, (e) => ti(e, t)), s.kind);
|
|
2957
3137
|
},
|
|
2958
3138
|
mssql: () => {
|
|
2959
3139
|
let t = i("mssql");
|
|
2960
|
-
return X(e,
|
|
3140
|
+
return X(e, xi(s, t ? bi(t, s.column, s.table) : void 0), s.kind);
|
|
2961
3141
|
},
|
|
2962
|
-
sqlite: () => Z(e,
|
|
2963
|
-
orElse: () => X(e,
|
|
3142
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3143
|
+
orElse: () => X(e, Xr(s, G, (e) => ri(e, t)), s.kind)
|
|
2964
3144
|
});
|
|
2965
3145
|
break;
|
|
2966
3146
|
}
|
|
2967
3147
|
case "alter-column-type": {
|
|
2968
|
-
let r =
|
|
3148
|
+
let r = Hr($r(n.declared, s.table, s.column) ?? { type: s.to }), i = s.using ? ` USING ${s.using}` : "";
|
|
2969
3149
|
if (t.classification !== "online-required") {
|
|
2970
3150
|
yield* e.onDialectOrElse({
|
|
2971
3151
|
mysql: () => {
|
|
2972
|
-
let t =
|
|
2973
|
-
return t ? X(e, `ALTER TABLE ${
|
|
3152
|
+
let t = q(n.declared, s.table, s.column);
|
|
3153
|
+
return t ? X(e, `ALTER TABLE ${K(s.table)} MODIFY COLUMN ${ei(t, s.column)};`, s.kind) : T.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${s.table}.${s.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2974
3154
|
},
|
|
2975
3155
|
mssql: () => {
|
|
2976
|
-
let t =
|
|
2977
|
-
return t ? X(e,
|
|
3156
|
+
let t = q(n.declared, s.table, s.column);
|
|
3157
|
+
return t ? X(e, bi(t, s.column, s.table), s.kind) : T.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${s.table}.${s.column}'.`));
|
|
2978
3158
|
},
|
|
2979
|
-
sqlite: () => Z(e,
|
|
2980
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
3159
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3160
|
+
orElse: () => X(e, `ALTER TABLE ${G(s.table)} ALTER COLUMN ${G(s.column)} TYPE ${r}${i};`, s.kind)
|
|
2981
3161
|
});
|
|
2982
3162
|
break;
|
|
2983
3163
|
}
|
|
2984
3164
|
yield* e.onDialectOrElse({
|
|
2985
|
-
mysql: () =>
|
|
2986
|
-
orElse: () =>
|
|
3165
|
+
mysql: () => T.die(/* @__PURE__ */ Error(`online-required alter-column-type on ${s.table}.${s.column} is not supported on mariadb (the shadow-swap path is postgres-only). Use a smaller-table window or an external online-DDL tool.`)),
|
|
3166
|
+
orElse: () => T.void
|
|
2987
3167
|
});
|
|
2988
|
-
let a = `${
|
|
2989
|
-
yield* e.unsafe(`ALTER TABLE ${
|
|
2990
|
-
let c =
|
|
3168
|
+
let a = `${s.column}__shadow`, o = `${s.column}__old`;
|
|
3169
|
+
yield* e.unsafe(`ALTER TABLE ${G(s.table)} ADD COLUMN ${G(a)} ${r}`);
|
|
3170
|
+
let c = s.using ?? G(s.column), l;
|
|
2991
3171
|
for (;;) {
|
|
2992
|
-
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(
|
|
3172
|
+
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${Q(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${Q(e, 5e3)}`;
|
|
2993
3173
|
if (t.length === 0) break;
|
|
2994
|
-
yield* e.unsafe(`UPDATE ${
|
|
3174
|
+
yield* e.unsafe(`UPDATE ${G(s.table)} SET ${G(a)} = ${c} WHERE ${G(s.column)} IS NOT NULL AND ${G(a)} IS NULL AND ${G("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
2995
3175
|
}
|
|
2996
|
-
yield*
|
|
3176
|
+
yield* T.logInfo(`alter-column-type shadow ${s.table}.${s.column}: shadow populated`).pipe(T.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${G(s.table)} RENAME COLUMN ${G(s.column)} TO ${G(o)}`), yield* e.unsafe(`ALTER TABLE ${G(s.table)} RENAME COLUMN ${G(a)} TO ${G(s.column)}`), yield* e.unsafe(`ALTER TABLE ${G(s.table)} DROP COLUMN ${G(o)}`);
|
|
2997
3177
|
break;
|
|
2998
3178
|
}
|
|
2999
3179
|
case "drop-foreign-key":
|
|
3000
3180
|
yield* e.onDialectOrElse({
|
|
3001
|
-
mysql: () => X(e,
|
|
3002
|
-
sqlite: () => Z(e,
|
|
3003
|
-
orElse: () => X(e,
|
|
3181
|
+
mysql: () => X(e, ta(s), s.kind),
|
|
3182
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3183
|
+
orElse: () => X(e, ea(s), s.kind)
|
|
3004
3184
|
});
|
|
3005
3185
|
break;
|
|
3006
3186
|
case "add-check":
|
|
3007
3187
|
yield* e.onDialectOrElse({
|
|
3008
|
-
mysql: () => X(e,
|
|
3009
|
-
sqlite: () => Z(e,
|
|
3010
|
-
orElse: () => X(e,
|
|
3188
|
+
mysql: () => X(e, na(s, K), s.kind),
|
|
3189
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3190
|
+
orElse: () => X(e, na(s, G), s.kind)
|
|
3011
3191
|
});
|
|
3012
3192
|
break;
|
|
3193
|
+
case "reconcile-json-check": {
|
|
3194
|
+
let t = Y(s.column), n = s.validation === "value" ? rt(t) : `(${t} IS NULL OR ISJSON(${t}) = 1)`;
|
|
3195
|
+
yield* e.onDialectOrElse({
|
|
3196
|
+
mssql: () => Z(e, [...s.dropConstraints.map((e) => `ALTER TABLE ${Y(s.table)} DROP CONSTRAINT ${Y(e)}`), `ALTER TABLE ${Y(s.table)} WITH CHECK ADD CHECK ${n}`], s.kind),
|
|
3197
|
+
orElse: () => T.dieMessage("reconcile-json-check requires SQL Server")
|
|
3198
|
+
});
|
|
3199
|
+
break;
|
|
3200
|
+
}
|
|
3013
3201
|
case "drop-check": yield* e.onDialectOrElse({
|
|
3014
|
-
mysql: () =>
|
|
3015
|
-
sqlite: () => Z(e,
|
|
3016
|
-
orElse: () => X(e,
|
|
3202
|
+
mysql: () => aa(e, s, n.declared),
|
|
3203
|
+
sqlite: () => Z(e, J(s.table, n.declared), s.kind),
|
|
3204
|
+
orElse: () => X(e, ra(s), s.kind)
|
|
3017
3205
|
});
|
|
3018
3206
|
}
|
|
3019
3207
|
return {
|
|
3020
|
-
op:
|
|
3208
|
+
op: s,
|
|
3021
3209
|
status: "applied",
|
|
3022
3210
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
3023
3211
|
};
|
|
3024
|
-
}),
|
|
3212
|
+
}), ga = (e, t, n, r) => T.gen(function* () {
|
|
3025
3213
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
3026
|
-
if (i.length > 1) return yield*
|
|
3214
|
+
if (i.length > 1) return yield* T.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger holds ${i.length} unfinished runs (${i.join(", ")}). Only one migration may be in flight at a time — the advisory lock enforces it — so this means a run was interrupted and a LATER one wrote over it without clearing.\nNothing was changed. Inspect \`${k}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
3027
3215
|
let a = i[0], o = [...r].map((e) => ({
|
|
3028
3216
|
index: Number(e.opIndex),
|
|
3029
3217
|
status: e.status,
|
|
3030
3218
|
planned: JSON.parse(e.payload)
|
|
3031
3219
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
3032
|
-
if (c > 1) return yield*
|
|
3033
|
-
if (yield*
|
|
3220
|
+
if (c > 1) return yield* T.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger records ${c} operations as in-flight for run ${a}. It is written strictly sequentially, so at most one can be — this ledger is corrupt and the schema state it describes cannot be trusted.\nNothing was changed. Reconcile \`${k}\` by hand before re-running.`));
|
|
3221
|
+
if (yield* T.logWarning(`migration resume: found an interrupted run (${a}) — ${o.filter((e) => e.status === "applied").length} of ${o.length} operation(s) completed${s ? `, in flight: ${s.planned.op.kind} ${Je(s.planned.op)}` : ""}`).pipe(T.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
3034
3222
|
kind: "discard",
|
|
3035
3223
|
runId: a,
|
|
3036
3224
|
why: "no operation had started — no DDL ran"
|
|
3037
3225
|
};
|
|
3038
|
-
let l = s ? yield*
|
|
3226
|
+
let l = s ? yield* ma(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
3039
3227
|
if (u !== n.toFingerprint) return {
|
|
3040
3228
|
kind: "discard",
|
|
3041
3229
|
runId: a,
|
|
3042
3230
|
why: `the declared schema changed since the interruption (recorded target ${u.slice(0, 12)}…, current ${n.toFingerprint.slice(0, 12)}…) — applying the freshly-diffed plan instead`
|
|
3043
3231
|
};
|
|
3044
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
3232
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : Xe(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
3045
3233
|
return f.length === 0 ? {
|
|
3046
3234
|
kind: "discard",
|
|
3047
3235
|
runId: a,
|
|
3048
3236
|
why: "every recorded operation had already taken effect"
|
|
3049
|
-
} : (yield*
|
|
3237
|
+
} : (yield* fa(e, a, f.map((e) => e.index), p.map((e) => e.index)), yield* T.logWarning(`migration resume: continuing run ${a} — replaying ${f.length} operation(s), ${o.length - f.length} already applied`).pipe(T.annotateLogs({ scope: "voltro:migrate" })), {
|
|
3050
3238
|
kind: "resume",
|
|
3051
3239
|
runId: a,
|
|
3052
3240
|
ops: f.map((e) => ({
|
|
@@ -3054,7 +3242,7 @@ BEGIN
|
|
|
3054
3242
|
planned: e.planned
|
|
3055
3243
|
}))
|
|
3056
3244
|
});
|
|
3057
|
-
}),
|
|
3245
|
+
}), _a = (e, t, n) => T.gen(function* () {
|
|
3058
3246
|
for (let r of t.operations) {
|
|
3059
3247
|
let i = r.op;
|
|
3060
3248
|
if (i.kind !== "add-index" || !i.index.unique || i.index.where === void 0 || t.operations.some((e) => e.op.kind === "rename-table" ? e.op.to === i.table : e.op.table === i.table && [
|
|
@@ -3063,9 +3251,9 @@ BEGIN
|
|
|
3063
3251
|
"rename-column"
|
|
3064
3252
|
].includes(e.op.kind))) continue;
|
|
3065
3253
|
let a = i.index.columns.map((e) => e.startsWith("(") ? e : o(e, n)), s = n === "mssql" ? "" : a.map((e) => ` AND ${e} IS NOT NULL`).join(""), c = n === "mssql" ? "SELECT TOP (1) 1" : "SELECT 1", l = n === "mssql" ? "" : " LIMIT 1";
|
|
3066
|
-
if ((yield* e.unsafe(`${c} FROM ${o(i.table, n)} WHERE (${i.index.where})${s} GROUP BY ${a.join(", ")} HAVING COUNT(*) > 1${l}`)).length > 0) return yield*
|
|
3254
|
+
if ((yield* e.unsafe(`${c} FROM ${o(i.table, n)} WHERE (${i.index.where})${s} GROUP BY ${a.join(", ")} HAVING COUNT(*) > 1${l}`)).length > 0) return yield* T.die(/* @__PURE__ */ Error(`applyPlan: partial unique index '${i.index.name}' on '${i.table}' conflicts with existing qualifying rows. No schema or row changes were applied. Resolve the conflicting data explicitly before retrying.`));
|
|
3067
3255
|
}
|
|
3068
|
-
}),
|
|
3256
|
+
}), va = (e) => {
|
|
3069
3257
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3070
3258
|
return [
|
|
3071
3259
|
t.kind,
|
|
@@ -3074,45 +3262,45 @@ BEGIN
|
|
|
3074
3262
|
n("name"),
|
|
3075
3263
|
n("to")
|
|
3076
3264
|
].join("\0");
|
|
3077
|
-
},
|
|
3265
|
+
}, ya = (e, t, n) => T.acquireUseRelease(Ve(e, { schema: n.lockSchema }), () => ba(e, t, n), (e) => e.release.pipe(T.orDie)), ba = (e, t, n) => T.gen(function* () {
|
|
3078
3266
|
let r = t.operations.filter((e) => e.blocked);
|
|
3079
|
-
if (r.length > 0) return yield*
|
|
3080
|
-
let i = Date.now(), a = [], o =
|
|
3267
|
+
if (r.length > 0) return yield* T.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
3268
|
+
let i = Date.now(), a = [], o = Ue(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => va(e))), l = {
|
|
3081
3269
|
...s,
|
|
3082
3270
|
operations: s.operations.map((e) => {
|
|
3083
|
-
if (!e.blocked || !c.has(
|
|
3271
|
+
if (!e.blocked || !c.has(va(e))) return e;
|
|
3084
3272
|
let { blocked: t, ...n } = e;
|
|
3085
3273
|
return n;
|
|
3086
3274
|
})
|
|
3087
3275
|
};
|
|
3088
|
-
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield*
|
|
3276
|
+
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield* T.logInfo(`migration: re-planned under the lock — ${t.operations.length} operation(s) became ${l.operations.length}. Another writer changed the schema while this plan waited.`).pipe(T.annotateLogs({ scope: "voltro:migrate" })));
|
|
3089
3277
|
let u = l.operations.filter((e) => e.blocked);
|
|
3090
|
-
if (u.length > 0) return yield*
|
|
3091
|
-
let d =
|
|
3278
|
+
if (u.length > 0) return yield* T.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — re-planning under the migration lock found ${u.length} blocked operation(s). Run \`voltro db plan\` to see the fixes.`));
|
|
3279
|
+
let d = Ge(o) === "plan-transactional", f = d ? l.operations.filter((e) => e.classification !== "online-required") : [], p = d ? l.operations.filter((e) => e.classification === "online-required") : l.operations, m = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, h = p.map((e, t) => ({
|
|
3092
3280
|
index: t,
|
|
3093
3281
|
planned: e
|
|
3094
3282
|
})), _ = "fresh";
|
|
3095
|
-
yield*
|
|
3096
|
-
let v = yield*
|
|
3283
|
+
yield* _a(e, l, o), yield* ca(e, o);
|
|
3284
|
+
let v = yield* la(e);
|
|
3097
3285
|
if (v.length > 0) {
|
|
3098
|
-
let t = yield*
|
|
3099
|
-
t.kind === "resume" ? (m = t.runId, h = t.ops, _ = "resume") : (yield*
|
|
3286
|
+
let t = yield* ga(e, o, l, v);
|
|
3287
|
+
t.kind === "resume" ? (m = t.runId, h = t.ops, _ = "resume") : (yield* T.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(T.annotateLogs({ scope: "voltro:migrate" })), yield* pa(e, t.runId));
|
|
3100
3288
|
}
|
|
3101
|
-
_ === "fresh" && h.length > 0 && (yield*
|
|
3289
|
+
_ === "fresh" && h.length > 0 && (yield* ua(e, m, l.toFingerprint, h)), f.length > 0 && (yield* Lr(e, T.gen(function* () {
|
|
3102
3290
|
let e = yield* E.SqlClient;
|
|
3103
|
-
for (let t of f) a.push(yield*
|
|
3291
|
+
for (let t of f) a.push(yield* ha(e, t, n));
|
|
3104
3292
|
})));
|
|
3105
3293
|
for (let { index: t, planned: r } of h) {
|
|
3106
|
-
yield*
|
|
3107
|
-
let i = a.length, o = yield*
|
|
3108
|
-
a.push(o), yield*
|
|
3294
|
+
yield* da(e, m, t, "started");
|
|
3295
|
+
let i = a.length, o = yield* ha(e, r, n, _).pipe(T.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${h.length + f.length} operation(s) applied before this one${f.length > 0 ? ` (${f.length} of them in a transaction)` : ""}.\n` + (d ? " This dialect applies a plan atomically, so the run is rolled back.\n" : ` This dialect does NOT apply a plan atomically: those ${i} are COMMITTED and there is no rollback.\n The next \`voltro db apply\` resumes from operation ${t} — the ledger records the sequence.\n`) })));
|
|
3296
|
+
a.push(o), yield* da(e, m, t, "applied", o.durationMs);
|
|
3109
3297
|
}
|
|
3110
3298
|
let y = yield* n.replan(e);
|
|
3111
3299
|
if (y.operations.length > 0) {
|
|
3112
3300
|
let e = y.operations.slice(0, 10).map((e) => ` - ${e.op.kind} ${"table" in e.op ? e.op.table : ""}${"column" in e.op ? `.${String(e.op.column)}` : ""}`).join("\n");
|
|
3113
|
-
return yield*
|
|
3301
|
+
return yield* T.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${y.operations.length}:\n${e}${y.operations.length > 10 ? `\n … and ${y.operations.length - 10} more` : ""}\nNo fingerprint was recorded — recording one would make the next boot report "schema up to date" for a schema that was never applied. This is a framework bug; the schema is unchanged and safe.\nTwo causes look identical from here, so read the list before assuming either:\n - the DDL for those operations is a no-op (it succeeded and changed nothing), or\n - the planner cannot see what the DDL did, so it proposes the same work again — which is what an\n operation naming an object a PREVIOUS operation created or renamed usually means.\nReport the operation kinds above with the column types involved.`));
|
|
3114
3302
|
}
|
|
3115
|
-
let b = a.filter((e) => e.status === "applied").length, x = Date.now() - i, S = m, C = (/* @__PURE__ */ new Date()).toISOString(),
|
|
3303
|
+
let b = a.filter((e) => e.status === "applied").length, x = Date.now() - i, S = m, C = (/* @__PURE__ */ new Date()).toISOString(), w = yield* W(e, C), ee = [...f, ...h.map((e) => e.planned)];
|
|
3116
3304
|
yield* e`
|
|
3117
3305
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3118
3306
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -3121,10 +3309,10 @@ BEGIN
|
|
|
3121
3309
|
VALUES
|
|
3122
3310
|
(${S}, ${l.toFingerprint}, ${y.fromFingerprint}, ${JSON.stringify(ee)},
|
|
3123
3311
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3124
|
-
${x}, ${
|
|
3125
|
-
`, yield*
|
|
3312
|
+
${x}, ${w}, ${n.notes ?? null})
|
|
3313
|
+
`, yield* pa(e, m);
|
|
3126
3314
|
let te = [...new Set(ee.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3127
|
-
return yield*
|
|
3315
|
+
return yield* T.promise(() => g({ changedTables: te }).catch(() => {})), {
|
|
3128
3316
|
id: S,
|
|
3129
3317
|
appliedAt: C,
|
|
3130
3318
|
fingerprint: l.toFingerprint,
|
|
@@ -3136,14 +3324,14 @@ BEGIN
|
|
|
3136
3324
|
source: n.source,
|
|
3137
3325
|
...n.notes ? { notes: n.notes } : {}
|
|
3138
3326
|
};
|
|
3139
|
-
}),
|
|
3327
|
+
}), xa = (e) => e.operations.filter((e) => e.blocked).map((e) => ` - ${e.op.kind} ${"table" in e.op ? `[${e.op.table}]` : ""}: ${e.reason ?? "<no reason>"}\n fix: ${e.blocked?.fix ?? "<no fix>"}`).join("\n"), Sa = (e) => e`
|
|
3140
3328
|
SELECT fingerprint
|
|
3141
3329
|
FROM _voltro_migration_plans
|
|
3142
3330
|
ORDER BY ${e("appliedAt")} DESC
|
|
3143
3331
|
LIMIT 1
|
|
3144
|
-
`.pipe(
|
|
3145
|
-
if ((yield*
|
|
3146
|
-
let r = `plan_${Date.now().toString(36)}`, i = yield*
|
|
3332
|
+
`.pipe(T.map((e) => e.length > 0 ? e[0].fingerprint : void 0), T.catchAll(() => T.succeed(void 0))), Ca = (e, t, n) => T.gen(function* () {
|
|
3333
|
+
if ((yield* Sa(e)) === t.toFingerprint) return "already-current";
|
|
3334
|
+
let r = `plan_${Date.now().toString(36)}`, i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3147
3335
|
return yield* e`
|
|
3148
3336
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3149
3337
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -3154,8 +3342,8 @@ BEGIN
|
|
|
3154
3342
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3155
3343
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3156
3344
|
`, "recorded";
|
|
3157
|
-
}).pipe(
|
|
3158
|
-
let n =
|
|
3345
|
+
}).pipe(T.catchAll(() => T.succeed("already-current"))), wa = (e, t) => T.gen(function* () {
|
|
3346
|
+
let n = R(z(t, Ue(e))), r = yield* Sa(e);
|
|
3159
3347
|
return r === n ? {
|
|
3160
3348
|
kind: "up-to-date",
|
|
3161
3349
|
fingerprint: n
|
|
@@ -3164,23 +3352,23 @@ BEGIN
|
|
|
3164
3352
|
expected: n,
|
|
3165
3353
|
...r === void 0 ? {} : { actual: r }
|
|
3166
3354
|
};
|
|
3167
|
-
}),
|
|
3355
|
+
}), Ta = [
|
|
3168
3356
|
"pgeagertest_",
|
|
3169
3357
|
"mig_e2e_",
|
|
3170
3358
|
"mig_test_",
|
|
3171
3359
|
"mysqleagertest_",
|
|
3172
3360
|
"mssqleagertest_",
|
|
3173
3361
|
"sqliteeagertest_"
|
|
3174
|
-
],
|
|
3362
|
+
], Ea = (e) => Ta.some((t) => e.startsWith(t)), Da = (e, t) => T.gen(function* () {
|
|
3175
3363
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3176
|
-
let n = t.filter((e) =>
|
|
3364
|
+
let n = t.filter((e) => Ea(e.name)).map((e) => e.name);
|
|
3177
3365
|
if (n.length === 0) return [];
|
|
3178
|
-
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(
|
|
3366
|
+
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(T.catchAll(() => T.void));
|
|
3179
3367
|
return n;
|
|
3180
|
-
}),
|
|
3368
|
+
}), Oa = () => {
|
|
3181
3369
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3182
3370
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3183
|
-
},
|
|
3371
|
+
}, ka = (e) => {
|
|
3184
3372
|
if (e === void 0) return;
|
|
3185
3373
|
let t = e.trim();
|
|
3186
3374
|
if (t === "") return;
|
|
@@ -3190,55 +3378,55 @@ BEGIN
|
|
|
3190
3378
|
kind: "tables",
|
|
3191
3379
|
tables: new Set(n)
|
|
3192
3380
|
} : void 0;
|
|
3193
|
-
},
|
|
3381
|
+
}, Aa = (e) => typeof e.table == "string" ? e.table : void 0, ja = (e, t = { kind: "all" }) => ({
|
|
3194
3382
|
...e,
|
|
3195
3383
|
operations: e.operations.map((e) => {
|
|
3196
3384
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3197
3385
|
if (t?.kind === "tables") {
|
|
3198
|
-
let n =
|
|
3386
|
+
let n = Aa(e.op);
|
|
3199
3387
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3200
3388
|
}
|
|
3201
3389
|
let { blocked: n, ...r } = e;
|
|
3202
3390
|
return r;
|
|
3203
3391
|
})
|
|
3204
|
-
}),
|
|
3205
|
-
let t =
|
|
3206
|
-
return t === void 0 ?
|
|
3207
|
-
}),
|
|
3208
|
-
let r =
|
|
3392
|
+
}), Ma = (e, t, n) => t === "postgres" ? Cn(e, n).pipe(T.flatMap((e) => {
|
|
3393
|
+
let t = wn(e);
|
|
3394
|
+
return t === void 0 ? T.void : T.logWarning(`auto-migrate: ${t}`).pipe(T.annotateLogs({ scope: "voltro:migrate" }));
|
|
3395
|
+
}), T.catchAll(() => T.void)) : T.void, Na = (e, t, n) => T.gen(function* () {
|
|
3396
|
+
let r = Ue(e), a = t;
|
|
3209
3397
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3210
|
-
let t =
|
|
3211
|
-
if ((yield*
|
|
3398
|
+
let t = R(z(a, r));
|
|
3399
|
+
if ((yield* Sa(e)) === t) return yield* Ma(e, r, a), {
|
|
3212
3400
|
kind: "up-to-date",
|
|
3213
3401
|
fingerprint: t
|
|
3214
3402
|
};
|
|
3215
3403
|
}
|
|
3216
|
-
let o = yield*
|
|
3217
|
-
s.length > 0 && (yield*
|
|
3404
|
+
let o = yield* Tr(e), s = yield* Da(e, o.tables);
|
|
3405
|
+
s.length > 0 && (yield* T.logInfo(`auto-migrate: reaped ${s.length} test-fixture leftover(s)`).pipe(T.annotateLogs({
|
|
3218
3406
|
scope: "voltro:migrate",
|
|
3219
3407
|
count: s.length
|
|
3220
|
-
})), o = yield*
|
|
3408
|
+
})), o = yield* Tr(e));
|
|
3221
3409
|
{
|
|
3222
3410
|
let e = n.softDropRetentionDays ?? 7, t = p(o, { retentionDays: e });
|
|
3223
|
-
t.length > 0 && (yield*
|
|
3411
|
+
t.length > 0 && (yield* T.logWarning(`auto-migrate: ${i(t, e)}`).pipe(T.annotateLogs({
|
|
3224
3412
|
scope: "voltro:migrate",
|
|
3225
3413
|
snapshots: t.map((e) => e.name)
|
|
3226
3414
|
})));
|
|
3227
3415
|
}
|
|
3228
|
-
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u =
|
|
3416
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u = nr({
|
|
3229
3417
|
declared: a,
|
|
3230
3418
|
live: { tables: l(o.tables) },
|
|
3231
3419
|
dialect: r,
|
|
3232
|
-
...
|
|
3420
|
+
...Oa()
|
|
3233
3421
|
});
|
|
3234
3422
|
if (u.summary.blocked > 0) {
|
|
3235
|
-
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
3236
|
-
if (t === void 0 || !e || (u =
|
|
3423
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = ka(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3424
|
+
if (t === void 0 || !e || (u = ja(u, t), u.operations.some((e) => e.blocked))) return {
|
|
3237
3425
|
kind: "refused-blocked",
|
|
3238
3426
|
plan: u
|
|
3239
3427
|
};
|
|
3240
3428
|
}
|
|
3241
|
-
return u.operations.length === 0 ? (yield*
|
|
3429
|
+
return u.operations.length === 0 ? (yield* Ca(e, u, {
|
|
3242
3430
|
appliedBy: n.appliedBy,
|
|
3243
3431
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3244
3432
|
source: "auto-diff"
|
|
@@ -3247,37 +3435,37 @@ BEGIN
|
|
|
3247
3435
|
fingerprint: u.toFingerprint
|
|
3248
3436
|
}) : {
|
|
3249
3437
|
kind: "applied",
|
|
3250
|
-
applied: yield*
|
|
3438
|
+
applied: yield* ya(e, u, {
|
|
3251
3439
|
declared: t,
|
|
3252
3440
|
appliedBy: n.appliedBy,
|
|
3253
3441
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3254
3442
|
source: "auto-diff",
|
|
3255
|
-
replan: (e) =>
|
|
3256
|
-
let t = yield*
|
|
3257
|
-
return
|
|
3443
|
+
replan: (e) => T.gen(function* () {
|
|
3444
|
+
let t = yield* Tr(e);
|
|
3445
|
+
return nr({
|
|
3258
3446
|
declared: a,
|
|
3259
3447
|
live: { tables: l(t.tables) },
|
|
3260
3448
|
dialect: r,
|
|
3261
|
-
...
|
|
3449
|
+
...Oa()
|
|
3262
3450
|
});
|
|
3263
3451
|
})
|
|
3264
3452
|
}),
|
|
3265
3453
|
plan: u
|
|
3266
3454
|
};
|
|
3267
|
-
}),
|
|
3455
|
+
}), Pa = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? T.succeed({
|
|
3268
3456
|
kind: "skipped",
|
|
3269
3457
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3270
|
-
}) : n.environment === "prod" ?
|
|
3458
|
+
}) : n.environment === "prod" ? wa(e, t) : Na(e, t, n), Fa = (e, t) => {
|
|
3271
3459
|
switch (e.kind) {
|
|
3272
3460
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3273
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
3461
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${_n(e.fingerprint)})`;
|
|
3274
3462
|
case "applied": {
|
|
3275
3463
|
let t = e.plan.summary;
|
|
3276
|
-
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${
|
|
3464
|
+
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${_n(e.applied.fingerprint)}`;
|
|
3277
3465
|
}
|
|
3278
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
3466
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${_n(e.expected)}` + (e.actual ? ` live=${_n(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
3279
3467
|
case "refused-blocked": {
|
|
3280
|
-
let t = e.plan.operations.filter((e) => e.blocked), n = t.filter((e) => e.op.kind === "drop-table").length, r = t.filter((e) => e.op.kind === "drop-table").map((e) => "table" in e.op ? e.op.table : "").filter(Boolean), i = t.filter((e) => e.op.kind === "add-column").length, a = t.filter((e) => e.op.kind === "drop-column").length, o = t.filter((e) => e.classification === "needs-rename-annotation").length, s = `auto-migrate: REFUSED — ${e.plan.summary.blocked} blocked operation(s):\n` +
|
|
3468
|
+
let t = e.plan.operations.filter((e) => e.blocked), n = t.filter((e) => e.op.kind === "drop-table").length, r = t.filter((e) => e.op.kind === "drop-table").map((e) => "table" in e.op ? e.op.table : "").filter(Boolean), i = t.filter((e) => e.op.kind === "add-column").length, a = t.filter((e) => e.op.kind === "drop-column").length, o = t.filter((e) => e.classification === "needs-rename-annotation").length, s = `auto-migrate: REFUSED — ${e.plan.summary.blocked} blocked operation(s):\n` + xa(e.plan), c = [""];
|
|
3281
3469
|
if (n > 0 && c.push(`${n} table(s) exist in the live DB but aren't in your declared schema.`, "This is usually one of three things:", " (a) You're iterating on the schema — the table file got renamed, moved, or temporarily commented out.", " → Restore the declaration. Your data stays intact.", " (b) You want to KEEP the table but NOT manage it with Voltro (a leftover from another tool —", " a Strapi/Rails/legacy migration artifact, or an externally-owned table).", ` → Set \`VOLTRO_DB_IGNORE_TABLES=${r.join(",")}\` (comma-separated).`, " The planner excludes those tables from the diff entirely — it never drops them, and they", " stop blocking your OTHER (additive) changes. This is the fix when a leftover freezes your schema.", " (c) You actually want to drop the table.", ` → Set \`VOLTRO_DESTRUCTIVE_OK=${r.join(",")}\` for ONE run — it acknowledges`, " the data loss for THOSE tables only; every other lossy op in this plan stays blocked.", " (`VOLTRO_DESTRUCTIVE_OK=1` acknowledges all of them, which is rarely what you mean.)", " There is deliberately no `dropped()` marker for a TABLE, unlike for a column: a", " dropped column leaves a slot worth documenting in the declaration, a dropped table", " leaves nothing — the marker would be a dead entry you must remember to delete.", " Soft-drop: set `VOLTRO_SOFT_DROP=1` alongside DESTRUCTIVE_OK to RENAME instead of DROP", " (data survives as `<name>__dropped_<ts>` for ~7d; restorable via `voltro db restore-snapshot`)."), i > 0 && c.push(`${i} required column(s) need a backfill strategy before adding to a populated table.`, " → Annotate the column: `.backfill(sql`<expr>`)` or `.backfill(row => <fn>)` or `.default(<value>)`.", " Existing rows get the backfill value; the column then lands as NOT NULL."), a > 0) {
|
|
3282
3470
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3283
3471
|
for (let r of e.plan.operations) {
|
|
@@ -3294,7 +3482,7 @@ BEGIN
|
|
|
3294
3482
|
return o > 0 && c.push(`${o} column(s) look like renames (one column gone + a new one of same shape appeared).`, " → On the NEW column add `.renamedFrom('<oldName>')` so the planner emits RENAME instead of DROP+ADD."), c.push("", "See `voltro db plan` for the full machine-readable diff."), s + "\n" + c.join("\n");
|
|
3295
3483
|
}
|
|
3296
3484
|
}
|
|
3297
|
-
},
|
|
3485
|
+
}, Ia = ae({ scope: "voltro:migrate" }), La = /* @__PURE__ */ new Set([
|
|
3298
3486
|
"node_modules",
|
|
3299
3487
|
"dist",
|
|
3300
3488
|
"build",
|
|
@@ -3303,12 +3491,12 @@ BEGIN
|
|
|
3303
3491
|
".next",
|
|
3304
3492
|
".git",
|
|
3305
3493
|
".framework"
|
|
3306
|
-
]),
|
|
3494
|
+
]), Ra = async (e) => {
|
|
3307
3495
|
let t = [], n = async (e) => {
|
|
3308
|
-
let r = await
|
|
3496
|
+
let r = await oe.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3309
3497
|
for (let i of r) {
|
|
3310
|
-
if (
|
|
3311
|
-
let r =
|
|
3498
|
+
if (La.has(i.name)) continue;
|
|
3499
|
+
let r = se(e, i.name);
|
|
3312
3500
|
i.isDirectory() ? await n(r) : i.isFile() && S.test(i.name) && t.push(r);
|
|
3313
3501
|
}
|
|
3314
3502
|
};
|
|
@@ -3316,12 +3504,12 @@ BEGIN
|
|
|
3316
3504
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3317
3505
|
return n.localeCompare(r);
|
|
3318
3506
|
});
|
|
3319
|
-
},
|
|
3507
|
+
}, za = async (e) => {
|
|
3320
3508
|
let t = [];
|
|
3321
3509
|
for (let n of e) {
|
|
3322
|
-
let e = (await import(
|
|
3510
|
+
let e = (await import(ce(n).href)).default;
|
|
3323
3511
|
if (!u(e)) {
|
|
3324
|
-
|
|
3512
|
+
Ia.warn("migration file has no default-exported `migration(...)` — skipped", { file: n });
|
|
3325
3513
|
continue;
|
|
3326
3514
|
}
|
|
3327
3515
|
t.push({
|
|
@@ -3330,11 +3518,11 @@ BEGIN
|
|
|
3330
3518
|
});
|
|
3331
3519
|
}
|
|
3332
3520
|
return t;
|
|
3333
|
-
},
|
|
3521
|
+
}, Ba = (e) => e`
|
|
3334
3522
|
SELECT ${e("id")}
|
|
3335
3523
|
FROM ${e("_voltro_migration_plans")}
|
|
3336
3524
|
WHERE ${e("source")} = 'file'
|
|
3337
|
-
`.pipe(
|
|
3525
|
+
`.pipe(T.map((e) => e.map((e) => e.id)), T.catchAll(() => T.succeed([]))), Va = class extends Error {
|
|
3338
3526
|
migrationId;
|
|
3339
3527
|
file;
|
|
3340
3528
|
cause;
|
|
@@ -3342,28 +3530,28 @@ BEGIN
|
|
|
3342
3530
|
constructor(e, t, n) {
|
|
3343
3531
|
super(`migration ${e}: up() SUCCEEDED but the ledger row could not be written.\n The change IS in the database. It is NOT recorded, so the next run would apply it AGAIN.\n Do not re-run ${t} until this is resolved.\n Cause: ${n instanceof Error ? n.message : String(n)}`), this.migrationId = e, this.file = t, this.cause = n, this.name = "FileMigrationLedgerError";
|
|
3344
3532
|
}
|
|
3345
|
-
},
|
|
3533
|
+
}, Ha = (e, t, n, r) => T.gen(function* () {
|
|
3346
3534
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3347
3535
|
sql: e,
|
|
3348
3536
|
log: {
|
|
3349
|
-
info: (e, n) =>
|
|
3537
|
+
info: (e, n) => T.logInfo(e).pipe(T.annotateLogs({
|
|
3350
3538
|
scope: `migrations:file:${t.migration.id}`,
|
|
3351
3539
|
...n ?? {}
|
|
3352
3540
|
})),
|
|
3353
|
-
warn: (e, n) =>
|
|
3541
|
+
warn: (e, n) => T.logWarning(e).pipe(T.annotateLogs({
|
|
3354
3542
|
scope: `migrations:file:${t.migration.id}`,
|
|
3355
3543
|
...n ?? {}
|
|
3356
3544
|
}))
|
|
3357
3545
|
},
|
|
3358
3546
|
appliedAt: a
|
|
3359
3547
|
}, s = t.migration.up(o);
|
|
3360
|
-
|
|
3548
|
+
T.isEffect(s) ? yield* s : yield* T.tryPromise({
|
|
3361
3549
|
try: () => s,
|
|
3362
3550
|
catch: (e) => e
|
|
3363
3551
|
});
|
|
3364
3552
|
let c = Date.now() - i;
|
|
3365
|
-
!
|
|
3366
|
-
let l = yield*
|
|
3553
|
+
!T.isEffect(s) && c < 2 && (yield* T.logWarning(`migration ${t.migration.id}: up() resolved in ${c}ms — did the body \`await\` an \`@effect/sql\` Effect by accident? \`sql.unsafe(...)\` returns an Effect, not a Promise; \`await\` on it is a silent no-op. Switch the body to \`Effect.gen(function* () { yield* sql.unsafe(...) })\` form.`).pipe(T.annotateLogs({ scope: `migrations:file:${t.migration.id}` })));
|
|
3554
|
+
let l = yield* W(e, a);
|
|
3367
3555
|
return yield* e`
|
|
3368
3556
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3369
3557
|
(${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
@@ -3376,87 +3564,87 @@ BEGIN
|
|
|
3376
3564
|
}])},
|
|
3377
3565
|
${r}, ${n}, ${"file"},
|
|
3378
3566
|
${c}, ${l}, ${t.migration.description})
|
|
3379
|
-
`.pipe(
|
|
3380
|
-
}),
|
|
3381
|
-
let n = yield*
|
|
3382
|
-
try: () =>
|
|
3567
|
+
`.pipe(T.mapError((e) => new Va(t.migration.id, t.file, e))), { durationMs: c };
|
|
3568
|
+
}), Ua = (e, t) => T.gen(function* () {
|
|
3569
|
+
let n = yield* T.tryPromise({
|
|
3570
|
+
try: () => Ra(se(t, "migrations")),
|
|
3383
3571
|
catch: (e) => e
|
|
3384
3572
|
});
|
|
3385
3573
|
if (n.length === 0) return {
|
|
3386
3574
|
pending: [],
|
|
3387
3575
|
skipped: []
|
|
3388
3576
|
};
|
|
3389
|
-
let r = yield*
|
|
3390
|
-
try: () =>
|
|
3577
|
+
let r = yield* T.tryPromise({
|
|
3578
|
+
try: () => za(n),
|
|
3391
3579
|
catch: (e) => e
|
|
3392
3580
|
});
|
|
3393
3581
|
if (r.length === 0) return {
|
|
3394
3582
|
pending: [],
|
|
3395
3583
|
skipped: []
|
|
3396
3584
|
};
|
|
3397
|
-
let i = new Set(yield*
|
|
3585
|
+
let i = new Set(yield* Ba(e));
|
|
3398
3586
|
return {
|
|
3399
3587
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3400
3588
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3401
3589
|
};
|
|
3402
|
-
}),
|
|
3403
|
-
let { pending: n, skipped: r } = yield*
|
|
3590
|
+
}), Wa = (e, t) => Ua(e, t).pipe(T.map((e) => e.pending.map((e) => e.migration.id))), Ga = (e, t) => T.gen(function* () {
|
|
3591
|
+
let { pending: n, skipped: r } = yield* Ua(e, t.projectRoot);
|
|
3404
3592
|
return n.length === 0 ? {
|
|
3405
3593
|
applied: [],
|
|
3406
3594
|
skipped: r
|
|
3407
3595
|
} : {
|
|
3408
|
-
applied: yield*
|
|
3596
|
+
applied: yield* T.acquireUseRelease(Ve(e, { schema: t.lockSchema }), () => T.gen(function* () {
|
|
3409
3597
|
let r = [];
|
|
3410
3598
|
for (let i of n) {
|
|
3411
|
-
yield*
|
|
3599
|
+
yield* T.logInfo("file-based migration applying").pipe(T.annotateLogs({
|
|
3412
3600
|
scope: "voltro:migrate",
|
|
3413
3601
|
id: i.migration.id,
|
|
3414
3602
|
file: i.file
|
|
3415
3603
|
}));
|
|
3416
|
-
let { durationMs: n } = yield*
|
|
3604
|
+
let { durationMs: n } = yield* Ha(e, i, t.env, t.appliedBy);
|
|
3417
3605
|
r.push({
|
|
3418
3606
|
id: i.migration.id,
|
|
3419
3607
|
durationMs: n
|
|
3420
|
-
}), yield*
|
|
3608
|
+
}), yield* T.logInfo("file-based migration applied").pipe(T.annotateLogs({
|
|
3421
3609
|
scope: "voltro:migrate",
|
|
3422
3610
|
id: i.migration.id,
|
|
3423
3611
|
durationMs: n
|
|
3424
3612
|
}));
|
|
3425
3613
|
}
|
|
3426
3614
|
return r;
|
|
3427
|
-
}), (e) => e.release.pipe(
|
|
3615
|
+
}), (e) => e.release.pipe(T.orDie)),
|
|
3428
3616
|
skipped: r
|
|
3429
3617
|
};
|
|
3430
|
-
}),
|
|
3618
|
+
}), Ka = (e, t) => e`
|
|
3431
3619
|
SELECT ${e("id")}
|
|
3432
3620
|
FROM ${e("_voltro_migration_plans")}
|
|
3433
3621
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3434
3622
|
LIMIT 1
|
|
3435
|
-
`,
|
|
3436
|
-
if (!(yield*
|
|
3437
|
-
let n = yield*
|
|
3438
|
-
try: () =>
|
|
3623
|
+
`, qa = (e, t) => T.gen(function* () {
|
|
3624
|
+
if (!(yield* Ka(e, t.id))[0]) return yield* T.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3625
|
+
let n = yield* T.tryPromise({
|
|
3626
|
+
try: () => Ra(se(t.projectRoot, "migrations")),
|
|
3439
3627
|
catch: (e) => e
|
|
3440
|
-
}), r = (yield*
|
|
3441
|
-
try: () =>
|
|
3628
|
+
}), r = (yield* T.tryPromise({
|
|
3629
|
+
try: () => za(n),
|
|
3442
3630
|
catch: (e) => e
|
|
3443
3631
|
})).find((e) => e.migration.id === t.id);
|
|
3444
|
-
return r ? yield*
|
|
3632
|
+
return r ? yield* T.acquireUseRelease(Ve(e, { schema: t.lockSchema }), () => T.gen(function* () {
|
|
3445
3633
|
let n = Date.now(), i = {
|
|
3446
3634
|
sql: e,
|
|
3447
3635
|
log: {
|
|
3448
|
-
info: (e, n) =>
|
|
3636
|
+
info: (e, n) => T.logInfo(e).pipe(T.annotateLogs({
|
|
3449
3637
|
scope: `migrations:file:${t.id}`,
|
|
3450
3638
|
...n ?? {}
|
|
3451
3639
|
})),
|
|
3452
|
-
warn: (e, n) =>
|
|
3640
|
+
warn: (e, n) => T.logWarning(e).pipe(T.annotateLogs({
|
|
3453
3641
|
scope: `migrations:file:${t.id}`,
|
|
3454
3642
|
...n ?? {}
|
|
3455
3643
|
}))
|
|
3456
3644
|
},
|
|
3457
3645
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3458
3646
|
}, a = r.migration.down(i);
|
|
3459
|
-
|
|
3647
|
+
T.isEffect(a) ? yield* a : yield* T.tryPromise({
|
|
3460
3648
|
try: () => a,
|
|
3461
3649
|
catch: (e) => e
|
|
3462
3650
|
});
|
|
@@ -3465,8 +3653,8 @@ BEGIN
|
|
|
3465
3653
|
id: t.id,
|
|
3466
3654
|
durationMs: o
|
|
3467
3655
|
};
|
|
3468
|
-
}), (e) => e.release.pipe(
|
|
3469
|
-
}),
|
|
3656
|
+
}), (e) => e.release.pipe(T.orDie)) : yield* T.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
3657
|
+
}), Ja = (e) => T.gen(function* () {
|
|
3470
3658
|
let t = yield* E.SqlClient, n = yield* t`
|
|
3471
3659
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3472
3660
|
WHERE source = 'auto-diff'
|
|
@@ -3474,9 +3662,9 @@ BEGIN
|
|
|
3474
3662
|
AND appliedAt < ${e.before}
|
|
3475
3663
|
ORDER BY appliedAt DESC
|
|
3476
3664
|
`;
|
|
3477
|
-
if (n.length === 0) return yield*
|
|
3665
|
+
if (n.length === 0) return yield* T.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3478
3666
|
let r = n[0];
|
|
3479
|
-
if (r.fingerprint !== e.fingerprint) return yield*
|
|
3667
|
+
if (r.fingerprint !== e.fingerprint) return yield* T.fail(/* @__PURE__ */ Error(`squash: latest pre-squash fingerprint (${r.fingerprint.slice(0, 12)}…) differs from current declared-schema fingerprint (${e.fingerprint.slice(0, 12)}…). This means the working tree carries un-applied changes — squashing now would lock the drift in.\n\nFix: run \`voltro db apply\` first to align the live schema with the working tree, then re-squash.`));
|
|
3480
3668
|
yield* t`
|
|
3481
3669
|
UPDATE _voltro_migration_plans
|
|
3482
3670
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3511,7 +3699,7 @@ BEGIN
|
|
|
3511
3699
|
snapshotFingerprint: e.fingerprint,
|
|
3512
3700
|
snapshotId: i
|
|
3513
3701
|
};
|
|
3514
|
-
}),
|
|
3702
|
+
}), Ya = { safe: !0 }, Xa = (e) => {
|
|
3515
3703
|
switch (e.kind) {
|
|
3516
3704
|
case "drop-column": return {
|
|
3517
3705
|
safe: !1,
|
|
@@ -3538,7 +3726,7 @@ BEGIN
|
|
|
3538
3726
|
reason: `old instances read/write "${e.table}"."${e.column}" as ${e.from}; the new ${e.to} type can reject their writes or fail to decode their reads`,
|
|
3539
3727
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
3540
3728
|
};
|
|
3541
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3729
|
+
case "alter-column-nullability": return e.toNullable ? Ya : {
|
|
3542
3730
|
safe: !1,
|
|
3543
3731
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3544
3732
|
remedy: `make code always write "${e.column}" and deploy that first; add NOT NULL in a LATER deploy (with a default to cover the gap)`
|
|
@@ -3549,6 +3737,11 @@ BEGIN
|
|
|
3549
3737
|
reason: `old instances still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
|
|
3550
3738
|
remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
|
|
3551
3739
|
};
|
|
3740
|
+
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ? Ya : {
|
|
3741
|
+
safe: !1,
|
|
3742
|
+
reason: `writes to "${e.table}"."${e.column}" must satisfy the new JSON validation`,
|
|
3743
|
+
remedy: "ensure all writers supply valid JSON in the required domain before enabling this check"
|
|
3744
|
+
};
|
|
3552
3745
|
case "add-check": return {
|
|
3553
3746
|
safe: !1,
|
|
3554
3747
|
reason: `old instances may write values to "${e.table}" the new CHECK rejects`,
|
|
@@ -3568,12 +3761,12 @@ BEGIN
|
|
|
3568
3761
|
case "drop-unique":
|
|
3569
3762
|
case "drop-unique-composite":
|
|
3570
3763
|
case "drop-foreign-key":
|
|
3571
|
-
case "drop-check": return
|
|
3764
|
+
case "drop-check": return Ya;
|
|
3572
3765
|
}
|
|
3573
|
-
},
|
|
3766
|
+
}, Za = (e) => {
|
|
3574
3767
|
let t = [];
|
|
3575
3768
|
for (let n of e) {
|
|
3576
|
-
let e =
|
|
3769
|
+
let e = Xa(n.op);
|
|
3577
3770
|
e.safe || t.push({
|
|
3578
3771
|
op: n,
|
|
3579
3772
|
reason: e.reason,
|
|
@@ -3581,7 +3774,7 @@ BEGIN
|
|
|
3581
3774
|
});
|
|
3582
3775
|
}
|
|
3583
3776
|
return t;
|
|
3584
|
-
},
|
|
3777
|
+
}, Qa = (e) => {
|
|
3585
3778
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3586
3779
|
refuse: !1,
|
|
3587
3780
|
warnForced: !1,
|
|
@@ -3597,18 +3790,18 @@ BEGIN
|
|
|
3597
3790
|
warnForced: !1,
|
|
3598
3791
|
message: `${t}. Old instances would break against the new schema mid-rollout. Split into expand → deploy → contract (see the ⚠ list above), deploy with no overlap (maintenance window / scale-to-zero), or pass --force to override.`
|
|
3599
3792
|
};
|
|
3600
|
-
},
|
|
3793
|
+
}, $a = (e) => {
|
|
3601
3794
|
let t = e.table;
|
|
3602
3795
|
if (typeof t == "string") return t;
|
|
3603
3796
|
let n = e.from;
|
|
3604
3797
|
return typeof n == "string" ? n : void 0;
|
|
3605
|
-
},
|
|
3798
|
+
}, eo = (e) => ({
|
|
3606
3799
|
kind: e.op.kind,
|
|
3607
|
-
table:
|
|
3800
|
+
table: $a(e.op),
|
|
3608
3801
|
classification: e.classification,
|
|
3609
3802
|
reason: e.reason,
|
|
3610
3803
|
blockedFix: e.blocked?.fix
|
|
3611
|
-
}),
|
|
3804
|
+
}), to = (e) => e.operations.map(eo), no = async (e) => {
|
|
3612
3805
|
let t = e.log ?? (() => {}), n = {
|
|
3613
3806
|
branchId: e.branchId,
|
|
3614
3807
|
mechanism: e.mechanism,
|
|
@@ -3627,10 +3820,10 @@ BEGIN
|
|
|
3627
3820
|
applied: !1,
|
|
3628
3821
|
converged: !1,
|
|
3629
3822
|
residual: r,
|
|
3630
|
-
infidelity:
|
|
3823
|
+
infidelity: to(o)
|
|
3631
3824
|
};
|
|
3632
3825
|
else {
|
|
3633
|
-
let i = await e.plan(), o =
|
|
3826
|
+
let i = await e.plan(), o = to(i), s = o.filter((e) => e.classification === "lossy"), c = ja(i), l = c.operations.filter((e) => e.blocked !== void 0).map(eo);
|
|
3634
3827
|
if (l.length > 0) a = {
|
|
3635
3828
|
...n,
|
|
3636
3829
|
outcome: "blocked",
|
|
@@ -3655,7 +3848,7 @@ BEGIN
|
|
|
3655
3848
|
};
|
|
3656
3849
|
else {
|
|
3657
3850
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3658
|
-
let i =
|
|
3851
|
+
let i = to(await e.replan());
|
|
3659
3852
|
a = {
|
|
3660
3853
|
...n,
|
|
3661
3854
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3693,7 +3886,7 @@ BEGIN
|
|
|
3693
3886
|
...a,
|
|
3694
3887
|
tornDown: o
|
|
3695
3888
|
};
|
|
3696
|
-
},
|
|
3889
|
+
}, ro = (e) => {
|
|
3697
3890
|
switch (e.outcome) {
|
|
3698
3891
|
case "clean": return 0;
|
|
3699
3892
|
case "lossy": return 2;
|
|
@@ -3702,22 +3895,22 @@ BEGIN
|
|
|
3702
3895
|
case "infidelity": return 1;
|
|
3703
3896
|
case "failed": return 1;
|
|
3704
3897
|
}
|
|
3705
|
-
},
|
|
3898
|
+
}, io = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, ao = (e) => {
|
|
3706
3899
|
let t = [];
|
|
3707
3900
|
if (t.push(`branch rehearsal · ${e.branchId} · mechanism ${e.mechanism}`), t.push(` branched ${e.branchedTables} table(s), replayed ${e.replayedForeignKeys} foreign key(s)`), e.outcome === "failed") t.push(` FAILED: ${e.error ?? "unknown error"}`);
|
|
3708
3901
|
else if (e.outcome === "infidelity") {
|
|
3709
3902
|
t.push(" BRANCH IS NOT A FAITHFUL COPY of the parent — the rehearsal proves nothing about your migration."), t.push(" The parent's own schema still differs from the branch by:");
|
|
3710
|
-
for (let n of e.infidelity) t.push(
|
|
3903
|
+
for (let n of e.infidelity) t.push(io(n));
|
|
3711
3904
|
} else {
|
|
3712
3905
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3713
|
-
for (let n of e.operations) t.push(
|
|
3714
|
-
if (e.lossy.length > 0 && (t.push(""), t.push(` ⚠ ${e.lossy.length} operation(s) DESTROY DATA. They were executed on the branch (it is`), t.push(" disposable) so they are rehearsed, but production refuses them until you set"), t.push(" VOLTRO_DESTRUCTIVE_OK — naming the tables, not `1`.")), e.blocked.length > 0 && (t.push(""), t.push(` ${e.blocked.length} operation(s) the planner will not auto-apply anywhere — the plan was NOT executed.`)), e.applied && (t.push(""), t.push(e.converged ? " ✓ applied on the branch, and the re-plan is EMPTY (the migration converges)." : ` ✗ applied, but the re-plan STILL proposes ${e.residual.length} operation(s) — this migration does not converge:`), !e.converged)) for (let n of e.residual) t.push(
|
|
3906
|
+
for (let n of e.operations) t.push(io(n));
|
|
3907
|
+
if (e.lossy.length > 0 && (t.push(""), t.push(` ⚠ ${e.lossy.length} operation(s) DESTROY DATA. They were executed on the branch (it is`), t.push(" disposable) so they are rehearsed, but production refuses them until you set"), t.push(" VOLTRO_DESTRUCTIVE_OK — naming the tables, not `1`.")), e.blocked.length > 0 && (t.push(""), t.push(` ${e.blocked.length} operation(s) the planner will not auto-apply anywhere — the plan was NOT executed.`)), e.applied && (t.push(""), t.push(e.converged ? " ✓ applied on the branch, and the re-plan is EMPTY (the migration converges)." : ` ✗ applied, but the re-plan STILL proposes ${e.residual.length} operation(s) — this migration does not converge:`), !e.converged)) for (let n of e.residual) t.push(io(n));
|
|
3715
3908
|
}
|
|
3716
3909
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3717
|
-
},
|
|
3910
|
+
}, oo = (e, ...t) => ({
|
|
3718
3911
|
_tag: "RawSqlFragment",
|
|
3719
3912
|
strings: [...e],
|
|
3720
3913
|
values: [...t]
|
|
3721
|
-
}),
|
|
3914
|
+
}), so = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3722
3915
|
//#endregion
|
|
3723
|
-
export { A as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN,
|
|
3916
|
+
export { A as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN, Va as FileMigrationLedgerError, st as REACTIVE_TRIGGER_PREFIX, xe as VOLTRO_MIGRATION_LOCK_KEY, Ve as acquireMigrationLock, W as appliedAtValue, Zt as applyNamespacedSchema, ya as applyPlan, Vt as applySchema, Qa as assessRollingDeployGate, ro as branchRehearsalExitCode, dr as chunkTables, Xa as classifyRollingDeploySafety, z as declaredSnapshot, mt as defaultArrayClause, pt as defaultClause, N as defaultJsonClause, Fa as describeOutcome, ka as destructiveScope, Cn as detectReactiveTriggerDrift, Ni as emitAddIndexMysql, wi as emitCreateTableMssql, pi as emitCreateTableMysql, ci as emitCreateTablePg, yi as emitCreateTableSqlite, Kr as emitDropColumnDdl, qr as emitDropColumnDdlMysql, Bt as emitFrameworkBootstrapSql, Rt as emitNamespaceProvisionDdl, zt as emitNamespacedSchemaSql, Lt as emitSchemaSql, Er as engineFromVersion, R as fingerprintSchema, De as fnv1a64, ao as formatBranchRehearsal, wn as formatReactiveTriggerDrift, Oa as ignoreTablesFromEnv, Tr as introspectSchema, Mr as isAlreadySatisfied, u as isFileMigration, so as isRawSqlFragment, Ut as isReRunSafeDdl, ar as mapPgType, d as migration, Oe as migrationLockKeyForSchema, ke as migrationLockNameForSchema, Oi as mysqlIndexPrefixFor, lt as notifyFunctionName, P as numericIdSql, ir as parseEnumCheck, Wa as pendingFileMigrationIds, nr as planMigrations, Qt as provisionTenantNamespace, ct as reactiveTriggerName, Ot as reactiveTriggerRepairSql, Ca as recordUpToDate, no as rehearseMigrationOnBranch, eo as rehearsedOperation, di as renderColumnMysql, ai as renderColumnPg, Ce as resolveMigrationLockSchema, Or as resolveMysqlEngine, qa as rollbackFileBasedMigration, Za as rollingDeployUnsafeOps, Ga as runFileBasedMigrations, $t as runFrameworkBootstrap, Xt as runMigrate, Pa as runPlannedMigrations, _n as shortFingerprint, vn as snapshotColumn, oo as sql, M as sqlType, Ja as squashMigrationPlans, ja as unblockLossy, He as withMigrationLock };
|