@voltro/database 0.68.0 → 0.69.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 +310 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +38 -31
- package/dist/sql.d.ts +46 -9
- package/dist/sql.js +872 -838
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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
|
|
2
|
-
import { Effect as
|
|
3
|
-
import { createHash as
|
|
4
|
-
import { createLogger as
|
|
5
|
-
import { SqlClient as
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL 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-CWbTSnjk.js";
|
|
2
|
+
import { Effect as w, Exit as T, Schedule as ee, Scope as te } from "effect";
|
|
3
|
+
import { createHash as ne } from "node:crypto";
|
|
4
|
+
import { createLogger as re } from "@voltro/logger";
|
|
5
|
+
import { SqlClient as E } from "@effect/sql";
|
|
6
|
+
import { promises as ie } from "node:fs";
|
|
7
|
+
import { join as ae } from "node:path";
|
|
8
|
+
import { pathToFileURL as oe } from "node:url";
|
|
9
9
|
//#region src/migrations/ddlError.ts
|
|
10
|
-
var
|
|
10
|
+
var se = (e, t, n, r = 400) => {
|
|
11
11
|
let i = n, a = i.cause ?? {}, o = (e) => {
|
|
12
12
|
let t = a[e];
|
|
13
13
|
return t == null || t === "" ? void 0 : String(t);
|
|
@@ -38,21 +38,21 @@ var oe = (e, t, n, r = 400) => {
|
|
|
38
38
|
let t = o(e);
|
|
39
39
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
40
40
|
}
|
|
41
|
-
let c =
|
|
41
|
+
let c = ce(o("code"));
|
|
42
42
|
return c !== void 0 && s.push("", c), s.push(""), s.join("\n");
|
|
43
|
-
},
|
|
44
|
-
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(
|
|
43
|
+
}, ce = (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, le = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, ue = (e) => e.replace(/"/g, "`"), de = (e) => typeof e == "string" ? e : e.name ?? String(e), fe = (e, t) => `_ua_${t}_${e}`.slice(0, 64), pe = (e, t) => {
|
|
44
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(le)) return e;
|
|
45
45
|
let n = { ...e.fields }, r = [], i = [];
|
|
46
46
|
for (let t of e.appliedIndexes) {
|
|
47
|
-
if (!
|
|
47
|
+
if (!le(t)) {
|
|
48
48
|
r.push(t);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
|
-
let a =
|
|
51
|
+
let a = ue(t.where), o = [];
|
|
52
52
|
for (let r of t.fields) {
|
|
53
|
-
let i =
|
|
53
|
+
let i = de(r);
|
|
54
54
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
55
|
-
let s =
|
|
55
|
+
let s = fe(t.name, i);
|
|
56
56
|
o.push(s), n[s] = {
|
|
57
57
|
type: "text",
|
|
58
58
|
nullable: !0,
|
|
@@ -75,86 +75,82 @@ var oe = (e, t, n, r = 400) => {
|
|
|
75
75
|
appliedIndexes: r,
|
|
76
76
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
77
77
|
};
|
|
78
|
-
},
|
|
78
|
+
}, D = (e, t) => `${e}::${t}`, me = (e, t) => {
|
|
79
79
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
80
80
|
n.add(e);
|
|
81
81
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
82
|
-
for (let t of o) n.has(t.target) ? i.add(
|
|
82
|
+
for (let t of o) n.has(t.target) ? i.add(D(e, t.column)) : r.has(t.target) || a(t.target);
|
|
83
83
|
n.delete(e), r.add(e);
|
|
84
84
|
};
|
|
85
85
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
86
86
|
return i;
|
|
87
|
-
},
|
|
87
|
+
}, O = (e, t) => e.executeUnprepared(t, [], void 0), he = 6322741009312437n, ge = (e) => {
|
|
88
88
|
let t = e?.trim();
|
|
89
89
|
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 *
|
|
90
|
+
}, _e = (e) => e?.schema === void 0 ? ge(process.env.DB_SCHEMA) : ge(e.schema), ve = 14695981039346656037n, ye = 1099511628211n, be = 18446744073709551615n, xe = (e) => {
|
|
91
|
+
let t = ve;
|
|
92
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * ye & be;
|
|
93
93
|
return t;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
return t === void 0 ?
|
|
97
|
-
},
|
|
98
|
-
let t = `voltro_migration_${
|
|
94
|
+
}, Se = (e) => {
|
|
95
|
+
let t = ge(e);
|
|
96
|
+
return t === void 0 ? he : xe(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
97
|
+
}, Ce = (e) => {
|
|
98
|
+
let t = `voltro_migration_${he.toString(36)}`, n = ge(e);
|
|
99
99
|
if (n === void 0) return t;
|
|
100
100
|
let r = `${t}_${n}`;
|
|
101
|
-
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(
|
|
102
|
-
},
|
|
101
|
+
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(xe(`voltro_migration_lock:${n}`) & be).toString(16)}`;
|
|
102
|
+
}, we = 250, Te = () => {
|
|
103
103
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
104
104
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
105
|
-
},
|
|
106
|
-
let n =
|
|
105
|
+
}, Ee = (e, t) => w.gen(function* () {
|
|
106
|
+
let n = Te(), r = Date.now();
|
|
107
107
|
for (;;) {
|
|
108
|
-
if ((yield* e`
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(yield* e`
|
|
116
|
-
SELECT GET_LOCK(${t}, ${Ee}) AS got`)[0]?.got !== 1 && (yield* C.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${Ee}s (another migration is in progress, or a prior one left it held).`)));
|
|
117
|
-
}), Oe = (e, t) => C.gen(function* () {
|
|
118
|
-
yield* e`SELECT RELEASE_LOCK(${t})`;
|
|
119
|
-
}), ke = 3e4, Ae = (e, t) => C.gen(function* () {
|
|
120
|
-
let n = yield* e`
|
|
108
|
+
if ((yield* O(e, `SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`))[0]?.got) return;
|
|
109
|
+
Date.now() - r >= n && (yield* w.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* w.sleep(`${we} millis`);
|
|
110
|
+
}
|
|
111
|
+
}), De = (e, t) => w.asVoid(O(e, `SELECT pg_advisory_unlock(${t.toString()}::bigint)`)), Oe = 30, ke = (e, t) => w.gen(function* () {
|
|
112
|
+
(yield* O(e, `SELECT GET_LOCK('${t}', ${String(Oe)}) AS got`))[0]?.got !== 1 && (yield* w.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${Oe}s (another migration is in progress, or a prior one left it held).`)));
|
|
113
|
+
}), Ae = (e, t) => w.asVoid(O(e, `SELECT RELEASE_LOCK('${t}')`)), je = 3e4, Me = (e, t) => w.gen(function* () {
|
|
114
|
+
let n = yield* O(e, `
|
|
121
115
|
DECLARE @res int;
|
|
122
|
-
EXEC @res = sp_getapplock @Resource = ${t}, @LockMode = 'Exclusive',
|
|
123
|
-
@LockOwner = 'Session', @LockTimeout = ${
|
|
124
|
-
SELECT @res AS res
|
|
125
|
-
(n[0]?.res ?? -999) < 0 && (yield*
|
|
126
|
-
}),
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
116
|
+
EXEC @res = sp_getapplock @Resource = '${t}', @LockMode = 'Exclusive',
|
|
117
|
+
@LockOwner = 'Session', @LockTimeout = ${String(je)};
|
|
118
|
+
SELECT @res AS res`);
|
|
119
|
+
(n[0]?.res ?? -999) < 0 && (yield* w.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
120
|
+
}), Ne = (e, t) => w.asVoid(O(e, `EXEC sp_releaseapplock @Resource = '${t}', @LockOwner = 'Session'`)), Pe = w.void, Fe = (e, t) => w.gen(function* () {
|
|
121
|
+
let n = _e(t), r = Ce(n), i = Se(n);
|
|
122
|
+
if (!e.onDialectOrElse({
|
|
123
|
+
mysql: () => !0,
|
|
124
|
+
mssql: () => !0,
|
|
125
|
+
sqlite: () => !1,
|
|
126
|
+
orElse: () => !0
|
|
127
|
+
})) return { release: Pe };
|
|
128
|
+
let a = yield* te.make(), o = yield* w.provideService(e.reserve, te.Scope, a), s = te.close(a, T.void);
|
|
129
|
+
return yield* e.onDialectOrElse({
|
|
130
|
+
mysql: () => ke(o, r),
|
|
131
|
+
mssql: () => Me(o, r),
|
|
132
|
+
sqlite: () => Pe,
|
|
133
|
+
orElse: () => Ee(o, i)
|
|
134
|
+
}).pipe(w.onExit((e) => T.isSuccess(e) ? w.void : s)), { release: e.onDialectOrElse({
|
|
135
|
+
mysql: () => Ae(o, r),
|
|
136
|
+
mssql: () => Ne(o, r),
|
|
137
|
+
sqlite: () => Pe,
|
|
138
|
+
orElse: () => De(o, i)
|
|
139
|
+
}).pipe(w.ensuring(s)) };
|
|
140
|
+
}), Ie = (e, t, n) => w.acquireUseRelease(Fe(e, n), () => t, (e) => e.release.pipe(w.orDie)), Le = (e) => e.onDialectOrElse({
|
|
145
141
|
pg: () => "postgres",
|
|
146
142
|
mysql: () => "mysql",
|
|
147
143
|
mssql: () => "mssql",
|
|
148
144
|
sqlite: () => "sqlite",
|
|
149
145
|
orElse: () => "sqlite"
|
|
150
|
-
}),
|
|
146
|
+
}), Re = {
|
|
151
147
|
postgres: "plan-transactional",
|
|
152
148
|
mssql: "plan-transactional",
|
|
153
149
|
mysql: "per-operation",
|
|
154
150
|
mariadb: "per-operation",
|
|
155
151
|
sqlite: "per-operation",
|
|
156
152
|
turso: "per-operation"
|
|
157
|
-
},
|
|
153
|
+
}, ze = (e) => Re[e], k = "_voltro_migration_ops", Be = l(k, {
|
|
158
154
|
id: y({ prefix: "mop" }),
|
|
159
155
|
runId: a(),
|
|
160
156
|
planFingerprint: a(),
|
|
@@ -167,7 +163,7 @@ var oe = (e, t, n, r = 400) => {
|
|
|
167
163
|
appliedAt: v().nullable(),
|
|
168
164
|
durationMs: t().nullable(),
|
|
169
165
|
createdAt: v().default("now")
|
|
170
|
-
}),
|
|
166
|
+
}), Ve = (e) => {
|
|
171
167
|
switch (e.kind) {
|
|
172
168
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
173
169
|
`table:${e.table}`,
|
|
@@ -194,11 +190,11 @@ var oe = (e, t, n, r = 400) => {
|
|
|
194
190
|
case "add-unique-composite":
|
|
195
191
|
case "drop-unique-composite": return /* @__PURE__ */ new Set([`unique:${e.table}.${e.name}`]);
|
|
196
192
|
}
|
|
197
|
-
},
|
|
198
|
-
let n =
|
|
199
|
-
for (let t of
|
|
193
|
+
}, He = (e) => [...Ve(e)].join(" "), Ue = (e, t) => {
|
|
194
|
+
let n = Ve(t);
|
|
195
|
+
for (let t of Ve(e)) if (n.has(t)) return !0;
|
|
200
196
|
return !1;
|
|
201
|
-
},
|
|
197
|
+
}, We = (e, t) => e.operations.some((e) => Ue(e.op, t)), Ge = "__voltro_rebuild", Ke = "__shadow", qe = "__old", Je = /* @__PURE__ */ new Set([
|
|
202
198
|
"add-unique",
|
|
203
199
|
"drop-unique",
|
|
204
200
|
"add-unique-composite",
|
|
@@ -210,20 +206,20 @@ var oe = (e, t, n, r = 400) => {
|
|
|
210
206
|
"alter-column-nullability",
|
|
211
207
|
"alter-column-type",
|
|
212
208
|
"alter-column-default"
|
|
213
|
-
]),
|
|
209
|
+
]), Ye = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Xe = (e, t, n) => {
|
|
214
210
|
let r = n === "sqlite" || n === "turso";
|
|
215
|
-
return e.kind === "alter-column-type" && t === "online-required" || r &&
|
|
211
|
+
return e.kind === "alter-column-type" && t === "online-required" || r && Je.has(e.kind) ? "artefact-repair" : Ye.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
216
212
|
};
|
|
217
|
-
Object.keys(
|
|
213
|
+
Object.keys(Re);
|
|
218
214
|
//#endregion
|
|
219
215
|
//#region src/migrations/reactiveTriggerName.ts
|
|
220
|
-
var A = "framework_changes",
|
|
216
|
+
var A = "framework_changes", Ze = "framework_changes_", Qe = (e, t) => t === "framework_changes" ? `${Ze}${e}` : `${Ze}${t}_${e}`, $e = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, et = "voltro:notify:v2", tt = (e, t) => {
|
|
221
217
|
if (e.type === "text" && e.generatedAs === void 0) {
|
|
222
218
|
if (e.maxLength !== void 0) return e.maxLength;
|
|
223
219
|
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
224
220
|
}
|
|
225
|
-
},
|
|
226
|
-
|
|
221
|
+
}, nt = re({ scope: "voltro:migrate" }), j = (e) => {
|
|
222
|
+
nt.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
227
223
|
}, M = (e, t) => {
|
|
228
224
|
let n = e.type;
|
|
229
225
|
if (e.spatial) {
|
|
@@ -306,7 +302,7 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
306
302
|
if (t === "mssql") switch (n) {
|
|
307
303
|
case "id": return "NVARCHAR(64)";
|
|
308
304
|
case "text": {
|
|
309
|
-
let t =
|
|
305
|
+
let t = tt(e, !1);
|
|
310
306
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
311
307
|
}
|
|
312
308
|
case "integer": return "INT";
|
|
@@ -338,11 +334,11 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
338
334
|
case "array": return "TEXT[]";
|
|
339
335
|
case "interval": return "INTERVAL";
|
|
340
336
|
}
|
|
341
|
-
},
|
|
337
|
+
}, rt = (e, t) => {
|
|
342
338
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
343
339
|
let n = e.defaultValue;
|
|
344
|
-
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) ?
|
|
345
|
-
},
|
|
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) ? it(n, e, t) : typeof n == "object" && n ? N(n, t) : null;
|
|
341
|
+
}, it = (e, t, n) => {
|
|
346
342
|
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return N(e, n);
|
|
347
343
|
let r = M({
|
|
348
344
|
...t,
|
|
@@ -370,18 +366,18 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
370
366
|
case "setNull": return "SET NULL";
|
|
371
367
|
case "noAction": return "NO ACTION";
|
|
372
368
|
}
|
|
373
|
-
},
|
|
369
|
+
}, at = (e, t, n) => n === null ? o(e, t) : `${o(n, t)}.${o(e, t)}`, ot = 191, st = (e, t) => {
|
|
374
370
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
375
371
|
let n = M(e, t).toUpperCase();
|
|
376
372
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
377
|
-
},
|
|
373
|
+
}, ct = (e, t, n) => {
|
|
378
374
|
let r = o(e, n);
|
|
379
375
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
380
376
|
let i = t[e];
|
|
381
377
|
if (!i) return r;
|
|
382
378
|
let a = M(i, n).toUpperCase();
|
|
383
|
-
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${
|
|
384
|
-
},
|
|
379
|
+
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${ot})` : r;
|
|
380
|
+
}, lt = (e, t) => {
|
|
385
381
|
if (!e.generatedAs) return null;
|
|
386
382
|
let { expr: n, stored: r } = e.generatedAs;
|
|
387
383
|
if (t === "postgres") return r || j("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
@@ -389,15 +385,15 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
389
385
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
390
386
|
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.");
|
|
391
387
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
392
|
-
},
|
|
388
|
+
}, ut = (e, t, n, r, i = !1, a = !1) => {
|
|
393
389
|
if (t.type === "id" && t.idScheme?.kind === "numeric") return P(e, n);
|
|
394
|
-
let s = n === "mssql" ?
|
|
390
|
+
let s = n === "mssql" ? tt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? M(t, n) : `NVARCHAR(${s})`, l = [o(e, n), c];
|
|
395
391
|
t.type === "id" && !a && l.push("PRIMARY KEY");
|
|
396
|
-
let u =
|
|
392
|
+
let u = lt(t, n);
|
|
397
393
|
if (u) l.push(u);
|
|
398
394
|
else {
|
|
399
|
-
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !
|
|
400
|
-
let e =
|
|
395
|
+
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !st(t, n) && l.push("UNIQUE");
|
|
396
|
+
let e = rt(t, n);
|
|
401
397
|
e && l.push(e);
|
|
402
398
|
}
|
|
403
399
|
if (t.type === "reference" && t.references && !i && !b(n)) {
|
|
@@ -422,26 +418,26 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
422
418
|
m(n) ? l.push(`CHECK (${t} IS NULL OR json_valid(${t}))`) : n === "mssql" && l.push(`CHECK (${t} IS NULL OR ISJSON(${t}) = 1)`);
|
|
423
419
|
}
|
|
424
420
|
return l.join(" ");
|
|
425
|
-
},
|
|
421
|
+
}, dt = (e, t, n = null, r) => {
|
|
426
422
|
let i = /* @__PURE__ */ new Set();
|
|
427
423
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
428
424
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
429
425
|
for (let [t, n] of Object.entries(e.fields)) n.unique && i.add(t);
|
|
430
426
|
let a = e.appliedPrimaryKey ?? [];
|
|
431
427
|
for (let e of a) i.add(e);
|
|
432
|
-
let s = a.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${
|
|
433
|
-
let r = n.fields.map((n) =>
|
|
428
|
+
let s = a.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${ut(e, n, t, i, r?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((n) => {
|
|
429
|
+
let r = n.fields.map((n) => ct(n, e.fields, t)).join(", ");
|
|
434
430
|
return ` CONSTRAINT ${o(n.name, t)} UNIQUE (${r})`;
|
|
435
|
-
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${o(e.name, t)} CHECK (${e.expr})`), d = s ? [` PRIMARY KEY (${a.map((n) =>
|
|
431
|
+
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${o(e.name, t)} CHECK (${e.expr})`), d = s ? [` PRIMARY KEY (${a.map((n) => ct(n, e.fields, t)).join(", ")})`] : [], f = b(t) ? Object.entries(e.fields).flatMap(([i, a]) => {
|
|
436
432
|
if (a.type !== "reference" || !a.references || (r?.has(i) ?? !1)) return [];
|
|
437
433
|
let s = a.references(), c = F(a.onDelete ?? "restrict", t), l = F(a.refOnUpdate ?? "noAction", t);
|
|
438
|
-
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${
|
|
434
|
+
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${at(s.tableName, t, n)} (${o(a.referenceColumn ?? "id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
439
435
|
}) : [], p = [
|
|
440
436
|
...d,
|
|
441
437
|
...l,
|
|
442
438
|
...u,
|
|
443
439
|
...f
|
|
444
|
-
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h =
|
|
440
|
+
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h = at(e.tableName, t, n);
|
|
445
441
|
if (t === "mssql") {
|
|
446
442
|
let t = n === null ? e.tableName : `${n}.${e.tableName}`, r = `CREATE TABLE ${h} (\n${m}\n)`;
|
|
447
443
|
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${r.replace(/'/g, "''")}');`;
|
|
@@ -451,10 +447,10 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
451
447
|
m,
|
|
452
448
|
");"
|
|
453
449
|
].join("\n");
|
|
454
|
-
},
|
|
450
|
+
}, ft = (e, t, n) => {
|
|
455
451
|
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 = [];
|
|
456
452
|
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;
|
|
457
|
-
},
|
|
453
|
+
}, pt = (e, t, n = null) => {
|
|
458
454
|
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"), s = (e, n, r, i) => {
|
|
459
455
|
let a = {
|
|
460
456
|
using: "",
|
|
@@ -500,10 +496,10 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
500
496
|
return a;
|
|
501
497
|
}, c = (n, r) => {
|
|
502
498
|
let i = n.map((n) => {
|
|
503
|
-
if (typeof n == "string") return
|
|
499
|
+
if (typeof n == "string") return ct(n, e.fields, t);
|
|
504
500
|
if ("jsonPath" in n) {
|
|
505
501
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
506
|
-
return `(${
|
|
502
|
+
return `(${C(e, r, t, { numeric: i })})`;
|
|
507
503
|
}
|
|
508
504
|
return `(${n.expr})`;
|
|
509
505
|
});
|
|
@@ -511,11 +507,11 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
511
507
|
}, l = (e, r, i, a, l, u = "", d = !1) => {
|
|
512
508
|
let f = s(e, r, a, l);
|
|
513
509
|
if (f.skip) return "";
|
|
514
|
-
let p = c(i, f.opclass), m = `${f.withSuffix}${u}`, h =
|
|
510
|
+
let p = c(i, f.opclass), m = `${f.withSuffix}${u}`, h = at(r, t, n), g = d ? "UNIQUE " : "";
|
|
515
511
|
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${o(e, t)} ON ${h}${f.using} (${p})${m};` : t === "mysql" ? `CREATE ${g}INDEX ${o(e, t)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${o(e, t)} ON ${h}${f.using} (${p})${m};`;
|
|
516
512
|
};
|
|
517
513
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
518
|
-
if (!i.unique || i.type === "id" || !
|
|
514
|
+
if (!i.unique || i.type === "id" || !st(i, t)) continue;
|
|
519
515
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
520
516
|
a && r.push(a);
|
|
521
517
|
}
|
|
@@ -529,7 +525,7 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
529
525
|
let i = n.columns.map((e) => o(e, t)).join(", ");
|
|
530
526
|
r.push(`CREATE FULLTEXT INDEX ${o(n.name, t)} ON ${o(e.tableName, t)} (${i});`);
|
|
531
527
|
} 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.`);
|
|
532
|
-
else t === "sqlite" ? r.push(...
|
|
528
|
+
else t === "sqlite" ? r.push(...ft(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).`);
|
|
533
529
|
for (let n of e.appliedIndexes) {
|
|
534
530
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
535
531
|
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(...).`);
|
|
@@ -547,17 +543,17 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
547
543
|
r.push(l(o, e.tableName, [t])), i.add(a([t]));
|
|
548
544
|
}
|
|
549
545
|
return r.join("\n");
|
|
550
|
-
},
|
|
546
|
+
}, mt = (e, t, n = A) => {
|
|
551
547
|
if (t !== "postgres") return [];
|
|
552
548
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
553
|
-
return r.length === 0 ? [] : [
|
|
554
|
-
},
|
|
555
|
-
CREATE OR REPLACE FUNCTION ${
|
|
549
|
+
return r.length === 0 ? [] : [ht(n), ...r.map((e) => _t(e, n))];
|
|
550
|
+
}, ht = (e) => `
|
|
551
|
+
CREATE OR REPLACE FUNCTION ${$e(e)}() RETURNS trigger AS $$
|
|
556
552
|
DECLARE
|
|
557
553
|
payload TEXT;
|
|
558
554
|
pk JSONB;
|
|
559
555
|
BEGIN
|
|
560
|
-
-- ${
|
|
556
|
+
-- ${et}
|
|
561
557
|
payload := json_build_object(
|
|
562
558
|
'table', TG_TABLE_NAME,
|
|
563
559
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -611,22 +607,22 @@ BEGIN
|
|
|
611
607
|
RETURN COALESCE(NEW, OLD);
|
|
612
608
|
END;
|
|
613
609
|
$$ LANGUAGE plpgsql;
|
|
614
|
-
`.trim(),
|
|
615
|
-
let n =
|
|
610
|
+
`.trim(), gt = (e, t) => {
|
|
611
|
+
let n = Qe(e.tableName, t);
|
|
616
612
|
return [
|
|
617
613
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
618
614
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
619
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
615
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${$e(t)}()`
|
|
620
616
|
];
|
|
621
|
-
},
|
|
617
|
+
}, _t = (e, t) => gt(e, t).map((e) => `${e};`).join("\n"), vt = (e) => {
|
|
622
618
|
if (e.dialect !== "postgres") return [];
|
|
623
619
|
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));
|
|
624
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
625
|
-
for (let e of i) r.push(...
|
|
626
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
620
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(ht(t));
|
|
621
|
+
for (let e of i) r.push(...gt(n.get(e), t));
|
|
622
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${Qe(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
627
623
|
return r;
|
|
628
|
-
},
|
|
629
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
624
|
+
}, yt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), bt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), xt = (e) => {
|
|
625
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = me(e.map((e) => e.tableName), (e) => {
|
|
630
626
|
let n = t.get(e);
|
|
631
627
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
632
628
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -637,7 +633,7 @@ $$ LANGUAGE plpgsql;
|
|
|
637
633
|
}] : [];
|
|
638
634
|
}) : [];
|
|
639
635
|
}), r = [];
|
|
640
|
-
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type === "reference" && i.references && n.has(
|
|
636
|
+
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type === "reference" && i.references && n.has(D(t.tableName, e)) && r.push({
|
|
641
637
|
table: t.tableName,
|
|
642
638
|
column: e,
|
|
643
639
|
targetTable: i.references().tableName,
|
|
@@ -649,7 +645,7 @@ $$ LANGUAGE plpgsql;
|
|
|
649
645
|
if (!(i.has(e.tableName) || a.has(e.tableName))) {
|
|
650
646
|
a.add(e.tableName);
|
|
651
647
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
652
|
-
if (i.type !== "reference" || !i.references || n.has(
|
|
648
|
+
if (i.type !== "reference" || !i.references || n.has(D(e.tableName, r))) continue;
|
|
653
649
|
let a = i.references();
|
|
654
650
|
if (a.tableName === e.tableName) continue;
|
|
655
651
|
let o = t.get(a.tableName);
|
|
@@ -663,7 +659,7 @@ $$ LANGUAGE plpgsql;
|
|
|
663
659
|
sorted: o,
|
|
664
660
|
cyclic: r
|
|
665
661
|
};
|
|
666
|
-
},
|
|
662
|
+
}, St = (e, t, n = null) => {
|
|
667
663
|
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}`;
|
|
668
664
|
switch (t) {
|
|
669
665
|
case "postgres": return [
|
|
@@ -678,7 +674,7 @@ $$ LANGUAGE plpgsql;
|
|
|
678
674
|
case "mariadb": return `ALTER TABLE ${r(e.table)} ${l(!0)};`;
|
|
679
675
|
default: return `ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
680
676
|
}
|
|
681
|
-
},
|
|
677
|
+
}, Ct = (e, t) => {
|
|
682
678
|
let n = /* @__PURE__ */ new Map();
|
|
683
679
|
if (m(t)) return n;
|
|
684
680
|
for (let t of e) {
|
|
@@ -686,7 +682,7 @@ $$ LANGUAGE plpgsql;
|
|
|
686
682
|
e.add(t.column), n.set(t.table, e);
|
|
687
683
|
}
|
|
688
684
|
return n;
|
|
689
|
-
},
|
|
685
|
+
}, wt = (e, t) => {
|
|
690
686
|
if (t !== "postgres") return "";
|
|
691
687
|
let n = /* @__PURE__ */ new Map();
|
|
692
688
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -702,7 +698,7 @@ $$ LANGUAGE plpgsql;
|
|
|
702
698
|
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 $$;`);
|
|
703
699
|
}
|
|
704
700
|
return r.join("\n\n");
|
|
705
|
-
},
|
|
701
|
+
}, Tt = (e, t) => {
|
|
706
702
|
if (t !== "postgres") return "";
|
|
707
703
|
let r = /* @__PURE__ */ new Set();
|
|
708
704
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && r.add(e.enumName);
|
|
@@ -716,30 +712,30 @@ BEGIN
|
|
|
716
712
|
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 $$;`);
|
|
717
713
|
}
|
|
718
714
|
return i.join("\n\n");
|
|
719
|
-
},
|
|
715
|
+
}, Et = (e) => {
|
|
720
716
|
let t = [], n = [];
|
|
721
717
|
for (let r of e) s(r) ? n.push(r) : t.push(r);
|
|
722
718
|
return {
|
|
723
719
|
tables: t,
|
|
724
720
|
views: n
|
|
725
721
|
};
|
|
726
|
-
},
|
|
727
|
-
let { tables: i, views: a } =
|
|
728
|
-
n === "postgres" &&
|
|
729
|
-
let u =
|
|
722
|
+
}, Dt = (t, n, r = A) => {
|
|
723
|
+
let { tables: i, views: a } = Et(t), { sorted: o, cyclic: s } = xt(i.map((e) => pe(e, n))), c = Ct(s, n), l = [];
|
|
724
|
+
n === "postgres" && yt(o) && l.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && bt(o) && l.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
725
|
+
let u = Tt(o, n);
|
|
730
726
|
u && l.push(u);
|
|
731
|
-
let d =
|
|
727
|
+
let d = wt(o, n);
|
|
732
728
|
d && l.push(d);
|
|
733
|
-
for (let e of o) l.push(
|
|
734
|
-
if (!m(n)) for (let e of s) l.push(
|
|
729
|
+
for (let e of o) l.push(dt(e, n, null, c.get(e.tableName)));
|
|
730
|
+
if (!m(n)) for (let e of s) l.push(St(e, n));
|
|
735
731
|
for (let e of o) {
|
|
736
|
-
let t =
|
|
732
|
+
let t = pt(e, n);
|
|
737
733
|
t && l.push(t);
|
|
738
734
|
}
|
|
739
|
-
l.push(...
|
|
735
|
+
l.push(...mt(o, n, r));
|
|
740
736
|
for (let t of a) l.push(e(t, n));
|
|
741
737
|
return l.join("\n\n") + "\n";
|
|
742
|
-
},
|
|
738
|
+
}, Ot = (e, t, n) => {
|
|
743
739
|
let r = o(e, t);
|
|
744
740
|
switch (t) {
|
|
745
741
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${r};`;
|
|
@@ -749,62 +745,62 @@ BEGIN
|
|
|
749
745
|
case "turso":
|
|
750
746
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${r};`;
|
|
751
747
|
}
|
|
752
|
-
},
|
|
753
|
-
let i =
|
|
754
|
-
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${
|
|
755
|
-
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${
|
|
756
|
-
let { sorted: s, cyclic: c } =
|
|
757
|
-
for (let e of s) u.push(
|
|
758
|
-
if (!m(t)) for (let e of c) u.push(
|
|
748
|
+
}, kt = (e, t, n, r) => {
|
|
749
|
+
let i = Ot(n, t, r), a = o(n, t);
|
|
750
|
+
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${Dt(e, t)}`;
|
|
751
|
+
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${Dt(e, t)}`;
|
|
752
|
+
let { sorted: s, cyclic: c } = xt(e), l = Ct(c, t), u = [i];
|
|
753
|
+
for (let e of s) u.push(dt(e, t, n, l.get(e.tableName)));
|
|
754
|
+
if (!m(t)) for (let e of c) u.push(St(e, t, n));
|
|
759
755
|
for (let e of s) {
|
|
760
|
-
let r =
|
|
756
|
+
let r = pt(e, t, n);
|
|
761
757
|
r && u.push(r);
|
|
762
758
|
}
|
|
763
759
|
return u.join("\n\n") + "\n";
|
|
764
|
-
},
|
|
765
|
-
let { sorted: r, cyclic: i } =
|
|
760
|
+
}, At = (e, t, n = A) => {
|
|
761
|
+
let { sorted: r, cyclic: i } = xt(e), a = Ct(i, t), o = [], s = Tt(r, t);
|
|
766
762
|
s && o.push(s);
|
|
767
|
-
let c =
|
|
763
|
+
let c = wt(r, t);
|
|
768
764
|
c && o.push(c);
|
|
769
|
-
for (let e of r) o.push(
|
|
770
|
-
for (let e of i) o.push(
|
|
771
|
-
return o.push(...
|
|
772
|
-
},
|
|
773
|
-
let i = yield*
|
|
774
|
-
yield*
|
|
775
|
-
}),
|
|
765
|
+
for (let e of r) o.push(dt(e, t, null, a.get(e.tableName)));
|
|
766
|
+
for (let e of i) o.push(St(e, t));
|
|
767
|
+
return o.push(...mt(r, t, n)), o.join("\n\n") + "\n";
|
|
768
|
+
}, jt = (e, t = "postgres", n = A, r = {}) => w.gen(function* () {
|
|
769
|
+
let i = yield* E.SqlClient;
|
|
770
|
+
yield* Ie(i, Rt(i, Dt(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
771
|
+
}), Mt = (e, t) => {
|
|
776
772
|
let n = t.cause ?? {};
|
|
777
773
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
778
|
-
},
|
|
774
|
+
}, Nt = (e, t) => {
|
|
779
775
|
let n = e.trimStart();
|
|
780
776
|
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));
|
|
781
|
-
},
|
|
777
|
+
}, Pt = () => {
|
|
782
778
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
783
779
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
784
|
-
},
|
|
780
|
+
}, Ft = (e) => ({
|
|
785
781
|
while: e,
|
|
786
|
-
times:
|
|
787
|
-
schedule:
|
|
788
|
-
}),
|
|
782
|
+
times: Pt(),
|
|
783
|
+
schedule: ee.jittered(ee.exponential("50 millis"))
|
|
784
|
+
}), It = class {
|
|
789
785
|
statement;
|
|
790
786
|
error;
|
|
791
787
|
_tag = "DdlStatementFailed";
|
|
792
788
|
constructor(e, t) {
|
|
793
789
|
this.statement = e, this.error = t;
|
|
794
790
|
}
|
|
795
|
-
},
|
|
796
|
-
let r = yield*
|
|
797
|
-
for (let a of
|
|
798
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
799
|
-
let e = r.unsafe(a).pipe(
|
|
800
|
-
|
|
791
|
+
}, Lt = (e, t, n) => w.gen(function* () {
|
|
792
|
+
let r = yield* E.SqlClient, i = n !== void 0 && ze(t) === "per-operation";
|
|
793
|
+
for (let a of zt(e)) {
|
|
794
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && nt.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
795
|
+
let e = r.unsafe(a).pipe(w.catchIf((e) => Mt(a, e), () => w.succeed([])), w.tapError((e) => w.sync(() => {
|
|
796
|
+
nt.error(se("migrate: statement failed", a, e, 200));
|
|
801
797
|
})));
|
|
802
|
-
yield* (i && n !== void 0 &&
|
|
798
|
+
yield* (i && n !== void 0 && Nt(a, t) ? e.pipe(w.retry(Ft((e) => n(e) === "retry"))) : e).pipe(w.mapError((e) => new It(a, e)));
|
|
803
799
|
}
|
|
804
|
-
}),
|
|
805
|
-
let i = n === "turso" ?
|
|
806
|
-
return (r !== void 0 &&
|
|
807
|
-
},
|
|
800
|
+
}), Rt = (e, t, n, r) => {
|
|
801
|
+
let i = n === "turso" ? Lt(t, n, r) : e.withTransaction(Lt(t, n, r)), a = (e) => e instanceof It ? e.error : e;
|
|
802
|
+
return (r !== void 0 && ze(n) === "plan-transactional" ? i.pipe(w.retry(Ft((e) => r(a(e)) === "retry"))) : i).pipe(w.orDieWith((e) => e instanceof It ? Error(se("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
803
|
+
}, zt = (e) => {
|
|
808
804
|
let t = [], n = "", r = !1;
|
|
809
805
|
for (let i = 0; i < e.length; i++) {
|
|
810
806
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -819,30 +815,78 @@ BEGIN
|
|
|
819
815
|
}
|
|
820
816
|
let i = n.trim();
|
|
821
817
|
return i.length > 0 && t.push(i), t;
|
|
822
|
-
},
|
|
823
|
-
await
|
|
824
|
-
},
|
|
825
|
-
let i =
|
|
826
|
-
yield*
|
|
827
|
-
}),
|
|
828
|
-
await
|
|
818
|
+
}, Bt = async (e, t, n = "postgres", r = {}) => {
|
|
819
|
+
await w.runPromise(jt(e, n, void 0, r).pipe(w.provide(t)));
|
|
820
|
+
}, Vt = (e, t, n = "postgres", r = {}) => w.gen(function* () {
|
|
821
|
+
let i = kt(e, n, t), a = yield* E.SqlClient;
|
|
822
|
+
yield* Ie(a, Rt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
823
|
+
}), Ht = async (e, t, n, r = "postgres", i = {}) => {
|
|
824
|
+
await w.runPromise(Vt(e, t, r, i).pipe(w.provide(n))), await f({
|
|
829
825
|
namespace: t,
|
|
830
826
|
dialect: r
|
|
831
827
|
});
|
|
832
|
-
},
|
|
833
|
-
await
|
|
834
|
-
let t =
|
|
835
|
-
yield*
|
|
836
|
-
}).pipe(
|
|
837
|
-
},
|
|
838
|
-
|
|
839
|
-
|
|
828
|
+
}, Ut = async (e, t, n = "postgres", r = {}) => {
|
|
829
|
+
await w.runPromise(w.gen(function* () {
|
|
830
|
+
let t = At(e, n), i = yield* E.SqlClient;
|
|
831
|
+
yield* Ie(i, Rt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
832
|
+
}).pipe(w.provide(t)));
|
|
833
|
+
}, I = (e) => {
|
|
834
|
+
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
835
|
+
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
836
|
+
let t = e;
|
|
837
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
840
838
|
}, Wt = (e) => {
|
|
839
|
+
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
840
|
+
let t = e.defaultValue;
|
|
841
|
+
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
842
|
+
if (typeof t == "number") return String(t);
|
|
843
|
+
if (typeof t != "string") return I(t);
|
|
844
|
+
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
845
|
+
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
846
|
+
let i = n.replace(/::[a-zA-Z0-9_ "]+$/, "").trim(), a = /^'(.*)'$/.test(i) ? i.slice(1, -1).replace(/''/g, "'") : i, o = /^cast\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+as\s+json\s*\)$/i.exec(a);
|
|
847
|
+
if (o) try {
|
|
848
|
+
return I(JSON.parse(o[1]));
|
|
849
|
+
} catch {}
|
|
850
|
+
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
851
|
+
if (s) try {
|
|
852
|
+
return I(JSON.parse(s[1]));
|
|
853
|
+
} catch {}
|
|
854
|
+
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
855
|
+
return I(JSON.parse(a));
|
|
856
|
+
} catch {}
|
|
857
|
+
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
858
|
+
}, Gt = (e) => {
|
|
859
|
+
let t = Wt(e);
|
|
860
|
+
return t === "1" || t === "true" ? "__BOOL_TRUE__" : t === "0" || t === "false" ? "__BOOL_FALSE__" : t;
|
|
861
|
+
}, Kt = (e) => typeof e.defaultValue == "string" && /^nextval\(.+::regclass\)$/i.test(e.defaultValue.trim()), qt = (e) => {
|
|
862
|
+
if (!e) return null;
|
|
863
|
+
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
864
|
+
return {
|
|
865
|
+
table: e.table,
|
|
866
|
+
column: e.column,
|
|
867
|
+
onDelete: t(e.onDelete),
|
|
868
|
+
onUpdate: t(e.onUpdate)
|
|
869
|
+
};
|
|
870
|
+
}, Jt = (e, t, n) => {
|
|
871
|
+
if (t === "mssql") {
|
|
872
|
+
let t = tt(e, n);
|
|
873
|
+
if (t !== void 0) return t;
|
|
874
|
+
}
|
|
875
|
+
try {
|
|
876
|
+
let n = /^N?VARCHAR\((\d+)\)$/i.exec(M(e, t).trim());
|
|
877
|
+
return n ? Number(n[1]) : void 0;
|
|
878
|
+
} catch {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
}, Yt = /'(?:''|[^'])*'|"(?:""|[^"])*"|\[(?:\]\]|[^\]])*\]|`(?:``|[^`])*`|[A-Za-z_][A-Za-z_0-9$]*|\d+(?:\.\d+)?|::|<>|!=|<=|>=|\|\||[^\s]/g, Xt = (e) => {
|
|
882
|
+
let t = 0;
|
|
883
|
+
for (let n of e.matchAll(Yt)) if (n[0] === "(" && t++, n[0] === ")" && t--, t === 0 && n[0].toLowerCase() === "where") return e.slice(n.index + n[0].length).trim().replace(/;$/, "").trim();
|
|
884
|
+
}, Zt = (e) => {
|
|
841
885
|
if (e === void 0) return;
|
|
842
|
-
let t = e.match(
|
|
886
|
+
let t = e.match(Yt) ?? [], n = "(?:'(?:''|[^'])*'(?:\\s*::\\s*text)?|[0-9]+)", r = RegExp(`^\\s*${n}(?:\\s*,\\s*${n})*\\s*$`, "i");
|
|
843
887
|
for (let e = 0; e < t.length - 5; e++) {
|
|
844
888
|
let n = t[e + 4];
|
|
845
|
-
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(
|
|
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(Yt) ?? [], ")");
|
|
846
890
|
}
|
|
847
891
|
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) => {
|
|
848
892
|
if (e.startsWith("'")) return e;
|
|
@@ -880,31 +924,40 @@ BEGIN
|
|
|
880
924
|
return r;
|
|
881
925
|
};
|
|
882
926
|
return JSON.stringify(a(i));
|
|
883
|
-
},
|
|
927
|
+
}, Qt = (e) => {
|
|
884
928
|
if (e == null) return e;
|
|
885
|
-
if (Array.isArray(e)) return e.map(
|
|
929
|
+
if (Array.isArray(e)) return e.map(Qt);
|
|
886
930
|
if (typeof e != "object") return e;
|
|
887
931
|
let t = {};
|
|
888
932
|
for (let n of Object.keys(e).sort()) {
|
|
889
933
|
let r = e[n];
|
|
890
|
-
r !== void 0 && (t[n] =
|
|
934
|
+
r !== void 0 && (t[n] = Qt(r));
|
|
891
935
|
}
|
|
892
936
|
return t;
|
|
893
|
-
},
|
|
937
|
+
}, $t = (e) => {
|
|
894
938
|
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs) return e;
|
|
895
939
|
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, ...a } = e;
|
|
896
940
|
return a;
|
|
897
|
-
},
|
|
941
|
+
}, en = (e) => {
|
|
942
|
+
let t = $t(e), { references: n, defaultValue: r, hasDefault: i, oneOf: a, ...o } = t, s = t.type === "id" && Kt(t) ? null : Gt(t), c = qt(t.references);
|
|
943
|
+
return {
|
|
944
|
+
...o,
|
|
945
|
+
hasDefault: s !== null,
|
|
946
|
+
...s === null ? {} : { defaultValue: s },
|
|
947
|
+
...c === null ? {} : { references: c },
|
|
948
|
+
...t.oneOf !== void 0 && t.oneOf.length > 0 ? { oneOf: [...t.oneOf].sort() } : {}
|
|
949
|
+
};
|
|
950
|
+
}, tn = (e) => e.filter((e) => !x(e.name)).map(en).sort((e, t) => e.name.localeCompare(t.name)), nn = (e) => [...e].map((e) => e.where === void 0 ? e : {
|
|
898
951
|
...e,
|
|
899
|
-
where:
|
|
900
|
-
}).sort((e, t) => e.name.localeCompare(t.name)),
|
|
952
|
+
where: Zt(e.where)
|
|
953
|
+
}).sort((e, t) => e.name.localeCompare(t.name)), rn = (e) => [...e].map((e) => ({
|
|
901
954
|
name: e.name,
|
|
902
|
-
columns:
|
|
903
|
-
indexes:
|
|
904
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
905
|
-
let t = { tables:
|
|
906
|
-
return
|
|
907
|
-
},
|
|
955
|
+
columns: tn(e.columns),
|
|
956
|
+
indexes: nn(e.indexes)
|
|
957
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), L = (e) => {
|
|
958
|
+
let t = { tables: rn(e.tables) }, n = JSON.stringify(Qt(t));
|
|
959
|
+
return ne("sha256").update(n).digest("hex");
|
|
960
|
+
}, an = (e) => e.slice(0, 16), on = (e, t) => {
|
|
908
961
|
let n = t.references ? {
|
|
909
962
|
table: t.references().tableName,
|
|
910
963
|
column: t.referenceColumn ?? "id",
|
|
@@ -944,7 +997,7 @@ BEGIN
|
|
|
944
997
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
945
998
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
946
999
|
};
|
|
947
|
-
},
|
|
1000
|
+
}, sn = (e) => {
|
|
948
1001
|
let t = [], n = /* @__PURE__ */ new Set(), i = (e) => {
|
|
949
1002
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
950
1003
|
}, a = e.appliedPrimaryKey ?? [];
|
|
@@ -992,11 +1045,11 @@ BEGIN
|
|
|
992
1045
|
});
|
|
993
1046
|
}
|
|
994
1047
|
return t;
|
|
995
|
-
},
|
|
1048
|
+
}, cn = (e) => {
|
|
996
1049
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
997
1050
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
998
1051
|
if (i.dropped) continue;
|
|
999
|
-
let e =
|
|
1052
|
+
let e = on(r, i);
|
|
1000
1053
|
n.push(t.has(r) ? {
|
|
1001
1054
|
...e,
|
|
1002
1055
|
unique: !0
|
|
@@ -1006,30 +1059,43 @@ BEGIN
|
|
|
1006
1059
|
return {
|
|
1007
1060
|
name: e.tableName,
|
|
1008
1061
|
columns: n,
|
|
1009
|
-
indexes:
|
|
1062
|
+
indexes: sn(e),
|
|
1010
1063
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
1011
1064
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
1012
1065
|
};
|
|
1013
|
-
},
|
|
1066
|
+
}, ln = (e) => {
|
|
1014
1067
|
let t = /* @__PURE__ */ new Map();
|
|
1015
1068
|
for (let n of e) for (let e of n.indexes) {
|
|
1016
1069
|
let r = t.get(e.name);
|
|
1017
1070
|
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}').`);
|
|
1018
1071
|
t.set(e.name, n.name);
|
|
1019
1072
|
}
|
|
1020
|
-
},
|
|
1021
|
-
let n = e.filter((e) => !c(e.tableName)).map((e) =>
|
|
1073
|
+
}, R = (e, t) => {
|
|
1074
|
+
let n = e.filter((e) => !c(e.tableName)).map((e) => cn(pe(e, t)));
|
|
1022
1075
|
if (t === "mysql" || t === "mariadb") {
|
|
1023
1076
|
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.`);
|
|
1024
1077
|
}
|
|
1025
|
-
return
|
|
1026
|
-
},
|
|
1078
|
+
return ln(n), { tables: t === void 0 ? n : n.map((e) => un(e, t)) };
|
|
1079
|
+
}, un = (e, t) => {
|
|
1080
|
+
let n = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1081
|
+
return {
|
|
1082
|
+
...e,
|
|
1083
|
+
columns: e.columns.map((e) => {
|
|
1084
|
+
if (e.maxLength !== void 0) return e;
|
|
1085
|
+
let r = Jt(e, t, n.has(e.name) || e.unique);
|
|
1086
|
+
return r === void 0 ? e : {
|
|
1087
|
+
...e,
|
|
1088
|
+
maxLength: r
|
|
1089
|
+
};
|
|
1090
|
+
})
|
|
1091
|
+
};
|
|
1092
|
+
}, dn = (e, t, n = A) => w.gen(function* () {
|
|
1027
1093
|
let r = (yield* e`
|
|
1028
1094
|
SELECT p.prosrc
|
|
1029
1095
|
FROM pg_proc p
|
|
1030
1096
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
1031
1097
|
WHERE n.nspname = current_schema()
|
|
1032
|
-
AND p.proname = ${
|
|
1098
|
+
AND p.proname = ${$e(n)}
|
|
1033
1099
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
1034
1100
|
if (a.length === 0) return {
|
|
1035
1101
|
missing: [],
|
|
@@ -1043,10 +1109,10 @@ BEGIN
|
|
|
1043
1109
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1044
1110
|
WHERE NOT t.tgisinternal
|
|
1045
1111
|
AND n.nspname = current_schema()
|
|
1046
|
-
AND t.tgname LIKE ${`${
|
|
1112
|
+
AND t.tgname LIKE ${`${Ze}%`}
|
|
1047
1113
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
1048
1114
|
for (let e of a) {
|
|
1049
|
-
let t = s.has(
|
|
1115
|
+
let t = s.has(Qe(e.tableName, n)), r = e.isReactive !== !1;
|
|
1050
1116
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
1051
1117
|
}
|
|
1052
1118
|
return {
|
|
@@ -1054,7 +1120,7 @@ BEGIN
|
|
|
1054
1120
|
stale: l.sort(),
|
|
1055
1121
|
functionOutdated: i
|
|
1056
1122
|
};
|
|
1057
|
-
}),
|
|
1123
|
+
}), fn = (e) => {
|
|
1058
1124
|
let t = [];
|
|
1059
1125
|
if (e.missing.length > 0) {
|
|
1060
1126
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -1065,19 +1131,19 @@ BEGIN
|
|
|
1065
1131
|
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.`);
|
|
1066
1132
|
}
|
|
1067
1133
|
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;
|
|
1068
|
-
},
|
|
1134
|
+
}, pn = {
|
|
1069
1135
|
postgres: !0,
|
|
1070
1136
|
mysql: !0,
|
|
1071
1137
|
mariadb: !0,
|
|
1072
1138
|
mssql: !0,
|
|
1073
1139
|
sqlite: !0
|
|
1074
|
-
},
|
|
1140
|
+
}, mn = {
|
|
1075
1141
|
postgres: !0,
|
|
1076
1142
|
mysql: !1,
|
|
1077
1143
|
mariadb: !1,
|
|
1078
1144
|
mssql: !0,
|
|
1079
1145
|
sqlite: !0
|
|
1080
|
-
},
|
|
1146
|
+
}, hn = (e) => {
|
|
1081
1147
|
switch (e) {
|
|
1082
1148
|
case "add-column":
|
|
1083
1149
|
case "drop-column":
|
|
@@ -1087,80 +1153,33 @@ BEGIN
|
|
|
1087
1153
|
case "add-foreign-key":
|
|
1088
1154
|
case "add-unique":
|
|
1089
1155
|
case "add-unique-composite":
|
|
1090
|
-
case "add-check": return
|
|
1091
|
-
default: return
|
|
1156
|
+
case "add-check": return mn;
|
|
1157
|
+
default: return pn;
|
|
1092
1158
|
}
|
|
1093
|
-
},
|
|
1159
|
+
}, gn = (e, t) => {
|
|
1094
1160
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1095
1161
|
return new Map(e.map((e) => [e.tableName, {
|
|
1096
1162
|
table: e,
|
|
1097
1163
|
snapshot: n.get(e.tableName),
|
|
1098
1164
|
columnDefs: e.fields
|
|
1099
1165
|
}]));
|
|
1100
|
-
},
|
|
1101
|
-
|
|
1102
|
-
if (Array.isArray(e)) return `[${e.map(L).join(",")}]`;
|
|
1103
|
-
let t = e;
|
|
1104
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${L(t[e])}`).join(",")}}`;
|
|
1105
|
-
}, ln = (e) => {
|
|
1106
|
-
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
1107
|
-
let t = e.defaultValue;
|
|
1108
|
-
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
1109
|
-
if (typeof t == "number") return String(t);
|
|
1110
|
-
if (typeof t != "string") return L(t);
|
|
1111
|
-
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
1112
|
-
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
1113
|
-
let i = n.replace(/::[a-zA-Z0-9_ "]+$/, "").trim(), a = /^'(.*)'$/.test(i) ? i.slice(1, -1).replace(/''/g, "'") : i, o = /^cast\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+as\s+json\s*\)$/i.exec(a);
|
|
1114
|
-
if (o) try {
|
|
1115
|
-
return L(JSON.parse(o[1]));
|
|
1116
|
-
} catch {}
|
|
1117
|
-
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1118
|
-
if (s) try {
|
|
1119
|
-
return L(JSON.parse(s[1]));
|
|
1120
|
-
} catch {}
|
|
1121
|
-
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1122
|
-
return L(JSON.parse(a));
|
|
1123
|
-
} catch {}
|
|
1124
|
-
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1125
|
-
}, un = (e, t) => {
|
|
1126
|
-
let n = ln(e), r = ln(t);
|
|
1166
|
+
}, _n = (e, t) => {
|
|
1167
|
+
let n = Wt(e), r = Wt(t);
|
|
1127
1168
|
if (n === r) return !0;
|
|
1128
|
-
let i =
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
return o(n) === o(r);
|
|
1132
|
-
}, dn = (e) => {
|
|
1133
|
-
if (!e) return null;
|
|
1134
|
-
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1135
|
-
return {
|
|
1136
|
-
table: e.table,
|
|
1137
|
-
column: e.column,
|
|
1138
|
-
onDelete: t(e.onDelete),
|
|
1139
|
-
onUpdate: t(e.onUpdate)
|
|
1140
|
-
};
|
|
1141
|
-
}, fn = (e, t) => {
|
|
1169
|
+
let i = Kt, a = (e) => e.type === "id" && e.idScheme?.kind === "numeric";
|
|
1170
|
+
return e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e)) ? !0 : Gt(e) === Gt(t);
|
|
1171
|
+
}, vn = (e, t) => {
|
|
1142
1172
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1143
1173
|
if (!n && !r) return !0;
|
|
1144
1174
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1145
1175
|
let i = [...n].sort(), a = [...r].sort();
|
|
1146
1176
|
return i.every((e, t) => e === a[t]);
|
|
1147
|
-
},
|
|
1148
|
-
if (t === "mssql") {
|
|
1149
|
-
let t = $e(e, n);
|
|
1150
|
-
if (t !== void 0) return t;
|
|
1151
|
-
}
|
|
1152
|
-
try {
|
|
1153
|
-
let n = /\((\d+)\)/.exec(M(e, t));
|
|
1154
|
-
return n ? Number(n[1]) : void 0;
|
|
1155
|
-
} catch {
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
}, mn = (e, t, n, r) => n === void 0 || m(n) ? !0 : e.type !== "text" || t.type !== "text" || pn(e, n, r) === t.maxLength, hn = (e, t, n, r) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && un(e, t) && mn(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(dn(e.references)) === JSON.stringify(dn(t.references)) && fn(e.oneOf, t.oneOf), gn = (e, t) => t.oneOf && t.oneOf.length > 0 ? R({
|
|
1177
|
+
}, yn = (e, t, n, r) => n === void 0 || m(n) ? !0 : e.type !== "text" || t.type !== "text" || Jt(e, n, r) === t.maxLength, bn = (e, t, n, r) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && _n(e, t) && yn(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(qt(e.references)) === JSON.stringify(qt(t.references)) && vn(e.oneOf, t.oneOf), xn = (e, t) => t.oneOf && t.oneOf.length > 0 ? z({
|
|
1159
1178
|
kind: "add-check",
|
|
1160
1179
|
table: e,
|
|
1161
1180
|
column: t.name,
|
|
1162
1181
|
values: t.oneOf
|
|
1163
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1182
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, Sn = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && Zt(e.where) === Zt(t.where) && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), Cn = (e, t, n) => {
|
|
1164
1183
|
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));
|
|
1165
1184
|
for (let t of e.columns) {
|
|
1166
1185
|
let e = r.get(t.name);
|
|
@@ -1168,7 +1187,7 @@ BEGIN
|
|
|
1168
1187
|
a.push(t);
|
|
1169
1188
|
continue;
|
|
1170
1189
|
}
|
|
1171
|
-
|
|
1190
|
+
bn(t, e, n, c.has(t.name) || t.unique) || s.push({
|
|
1172
1191
|
declared: t,
|
|
1173
1192
|
live: e
|
|
1174
1193
|
});
|
|
@@ -1179,50 +1198,50 @@ BEGIN
|
|
|
1179
1198
|
removed: o,
|
|
1180
1199
|
changed: s
|
|
1181
1200
|
};
|
|
1182
|
-
},
|
|
1201
|
+
}, wn = (e, t, n) => {
|
|
1183
1202
|
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 = [];
|
|
1184
1203
|
for (let t of e.indexes) {
|
|
1185
1204
|
let e = i.get(r(t.name));
|
|
1186
|
-
(!e || !
|
|
1205
|
+
(!e || !Sn(t, e)) && o.push(t);
|
|
1187
1206
|
}
|
|
1188
1207
|
for (let e of t.indexes) {
|
|
1189
1208
|
let t = a.get(r(e.name));
|
|
1190
|
-
(!t || (e.where !== void 0 || t.where !== void 0) && !
|
|
1209
|
+
(!t || (e.where !== void 0 || t.where !== void 0) && !Sn(t, e)) && s.push(e);
|
|
1191
1210
|
}
|
|
1192
1211
|
return {
|
|
1193
1212
|
added: o,
|
|
1194
1213
|
removed: s
|
|
1195
1214
|
};
|
|
1196
|
-
},
|
|
1215
|
+
}, z = (e, t, n, r) => ({
|
|
1197
1216
|
op: e,
|
|
1198
1217
|
classification: t,
|
|
1199
|
-
atomicByDialect:
|
|
1218
|
+
atomicByDialect: hn(e.kind),
|
|
1200
1219
|
...n ? { reason: n } : {},
|
|
1201
1220
|
...r ? { blocked: r } : {}
|
|
1202
|
-
}),
|
|
1221
|
+
}), Tn = (e, t, n) => {
|
|
1203
1222
|
let r = {
|
|
1204
1223
|
kind: "add-column",
|
|
1205
1224
|
table: e,
|
|
1206
1225
|
column: t
|
|
1207
1226
|
};
|
|
1208
|
-
return t.nullable ?
|
|
1209
|
-
},
|
|
1227
|
+
return t.nullable ? z(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? z(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? z(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : z(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` });
|
|
1228
|
+
}, En = (e, t, n) => {
|
|
1210
1229
|
let r = {
|
|
1211
1230
|
kind: "drop-column",
|
|
1212
1231
|
table: e,
|
|
1213
1232
|
column: t.name
|
|
1214
1233
|
};
|
|
1215
|
-
return n?.dropped ?
|
|
1216
|
-
},
|
|
1234
|
+
return n?.dropped ? z(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : z(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1235
|
+
}, Dn = (e, t, n, r, i) => z({
|
|
1217
1236
|
kind: "create-table",
|
|
1218
1237
|
table: e,
|
|
1219
1238
|
columns: t,
|
|
1220
1239
|
indexes: n,
|
|
1221
1240
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1222
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1241
|
+
}, "safe", i ?? "new table — no data to preserve"), On = (e) => z({
|
|
1223
1242
|
kind: "drop-table",
|
|
1224
1243
|
table: e
|
|
1225
|
-
}, "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" }),
|
|
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" }), kn = 5e4, An = (e, t, n, r) => {
|
|
1226
1245
|
let i = (n ?? 0) >= r, a;
|
|
1227
1246
|
return a = !t.unique || t.where !== void 0 ? {
|
|
1228
1247
|
kind: "add-index",
|
|
@@ -1237,16 +1256,16 @@ BEGIN
|
|
|
1237
1256
|
table: e,
|
|
1238
1257
|
name: t.name,
|
|
1239
1258
|
fields: t.columns
|
|
1240
|
-
}, i ?
|
|
1241
|
-
},
|
|
1259
|
+
}, i ? z(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : z(a, "safe", t.where === void 0 ? t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index" : `add ${t.unique ? "unique " : ""}partial index`);
|
|
1260
|
+
}, jn = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ? z({
|
|
1242
1261
|
kind: "drop-unique-composite",
|
|
1243
1262
|
table: e,
|
|
1244
1263
|
name: t.name
|
|
1245
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1264
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : z({
|
|
1246
1265
|
kind: "drop-index",
|
|
1247
1266
|
table: e,
|
|
1248
1267
|
index: t.name
|
|
1249
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1268
|
+
}, "safe", "drop index (no data loss — index is derived data)"), Mn = (e, t) => {
|
|
1250
1269
|
let n = e.type;
|
|
1251
1270
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
1252
1271
|
switch (t) {
|
|
@@ -1255,10 +1274,10 @@ BEGIN
|
|
|
1255
1274
|
case "mssql": return n === "json" ? "text" : n;
|
|
1256
1275
|
default: return n;
|
|
1257
1276
|
}
|
|
1258
|
-
},
|
|
1277
|
+
}, Nn = (e, t, n) => {
|
|
1259
1278
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1260
1279
|
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`;
|
|
1261
|
-
},
|
|
1280
|
+
}, Pn = (e, t, n, r, i, a) => {
|
|
1262
1281
|
let o = [];
|
|
1263
1282
|
if (t.nullable !== n.nullable) {
|
|
1264
1283
|
let n = {
|
|
@@ -1267,7 +1286,7 @@ BEGIN
|
|
|
1267
1286
|
column: t.name,
|
|
1268
1287
|
toNullable: t.nullable
|
|
1269
1288
|
};
|
|
1270
|
-
o.push(t.nullable ?
|
|
1289
|
+
o.push(t.nullable ? z(n, "safe", `loosen ${e}.${t.name} to nullable`) : z(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1271
1290
|
}
|
|
1272
1291
|
if (t.unique !== n.unique) {
|
|
1273
1292
|
if (t.unique) {
|
|
@@ -1276,14 +1295,14 @@ BEGIN
|
|
|
1276
1295
|
table: e,
|
|
1277
1296
|
column: t.name
|
|
1278
1297
|
}, r = (i ?? 0) >= a;
|
|
1279
|
-
o.push(r ?
|
|
1280
|
-
} else o.push(
|
|
1298
|
+
o.push(r ? z(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : z(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1299
|
+
} else o.push(z({
|
|
1281
1300
|
kind: "drop-unique",
|
|
1282
1301
|
table: e,
|
|
1283
1302
|
column: t.name
|
|
1284
1303
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1285
1304
|
}
|
|
1286
|
-
if (
|
|
1305
|
+
if (Mn(t, r) !== Mn(n, r)) {
|
|
1287
1306
|
let i = t.narrowedFrom;
|
|
1288
1307
|
if (i && i.from === n.type) {
|
|
1289
1308
|
let r = {
|
|
@@ -1294,7 +1313,7 @@ BEGIN
|
|
|
1294
1313
|
to: t.type,
|
|
1295
1314
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1296
1315
|
};
|
|
1297
|
-
o.push(
|
|
1316
|
+
o.push(z(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)")));
|
|
1298
1317
|
} else {
|
|
1299
1318
|
let i = {
|
|
1300
1319
|
kind: "alter-column-type",
|
|
@@ -1303,12 +1322,12 @@ BEGIN
|
|
|
1303
1322
|
from: n.type,
|
|
1304
1323
|
to: t.type
|
|
1305
1324
|
};
|
|
1306
|
-
o.push(
|
|
1325
|
+
o.push(z(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: Nn(n.type, t, r) }));
|
|
1307
1326
|
}
|
|
1308
1327
|
}
|
|
1309
1328
|
if (t.type === "text" && n.type === "text" && !m(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1310
1329
|
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})`;
|
|
1311
|
-
o.push(
|
|
1330
|
+
o.push(z({
|
|
1312
1331
|
kind: "alter-column-type",
|
|
1313
1332
|
table: e,
|
|
1314
1333
|
column: t.name,
|
|
@@ -1316,7 +1335,7 @@ BEGIN
|
|
|
1316
1335
|
to: "text"
|
|
1317
1336
|
}, 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)}`));
|
|
1318
1337
|
}
|
|
1319
|
-
if (!
|
|
1338
|
+
if (!_n(t, n)) {
|
|
1320
1339
|
let n = {
|
|
1321
1340
|
kind: "alter-column-default",
|
|
1322
1341
|
table: e,
|
|
@@ -1324,23 +1343,23 @@ BEGIN
|
|
|
1324
1343
|
hasDefault: t.hasDefault,
|
|
1325
1344
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1326
1345
|
};
|
|
1327
|
-
o.push(
|
|
1346
|
+
o.push(z(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1328
1347
|
}
|
|
1329
|
-
if (!
|
|
1330
|
-
n.oneOf && n.oneOf.length > 0 && o.push(
|
|
1348
|
+
if (!vn(t.oneOf, n.oneOf)) {
|
|
1349
|
+
n.oneOf && n.oneOf.length > 0 && o.push(z({
|
|
1331
1350
|
kind: "drop-check",
|
|
1332
1351
|
table: e,
|
|
1333
1352
|
column: t.name
|
|
1334
1353
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1335
|
-
let r =
|
|
1354
|
+
let r = xn(e, t);
|
|
1336
1355
|
r && o.push(r);
|
|
1337
1356
|
}
|
|
1338
|
-
return JSON.stringify(
|
|
1357
|
+
return JSON.stringify(qt(t.references)) !== JSON.stringify(qt(n.references)) && (n.references && o.push(z({
|
|
1339
1358
|
kind: "drop-foreign-key",
|
|
1340
1359
|
table: e,
|
|
1341
1360
|
column: t.name
|
|
1342
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1343
|
-
},
|
|
1361
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...Fn(e, t))), o;
|
|
1362
|
+
}, Fn = (e, t) => {
|
|
1344
1363
|
let n = [];
|
|
1345
1364
|
if (!t.references) return n;
|
|
1346
1365
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1352,15 +1371,15 @@ BEGIN
|
|
|
1352
1371
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1353
1372
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1354
1373
|
};
|
|
1355
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1374
|
+
return i === "null" && !t.nullable ? n.push(z(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(z({
|
|
1356
1375
|
...a,
|
|
1357
1376
|
orphanPolicy: i
|
|
1358
|
-
}, "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(
|
|
1359
|
-
},
|
|
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(z(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1378
|
+
}, In = (e, t, n) => {
|
|
1360
1379
|
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));
|
|
1361
1380
|
for (let [n, c] of Object.entries(t)) {
|
|
1362
1381
|
let t = c.renamedFrom;
|
|
1363
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1382
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(z({
|
|
1364
1383
|
kind: "rename-column",
|
|
1365
1384
|
table: e.tableName,
|
|
1366
1385
|
from: t,
|
|
@@ -1372,26 +1391,26 @@ BEGIN
|
|
|
1372
1391
|
consumedAddedNames: i,
|
|
1373
1392
|
consumedRemovedNames: a
|
|
1374
1393
|
};
|
|
1375
|
-
},
|
|
1394
|
+
}, Ln = /* @__PURE__ */ new Set([
|
|
1376
1395
|
"postgres",
|
|
1377
1396
|
"mysql",
|
|
1378
1397
|
"mariadb",
|
|
1379
1398
|
"mssql"
|
|
1380
|
-
]),
|
|
1399
|
+
]), Rn = {
|
|
1381
1400
|
ops: [],
|
|
1382
1401
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1383
1402
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1384
|
-
},
|
|
1385
|
-
if (i === void 0 || !
|
|
1386
|
-
let a = t.added.filter((e) =>
|
|
1387
|
-
if (a.length === 0) return
|
|
1403
|
+
}, zn = (e) => !e.unique && !e.expression && e.where === void 0, Bn = (e, t, n, r, i) => {
|
|
1404
|
+
if (i === void 0 || !Ln.has(i)) return Rn;
|
|
1405
|
+
let a = t.added.filter((e) => zn(e) && !r.has(e.name));
|
|
1406
|
+
if (a.length === 0) return Rn;
|
|
1388
1407
|
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();
|
|
1389
1408
|
for (let n of t.removed) {
|
|
1390
|
-
if (!
|
|
1409
|
+
if (!zn(n)) continue;
|
|
1391
1410
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1392
1411
|
if (r.length !== 1) continue;
|
|
1393
1412
|
let i = r[0];
|
|
1394
|
-
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(
|
|
1413
|
+
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(z({
|
|
1395
1414
|
kind: "rename-index",
|
|
1396
1415
|
table: e,
|
|
1397
1416
|
from: n.name,
|
|
@@ -1403,7 +1422,7 @@ BEGIN
|
|
|
1403
1422
|
consumedAddedNames: l,
|
|
1404
1423
|
consumedRemovedNames: u
|
|
1405
1424
|
};
|
|
1406
|
-
},
|
|
1425
|
+
}, Vn = (e, t, n) => {
|
|
1407
1426
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1408
1427
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1409
1428
|
for (let c of e.tables) {
|
|
@@ -1414,7 +1433,7 @@ BEGIN
|
|
|
1414
1433
|
continue;
|
|
1415
1434
|
}
|
|
1416
1435
|
if (t.has(c.name)) {
|
|
1417
|
-
r.push(
|
|
1436
|
+
r.push(z({
|
|
1418
1437
|
kind: "rename-table",
|
|
1419
1438
|
from: e,
|
|
1420
1439
|
to: c.name
|
|
@@ -1422,14 +1441,14 @@ BEGIN
|
|
|
1422
1441
|
continue;
|
|
1423
1442
|
}
|
|
1424
1443
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1425
|
-
r.push(
|
|
1444
|
+
r.push(z({
|
|
1426
1445
|
kind: "rename-table",
|
|
1427
1446
|
from: e,
|
|
1428
1447
|
to: c.name
|
|
1429
1448
|
}, "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.` }));
|
|
1430
1449
|
continue;
|
|
1431
1450
|
}
|
|
1432
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1451
|
+
i.set(c.name, e), a.add(e), r.push(z({
|
|
1433
1452
|
kind: "rename-table",
|
|
1434
1453
|
from: e,
|
|
1435
1454
|
to: c.name
|
|
@@ -1443,19 +1462,19 @@ BEGIN
|
|
|
1443
1462
|
claimedOldNames: c,
|
|
1444
1463
|
refusals: o
|
|
1445
1464
|
};
|
|
1446
|
-
},
|
|
1465
|
+
}, Hn = (e, t, n, r) => {
|
|
1447
1466
|
if (t === void 0) return {
|
|
1448
1467
|
live: e,
|
|
1449
1468
|
ops: []
|
|
1450
1469
|
};
|
|
1451
|
-
let i = r !== void 0 &&
|
|
1470
|
+
let i = r !== void 0 && Ln.has(r), a = [], o = e.indexes.map((e) => {
|
|
1452
1471
|
if (!e.name.startsWith(t)) return e;
|
|
1453
1472
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1454
1473
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1455
1474
|
...e,
|
|
1456
1475
|
name: r,
|
|
1457
1476
|
table: n
|
|
1458
|
-
} : i ? (a.push(
|
|
1477
|
+
} : i ? (a.push(z({
|
|
1459
1478
|
kind: "rename-index",
|
|
1460
1479
|
table: n,
|
|
1461
1480
|
from: e.name,
|
|
@@ -1474,7 +1493,7 @@ BEGIN
|
|
|
1474
1493
|
},
|
|
1475
1494
|
ops: a
|
|
1476
1495
|
};
|
|
1477
|
-
},
|
|
1496
|
+
}, Un = (e) => {
|
|
1478
1497
|
let t = {
|
|
1479
1498
|
safe: 0,
|
|
1480
1499
|
needsDefault: 0,
|
|
@@ -1507,51 +1526,69 @@ BEGIN
|
|
|
1507
1526
|
case "multi-step": t.multiStep++;
|
|
1508
1527
|
}
|
|
1509
1528
|
return t;
|
|
1510
|
-
},
|
|
1511
|
-
let t =
|
|
1529
|
+
}, Wn = (e) => {
|
|
1530
|
+
let t = R(e.declared, e.dialect), n = gn(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? kn, a = [], o = Vn(t, r, n);
|
|
1512
1531
|
a.push(...o.ops);
|
|
1513
1532
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1514
|
-
a.push(
|
|
1533
|
+
a.push(Dn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1515
1534
|
for (let t of e.columns) {
|
|
1516
|
-
let n =
|
|
1535
|
+
let n = xn(e.name, t);
|
|
1517
1536
|
n && a.push(n);
|
|
1518
1537
|
}
|
|
1519
1538
|
}
|
|
1520
|
-
let s = new Set(e.ignoreTables ?? []);
|
|
1521
|
-
for (let t of e.live.tables) n.has(t.name)
|
|
1539
|
+
let s = new Set(e.ignoreTables ?? []), c = [];
|
|
1540
|
+
for (let t of e.live.tables) if (!n.has(t.name)) {
|
|
1541
|
+
if (o.claimedOldNames.has(t.name)) {
|
|
1542
|
+
c.push(t.name);
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
if (_(t.name)) {
|
|
1546
|
+
c.push(t.name);
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
if (x(t.name)) {
|
|
1550
|
+
c.push(t.name);
|
|
1551
|
+
continue;
|
|
1552
|
+
}
|
|
1553
|
+
if (s.has(t.name)) {
|
|
1554
|
+
c.push(t.name);
|
|
1555
|
+
continue;
|
|
1556
|
+
}
|
|
1557
|
+
a.push(On(t.name));
|
|
1558
|
+
}
|
|
1522
1559
|
for (let s of t.tables) {
|
|
1523
1560
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1524
1561
|
if (!c) continue;
|
|
1525
|
-
let l =
|
|
1562
|
+
let l = Hn(c, t, s.name, e.dialect);
|
|
1526
1563
|
a.push(...l.ops);
|
|
1527
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1564
|
+
let u = l.live, d = n.get(s.name), f = Cn(s, u, e.dialect), p = wn(s, u, e.dialect), m = In(d.table, d.columnDefs, f);
|
|
1528
1565
|
a.push(...m.ops);
|
|
1529
1566
|
for (let e of f.removed) {
|
|
1530
1567
|
if (m.consumedRemovedNames.has(e.name) || x(e.name)) continue;
|
|
1531
1568
|
let t = d.columnDefs[e.name];
|
|
1532
|
-
a.push(
|
|
1569
|
+
a.push(En(s.name, e, t));
|
|
1533
1570
|
}
|
|
1534
1571
|
for (let e of f.added) {
|
|
1535
1572
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1536
1573
|
let t = d.columnDefs[e.name];
|
|
1537
|
-
a.push(
|
|
1538
|
-
let n =
|
|
1539
|
-
n && a.push(n), a.push(...
|
|
1574
|
+
a.push(Tn(s.name, e, t));
|
|
1575
|
+
let n = xn(s.name, e);
|
|
1576
|
+
n && a.push(n), a.push(...Fn(s.name, e));
|
|
1540
1577
|
}
|
|
1541
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1578
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Bn(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1542
1579
|
a.push(...g.ops);
|
|
1543
|
-
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(
|
|
1544
|
-
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(
|
|
1545
|
-
for (let { declared: t, live: n } of f.changed) a.push(...
|
|
1580
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(An(s.name, e, u.rowCount, i));
|
|
1581
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(jn(s.name, e));
|
|
1582
|
+
for (let { declared: t, live: n } of f.changed) a.push(...Pn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1546
1583
|
}
|
|
1547
|
-
let
|
|
1548
|
-
let t =
|
|
1549
|
-
return t ? t.columns.flatMap((e) => e.references &&
|
|
1584
|
+
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
|
+
let t = u.get(e);
|
|
1586
|
+
return t ? t.columns.flatMap((e) => e.references && l.has(e.references.table) ? [{
|
|
1550
1587
|
column: e.name,
|
|
1551
1588
|
target: e.references.table
|
|
1552
1589
|
}] : []) : [];
|
|
1553
|
-
},
|
|
1554
|
-
for (let e of t.tables) if (
|
|
1590
|
+
}, f = me([...l], d), p = [];
|
|
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(z({
|
|
1555
1592
|
kind: "add-foreign-key",
|
|
1556
1593
|
table: e.name,
|
|
1557
1594
|
column: t.name,
|
|
@@ -1560,14 +1597,14 @@ BEGIN
|
|
|
1560
1597
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1561
1598
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1562
1599
|
}, "safe", `deferred FK ${e.name}.${t.name} → ${t.references.table} — breaks a create-time table cycle`));
|
|
1563
|
-
if (
|
|
1600
|
+
if (f.size > 0) {
|
|
1564
1601
|
let e = (e) => e.references ? Object.fromEntries(Object.entries(e).filter(([e]) => e !== "references")) : e;
|
|
1565
1602
|
for (let t = 0; t < a.length; t += 1) {
|
|
1566
1603
|
let n = a[t];
|
|
1567
1604
|
if (n.op.kind !== "create-table") continue;
|
|
1568
1605
|
let r = n.op;
|
|
1569
|
-
if (!r.columns.some((e) =>
|
|
1570
|
-
let i = r.columns.map((t) =>
|
|
1606
|
+
if (!r.columns.some((e) => f.has(D(r.table, e.name)))) continue;
|
|
1607
|
+
let i = r.columns.map((t) => f.has(D(r.table, t.name)) ? e(t) : t);
|
|
1571
1608
|
a[t] = {
|
|
1572
1609
|
...n,
|
|
1573
1610
|
op: {
|
|
@@ -1576,24 +1613,24 @@ BEGIN
|
|
|
1576
1613
|
}
|
|
1577
1614
|
};
|
|
1578
1615
|
}
|
|
1579
|
-
a.push(...
|
|
1616
|
+
a.push(...p);
|
|
1580
1617
|
}
|
|
1581
|
-
let
|
|
1582
|
-
let n =
|
|
1618
|
+
let m = new Map(t.tables.map((e) => [e.name, e])), h = /* @__PURE__ */ new Map(), g = (e, t = /* @__PURE__ */ new Set()) => {
|
|
1619
|
+
let n = h.get(e);
|
|
1583
1620
|
if (n !== void 0) return n;
|
|
1584
1621
|
if (t.has(e)) return 0;
|
|
1585
|
-
let r =
|
|
1622
|
+
let r = m.get(e);
|
|
1586
1623
|
if (!r) return 0;
|
|
1587
1624
|
let i = new Set(t).add(e), a = 0;
|
|
1588
1625
|
for (let t of r.columns) {
|
|
1589
1626
|
let n = t.references?.table;
|
|
1590
|
-
n && n !== e && !
|
|
1627
|
+
n && n !== e && !f.has(D(e, t.name)) && (a = Math.max(a, g(n, i) + 1));
|
|
1591
1628
|
}
|
|
1592
|
-
return
|
|
1593
|
-
},
|
|
1629
|
+
return h.set(e, a), a;
|
|
1630
|
+
}, v = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, y = (e) => {
|
|
1594
1631
|
let t = "table" in e ? e.table : "";
|
|
1595
|
-
return e.kind === "create-table" ?
|
|
1596
|
-
},
|
|
1632
|
+
return e.kind === "create-table" ? g(t) : e.kind === "drop-table" ? -g(t) : 0;
|
|
1633
|
+
}, b = {
|
|
1597
1634
|
"add-column": 0,
|
|
1598
1635
|
"rename-column": 1,
|
|
1599
1636
|
"rename-index": 1,
|
|
@@ -1611,23 +1648,34 @@ BEGIN
|
|
|
1611
1648
|
"add-unique-composite": 5,
|
|
1612
1649
|
"add-foreign-key": 5,
|
|
1613
1650
|
"add-check": 5
|
|
1614
|
-
},
|
|
1615
|
-
let n =
|
|
1651
|
+
}, S = (e) => b[e] ?? 9, C = [...a].sort((e, t) => {
|
|
1652
|
+
let n = v(e.op.kind), r = v(t.op.kind);
|
|
1616
1653
|
if (n !== r) return n - r;
|
|
1617
|
-
let i =
|
|
1654
|
+
let i = y(e.op), a = y(t.op);
|
|
1618
1655
|
if (i !== a) return i - a;
|
|
1619
1656
|
let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
|
|
1620
1657
|
if (o !== s) return o.localeCompare(s);
|
|
1621
|
-
let c =
|
|
1658
|
+
let c = S(e.op.kind), l = S(t.op.kind);
|
|
1622
1659
|
return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
|
|
1623
|
-
});
|
|
1660
|
+
}), w = /* @__PURE__ */ new Set();
|
|
1661
|
+
for (let e of C) "table" in e.op && w.add(e.op.table);
|
|
1662
|
+
let T = [];
|
|
1663
|
+
for (let e of t.tables) {
|
|
1664
|
+
if (w.has(e.name) || o.renamedInto.has(e.name)) continue;
|
|
1665
|
+
let t = r.get(e.name);
|
|
1666
|
+
t !== void 0 && L({ tables: [t] }) !== L({ tables: [e] }) && T.push(e.name);
|
|
1667
|
+
}
|
|
1624
1668
|
return {
|
|
1625
|
-
operations:
|
|
1626
|
-
fromFingerprint:
|
|
1627
|
-
toFingerprint:
|
|
1628
|
-
summary:
|
|
1669
|
+
operations: C,
|
|
1670
|
+
fromFingerprint: L(e.live),
|
|
1671
|
+
toFingerprint: L(t),
|
|
1672
|
+
summary: Un(C),
|
|
1673
|
+
fingerprintDivergence: {
|
|
1674
|
+
outsideDiff: c,
|
|
1675
|
+
diffEquivalent: T
|
|
1676
|
+
}
|
|
1629
1677
|
};
|
|
1630
|
-
},
|
|
1678
|
+
}, Gn = (e) => {
|
|
1631
1679
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1632
1680
|
if (!t) return null;
|
|
1633
1681
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -1635,7 +1683,7 @@ BEGIN
|
|
|
1635
1683
|
column: t[1],
|
|
1636
1684
|
values: n
|
|
1637
1685
|
};
|
|
1638
|
-
},
|
|
1686
|
+
}, Kn = (e, t) => {
|
|
1639
1687
|
if (t === "vector") return "vector";
|
|
1640
1688
|
switch (e) {
|
|
1641
1689
|
case "text":
|
|
@@ -1662,10 +1710,10 @@ BEGIN
|
|
|
1662
1710
|
case "USER-DEFINED": return "text";
|
|
1663
1711
|
default: return "text";
|
|
1664
1712
|
}
|
|
1665
|
-
},
|
|
1713
|
+
}, qn = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1666
1714
|
expr: e,
|
|
1667
1715
|
stored: t
|
|
1668
|
-
} },
|
|
1716
|
+
} }, B = (e) => {
|
|
1669
1717
|
switch (e.toUpperCase()) {
|
|
1670
1718
|
case "CASCADE": return "cascade";
|
|
1671
1719
|
case "RESTRICT": return "restrict";
|
|
@@ -1673,25 +1721,25 @@ BEGIN
|
|
|
1673
1721
|
case "SET DEFAULT": return "noAction";
|
|
1674
1722
|
default: return "noAction";
|
|
1675
1723
|
}
|
|
1676
|
-
},
|
|
1724
|
+
}, Jn = (e, t) => {
|
|
1677
1725
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1678
1726
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1679
|
-
},
|
|
1727
|
+
}, Yn = () => Jn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Xn = 300, Zn = () => {
|
|
1680
1728
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1681
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1682
|
-
},
|
|
1729
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Jn(e, 3e4);
|
|
1730
|
+
}, Qn = (e, t) => {
|
|
1683
1731
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1684
1732
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1685
1733
|
return r;
|
|
1686
|
-
},
|
|
1687
|
-
let t =
|
|
1734
|
+
}, $n = (e) => {
|
|
1735
|
+
let t = Zn(), n = w.gen(function* () {
|
|
1688
1736
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1689
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
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 = Yn(), a = (e, t) => w.gen(function* () {
|
|
1690
1738
|
let r = [];
|
|
1691
|
-
for (let a of
|
|
1739
|
+
for (let a of Qn(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1692
1740
|
return r;
|
|
1693
1741
|
}), o = [];
|
|
1694
|
-
for (let t = 0;; t +=
|
|
1742
|
+
for (let t = 0;; t += Xn) {
|
|
1695
1743
|
let n = yield* e`
|
|
1696
1744
|
SELECT c.relname AS table_name,
|
|
1697
1745
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1699,9 +1747,9 @@ BEGIN
|
|
|
1699
1747
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1700
1748
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1701
1749
|
ORDER BY c.relname
|
|
1702
|
-
LIMIT ${r(
|
|
1750
|
+
LIMIT ${r(Xn)} OFFSET ${r(t)}
|
|
1703
1751
|
`;
|
|
1704
|
-
if (o.push(...n), n.length <
|
|
1752
|
+
if (o.push(...n), n.length < Xn) break;
|
|
1705
1753
|
}
|
|
1706
1754
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1707
1755
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1798,18 +1846,18 @@ BEGIN
|
|
|
1798
1846
|
let t = v.get(e.table_name);
|
|
1799
1847
|
t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
|
|
1800
1848
|
}
|
|
1801
|
-
let
|
|
1849
|
+
let C = /* @__PURE__ */ new Map();
|
|
1802
1850
|
for (let e of f) {
|
|
1803
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
1851
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = C.get(t);
|
|
1804
1852
|
n || (n = {
|
|
1805
1853
|
table: e.table_name,
|
|
1806
1854
|
columns: []
|
|
1807
|
-
},
|
|
1855
|
+
}, C.set(t, n)), n.columns.push({
|
|
1808
1856
|
name: e.column_name,
|
|
1809
1857
|
position: e.position
|
|
1810
1858
|
});
|
|
1811
1859
|
}
|
|
1812
|
-
for (let [e, t] of
|
|
1860
|
+
for (let [e, t] of C) {
|
|
1813
1861
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
1814
1862
|
if (n.length === 1) {
|
|
1815
1863
|
let e = y.get(t.table);
|
|
@@ -1834,14 +1882,14 @@ BEGIN
|
|
|
1834
1882
|
let n = t.get(e.index_name);
|
|
1835
1883
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1836
1884
|
}
|
|
1837
|
-
let
|
|
1885
|
+
let T = [];
|
|
1838
1886
|
for (let e of c) {
|
|
1839
1887
|
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) => {
|
|
1840
|
-
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" :
|
|
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" : Kn(t.data_type, t.udt_name), c = a ? {
|
|
1841
1889
|
table: a.target_table,
|
|
1842
1890
|
column: a.target_column,
|
|
1843
|
-
onDelete:
|
|
1844
|
-
onUpdate:
|
|
1891
|
+
onDelete: B(a.delete_rule),
|
|
1892
|
+
onUpdate: B(a.update_rule)
|
|
1845
1893
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1846
1894
|
return {
|
|
1847
1895
|
name: t.column_name,
|
|
@@ -1852,9 +1900,9 @@ BEGIN
|
|
|
1852
1900
|
hasDefault: t.column_default !== null,
|
|
1853
1901
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
1854
1902
|
...c ? { references: c } : {},
|
|
1855
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
1903
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(Kn(t.data_type, t.udt_name)) ? "numeric" : "text" } : {},
|
|
1856
1904
|
...l ? { oneOf: l } : {},
|
|
1857
|
-
...
|
|
1905
|
+
...qn(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
1858
1906
|
};
|
|
1859
1907
|
}), l = [], u = S.get(e.table_name);
|
|
1860
1908
|
if (u) for (let [t, n] of u) {
|
|
@@ -1882,20 +1930,20 @@ BEGIN
|
|
|
1882
1930
|
unique: !0
|
|
1883
1931
|
});
|
|
1884
1932
|
let d = Number(e.row_count ?? 0);
|
|
1885
|
-
|
|
1933
|
+
T.push({
|
|
1886
1934
|
name: e.table_name,
|
|
1887
1935
|
columns: c,
|
|
1888
1936
|
indexes: l,
|
|
1889
1937
|
...d > 0 ? { rowCount: d } : {}
|
|
1890
1938
|
});
|
|
1891
1939
|
}
|
|
1892
|
-
return { tables:
|
|
1940
|
+
return { tables: T };
|
|
1893
1941
|
});
|
|
1894
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
1942
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(w.catchAll((e) => {
|
|
1895
1943
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1896
|
-
return n.includes("statement timeout") || n.includes("57014") ?
|
|
1944
|
+
return n.includes("statement timeout") || n.includes("57014") ? w.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.`)) : w.fail(e);
|
|
1897
1945
|
}));
|
|
1898
|
-
},
|
|
1946
|
+
}, er = (e, t) => {
|
|
1899
1947
|
switch (e.toLowerCase()) {
|
|
1900
1948
|
case "varchar":
|
|
1901
1949
|
case "char":
|
|
@@ -1927,21 +1975,21 @@ BEGIN
|
|
|
1927
1975
|
case "json": return "json";
|
|
1928
1976
|
default: return "text";
|
|
1929
1977
|
}
|
|
1930
|
-
},
|
|
1978
|
+
}, tr = (e) => e.map((e) => {
|
|
1931
1979
|
let t = e, n = {};
|
|
1932
1980
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1933
1981
|
return n;
|
|
1934
|
-
}),
|
|
1935
|
-
let t =
|
|
1982
|
+
}), nr = (e) => w.gen(function* () {
|
|
1983
|
+
let t = tr(yield* e`
|
|
1936
1984
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1937
1985
|
FROM information_schema.tables
|
|
1938
1986
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1939
|
-
ORDER BY table_name`), n =
|
|
1987
|
+
ORDER BY table_name`), n = tr(yield* e`
|
|
1940
1988
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1941
1989
|
character_maximum_length, generation_expression, extra
|
|
1942
1990
|
FROM information_schema.columns
|
|
1943
1991
|
WHERE table_schema = DATABASE()
|
|
1944
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
1992
|
+
ORDER BY table_name, ordinal_position`), r = tr(yield* e`
|
|
1945
1993
|
SELECT k.table_name AS source_table,
|
|
1946
1994
|
k.column_name AS source_column,
|
|
1947
1995
|
k.referenced_table_name AS target_table,
|
|
@@ -1951,7 +1999,7 @@ BEGIN
|
|
|
1951
1999
|
JOIN information_schema.referential_constraints r
|
|
1952
2000
|
ON k.constraint_name = r.constraint_name
|
|
1953
2001
|
AND k.table_schema = r.constraint_schema
|
|
1954
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
2002
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = tr(yield* e`
|
|
1955
2003
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
1956
2004
|
FROM information_schema.statistics
|
|
1957
2005
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -1964,14 +2012,14 @@ BEGIN
|
|
|
1964
2012
|
JOIN information_schema.table_constraints tc
|
|
1965
2013
|
ON tc.constraint_schema = cc.constraint_schema
|
|
1966
2014
|
AND tc.constraint_name = cc.constraint_name
|
|
1967
|
-
WHERE cc.constraint_schema = DATABASE()`.unprepared, s =
|
|
2015
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared, s = tr(yield* a.pipe(w.orElse(() => o), w.orElseSucceed(() => []))), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map();
|
|
1968
2016
|
for (let e of s) {
|
|
1969
2017
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
1970
2018
|
if (t) {
|
|
1971
2019
|
c.add(`${e.table_name}.${t[1]}`);
|
|
1972
2020
|
continue;
|
|
1973
2021
|
}
|
|
1974
|
-
let n =
|
|
2022
|
+
let n = Gn(e.check_clause);
|
|
1975
2023
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
1976
2024
|
}
|
|
1977
2025
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -1994,11 +2042,11 @@ BEGIN
|
|
|
1994
2042
|
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);
|
|
1995
2043
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1996
2044
|
let s = t.map((t) => {
|
|
1997
|
-
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" :
|
|
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" : er(t.data_type, t.column_type), u = o ? {
|
|
1998
2046
|
table: o.target_table,
|
|
1999
2047
|
column: o.target_column,
|
|
2000
|
-
onDelete:
|
|
2001
|
-
onUpdate:
|
|
2048
|
+
onDelete: B(o.delete_rule),
|
|
2049
|
+
onUpdate: B(o.update_rule)
|
|
2002
2050
|
} : 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}`);
|
|
2003
2051
|
return {
|
|
2004
2052
|
name: t.column_name,
|
|
@@ -2009,9 +2057,9 @@ BEGIN
|
|
|
2009
2057
|
hasDefault: f !== null,
|
|
2010
2058
|
...f === null ? {} : { defaultValue: f },
|
|
2011
2059
|
...u ? { references: u } : {},
|
|
2012
|
-
...o ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2060
|
+
...o ? { referenceStorage: ["integer", "bigint"].includes(er(t.data_type, t.column_type)) ? "numeric" : "text" } : {},
|
|
2013
2061
|
...p ? { oneOf: p } : {},
|
|
2014
|
-
...
|
|
2062
|
+
...qn(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {}
|
|
2015
2063
|
};
|
|
2016
2064
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
2017
2065
|
if (o) for (let [t, n] of o) {
|
|
@@ -2038,10 +2086,10 @@ BEGIN
|
|
|
2038
2086
|
});
|
|
2039
2087
|
}
|
|
2040
2088
|
return { tables: p };
|
|
2041
|
-
}),
|
|
2089
|
+
}), rr = (e) => {
|
|
2042
2090
|
let t = e.toUpperCase();
|
|
2043
2091
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
2044
|
-
},
|
|
2092
|
+
}, ir = (e) => e === 1 || e === !0, ar = (e) => w.gen(function* () {
|
|
2045
2093
|
let t = yield* e`
|
|
2046
2094
|
SELECT name, sql FROM sqlite_master
|
|
2047
2095
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -2055,18 +2103,18 @@ BEGIN
|
|
|
2055
2103
|
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();
|
|
2056
2104
|
for (let t of c) {
|
|
2057
2105
|
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);
|
|
2058
|
-
if (f.set(t.name, r), t.partial !== void 0 &&
|
|
2059
|
-
let n =
|
|
2106
|
+
if (f.set(t.name, r), t.partial !== void 0 && ir(t.partial)) {
|
|
2107
|
+
let n = Xt((yield* e`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${t.name}`)[0]?.sql ?? "");
|
|
2060
2108
|
n !== void 0 && p.set(t.name, n);
|
|
2061
2109
|
}
|
|
2062
|
-
!p.has(t.name) &&
|
|
2110
|
+
!p.has(t.name) && ir(t.unique) && r.length === 1 && m.add(r[0]);
|
|
2063
2111
|
}
|
|
2064
2112
|
let h = o.map((e) => {
|
|
2065
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
2113
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : rr(e.type), a = r ? {
|
|
2066
2114
|
table: r.table,
|
|
2067
2115
|
column: r.to,
|
|
2068
|
-
onDelete:
|
|
2069
|
-
onUpdate:
|
|
2116
|
+
onDelete: B(r.on_delete),
|
|
2117
|
+
onUpdate: B(r.on_update)
|
|
2070
2118
|
} : void 0, o = t.get(e.name);
|
|
2071
2119
|
return {
|
|
2072
2120
|
name: e.name,
|
|
@@ -2076,19 +2124,19 @@ BEGIN
|
|
|
2076
2124
|
hasDefault: e.dflt_value !== null,
|
|
2077
2125
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
2078
2126
|
...a ? { references: a } : {},
|
|
2079
|
-
...r ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2127
|
+
...r ? { referenceStorage: ["integer", "bigint"].includes(rr(e.type)) ? "numeric" : "text" } : {},
|
|
2080
2128
|
...o ? { oneOf: o } : {},
|
|
2081
|
-
...
|
|
2129
|
+
...qn(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
2082
2130
|
};
|
|
2083
2131
|
}), g = new Set(s.map((e) => e.from)), _ = [];
|
|
2084
2132
|
for (let e of c) {
|
|
2085
2133
|
if (e.origin === "pk") continue;
|
|
2086
2134
|
let t = f.get(e.name) ?? [], n = p.get(e.name);
|
|
2087
|
-
n === void 0 && t.length === 1 &&
|
|
2135
|
+
n === void 0 && t.length === 1 && ir(e.unique) || (n !== void 0 || t.length !== 1 || ir(e.unique) || !g.has(t[0]) || e.name === `${i}_${t[0]}_idx`) && _.push({
|
|
2088
2136
|
name: e.name,
|
|
2089
2137
|
table: i,
|
|
2090
2138
|
columns: t,
|
|
2091
|
-
unique:
|
|
2139
|
+
unique: ir(e.unique),
|
|
2092
2140
|
...n === void 0 ? {} : { where: n }
|
|
2093
2141
|
});
|
|
2094
2142
|
}
|
|
@@ -2104,7 +2152,7 @@ BEGIN
|
|
|
2104
2152
|
});
|
|
2105
2153
|
}
|
|
2106
2154
|
return { tables: r };
|
|
2107
|
-
}),
|
|
2155
|
+
}), or = (e) => {
|
|
2108
2156
|
switch (e.toLowerCase()) {
|
|
2109
2157
|
case "int":
|
|
2110
2158
|
case "smallint":
|
|
@@ -2126,14 +2174,14 @@ BEGIN
|
|
|
2126
2174
|
case "image": return "bytes";
|
|
2127
2175
|
default: return "text";
|
|
2128
2176
|
}
|
|
2129
|
-
}, V = (e) => e === !0 || e === 1,
|
|
2177
|
+
}, V = (e) => e === !0 || e === 1, sr = (e) => w.gen(function* () {
|
|
2130
2178
|
let t = yield* e`
|
|
2131
2179
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2132
2180
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
2133
2181
|
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
|
|
2134
2182
|
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
2135
2183
|
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length
|
|
2136
|
-
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield*
|
|
2184
|
+
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield* w.orElseSucceed(e`
|
|
2137
2185
|
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS definition,
|
|
2138
2186
|
cc.is_persisted AS is_persisted
|
|
2139
2187
|
FROM sys.computed_columns cc
|
|
@@ -2193,12 +2241,12 @@ BEGIN
|
|
|
2193
2241
|
else t[0].predicate == null && V(t[0].is_unique) && t.length === 1 && p.add(t[0].column_name);
|
|
2194
2242
|
}
|
|
2195
2243
|
let m = t.map((t) => {
|
|
2196
|
-
let n = s.length === 1 && s[0] === t.column_name, a = r.get(t.column_name), o = a ? "reference" : n && t.column_name === "id" ? "id" :
|
|
2244
|
+
let n = s.length === 1 && s[0] === t.column_name, a = r.get(t.column_name), o = a ? "reference" : n && t.column_name === "id" ? "id" : or(t.data_type), l = a ? {
|
|
2197
2245
|
table: a.target_table,
|
|
2198
2246
|
column: a.target_column,
|
|
2199
|
-
onDelete:
|
|
2200
|
-
onUpdate:
|
|
2201
|
-
} : void 0, u = t.column_default === null ? null :
|
|
2247
|
+
onDelete: cr(a.delete_rule),
|
|
2248
|
+
onUpdate: cr(a.update_rule)
|
|
2249
|
+
} : void 0, u = t.column_default === null ? null : lr(t.column_default), d = c.get(`${e}.${t.column_name}`);
|
|
2202
2250
|
return {
|
|
2203
2251
|
name: t.column_name,
|
|
2204
2252
|
type: o,
|
|
@@ -2208,9 +2256,9 @@ BEGIN
|
|
|
2208
2256
|
hasDefault: u !== null,
|
|
2209
2257
|
...u === null ? {} : { defaultValue: u },
|
|
2210
2258
|
...l ? { references: l } : {},
|
|
2211
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2259
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(or(t.data_type)) ? "numeric" : "text" } : {},
|
|
2212
2260
|
...d ? { oneOf: d } : {},
|
|
2213
|
-
...
|
|
2261
|
+
...qn(i.get(`${e}.${t.column_name}`)?.definition ?? null, V(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2214
2262
|
};
|
|
2215
2263
|
}), h = [];
|
|
2216
2264
|
if (o) for (let [t, n] of o) {
|
|
@@ -2237,18 +2285,18 @@ BEGIN
|
|
|
2237
2285
|
});
|
|
2238
2286
|
}
|
|
2239
2287
|
return { tables: f };
|
|
2240
|
-
}),
|
|
2288
|
+
}), cr = (e) => {
|
|
2241
2289
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2242
2290
|
case "CASCADE": return "cascade";
|
|
2243
2291
|
case "SET NULL": return "setNull";
|
|
2244
2292
|
case "SET DEFAULT": return "noAction";
|
|
2245
2293
|
default: return "noAction";
|
|
2246
2294
|
}
|
|
2247
|
-
},
|
|
2295
|
+
}, lr = (e) => {
|
|
2248
2296
|
let t = e.trim();
|
|
2249
2297
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2250
2298
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2251
|
-
},
|
|
2299
|
+
}, ur = /* @__PURE__ */ new Set([
|
|
2252
2300
|
"character varying",
|
|
2253
2301
|
"varchar",
|
|
2254
2302
|
"nvarchar",
|
|
@@ -2256,71 +2304,71 @@ BEGIN
|
|
|
2256
2304
|
"character",
|
|
2257
2305
|
"nchar"
|
|
2258
2306
|
]), H = (e, t) => {
|
|
2259
|
-
if (!
|
|
2307
|
+
if (!ur.has(e.toLowerCase())) return;
|
|
2260
2308
|
let n = Number(t);
|
|
2261
2309
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2262
|
-
},
|
|
2263
|
-
mysql: () =>
|
|
2264
|
-
mssql: () =>
|
|
2265
|
-
sqlite: () =>
|
|
2266
|
-
orElse: () =>
|
|
2267
|
-
}).pipe(
|
|
2310
|
+
}, dr = /* @__PURE__ */ new Set([k]), fr = (e) => e.onDialectOrElse({
|
|
2311
|
+
mysql: () => nr(e),
|
|
2312
|
+
mssql: () => sr(e),
|
|
2313
|
+
sqlite: () => ar(e),
|
|
2314
|
+
orElse: () => $n(e)
|
|
2315
|
+
}).pipe(w.map((e) => ({
|
|
2268
2316
|
...e,
|
|
2269
|
-
tables: e.tables.filter((e) => !
|
|
2270
|
-
}))),
|
|
2271
|
-
let t =
|
|
2272
|
-
return t === void 0 ?
|
|
2273
|
-
}),
|
|
2317
|
+
tables: e.tables.filter((e) => !dr.has(e.name))
|
|
2318
|
+
}))), pr = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", mr = /* @__PURE__ */ new WeakMap(), hr = (e) => w.suspend(() => {
|
|
2319
|
+
let t = mr.get(e);
|
|
2320
|
+
return t === void 0 ? gr(e).pipe(w.tap((t) => w.sync(() => mr.set(e, t)))) : w.succeed(t);
|
|
2321
|
+
}), gr = (e) => e.unsafe("SELECT VERSION() AS v").pipe(w.map((e) => {
|
|
2274
2322
|
let t = e[0]?.v;
|
|
2275
|
-
return typeof t == "string" ?
|
|
2276
|
-
}),
|
|
2323
|
+
return typeof t == "string" ? pr(t) : "mysql";
|
|
2324
|
+
}), w.catchAll(() => w.succeed("mysql"))), _r = (e) => {
|
|
2277
2325
|
let t = e;
|
|
2278
2326
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2279
2327
|
let e = t;
|
|
2280
2328
|
if (typeof e.errno == "number") return e.errno;
|
|
2281
2329
|
t = e.cause;
|
|
2282
2330
|
}
|
|
2283
|
-
},
|
|
2331
|
+
}, vr = (e) => {
|
|
2284
2332
|
let t = [], n = e;
|
|
2285
2333
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2286
2334
|
let e = n;
|
|
2287
2335
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2288
2336
|
}
|
|
2289
2337
|
return t.join(" | ");
|
|
2290
|
-
},
|
|
2338
|
+
}, yr = (e, t) => {
|
|
2291
2339
|
if (t.length === 0) return !1;
|
|
2292
|
-
let n =
|
|
2340
|
+
let n = _r(e), r = vr(e);
|
|
2293
2341
|
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)));
|
|
2294
|
-
},
|
|
2342
|
+
}, br = {
|
|
2295
2343
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2296
2344
|
errno: [1061]
|
|
2297
|
-
},
|
|
2345
|
+
}, xr = {
|
|
2298
2346
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2299
2347
|
errno: [1091]
|
|
2300
|
-
},
|
|
2348
|
+
}, Sr = {
|
|
2301
2349
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2302
2350
|
messageIncludes: ["no such column"]
|
|
2303
|
-
},
|
|
2351
|
+
}, Cr = {
|
|
2304
2352
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2305
2353
|
errno: [1091, 3940]
|
|
2306
2354
|
}, U = (e, t) => e.onDialectOrElse({
|
|
2307
|
-
mysql: () =>
|
|
2308
|
-
orElse: () =>
|
|
2309
|
-
}),
|
|
2310
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2355
|
+
mysql: () => w.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2356
|
+
orElse: () => w.succeed(t)
|
|
2357
|
+
}), wr = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, Tr = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), Er = (e, t) => {
|
|
2358
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !Tr(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2311
2359
|
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;
|
|
2312
2360
|
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.`);
|
|
2313
2361
|
return M(e, t);
|
|
2314
|
-
},
|
|
2315
|
-
let t =
|
|
2316
|
-
return t === void 0 ?
|
|
2317
|
-
},
|
|
2362
|
+
}, Dr = (e) => {
|
|
2363
|
+
let t = Er(e, "postgres");
|
|
2364
|
+
return t === void 0 ? Or(e) : t;
|
|
2365
|
+
}, Or = (e) => {
|
|
2318
2366
|
switch (e.type) {
|
|
2319
2367
|
case "id": return "text";
|
|
2320
2368
|
case "text": return "text";
|
|
2321
2369
|
case "integer": return "integer";
|
|
2322
2370
|
case "real": return "double precision";
|
|
2323
|
-
case "decimal": return
|
|
2371
|
+
case "decimal": return wr(e, "NUMERIC");
|
|
2324
2372
|
case "bigint": return "bigint";
|
|
2325
2373
|
case "boolean": return "boolean";
|
|
2326
2374
|
case "timestamp": return "timestamptz";
|
|
@@ -2334,15 +2382,15 @@ BEGIN
|
|
|
2334
2382
|
case "interval": return "interval";
|
|
2335
2383
|
case "raw": return e.rawDdl ?? "text";
|
|
2336
2384
|
}
|
|
2337
|
-
},
|
|
2338
|
-
let t =
|
|
2385
|
+
}, kr = (e) => {
|
|
2386
|
+
let t = Er(e, "mariadb");
|
|
2339
2387
|
if (t !== void 0) return t;
|
|
2340
2388
|
switch (e.type) {
|
|
2341
2389
|
case "id": return "VARCHAR(64)";
|
|
2342
2390
|
case "text": return "LONGTEXT";
|
|
2343
2391
|
case "integer": return "INT";
|
|
2344
2392
|
case "real": return "DOUBLE";
|
|
2345
|
-
case "decimal": return
|
|
2393
|
+
case "decimal": return wr(e, "DECIMAL");
|
|
2346
2394
|
case "bigint": return "BIGINT";
|
|
2347
2395
|
case "boolean": return "TINYINT(1)";
|
|
2348
2396
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2356,38 +2404,38 @@ BEGIN
|
|
|
2356
2404
|
case "interval": return "BIGINT";
|
|
2357
2405
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2358
2406
|
}
|
|
2359
|
-
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2407
|
+
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``, Ar = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", jr = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, Mr = (e, t = "mariadb") => `ALTER TABLE ${G(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${G(e.column)}, ALGORITHM=COPY;`, Nr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Pr = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${li(t)}`)};`, Fr = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Lr(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, Ir = (e, t) => {
|
|
2360
2408
|
let { defaultFactory: n, ...r } = e;
|
|
2361
2409
|
return M(e, t) !== M({
|
|
2362
2410
|
...r,
|
|
2363
2411
|
hasDefault: !1
|
|
2364
2412
|
}, t);
|
|
2365
|
-
},
|
|
2413
|
+
}, Lr = (e, t) => {
|
|
2366
2414
|
let n = t(e.defaultValue);
|
|
2367
2415
|
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.`);
|
|
2368
2416
|
return n;
|
|
2369
|
-
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2417
|
+
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Rr = (e, t, n) => {
|
|
2370
2418
|
let r = K(e, t, n);
|
|
2371
|
-
return r ?
|
|
2372
|
-
},
|
|
2373
|
-
let r = n ?? e.nullable, i =
|
|
2419
|
+
return r ? on(n, r) : void 0;
|
|
2420
|
+
}, zr = (e, t, n) => {
|
|
2421
|
+
let r = n ?? e.nullable, i = rt(e, "mariadb");
|
|
2374
2422
|
return [
|
|
2375
2423
|
G(t),
|
|
2376
2424
|
M(e, "mariadb"),
|
|
2377
2425
|
r ? null : "NOT NULL",
|
|
2378
2426
|
i
|
|
2379
2427
|
].filter(Boolean).join(" ");
|
|
2380
|
-
},
|
|
2428
|
+
}, Br = (e, t) => e == null ? null : Array.isArray(e) ? Vr(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, Vr = (e, t, n) => it(e, t ?? { type: "json" }, n), Hr = (e, t) => e == null ? null : Array.isArray(e) ? Vr(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, Ur = (e, t) => {
|
|
2381
2429
|
if (!e.generatedAs) return null;
|
|
2382
2430
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2383
2431
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2384
|
-
},
|
|
2432
|
+
}, Wr = (e) => {
|
|
2385
2433
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "postgres");
|
|
2386
|
-
let t =
|
|
2387
|
-
if (t) return `${W(e.name)} ${
|
|
2388
|
-
let n = [W(e.name),
|
|
2434
|
+
let t = Ur(e, "postgres");
|
|
2435
|
+
if (t) return `${W(e.name)} ${Dr(e)} ${t}`;
|
|
2436
|
+
let n = [W(e.name), Dr(e)];
|
|
2389
2437
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2390
|
-
let t =
|
|
2438
|
+
let t = Hr(e.defaultValue, e);
|
|
2391
2439
|
t && n.push(t);
|
|
2392
2440
|
}
|
|
2393
2441
|
return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
@@ -2396,24 +2444,24 @@ BEGIN
|
|
|
2396
2444
|
setNull: "SET NULL",
|
|
2397
2445
|
noAction: "NO ACTION"
|
|
2398
2446
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2399
|
-
},
|
|
2400
|
-
let t = e.columns.map((e) => ` ${
|
|
2401
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(
|
|
2447
|
+
}, Gr = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Kr = (e) => {
|
|
2448
|
+
let t = e.columns.map((e) => ` ${Wr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Gr(e, W)}\n)`];
|
|
2449
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(mi).join(", ")})${Y(t)}`);
|
|
2402
2450
|
return n;
|
|
2403
|
-
},
|
|
2404
|
-
let t =
|
|
2451
|
+
}, qr = 191, Jr = (e) => {
|
|
2452
|
+
let t = kr(e).toUpperCase();
|
|
2405
2453
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2406
|
-
},
|
|
2454
|
+
}, Yr = (e) => {
|
|
2407
2455
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "mariadb");
|
|
2408
|
-
let t =
|
|
2409
|
-
if (t) return `${G(e.name)} ${
|
|
2410
|
-
let n = [G(e.name),
|
|
2411
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2412
|
-
let t =
|
|
2456
|
+
let t = Ur(e, "mariadb");
|
|
2457
|
+
if (t) return `${G(e.name)} ${kr(e)} ${t}`;
|
|
2458
|
+
let n = [G(e.name), kr(e)];
|
|
2459
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !Jr(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2460
|
+
let t = Br(e.defaultValue, e);
|
|
2413
2461
|
t && n.push(t);
|
|
2414
2462
|
}
|
|
2415
2463
|
return n.join(" ");
|
|
2416
|
-
},
|
|
2464
|
+
}, Xr = (e) => e.columns.flatMap((t) => {
|
|
2417
2465
|
if (!t.references) return [];
|
|
2418
2466
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2419
2467
|
cascade: "CASCADE",
|
|
@@ -2422,27 +2470,27 @@ BEGIN
|
|
|
2422
2470
|
noAction: "NO ACTION"
|
|
2423
2471
|
}[t.references.onDelete]}` : "";
|
|
2424
2472
|
return [` CONSTRAINT ${G(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${G(t.name)}) REFERENCES ${G(t.references.table)} (${G(t.references.column)})${n}`];
|
|
2425
|
-
}),
|
|
2426
|
-
for (let n of e.indexes)
|
|
2473
|
+
}), Zr = (e, t = "mariadb") => {
|
|
2474
|
+
for (let n of e.indexes) _i(n, t);
|
|
2427
2475
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2428
|
-
let t =
|
|
2476
|
+
let t = fi(n.get(e));
|
|
2429
2477
|
return t === void 0 ? G(e) : `${G(e)}(${t})`;
|
|
2430
|
-
}, i = e.columns.map((e) => ` ${
|
|
2431
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
2432
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2478
|
+
}, i = e.columns.map((e) => ` ${Yr(e)}`).join(",\n"), a = Xr(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${o}${Gr(e, r)}\n)`];
|
|
2479
|
+
for (let n of e.columns) n.unique && n.type !== "id" && Jr(n) && s.push(`CREATE UNIQUE INDEX ${Ar(t)}${G(`${e.table}_${n.name}_key`)} ON ${G(e.table)} (${r(n.name)})`);
|
|
2480
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Ar(t)}${G(n.name)} ON ${G(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2433
2481
|
return s;
|
|
2434
|
-
},
|
|
2482
|
+
}, Qr = {
|
|
2435
2483
|
cascade: "CASCADE",
|
|
2436
2484
|
restrict: "RESTRICT",
|
|
2437
2485
|
setNull: "SET NULL",
|
|
2438
2486
|
noAction: "NO ACTION"
|
|
2439
|
-
},
|
|
2487
|
+
}, $r = {
|
|
2440
2488
|
cascade: "CASCADE",
|
|
2441
2489
|
restrict: "NO ACTION",
|
|
2442
2490
|
setNull: "SET NULL",
|
|
2443
2491
|
noAction: "NO ACTION"
|
|
2444
|
-
},
|
|
2445
|
-
let t =
|
|
2492
|
+
}, ei = (e) => {
|
|
2493
|
+
let t = Er(e, "sqlite");
|
|
2446
2494
|
if (t !== void 0) return t;
|
|
2447
2495
|
switch (e.type) {
|
|
2448
2496
|
case "integer":
|
|
@@ -2454,29 +2502,29 @@ BEGIN
|
|
|
2454
2502
|
case "bytes": return "BLOB";
|
|
2455
2503
|
default: return "TEXT";
|
|
2456
2504
|
}
|
|
2457
|
-
},
|
|
2505
|
+
}, ti = (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, ni = (e) => {
|
|
2458
2506
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "sqlite");
|
|
2459
|
-
let t =
|
|
2460
|
-
if (t) return `${W(e.name)} ${
|
|
2461
|
-
let n = [W(e.name),
|
|
2507
|
+
let t = Ur(e, "sqlite");
|
|
2508
|
+
if (t) return `${W(e.name)} ${ei(e)} ${t}`;
|
|
2509
|
+
let n = [W(e.name), ei(e)];
|
|
2462
2510
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2463
|
-
let t =
|
|
2511
|
+
let t = ti(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2464
2512
|
t && n.push(t);
|
|
2465
2513
|
}
|
|
2466
|
-
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${
|
|
2514
|
+
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Qr[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2467
2515
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2468
2516
|
n.push(`CHECK (${W(e.name)} IN (${t}))`);
|
|
2469
2517
|
}
|
|
2470
2518
|
return n.join(" ");
|
|
2471
|
-
},
|
|
2472
|
-
let t = e.columns.map((e) => ` ${
|
|
2519
|
+
}, ri = (e) => {
|
|
2520
|
+
let t = e.columns.map((e) => ` ${ni(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Gr(e, W)}\n)`];
|
|
2473
2521
|
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(W).join(", ")})${Y(t)}`);
|
|
2474
2522
|
return n;
|
|
2475
2523
|
}, q = (e, t) => {
|
|
2476
2524
|
let n = t.find((t) => t.tableName === e);
|
|
2477
2525
|
if (!n) return [];
|
|
2478
|
-
let r =
|
|
2479
|
-
...
|
|
2526
|
+
let r = R([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => W(e.name)).join(", "), o = [
|
|
2527
|
+
...ri({
|
|
2480
2528
|
kind: "create-table",
|
|
2481
2529
|
table: i,
|
|
2482
2530
|
columns: r.columns,
|
|
@@ -2489,25 +2537,25 @@ BEGIN
|
|
|
2489
2537
|
];
|
|
2490
2538
|
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e)} (${t.columns.map(W).join(", ")})${Y(t)}`);
|
|
2491
2539
|
return o;
|
|
2492
|
-
},
|
|
2540
|
+
}, ii = (e, t, n, r) => {
|
|
2493
2541
|
let i = r ?? e.nullable;
|
|
2494
2542
|
return `ALTER TABLE ${J(n)} ALTER COLUMN ${J(t)} ${M(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2495
|
-
},
|
|
2543
|
+
}, ai = (e, t) => {
|
|
2496
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 ${J(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
2497
2545
|
if (!e.hasDefault) return n;
|
|
2498
|
-
let r =
|
|
2546
|
+
let r = ti(e.defaultValue, "SYSUTCDATETIME()");
|
|
2499
2547
|
if (!r) return n;
|
|
2500
2548
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2501
2549
|
return `${n} ALTER TABLE ${J(e.table)} ADD DEFAULT ${i} FOR ${J(e.column)};`;
|
|
2502
|
-
}, J = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2503
|
-
let t =
|
|
2550
|
+
}, J = (e) => `[${e.replace(/]/g, "]]")}]`, oi = (e) => {
|
|
2551
|
+
let t = Er(e, "mssql");
|
|
2504
2552
|
if (t !== void 0) return t;
|
|
2505
2553
|
switch (e.type) {
|
|
2506
2554
|
case "id": return "NVARCHAR(64)";
|
|
2507
2555
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
2508
2556
|
case "integer": return "INT";
|
|
2509
2557
|
case "real": return "FLOAT";
|
|
2510
|
-
case "decimal": return
|
|
2558
|
+
case "decimal": return wr(e, "DECIMAL");
|
|
2511
2559
|
case "bigint": return "BIGINT";
|
|
2512
2560
|
case "boolean": return "BIT";
|
|
2513
2561
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2515,46 +2563,46 @@ BEGIN
|
|
|
2515
2563
|
case "bytes": return "VARBINARY(MAX)";
|
|
2516
2564
|
default: return "NVARCHAR(MAX)";
|
|
2517
2565
|
}
|
|
2518
|
-
},
|
|
2566
|
+
}, si = (e, t) => {
|
|
2519
2567
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return P(e.name, "mssql");
|
|
2520
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2568
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : oi(e), r = Ur(e, "mssql");
|
|
2521
2569
|
if (r) return `${J(e.name)} ${r}`;
|
|
2522
2570
|
let i = [J(e.name), n];
|
|
2523
2571
|
if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
|
|
2524
|
-
let t =
|
|
2572
|
+
let t = ti(e.defaultValue, "SYSUTCDATETIME()");
|
|
2525
2573
|
t && i.push(t);
|
|
2526
2574
|
}
|
|
2527
|
-
return e.references && (i.push(`REFERENCES ${J(e.references.table)} (${J(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2528
|
-
},
|
|
2529
|
-
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((e) => ` ${
|
|
2575
|
+
return e.references && (i.push(`REFERENCES ${J(e.references.table)} (${J(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${$r[e.references.onDelete]}`)), i.join(" ");
|
|
2576
|
+
}, ci = (e) => {
|
|
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((e) => ` ${si(e, n)}`).join(",\n"), i = `CREATE TABLE ${J(e.table)} (\n${r}${Gr(e, J)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2530
2578
|
for (let n of e.indexes) {
|
|
2531
2579
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2532
2580
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${J(n.name)} ON ${J(e.table)} (${n.columns.map(J).join(", ")})${Y(n)}`;
|
|
2533
2581
|
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)}')`);
|
|
2534
2582
|
}
|
|
2535
2583
|
return a;
|
|
2536
|
-
},
|
|
2537
|
-
let r = `${e.table}${
|
|
2584
|
+
}, li = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, ui = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, di = (e, t, n) => {
|
|
2585
|
+
let r = `${e.table}${li(t)}`;
|
|
2538
2586
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2539
|
-
},
|
|
2540
|
-
if (e === void 0 || !
|
|
2587
|
+
}, fi = (e) => {
|
|
2588
|
+
if (e === void 0 || !Jr(e)) return;
|
|
2541
2589
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2542
|
-
return t === void 0 ?
|
|
2543
|
-
},
|
|
2544
|
-
let r =
|
|
2590
|
+
return t === void 0 ? qr : Math.min(qr, t);
|
|
2591
|
+
}, pi = (e, t, n) => {
|
|
2592
|
+
let r = fi(Rr(e, t, n));
|
|
2545
2593
|
return r === void 0 ? G(n) : `${G(n)}(${r})`;
|
|
2546
|
-
},
|
|
2594
|
+
}, mi = (e) => e.startsWith("(") ? e : W(e), Y = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, hi = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)} (${e.index.columns.map(mi).join(", ")})${Y(e.index)};`, gi = (e, t, n = "mariadb") => (_i(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Ar(n)}${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map((n) => pi(t, e.table, n)).join(", ")});`), _i = (e, t) => {
|
|
2547
2595
|
if (e.where !== void 0) throw Error(`Partial index '${e.name}' is not supported by ${t}; uniqueActive must be lowered before applying the plan.`);
|
|
2548
|
-
},
|
|
2596
|
+
}, vi = (e) => `DROP INDEX IF EXISTS ${W(e.index)};`, yi = (e) => `DROP INDEX ${G(e.index)} ON ${G(e.table)};`, bi = (e) => `DROP INDEX IF EXISTS ${J(e.index)} ON ${J(e.table)};`, xi = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, Si = (e) => {
|
|
2549
2597
|
let t = (e) => e.replace(/'/g, "''");
|
|
2550
2598
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2551
|
-
},
|
|
2599
|
+
}, Ci = (e) => `ALTER INDEX ${W(e.from)} RENAME TO ${W(e.to)};`, wi = (e) => `ALTER TABLE ${G(e.table)} RENAME INDEX ${G(e.from)} TO ${G(e.to)};`, Ti = (e) => {
|
|
2552
2600
|
let t = (e) => e.replace(/'/g, "''");
|
|
2553
2601
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2554
|
-
},
|
|
2602
|
+
}, Ei = (e) => {
|
|
2555
2603
|
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${J(e.index.name)} ON ${J(e.table)} (${e.index.columns.map(J).join(", ")})${Y(e.index)}`;
|
|
2556
2604
|
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)}');`;
|
|
2557
|
-
},
|
|
2605
|
+
}, Di = (e, t, n) => {
|
|
2558
2606
|
let r = n.find((t) => t.tableName === e);
|
|
2559
2607
|
if (!r) return [];
|
|
2560
2608
|
let i = [];
|
|
@@ -2563,13 +2611,13 @@ BEGIN
|
|
|
2563
2611
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${J(e)} ALTER COLUMN ${J(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2564
2612
|
}
|
|
2565
2613
|
return i;
|
|
2566
|
-
},
|
|
2614
|
+
}, Oi = (e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${W(e.column)});`, ki = (e, t) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${pi(t, e.table, e.column)});`, Ai = (e) => {
|
|
2567
2615
|
let t = e.fields.map((e) => W(e)).join(", ");
|
|
2568
2616
|
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
|
|
2569
|
-
},
|
|
2570
|
-
let n = e.fields.map((n) =>
|
|
2617
|
+
}, ji = (e, t) => {
|
|
2618
|
+
let n = e.fields.map((n) => pi(t, e.table, n)).join(", ");
|
|
2571
2619
|
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
|
|
2572
|
-
},
|
|
2620
|
+
}, Mi = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(e.name)};`, Ni = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(e.name)};`, Pi = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_key`)};`, Fi = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(`${e.table}_${e.column}_key`)};`, Ii = (e, t) => {
|
|
2573
2621
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2574
2622
|
if (e.orphanPolicy) {
|
|
2575
2623
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2587,34 +2635,34 @@ BEGIN
|
|
|
2587
2635
|
setNull: "SET NULL",
|
|
2588
2636
|
noAction: "NO ACTION"
|
|
2589
2637
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2590
|
-
},
|
|
2638
|
+
}, Li = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_fkey`)};`, Ri = (e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(`${e.table}_${e.column}_fkey`)};`, zi = (e, t) => {
|
|
2591
2639
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2592
2640
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2593
|
-
},
|
|
2641
|
+
}, Bi = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Vi = (e, t) => w.gen(function* () {
|
|
2594
2642
|
let n = yield* e`
|
|
2595
2643
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2596
2644
|
FROM information_schema.check_constraints cc
|
|
2597
|
-
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(
|
|
2645
|
+
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(w.orElse(() => e`
|
|
2598
2646
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2599
2647
|
FROM information_schema.check_constraints cc
|
|
2600
2648
|
JOIN information_schema.table_constraints tc
|
|
2601
2649
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2602
2650
|
AND tc.constraint_name = cc.constraint_name
|
|
2603
|
-
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`),
|
|
2651
|
+
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`), w.orElseSucceed(() => []));
|
|
2604
2652
|
for (let e of n) {
|
|
2605
2653
|
let n = String(e.n ?? "");
|
|
2606
|
-
if (n !== "" &&
|
|
2654
|
+
if (n !== "" && Gn(String(e.c ?? ""))?.column === t.column) return n;
|
|
2607
2655
|
}
|
|
2608
|
-
}),
|
|
2609
|
-
let r = yield*
|
|
2610
|
-
r !== void 0 && (yield* X(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [
|
|
2611
|
-
let i = yield*
|
|
2656
|
+
}), Hi = (e, t, n) => w.gen(function* () {
|
|
2657
|
+
let r = yield* Vi(e, t);
|
|
2658
|
+
r !== void 0 && (yield* X(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [Cr]));
|
|
2659
|
+
let i = yield* Vi(e, t);
|
|
2612
2660
|
if (i === void 0) return;
|
|
2613
2661
|
let a = K(n, t.table, t.column);
|
|
2614
|
-
if (!a) return yield*
|
|
2615
|
-
yield* X(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${
|
|
2616
|
-
}),
|
|
2617
|
-
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? J : W, s = a ?
|
|
2662
|
+
if (!a) return yield* w.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.`));
|
|
2663
|
+
yield* X(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${zr(a, t.column)};`, t.kind);
|
|
2664
|
+
}), Ui = (e, t, n, r) => {
|
|
2665
|
+
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? J : W, s = a ? kr(i) : r === "mssql" ? oi(i) : r === "sqlite" ? ei(i) : Dr(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? Br(e, i) : r === "mssql" ? ti(e, "SYSUTCDATETIME()") : r === "sqlite" ? ti(e, "CURRENT_TIMESTAMP") : Hr(e, i), u = Ur(i, r);
|
|
2618
2666
|
if (u) {
|
|
2619
2667
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2620
2668
|
return {
|
|
@@ -2642,7 +2690,7 @@ BEGIN
|
|
|
2642
2690
|
post: f ? [f] : []
|
|
2643
2691
|
};
|
|
2644
2692
|
return d?.sql && (p.backfillKind = "sql", p.backfillSql = d.sql), d?.js && (p.backfillKind = "js", p.backfillJs = d.js), d?.batchSize !== void 0 && (p.batchSize = d.batchSize), d?.sleepMs !== void 0 && (p.sleepMs = d.sleepMs), p;
|
|
2645
|
-
},
|
|
2693
|
+
}, Wi = (e) => {
|
|
2646
2694
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2647
2695
|
return (e, n) => {
|
|
2648
2696
|
let r = t.get(e);
|
|
@@ -2662,43 +2710,43 @@ BEGIN
|
|
|
2662
2710
|
...o
|
|
2663
2711
|
};
|
|
2664
2712
|
};
|
|
2665
|
-
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(
|
|
2666
|
-
process.stderr.write(
|
|
2667
|
-
})),
|
|
2668
|
-
let r =
|
|
2713
|
+
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(w.catchIf((e) => yr(e, r), () => w.void), w.tapError((e) => w.sync(() => {
|
|
2714
|
+
process.stderr.write(se(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2715
|
+
})), w.mapError((e) => {
|
|
2716
|
+
let r = se(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2669
2717
|
return Object.assign(e, { message: r });
|
|
2670
|
-
}),
|
|
2671
|
-
let n =
|
|
2672
|
-
if (!n) return yield*
|
|
2718
|
+
}), w.map(() => void 0)), Z = (e, t, n) => w.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(w.as(!0), w.catchAll(() => w.succeed(!1))), Gi = (e, t) => w.gen(function* () {
|
|
2719
|
+
let n = R([Be], t).tables[0];
|
|
2720
|
+
if (!n) return yield* w.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2673
2721
|
let r = {
|
|
2674
2722
|
kind: "create-table",
|
|
2675
2723
|
table: k,
|
|
2676
2724
|
columns: n.columns,
|
|
2677
2725
|
indexes: []
|
|
2678
2726
|
}, i = yield* e.onDialectOrElse({
|
|
2679
|
-
mysql: () =>
|
|
2680
|
-
mssql: () =>
|
|
2681
|
-
sqlite: () =>
|
|
2682
|
-
orElse: () =>
|
|
2727
|
+
mysql: () => hr(e).pipe(w.map((e) => Zr(r, e))),
|
|
2728
|
+
mssql: () => w.succeed(ci(r)),
|
|
2729
|
+
sqlite: () => w.succeed(ri(r)),
|
|
2730
|
+
orElse: () => w.succeed(Kr(r))
|
|
2683
2731
|
});
|
|
2684
|
-
yield*
|
|
2685
|
-
}),
|
|
2732
|
+
yield* w.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2733
|
+
}), Ki = (e) => e`
|
|
2686
2734
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2687
2735
|
${e("status")}, ${e("payload")}
|
|
2688
2736
|
FROM ${e(k)}
|
|
2689
|
-
`,
|
|
2737
|
+
`, qi = (e, t, n, r) => w.gen(function* () {
|
|
2690
2738
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2691
|
-
yield*
|
|
2739
|
+
yield* w.forEach(r, ({ index: r, planned: a }) => e`
|
|
2692
2740
|
INSERT INTO ${e(k)}
|
|
2693
2741
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2694
2742
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2695
2743
|
${e("createdAt")})
|
|
2696
2744
|
VALUES
|
|
2697
2745
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2698
|
-
${a.op.kind}, ${
|
|
2746
|
+
${a.op.kind}, ${He(a.op)}, ${"pending"},
|
|
2699
2747
|
${JSON.stringify(a)}, ${i})
|
|
2700
2748
|
`, { discard: !0 });
|
|
2701
|
-
}),
|
|
2749
|
+
}), Ji = (e, t, n, r, i) => w.gen(function* () {
|
|
2702
2750
|
let a = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2703
2751
|
if (r === "applied") {
|
|
2704
2752
|
yield* e`
|
|
@@ -2714,7 +2762,7 @@ BEGIN
|
|
|
2714
2762
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2715
2763
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2716
2764
|
`;
|
|
2717
|
-
}),
|
|
2765
|
+
}), Yi = (e, t, n, r) => w.gen(function* () {
|
|
2718
2766
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2719
2767
|
r.length > 0 && (yield* e`
|
|
2720
2768
|
UPDATE ${e(k)}
|
|
@@ -2725,35 +2773,35 @@ BEGIN
|
|
|
2725
2773
|
SET ${e("status")} = ${"pending"}
|
|
2726
2774
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2727
2775
|
`);
|
|
2728
|
-
}),
|
|
2729
|
-
if (
|
|
2776
|
+
}), Xi = (e, t) => t === void 0 ? e`DELETE FROM ${e(k)}`.pipe(w.asVoid) : e`DELETE FROM ${e(k)} WHERE ${e("runId")} = ${t}`.pipe(w.asVoid), Zi = (e, t, n) => w.gen(function* () {
|
|
2777
|
+
if (Xe(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
2730
2778
|
let r = n.op, i = (e) => o(e, t);
|
|
2731
2779
|
if (t === "sqlite" || t === "turso") {
|
|
2732
2780
|
if (!("table" in r)) return "clean";
|
|
2733
|
-
let n = `${r.table}${
|
|
2734
|
-
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*
|
|
2781
|
+
let n = `${r.table}${Ge}`;
|
|
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* w.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
2735
2783
|
}
|
|
2736
2784
|
if (r.kind !== "alter-column-type") return "clean";
|
|
2737
|
-
let a = `${r.column}${
|
|
2738
|
-
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*
|
|
2739
|
-
}),
|
|
2740
|
-
let i = process.hrtime.bigint(), a =
|
|
2785
|
+
let a = `${r.column}${Ke}`, s = `${r.column}${qe}`, c = yield* $(e, t, r.table, r.column), l = yield* $(e, t, r.table, a), u = yield* $(e, t, r.table, s), d = (e) => w.logWarning(`migration resume: ${e}`).pipe(w.annotateLogs({ scope: "voltro:migrate" }));
|
|
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* w.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.`));
|
|
2787
|
+
}), Qi = (e, t, n, r = "fresh") => w.gen(function* () {
|
|
2788
|
+
let i = process.hrtime.bigint(), a = Wi(n.declared), o = t.op;
|
|
2741
2789
|
switch (o.kind) {
|
|
2742
2790
|
case "create-table": {
|
|
2743
2791
|
let t = yield* e.onDialectOrElse({
|
|
2744
|
-
mysql: () =>
|
|
2745
|
-
mssql: () =>
|
|
2746
|
-
sqlite: () =>
|
|
2747
|
-
orElse: () =>
|
|
2792
|
+
mysql: () => hr(e).pipe(w.map((e) => Zr(o, e))),
|
|
2793
|
+
mssql: () => w.succeed(ci(o)),
|
|
2794
|
+
sqlite: () => w.succeed(ri(o)),
|
|
2795
|
+
orElse: () => w.succeed(Kr(o))
|
|
2748
2796
|
}), n = yield* e.onDialectOrElse({
|
|
2749
|
-
mysql: () =>
|
|
2750
|
-
orElse: () =>
|
|
2797
|
+
mysql: () => w.succeed([br]),
|
|
2798
|
+
orElse: () => w.succeed([])
|
|
2751
2799
|
});
|
|
2752
2800
|
for (let r of t) yield* X(e, r, o.kind, n);
|
|
2753
2801
|
break;
|
|
2754
2802
|
}
|
|
2755
2803
|
case "drop-table": {
|
|
2756
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2804
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? di(o, n, e) : ui(o, e);
|
|
2757
2805
|
yield* e.onDialectOrElse({
|
|
2758
2806
|
mysql: () => X(e, r(G), o.kind),
|
|
2759
2807
|
orElse: () => X(e, r(W), o.kind)
|
|
@@ -2763,93 +2811,93 @@ BEGIN
|
|
|
2763
2811
|
case "drop-column": {
|
|
2764
2812
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2765
2813
|
yield* e.onDialectOrElse({
|
|
2766
|
-
mysql: () =>
|
|
2767
|
-
sqlite: () => X(e, t ?
|
|
2768
|
-
orElse: () => X(e, t ?
|
|
2814
|
+
mysql: () => hr(e).pipe(w.flatMap((r) => X(e, t ? Pr(o, n, G) : Mr(o, r), o.kind, t ? [] : [xr]))),
|
|
2815
|
+
sqlite: () => X(e, t ? Pr(o, n, W) : jr(o, W, !1), o.kind, t ? [] : [Sr]),
|
|
2816
|
+
orElse: () => X(e, t ? Pr(o, n, W) : jr(o, W), o.kind)
|
|
2769
2817
|
});
|
|
2770
2818
|
break;
|
|
2771
2819
|
}
|
|
2772
2820
|
case "rename-column":
|
|
2773
2821
|
yield* e.onDialectOrElse({
|
|
2774
|
-
mysql: () => X(e,
|
|
2822
|
+
mysql: () => X(e, Nr(o, G), o.kind),
|
|
2775
2823
|
mssql: () => X(e, `EXEC sp_rename N'${o.table.replace(/'/g, "''")}.${o.from.replace(/'/g, "''")}', N'${o.to.replace(/'/g, "''")}', 'COLUMN';`, o.kind),
|
|
2776
|
-
orElse: () => X(e,
|
|
2824
|
+
orElse: () => X(e, Nr(o, W), o.kind)
|
|
2777
2825
|
});
|
|
2778
2826
|
break;
|
|
2779
2827
|
case "add-index":
|
|
2780
2828
|
yield* e.onDialectOrElse({
|
|
2781
|
-
sqlite: () => X(e,
|
|
2782
|
-
mysql: () =>
|
|
2783
|
-
mssql: () => Z(e, [...
|
|
2784
|
-
orElse: () => X(e,
|
|
2829
|
+
sqlite: () => X(e, hi(o, !1), o.kind),
|
|
2830
|
+
mysql: () => hr(e).pipe(w.flatMap((t) => X(e, gi(o, n.declared, t), o.kind, [br]))),
|
|
2831
|
+
mssql: () => Z(e, [...Di(o.table, o.index.columns, n.declared), Ei(o)], o.kind),
|
|
2832
|
+
orElse: () => X(e, hi(o, t.classification === "online-required"), o.kind)
|
|
2785
2833
|
});
|
|
2786
2834
|
break;
|
|
2787
2835
|
case "drop-index":
|
|
2788
2836
|
yield* e.onDialectOrElse({
|
|
2789
|
-
mysql: () => X(e,
|
|
2790
|
-
mssql: () => X(e,
|
|
2791
|
-
orElse: () => X(e,
|
|
2837
|
+
mysql: () => X(e, yi(o), o.kind),
|
|
2838
|
+
mssql: () => X(e, bi(o), o.kind),
|
|
2839
|
+
orElse: () => X(e, vi(o), o.kind)
|
|
2792
2840
|
});
|
|
2793
2841
|
break;
|
|
2794
2842
|
case "rename-table":
|
|
2795
2843
|
yield* e.onDialectOrElse({
|
|
2796
|
-
mysql: () => X(e,
|
|
2797
|
-
mssql: () => X(e,
|
|
2798
|
-
orElse: () => X(e,
|
|
2844
|
+
mysql: () => X(e, xi(o, G), o.kind),
|
|
2845
|
+
mssql: () => X(e, Si(o), o.kind),
|
|
2846
|
+
orElse: () => X(e, xi(o, W), o.kind)
|
|
2799
2847
|
});
|
|
2800
2848
|
break;
|
|
2801
2849
|
case "rename-index":
|
|
2802
2850
|
yield* e.onDialectOrElse({
|
|
2803
|
-
mysql: () => X(e,
|
|
2804
|
-
mssql: () => X(e,
|
|
2805
|
-
orElse: () => X(e,
|
|
2851
|
+
mysql: () => X(e, wi(o), o.kind),
|
|
2852
|
+
mssql: () => X(e, Ti(o), o.kind),
|
|
2853
|
+
orElse: () => X(e, Ci(o), o.kind)
|
|
2806
2854
|
});
|
|
2807
2855
|
break;
|
|
2808
2856
|
case "add-unique":
|
|
2809
2857
|
yield* e.onDialectOrElse({
|
|
2810
|
-
mysql: () => X(e,
|
|
2858
|
+
mysql: () => X(e, ki(o, n.declared), o.kind),
|
|
2811
2859
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2812
|
-
mssql: () => Z(e, [...
|
|
2813
|
-
orElse: () => X(e,
|
|
2860
|
+
mssql: () => Z(e, [...Di(o.table, [o.column], n.declared), Oi(o)], o.kind),
|
|
2861
|
+
orElse: () => X(e, Oi(o), o.kind)
|
|
2814
2862
|
});
|
|
2815
2863
|
break;
|
|
2816
2864
|
case "drop-unique":
|
|
2817
2865
|
yield* e.onDialectOrElse({
|
|
2818
|
-
mysql: () => X(e,
|
|
2866
|
+
mysql: () => X(e, Fi(o), o.kind),
|
|
2819
2867
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2820
|
-
orElse: () => X(e,
|
|
2868
|
+
orElse: () => X(e, Pi(o), o.kind)
|
|
2821
2869
|
});
|
|
2822
2870
|
break;
|
|
2823
2871
|
case "add-unique-composite":
|
|
2824
2872
|
yield* e.onDialectOrElse({
|
|
2825
|
-
mysql: () => X(e,
|
|
2873
|
+
mysql: () => X(e, ji(o, n.declared), o.kind),
|
|
2826
2874
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2827
|
-
mssql: () => Z(e, [...
|
|
2828
|
-
orElse: () => X(e,
|
|
2875
|
+
mssql: () => Z(e, [...Di(o.table, o.fields, n.declared), Ai(o)], o.kind),
|
|
2876
|
+
orElse: () => X(e, Ai(o), o.kind)
|
|
2829
2877
|
});
|
|
2830
2878
|
break;
|
|
2831
2879
|
case "drop-unique-composite":
|
|
2832
2880
|
yield* e.onDialectOrElse({
|
|
2833
|
-
mysql: () => X(e,
|
|
2881
|
+
mysql: () => X(e, Ni(o), o.kind),
|
|
2834
2882
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2835
|
-
orElse: () => X(e,
|
|
2883
|
+
orElse: () => X(e, Mi(o), o.kind)
|
|
2836
2884
|
});
|
|
2837
2885
|
break;
|
|
2838
2886
|
case "add-foreign-key":
|
|
2839
2887
|
yield* e.onDialectOrElse({
|
|
2840
|
-
mysql: () => Z(e,
|
|
2888
|
+
mysql: () => Z(e, Ii(o, G), o.kind),
|
|
2841
2889
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2842
|
-
orElse: () => Z(e,
|
|
2890
|
+
orElse: () => Z(e, Ii(o, W), o.kind)
|
|
2843
2891
|
});
|
|
2844
2892
|
break;
|
|
2845
2893
|
case "add-column": {
|
|
2846
|
-
let n =
|
|
2847
|
-
mysql: () =>
|
|
2848
|
-
mssql: () =>
|
|
2849
|
-
sqlite: () =>
|
|
2850
|
-
orElse: () =>
|
|
2894
|
+
let n = Ui(o, t, a, yield* e.onDialectOrElse({
|
|
2895
|
+
mysql: () => w.succeed("mariadb"),
|
|
2896
|
+
mssql: () => w.succeed("mssql"),
|
|
2897
|
+
sqlite: () => w.succeed("sqlite"),
|
|
2898
|
+
orElse: () => w.succeed("postgres")
|
|
2851
2899
|
}));
|
|
2852
|
-
if (!(r === "resume" && (yield* $(e,
|
|
2900
|
+
if (!(r === "resume" && (yield* $(e, Le(e), o.table, o.column.name)))) for (let t of n.pre) yield* X(e, t, o.kind);
|
|
2853
2901
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2854
2902
|
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2855
2903
|
else {
|
|
@@ -2858,10 +2906,10 @@ BEGIN
|
|
|
2858
2906
|
let s = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
2859
2907
|
if (s.length === 0) break;
|
|
2860
2908
|
let c = s.map((e) => e.id);
|
|
2861
|
-
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield*
|
|
2909
|
+
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield* w.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows`).pipe(w.annotateLogs({
|
|
2862
2910
|
scope: "voltro:migrate",
|
|
2863
2911
|
mode: "sql-batched"
|
|
2864
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2912
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* w.sleep(`${r} millis`));
|
|
2865
2913
|
}
|
|
2866
2914
|
}
|
|
2867
2915
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
@@ -2870,17 +2918,17 @@ BEGIN
|
|
|
2870
2918
|
let s = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
2871
2919
|
if (s.length === 0) break;
|
|
2872
2920
|
for (let t of s) {
|
|
2873
|
-
let r = yield*
|
|
2921
|
+
let r = yield* w.tryPromise({
|
|
2874
2922
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2875
2923
|
catch: (e) => e
|
|
2876
|
-
}).pipe(
|
|
2924
|
+
}).pipe(w.orDie);
|
|
2877
2925
|
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2878
2926
|
}
|
|
2879
|
-
a += s.length, yield*
|
|
2927
|
+
a += s.length, yield* w.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows processed`).pipe(w.annotateLogs({
|
|
2880
2928
|
scope: "voltro:migrate",
|
|
2881
2929
|
table: o.table,
|
|
2882
2930
|
column: o.column.name
|
|
2883
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2931
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* w.sleep(`${r} millis`));
|
|
2884
2932
|
}
|
|
2885
2933
|
}
|
|
2886
2934
|
for (let t of n.post) yield* X(e, t, o.kind);
|
|
@@ -2890,43 +2938,43 @@ BEGIN
|
|
|
2890
2938
|
yield* e.onDialectOrElse({
|
|
2891
2939
|
mysql: () => {
|
|
2892
2940
|
let t = K(n.declared, o.table, o.column);
|
|
2893
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2941
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${zr(t, o.column, o.toNullable)};`, o.kind) : w.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${o.table}.${o.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2894
2942
|
},
|
|
2895
2943
|
mssql: () => {
|
|
2896
2944
|
let t = K(n.declared, o.table, o.column);
|
|
2897
|
-
return t ? X(e,
|
|
2945
|
+
return t ? X(e, ii(t, o.column, o.table, o.toNullable), o.kind) : w.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2898
2946
|
},
|
|
2899
2947
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2900
2948
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2901
2949
|
});
|
|
2902
2950
|
break;
|
|
2903
2951
|
case "alter-column-default": {
|
|
2904
|
-
let t =
|
|
2952
|
+
let t = Rr(n.declared, o.table, o.column), r = K(n.declared, o.table, o.column), i = (e) => o.hasDefault && r !== void 0 && Ir(r, e) ? r : void 0;
|
|
2905
2953
|
yield* e.onDialectOrElse({
|
|
2906
2954
|
mysql: () => {
|
|
2907
2955
|
let n = i("mariadb");
|
|
2908
|
-
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2956
|
+
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${zr(n, o.column)};` : Fr(o, G, (e) => Br(e, t)), o.kind);
|
|
2909
2957
|
},
|
|
2910
2958
|
mssql: () => {
|
|
2911
2959
|
let t = i("mssql");
|
|
2912
|
-
return X(e,
|
|
2960
|
+
return X(e, ai(o, t ? ii(t, o.column, o.table) : void 0), o.kind);
|
|
2913
2961
|
},
|
|
2914
2962
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2915
|
-
orElse: () => X(e,
|
|
2963
|
+
orElse: () => X(e, Fr(o, W, (e) => Hr(e, t)), o.kind)
|
|
2916
2964
|
});
|
|
2917
2965
|
break;
|
|
2918
2966
|
}
|
|
2919
2967
|
case "alter-column-type": {
|
|
2920
|
-
let r =
|
|
2968
|
+
let r = Dr(Rr(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2921
2969
|
if (t.classification !== "online-required") {
|
|
2922
2970
|
yield* e.onDialectOrElse({
|
|
2923
2971
|
mysql: () => {
|
|
2924
2972
|
let t = K(n.declared, o.table, o.column);
|
|
2925
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2973
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${zr(t, o.column)};`, o.kind) : w.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${o.table}.${o.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2926
2974
|
},
|
|
2927
2975
|
mssql: () => {
|
|
2928
2976
|
let t = K(n.declared, o.table, o.column);
|
|
2929
|
-
return t ? X(e,
|
|
2977
|
+
return t ? X(e, ii(t, o.column, o.table), o.kind) : w.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2930
2978
|
},
|
|
2931
2979
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2932
2980
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} TYPE ${r}${i};`, o.kind)
|
|
@@ -2934,8 +2982,8 @@ BEGIN
|
|
|
2934
2982
|
break;
|
|
2935
2983
|
}
|
|
2936
2984
|
yield* e.onDialectOrElse({
|
|
2937
|
-
mysql: () =>
|
|
2938
|
-
orElse: () =>
|
|
2985
|
+
mysql: () => w.die(/* @__PURE__ */ Error(`online-required alter-column-type on ${o.table}.${o.column} is not supported on mariadb (the shadow-swap path is postgres-only). Use a smaller-table window or an external online-DDL tool.`)),
|
|
2986
|
+
orElse: () => w.void
|
|
2939
2987
|
});
|
|
2940
2988
|
let a = `${o.column}__shadow`, s = `${o.column}__old`;
|
|
2941
2989
|
yield* e.unsafe(`ALTER TABLE ${W(o.table)} ADD COLUMN ${W(a)} ${r}`);
|
|
@@ -2945,27 +2993,27 @@ BEGIN
|
|
|
2945
2993
|
if (t.length === 0) break;
|
|
2946
2994
|
yield* e.unsafe(`UPDATE ${W(o.table)} SET ${W(a)} = ${c} WHERE ${W(o.column)} IS NOT NULL AND ${W(a)} IS NULL AND ${W("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
2947
2995
|
}
|
|
2948
|
-
yield*
|
|
2996
|
+
yield* w.logInfo(`alter-column-type shadow ${o.table}.${o.column}: shadow populated`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${W(o.table)} RENAME COLUMN ${W(o.column)} TO ${W(s)}`), yield* e.unsafe(`ALTER TABLE ${W(o.table)} RENAME COLUMN ${W(a)} TO ${W(o.column)}`), yield* e.unsafe(`ALTER TABLE ${W(o.table)} DROP COLUMN ${W(s)}`);
|
|
2949
2997
|
break;
|
|
2950
2998
|
}
|
|
2951
2999
|
case "drop-foreign-key":
|
|
2952
3000
|
yield* e.onDialectOrElse({
|
|
2953
|
-
mysql: () => X(e,
|
|
3001
|
+
mysql: () => X(e, Ri(o), o.kind),
|
|
2954
3002
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2955
|
-
orElse: () => X(e,
|
|
3003
|
+
orElse: () => X(e, Li(o), o.kind)
|
|
2956
3004
|
});
|
|
2957
3005
|
break;
|
|
2958
3006
|
case "add-check":
|
|
2959
3007
|
yield* e.onDialectOrElse({
|
|
2960
|
-
mysql: () => X(e,
|
|
3008
|
+
mysql: () => X(e, zi(o, G), o.kind),
|
|
2961
3009
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2962
|
-
orElse: () => X(e,
|
|
3010
|
+
orElse: () => X(e, zi(o, W), o.kind)
|
|
2963
3011
|
});
|
|
2964
3012
|
break;
|
|
2965
3013
|
case "drop-check": yield* e.onDialectOrElse({
|
|
2966
|
-
mysql: () =>
|
|
3014
|
+
mysql: () => Hi(e, o, n.declared),
|
|
2967
3015
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2968
|
-
orElse: () => X(e,
|
|
3016
|
+
orElse: () => X(e, Bi(o), o.kind)
|
|
2969
3017
|
});
|
|
2970
3018
|
}
|
|
2971
3019
|
return {
|
|
@@ -2973,32 +3021,32 @@ BEGIN
|
|
|
2973
3021
|
status: "applied",
|
|
2974
3022
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2975
3023
|
};
|
|
2976
|
-
}),
|
|
3024
|
+
}), $i = (e, t, n, r) => w.gen(function* () {
|
|
2977
3025
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2978
|
-
if (i.length > 1) return yield*
|
|
3026
|
+
if (i.length > 1) return yield* w.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.`));
|
|
2979
3027
|
let a = i[0], o = [...r].map((e) => ({
|
|
2980
3028
|
index: Number(e.opIndex),
|
|
2981
3029
|
status: e.status,
|
|
2982
3030
|
planned: JSON.parse(e.payload)
|
|
2983
3031
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
2984
|
-
if (c > 1) return yield*
|
|
2985
|
-
if (yield*
|
|
3032
|
+
if (c > 1) return yield* w.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.`));
|
|
3033
|
+
if (yield* w.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} ${He(s.planned.op)}` : ""}`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
2986
3034
|
kind: "discard",
|
|
2987
3035
|
runId: a,
|
|
2988
3036
|
why: "no operation had started — no DDL ran"
|
|
2989
3037
|
};
|
|
2990
|
-
let l = s ? yield*
|
|
3038
|
+
let l = s ? yield* Zi(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2991
3039
|
if (u !== n.toFingerprint) return {
|
|
2992
3040
|
kind: "discard",
|
|
2993
3041
|
runId: a,
|
|
2994
3042
|
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`
|
|
2995
3043
|
};
|
|
2996
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
3044
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : We(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
2997
3045
|
return f.length === 0 ? {
|
|
2998
3046
|
kind: "discard",
|
|
2999
3047
|
runId: a,
|
|
3000
3048
|
why: "every recorded operation had already taken effect"
|
|
3001
|
-
} : (yield*
|
|
3049
|
+
} : (yield* Yi(e, a, f.map((e) => e.index), p.map((e) => e.index)), yield* w.logWarning(`migration resume: continuing run ${a} — replaying ${f.length} operation(s), ${o.length - f.length} already applied`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), {
|
|
3002
3050
|
kind: "resume",
|
|
3003
3051
|
runId: a,
|
|
3004
3052
|
ops: f.map((e) => ({
|
|
@@ -3006,7 +3054,7 @@ BEGIN
|
|
|
3006
3054
|
planned: e.planned
|
|
3007
3055
|
}))
|
|
3008
3056
|
});
|
|
3009
|
-
}),
|
|
3057
|
+
}), ea = (e, t, n) => w.gen(function* () {
|
|
3010
3058
|
for (let r of t.operations) {
|
|
3011
3059
|
let i = r.op;
|
|
3012
3060
|
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 && [
|
|
@@ -3015,9 +3063,9 @@ BEGIN
|
|
|
3015
3063
|
"rename-column"
|
|
3016
3064
|
].includes(e.op.kind))) continue;
|
|
3017
3065
|
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";
|
|
3018
|
-
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*
|
|
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* w.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.`));
|
|
3019
3067
|
}
|
|
3020
|
-
}),
|
|
3068
|
+
}), ta = (e) => {
|
|
3021
3069
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3022
3070
|
return [
|
|
3023
3071
|
t.kind,
|
|
@@ -3026,80 +3074,75 @@ BEGIN
|
|
|
3026
3074
|
n("name"),
|
|
3027
3075
|
n("to")
|
|
3028
3076
|
].join("\0");
|
|
3029
|
-
},
|
|
3077
|
+
}, na = (e, t, n) => w.acquireUseRelease(Fe(e, { schema: n.lockSchema }), () => ra(e, t, n), (e) => e.release.pipe(w.orDie)), ra = (e, t, n) => w.gen(function* () {
|
|
3030
3078
|
let r = t.operations.filter((e) => e.blocked);
|
|
3031
|
-
if (r.length > 0) return yield*
|
|
3032
|
-
yield*
|
|
3033
|
-
let i = Date.now(), a = [], o = Fe(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => Yi(e))), l = {
|
|
3079
|
+
if (r.length > 0) return yield* w.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
3080
|
+
let i = Date.now(), a = [], o = Le(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => ta(e))), l = {
|
|
3034
3081
|
...s,
|
|
3035
3082
|
operations: s.operations.map((e) => {
|
|
3036
|
-
if (!e.blocked || !c.has(
|
|
3083
|
+
if (!e.blocked || !c.has(ta(e))) return e;
|
|
3037
3084
|
let { blocked: t, ...n } = e;
|
|
3038
3085
|
return n;
|
|
3039
3086
|
})
|
|
3040
3087
|
};
|
|
3041
|
-
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield*
|
|
3088
|
+
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield* w.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(w.annotateLogs({ scope: "voltro:migrate" })));
|
|
3042
3089
|
let u = l.operations.filter((e) => e.blocked);
|
|
3043
|
-
if (u.length > 0) return yield*
|
|
3044
|
-
let d =
|
|
3090
|
+
if (u.length > 0) return yield* w.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.`));
|
|
3091
|
+
let d = ze(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) => ({
|
|
3045
3092
|
index: t,
|
|
3046
3093
|
planned: e
|
|
3047
3094
|
})), _ = "fresh";
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
let e = v.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");
|
|
3070
|
-
return yield* C.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 ${v.operations.length}:\n${e}${v.operations.length > 10 ? `\n … and ${v.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.`));
|
|
3071
|
-
}
|
|
3072
|
-
let y = a.filter((e) => e.status === "applied").length, b = Date.now() - i, x = m, S = (/* @__PURE__ */ new Date()).toISOString(), ee = yield* U(e, S), w = [...f, ...h.map((e) => e.planned)];
|
|
3095
|
+
yield* ea(e, l, o), yield* Gi(e, o);
|
|
3096
|
+
let v = yield* Ki(e);
|
|
3097
|
+
if (v.length > 0) {
|
|
3098
|
+
let t = yield* $i(e, o, l, v);
|
|
3099
|
+
t.kind === "resume" ? (m = t.runId, h = t.ops, _ = "resume") : (yield* w.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), yield* Xi(e, t.runId));
|
|
3100
|
+
}
|
|
3101
|
+
_ === "fresh" && h.length > 0 && (yield* qi(e, m, l.toFingerprint, h)), f.length > 0 && (yield* e.withTransaction(w.gen(function* () {
|
|
3102
|
+
let e = yield* E.SqlClient;
|
|
3103
|
+
for (let t of f) a.push(yield* Qi(e, t, n));
|
|
3104
|
+
})));
|
|
3105
|
+
for (let { index: t, planned: r } of h) {
|
|
3106
|
+
yield* Ji(e, m, t, "started");
|
|
3107
|
+
let i = a.length, o = yield* Qi(e, r, n, _).pipe(w.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`) })));
|
|
3108
|
+
a.push(o), yield* Ji(e, m, t, "applied", o.durationMs);
|
|
3109
|
+
}
|
|
3110
|
+
let y = yield* n.replan(e);
|
|
3111
|
+
if (y.operations.length > 0) {
|
|
3112
|
+
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* w.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
|
+
}
|
|
3115
|
+
let b = a.filter((e) => e.status === "applied").length, x = Date.now() - i, S = m, C = (/* @__PURE__ */ new Date()).toISOString(), T = yield* U(e, C), ee = [...f, ...h.map((e) => e.planned)];
|
|
3073
3116
|
yield* e`
|
|
3074
3117
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3075
3118
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
3076
3119
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
3077
3120
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
3078
3121
|
VALUES
|
|
3079
|
-
(${
|
|
3122
|
+
(${S}, ${l.toFingerprint}, ${y.fromFingerprint}, ${JSON.stringify(ee)},
|
|
3080
3123
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3081
|
-
${
|
|
3082
|
-
`, yield*
|
|
3083
|
-
let te = [...new Set(
|
|
3084
|
-
return yield*
|
|
3085
|
-
id:
|
|
3086
|
-
appliedAt:
|
|
3124
|
+
${x}, ${T}, ${n.notes ?? null})
|
|
3125
|
+
`, yield* Xi(e, m);
|
|
3126
|
+
let te = [...new Set(ee.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3127
|
+
return yield* w.promise(() => g({ changedTables: te }).catch(() => {})), {
|
|
3128
|
+
id: S,
|
|
3129
|
+
appliedAt: C,
|
|
3087
3130
|
fingerprint: l.toFingerprint,
|
|
3088
|
-
operations:
|
|
3131
|
+
operations: ee,
|
|
3089
3132
|
appliedBy: n.appliedBy,
|
|
3090
3133
|
environment: n.environment,
|
|
3091
|
-
durationMs:
|
|
3092
|
-
appliedOps:
|
|
3134
|
+
durationMs: x,
|
|
3135
|
+
appliedOps: b,
|
|
3093
3136
|
source: n.source,
|
|
3094
3137
|
...n.notes ? { notes: n.notes } : {}
|
|
3095
3138
|
};
|
|
3096
|
-
}),
|
|
3139
|
+
}), ia = (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"), aa = (e) => e`
|
|
3097
3140
|
SELECT fingerprint
|
|
3098
3141
|
FROM _voltro_migration_plans
|
|
3099
3142
|
ORDER BY ${e("appliedAt")} DESC
|
|
3100
3143
|
LIMIT 1
|
|
3101
|
-
`.pipe(
|
|
3102
|
-
if ((yield*
|
|
3144
|
+
`.pipe(w.map((e) => e.length > 0 ? e[0].fingerprint : void 0), w.catchAll(() => w.succeed(void 0))), oa = (e, t, n) => w.gen(function* () {
|
|
3145
|
+
if ((yield* aa(e)) === t.toFingerprint) return "already-current";
|
|
3103
3146
|
let r = `plan_${Date.now().toString(36)}`, i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3104
3147
|
return yield* e`
|
|
3105
3148
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3111,8 +3154,8 @@ BEGIN
|
|
|
3111
3154
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3112
3155
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3113
3156
|
`, "recorded";
|
|
3114
|
-
}).pipe(
|
|
3115
|
-
let n =
|
|
3157
|
+
}).pipe(w.catchAll(() => w.succeed("already-current"))), sa = (e, t) => w.gen(function* () {
|
|
3158
|
+
let n = L(R(t, Le(e))), r = yield* aa(e);
|
|
3116
3159
|
return r === n ? {
|
|
3117
3160
|
kind: "up-to-date",
|
|
3118
3161
|
fingerprint: n
|
|
@@ -3121,23 +3164,23 @@ BEGIN
|
|
|
3121
3164
|
expected: n,
|
|
3122
3165
|
...r === void 0 ? {} : { actual: r }
|
|
3123
3166
|
};
|
|
3124
|
-
}),
|
|
3167
|
+
}), ca = [
|
|
3125
3168
|
"pgeagertest_",
|
|
3126
3169
|
"mig_e2e_",
|
|
3127
3170
|
"mig_test_",
|
|
3128
3171
|
"mysqleagertest_",
|
|
3129
3172
|
"mssqleagertest_",
|
|
3130
3173
|
"sqliteeagertest_"
|
|
3131
|
-
],
|
|
3174
|
+
], la = (e) => ca.some((t) => e.startsWith(t)), ua = (e, t) => w.gen(function* () {
|
|
3132
3175
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3133
|
-
let n = t.filter((e) =>
|
|
3176
|
+
let n = t.filter((e) => la(e.name)).map((e) => e.name);
|
|
3134
3177
|
if (n.length === 0) return [];
|
|
3135
|
-
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(
|
|
3178
|
+
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(w.catchAll(() => w.void));
|
|
3136
3179
|
return n;
|
|
3137
|
-
}),
|
|
3180
|
+
}), da = () => {
|
|
3138
3181
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3139
3182
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3140
|
-
},
|
|
3183
|
+
}, fa = (e) => {
|
|
3141
3184
|
if (e === void 0) return;
|
|
3142
3185
|
let t = e.trim();
|
|
3143
3186
|
if (t === "") return;
|
|
@@ -3147,55 +3190,55 @@ BEGIN
|
|
|
3147
3190
|
kind: "tables",
|
|
3148
3191
|
tables: new Set(n)
|
|
3149
3192
|
} : void 0;
|
|
3150
|
-
},
|
|
3193
|
+
}, pa = (e) => typeof e.table == "string" ? e.table : void 0, ma = (e, t = { kind: "all" }) => ({
|
|
3151
3194
|
...e,
|
|
3152
3195
|
operations: e.operations.map((e) => {
|
|
3153
3196
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3154
3197
|
if (t?.kind === "tables") {
|
|
3155
|
-
let n =
|
|
3198
|
+
let n = pa(e.op);
|
|
3156
3199
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3157
3200
|
}
|
|
3158
3201
|
let { blocked: n, ...r } = e;
|
|
3159
3202
|
return r;
|
|
3160
3203
|
})
|
|
3161
|
-
}),
|
|
3162
|
-
let t =
|
|
3163
|
-
return t === void 0 ?
|
|
3164
|
-
}),
|
|
3165
|
-
let r =
|
|
3204
|
+
}), ha = (e, t, n) => t === "postgres" ? dn(e, n).pipe(w.flatMap((e) => {
|
|
3205
|
+
let t = fn(e);
|
|
3206
|
+
return t === void 0 ? w.void : w.logWarning(`auto-migrate: ${t}`).pipe(w.annotateLogs({ scope: "voltro:migrate" }));
|
|
3207
|
+
}), w.catchAll(() => w.void)) : w.void, ga = (e, t, n) => w.gen(function* () {
|
|
3208
|
+
let r = Le(e), a = t;
|
|
3166
3209
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3167
|
-
let t =
|
|
3168
|
-
if ((yield*
|
|
3210
|
+
let t = L(R(a, r));
|
|
3211
|
+
if ((yield* aa(e)) === t) return yield* ha(e, r, a), {
|
|
3169
3212
|
kind: "up-to-date",
|
|
3170
3213
|
fingerprint: t
|
|
3171
3214
|
};
|
|
3172
3215
|
}
|
|
3173
|
-
let o = yield*
|
|
3174
|
-
s.length > 0 && (yield*
|
|
3216
|
+
let o = yield* fr(e), s = yield* ua(e, o.tables);
|
|
3217
|
+
s.length > 0 && (yield* w.logInfo(`auto-migrate: reaped ${s.length} test-fixture leftover(s)`).pipe(w.annotateLogs({
|
|
3175
3218
|
scope: "voltro:migrate",
|
|
3176
3219
|
count: s.length
|
|
3177
|
-
})), o = yield*
|
|
3220
|
+
})), o = yield* fr(e));
|
|
3178
3221
|
{
|
|
3179
3222
|
let e = n.softDropRetentionDays ?? 7, t = p(o, { retentionDays: e });
|
|
3180
|
-
t.length > 0 && (yield*
|
|
3223
|
+
t.length > 0 && (yield* w.logWarning(`auto-migrate: ${i(t, e)}`).pipe(w.annotateLogs({
|
|
3181
3224
|
scope: "voltro:migrate",
|
|
3182
3225
|
snapshots: t.map((e) => e.name)
|
|
3183
3226
|
})));
|
|
3184
3227
|
}
|
|
3185
|
-
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u =
|
|
3228
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u = Wn({
|
|
3186
3229
|
declared: a,
|
|
3187
3230
|
live: { tables: l(o.tables) },
|
|
3188
3231
|
dialect: r,
|
|
3189
|
-
...
|
|
3232
|
+
...da()
|
|
3190
3233
|
});
|
|
3191
3234
|
if (u.summary.blocked > 0) {
|
|
3192
|
-
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
3193
|
-
if (t === void 0 || !e || (u =
|
|
3235
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = fa(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3236
|
+
if (t === void 0 || !e || (u = ma(u, t), u.operations.some((e) => e.blocked))) return {
|
|
3194
3237
|
kind: "refused-blocked",
|
|
3195
3238
|
plan: u
|
|
3196
3239
|
};
|
|
3197
3240
|
}
|
|
3198
|
-
return u.operations.length === 0 ? (yield*
|
|
3241
|
+
return u.operations.length === 0 ? (yield* oa(e, u, {
|
|
3199
3242
|
appliedBy: n.appliedBy,
|
|
3200
3243
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3201
3244
|
source: "auto-diff"
|
|
@@ -3204,37 +3247,37 @@ BEGIN
|
|
|
3204
3247
|
fingerprint: u.toFingerprint
|
|
3205
3248
|
}) : {
|
|
3206
3249
|
kind: "applied",
|
|
3207
|
-
applied: yield*
|
|
3250
|
+
applied: yield* na(e, u, {
|
|
3208
3251
|
declared: t,
|
|
3209
3252
|
appliedBy: n.appliedBy,
|
|
3210
3253
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3211
3254
|
source: "auto-diff",
|
|
3212
|
-
replan: (e) =>
|
|
3213
|
-
let t = yield*
|
|
3214
|
-
return
|
|
3255
|
+
replan: (e) => w.gen(function* () {
|
|
3256
|
+
let t = yield* fr(e);
|
|
3257
|
+
return Wn({
|
|
3215
3258
|
declared: a,
|
|
3216
3259
|
live: { tables: l(t.tables) },
|
|
3217
3260
|
dialect: r,
|
|
3218
|
-
...
|
|
3261
|
+
...da()
|
|
3219
3262
|
});
|
|
3220
3263
|
})
|
|
3221
3264
|
}),
|
|
3222
3265
|
plan: u
|
|
3223
3266
|
};
|
|
3224
|
-
}),
|
|
3267
|
+
}), _a = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? w.succeed({
|
|
3225
3268
|
kind: "skipped",
|
|
3226
3269
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3227
|
-
}) : n.environment === "prod" ?
|
|
3270
|
+
}) : n.environment === "prod" ? sa(e, t) : ga(e, t, n), va = (e, t) => {
|
|
3228
3271
|
switch (e.kind) {
|
|
3229
3272
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3230
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
3273
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${an(e.fingerprint)})`;
|
|
3231
3274
|
case "applied": {
|
|
3232
3275
|
let t = e.plan.summary;
|
|
3233
|
-
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=${
|
|
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=${an(e.applied.fingerprint)}`;
|
|
3234
3277
|
}
|
|
3235
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
3278
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${an(e.expected)}` + (e.actual ? ` live=${an(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
3236
3279
|
case "refused-blocked": {
|
|
3237
|
-
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` +
|
|
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` + ia(e.plan), c = [""];
|
|
3238
3281
|
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) {
|
|
3239
3282
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3240
3283
|
for (let r of e.plan.operations) {
|
|
@@ -3251,7 +3294,7 @@ BEGIN
|
|
|
3251
3294
|
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");
|
|
3252
3295
|
}
|
|
3253
3296
|
}
|
|
3254
|
-
},
|
|
3297
|
+
}, ya = re({ scope: "voltro:migrate" }), ba = /* @__PURE__ */ new Set([
|
|
3255
3298
|
"node_modules",
|
|
3256
3299
|
"dist",
|
|
3257
3300
|
"build",
|
|
@@ -3260,12 +3303,12 @@ BEGIN
|
|
|
3260
3303
|
".next",
|
|
3261
3304
|
".git",
|
|
3262
3305
|
".framework"
|
|
3263
|
-
]),
|
|
3306
|
+
]), xa = async (e) => {
|
|
3264
3307
|
let t = [], n = async (e) => {
|
|
3265
|
-
let r = await
|
|
3308
|
+
let r = await ie.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3266
3309
|
for (let i of r) {
|
|
3267
|
-
if (
|
|
3268
|
-
let r =
|
|
3310
|
+
if (ba.has(i.name)) continue;
|
|
3311
|
+
let r = ae(e, i.name);
|
|
3269
3312
|
i.isDirectory() ? await n(r) : i.isFile() && S.test(i.name) && t.push(r);
|
|
3270
3313
|
}
|
|
3271
3314
|
};
|
|
@@ -3273,12 +3316,12 @@ BEGIN
|
|
|
3273
3316
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3274
3317
|
return n.localeCompare(r);
|
|
3275
3318
|
});
|
|
3276
|
-
},
|
|
3319
|
+
}, Sa = async (e) => {
|
|
3277
3320
|
let t = [];
|
|
3278
3321
|
for (let n of e) {
|
|
3279
|
-
let e = (await import(
|
|
3322
|
+
let e = (await import(oe(n).href)).default;
|
|
3280
3323
|
if (!u(e)) {
|
|
3281
|
-
|
|
3324
|
+
ya.warn("migration file has no default-exported `migration(...)` — skipped", { file: n });
|
|
3282
3325
|
continue;
|
|
3283
3326
|
}
|
|
3284
3327
|
t.push({
|
|
@@ -3287,11 +3330,11 @@ BEGIN
|
|
|
3287
3330
|
});
|
|
3288
3331
|
}
|
|
3289
3332
|
return t;
|
|
3290
|
-
},
|
|
3333
|
+
}, Ca = (e) => e`
|
|
3291
3334
|
SELECT ${e("id")}
|
|
3292
3335
|
FROM ${e("_voltro_migration_plans")}
|
|
3293
3336
|
WHERE ${e("source")} = 'file'
|
|
3294
|
-
`.pipe(
|
|
3337
|
+
`.pipe(w.map((e) => e.map((e) => e.id)), w.catchAll(() => w.succeed([]))), wa = class extends Error {
|
|
3295
3338
|
migrationId;
|
|
3296
3339
|
file;
|
|
3297
3340
|
cause;
|
|
@@ -3299,27 +3342,27 @@ BEGIN
|
|
|
3299
3342
|
constructor(e, t, n) {
|
|
3300
3343
|
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";
|
|
3301
3344
|
}
|
|
3302
|
-
},
|
|
3345
|
+
}, Ta = (e, t, n, r) => w.gen(function* () {
|
|
3303
3346
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3304
3347
|
sql: e,
|
|
3305
3348
|
log: {
|
|
3306
|
-
info: (e, n) =>
|
|
3349
|
+
info: (e, n) => w.logInfo(e).pipe(w.annotateLogs({
|
|
3307
3350
|
scope: `migrations:file:${t.migration.id}`,
|
|
3308
3351
|
...n ?? {}
|
|
3309
3352
|
})),
|
|
3310
|
-
warn: (e, n) =>
|
|
3353
|
+
warn: (e, n) => w.logWarning(e).pipe(w.annotateLogs({
|
|
3311
3354
|
scope: `migrations:file:${t.migration.id}`,
|
|
3312
3355
|
...n ?? {}
|
|
3313
3356
|
}))
|
|
3314
3357
|
},
|
|
3315
3358
|
appliedAt: a
|
|
3316
3359
|
}, s = t.migration.up(o);
|
|
3317
|
-
|
|
3360
|
+
w.isEffect(s) ? yield* s : yield* w.tryPromise({
|
|
3318
3361
|
try: () => s,
|
|
3319
3362
|
catch: (e) => e
|
|
3320
3363
|
});
|
|
3321
3364
|
let c = Date.now() - i;
|
|
3322
|
-
!
|
|
3365
|
+
!w.isEffect(s) && c < 2 && (yield* w.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(w.annotateLogs({ scope: `migrations:file:${t.migration.id}` })));
|
|
3323
3366
|
let l = yield* U(e, a);
|
|
3324
3367
|
return yield* e`
|
|
3325
3368
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3333,116 +3376,107 @@ BEGIN
|
|
|
3333
3376
|
}])},
|
|
3334
3377
|
${r}, ${n}, ${"file"},
|
|
3335
3378
|
${c}, ${l}, ${t.migration.description})
|
|
3336
|
-
`.pipe(
|
|
3337
|
-
}),
|
|
3338
|
-
let n = yield*
|
|
3339
|
-
try: () =>
|
|
3379
|
+
`.pipe(w.mapError((e) => new wa(t.migration.id, t.file, e))), { durationMs: c };
|
|
3380
|
+
}), Ea = (e, t) => w.gen(function* () {
|
|
3381
|
+
let n = yield* w.tryPromise({
|
|
3382
|
+
try: () => xa(ae(t, "migrations")),
|
|
3340
3383
|
catch: (e) => e
|
|
3341
3384
|
});
|
|
3342
3385
|
if (n.length === 0) return {
|
|
3343
3386
|
pending: [],
|
|
3344
3387
|
skipped: []
|
|
3345
3388
|
};
|
|
3346
|
-
let r = yield*
|
|
3347
|
-
try: () =>
|
|
3389
|
+
let r = yield* w.tryPromise({
|
|
3390
|
+
try: () => Sa(n),
|
|
3348
3391
|
catch: (e) => e
|
|
3349
3392
|
});
|
|
3350
3393
|
if (r.length === 0) return {
|
|
3351
3394
|
pending: [],
|
|
3352
3395
|
skipped: []
|
|
3353
3396
|
};
|
|
3354
|
-
let i = new Set(yield*
|
|
3397
|
+
let i = new Set(yield* Ca(e));
|
|
3355
3398
|
return {
|
|
3356
3399
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3357
3400
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3358
3401
|
};
|
|
3359
|
-
}),
|
|
3360
|
-
let { pending: n, skipped: r } = yield*
|
|
3361
|
-
|
|
3402
|
+
}), Da = (e, t) => Ea(e, t).pipe(w.map((e) => e.pending.map((e) => e.migration.id))), Oa = (e, t) => w.gen(function* () {
|
|
3403
|
+
let { pending: n, skipped: r } = yield* Ea(e, t.projectRoot);
|
|
3404
|
+
return n.length === 0 ? {
|
|
3362
3405
|
applied: [],
|
|
3363
3406
|
skipped: r
|
|
3364
|
-
}
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
}
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
yield* O(e, { schema: t.lockSchema }).pipe(C.orDie);
|
|
3386
|
-
}
|
|
3387
|
-
return {
|
|
3388
|
-
applied: i,
|
|
3407
|
+
} : {
|
|
3408
|
+
applied: yield* w.acquireUseRelease(Fe(e, { schema: t.lockSchema }), () => w.gen(function* () {
|
|
3409
|
+
let r = [];
|
|
3410
|
+
for (let i of n) {
|
|
3411
|
+
yield* w.logInfo("file-based migration applying").pipe(w.annotateLogs({
|
|
3412
|
+
scope: "voltro:migrate",
|
|
3413
|
+
id: i.migration.id,
|
|
3414
|
+
file: i.file
|
|
3415
|
+
}));
|
|
3416
|
+
let { durationMs: n } = yield* Ta(e, i, t.env, t.appliedBy);
|
|
3417
|
+
r.push({
|
|
3418
|
+
id: i.migration.id,
|
|
3419
|
+
durationMs: n
|
|
3420
|
+
}), yield* w.logInfo("file-based migration applied").pipe(w.annotateLogs({
|
|
3421
|
+
scope: "voltro:migrate",
|
|
3422
|
+
id: i.migration.id,
|
|
3423
|
+
durationMs: n
|
|
3424
|
+
}));
|
|
3425
|
+
}
|
|
3426
|
+
return r;
|
|
3427
|
+
}), (e) => e.release.pipe(w.orDie)),
|
|
3389
3428
|
skipped: r
|
|
3390
3429
|
};
|
|
3391
|
-
}),
|
|
3430
|
+
}), ka = (e, t) => e`
|
|
3392
3431
|
SELECT ${e("id")}
|
|
3393
3432
|
FROM ${e("_voltro_migration_plans")}
|
|
3394
3433
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3395
3434
|
LIMIT 1
|
|
3396
|
-
`,
|
|
3397
|
-
if (!(yield*
|
|
3398
|
-
let n = yield*
|
|
3399
|
-
try: () =>
|
|
3435
|
+
`, Aa = (e, t) => w.gen(function* () {
|
|
3436
|
+
if (!(yield* ka(e, t.id))[0]) return yield* w.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3437
|
+
let n = yield* w.tryPromise({
|
|
3438
|
+
try: () => xa(ae(t.projectRoot, "migrations")),
|
|
3400
3439
|
catch: (e) => e
|
|
3401
|
-
}), r = (yield*
|
|
3402
|
-
try: () =>
|
|
3440
|
+
}), r = (yield* w.tryPromise({
|
|
3441
|
+
try: () => Sa(n),
|
|
3403
3442
|
catch: (e) => e
|
|
3404
3443
|
})).find((e) => e.migration.id === t.id);
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
let i = Date.now();
|
|
3408
|
-
try {
|
|
3409
|
-
let n = {
|
|
3444
|
+
return r ? yield* w.acquireUseRelease(Fe(e, { schema: t.lockSchema }), () => w.gen(function* () {
|
|
3445
|
+
let n = Date.now(), i = {
|
|
3410
3446
|
sql: e,
|
|
3411
3447
|
log: {
|
|
3412
|
-
info: (e, n) =>
|
|
3448
|
+
info: (e, n) => w.logInfo(e).pipe(w.annotateLogs({
|
|
3413
3449
|
scope: `migrations:file:${t.id}`,
|
|
3414
3450
|
...n ?? {}
|
|
3415
3451
|
})),
|
|
3416
|
-
warn: (e, n) =>
|
|
3452
|
+
warn: (e, n) => w.logWarning(e).pipe(w.annotateLogs({
|
|
3417
3453
|
scope: `migrations:file:${t.id}`,
|
|
3418
3454
|
...n ?? {}
|
|
3419
3455
|
}))
|
|
3420
3456
|
},
|
|
3421
3457
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3422
|
-
}, a = r.migration.down(
|
|
3423
|
-
|
|
3458
|
+
}, a = r.migration.down(i);
|
|
3459
|
+
w.isEffect(a) ? yield* a : yield* w.tryPromise({
|
|
3424
3460
|
try: () => a,
|
|
3425
3461
|
catch: (e) => e
|
|
3426
3462
|
});
|
|
3427
|
-
let o = Date.now() -
|
|
3463
|
+
let o = Date.now() - n;
|
|
3428
3464
|
return yield* e`DELETE FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t.id} AND ${e("source")} = 'file'`, {
|
|
3429
3465
|
id: t.id,
|
|
3430
3466
|
durationMs: o
|
|
3431
3467
|
};
|
|
3432
|
-
}
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
}), wa = (e) => C.gen(function* () {
|
|
3436
|
-
let t = yield* T.SqlClient, n = yield* t`
|
|
3468
|
+
}), (e) => e.release.pipe(w.orDie)) : yield* w.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
3469
|
+
}), ja = (e) => w.gen(function* () {
|
|
3470
|
+
let t = yield* E.SqlClient, n = yield* t`
|
|
3437
3471
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3438
3472
|
WHERE source = 'auto-diff'
|
|
3439
3473
|
AND squashedAt IS NULL
|
|
3440
3474
|
AND appliedAt < ${e.before}
|
|
3441
3475
|
ORDER BY appliedAt DESC
|
|
3442
3476
|
`;
|
|
3443
|
-
if (n.length === 0) return yield*
|
|
3477
|
+
if (n.length === 0) return yield* w.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3444
3478
|
let r = n[0];
|
|
3445
|
-
if (r.fingerprint !== e.fingerprint) return yield*
|
|
3479
|
+
if (r.fingerprint !== e.fingerprint) return yield* w.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.`));
|
|
3446
3480
|
yield* t`
|
|
3447
3481
|
UPDATE _voltro_migration_plans
|
|
3448
3482
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3477,7 +3511,7 @@ BEGIN
|
|
|
3477
3511
|
snapshotFingerprint: e.fingerprint,
|
|
3478
3512
|
snapshotId: i
|
|
3479
3513
|
};
|
|
3480
|
-
}),
|
|
3514
|
+
}), Ma = { safe: !0 }, Na = (e) => {
|
|
3481
3515
|
switch (e.kind) {
|
|
3482
3516
|
case "drop-column": return {
|
|
3483
3517
|
safe: !1,
|
|
@@ -3504,7 +3538,7 @@ BEGIN
|
|
|
3504
3538
|
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`,
|
|
3505
3539
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
3506
3540
|
};
|
|
3507
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3541
|
+
case "alter-column-nullability": return e.toNullable ? Ma : {
|
|
3508
3542
|
safe: !1,
|
|
3509
3543
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3510
3544
|
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)`
|
|
@@ -3534,12 +3568,12 @@ BEGIN
|
|
|
3534
3568
|
case "drop-unique":
|
|
3535
3569
|
case "drop-unique-composite":
|
|
3536
3570
|
case "drop-foreign-key":
|
|
3537
|
-
case "drop-check": return
|
|
3571
|
+
case "drop-check": return Ma;
|
|
3538
3572
|
}
|
|
3539
|
-
},
|
|
3573
|
+
}, Pa = (e) => {
|
|
3540
3574
|
let t = [];
|
|
3541
3575
|
for (let n of e) {
|
|
3542
|
-
let e =
|
|
3576
|
+
let e = Na(n.op);
|
|
3543
3577
|
e.safe || t.push({
|
|
3544
3578
|
op: n,
|
|
3545
3579
|
reason: e.reason,
|
|
@@ -3547,7 +3581,7 @@ BEGIN
|
|
|
3547
3581
|
});
|
|
3548
3582
|
}
|
|
3549
3583
|
return t;
|
|
3550
|
-
},
|
|
3584
|
+
}, Fa = (e) => {
|
|
3551
3585
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3552
3586
|
refuse: !1,
|
|
3553
3587
|
warnForced: !1,
|
|
@@ -3563,18 +3597,18 @@ BEGIN
|
|
|
3563
3597
|
warnForced: !1,
|
|
3564
3598
|
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.`
|
|
3565
3599
|
};
|
|
3566
|
-
},
|
|
3600
|
+
}, Ia = (e) => {
|
|
3567
3601
|
let t = e.table;
|
|
3568
3602
|
if (typeof t == "string") return t;
|
|
3569
3603
|
let n = e.from;
|
|
3570
3604
|
return typeof n == "string" ? n : void 0;
|
|
3571
|
-
},
|
|
3605
|
+
}, La = (e) => ({
|
|
3572
3606
|
kind: e.op.kind,
|
|
3573
|
-
table:
|
|
3607
|
+
table: Ia(e.op),
|
|
3574
3608
|
classification: e.classification,
|
|
3575
3609
|
reason: e.reason,
|
|
3576
3610
|
blockedFix: e.blocked?.fix
|
|
3577
|
-
}),
|
|
3611
|
+
}), Ra = (e) => e.operations.map(La), za = async (e) => {
|
|
3578
3612
|
let t = e.log ?? (() => {}), n = {
|
|
3579
3613
|
branchId: e.branchId,
|
|
3580
3614
|
mechanism: e.mechanism,
|
|
@@ -3593,10 +3627,10 @@ BEGIN
|
|
|
3593
3627
|
applied: !1,
|
|
3594
3628
|
converged: !1,
|
|
3595
3629
|
residual: r,
|
|
3596
|
-
infidelity:
|
|
3630
|
+
infidelity: Ra(o)
|
|
3597
3631
|
};
|
|
3598
3632
|
else {
|
|
3599
|
-
let i = await e.plan(), o =
|
|
3633
|
+
let i = await e.plan(), o = Ra(i), s = o.filter((e) => e.classification === "lossy"), c = ma(i), l = c.operations.filter((e) => e.blocked !== void 0).map(La);
|
|
3600
3634
|
if (l.length > 0) a = {
|
|
3601
3635
|
...n,
|
|
3602
3636
|
outcome: "blocked",
|
|
@@ -3621,7 +3655,7 @@ BEGIN
|
|
|
3621
3655
|
};
|
|
3622
3656
|
else {
|
|
3623
3657
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3624
|
-
let i =
|
|
3658
|
+
let i = Ra(await e.replan());
|
|
3625
3659
|
a = {
|
|
3626
3660
|
...n,
|
|
3627
3661
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3659,7 +3693,7 @@ BEGIN
|
|
|
3659
3693
|
...a,
|
|
3660
3694
|
tornDown: o
|
|
3661
3695
|
};
|
|
3662
|
-
},
|
|
3696
|
+
}, Ba = (e) => {
|
|
3663
3697
|
switch (e.outcome) {
|
|
3664
3698
|
case "clean": return 0;
|
|
3665
3699
|
case "lossy": return 2;
|
|
@@ -3668,22 +3702,22 @@ BEGIN
|
|
|
3668
3702
|
case "infidelity": return 1;
|
|
3669
3703
|
case "failed": return 1;
|
|
3670
3704
|
}
|
|
3671
|
-
},
|
|
3705
|
+
}, Va = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, Ha = (e) => {
|
|
3672
3706
|
let t = [];
|
|
3673
3707
|
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"}`);
|
|
3674
3708
|
else if (e.outcome === "infidelity") {
|
|
3675
3709
|
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:");
|
|
3676
|
-
for (let n of e.infidelity) t.push(
|
|
3710
|
+
for (let n of e.infidelity) t.push(Va(n));
|
|
3677
3711
|
} else {
|
|
3678
3712
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3679
|
-
for (let n of e.operations) t.push(
|
|
3680
|
-
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(
|
|
3713
|
+
for (let n of e.operations) t.push(Va(n));
|
|
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(Va(n));
|
|
3681
3715
|
}
|
|
3682
3716
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3683
|
-
},
|
|
3717
|
+
}, Ua = (e, ...t) => ({
|
|
3684
3718
|
_tag: "RawSqlFragment",
|
|
3685
3719
|
strings: [...e],
|
|
3686
3720
|
values: [...t]
|
|
3687
|
-
}),
|
|
3721
|
+
}), Wa = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3688
3722
|
//#endregion
|
|
3689
|
-
export { A as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN,
|
|
3723
|
+
export { A as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN, wa as FileMigrationLedgerError, Ze as REACTIVE_TRIGGER_PREFIX, he as VOLTRO_MIGRATION_LOCK_KEY, Fe as acquireMigrationLock, U as appliedAtValue, Vt as applyNamespacedSchema, na as applyPlan, jt as applySchema, Fa as assessRollingDeployGate, Ba as branchRehearsalExitCode, Qn as chunkTables, Na as classifyRollingDeploySafety, R as declaredSnapshot, it as defaultArrayClause, rt as defaultClause, N as defaultJsonClause, va as describeOutcome, fa as destructiveScope, dn as detectReactiveTriggerDrift, gi as emitAddIndexMysql, Zr as emitCreateTableMysql, jr as emitDropColumnDdl, Mr as emitDropColumnDdlMysql, At as emitFrameworkBootstrapSql, Ot as emitNamespaceProvisionDdl, kt as emitNamespacedSchemaSql, Dt as emitSchemaSql, pr as engineFromVersion, L as fingerprintSchema, xe as fnv1a64, Ha as formatBranchRehearsal, fn as formatReactiveTriggerDrift, da as ignoreTablesFromEnv, fr as introspectSchema, yr as isAlreadySatisfied, u as isFileMigration, Wa as isRawSqlFragment, Nt as isReRunSafeDdl, Kn as mapPgType, d as migration, Se as migrationLockKeyForSchema, Ce as migrationLockNameForSchema, fi as mysqlIndexPrefixFor, $e as notifyFunctionName, P as numericIdSql, Gn as parseEnumCheck, Da as pendingFileMigrationIds, Wn as planMigrations, Ht as provisionTenantNamespace, Qe as reactiveTriggerName, vt as reactiveTriggerRepairSql, oa as recordUpToDate, za as rehearseMigrationOnBranch, La as rehearsedOperation, Yr as renderColumnMysql, Wr as renderColumnPg, _e as resolveMigrationLockSchema, hr as resolveMysqlEngine, Aa as rollbackFileBasedMigration, Pa as rollingDeployUnsafeOps, Oa as runFileBasedMigrations, Ut as runFrameworkBootstrap, Bt as runMigrate, _a as runPlannedMigrations, an as shortFingerprint, on as snapshotColumn, Ua as sql, M as sqlType, ja as squashMigrationPlans, ma as unblockLossy, Ie as withMigrationLock };
|