@voltro/database 0.67.0 → 0.69.0
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 +437 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +38 -31
- package/dist/sql.d.ts +25 -9
- package/dist/sql.js +801 -819
- 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
|
|
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 ee, Schedule as te, Scope as ne } from "effect";
|
|
3
|
+
import { createHash as re } from "node:crypto";
|
|
4
|
+
import { createLogger as ie } from "@voltro/logger";
|
|
5
5
|
import { SqlClient as T } from "@effect/sql";
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
6
|
+
import { promises as ae } from "node:fs";
|
|
7
|
+
import { join as oe } from "node:path";
|
|
8
|
+
import { pathToFileURL as se } from "node:url";
|
|
9
9
|
//#region src/migrations/ddlError.ts
|
|
10
|
-
var
|
|
10
|
+
var ce = (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 = le(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
|
+
}, le = (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, ue = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, de = (e) => e.replace(/"/g, "`"), fe = (e) => typeof e == "string" ? e : e.name ?? String(e), pe = (e, t) => `_ua_${t}_${e}`.slice(0, 64), me = (e, t) => {
|
|
44
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(ue)) return e;
|
|
45
45
|
let n = { ...e.fields }, r = [], i = [];
|
|
46
46
|
for (let t of e.appliedIndexes) {
|
|
47
|
-
if (!
|
|
47
|
+
if (!ue(t)) {
|
|
48
48
|
r.push(t);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
|
-
let a =
|
|
51
|
+
let a = de(t.where), o = [];
|
|
52
52
|
for (let r of t.fields) {
|
|
53
|
-
let i =
|
|
53
|
+
let i = fe(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 = pe(t.name, i);
|
|
56
56
|
o.push(s), n[s] = {
|
|
57
57
|
type: "text",
|
|
58
58
|
nullable: !0,
|
|
@@ -75,7 +75,7 @@ var oe = (e, t, n, r = 400) => {
|
|
|
75
75
|
appliedIndexes: r,
|
|
76
76
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
77
77
|
};
|
|
78
|
-
}, E = (e, t) => `${e}::${t}`,
|
|
78
|
+
}, E = (e, t) => `${e}::${t}`, he = (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));
|
|
@@ -84,77 +84,73 @@ var oe = (e, t, n, r = 400) => {
|
|
|
84
84
|
};
|
|
85
85
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
86
86
|
return i;
|
|
87
|
-
},
|
|
87
|
+
}, D = (e, t) => e.executeUnprepared(t, [], void 0), ge = 6322741009312437n, _e = (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
|
+
}, ve = (e) => e?.schema === void 0 ? _e(process.env.DB_SCHEMA) : _e(e.schema), ye = 14695981039346656037n, be = 1099511628211n, xe = 18446744073709551615n, Se = (e) => {
|
|
91
|
+
let t = ye;
|
|
92
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * be & xe;
|
|
93
93
|
return t;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
return t === void 0 ?
|
|
97
|
-
},
|
|
98
|
-
let t = `voltro_migration_${
|
|
94
|
+
}, Ce = (e) => {
|
|
95
|
+
let t = _e(e);
|
|
96
|
+
return t === void 0 ? ge : Se(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
97
|
+
}, we = (e) => {
|
|
98
|
+
let t = `voltro_migration_${ge.toString(36)}`, n = _e(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${(Se(`voltro_migration_lock:${n}`) & xe).toString(16)}`;
|
|
102
|
+
}, Te = 250, Ee = () => {
|
|
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
|
+
}, De = (e, t) => w.gen(function* () {
|
|
106
|
+
let n = Ee(), 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* D(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(`${Te} millis`);
|
|
110
|
+
}
|
|
111
|
+
}), Oe = (e, t) => w.asVoid(D(e, `SELECT pg_advisory_unlock(${t.toString()}::bigint)`)), ke = 30, Ae = (e, t) => w.gen(function* () {
|
|
112
|
+
(yield* D(e, `SELECT GET_LOCK('${t}', ${String(ke)}) AS got`))[0]?.got !== 1 && (yield* w.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${ke}s (another migration is in progress, or a prior one left it held).`)));
|
|
113
|
+
}), je = (e, t) => w.asVoid(D(e, `SELECT RELEASE_LOCK('${t}')`)), Me = 3e4, Ne = (e, t) => w.gen(function* () {
|
|
114
|
+
let n = yield* D(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(Me)};
|
|
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
|
+
}), Pe = (e, t) => w.asVoid(D(e, `EXEC sp_releaseapplock @Resource = '${t}', @LockOwner = 'Session'`)), Fe = w.void, Ie = (e, t) => w.gen(function* () {
|
|
121
|
+
let n = ve(t), r = we(n), i = Ce(n);
|
|
122
|
+
if (!e.onDialectOrElse({
|
|
123
|
+
mysql: () => !0,
|
|
124
|
+
mssql: () => !0,
|
|
125
|
+
sqlite: () => !1,
|
|
126
|
+
orElse: () => !0
|
|
127
|
+
})) return { release: Fe };
|
|
128
|
+
let a = yield* ne.make(), o = yield* w.provideService(e.reserve, ne.Scope, a), s = ne.close(a, ee.void);
|
|
129
|
+
return yield* e.onDialectOrElse({
|
|
130
|
+
mysql: () => Ae(o, r),
|
|
131
|
+
mssql: () => Ne(o, r),
|
|
132
|
+
sqlite: () => Fe,
|
|
133
|
+
orElse: () => De(o, i)
|
|
134
|
+
}).pipe(w.onExit((e) => ee.isSuccess(e) ? w.void : s)), { release: e.onDialectOrElse({
|
|
135
|
+
mysql: () => je(o, r),
|
|
136
|
+
mssql: () => Pe(o, r),
|
|
137
|
+
sqlite: () => Fe,
|
|
138
|
+
orElse: () => Oe(o, i)
|
|
139
|
+
}).pipe(w.ensuring(s)) };
|
|
140
|
+
}), Le = (e, t, n) => w.acquireUseRelease(Ie(e, n), () => t, (e) => e.release.pipe(w.orDie)), Re = (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
|
+
}), ze = {
|
|
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
|
+
}, Be = (e) => ze[e], O = "_voltro_migration_ops", Ve = l(O, {
|
|
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
|
+
}), He = (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
|
+
}, Ue = (e) => [...He(e)].join(" "), We = (e, t) => {
|
|
194
|
+
let n = He(t);
|
|
195
|
+
for (let t of He(e)) if (n.has(t)) return !0;
|
|
200
196
|
return !1;
|
|
201
|
-
},
|
|
197
|
+
}, Ge = (e, t) => e.operations.some((e) => We(e.op, t)), Ke = "__voltro_rebuild", qe = "__shadow", Je = "__old", Ye = /* @__PURE__ */ new Set([
|
|
202
198
|
"add-unique",
|
|
203
199
|
"drop-unique",
|
|
204
200
|
"add-unique-composite",
|
|
@@ -210,21 +206,21 @@ var oe = (e, t, n, r = 400) => {
|
|
|
210
206
|
"alter-column-nullability",
|
|
211
207
|
"alter-column-type",
|
|
212
208
|
"alter-column-default"
|
|
213
|
-
]),
|
|
209
|
+
]), Xe = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Ze = (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 && Ye.has(e.kind) ? "artefact-repair" : Xe.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
216
212
|
};
|
|
217
|
-
Object.keys(
|
|
213
|
+
Object.keys(ze);
|
|
218
214
|
//#endregion
|
|
219
215
|
//#region src/migrations/reactiveTriggerName.ts
|
|
220
|
-
var
|
|
216
|
+
var k = "framework_changes", Qe = "framework_changes_", $e = (e, t) => t === "framework_changes" ? `${Qe}${e}` : `${Qe}${t}_${e}`, et = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, tt = "voltro:notify:v2", nt = (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
|
-
|
|
227
|
-
},
|
|
221
|
+
}, rt = ie({ scope: "voltro:migrate" }), A = (e) => {
|
|
222
|
+
rt.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
223
|
+
}, j = (e, t) => {
|
|
228
224
|
let n = e.type;
|
|
229
225
|
if (e.spatial) {
|
|
230
226
|
if (t === "postgres") return `${e.spatial.kind}(${e.spatial.geomKind},${e.spatial.srid})`;
|
|
@@ -235,7 +231,7 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
235
231
|
return e.rawDdl;
|
|
236
232
|
}
|
|
237
233
|
if (n === "array" && e.arrayElement) {
|
|
238
|
-
if (t === "postgres") return `${
|
|
234
|
+
if (t === "postgres") return `${j({
|
|
239
235
|
...e,
|
|
240
236
|
type: e.arrayElement,
|
|
241
237
|
arrayElement: void 0
|
|
@@ -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 = nt(e, !1);
|
|
310
306
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
311
307
|
}
|
|
312
308
|
case "integer": return "INT";
|
|
@@ -338,22 +334,22 @@ 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
|
+
}, it = (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
|
-
},
|
|
346
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
347
|
-
let r =
|
|
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) ? at(n, e, t) : typeof n == "object" && n ? M(n, t) : null;
|
|
341
|
+
}, at = (e, t, n) => {
|
|
342
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return M(e, n);
|
|
343
|
+
let r = j({
|
|
348
344
|
...t,
|
|
349
345
|
type: t.arrayElement,
|
|
350
346
|
arrayElement: void 0
|
|
351
347
|
}, n);
|
|
352
348
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
353
|
-
},
|
|
349
|
+
}, M = (e, t) => {
|
|
354
350
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
355
351
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
356
|
-
},
|
|
352
|
+
}, N = (e, t) => {
|
|
357
353
|
switch (t) {
|
|
358
354
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
359
355
|
case "mysql":
|
|
@@ -362,7 +358,7 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
362
358
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
363
359
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
364
360
|
}
|
|
365
|
-
},
|
|
361
|
+
}, P = (e, t) => {
|
|
366
362
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
367
363
|
switch (e) {
|
|
368
364
|
case "cascade": return "CASCADE";
|
|
@@ -370,42 +366,42 @@ 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
|
+
}, ot = (e, t, n) => n === null ? o(e, t) : `${o(n, t)}.${o(e, t)}`, st = 191, ct = (e, t) => {
|
|
374
370
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
375
|
-
let n =
|
|
371
|
+
let n = j(e, t).toUpperCase();
|
|
376
372
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
377
|
-
},
|
|
373
|
+
}, lt = (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
|
-
let a =
|
|
383
|
-
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${
|
|
384
|
-
},
|
|
378
|
+
let a = j(i, n).toUpperCase();
|
|
379
|
+
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${st})` : r;
|
|
380
|
+
}, ut = (e, t) => {
|
|
385
381
|
if (!e.generatedAs) return null;
|
|
386
382
|
let { expr: n, stored: r } = e.generatedAs;
|
|
387
|
-
if (t === "postgres") return r ||
|
|
383
|
+
if (t === "postgres") return r || A("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
388
384
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
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
|
-
},
|
|
393
|
-
if (t.type === "id" && t.idScheme?.kind === "numeric") return
|
|
394
|
-
let s = n === "mssql" ?
|
|
388
|
+
}, dt = (e, t, n, r, i = !1, a = !1) => {
|
|
389
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return N(e, n);
|
|
390
|
+
let s = n === "mssql" ? nt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? j(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 = ut(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" && !ct(t, n) && l.push("UNIQUE");
|
|
396
|
+
let e = it(t, n);
|
|
401
397
|
e && l.push(e);
|
|
402
398
|
}
|
|
403
399
|
if (t.type === "reference" && t.references && !i && !b(n)) {
|
|
404
400
|
let e = t.references();
|
|
405
401
|
l.push(`REFERENCES ${o(e.tableName, n)} (${o(t.referenceColumn ?? "id", n)})`);
|
|
406
|
-
let r =
|
|
402
|
+
let r = P(t.onDelete ?? "restrict", n);
|
|
407
403
|
l.push(`ON DELETE ${r}`);
|
|
408
|
-
let i =
|
|
404
|
+
let i = P(t.refOnUpdate ?? "noAction", n);
|
|
409
405
|
i !== "NO ACTION" && l.push(`ON UPDATE ${i}`);
|
|
410
406
|
}
|
|
411
407
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
@@ -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
|
+
}, ft = (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]) => ` ${dt(e, n, t, i, r?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((n) => {
|
|
429
|
+
let r = n.fields.map((n) => lt(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) => lt(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
|
-
let s = a.references(), c =
|
|
438
|
-
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${
|
|
433
|
+
let s = a.references(), c = P(a.onDelete ?? "restrict", t), l = P(a.refOnUpdate ?? "noAction", t);
|
|
434
|
+
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${ot(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 = ot(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
|
+
}, pt = (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
|
+
}, mt = (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: "",
|
|
@@ -466,21 +462,21 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
466
462
|
using: " USING GIST",
|
|
467
463
|
withSuffix: "",
|
|
468
464
|
skip: !1
|
|
469
|
-
} : (
|
|
465
|
+
} : (A(`[voltro:migrate] index '${e}' on '${n}': ${t} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), a);
|
|
470
466
|
if (r === "gin") return t === "postgres" ? {
|
|
471
467
|
using: " USING GIN",
|
|
472
468
|
withSuffix: "",
|
|
473
469
|
skip: !1
|
|
474
|
-
} : t === "mysql" || t === "mariadb" ? (
|
|
470
|
+
} : t === "mysql" || t === "mariadb" ? (A(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
475
471
|
using: "",
|
|
476
472
|
withSuffix: "",
|
|
477
473
|
skip: !0
|
|
478
|
-
}) : (
|
|
474
|
+
}) : (A(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), a);
|
|
479
475
|
if (r === "brin") return t === "postgres" ? {
|
|
480
476
|
using: " USING BRIN",
|
|
481
477
|
withSuffix: "",
|
|
482
478
|
skip: !1
|
|
483
|
-
} : (
|
|
479
|
+
} : (A(`[voltro:migrate] brin index '${e}' on '${n}': ${t} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), a);
|
|
484
480
|
if (r === "hnsw") {
|
|
485
481
|
if (t === "postgres") {
|
|
486
482
|
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? h(i?.hnsw?.distance);
|
|
@@ -491,7 +487,7 @@ var A = "framework_changes", Ye = "framework_changes_", Xe = (e, t) => t === "fr
|
|
|
491
487
|
skip: !1
|
|
492
488
|
};
|
|
493
489
|
}
|
|
494
|
-
return
|
|
490
|
+
return A(`[voltro:migrate] hnsw index '${e}' on '${n}': ${t} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
495
491
|
using: "",
|
|
496
492
|
withSuffix: "",
|
|
497
493
|
skip: !0
|
|
@@ -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 lt(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 = ot(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" || !ct(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,15 +525,15 @@ 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(...pt(e.tableName, n, t)) : A(`[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
|
+
A(`[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(...).`);
|
|
536
532
|
continue;
|
|
537
533
|
}
|
|
538
534
|
if (n.unique && n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb")) throw Error(`@voltro/migrate: uniqueActive index '${n.name}' on '${e.tableName}' cannot be expressed on ${t} — it has no partial (WHERE) index support, and a full UNIQUE index would forbid re-creating a soft-deleted row. Use a generated STORED column (text().generatedAs("CASE WHEN \`deletedAt\` IS NULL THEN <key> ELSE NULL END", { stored: true })) + .unique([...]) on ${t}, or move this table to postgres/sqlite/mssql.`);
|
|
539
535
|
let o = "";
|
|
540
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ?
|
|
536
|
+
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? A(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) : o = ` WHERE ${n.where}`);
|
|
541
537
|
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions, o, n.unique === !0);
|
|
542
538
|
s !== "" && r.push(s), n.fields.every((e) => typeof e == "string") && i.add(a(n.fields));
|
|
543
539
|
}
|
|
@@ -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
|
+
}, ht = (e, t, n = k) => {
|
|
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 ? [] : [gt(n), ...r.map((e) => vt(e, n))];
|
|
550
|
+
}, gt = (e) => `
|
|
551
|
+
CREATE OR REPLACE FUNCTION ${et(e)}() RETURNS trigger AS $$
|
|
556
552
|
DECLARE
|
|
557
553
|
payload TEXT;
|
|
558
554
|
pk JSONB;
|
|
559
555
|
BEGIN
|
|
560
|
-
-- ${
|
|
556
|
+
-- ${tt}
|
|
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(), _t = (e, t) => {
|
|
611
|
+
let n = $e(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 ${et(t)}()`
|
|
620
616
|
];
|
|
621
|
-
},
|
|
617
|
+
}, vt = (e, t) => _t(e, t).map((e) => `${e};`).join("\n"), yt = (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(gt(t));
|
|
621
|
+
for (let e of i) r.push(..._t(n.get(e), t));
|
|
622
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${$e(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
|
+
}, bt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), xt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), St = (e) => {
|
|
625
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = he(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 [];
|
|
@@ -663,8 +659,8 @@ $$ LANGUAGE plpgsql;
|
|
|
663
659
|
sorted: o,
|
|
664
660
|
cyclic: r
|
|
665
661
|
};
|
|
666
|
-
},
|
|
667
|
-
let r = (e) => n ? `${o(n, t)}.${o(e, t)}` : o(e, t), i = `${e.table}_${e.column}_fkey`, a =
|
|
662
|
+
}, Ct = (e, t, n = null) => {
|
|
663
|
+
let r = (e) => n ? `${o(n, t)}.${o(e, t)}` : o(e, t), i = `${e.table}_${e.column}_fkey`, a = P(e.onDelete, t), s = P(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 [
|
|
670
666
|
"DO $$ BEGIN",
|
|
@@ -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
|
+
}, wt = (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
|
+
}, Tt = (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
|
+
}, Et = (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
|
+
}, Dt = (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
|
+
}, Ot = (t, n, r = k) => {
|
|
723
|
+
let { tables: i, views: a } = Dt(t), { sorted: o, cyclic: s } = St(i.map((e) => me(e, n))), c = wt(s, n), l = [];
|
|
724
|
+
n === "postgres" && bt(o) && l.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && xt(o) && l.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
725
|
+
let u = Et(o, n);
|
|
730
726
|
u && l.push(u);
|
|
731
|
-
let d =
|
|
727
|
+
let d = Tt(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(ft(e, n, null, c.get(e.tableName)));
|
|
730
|
+
if (!m(n)) for (let e of s) l.push(Ct(e, n));
|
|
735
731
|
for (let e of o) {
|
|
736
|
-
let t =
|
|
732
|
+
let t = mt(e, n);
|
|
737
733
|
t && l.push(t);
|
|
738
734
|
}
|
|
739
|
-
l.push(...
|
|
735
|
+
l.push(...ht(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
|
+
}, kt = (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
|
+
}, At = (e, t, n, r) => {
|
|
749
|
+
let i = kt(n, t, r), a = o(n, t);
|
|
750
|
+
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${Ot(e, t)}`;
|
|
751
|
+
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${Ot(e, t)}`;
|
|
752
|
+
let { sorted: s, cyclic: c } = St(e), l = wt(c, t), u = [i];
|
|
753
|
+
for (let e of s) u.push(ft(e, t, n, l.get(e.tableName)));
|
|
754
|
+
if (!m(t)) for (let e of c) u.push(Ct(e, t, n));
|
|
759
755
|
for (let e of s) {
|
|
760
|
-
let r =
|
|
756
|
+
let r = mt(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
|
+
}, jt = (e, t, n = k) => {
|
|
761
|
+
let { sorted: r, cyclic: i } = St(e), a = wt(i, t), o = [], s = Et(r, t);
|
|
766
762
|
s && o.push(s);
|
|
767
|
-
let c =
|
|
763
|
+
let c = Tt(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
|
-
},
|
|
765
|
+
for (let e of r) o.push(ft(e, t, null, a.get(e.tableName)));
|
|
766
|
+
for (let e of i) o.push(Ct(e, t));
|
|
767
|
+
return o.push(...ht(r, t, n)), o.join("\n\n") + "\n";
|
|
768
|
+
}, Mt = (e, t = "postgres", n = k, r = {}) => w.gen(function* () {
|
|
773
769
|
let i = yield* T.SqlClient;
|
|
774
|
-
yield*
|
|
775
|
-
}),
|
|
770
|
+
yield* Le(i, zt(i, Ot(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
771
|
+
}), Nt = (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
|
+
}, Pt = (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
|
+
}, Ft = () => {
|
|
782
778
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
783
779
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
784
|
-
},
|
|
780
|
+
}, It = (e) => ({
|
|
785
781
|
while: e,
|
|
786
|
-
times:
|
|
787
|
-
schedule:
|
|
788
|
-
}),
|
|
782
|
+
times: Ft(),
|
|
783
|
+
schedule: te.jittered(te.exponential("50 millis"))
|
|
784
|
+
}), Lt = 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* T.SqlClient, i = n !== void 0 &&
|
|
797
|
-
for (let a of
|
|
798
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
799
|
-
let e = r.unsafe(a).pipe(
|
|
800
|
-
|
|
791
|
+
}, Rt = (e, t, n) => w.gen(function* () {
|
|
792
|
+
let r = yield* T.SqlClient, i = n !== void 0 && Be(t) === "per-operation";
|
|
793
|
+
for (let a of Bt(e)) {
|
|
794
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && rt.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
795
|
+
let e = r.unsafe(a).pipe(w.catchIf((e) => Nt(a, e), () => w.succeed([])), w.tapError((e) => w.sync(() => {
|
|
796
|
+
rt.error(ce("migrate: statement failed", a, e, 200));
|
|
801
797
|
})));
|
|
802
|
-
yield* (i && n !== void 0 &&
|
|
798
|
+
yield* (i && n !== void 0 && Pt(a, t) ? e.pipe(w.retry(It((e) => n(e) === "retry"))) : e).pipe(w.mapError((e) => new Lt(a, e)));
|
|
803
799
|
}
|
|
804
|
-
}),
|
|
805
|
-
let i = n === "turso" ?
|
|
806
|
-
return (r !== void 0 &&
|
|
807
|
-
},
|
|
800
|
+
}), zt = (e, t, n, r) => {
|
|
801
|
+
let i = n === "turso" ? Rt(t, n, r) : e.withTransaction(Rt(t, n, r)), a = (e) => e instanceof Lt ? e.error : e;
|
|
802
|
+
return (r !== void 0 && Be(n) === "plan-transactional" ? i.pipe(w.retry(It((e) => r(a(e)) === "retry"))) : i).pipe(w.orDieWith((e) => e instanceof Lt ? Error(ce("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
803
|
+
}, Bt = (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,30 @@ 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
|
+
}, Vt = async (e, t, n = "postgres", r = {}) => {
|
|
819
|
+
await w.runPromise(Mt(e, n, void 0, r).pipe(w.provide(t)));
|
|
820
|
+
}, Ht = (e, t, n = "postgres", r = {}) => w.gen(function* () {
|
|
821
|
+
let i = At(e, n, t), a = yield* T.SqlClient;
|
|
822
|
+
yield* Le(a, zt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
823
|
+
}), Ut = async (e, t, n, r = "postgres", i = {}) => {
|
|
824
|
+
await w.runPromise(Ht(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
|
-
},
|
|
828
|
+
}, Wt = async (e, t, n = "postgres", r = {}) => {
|
|
829
|
+
await w.runPromise(w.gen(function* () {
|
|
830
|
+
let t = jt(e, n), i = yield* T.SqlClient;
|
|
831
|
+
yield* Le(i, zt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(w.orDie);
|
|
832
|
+
}).pipe(w.provide(t)));
|
|
833
|
+
}, Gt = /'(?:''|[^'])*'|"(?:""|[^"])*"|\[(?:\]\]|[^\]])*\]|`(?:``|[^`])*`|[A-Za-z_][A-Za-z_0-9$]*|\d+(?:\.\d+)?|::|<>|!=|<=|>=|\|\||[^\s]/g, Kt = (e) => {
|
|
838
834
|
let t = 0;
|
|
839
|
-
for (let n of e.matchAll(
|
|
840
|
-
},
|
|
835
|
+
for (let n of e.matchAll(Gt)) if (n[0] === "(" && t++, n[0] === ")" && t--, t === 0 && n[0].toLowerCase() === "where") return e.slice(n.index + n[0].length).trim().replace(/;$/, "").trim();
|
|
836
|
+
}, qt = (e) => {
|
|
841
837
|
if (e === void 0) return;
|
|
842
|
-
let t = e.match(
|
|
838
|
+
let t = e.match(Gt) ?? [], n = "(?:'(?:''|[^'])*'(?:\\s*::\\s*text)?|[0-9]+)", r = RegExp(`^\\s*${n}(?:\\s*,\\s*${n})*\\s*$`, "i");
|
|
843
839
|
for (let e = 0; e < t.length - 5; e++) {
|
|
844
840
|
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(
|
|
841
|
+
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(Gt) ?? [], ")");
|
|
846
842
|
}
|
|
847
843
|
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
844
|
if (e.startsWith("'")) return e;
|
|
@@ -880,31 +876,31 @@ BEGIN
|
|
|
880
876
|
return r;
|
|
881
877
|
};
|
|
882
878
|
return JSON.stringify(a(i));
|
|
883
|
-
},
|
|
879
|
+
}, Jt = (e) => {
|
|
884
880
|
if (e == null) return e;
|
|
885
|
-
if (Array.isArray(e)) return e.map(
|
|
881
|
+
if (Array.isArray(e)) return e.map(Jt);
|
|
886
882
|
if (typeof e != "object") return e;
|
|
887
883
|
let t = {};
|
|
888
884
|
for (let n of Object.keys(e).sort()) {
|
|
889
885
|
let r = e[n];
|
|
890
|
-
r !== void 0 && (t[n] =
|
|
886
|
+
r !== void 0 && (t[n] = Jt(r));
|
|
891
887
|
}
|
|
892
888
|
return t;
|
|
893
|
-
},
|
|
889
|
+
}, Yt = (e) => {
|
|
894
890
|
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs) return e;
|
|
895
891
|
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, ...a } = e;
|
|
896
892
|
return a;
|
|
897
|
-
},
|
|
893
|
+
}, Xt = (e) => [...e].map(Yt).sort((e, t) => e.name.localeCompare(t.name)), Zt = (e) => [...e].map((e) => e.where === void 0 ? e : {
|
|
898
894
|
...e,
|
|
899
|
-
where:
|
|
900
|
-
}).sort((e, t) => e.name.localeCompare(t.name)),
|
|
895
|
+
where: qt(e.where)
|
|
896
|
+
}).sort((e, t) => e.name.localeCompare(t.name)), Qt = (e) => [...e].map((e) => ({
|
|
901
897
|
name: e.name,
|
|
902
|
-
columns:
|
|
903
|
-
indexes:
|
|
904
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
905
|
-
let t = { tables:
|
|
906
|
-
return
|
|
907
|
-
},
|
|
898
|
+
columns: Xt(e.columns),
|
|
899
|
+
indexes: Zt(e.indexes)
|
|
900
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), $t = (e) => {
|
|
901
|
+
let t = { tables: Qt(e.tables) }, n = JSON.stringify(Jt(t));
|
|
902
|
+
return re("sha256").update(n).digest("hex");
|
|
903
|
+
}, en = (e) => e.slice(0, 16), tn = (e, t) => {
|
|
908
904
|
let n = t.references ? {
|
|
909
905
|
table: t.references().tableName,
|
|
910
906
|
column: t.referenceColumn ?? "id",
|
|
@@ -944,7 +940,7 @@ BEGIN
|
|
|
944
940
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
945
941
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
946
942
|
};
|
|
947
|
-
},
|
|
943
|
+
}, nn = (e) => {
|
|
948
944
|
let t = [], n = /* @__PURE__ */ new Set(), i = (e) => {
|
|
949
945
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
950
946
|
}, a = e.appliedPrimaryKey ?? [];
|
|
@@ -992,11 +988,11 @@ BEGIN
|
|
|
992
988
|
});
|
|
993
989
|
}
|
|
994
990
|
return t;
|
|
995
|
-
},
|
|
991
|
+
}, rn = (e) => {
|
|
996
992
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
997
993
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
998
994
|
if (i.dropped) continue;
|
|
999
|
-
let e =
|
|
995
|
+
let e = tn(r, i);
|
|
1000
996
|
n.push(t.has(r) ? {
|
|
1001
997
|
...e,
|
|
1002
998
|
unique: !0
|
|
@@ -1006,30 +1002,30 @@ BEGIN
|
|
|
1006
1002
|
return {
|
|
1007
1003
|
name: e.tableName,
|
|
1008
1004
|
columns: n,
|
|
1009
|
-
indexes:
|
|
1005
|
+
indexes: nn(e),
|
|
1010
1006
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
1011
1007
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
1012
1008
|
};
|
|
1013
|
-
},
|
|
1009
|
+
}, an = (e) => {
|
|
1014
1010
|
let t = /* @__PURE__ */ new Map();
|
|
1015
1011
|
for (let n of e) for (let e of n.indexes) {
|
|
1016
1012
|
let r = t.get(e.name);
|
|
1017
1013
|
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
1014
|
t.set(e.name, n.name);
|
|
1019
1015
|
}
|
|
1020
|
-
},
|
|
1021
|
-
let n = e.filter((e) => !c(e.tableName)).map((e) =>
|
|
1016
|
+
}, F = (e, t) => {
|
|
1017
|
+
let n = e.filter((e) => !c(e.tableName)).map((e) => rn(me(e, t)));
|
|
1022
1018
|
if (t === "mysql" || t === "mariadb") {
|
|
1023
1019
|
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
1020
|
}
|
|
1025
|
-
return
|
|
1026
|
-
},
|
|
1021
|
+
return an(n), { tables: n };
|
|
1022
|
+
}, on = (e, t, n = k) => w.gen(function* () {
|
|
1027
1023
|
let r = (yield* e`
|
|
1028
1024
|
SELECT p.prosrc
|
|
1029
1025
|
FROM pg_proc p
|
|
1030
1026
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
1031
1027
|
WHERE n.nspname = current_schema()
|
|
1032
|
-
AND p.proname = ${
|
|
1028
|
+
AND p.proname = ${et(n)}
|
|
1033
1029
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
1034
1030
|
if (a.length === 0) return {
|
|
1035
1031
|
missing: [],
|
|
@@ -1043,10 +1039,10 @@ BEGIN
|
|
|
1043
1039
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1044
1040
|
WHERE NOT t.tgisinternal
|
|
1045
1041
|
AND n.nspname = current_schema()
|
|
1046
|
-
AND t.tgname LIKE ${`${
|
|
1042
|
+
AND t.tgname LIKE ${`${Qe}%`}
|
|
1047
1043
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
1048
1044
|
for (let e of a) {
|
|
1049
|
-
let t = s.has(
|
|
1045
|
+
let t = s.has($e(e.tableName, n)), r = e.isReactive !== !1;
|
|
1050
1046
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
1051
1047
|
}
|
|
1052
1048
|
return {
|
|
@@ -1054,7 +1050,7 @@ BEGIN
|
|
|
1054
1050
|
stale: l.sort(),
|
|
1055
1051
|
functionOutdated: i
|
|
1056
1052
|
};
|
|
1057
|
-
}),
|
|
1053
|
+
}), sn = (e) => {
|
|
1058
1054
|
let t = [];
|
|
1059
1055
|
if (e.missing.length > 0) {
|
|
1060
1056
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -1065,19 +1061,19 @@ BEGIN
|
|
|
1065
1061
|
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
1062
|
}
|
|
1067
1063
|
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
|
-
},
|
|
1064
|
+
}, cn = {
|
|
1069
1065
|
postgres: !0,
|
|
1070
1066
|
mysql: !0,
|
|
1071
1067
|
mariadb: !0,
|
|
1072
1068
|
mssql: !0,
|
|
1073
1069
|
sqlite: !0
|
|
1074
|
-
},
|
|
1070
|
+
}, ln = {
|
|
1075
1071
|
postgres: !0,
|
|
1076
1072
|
mysql: !1,
|
|
1077
1073
|
mariadb: !1,
|
|
1078
1074
|
mssql: !0,
|
|
1079
1075
|
sqlite: !0
|
|
1080
|
-
},
|
|
1076
|
+
}, un = (e) => {
|
|
1081
1077
|
switch (e) {
|
|
1082
1078
|
case "add-column":
|
|
1083
1079
|
case "drop-column":
|
|
@@ -1087,49 +1083,49 @@ BEGIN
|
|
|
1087
1083
|
case "add-foreign-key":
|
|
1088
1084
|
case "add-unique":
|
|
1089
1085
|
case "add-unique-composite":
|
|
1090
|
-
case "add-check": return
|
|
1091
|
-
default: return
|
|
1086
|
+
case "add-check": return ln;
|
|
1087
|
+
default: return cn;
|
|
1092
1088
|
}
|
|
1093
|
-
},
|
|
1089
|
+
}, dn = (e, t) => {
|
|
1094
1090
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1095
1091
|
return new Map(e.map((e) => [e.tableName, {
|
|
1096
1092
|
table: e,
|
|
1097
1093
|
snapshot: n.get(e.tableName),
|
|
1098
1094
|
columnDefs: e.fields
|
|
1099
1095
|
}]));
|
|
1100
|
-
},
|
|
1096
|
+
}, I = (e) => {
|
|
1101
1097
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
1102
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
1098
|
+
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
1103
1099
|
let t = e;
|
|
1104
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
1105
|
-
},
|
|
1100
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
1101
|
+
}, fn = (e) => {
|
|
1106
1102
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
1107
1103
|
let t = e.defaultValue;
|
|
1108
1104
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
1109
1105
|
if (typeof t == "number") return String(t);
|
|
1110
|
-
if (typeof t != "string") return
|
|
1106
|
+
if (typeof t != "string") return I(t);
|
|
1111
1107
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
1112
1108
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
1113
1109
|
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
1110
|
if (o) try {
|
|
1115
|
-
return
|
|
1111
|
+
return I(JSON.parse(o[1]));
|
|
1116
1112
|
} catch {}
|
|
1117
1113
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1118
1114
|
if (s) try {
|
|
1119
|
-
return
|
|
1115
|
+
return I(JSON.parse(s[1]));
|
|
1120
1116
|
} catch {}
|
|
1121
1117
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1122
|
-
return
|
|
1118
|
+
return I(JSON.parse(a));
|
|
1123
1119
|
} catch {}
|
|
1124
1120
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1125
|
-
},
|
|
1126
|
-
let n =
|
|
1121
|
+
}, pn = (e, t) => {
|
|
1122
|
+
let n = fn(e), r = fn(t);
|
|
1127
1123
|
if (n === r) return !0;
|
|
1128
1124
|
let i = (e) => typeof e.defaultValue == "string" && /^nextval\(.+::regclass\)$/i.test(e.defaultValue.trim()), a = (e) => e.type === "id" && e.idScheme?.kind === "numeric";
|
|
1129
1125
|
if (e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e))) return !0;
|
|
1130
1126
|
let o = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
1131
1127
|
return o(n) === o(r);
|
|
1132
|
-
},
|
|
1128
|
+
}, mn = (e) => {
|
|
1133
1129
|
if (!e) return null;
|
|
1134
1130
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1135
1131
|
return {
|
|
@@ -1138,29 +1134,29 @@ BEGIN
|
|
|
1138
1134
|
onDelete: t(e.onDelete),
|
|
1139
1135
|
onUpdate: t(e.onUpdate)
|
|
1140
1136
|
};
|
|
1141
|
-
},
|
|
1137
|
+
}, hn = (e, t) => {
|
|
1142
1138
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1143
1139
|
if (!n && !r) return !0;
|
|
1144
1140
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1145
1141
|
let i = [...n].sort(), a = [...r].sort();
|
|
1146
1142
|
return i.every((e, t) => e === a[t]);
|
|
1147
|
-
},
|
|
1143
|
+
}, gn = (e, t, n) => {
|
|
1148
1144
|
if (t === "mssql") {
|
|
1149
|
-
let t =
|
|
1145
|
+
let t = nt(e, n);
|
|
1150
1146
|
if (t !== void 0) return t;
|
|
1151
1147
|
}
|
|
1152
1148
|
try {
|
|
1153
|
-
let n = /\((\d+)\)/.exec(
|
|
1149
|
+
let n = /\((\d+)\)/.exec(j(e, t));
|
|
1154
1150
|
return n ? Number(n[1]) : void 0;
|
|
1155
1151
|
} catch {
|
|
1156
1152
|
return;
|
|
1157
1153
|
}
|
|
1158
|
-
},
|
|
1154
|
+
}, _n = (e, t, n, r) => n === void 0 || m(n) ? !0 : e.type !== "text" || t.type !== "text" || gn(e, n, r) === t.maxLength, vn = (e, t, n, r) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && pn(e, t) && _n(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(mn(e.references)) === JSON.stringify(mn(t.references)) && hn(e.oneOf, t.oneOf), yn = (e, t) => t.oneOf && t.oneOf.length > 0 ? L({
|
|
1159
1155
|
kind: "add-check",
|
|
1160
1156
|
table: e,
|
|
1161
1157
|
column: t.name,
|
|
1162
1158
|
values: t.oneOf
|
|
1163
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1159
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, bn = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && qt(e.where) === qt(t.where) && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), xn = (e, t, n) => {
|
|
1164
1160
|
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
1161
|
for (let t of e.columns) {
|
|
1166
1162
|
let e = r.get(t.name);
|
|
@@ -1168,7 +1164,7 @@ BEGIN
|
|
|
1168
1164
|
a.push(t);
|
|
1169
1165
|
continue;
|
|
1170
1166
|
}
|
|
1171
|
-
|
|
1167
|
+
vn(t, e, n, c.has(t.name) || t.unique) || s.push({
|
|
1172
1168
|
declared: t,
|
|
1173
1169
|
live: e
|
|
1174
1170
|
});
|
|
@@ -1179,50 +1175,50 @@ BEGIN
|
|
|
1179
1175
|
removed: o,
|
|
1180
1176
|
changed: s
|
|
1181
1177
|
};
|
|
1182
|
-
},
|
|
1178
|
+
}, Sn = (e, t, n) => {
|
|
1183
1179
|
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
1180
|
for (let t of e.indexes) {
|
|
1185
1181
|
let e = i.get(r(t.name));
|
|
1186
|
-
(!e || !
|
|
1182
|
+
(!e || !bn(t, e)) && o.push(t);
|
|
1187
1183
|
}
|
|
1188
1184
|
for (let e of t.indexes) {
|
|
1189
1185
|
let t = a.get(r(e.name));
|
|
1190
|
-
(!t || (e.where !== void 0 || t.where !== void 0) && !
|
|
1186
|
+
(!t || (e.where !== void 0 || t.where !== void 0) && !bn(t, e)) && s.push(e);
|
|
1191
1187
|
}
|
|
1192
1188
|
return {
|
|
1193
1189
|
added: o,
|
|
1194
1190
|
removed: s
|
|
1195
1191
|
};
|
|
1196
|
-
},
|
|
1192
|
+
}, L = (e, t, n, r) => ({
|
|
1197
1193
|
op: e,
|
|
1198
1194
|
classification: t,
|
|
1199
|
-
atomicByDialect:
|
|
1195
|
+
atomicByDialect: un(e.kind),
|
|
1200
1196
|
...n ? { reason: n } : {},
|
|
1201
1197
|
...r ? { blocked: r } : {}
|
|
1202
|
-
}),
|
|
1198
|
+
}), Cn = (e, t, n) => {
|
|
1203
1199
|
let r = {
|
|
1204
1200
|
kind: "add-column",
|
|
1205
1201
|
table: e,
|
|
1206
1202
|
column: t
|
|
1207
1203
|
};
|
|
1208
|
-
return t.nullable ?
|
|
1209
|
-
},
|
|
1204
|
+
return t.nullable ? L(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? L(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? L(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : L(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` });
|
|
1205
|
+
}, wn = (e, t, n) => {
|
|
1210
1206
|
let r = {
|
|
1211
1207
|
kind: "drop-column",
|
|
1212
1208
|
table: e,
|
|
1213
1209
|
column: t.name
|
|
1214
1210
|
};
|
|
1215
|
-
return n?.dropped ?
|
|
1216
|
-
},
|
|
1211
|
+
return n?.dropped ? L(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : L(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1212
|
+
}, Tn = (e, t, n, r, i) => L({
|
|
1217
1213
|
kind: "create-table",
|
|
1218
1214
|
table: e,
|
|
1219
1215
|
columns: t,
|
|
1220
1216
|
indexes: n,
|
|
1221
1217
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1222
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1218
|
+
}, "safe", i ?? "new table — no data to preserve"), En = (e) => L({
|
|
1223
1219
|
kind: "drop-table",
|
|
1224
1220
|
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" }),
|
|
1221
|
+
}, "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" }), Dn = 5e4, On = (e, t, n, r) => {
|
|
1226
1222
|
let i = (n ?? 0) >= r, a;
|
|
1227
1223
|
return a = !t.unique || t.where !== void 0 ? {
|
|
1228
1224
|
kind: "add-index",
|
|
@@ -1237,16 +1233,16 @@ BEGIN
|
|
|
1237
1233
|
table: e,
|
|
1238
1234
|
name: t.name,
|
|
1239
1235
|
fields: t.columns
|
|
1240
|
-
}, i ?
|
|
1241
|
-
},
|
|
1236
|
+
}, i ? L(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : L(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`);
|
|
1237
|
+
}, kn = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ? L({
|
|
1242
1238
|
kind: "drop-unique-composite",
|
|
1243
1239
|
table: e,
|
|
1244
1240
|
name: t.name
|
|
1245
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1241
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : L({
|
|
1246
1242
|
kind: "drop-index",
|
|
1247
1243
|
table: e,
|
|
1248
1244
|
index: t.name
|
|
1249
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1245
|
+
}, "safe", "drop index (no data loss — index is derived data)"), An = (e, t) => {
|
|
1250
1246
|
let n = e.type;
|
|
1251
1247
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
1252
1248
|
switch (t) {
|
|
@@ -1255,10 +1251,10 @@ BEGIN
|
|
|
1255
1251
|
case "mssql": return n === "json" ? "text" : n;
|
|
1256
1252
|
default: return n;
|
|
1257
1253
|
}
|
|
1258
|
-
},
|
|
1254
|
+
}, jn = (e, t, n) => {
|
|
1259
1255
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1260
1256
|
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
|
-
},
|
|
1257
|
+
}, Mn = (e, t, n, r, i, a) => {
|
|
1262
1258
|
let o = [];
|
|
1263
1259
|
if (t.nullable !== n.nullable) {
|
|
1264
1260
|
let n = {
|
|
@@ -1267,7 +1263,7 @@ BEGIN
|
|
|
1267
1263
|
column: t.name,
|
|
1268
1264
|
toNullable: t.nullable
|
|
1269
1265
|
};
|
|
1270
|
-
o.push(t.nullable ?
|
|
1266
|
+
o.push(t.nullable ? L(n, "safe", `loosen ${e}.${t.name} to nullable`) : L(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1271
1267
|
}
|
|
1272
1268
|
if (t.unique !== n.unique) {
|
|
1273
1269
|
if (t.unique) {
|
|
@@ -1276,14 +1272,14 @@ BEGIN
|
|
|
1276
1272
|
table: e,
|
|
1277
1273
|
column: t.name
|
|
1278
1274
|
}, r = (i ?? 0) >= a;
|
|
1279
|
-
o.push(r ?
|
|
1280
|
-
} else o.push(
|
|
1275
|
+
o.push(r ? L(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : L(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1276
|
+
} else o.push(L({
|
|
1281
1277
|
kind: "drop-unique",
|
|
1282
1278
|
table: e,
|
|
1283
1279
|
column: t.name
|
|
1284
1280
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1285
1281
|
}
|
|
1286
|
-
if (
|
|
1282
|
+
if (An(t, r) !== An(n, r)) {
|
|
1287
1283
|
let i = t.narrowedFrom;
|
|
1288
1284
|
if (i && i.from === n.type) {
|
|
1289
1285
|
let r = {
|
|
@@ -1294,7 +1290,7 @@ BEGIN
|
|
|
1294
1290
|
to: t.type,
|
|
1295
1291
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1296
1292
|
};
|
|
1297
|
-
o.push(
|
|
1293
|
+
o.push(L(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
1294
|
} else {
|
|
1299
1295
|
let i = {
|
|
1300
1296
|
kind: "alter-column-type",
|
|
@@ -1303,12 +1299,12 @@ BEGIN
|
|
|
1303
1299
|
from: n.type,
|
|
1304
1300
|
to: t.type
|
|
1305
1301
|
};
|
|
1306
|
-
o.push(
|
|
1302
|
+
o.push(L(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: jn(n.type, t, r) }));
|
|
1307
1303
|
}
|
|
1308
1304
|
}
|
|
1309
1305
|
if (t.type === "text" && n.type === "text" && !m(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1310
1306
|
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(
|
|
1307
|
+
o.push(L({
|
|
1312
1308
|
kind: "alter-column-type",
|
|
1313
1309
|
table: e,
|
|
1314
1310
|
column: t.name,
|
|
@@ -1316,7 +1312,7 @@ BEGIN
|
|
|
1316
1312
|
to: "text"
|
|
1317
1313
|
}, 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
1314
|
}
|
|
1319
|
-
if (!
|
|
1315
|
+
if (!pn(t, n)) {
|
|
1320
1316
|
let n = {
|
|
1321
1317
|
kind: "alter-column-default",
|
|
1322
1318
|
table: e,
|
|
@@ -1324,23 +1320,23 @@ BEGIN
|
|
|
1324
1320
|
hasDefault: t.hasDefault,
|
|
1325
1321
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1326
1322
|
};
|
|
1327
|
-
o.push(
|
|
1323
|
+
o.push(L(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1328
1324
|
}
|
|
1329
|
-
if (!
|
|
1330
|
-
n.oneOf && n.oneOf.length > 0 && o.push(
|
|
1325
|
+
if (!hn(t.oneOf, n.oneOf)) {
|
|
1326
|
+
n.oneOf && n.oneOf.length > 0 && o.push(L({
|
|
1331
1327
|
kind: "drop-check",
|
|
1332
1328
|
table: e,
|
|
1333
1329
|
column: t.name
|
|
1334
1330
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1335
|
-
let r =
|
|
1331
|
+
let r = yn(e, t);
|
|
1336
1332
|
r && o.push(r);
|
|
1337
1333
|
}
|
|
1338
|
-
return JSON.stringify(
|
|
1334
|
+
return JSON.stringify(mn(t.references)) !== JSON.stringify(mn(n.references)) && (n.references && o.push(L({
|
|
1339
1335
|
kind: "drop-foreign-key",
|
|
1340
1336
|
table: e,
|
|
1341
1337
|
column: t.name
|
|
1342
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1343
|
-
},
|
|
1338
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...Nn(e, t))), o;
|
|
1339
|
+
}, Nn = (e, t) => {
|
|
1344
1340
|
let n = [];
|
|
1345
1341
|
if (!t.references) return n;
|
|
1346
1342
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1352,15 +1348,15 @@ BEGIN
|
|
|
1352
1348
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1353
1349
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1354
1350
|
};
|
|
1355
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1351
|
+
return i === "null" && !t.nullable ? n.push(L(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(L({
|
|
1356
1352
|
...a,
|
|
1357
1353
|
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
|
-
},
|
|
1354
|
+
}, "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(L(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1355
|
+
}, Pn = (e, t, n) => {
|
|
1360
1356
|
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
1357
|
for (let [n, c] of Object.entries(t)) {
|
|
1362
1358
|
let t = c.renamedFrom;
|
|
1363
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1359
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(L({
|
|
1364
1360
|
kind: "rename-column",
|
|
1365
1361
|
table: e.tableName,
|
|
1366
1362
|
from: t,
|
|
@@ -1372,26 +1368,26 @@ BEGIN
|
|
|
1372
1368
|
consumedAddedNames: i,
|
|
1373
1369
|
consumedRemovedNames: a
|
|
1374
1370
|
};
|
|
1375
|
-
},
|
|
1371
|
+
}, Fn = /* @__PURE__ */ new Set([
|
|
1376
1372
|
"postgres",
|
|
1377
1373
|
"mysql",
|
|
1378
1374
|
"mariadb",
|
|
1379
1375
|
"mssql"
|
|
1380
|
-
]),
|
|
1376
|
+
]), In = {
|
|
1381
1377
|
ops: [],
|
|
1382
1378
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1383
1379
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1384
|
-
},
|
|
1385
|
-
if (i === void 0 || !
|
|
1386
|
-
let a = t.added.filter((e) =>
|
|
1387
|
-
if (a.length === 0) return
|
|
1380
|
+
}, Ln = (e) => !e.unique && !e.expression && e.where === void 0, Rn = (e, t, n, r, i) => {
|
|
1381
|
+
if (i === void 0 || !Fn.has(i)) return In;
|
|
1382
|
+
let a = t.added.filter((e) => Ln(e) && !r.has(e.name));
|
|
1383
|
+
if (a.length === 0) return In;
|
|
1388
1384
|
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
1385
|
for (let n of t.removed) {
|
|
1390
|
-
if (!
|
|
1386
|
+
if (!Ln(n)) continue;
|
|
1391
1387
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1392
1388
|
if (r.length !== 1) continue;
|
|
1393
1389
|
let i = r[0];
|
|
1394
|
-
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(
|
|
1390
|
+
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(L({
|
|
1395
1391
|
kind: "rename-index",
|
|
1396
1392
|
table: e,
|
|
1397
1393
|
from: n.name,
|
|
@@ -1403,7 +1399,7 @@ BEGIN
|
|
|
1403
1399
|
consumedAddedNames: l,
|
|
1404
1400
|
consumedRemovedNames: u
|
|
1405
1401
|
};
|
|
1406
|
-
},
|
|
1402
|
+
}, zn = (e, t, n) => {
|
|
1407
1403
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1408
1404
|
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
1405
|
for (let c of e.tables) {
|
|
@@ -1414,7 +1410,7 @@ BEGIN
|
|
|
1414
1410
|
continue;
|
|
1415
1411
|
}
|
|
1416
1412
|
if (t.has(c.name)) {
|
|
1417
|
-
r.push(
|
|
1413
|
+
r.push(L({
|
|
1418
1414
|
kind: "rename-table",
|
|
1419
1415
|
from: e,
|
|
1420
1416
|
to: c.name
|
|
@@ -1422,14 +1418,14 @@ BEGIN
|
|
|
1422
1418
|
continue;
|
|
1423
1419
|
}
|
|
1424
1420
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1425
|
-
r.push(
|
|
1421
|
+
r.push(L({
|
|
1426
1422
|
kind: "rename-table",
|
|
1427
1423
|
from: e,
|
|
1428
1424
|
to: c.name
|
|
1429
1425
|
}, "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
1426
|
continue;
|
|
1431
1427
|
}
|
|
1432
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1428
|
+
i.set(c.name, e), a.add(e), r.push(L({
|
|
1433
1429
|
kind: "rename-table",
|
|
1434
1430
|
from: e,
|
|
1435
1431
|
to: c.name
|
|
@@ -1443,19 +1439,19 @@ BEGIN
|
|
|
1443
1439
|
claimedOldNames: c,
|
|
1444
1440
|
refusals: o
|
|
1445
1441
|
};
|
|
1446
|
-
},
|
|
1442
|
+
}, Bn = (e, t, n, r) => {
|
|
1447
1443
|
if (t === void 0) return {
|
|
1448
1444
|
live: e,
|
|
1449
1445
|
ops: []
|
|
1450
1446
|
};
|
|
1451
|
-
let i = r !== void 0 &&
|
|
1447
|
+
let i = r !== void 0 && Fn.has(r), a = [], o = e.indexes.map((e) => {
|
|
1452
1448
|
if (!e.name.startsWith(t)) return e;
|
|
1453
1449
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1454
1450
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1455
1451
|
...e,
|
|
1456
1452
|
name: r,
|
|
1457
1453
|
table: n
|
|
1458
|
-
} : i ? (a.push(
|
|
1454
|
+
} : i ? (a.push(L({
|
|
1459
1455
|
kind: "rename-index",
|
|
1460
1456
|
table: n,
|
|
1461
1457
|
from: e.name,
|
|
@@ -1474,7 +1470,7 @@ BEGIN
|
|
|
1474
1470
|
},
|
|
1475
1471
|
ops: a
|
|
1476
1472
|
};
|
|
1477
|
-
},
|
|
1473
|
+
}, Vn = (e) => {
|
|
1478
1474
|
let t = {
|
|
1479
1475
|
safe: 0,
|
|
1480
1476
|
needsDefault: 0,
|
|
@@ -1507,42 +1503,42 @@ BEGIN
|
|
|
1507
1503
|
case "multi-step": t.multiStep++;
|
|
1508
1504
|
}
|
|
1509
1505
|
return t;
|
|
1510
|
-
},
|
|
1511
|
-
let t =
|
|
1506
|
+
}, Hn = (e) => {
|
|
1507
|
+
let t = F(e.declared, e.dialect), n = dn(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? Dn, a = [], o = zn(t, r, n);
|
|
1512
1508
|
a.push(...o.ops);
|
|
1513
1509
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1514
|
-
a.push(
|
|
1510
|
+
a.push(Tn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1515
1511
|
for (let t of e.columns) {
|
|
1516
|
-
let n =
|
|
1512
|
+
let n = yn(e.name, t);
|
|
1517
1513
|
n && a.push(n);
|
|
1518
1514
|
}
|
|
1519
1515
|
}
|
|
1520
1516
|
let s = new Set(e.ignoreTables ?? []);
|
|
1521
|
-
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || _(t.name) || x(t.name) || s.has(t.name) || a.push(
|
|
1517
|
+
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || _(t.name) || x(t.name) || s.has(t.name) || a.push(En(t.name));
|
|
1522
1518
|
for (let s of t.tables) {
|
|
1523
1519
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1524
1520
|
if (!c) continue;
|
|
1525
|
-
let l =
|
|
1521
|
+
let l = Bn(c, t, s.name, e.dialect);
|
|
1526
1522
|
a.push(...l.ops);
|
|
1527
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1523
|
+
let u = l.live, d = n.get(s.name), f = xn(s, u, e.dialect), p = Sn(s, u, e.dialect), m = Pn(d.table, d.columnDefs, f);
|
|
1528
1524
|
a.push(...m.ops);
|
|
1529
1525
|
for (let e of f.removed) {
|
|
1530
1526
|
if (m.consumedRemovedNames.has(e.name) || x(e.name)) continue;
|
|
1531
1527
|
let t = d.columnDefs[e.name];
|
|
1532
|
-
a.push(
|
|
1528
|
+
a.push(wn(s.name, e, t));
|
|
1533
1529
|
}
|
|
1534
1530
|
for (let e of f.added) {
|
|
1535
1531
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1536
1532
|
let t = d.columnDefs[e.name];
|
|
1537
|
-
a.push(
|
|
1538
|
-
let n =
|
|
1539
|
-
n && a.push(n), a.push(...
|
|
1533
|
+
a.push(Cn(s.name, e, t));
|
|
1534
|
+
let n = yn(s.name, e);
|
|
1535
|
+
n && a.push(n), a.push(...Nn(s.name, e));
|
|
1540
1536
|
}
|
|
1541
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1537
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Rn(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1542
1538
|
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(...
|
|
1539
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(On(s.name, e, u.rowCount, i));
|
|
1540
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(kn(s.name, e));
|
|
1541
|
+
for (let { declared: t, live: n } of f.changed) a.push(...Mn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1546
1542
|
}
|
|
1547
1543
|
let c = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), l = new Map(t.tables.map((e) => [e.name, e])), u = (e) => {
|
|
1548
1544
|
let t = l.get(e);
|
|
@@ -1550,8 +1546,8 @@ BEGIN
|
|
|
1550
1546
|
column: e.name,
|
|
1551
1547
|
target: e.references.table
|
|
1552
1548
|
}] : []) : [];
|
|
1553
|
-
}, d =
|
|
1554
|
-
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) t.references && d.has(E(e.name, t.name)) && f.push(
|
|
1549
|
+
}, d = he([...c], u), f = [];
|
|
1550
|
+
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) t.references && d.has(E(e.name, t.name)) && f.push(L({
|
|
1555
1551
|
kind: "add-foreign-key",
|
|
1556
1552
|
table: e.name,
|
|
1557
1553
|
column: t.name,
|
|
@@ -1623,11 +1619,11 @@ BEGIN
|
|
|
1623
1619
|
});
|
|
1624
1620
|
return {
|
|
1625
1621
|
operations: S,
|
|
1626
|
-
fromFingerprint:
|
|
1627
|
-
toFingerprint:
|
|
1628
|
-
summary:
|
|
1622
|
+
fromFingerprint: $t(e.live),
|
|
1623
|
+
toFingerprint: $t(t),
|
|
1624
|
+
summary: Vn(S)
|
|
1629
1625
|
};
|
|
1630
|
-
},
|
|
1626
|
+
}, Un = (e) => {
|
|
1631
1627
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1632
1628
|
if (!t) return null;
|
|
1633
1629
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -1635,7 +1631,7 @@ BEGIN
|
|
|
1635
1631
|
column: t[1],
|
|
1636
1632
|
values: n
|
|
1637
1633
|
};
|
|
1638
|
-
},
|
|
1634
|
+
}, Wn = (e, t) => {
|
|
1639
1635
|
if (t === "vector") return "vector";
|
|
1640
1636
|
switch (e) {
|
|
1641
1637
|
case "text":
|
|
@@ -1662,10 +1658,10 @@ BEGIN
|
|
|
1662
1658
|
case "USER-DEFINED": return "text";
|
|
1663
1659
|
default: return "text";
|
|
1664
1660
|
}
|
|
1665
|
-
},
|
|
1661
|
+
}, Gn = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1666
1662
|
expr: e,
|
|
1667
1663
|
stored: t
|
|
1668
|
-
} },
|
|
1664
|
+
} }, R = (e) => {
|
|
1669
1665
|
switch (e.toUpperCase()) {
|
|
1670
1666
|
case "CASCADE": return "cascade";
|
|
1671
1667
|
case "RESTRICT": return "restrict";
|
|
@@ -1673,25 +1669,25 @@ BEGIN
|
|
|
1673
1669
|
case "SET DEFAULT": return "noAction";
|
|
1674
1670
|
default: return "noAction";
|
|
1675
1671
|
}
|
|
1676
|
-
},
|
|
1672
|
+
}, Kn = (e, t) => {
|
|
1677
1673
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1678
1674
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1679
|
-
},
|
|
1675
|
+
}, qn = () => Kn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Jn = 300, Yn = () => {
|
|
1680
1676
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1681
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1682
|
-
},
|
|
1677
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Kn(e, 3e4);
|
|
1678
|
+
}, Xn = (e, t) => {
|
|
1683
1679
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1684
1680
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1685
1681
|
return r;
|
|
1686
|
-
},
|
|
1687
|
-
let t =
|
|
1682
|
+
}, Zn = (e) => {
|
|
1683
|
+
let t = Yn(), n = w.gen(function* () {
|
|
1688
1684
|
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 =
|
|
1685
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = qn(), a = (e, t) => w.gen(function* () {
|
|
1690
1686
|
let r = [];
|
|
1691
|
-
for (let a of
|
|
1687
|
+
for (let a of Xn(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1692
1688
|
return r;
|
|
1693
1689
|
}), o = [];
|
|
1694
|
-
for (let t = 0;; t +=
|
|
1690
|
+
for (let t = 0;; t += Jn) {
|
|
1695
1691
|
let n = yield* e`
|
|
1696
1692
|
SELECT c.relname AS table_name,
|
|
1697
1693
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1699,9 +1695,9 @@ BEGIN
|
|
|
1699
1695
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1700
1696
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1701
1697
|
ORDER BY c.relname
|
|
1702
|
-
LIMIT ${r(
|
|
1698
|
+
LIMIT ${r(Jn)} OFFSET ${r(t)}
|
|
1703
1699
|
`;
|
|
1704
|
-
if (o.push(...n), n.length <
|
|
1700
|
+
if (o.push(...n), n.length < Jn) break;
|
|
1705
1701
|
}
|
|
1706
1702
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1707
1703
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1798,18 +1794,18 @@ BEGIN
|
|
|
1798
1794
|
let t = v.get(e.table_name);
|
|
1799
1795
|
t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
|
|
1800
1796
|
}
|
|
1801
|
-
let
|
|
1797
|
+
let C = /* @__PURE__ */ new Map();
|
|
1802
1798
|
for (let e of f) {
|
|
1803
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
1799
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = C.get(t);
|
|
1804
1800
|
n || (n = {
|
|
1805
1801
|
table: e.table_name,
|
|
1806
1802
|
columns: []
|
|
1807
|
-
},
|
|
1803
|
+
}, C.set(t, n)), n.columns.push({
|
|
1808
1804
|
name: e.column_name,
|
|
1809
1805
|
position: e.position
|
|
1810
1806
|
});
|
|
1811
1807
|
}
|
|
1812
|
-
for (let [e, t] of
|
|
1808
|
+
for (let [e, t] of C) {
|
|
1813
1809
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
1814
1810
|
if (n.length === 1) {
|
|
1815
1811
|
let e = y.get(t.table);
|
|
@@ -1834,27 +1830,27 @@ BEGIN
|
|
|
1834
1830
|
let n = t.get(e.index_name);
|
|
1835
1831
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1836
1832
|
}
|
|
1837
|
-
let
|
|
1833
|
+
let ee = [];
|
|
1838
1834
|
for (let e of c) {
|
|
1839
1835
|
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" :
|
|
1836
|
+
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" : Wn(t.data_type, t.udt_name), c = a ? {
|
|
1841
1837
|
table: a.target_table,
|
|
1842
1838
|
column: a.target_column,
|
|
1843
|
-
onDelete:
|
|
1844
|
-
onUpdate:
|
|
1839
|
+
onDelete: R(a.delete_rule),
|
|
1840
|
+
onUpdate: R(a.update_rule)
|
|
1845
1841
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1846
1842
|
return {
|
|
1847
1843
|
name: t.column_name,
|
|
1848
1844
|
type: s,
|
|
1849
|
-
...
|
|
1845
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
1850
1846
|
nullable: t.is_nullable === "YES",
|
|
1851
1847
|
unique: i.has(t.column_name) || n && t.column_name === "id",
|
|
1852
1848
|
hasDefault: t.column_default !== null,
|
|
1853
1849
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
1854
1850
|
...c ? { references: c } : {},
|
|
1855
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
1851
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(Wn(t.data_type, t.udt_name)) ? "numeric" : "text" } : {},
|
|
1856
1852
|
...l ? { oneOf: l } : {},
|
|
1857
|
-
...
|
|
1853
|
+
...Gn(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
1858
1854
|
};
|
|
1859
1855
|
}), l = [], u = S.get(e.table_name);
|
|
1860
1856
|
if (u) for (let [t, n] of u) {
|
|
@@ -1882,20 +1878,20 @@ BEGIN
|
|
|
1882
1878
|
unique: !0
|
|
1883
1879
|
});
|
|
1884
1880
|
let d = Number(e.row_count ?? 0);
|
|
1885
|
-
|
|
1881
|
+
ee.push({
|
|
1886
1882
|
name: e.table_name,
|
|
1887
1883
|
columns: c,
|
|
1888
1884
|
indexes: l,
|
|
1889
1885
|
...d > 0 ? { rowCount: d } : {}
|
|
1890
1886
|
});
|
|
1891
1887
|
}
|
|
1892
|
-
return { tables:
|
|
1888
|
+
return { tables: ee };
|
|
1893
1889
|
});
|
|
1894
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
1890
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(w.catchAll((e) => {
|
|
1895
1891
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1896
|
-
return n.includes("statement timeout") || n.includes("57014") ?
|
|
1892
|
+
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
1893
|
}));
|
|
1898
|
-
},
|
|
1894
|
+
}, Qn = (e, t) => {
|
|
1899
1895
|
switch (e.toLowerCase()) {
|
|
1900
1896
|
case "varchar":
|
|
1901
1897
|
case "char":
|
|
@@ -1927,21 +1923,21 @@ BEGIN
|
|
|
1927
1923
|
case "json": return "json";
|
|
1928
1924
|
default: return "text";
|
|
1929
1925
|
}
|
|
1930
|
-
},
|
|
1926
|
+
}, z = (e) => e.map((e) => {
|
|
1931
1927
|
let t = e, n = {};
|
|
1932
1928
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1933
1929
|
return n;
|
|
1934
|
-
}),
|
|
1935
|
-
let t =
|
|
1930
|
+
}), $n = (e) => w.gen(function* () {
|
|
1931
|
+
let t = z(yield* e`
|
|
1936
1932
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1937
1933
|
FROM information_schema.tables
|
|
1938
1934
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1939
|
-
ORDER BY table_name`), n =
|
|
1935
|
+
ORDER BY table_name`), n = z(yield* e`
|
|
1940
1936
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1941
1937
|
character_maximum_length, generation_expression, extra
|
|
1942
1938
|
FROM information_schema.columns
|
|
1943
1939
|
WHERE table_schema = DATABASE()
|
|
1944
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
1940
|
+
ORDER BY table_name, ordinal_position`), r = z(yield* e`
|
|
1945
1941
|
SELECT k.table_name AS source_table,
|
|
1946
1942
|
k.column_name AS source_column,
|
|
1947
1943
|
k.referenced_table_name AS target_table,
|
|
@@ -1951,7 +1947,7 @@ BEGIN
|
|
|
1951
1947
|
JOIN information_schema.referential_constraints r
|
|
1952
1948
|
ON k.constraint_name = r.constraint_name
|
|
1953
1949
|
AND k.table_schema = r.constraint_schema
|
|
1954
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
1950
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = z(yield* e`
|
|
1955
1951
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
1956
1952
|
FROM information_schema.statistics
|
|
1957
1953
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -1964,14 +1960,14 @@ BEGIN
|
|
|
1964
1960
|
JOIN information_schema.table_constraints tc
|
|
1965
1961
|
ON tc.constraint_schema = cc.constraint_schema
|
|
1966
1962
|
AND tc.constraint_name = cc.constraint_name
|
|
1967
|
-
WHERE cc.constraint_schema = DATABASE()`.unprepared, s =
|
|
1963
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared, s = z(yield* a.pipe(w.orElse(() => o), w.orElseSucceed(() => []))), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map();
|
|
1968
1964
|
for (let e of s) {
|
|
1969
1965
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
1970
1966
|
if (t) {
|
|
1971
1967
|
c.add(`${e.table_name}.${t[1]}`);
|
|
1972
1968
|
continue;
|
|
1973
1969
|
}
|
|
1974
|
-
let n =
|
|
1970
|
+
let n = Un(e.check_clause);
|
|
1975
1971
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
1976
1972
|
}
|
|
1977
1973
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -1994,24 +1990,24 @@ BEGIN
|
|
|
1994
1990
|
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
1991
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1996
1992
|
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" :
|
|
1993
|
+
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" : Qn(t.data_type, t.column_type), u = o ? {
|
|
1998
1994
|
table: o.target_table,
|
|
1999
1995
|
column: o.target_column,
|
|
2000
|
-
onDelete:
|
|
2001
|
-
onUpdate:
|
|
1996
|
+
onDelete: R(o.delete_rule),
|
|
1997
|
+
onUpdate: R(o.update_rule)
|
|
2002
1998
|
} : 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
1999
|
return {
|
|
2004
2000
|
name: t.column_name,
|
|
2005
2001
|
type: s,
|
|
2006
2002
|
nullable: t.is_nullable === "YES",
|
|
2007
|
-
...
|
|
2003
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
2008
2004
|
unique: d,
|
|
2009
2005
|
hasDefault: f !== null,
|
|
2010
2006
|
...f === null ? {} : { defaultValue: f },
|
|
2011
2007
|
...u ? { references: u } : {},
|
|
2012
|
-
...o ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2008
|
+
...o ? { referenceStorage: ["integer", "bigint"].includes(Qn(t.data_type, t.column_type)) ? "numeric" : "text" } : {},
|
|
2013
2009
|
...p ? { oneOf: p } : {},
|
|
2014
|
-
...
|
|
2010
|
+
...Gn(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {}
|
|
2015
2011
|
};
|
|
2016
2012
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
2017
2013
|
if (o) for (let [t, n] of o) {
|
|
@@ -2038,10 +2034,10 @@ BEGIN
|
|
|
2038
2034
|
});
|
|
2039
2035
|
}
|
|
2040
2036
|
return { tables: p };
|
|
2041
|
-
}),
|
|
2037
|
+
}), er = (e) => {
|
|
2042
2038
|
let t = e.toUpperCase();
|
|
2043
2039
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
2044
|
-
},
|
|
2040
|
+
}, tr = (e) => e === 1 || e === !0, nr = (e) => w.gen(function* () {
|
|
2045
2041
|
let t = yield* e`
|
|
2046
2042
|
SELECT name, sql FROM sqlite_master
|
|
2047
2043
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -2055,18 +2051,18 @@ BEGIN
|
|
|
2055
2051
|
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
2052
|
for (let t of c) {
|
|
2057
2053
|
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 =
|
|
2054
|
+
if (f.set(t.name, r), t.partial !== void 0 && tr(t.partial)) {
|
|
2055
|
+
let n = Kt((yield* e`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${t.name}`)[0]?.sql ?? "");
|
|
2060
2056
|
n !== void 0 && p.set(t.name, n);
|
|
2061
2057
|
}
|
|
2062
|
-
!p.has(t.name) &&
|
|
2058
|
+
!p.has(t.name) && tr(t.unique) && r.length === 1 && m.add(r[0]);
|
|
2063
2059
|
}
|
|
2064
2060
|
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" :
|
|
2061
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : er(e.type), a = r ? {
|
|
2066
2062
|
table: r.table,
|
|
2067
2063
|
column: r.to,
|
|
2068
|
-
onDelete:
|
|
2069
|
-
onUpdate:
|
|
2064
|
+
onDelete: R(r.on_delete),
|
|
2065
|
+
onUpdate: R(r.on_update)
|
|
2070
2066
|
} : void 0, o = t.get(e.name);
|
|
2071
2067
|
return {
|
|
2072
2068
|
name: e.name,
|
|
@@ -2076,19 +2072,19 @@ BEGIN
|
|
|
2076
2072
|
hasDefault: e.dflt_value !== null,
|
|
2077
2073
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
2078
2074
|
...a ? { references: a } : {},
|
|
2079
|
-
...r ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2075
|
+
...r ? { referenceStorage: ["integer", "bigint"].includes(er(e.type)) ? "numeric" : "text" } : {},
|
|
2080
2076
|
...o ? { oneOf: o } : {},
|
|
2081
|
-
...
|
|
2077
|
+
...Gn(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
2082
2078
|
};
|
|
2083
2079
|
}), g = new Set(s.map((e) => e.from)), _ = [];
|
|
2084
2080
|
for (let e of c) {
|
|
2085
2081
|
if (e.origin === "pk") continue;
|
|
2086
2082
|
let t = f.get(e.name) ?? [], n = p.get(e.name);
|
|
2087
|
-
n === void 0 && t.length === 1 &&
|
|
2083
|
+
n === void 0 && t.length === 1 && tr(e.unique) || (n !== void 0 || t.length !== 1 || tr(e.unique) || !g.has(t[0]) || e.name === `${i}_${t[0]}_idx`) && _.push({
|
|
2088
2084
|
name: e.name,
|
|
2089
2085
|
table: i,
|
|
2090
2086
|
columns: t,
|
|
2091
|
-
unique:
|
|
2087
|
+
unique: tr(e.unique),
|
|
2092
2088
|
...n === void 0 ? {} : { where: n }
|
|
2093
2089
|
});
|
|
2094
2090
|
}
|
|
@@ -2104,7 +2100,7 @@ BEGIN
|
|
|
2104
2100
|
});
|
|
2105
2101
|
}
|
|
2106
2102
|
return { tables: r };
|
|
2107
|
-
}),
|
|
2103
|
+
}), rr = (e) => {
|
|
2108
2104
|
switch (e.toLowerCase()) {
|
|
2109
2105
|
case "int":
|
|
2110
2106
|
case "smallint":
|
|
@@ -2126,14 +2122,14 @@ BEGIN
|
|
|
2126
2122
|
case "image": return "bytes";
|
|
2127
2123
|
default: return "text";
|
|
2128
2124
|
}
|
|
2129
|
-
},
|
|
2125
|
+
}, B = (e) => e === !0 || e === 1, ir = (e) => w.gen(function* () {
|
|
2130
2126
|
let t = yield* e`
|
|
2131
2127
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2132
2128
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
2133
2129
|
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
|
|
2134
2130
|
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
2135
2131
|
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length
|
|
2136
|
-
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield*
|
|
2132
|
+
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield* w.orElseSucceed(e`
|
|
2137
2133
|
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS definition,
|
|
2138
2134
|
cc.is_persisted AS is_persisted
|
|
2139
2135
|
FROM sys.computed_columns cc
|
|
@@ -2189,39 +2185,39 @@ BEGIN
|
|
|
2189
2185
|
let t = l.get(e) ?? [], n = u.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), a = new Set(n.map((e) => e.source_column)), o = d.get(e), s = [], p = /* @__PURE__ */ new Set();
|
|
2190
2186
|
if (o) for (let [, e] of o) {
|
|
2191
2187
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2192
|
-
if (
|
|
2193
|
-
else t[0].predicate == null &&
|
|
2188
|
+
if (B(t[0].is_primary)) for (let e of t) s.push(e.column_name);
|
|
2189
|
+
else t[0].predicate == null && B(t[0].is_unique) && t.length === 1 && p.add(t[0].column_name);
|
|
2194
2190
|
}
|
|
2195
2191
|
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" :
|
|
2192
|
+
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" : rr(t.data_type), l = a ? {
|
|
2197
2193
|
table: a.target_table,
|
|
2198
2194
|
column: a.target_column,
|
|
2199
|
-
onDelete:
|
|
2200
|
-
onUpdate:
|
|
2201
|
-
} : void 0, u = t.column_default === null ? null :
|
|
2195
|
+
onDelete: ar(a.delete_rule),
|
|
2196
|
+
onUpdate: ar(a.update_rule)
|
|
2197
|
+
} : void 0, u = t.column_default === null ? null : or(t.column_default), d = c.get(`${e}.${t.column_name}`);
|
|
2202
2198
|
return {
|
|
2203
2199
|
name: t.column_name,
|
|
2204
2200
|
type: o,
|
|
2205
2201
|
nullable: t.is_nullable === "YES",
|
|
2206
|
-
...
|
|
2202
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
2207
2203
|
unique: p.has(t.column_name) || n && t.column_name === "id",
|
|
2208
2204
|
hasDefault: u !== null,
|
|
2209
2205
|
...u === null ? {} : { defaultValue: u },
|
|
2210
2206
|
...l ? { references: l } : {},
|
|
2211
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2207
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(rr(t.data_type)) ? "numeric" : "text" } : {},
|
|
2212
2208
|
...d ? { oneOf: d } : {},
|
|
2213
|
-
...
|
|
2209
|
+
...Gn(i.get(`${e}.${t.column_name}`)?.definition ?? null, B(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2214
2210
|
};
|
|
2215
2211
|
}), h = [];
|
|
2216
2212
|
if (o) for (let [t, n] of o) {
|
|
2217
2213
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2218
|
-
if (
|
|
2214
|
+
if (B(r[0].is_primary)) continue;
|
|
2219
2215
|
let i = r[0].predicate ?? void 0;
|
|
2220
|
-
i === void 0 && r.length === 1 &&
|
|
2216
|
+
i === void 0 && r.length === 1 && B(r[0].is_unique) || (i !== void 0 || r.length !== 1 || B(r[0].is_unique) || !a.has(r[0].column_name) || t === `${e}_${r[0].column_name}_idx`) && h.push({
|
|
2221
2217
|
name: t,
|
|
2222
2218
|
table: e,
|
|
2223
2219
|
columns: r.map((e) => e.column_name),
|
|
2224
|
-
unique:
|
|
2220
|
+
unique: B(r[0].is_unique),
|
|
2225
2221
|
...i === void 0 ? {} : { where: i }
|
|
2226
2222
|
});
|
|
2227
2223
|
}
|
|
@@ -2237,90 +2233,90 @@ BEGIN
|
|
|
2237
2233
|
});
|
|
2238
2234
|
}
|
|
2239
2235
|
return { tables: f };
|
|
2240
|
-
}),
|
|
2236
|
+
}), ar = (e) => {
|
|
2241
2237
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2242
2238
|
case "CASCADE": return "cascade";
|
|
2243
2239
|
case "SET NULL": return "setNull";
|
|
2244
2240
|
case "SET DEFAULT": return "noAction";
|
|
2245
2241
|
default: return "noAction";
|
|
2246
2242
|
}
|
|
2247
|
-
},
|
|
2243
|
+
}, or = (e) => {
|
|
2248
2244
|
let t = e.trim();
|
|
2249
2245
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2250
2246
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2251
|
-
},
|
|
2247
|
+
}, sr = /* @__PURE__ */ new Set([
|
|
2252
2248
|
"character varying",
|
|
2253
2249
|
"varchar",
|
|
2254
2250
|
"nvarchar",
|
|
2255
2251
|
"char",
|
|
2256
2252
|
"character",
|
|
2257
2253
|
"nchar"
|
|
2258
|
-
]),
|
|
2259
|
-
if (!
|
|
2254
|
+
]), V = (e, t) => {
|
|
2255
|
+
if (!sr.has(e.toLowerCase())) return;
|
|
2260
2256
|
let n = Number(t);
|
|
2261
2257
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2262
|
-
},
|
|
2263
|
-
mysql: () =>
|
|
2264
|
-
mssql: () =>
|
|
2265
|
-
sqlite: () =>
|
|
2266
|
-
orElse: () =>
|
|
2267
|
-
}).pipe(
|
|
2258
|
+
}, cr = /* @__PURE__ */ new Set([O]), lr = (e) => e.onDialectOrElse({
|
|
2259
|
+
mysql: () => $n(e),
|
|
2260
|
+
mssql: () => ir(e),
|
|
2261
|
+
sqlite: () => nr(e),
|
|
2262
|
+
orElse: () => Zn(e)
|
|
2263
|
+
}).pipe(w.map((e) => ({
|
|
2268
2264
|
...e,
|
|
2269
|
-
tables: e.tables.filter((e) => !
|
|
2270
|
-
}))),
|
|
2271
|
-
let t =
|
|
2272
|
-
return t === void 0 ?
|
|
2273
|
-
}),
|
|
2265
|
+
tables: e.tables.filter((e) => !cr.has(e.name))
|
|
2266
|
+
}))), ur = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", dr = /* @__PURE__ */ new WeakMap(), H = (e) => w.suspend(() => {
|
|
2267
|
+
let t = dr.get(e);
|
|
2268
|
+
return t === void 0 ? fr(e).pipe(w.tap((t) => w.sync(() => dr.set(e, t)))) : w.succeed(t);
|
|
2269
|
+
}), fr = (e) => e.unsafe("SELECT VERSION() AS v").pipe(w.map((e) => {
|
|
2274
2270
|
let t = e[0]?.v;
|
|
2275
|
-
return typeof t == "string" ?
|
|
2276
|
-
}),
|
|
2271
|
+
return typeof t == "string" ? ur(t) : "mysql";
|
|
2272
|
+
}), w.catchAll(() => w.succeed("mysql"))), pr = (e) => {
|
|
2277
2273
|
let t = e;
|
|
2278
2274
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2279
2275
|
let e = t;
|
|
2280
2276
|
if (typeof e.errno == "number") return e.errno;
|
|
2281
2277
|
t = e.cause;
|
|
2282
2278
|
}
|
|
2283
|
-
},
|
|
2279
|
+
}, mr = (e) => {
|
|
2284
2280
|
let t = [], n = e;
|
|
2285
2281
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2286
2282
|
let e = n;
|
|
2287
2283
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2288
2284
|
}
|
|
2289
2285
|
return t.join(" | ");
|
|
2290
|
-
},
|
|
2286
|
+
}, hr = (e, t) => {
|
|
2291
2287
|
if (t.length === 0) return !1;
|
|
2292
|
-
let n =
|
|
2288
|
+
let n = pr(e), r = mr(e);
|
|
2293
2289
|
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
|
-
},
|
|
2290
|
+
}, gr = {
|
|
2295
2291
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2296
2292
|
errno: [1061]
|
|
2297
|
-
},
|
|
2293
|
+
}, _r = {
|
|
2298
2294
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2299
2295
|
errno: [1091]
|
|
2300
|
-
},
|
|
2296
|
+
}, vr = {
|
|
2301
2297
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2302
2298
|
messageIncludes: ["no such column"]
|
|
2303
|
-
},
|
|
2299
|
+
}, yr = {
|
|
2304
2300
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2305
2301
|
errno: [1091, 3940]
|
|
2306
2302
|
}, U = (e, t) => e.onDialectOrElse({
|
|
2307
|
-
mysql: () =>
|
|
2308
|
-
orElse: () =>
|
|
2309
|
-
}),
|
|
2310
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2303
|
+
mysql: () => w.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2304
|
+
orElse: () => w.succeed(t)
|
|
2305
|
+
}), br = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, xr = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), Sr = (e, t) => {
|
|
2306
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !xr(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2311
2307
|
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
2308
|
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
|
-
return
|
|
2314
|
-
},
|
|
2315
|
-
let t =
|
|
2316
|
-
return t === void 0 ?
|
|
2317
|
-
},
|
|
2309
|
+
return j(e, t);
|
|
2310
|
+
}, Cr = (e) => {
|
|
2311
|
+
let t = Sr(e, "postgres");
|
|
2312
|
+
return t === void 0 ? wr(e) : t;
|
|
2313
|
+
}, wr = (e) => {
|
|
2318
2314
|
switch (e.type) {
|
|
2319
2315
|
case "id": return "text";
|
|
2320
2316
|
case "text": return "text";
|
|
2321
2317
|
case "integer": return "integer";
|
|
2322
2318
|
case "real": return "double precision";
|
|
2323
|
-
case "decimal": return
|
|
2319
|
+
case "decimal": return br(e, "NUMERIC");
|
|
2324
2320
|
case "bigint": return "bigint";
|
|
2325
2321
|
case "boolean": return "boolean";
|
|
2326
2322
|
case "timestamp": return "timestamptz";
|
|
@@ -2334,15 +2330,15 @@ BEGIN
|
|
|
2334
2330
|
case "interval": return "interval";
|
|
2335
2331
|
case "raw": return e.rawDdl ?? "text";
|
|
2336
2332
|
}
|
|
2337
|
-
},
|
|
2338
|
-
let t =
|
|
2333
|
+
}, Tr = (e) => {
|
|
2334
|
+
let t = Sr(e, "mariadb");
|
|
2339
2335
|
if (t !== void 0) return t;
|
|
2340
2336
|
switch (e.type) {
|
|
2341
2337
|
case "id": return "VARCHAR(64)";
|
|
2342
2338
|
case "text": return "LONGTEXT";
|
|
2343
2339
|
case "integer": return "INT";
|
|
2344
2340
|
case "real": return "DOUBLE";
|
|
2345
|
-
case "decimal": return
|
|
2341
|
+
case "decimal": return br(e, "DECIMAL");
|
|
2346
2342
|
case "bigint": return "BIGINT";
|
|
2347
2343
|
case "boolean": return "TINYINT(1)";
|
|
2348
2344
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2356,38 +2352,38 @@ BEGIN
|
|
|
2356
2352
|
case "interval": return "BIGINT";
|
|
2357
2353
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2358
2354
|
}
|
|
2359
|
-
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2355
|
+
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``, Er = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", Dr = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, Or = (e, t = "mariadb") => `ALTER TABLE ${G(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${G(e.column)}, ALGORITHM=COPY;`, kr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Ar = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${ai(t)}`)};`, jr = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Nr(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, Mr = (e, t) => {
|
|
2360
2356
|
let { defaultFactory: n, ...r } = e;
|
|
2361
|
-
return
|
|
2357
|
+
return j(e, t) !== j({
|
|
2362
2358
|
...r,
|
|
2363
2359
|
hasDefault: !1
|
|
2364
2360
|
}, t);
|
|
2365
|
-
},
|
|
2361
|
+
}, Nr = (e, t) => {
|
|
2366
2362
|
let n = t(e.defaultValue);
|
|
2367
2363
|
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
2364
|
return n;
|
|
2369
|
-
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2365
|
+
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Pr = (e, t, n) => {
|
|
2370
2366
|
let r = K(e, t, n);
|
|
2371
|
-
return r ?
|
|
2372
|
-
},
|
|
2373
|
-
let r = n ?? e.nullable, i =
|
|
2367
|
+
return r ? tn(n, r) : void 0;
|
|
2368
|
+
}, Fr = (e, t, n) => {
|
|
2369
|
+
let r = n ?? e.nullable, i = it(e, "mariadb");
|
|
2374
2370
|
return [
|
|
2375
2371
|
G(t),
|
|
2376
|
-
|
|
2372
|
+
j(e, "mariadb"),
|
|
2377
2373
|
r ? null : "NOT NULL",
|
|
2378
2374
|
i
|
|
2379
2375
|
].filter(Boolean).join(" ");
|
|
2380
|
-
},
|
|
2376
|
+
}, Ir = (e, t) => e == null ? null : Array.isArray(e) ? Lr(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" ? M(e, "mariadb") : null, Lr = (e, t, n) => at(e, t ?? { type: "json" }, n), Rr = (e, t) => e == null ? null : Array.isArray(e) ? Lr(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" ? M(e, "postgres") : null, zr = (e, t) => {
|
|
2381
2377
|
if (!e.generatedAs) return null;
|
|
2382
2378
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2383
2379
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2384
|
-
},
|
|
2385
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2386
|
-
let t =
|
|
2387
|
-
if (t) return `${W(e.name)} ${
|
|
2388
|
-
let n = [W(e.name),
|
|
2380
|
+
}, Br = (e) => {
|
|
2381
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "postgres");
|
|
2382
|
+
let t = zr(e, "postgres");
|
|
2383
|
+
if (t) return `${W(e.name)} ${Cr(e)} ${t}`;
|
|
2384
|
+
let n = [W(e.name), Cr(e)];
|
|
2389
2385
|
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 =
|
|
2386
|
+
let t = Rr(e.defaultValue, e);
|
|
2391
2387
|
t && n.push(t);
|
|
2392
2388
|
}
|
|
2393
2389
|
return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
@@ -2396,24 +2392,24 @@ BEGIN
|
|
|
2396
2392
|
setNull: "SET NULL",
|
|
2397
2393
|
noAction: "NO ACTION"
|
|
2398
2394
|
}[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(
|
|
2395
|
+
}, Vr = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Hr = (e) => {
|
|
2396
|
+
let t = e.columns.map((e) => ` ${Br(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Vr(e, W)}\n)`];
|
|
2397
|
+
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(ui).join(", ")})${Y(t)}`);
|
|
2402
2398
|
return n;
|
|
2403
|
-
},
|
|
2404
|
-
let t =
|
|
2399
|
+
}, Ur = 191, Wr = (e) => {
|
|
2400
|
+
let t = Tr(e).toUpperCase();
|
|
2405
2401
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2406
|
-
},
|
|
2407
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
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 =
|
|
2402
|
+
}, Gr = (e) => {
|
|
2403
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mariadb");
|
|
2404
|
+
let t = zr(e, "mariadb");
|
|
2405
|
+
if (t) return `${G(e.name)} ${Tr(e)} ${t}`;
|
|
2406
|
+
let n = [G(e.name), Tr(e)];
|
|
2407
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !Wr(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2408
|
+
let t = Ir(e.defaultValue, e);
|
|
2413
2409
|
t && n.push(t);
|
|
2414
2410
|
}
|
|
2415
2411
|
return n.join(" ");
|
|
2416
|
-
},
|
|
2412
|
+
}, Kr = (e) => e.columns.flatMap((t) => {
|
|
2417
2413
|
if (!t.references) return [];
|
|
2418
2414
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2419
2415
|
cascade: "CASCADE",
|
|
@@ -2422,27 +2418,27 @@ BEGIN
|
|
|
2422
2418
|
noAction: "NO ACTION"
|
|
2423
2419
|
}[t.references.onDelete]}` : "";
|
|
2424
2420
|
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)
|
|
2421
|
+
}), qr = (e, t = "mariadb") => {
|
|
2422
|
+
for (let n of e.indexes) pi(n, t);
|
|
2427
2423
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2428
|
-
let t =
|
|
2424
|
+
let t = ci(n.get(e));
|
|
2429
2425
|
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 ${
|
|
2426
|
+
}, i = e.columns.map((e) => ` ${Gr(e)}`).join(",\n"), a = Kr(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${o}${Vr(e, r)}\n)`];
|
|
2427
|
+
for (let n of e.columns) n.unique && n.type !== "id" && Wr(n) && s.push(`CREATE UNIQUE INDEX ${Er(t)}${G(`${e.table}_${n.name}_key`)} ON ${G(e.table)} (${r(n.name)})`);
|
|
2428
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Er(t)}${G(n.name)} ON ${G(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2433
2429
|
return s;
|
|
2434
|
-
},
|
|
2430
|
+
}, Jr = {
|
|
2435
2431
|
cascade: "CASCADE",
|
|
2436
2432
|
restrict: "RESTRICT",
|
|
2437
2433
|
setNull: "SET NULL",
|
|
2438
2434
|
noAction: "NO ACTION"
|
|
2439
|
-
},
|
|
2435
|
+
}, Yr = {
|
|
2440
2436
|
cascade: "CASCADE",
|
|
2441
2437
|
restrict: "NO ACTION",
|
|
2442
2438
|
setNull: "SET NULL",
|
|
2443
2439
|
noAction: "NO ACTION"
|
|
2444
|
-
},
|
|
2445
|
-
let t =
|
|
2440
|
+
}, Xr = (e) => {
|
|
2441
|
+
let t = Sr(e, "sqlite");
|
|
2446
2442
|
if (t !== void 0) return t;
|
|
2447
2443
|
switch (e.type) {
|
|
2448
2444
|
case "integer":
|
|
@@ -2454,29 +2450,29 @@ BEGIN
|
|
|
2454
2450
|
case "bytes": return "BLOB";
|
|
2455
2451
|
default: return "TEXT";
|
|
2456
2452
|
}
|
|
2457
|
-
},
|
|
2458
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2459
|
-
let t =
|
|
2460
|
-
if (t) return `${W(e.name)} ${
|
|
2461
|
-
let n = [W(e.name),
|
|
2453
|
+
}, Zr = (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" ? M(e, "sqlite") : null, Qr = (e) => {
|
|
2454
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "sqlite");
|
|
2455
|
+
let t = zr(e, "sqlite");
|
|
2456
|
+
if (t) return `${W(e.name)} ${Xr(e)} ${t}`;
|
|
2457
|
+
let n = [W(e.name), Xr(e)];
|
|
2462
2458
|
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 =
|
|
2459
|
+
let t = Zr(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2464
2460
|
t && n.push(t);
|
|
2465
2461
|
}
|
|
2466
|
-
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${
|
|
2462
|
+
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Jr[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2467
2463
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2468
2464
|
n.push(`CHECK (${W(e.name)} IN (${t}))`);
|
|
2469
2465
|
}
|
|
2470
2466
|
return n.join(" ");
|
|
2471
|
-
},
|
|
2472
|
-
let t = e.columns.map((e) => ` ${
|
|
2467
|
+
}, $r = (e) => {
|
|
2468
|
+
let t = e.columns.map((e) => ` ${Qr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Vr(e, W)}\n)`];
|
|
2473
2469
|
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
2470
|
return n;
|
|
2475
2471
|
}, q = (e, t) => {
|
|
2476
2472
|
let n = t.find((t) => t.tableName === e);
|
|
2477
2473
|
if (!n) return [];
|
|
2478
|
-
let r =
|
|
2479
|
-
|
|
2474
|
+
let r = F([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => W(e.name)).join(", "), o = [
|
|
2475
|
+
...$r({
|
|
2480
2476
|
kind: "create-table",
|
|
2481
2477
|
table: i,
|
|
2482
2478
|
columns: r.columns,
|
|
@@ -2489,25 +2485,25 @@ BEGIN
|
|
|
2489
2485
|
];
|
|
2490
2486
|
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
2487
|
return o;
|
|
2492
|
-
},
|
|
2488
|
+
}, ei = (e, t, n, r) => {
|
|
2493
2489
|
let i = r ?? e.nullable;
|
|
2494
|
-
return `ALTER TABLE ${J(n)} ALTER COLUMN ${J(t)} ${
|
|
2495
|
-
},
|
|
2490
|
+
return `ALTER TABLE ${J(n)} ALTER COLUMN ${J(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2491
|
+
}, ti = (e, t) => {
|
|
2496
2492
|
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
2493
|
if (!e.hasDefault) return n;
|
|
2498
|
-
let r =
|
|
2494
|
+
let r = Zr(e.defaultValue, "SYSUTCDATETIME()");
|
|
2499
2495
|
if (!r) return n;
|
|
2500
2496
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2501
2497
|
return `${n} ALTER TABLE ${J(e.table)} ADD DEFAULT ${i} FOR ${J(e.column)};`;
|
|
2502
|
-
}, J = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2503
|
-
let t =
|
|
2498
|
+
}, J = (e) => `[${e.replace(/]/g, "]]")}]`, ni = (e) => {
|
|
2499
|
+
let t = Sr(e, "mssql");
|
|
2504
2500
|
if (t !== void 0) return t;
|
|
2505
2501
|
switch (e.type) {
|
|
2506
2502
|
case "id": return "NVARCHAR(64)";
|
|
2507
2503
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
2508
2504
|
case "integer": return "INT";
|
|
2509
2505
|
case "real": return "FLOAT";
|
|
2510
|
-
case "decimal": return
|
|
2506
|
+
case "decimal": return br(e, "DECIMAL");
|
|
2511
2507
|
case "bigint": return "BIGINT";
|
|
2512
2508
|
case "boolean": return "BIT";
|
|
2513
2509
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2515,46 +2511,46 @@ BEGIN
|
|
|
2515
2511
|
case "bytes": return "VARBINARY(MAX)";
|
|
2516
2512
|
default: return "NVARCHAR(MAX)";
|
|
2517
2513
|
}
|
|
2518
|
-
},
|
|
2519
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2520
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2514
|
+
}, ri = (e, t) => {
|
|
2515
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mssql");
|
|
2516
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : ni(e), r = zr(e, "mssql");
|
|
2521
2517
|
if (r) return `${J(e.name)} ${r}`;
|
|
2522
2518
|
let i = [J(e.name), n];
|
|
2523
2519
|
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 =
|
|
2520
|
+
let t = Zr(e.defaultValue, "SYSUTCDATETIME()");
|
|
2525
2521
|
t && i.push(t);
|
|
2526
2522
|
}
|
|
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) => ` ${
|
|
2523
|
+
return e.references && (i.push(`REFERENCES ${J(e.references.table)} (${J(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${Yr[e.references.onDelete]}`)), i.join(" ");
|
|
2524
|
+
}, ii = (e) => {
|
|
2525
|
+
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) => ` ${ri(e, n)}`).join(",\n"), i = `CREATE TABLE ${J(e.table)} (\n${r}${Vr(e, J)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2530
2526
|
for (let n of e.indexes) {
|
|
2531
2527
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2532
2528
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${J(n.name)} ON ${J(e.table)} (${n.columns.map(J).join(", ")})${Y(n)}`;
|
|
2533
2529
|
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
2530
|
}
|
|
2535
2531
|
return a;
|
|
2536
|
-
},
|
|
2537
|
-
let r = `${e.table}${
|
|
2532
|
+
}, ai = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, oi = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, si = (e, t, n) => {
|
|
2533
|
+
let r = `${e.table}${ai(t)}`;
|
|
2538
2534
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2539
|
-
},
|
|
2540
|
-
if (e === void 0 || !
|
|
2535
|
+
}, ci = (e) => {
|
|
2536
|
+
if (e === void 0 || !Wr(e)) return;
|
|
2541
2537
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2542
|
-
return t === void 0 ?
|
|
2543
|
-
},
|
|
2544
|
-
let r =
|
|
2538
|
+
return t === void 0 ? Ur : Math.min(Ur, t);
|
|
2539
|
+
}, li = (e, t, n) => {
|
|
2540
|
+
let r = ci(Pr(e, t, n));
|
|
2545
2541
|
return r === void 0 ? G(n) : `${G(n)}(${r})`;
|
|
2546
|
-
},
|
|
2542
|
+
}, ui = (e) => e.startsWith("(") ? e : W(e), Y = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, di = (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(ui).join(", ")})${Y(e.index)};`, fi = (e, t, n = "mariadb") => (pi(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Er(n)}${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map((n) => li(t, e.table, n)).join(", ")});`), pi = (e, t) => {
|
|
2547
2543
|
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
|
-
},
|
|
2544
|
+
}, mi = (e) => `DROP INDEX IF EXISTS ${W(e.index)};`, hi = (e) => `DROP INDEX ${G(e.index)} ON ${G(e.table)};`, gi = (e) => `DROP INDEX IF EXISTS ${J(e.index)} ON ${J(e.table)};`, _i = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, vi = (e) => {
|
|
2549
2545
|
let t = (e) => e.replace(/'/g, "''");
|
|
2550
2546
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2551
|
-
},
|
|
2547
|
+
}, yi = (e) => `ALTER INDEX ${W(e.from)} RENAME TO ${W(e.to)};`, bi = (e) => `ALTER TABLE ${G(e.table)} RENAME INDEX ${G(e.from)} TO ${G(e.to)};`, xi = (e) => {
|
|
2552
2548
|
let t = (e) => e.replace(/'/g, "''");
|
|
2553
2549
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2554
|
-
},
|
|
2550
|
+
}, Si = (e) => {
|
|
2555
2551
|
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
2552
|
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
|
-
},
|
|
2553
|
+
}, Ci = (e, t, n) => {
|
|
2558
2554
|
let r = n.find((t) => t.tableName === e);
|
|
2559
2555
|
if (!r) return [];
|
|
2560
2556
|
let i = [];
|
|
@@ -2563,13 +2559,13 @@ BEGIN
|
|
|
2563
2559
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${J(e)} ALTER COLUMN ${J(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2564
2560
|
}
|
|
2565
2561
|
return i;
|
|
2566
|
-
},
|
|
2562
|
+
}, wi = (e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${W(e.column)});`, Ti = (e, t) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${li(t, e.table, e.column)});`, Ei = (e) => {
|
|
2567
2563
|
let t = e.fields.map((e) => W(e)).join(", ");
|
|
2568
2564
|
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
|
|
2569
|
-
},
|
|
2570
|
-
let n = e.fields.map((n) =>
|
|
2565
|
+
}, Di = (e, t) => {
|
|
2566
|
+
let n = e.fields.map((n) => li(t, e.table, n)).join(", ");
|
|
2571
2567
|
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
|
|
2572
|
-
},
|
|
2568
|
+
}, Oi = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(e.name)};`, ki = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(e.name)};`, Ai = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_key`)};`, ji = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(`${e.table}_${e.column}_key`)};`, Mi = (e, t) => {
|
|
2573
2569
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2574
2570
|
if (e.orphanPolicy) {
|
|
2575
2571
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2587,34 +2583,34 @@ BEGIN
|
|
|
2587
2583
|
setNull: "SET NULL",
|
|
2588
2584
|
noAction: "NO ACTION"
|
|
2589
2585
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2590
|
-
},
|
|
2586
|
+
}, Ni = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_fkey`)};`, Pi = (e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(`${e.table}_${e.column}_fkey`)};`, Fi = (e, t) => {
|
|
2591
2587
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2592
2588
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2593
|
-
},
|
|
2589
|
+
}, Ii = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Li = (e, t) => w.gen(function* () {
|
|
2594
2590
|
let n = yield* e`
|
|
2595
2591
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2596
2592
|
FROM information_schema.check_constraints cc
|
|
2597
|
-
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(
|
|
2593
|
+
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(w.orElse(() => e`
|
|
2598
2594
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2599
2595
|
FROM information_schema.check_constraints cc
|
|
2600
2596
|
JOIN information_schema.table_constraints tc
|
|
2601
2597
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2602
2598
|
AND tc.constraint_name = cc.constraint_name
|
|
2603
|
-
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`),
|
|
2599
|
+
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`), w.orElseSucceed(() => []));
|
|
2604
2600
|
for (let e of n) {
|
|
2605
2601
|
let n = String(e.n ?? "");
|
|
2606
|
-
if (n !== "" &&
|
|
2602
|
+
if (n !== "" && Un(String(e.c ?? ""))?.column === t.column) return n;
|
|
2607
2603
|
}
|
|
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*
|
|
2604
|
+
}), Ri = (e, t, n) => w.gen(function* () {
|
|
2605
|
+
let r = yield* Li(e, t);
|
|
2606
|
+
r !== void 0 && (yield* X(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [yr]));
|
|
2607
|
+
let i = yield* Li(e, t);
|
|
2612
2608
|
if (i === void 0) return;
|
|
2613
2609
|
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 ?
|
|
2610
|
+
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.`));
|
|
2611
|
+
yield* X(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${Fr(a, t.column)};`, t.kind);
|
|
2612
|
+
}), zi = (e, t, n, r) => {
|
|
2613
|
+
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? J : W, s = a ? Tr(i) : r === "mssql" ? ni(i) : r === "sqlite" ? Xr(i) : Cr(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? Ir(e, i) : r === "mssql" ? Zr(e, "SYSUTCDATETIME()") : r === "sqlite" ? Zr(e, "CURRENT_TIMESTAMP") : Rr(e, i), u = zr(i, r);
|
|
2618
2614
|
if (u) {
|
|
2619
2615
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2620
2616
|
return {
|
|
@@ -2642,7 +2638,7 @@ BEGIN
|
|
|
2642
2638
|
post: f ? [f] : []
|
|
2643
2639
|
};
|
|
2644
2640
|
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
|
-
},
|
|
2641
|
+
}, Bi = (e) => {
|
|
2646
2642
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2647
2643
|
return (e, n) => {
|
|
2648
2644
|
let r = t.get(e);
|
|
@@ -2662,47 +2658,47 @@ BEGIN
|
|
|
2662
2658
|
...o
|
|
2663
2659
|
};
|
|
2664
2660
|
};
|
|
2665
|
-
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(
|
|
2666
|
-
process.stderr.write(
|
|
2667
|
-
})),
|
|
2668
|
-
let r =
|
|
2661
|
+
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(w.catchIf((e) => hr(e, r), () => w.void), w.tapError((e) => w.sync(() => {
|
|
2662
|
+
process.stderr.write(ce(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2663
|
+
})), w.mapError((e) => {
|
|
2664
|
+
let r = ce(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2669
2665
|
return Object.assign(e, { message: r });
|
|
2670
|
-
}),
|
|
2671
|
-
let n =
|
|
2672
|
-
if (!n) return yield*
|
|
2666
|
+
}), 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))), Vi = (e, t) => w.gen(function* () {
|
|
2667
|
+
let n = F([Ve], t).tables[0];
|
|
2668
|
+
if (!n) return yield* w.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2673
2669
|
let r = {
|
|
2674
2670
|
kind: "create-table",
|
|
2675
|
-
table:
|
|
2671
|
+
table: O,
|
|
2676
2672
|
columns: n.columns,
|
|
2677
2673
|
indexes: []
|
|
2678
2674
|
}, i = yield* e.onDialectOrElse({
|
|
2679
|
-
mysql: () =>
|
|
2680
|
-
mssql: () =>
|
|
2681
|
-
sqlite: () =>
|
|
2682
|
-
orElse: () =>
|
|
2675
|
+
mysql: () => H(e).pipe(w.map((e) => qr(r, e))),
|
|
2676
|
+
mssql: () => w.succeed(ii(r)),
|
|
2677
|
+
sqlite: () => w.succeed($r(r)),
|
|
2678
|
+
orElse: () => w.succeed(Hr(r))
|
|
2683
2679
|
});
|
|
2684
|
-
yield*
|
|
2685
|
-
}),
|
|
2680
|
+
yield* w.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2681
|
+
}), Hi = (e) => e`
|
|
2686
2682
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2687
2683
|
${e("status")}, ${e("payload")}
|
|
2688
|
-
FROM ${e(
|
|
2689
|
-
`,
|
|
2684
|
+
FROM ${e(O)}
|
|
2685
|
+
`, Ui = (e, t, n, r) => w.gen(function* () {
|
|
2690
2686
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2691
|
-
yield*
|
|
2692
|
-
INSERT INTO ${e(
|
|
2687
|
+
yield* w.forEach(r, ({ index: r, planned: a }) => e`
|
|
2688
|
+
INSERT INTO ${e(O)}
|
|
2693
2689
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2694
2690
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2695
2691
|
${e("createdAt")})
|
|
2696
2692
|
VALUES
|
|
2697
2693
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2698
|
-
${a.op.kind}, ${
|
|
2694
|
+
${a.op.kind}, ${Ue(a.op)}, ${"pending"},
|
|
2699
2695
|
${JSON.stringify(a)}, ${i})
|
|
2700
2696
|
`, { discard: !0 });
|
|
2701
|
-
}),
|
|
2697
|
+
}), Wi = (e, t, n, r, i) => w.gen(function* () {
|
|
2702
2698
|
let a = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2703
2699
|
if (r === "applied") {
|
|
2704
2700
|
yield* e`
|
|
2705
|
-
UPDATE ${e(
|
|
2701
|
+
UPDATE ${e(O)}
|
|
2706
2702
|
SET ${e("status")} = ${r}, ${e("appliedAt")} = ${a},
|
|
2707
2703
|
${e("durationMs")} = ${i ?? null}
|
|
2708
2704
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
@@ -2710,50 +2706,50 @@ BEGIN
|
|
|
2710
2706
|
return;
|
|
2711
2707
|
}
|
|
2712
2708
|
yield* e`
|
|
2713
|
-
UPDATE ${e(
|
|
2709
|
+
UPDATE ${e(O)}
|
|
2714
2710
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2715
2711
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2716
2712
|
`;
|
|
2717
|
-
}),
|
|
2713
|
+
}), Gi = (e, t, n, r) => w.gen(function* () {
|
|
2718
2714
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2719
2715
|
r.length > 0 && (yield* e`
|
|
2720
|
-
UPDATE ${e(
|
|
2716
|
+
UPDATE ${e(O)}
|
|
2721
2717
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
2722
2718
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(r)}
|
|
2723
2719
|
`), n.length > 0 && (yield* e`
|
|
2724
|
-
UPDATE ${e(
|
|
2720
|
+
UPDATE ${e(O)}
|
|
2725
2721
|
SET ${e("status")} = ${"pending"}
|
|
2726
2722
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2727
2723
|
`);
|
|
2728
|
-
}),
|
|
2729
|
-
if (
|
|
2724
|
+
}), Ki = (e, t) => t === void 0 ? e`DELETE FROM ${e(O)}`.pipe(w.asVoid) : e`DELETE FROM ${e(O)} WHERE ${e("runId")} = ${t}`.pipe(w.asVoid), qi = (e, t, n) => w.gen(function* () {
|
|
2725
|
+
if (Ze(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
2730
2726
|
let r = n.op, i = (e) => o(e, t);
|
|
2731
2727
|
if (t === "sqlite" || t === "turso") {
|
|
2732
2728
|
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*
|
|
2729
|
+
let n = `${r.table}${Ke}`;
|
|
2730
|
+
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
2731
|
}
|
|
2736
2732
|
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 =
|
|
2733
|
+
let a = `${r.column}${qe}`, s = `${r.column}${Je}`, 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" }));
|
|
2734
|
+
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.`));
|
|
2735
|
+
}), Ji = (e, t, n, r = "fresh") => w.gen(function* () {
|
|
2736
|
+
let i = process.hrtime.bigint(), a = Bi(n.declared), o = t.op;
|
|
2741
2737
|
switch (o.kind) {
|
|
2742
2738
|
case "create-table": {
|
|
2743
2739
|
let t = yield* e.onDialectOrElse({
|
|
2744
|
-
mysql: () =>
|
|
2745
|
-
mssql: () =>
|
|
2746
|
-
sqlite: () =>
|
|
2747
|
-
orElse: () =>
|
|
2740
|
+
mysql: () => H(e).pipe(w.map((e) => qr(o, e))),
|
|
2741
|
+
mssql: () => w.succeed(ii(o)),
|
|
2742
|
+
sqlite: () => w.succeed($r(o)),
|
|
2743
|
+
orElse: () => w.succeed(Hr(o))
|
|
2748
2744
|
}), n = yield* e.onDialectOrElse({
|
|
2749
|
-
mysql: () =>
|
|
2750
|
-
orElse: () =>
|
|
2745
|
+
mysql: () => w.succeed([gr]),
|
|
2746
|
+
orElse: () => w.succeed([])
|
|
2751
2747
|
});
|
|
2752
2748
|
for (let r of t) yield* X(e, r, o.kind, n);
|
|
2753
2749
|
break;
|
|
2754
2750
|
}
|
|
2755
2751
|
case "drop-table": {
|
|
2756
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2752
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? si(o, n, e) : oi(o, e);
|
|
2757
2753
|
yield* e.onDialectOrElse({
|
|
2758
2754
|
mysql: () => X(e, r(G), o.kind),
|
|
2759
2755
|
orElse: () => X(e, r(W), o.kind)
|
|
@@ -2763,93 +2759,93 @@ BEGIN
|
|
|
2763
2759
|
case "drop-column": {
|
|
2764
2760
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2765
2761
|
yield* e.onDialectOrElse({
|
|
2766
|
-
mysql: () =>
|
|
2767
|
-
sqlite: () => X(e, t ?
|
|
2768
|
-
orElse: () => X(e, t ?
|
|
2762
|
+
mysql: () => H(e).pipe(w.flatMap((r) => X(e, t ? Ar(o, n, G) : Or(o, r), o.kind, t ? [] : [_r]))),
|
|
2763
|
+
sqlite: () => X(e, t ? Ar(o, n, W) : Dr(o, W, !1), o.kind, t ? [] : [vr]),
|
|
2764
|
+
orElse: () => X(e, t ? Ar(o, n, W) : Dr(o, W), o.kind)
|
|
2769
2765
|
});
|
|
2770
2766
|
break;
|
|
2771
2767
|
}
|
|
2772
2768
|
case "rename-column":
|
|
2773
2769
|
yield* e.onDialectOrElse({
|
|
2774
|
-
mysql: () => X(e,
|
|
2770
|
+
mysql: () => X(e, kr(o, G), o.kind),
|
|
2775
2771
|
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,
|
|
2772
|
+
orElse: () => X(e, kr(o, W), o.kind)
|
|
2777
2773
|
});
|
|
2778
2774
|
break;
|
|
2779
2775
|
case "add-index":
|
|
2780
2776
|
yield* e.onDialectOrElse({
|
|
2781
|
-
sqlite: () => X(e,
|
|
2782
|
-
mysql: () =>
|
|
2783
|
-
mssql: () => Z(e, [...
|
|
2784
|
-
orElse: () => X(e,
|
|
2777
|
+
sqlite: () => X(e, di(o, !1), o.kind),
|
|
2778
|
+
mysql: () => H(e).pipe(w.flatMap((t) => X(e, fi(o, n.declared, t), o.kind, [gr]))),
|
|
2779
|
+
mssql: () => Z(e, [...Ci(o.table, o.index.columns, n.declared), Si(o)], o.kind),
|
|
2780
|
+
orElse: () => X(e, di(o, t.classification === "online-required"), o.kind)
|
|
2785
2781
|
});
|
|
2786
2782
|
break;
|
|
2787
2783
|
case "drop-index":
|
|
2788
2784
|
yield* e.onDialectOrElse({
|
|
2789
|
-
mysql: () => X(e,
|
|
2790
|
-
mssql: () => X(e,
|
|
2791
|
-
orElse: () => X(e,
|
|
2785
|
+
mysql: () => X(e, hi(o), o.kind),
|
|
2786
|
+
mssql: () => X(e, gi(o), o.kind),
|
|
2787
|
+
orElse: () => X(e, mi(o), o.kind)
|
|
2792
2788
|
});
|
|
2793
2789
|
break;
|
|
2794
2790
|
case "rename-table":
|
|
2795
2791
|
yield* e.onDialectOrElse({
|
|
2796
|
-
mysql: () => X(e,
|
|
2797
|
-
mssql: () => X(e,
|
|
2798
|
-
orElse: () => X(e,
|
|
2792
|
+
mysql: () => X(e, _i(o, G), o.kind),
|
|
2793
|
+
mssql: () => X(e, vi(o), o.kind),
|
|
2794
|
+
orElse: () => X(e, _i(o, W), o.kind)
|
|
2799
2795
|
});
|
|
2800
2796
|
break;
|
|
2801
2797
|
case "rename-index":
|
|
2802
2798
|
yield* e.onDialectOrElse({
|
|
2803
|
-
mysql: () => X(e,
|
|
2804
|
-
mssql: () => X(e,
|
|
2805
|
-
orElse: () => X(e,
|
|
2799
|
+
mysql: () => X(e, bi(o), o.kind),
|
|
2800
|
+
mssql: () => X(e, xi(o), o.kind),
|
|
2801
|
+
orElse: () => X(e, yi(o), o.kind)
|
|
2806
2802
|
});
|
|
2807
2803
|
break;
|
|
2808
2804
|
case "add-unique":
|
|
2809
2805
|
yield* e.onDialectOrElse({
|
|
2810
|
-
mysql: () => X(e,
|
|
2806
|
+
mysql: () => X(e, Ti(o, n.declared), o.kind),
|
|
2811
2807
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2812
|
-
mssql: () => Z(e, [...
|
|
2813
|
-
orElse: () => X(e,
|
|
2808
|
+
mssql: () => Z(e, [...Ci(o.table, [o.column], n.declared), wi(o)], o.kind),
|
|
2809
|
+
orElse: () => X(e, wi(o), o.kind)
|
|
2814
2810
|
});
|
|
2815
2811
|
break;
|
|
2816
2812
|
case "drop-unique":
|
|
2817
2813
|
yield* e.onDialectOrElse({
|
|
2818
|
-
mysql: () => X(e,
|
|
2814
|
+
mysql: () => X(e, ji(o), o.kind),
|
|
2819
2815
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2820
|
-
orElse: () => X(e,
|
|
2816
|
+
orElse: () => X(e, Ai(o), o.kind)
|
|
2821
2817
|
});
|
|
2822
2818
|
break;
|
|
2823
2819
|
case "add-unique-composite":
|
|
2824
2820
|
yield* e.onDialectOrElse({
|
|
2825
|
-
mysql: () => X(e,
|
|
2821
|
+
mysql: () => X(e, Di(o, n.declared), o.kind),
|
|
2826
2822
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2827
|
-
mssql: () => Z(e, [...
|
|
2828
|
-
orElse: () => X(e,
|
|
2823
|
+
mssql: () => Z(e, [...Ci(o.table, o.fields, n.declared), Ei(o)], o.kind),
|
|
2824
|
+
orElse: () => X(e, Ei(o), o.kind)
|
|
2829
2825
|
});
|
|
2830
2826
|
break;
|
|
2831
2827
|
case "drop-unique-composite":
|
|
2832
2828
|
yield* e.onDialectOrElse({
|
|
2833
|
-
mysql: () => X(e,
|
|
2829
|
+
mysql: () => X(e, ki(o), o.kind),
|
|
2834
2830
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2835
|
-
orElse: () => X(e,
|
|
2831
|
+
orElse: () => X(e, Oi(o), o.kind)
|
|
2836
2832
|
});
|
|
2837
2833
|
break;
|
|
2838
2834
|
case "add-foreign-key":
|
|
2839
2835
|
yield* e.onDialectOrElse({
|
|
2840
|
-
mysql: () => Z(e,
|
|
2836
|
+
mysql: () => Z(e, Mi(o, G), o.kind),
|
|
2841
2837
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2842
|
-
orElse: () => Z(e,
|
|
2838
|
+
orElse: () => Z(e, Mi(o, W), o.kind)
|
|
2843
2839
|
});
|
|
2844
2840
|
break;
|
|
2845
2841
|
case "add-column": {
|
|
2846
|
-
let n =
|
|
2847
|
-
mysql: () =>
|
|
2848
|
-
mssql: () =>
|
|
2849
|
-
sqlite: () =>
|
|
2850
|
-
orElse: () =>
|
|
2842
|
+
let n = zi(o, t, a, yield* e.onDialectOrElse({
|
|
2843
|
+
mysql: () => w.succeed("mariadb"),
|
|
2844
|
+
mssql: () => w.succeed("mssql"),
|
|
2845
|
+
sqlite: () => w.succeed("sqlite"),
|
|
2846
|
+
orElse: () => w.succeed("postgres")
|
|
2851
2847
|
}));
|
|
2852
|
-
if (!(r === "resume" && (yield* $(e,
|
|
2848
|
+
if (!(r === "resume" && (yield* $(e, Re(e), o.table, o.column.name)))) for (let t of n.pre) yield* X(e, t, o.kind);
|
|
2853
2849
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2854
2850
|
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2855
2851
|
else {
|
|
@@ -2858,10 +2854,10 @@ BEGIN
|
|
|
2858
2854
|
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
2855
|
if (s.length === 0) break;
|
|
2860
2856
|
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*
|
|
2857
|
+
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
2858
|
scope: "voltro:migrate",
|
|
2863
2859
|
mode: "sql-batched"
|
|
2864
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2860
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* w.sleep(`${r} millis`));
|
|
2865
2861
|
}
|
|
2866
2862
|
}
|
|
2867
2863
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
@@ -2870,17 +2866,17 @@ BEGIN
|
|
|
2870
2866
|
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
2867
|
if (s.length === 0) break;
|
|
2872
2868
|
for (let t of s) {
|
|
2873
|
-
let r = yield*
|
|
2869
|
+
let r = yield* w.tryPromise({
|
|
2874
2870
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2875
2871
|
catch: (e) => e
|
|
2876
|
-
}).pipe(
|
|
2872
|
+
}).pipe(w.orDie);
|
|
2877
2873
|
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2878
2874
|
}
|
|
2879
|
-
a += s.length, yield*
|
|
2875
|
+
a += s.length, yield* w.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows processed`).pipe(w.annotateLogs({
|
|
2880
2876
|
scope: "voltro:migrate",
|
|
2881
2877
|
table: o.table,
|
|
2882
2878
|
column: o.column.name
|
|
2883
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2879
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* w.sleep(`${r} millis`));
|
|
2884
2880
|
}
|
|
2885
2881
|
}
|
|
2886
2882
|
for (let t of n.post) yield* X(e, t, o.kind);
|
|
@@ -2890,43 +2886,43 @@ BEGIN
|
|
|
2890
2886
|
yield* e.onDialectOrElse({
|
|
2891
2887
|
mysql: () => {
|
|
2892
2888
|
let t = K(n.declared, o.table, o.column);
|
|
2893
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2889
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Fr(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
2890
|
},
|
|
2895
2891
|
mssql: () => {
|
|
2896
2892
|
let t = K(n.declared, o.table, o.column);
|
|
2897
|
-
return t ? X(e,
|
|
2893
|
+
return t ? X(e, ei(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
2894
|
},
|
|
2899
2895
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2900
2896
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2901
2897
|
});
|
|
2902
2898
|
break;
|
|
2903
2899
|
case "alter-column-default": {
|
|
2904
|
-
let t =
|
|
2900
|
+
let t = Pr(n.declared, o.table, o.column), r = K(n.declared, o.table, o.column), i = (e) => o.hasDefault && r !== void 0 && Mr(r, e) ? r : void 0;
|
|
2905
2901
|
yield* e.onDialectOrElse({
|
|
2906
2902
|
mysql: () => {
|
|
2907
2903
|
let n = i("mariadb");
|
|
2908
|
-
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2904
|
+
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Fr(n, o.column)};` : jr(o, G, (e) => Ir(e, t)), o.kind);
|
|
2909
2905
|
},
|
|
2910
2906
|
mssql: () => {
|
|
2911
2907
|
let t = i("mssql");
|
|
2912
|
-
return X(e,
|
|
2908
|
+
return X(e, ti(o, t ? ei(t, o.column, o.table) : void 0), o.kind);
|
|
2913
2909
|
},
|
|
2914
2910
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2915
|
-
orElse: () => X(e,
|
|
2911
|
+
orElse: () => X(e, jr(o, W, (e) => Rr(e, t)), o.kind)
|
|
2916
2912
|
});
|
|
2917
2913
|
break;
|
|
2918
2914
|
}
|
|
2919
2915
|
case "alter-column-type": {
|
|
2920
|
-
let r =
|
|
2916
|
+
let r = Cr(Pr(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2921
2917
|
if (t.classification !== "online-required") {
|
|
2922
2918
|
yield* e.onDialectOrElse({
|
|
2923
2919
|
mysql: () => {
|
|
2924
2920
|
let t = K(n.declared, o.table, o.column);
|
|
2925
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2921
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Fr(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
2922
|
},
|
|
2927
2923
|
mssql: () => {
|
|
2928
2924
|
let t = K(n.declared, o.table, o.column);
|
|
2929
|
-
return t ? X(e,
|
|
2925
|
+
return t ? X(e, ei(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
2926
|
},
|
|
2931
2927
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2932
2928
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} TYPE ${r}${i};`, o.kind)
|
|
@@ -2934,8 +2930,8 @@ BEGIN
|
|
|
2934
2930
|
break;
|
|
2935
2931
|
}
|
|
2936
2932
|
yield* e.onDialectOrElse({
|
|
2937
|
-
mysql: () =>
|
|
2938
|
-
orElse: () =>
|
|
2933
|
+
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.`)),
|
|
2934
|
+
orElse: () => w.void
|
|
2939
2935
|
});
|
|
2940
2936
|
let a = `${o.column}__shadow`, s = `${o.column}__old`;
|
|
2941
2937
|
yield* e.unsafe(`ALTER TABLE ${W(o.table)} ADD COLUMN ${W(a)} ${r}`);
|
|
@@ -2945,27 +2941,27 @@ BEGIN
|
|
|
2945
2941
|
if (t.length === 0) break;
|
|
2946
2942
|
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
2943
|
}
|
|
2948
|
-
yield*
|
|
2944
|
+
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
2945
|
break;
|
|
2950
2946
|
}
|
|
2951
2947
|
case "drop-foreign-key":
|
|
2952
2948
|
yield* e.onDialectOrElse({
|
|
2953
|
-
mysql: () => X(e,
|
|
2949
|
+
mysql: () => X(e, Pi(o), o.kind),
|
|
2954
2950
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2955
|
-
orElse: () => X(e,
|
|
2951
|
+
orElse: () => X(e, Ni(o), o.kind)
|
|
2956
2952
|
});
|
|
2957
2953
|
break;
|
|
2958
2954
|
case "add-check":
|
|
2959
2955
|
yield* e.onDialectOrElse({
|
|
2960
|
-
mysql: () => X(e,
|
|
2956
|
+
mysql: () => X(e, Fi(o, G), o.kind),
|
|
2961
2957
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2962
|
-
orElse: () => X(e,
|
|
2958
|
+
orElse: () => X(e, Fi(o, W), o.kind)
|
|
2963
2959
|
});
|
|
2964
2960
|
break;
|
|
2965
2961
|
case "drop-check": yield* e.onDialectOrElse({
|
|
2966
|
-
mysql: () =>
|
|
2962
|
+
mysql: () => Ri(e, o, n.declared),
|
|
2967
2963
|
sqlite: () => Z(e, q(o.table, n.declared), o.kind),
|
|
2968
|
-
orElse: () => X(e,
|
|
2964
|
+
orElse: () => X(e, Ii(o), o.kind)
|
|
2969
2965
|
});
|
|
2970
2966
|
}
|
|
2971
2967
|
return {
|
|
@@ -2973,32 +2969,32 @@ BEGIN
|
|
|
2973
2969
|
status: "applied",
|
|
2974
2970
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2975
2971
|
};
|
|
2976
|
-
}),
|
|
2972
|
+
}), Yi = (e, t, n, r) => w.gen(function* () {
|
|
2977
2973
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2978
|
-
if (i.length > 1) return yield*
|
|
2974
|
+
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 \`${O}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
2979
2975
|
let a = i[0], o = [...r].map((e) => ({
|
|
2980
2976
|
index: Number(e.opIndex),
|
|
2981
2977
|
status: e.status,
|
|
2982
2978
|
planned: JSON.parse(e.payload)
|
|
2983
2979
|
})).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*
|
|
2980
|
+
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 \`${O}\` by hand before re-running.`));
|
|
2981
|
+
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} ${Ue(s.planned.op)}` : ""}`).pipe(w.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
2986
2982
|
kind: "discard",
|
|
2987
2983
|
runId: a,
|
|
2988
2984
|
why: "no operation had started — no DDL ran"
|
|
2989
2985
|
};
|
|
2990
|
-
let l = s ? yield*
|
|
2986
|
+
let l = s ? yield* qi(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2991
2987
|
if (u !== n.toFingerprint) return {
|
|
2992
2988
|
kind: "discard",
|
|
2993
2989
|
runId: a,
|
|
2994
2990
|
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
2991
|
};
|
|
2996
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
2992
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : Ge(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
2997
2993
|
return f.length === 0 ? {
|
|
2998
2994
|
kind: "discard",
|
|
2999
2995
|
runId: a,
|
|
3000
2996
|
why: "every recorded operation had already taken effect"
|
|
3001
|
-
} : (yield*
|
|
2997
|
+
} : (yield* Gi(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
2998
|
kind: "resume",
|
|
3003
2999
|
runId: a,
|
|
3004
3000
|
ops: f.map((e) => ({
|
|
@@ -3006,7 +3002,7 @@ BEGIN
|
|
|
3006
3002
|
planned: e.planned
|
|
3007
3003
|
}))
|
|
3008
3004
|
});
|
|
3009
|
-
}),
|
|
3005
|
+
}), Xi = (e, t, n) => w.gen(function* () {
|
|
3010
3006
|
for (let r of t.operations) {
|
|
3011
3007
|
let i = r.op;
|
|
3012
3008
|
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 +3011,9 @@ BEGIN
|
|
|
3015
3011
|
"rename-column"
|
|
3016
3012
|
].includes(e.op.kind))) continue;
|
|
3017
3013
|
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*
|
|
3014
|
+
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
3015
|
}
|
|
3020
|
-
}),
|
|
3016
|
+
}), Zi = (e) => {
|
|
3021
3017
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3022
3018
|
return [
|
|
3023
3019
|
t.kind,
|
|
@@ -3026,80 +3022,75 @@ BEGIN
|
|
|
3026
3022
|
n("name"),
|
|
3027
3023
|
n("to")
|
|
3028
3024
|
].join("\0");
|
|
3029
|
-
},
|
|
3025
|
+
}, Qi = (e, t, n) => w.acquireUseRelease(Ie(e, { schema: n.lockSchema }), () => $i(e, t, n), (e) => e.release.pipe(w.orDie)), $i = (e, t, n) => w.gen(function* () {
|
|
3030
3026
|
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 = {
|
|
3027
|
+
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.`));
|
|
3028
|
+
let i = Date.now(), a = [], o = Re(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => Zi(e))), l = {
|
|
3034
3029
|
...s,
|
|
3035
3030
|
operations: s.operations.map((e) => {
|
|
3036
|
-
if (!e.blocked || !c.has(
|
|
3031
|
+
if (!e.blocked || !c.has(Zi(e))) return e;
|
|
3037
3032
|
let { blocked: t, ...n } = e;
|
|
3038
3033
|
return n;
|
|
3039
3034
|
})
|
|
3040
3035
|
};
|
|
3041
|
-
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield*
|
|
3036
|
+
(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
3037
|
let u = l.operations.filter((e) => e.blocked);
|
|
3043
|
-
if (u.length > 0) return yield*
|
|
3044
|
-
let d =
|
|
3038
|
+
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.`));
|
|
3039
|
+
let d = Be(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
3040
|
index: t,
|
|
3046
3041
|
planned: e
|
|
3047
3042
|
})), _ = "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)];
|
|
3043
|
+
yield* Xi(e, l, o), yield* Vi(e, o);
|
|
3044
|
+
let v = yield* Hi(e);
|
|
3045
|
+
if (v.length > 0) {
|
|
3046
|
+
let t = yield* Yi(e, o, l, v);
|
|
3047
|
+
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* Ki(e, t.runId));
|
|
3048
|
+
}
|
|
3049
|
+
_ === "fresh" && h.length > 0 && (yield* Ui(e, m, l.toFingerprint, h)), f.length > 0 && (yield* e.withTransaction(w.gen(function* () {
|
|
3050
|
+
let e = yield* T.SqlClient;
|
|
3051
|
+
for (let t of f) a.push(yield* Ji(e, t, n));
|
|
3052
|
+
})));
|
|
3053
|
+
for (let { index: t, planned: r } of h) {
|
|
3054
|
+
yield* Wi(e, m, t, "started");
|
|
3055
|
+
let i = a.length, o = yield* Ji(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`) })));
|
|
3056
|
+
a.push(o), yield* Wi(e, m, t, "applied", o.durationMs);
|
|
3057
|
+
}
|
|
3058
|
+
let y = yield* n.replan(e);
|
|
3059
|
+
if (y.operations.length > 0) {
|
|
3060
|
+
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");
|
|
3061
|
+
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.`));
|
|
3062
|
+
}
|
|
3063
|
+
let b = a.filter((e) => e.status === "applied").length, x = Date.now() - i, S = m, C = (/* @__PURE__ */ new Date()).toISOString(), ee = yield* U(e, C), te = [...f, ...h.map((e) => e.planned)];
|
|
3073
3064
|
yield* e`
|
|
3074
3065
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3075
3066
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
3076
3067
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
3077
3068
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
3078
3069
|
VALUES
|
|
3079
|
-
(${
|
|
3070
|
+
(${S}, ${l.toFingerprint}, ${y.fromFingerprint}, ${JSON.stringify(te)},
|
|
3080
3071
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3081
|
-
${
|
|
3082
|
-
`, yield*
|
|
3083
|
-
let
|
|
3084
|
-
return yield*
|
|
3085
|
-
id:
|
|
3086
|
-
appliedAt:
|
|
3072
|
+
${x}, ${ee}, ${n.notes ?? null})
|
|
3073
|
+
`, yield* Ki(e, m);
|
|
3074
|
+
let ne = [...new Set(te.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3075
|
+
return yield* w.promise(() => g({ changedTables: ne }).catch(() => {})), {
|
|
3076
|
+
id: S,
|
|
3077
|
+
appliedAt: C,
|
|
3087
3078
|
fingerprint: l.toFingerprint,
|
|
3088
|
-
operations:
|
|
3079
|
+
operations: te,
|
|
3089
3080
|
appliedBy: n.appliedBy,
|
|
3090
3081
|
environment: n.environment,
|
|
3091
|
-
durationMs:
|
|
3092
|
-
appliedOps:
|
|
3082
|
+
durationMs: x,
|
|
3083
|
+
appliedOps: b,
|
|
3093
3084
|
source: n.source,
|
|
3094
3085
|
...n.notes ? { notes: n.notes } : {}
|
|
3095
3086
|
};
|
|
3096
|
-
}),
|
|
3087
|
+
}), ea = (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"), ta = (e) => e`
|
|
3097
3088
|
SELECT fingerprint
|
|
3098
3089
|
FROM _voltro_migration_plans
|
|
3099
3090
|
ORDER BY ${e("appliedAt")} DESC
|
|
3100
3091
|
LIMIT 1
|
|
3101
|
-
`.pipe(
|
|
3102
|
-
if ((yield*
|
|
3092
|
+
`.pipe(w.map((e) => e.length > 0 ? e[0].fingerprint : void 0), w.catchAll(() => w.succeed(void 0))), na = (e, t, n) => w.gen(function* () {
|
|
3093
|
+
if ((yield* ta(e)) === t.toFingerprint) return "already-current";
|
|
3103
3094
|
let r = `plan_${Date.now().toString(36)}`, i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3104
3095
|
return yield* e`
|
|
3105
3096
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3111,8 +3102,8 @@ BEGIN
|
|
|
3111
3102
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3112
3103
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3113
3104
|
`, "recorded";
|
|
3114
|
-
}).pipe(
|
|
3115
|
-
let n =
|
|
3105
|
+
}).pipe(w.catchAll(() => w.succeed("already-current"))), ra = (e, t) => w.gen(function* () {
|
|
3106
|
+
let n = $t(F(t, Re(e))), r = yield* ta(e);
|
|
3116
3107
|
return r === n ? {
|
|
3117
3108
|
kind: "up-to-date",
|
|
3118
3109
|
fingerprint: n
|
|
@@ -3121,23 +3112,23 @@ BEGIN
|
|
|
3121
3112
|
expected: n,
|
|
3122
3113
|
...r === void 0 ? {} : { actual: r }
|
|
3123
3114
|
};
|
|
3124
|
-
}),
|
|
3115
|
+
}), ia = [
|
|
3125
3116
|
"pgeagertest_",
|
|
3126
3117
|
"mig_e2e_",
|
|
3127
3118
|
"mig_test_",
|
|
3128
3119
|
"mysqleagertest_",
|
|
3129
3120
|
"mssqleagertest_",
|
|
3130
3121
|
"sqliteeagertest_"
|
|
3131
|
-
],
|
|
3122
|
+
], aa = (e) => ia.some((t) => e.startsWith(t)), oa = (e, t) => w.gen(function* () {
|
|
3132
3123
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3133
|
-
let n = t.filter((e) =>
|
|
3124
|
+
let n = t.filter((e) => aa(e.name)).map((e) => e.name);
|
|
3134
3125
|
if (n.length === 0) return [];
|
|
3135
|
-
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(
|
|
3126
|
+
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(w.catchAll(() => w.void));
|
|
3136
3127
|
return n;
|
|
3137
|
-
}),
|
|
3128
|
+
}), sa = () => {
|
|
3138
3129
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3139
3130
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3140
|
-
},
|
|
3131
|
+
}, ca = (e) => {
|
|
3141
3132
|
if (e === void 0) return;
|
|
3142
3133
|
let t = e.trim();
|
|
3143
3134
|
if (t === "") return;
|
|
@@ -3147,55 +3138,55 @@ BEGIN
|
|
|
3147
3138
|
kind: "tables",
|
|
3148
3139
|
tables: new Set(n)
|
|
3149
3140
|
} : void 0;
|
|
3150
|
-
},
|
|
3141
|
+
}, la = (e) => typeof e.table == "string" ? e.table : void 0, ua = (e, t = { kind: "all" }) => ({
|
|
3151
3142
|
...e,
|
|
3152
3143
|
operations: e.operations.map((e) => {
|
|
3153
3144
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3154
3145
|
if (t?.kind === "tables") {
|
|
3155
|
-
let n =
|
|
3146
|
+
let n = la(e.op);
|
|
3156
3147
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3157
3148
|
}
|
|
3158
3149
|
let { blocked: n, ...r } = e;
|
|
3159
3150
|
return r;
|
|
3160
3151
|
})
|
|
3161
|
-
}),
|
|
3162
|
-
let t =
|
|
3163
|
-
return t === void 0 ?
|
|
3164
|
-
}),
|
|
3165
|
-
let r =
|
|
3152
|
+
}), da = (e, t, n) => t === "postgres" ? on(e, n).pipe(w.flatMap((e) => {
|
|
3153
|
+
let t = sn(e);
|
|
3154
|
+
return t === void 0 ? w.void : w.logWarning(`auto-migrate: ${t}`).pipe(w.annotateLogs({ scope: "voltro:migrate" }));
|
|
3155
|
+
}), w.catchAll(() => w.void)) : w.void, fa = (e, t, n) => w.gen(function* () {
|
|
3156
|
+
let r = Re(e), a = t;
|
|
3166
3157
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3167
|
-
let t =
|
|
3168
|
-
if ((yield*
|
|
3158
|
+
let t = $t(F(a, r));
|
|
3159
|
+
if ((yield* ta(e)) === t) return yield* da(e, r, a), {
|
|
3169
3160
|
kind: "up-to-date",
|
|
3170
3161
|
fingerprint: t
|
|
3171
3162
|
};
|
|
3172
3163
|
}
|
|
3173
|
-
let o = yield*
|
|
3174
|
-
s.length > 0 && (yield*
|
|
3164
|
+
let o = yield* lr(e), s = yield* oa(e, o.tables);
|
|
3165
|
+
s.length > 0 && (yield* w.logInfo(`auto-migrate: reaped ${s.length} test-fixture leftover(s)`).pipe(w.annotateLogs({
|
|
3175
3166
|
scope: "voltro:migrate",
|
|
3176
3167
|
count: s.length
|
|
3177
|
-
})), o = yield*
|
|
3168
|
+
})), o = yield* lr(e));
|
|
3178
3169
|
{
|
|
3179
3170
|
let e = n.softDropRetentionDays ?? 7, t = p(o, { retentionDays: e });
|
|
3180
|
-
t.length > 0 && (yield*
|
|
3171
|
+
t.length > 0 && (yield* w.logWarning(`auto-migrate: ${i(t, e)}`).pipe(w.annotateLogs({
|
|
3181
3172
|
scope: "voltro:migrate",
|
|
3182
3173
|
snapshots: t.map((e) => e.name)
|
|
3183
3174
|
})));
|
|
3184
3175
|
}
|
|
3185
|
-
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u =
|
|
3176
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u = Hn({
|
|
3186
3177
|
declared: a,
|
|
3187
3178
|
live: { tables: l(o.tables) },
|
|
3188
3179
|
dialect: r,
|
|
3189
|
-
...
|
|
3180
|
+
...sa()
|
|
3190
3181
|
});
|
|
3191
3182
|
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 =
|
|
3183
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = ca(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3184
|
+
if (t === void 0 || !e || (u = ua(u, t), u.operations.some((e) => e.blocked))) return {
|
|
3194
3185
|
kind: "refused-blocked",
|
|
3195
3186
|
plan: u
|
|
3196
3187
|
};
|
|
3197
3188
|
}
|
|
3198
|
-
return u.operations.length === 0 ? (yield*
|
|
3189
|
+
return u.operations.length === 0 ? (yield* na(e, u, {
|
|
3199
3190
|
appliedBy: n.appliedBy,
|
|
3200
3191
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3201
3192
|
source: "auto-diff"
|
|
@@ -3204,37 +3195,37 @@ BEGIN
|
|
|
3204
3195
|
fingerprint: u.toFingerprint
|
|
3205
3196
|
}) : {
|
|
3206
3197
|
kind: "applied",
|
|
3207
|
-
applied: yield*
|
|
3198
|
+
applied: yield* Qi(e, u, {
|
|
3208
3199
|
declared: t,
|
|
3209
3200
|
appliedBy: n.appliedBy,
|
|
3210
3201
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3211
3202
|
source: "auto-diff",
|
|
3212
|
-
replan: (e) =>
|
|
3213
|
-
let t = yield*
|
|
3214
|
-
return
|
|
3203
|
+
replan: (e) => w.gen(function* () {
|
|
3204
|
+
let t = yield* lr(e);
|
|
3205
|
+
return Hn({
|
|
3215
3206
|
declared: a,
|
|
3216
3207
|
live: { tables: l(t.tables) },
|
|
3217
3208
|
dialect: r,
|
|
3218
|
-
...
|
|
3209
|
+
...sa()
|
|
3219
3210
|
});
|
|
3220
3211
|
})
|
|
3221
3212
|
}),
|
|
3222
3213
|
plan: u
|
|
3223
3214
|
};
|
|
3224
|
-
}),
|
|
3215
|
+
}), pa = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? w.succeed({
|
|
3225
3216
|
kind: "skipped",
|
|
3226
3217
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3227
|
-
}) : n.environment === "prod" ?
|
|
3218
|
+
}) : n.environment === "prod" ? ra(e, t) : fa(e, t, n), ma = (e, t) => {
|
|
3228
3219
|
switch (e.kind) {
|
|
3229
3220
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3230
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
3221
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${en(e.fingerprint)})`;
|
|
3231
3222
|
case "applied": {
|
|
3232
3223
|
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=${
|
|
3224
|
+
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=${en(e.applied.fingerprint)}`;
|
|
3234
3225
|
}
|
|
3235
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
3226
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${en(e.expected)}` + (e.actual ? ` live=${en(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
3236
3227
|
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` +
|
|
3228
|
+
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` + ea(e.plan), c = [""];
|
|
3238
3229
|
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
3230
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3240
3231
|
for (let r of e.plan.operations) {
|
|
@@ -3251,7 +3242,7 @@ BEGIN
|
|
|
3251
3242
|
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
3243
|
}
|
|
3253
3244
|
}
|
|
3254
|
-
},
|
|
3245
|
+
}, ha = ie({ scope: "voltro:migrate" }), ga = /* @__PURE__ */ new Set([
|
|
3255
3246
|
"node_modules",
|
|
3256
3247
|
"dist",
|
|
3257
3248
|
"build",
|
|
@@ -3260,12 +3251,12 @@ BEGIN
|
|
|
3260
3251
|
".next",
|
|
3261
3252
|
".git",
|
|
3262
3253
|
".framework"
|
|
3263
|
-
]),
|
|
3254
|
+
]), _a = async (e) => {
|
|
3264
3255
|
let t = [], n = async (e) => {
|
|
3265
|
-
let r = await
|
|
3256
|
+
let r = await ae.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3266
3257
|
for (let i of r) {
|
|
3267
|
-
if (
|
|
3268
|
-
let r =
|
|
3258
|
+
if (ga.has(i.name)) continue;
|
|
3259
|
+
let r = oe(e, i.name);
|
|
3269
3260
|
i.isDirectory() ? await n(r) : i.isFile() && S.test(i.name) && t.push(r);
|
|
3270
3261
|
}
|
|
3271
3262
|
};
|
|
@@ -3273,12 +3264,12 @@ BEGIN
|
|
|
3273
3264
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3274
3265
|
return n.localeCompare(r);
|
|
3275
3266
|
});
|
|
3276
|
-
},
|
|
3267
|
+
}, va = async (e) => {
|
|
3277
3268
|
let t = [];
|
|
3278
3269
|
for (let n of e) {
|
|
3279
|
-
let e = (await import(
|
|
3270
|
+
let e = (await import(se(n).href)).default;
|
|
3280
3271
|
if (!u(e)) {
|
|
3281
|
-
|
|
3272
|
+
ha.warn("migration file has no default-exported `migration(...)` — skipped", { file: n });
|
|
3282
3273
|
continue;
|
|
3283
3274
|
}
|
|
3284
3275
|
t.push({
|
|
@@ -3287,11 +3278,11 @@ BEGIN
|
|
|
3287
3278
|
});
|
|
3288
3279
|
}
|
|
3289
3280
|
return t;
|
|
3290
|
-
},
|
|
3281
|
+
}, ya = (e) => e`
|
|
3291
3282
|
SELECT ${e("id")}
|
|
3292
3283
|
FROM ${e("_voltro_migration_plans")}
|
|
3293
3284
|
WHERE ${e("source")} = 'file'
|
|
3294
|
-
`.pipe(
|
|
3285
|
+
`.pipe(w.map((e) => e.map((e) => e.id)), w.catchAll(() => w.succeed([]))), ba = class extends Error {
|
|
3295
3286
|
migrationId;
|
|
3296
3287
|
file;
|
|
3297
3288
|
cause;
|
|
@@ -3299,27 +3290,27 @@ BEGIN
|
|
|
3299
3290
|
constructor(e, t, n) {
|
|
3300
3291
|
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
3292
|
}
|
|
3302
|
-
},
|
|
3293
|
+
}, xa = (e, t, n, r) => w.gen(function* () {
|
|
3303
3294
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3304
3295
|
sql: e,
|
|
3305
3296
|
log: {
|
|
3306
|
-
info: (e, n) =>
|
|
3297
|
+
info: (e, n) => w.logInfo(e).pipe(w.annotateLogs({
|
|
3307
3298
|
scope: `migrations:file:${t.migration.id}`,
|
|
3308
3299
|
...n ?? {}
|
|
3309
3300
|
})),
|
|
3310
|
-
warn: (e, n) =>
|
|
3301
|
+
warn: (e, n) => w.logWarning(e).pipe(w.annotateLogs({
|
|
3311
3302
|
scope: `migrations:file:${t.migration.id}`,
|
|
3312
3303
|
...n ?? {}
|
|
3313
3304
|
}))
|
|
3314
3305
|
},
|
|
3315
3306
|
appliedAt: a
|
|
3316
3307
|
}, s = t.migration.up(o);
|
|
3317
|
-
|
|
3308
|
+
w.isEffect(s) ? yield* s : yield* w.tryPromise({
|
|
3318
3309
|
try: () => s,
|
|
3319
3310
|
catch: (e) => e
|
|
3320
3311
|
});
|
|
3321
3312
|
let c = Date.now() - i;
|
|
3322
|
-
!
|
|
3313
|
+
!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
3314
|
let l = yield* U(e, a);
|
|
3324
3315
|
return yield* e`
|
|
3325
3316
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3333,106 +3324,97 @@ BEGIN
|
|
|
3333
3324
|
}])},
|
|
3334
3325
|
${r}, ${n}, ${"file"},
|
|
3335
3326
|
${c}, ${l}, ${t.migration.description})
|
|
3336
|
-
`.pipe(
|
|
3337
|
-
}),
|
|
3338
|
-
let n = yield*
|
|
3339
|
-
try: () =>
|
|
3327
|
+
`.pipe(w.mapError((e) => new ba(t.migration.id, t.file, e))), { durationMs: c };
|
|
3328
|
+
}), Sa = (e, t) => w.gen(function* () {
|
|
3329
|
+
let n = yield* w.tryPromise({
|
|
3330
|
+
try: () => _a(oe(t, "migrations")),
|
|
3340
3331
|
catch: (e) => e
|
|
3341
3332
|
});
|
|
3342
3333
|
if (n.length === 0) return {
|
|
3343
3334
|
pending: [],
|
|
3344
3335
|
skipped: []
|
|
3345
3336
|
};
|
|
3346
|
-
let r = yield*
|
|
3347
|
-
try: () =>
|
|
3337
|
+
let r = yield* w.tryPromise({
|
|
3338
|
+
try: () => va(n),
|
|
3348
3339
|
catch: (e) => e
|
|
3349
3340
|
});
|
|
3350
3341
|
if (r.length === 0) return {
|
|
3351
3342
|
pending: [],
|
|
3352
3343
|
skipped: []
|
|
3353
3344
|
};
|
|
3354
|
-
let i = new Set(yield*
|
|
3345
|
+
let i = new Set(yield* ya(e));
|
|
3355
3346
|
return {
|
|
3356
3347
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3357
3348
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3358
3349
|
};
|
|
3359
|
-
}),
|
|
3360
|
-
let { pending: n, skipped: r } = yield*
|
|
3361
|
-
|
|
3350
|
+
}), Ca = (e, t) => Sa(e, t).pipe(w.map((e) => e.pending.map((e) => e.migration.id))), wa = (e, t) => w.gen(function* () {
|
|
3351
|
+
let { pending: n, skipped: r } = yield* Sa(e, t.projectRoot);
|
|
3352
|
+
return n.length === 0 ? {
|
|
3362
3353
|
applied: [],
|
|
3363
3354
|
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,
|
|
3355
|
+
} : {
|
|
3356
|
+
applied: yield* w.acquireUseRelease(Ie(e, { schema: t.lockSchema }), () => w.gen(function* () {
|
|
3357
|
+
let r = [];
|
|
3358
|
+
for (let i of n) {
|
|
3359
|
+
yield* w.logInfo("file-based migration applying").pipe(w.annotateLogs({
|
|
3360
|
+
scope: "voltro:migrate",
|
|
3361
|
+
id: i.migration.id,
|
|
3362
|
+
file: i.file
|
|
3363
|
+
}));
|
|
3364
|
+
let { durationMs: n } = yield* xa(e, i, t.env, t.appliedBy);
|
|
3365
|
+
r.push({
|
|
3366
|
+
id: i.migration.id,
|
|
3367
|
+
durationMs: n
|
|
3368
|
+
}), yield* w.logInfo("file-based migration applied").pipe(w.annotateLogs({
|
|
3369
|
+
scope: "voltro:migrate",
|
|
3370
|
+
id: i.migration.id,
|
|
3371
|
+
durationMs: n
|
|
3372
|
+
}));
|
|
3373
|
+
}
|
|
3374
|
+
return r;
|
|
3375
|
+
}), (e) => e.release.pipe(w.orDie)),
|
|
3389
3376
|
skipped: r
|
|
3390
3377
|
};
|
|
3391
|
-
}),
|
|
3378
|
+
}), Ta = (e, t) => e`
|
|
3392
3379
|
SELECT ${e("id")}
|
|
3393
3380
|
FROM ${e("_voltro_migration_plans")}
|
|
3394
3381
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3395
3382
|
LIMIT 1
|
|
3396
|
-
`,
|
|
3397
|
-
if (!(yield*
|
|
3398
|
-
let n = yield*
|
|
3399
|
-
try: () =>
|
|
3383
|
+
`, Ea = (e, t) => w.gen(function* () {
|
|
3384
|
+
if (!(yield* Ta(e, t.id))[0]) return yield* w.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3385
|
+
let n = yield* w.tryPromise({
|
|
3386
|
+
try: () => _a(oe(t.projectRoot, "migrations")),
|
|
3400
3387
|
catch: (e) => e
|
|
3401
|
-
}), r = (yield*
|
|
3402
|
-
try: () =>
|
|
3388
|
+
}), r = (yield* w.tryPromise({
|
|
3389
|
+
try: () => va(n),
|
|
3403
3390
|
catch: (e) => e
|
|
3404
3391
|
})).find((e) => e.migration.id === t.id);
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
let i = Date.now();
|
|
3408
|
-
try {
|
|
3409
|
-
let n = {
|
|
3392
|
+
return r ? yield* w.acquireUseRelease(Ie(e, { schema: t.lockSchema }), () => w.gen(function* () {
|
|
3393
|
+
let n = Date.now(), i = {
|
|
3410
3394
|
sql: e,
|
|
3411
3395
|
log: {
|
|
3412
|
-
info: (e, n) =>
|
|
3396
|
+
info: (e, n) => w.logInfo(e).pipe(w.annotateLogs({
|
|
3413
3397
|
scope: `migrations:file:${t.id}`,
|
|
3414
3398
|
...n ?? {}
|
|
3415
3399
|
})),
|
|
3416
|
-
warn: (e, n) =>
|
|
3400
|
+
warn: (e, n) => w.logWarning(e).pipe(w.annotateLogs({
|
|
3417
3401
|
scope: `migrations:file:${t.id}`,
|
|
3418
3402
|
...n ?? {}
|
|
3419
3403
|
}))
|
|
3420
3404
|
},
|
|
3421
3405
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3422
|
-
}, a = r.migration.down(
|
|
3423
|
-
|
|
3406
|
+
}, a = r.migration.down(i);
|
|
3407
|
+
w.isEffect(a) ? yield* a : yield* w.tryPromise({
|
|
3424
3408
|
try: () => a,
|
|
3425
3409
|
catch: (e) => e
|
|
3426
3410
|
});
|
|
3427
|
-
let o = Date.now() -
|
|
3411
|
+
let o = Date.now() - n;
|
|
3428
3412
|
return yield* e`DELETE FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t.id} AND ${e("source")} = 'file'`, {
|
|
3429
3413
|
id: t.id,
|
|
3430
3414
|
durationMs: o
|
|
3431
3415
|
};
|
|
3432
|
-
}
|
|
3433
|
-
|
|
3434
|
-
}
|
|
3435
|
-
}), wa = (e) => C.gen(function* () {
|
|
3416
|
+
}), (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/`));
|
|
3417
|
+
}), Da = (e) => w.gen(function* () {
|
|
3436
3418
|
let t = yield* T.SqlClient, n = yield* t`
|
|
3437
3419
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3438
3420
|
WHERE source = 'auto-diff'
|
|
@@ -3440,9 +3422,9 @@ BEGIN
|
|
|
3440
3422
|
AND appliedAt < ${e.before}
|
|
3441
3423
|
ORDER BY appliedAt DESC
|
|
3442
3424
|
`;
|
|
3443
|
-
if (n.length === 0) return yield*
|
|
3425
|
+
if (n.length === 0) return yield* w.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3444
3426
|
let r = n[0];
|
|
3445
|
-
if (r.fingerprint !== e.fingerprint) return yield*
|
|
3427
|
+
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
3428
|
yield* t`
|
|
3447
3429
|
UPDATE _voltro_migration_plans
|
|
3448
3430
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3477,7 +3459,7 @@ BEGIN
|
|
|
3477
3459
|
snapshotFingerprint: e.fingerprint,
|
|
3478
3460
|
snapshotId: i
|
|
3479
3461
|
};
|
|
3480
|
-
}),
|
|
3462
|
+
}), Oa = { safe: !0 }, ka = (e) => {
|
|
3481
3463
|
switch (e.kind) {
|
|
3482
3464
|
case "drop-column": return {
|
|
3483
3465
|
safe: !1,
|
|
@@ -3504,7 +3486,7 @@ BEGIN
|
|
|
3504
3486
|
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
3487
|
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
3488
|
};
|
|
3507
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3489
|
+
case "alter-column-nullability": return e.toNullable ? Oa : {
|
|
3508
3490
|
safe: !1,
|
|
3509
3491
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3510
3492
|
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 +3516,12 @@ BEGIN
|
|
|
3534
3516
|
case "drop-unique":
|
|
3535
3517
|
case "drop-unique-composite":
|
|
3536
3518
|
case "drop-foreign-key":
|
|
3537
|
-
case "drop-check": return
|
|
3519
|
+
case "drop-check": return Oa;
|
|
3538
3520
|
}
|
|
3539
|
-
},
|
|
3521
|
+
}, Aa = (e) => {
|
|
3540
3522
|
let t = [];
|
|
3541
3523
|
for (let n of e) {
|
|
3542
|
-
let e =
|
|
3524
|
+
let e = ka(n.op);
|
|
3543
3525
|
e.safe || t.push({
|
|
3544
3526
|
op: n,
|
|
3545
3527
|
reason: e.reason,
|
|
@@ -3547,7 +3529,7 @@ BEGIN
|
|
|
3547
3529
|
});
|
|
3548
3530
|
}
|
|
3549
3531
|
return t;
|
|
3550
|
-
},
|
|
3532
|
+
}, ja = (e) => {
|
|
3551
3533
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3552
3534
|
refuse: !1,
|
|
3553
3535
|
warnForced: !1,
|
|
@@ -3563,18 +3545,18 @@ BEGIN
|
|
|
3563
3545
|
warnForced: !1,
|
|
3564
3546
|
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
3547
|
};
|
|
3566
|
-
},
|
|
3548
|
+
}, Ma = (e) => {
|
|
3567
3549
|
let t = e.table;
|
|
3568
3550
|
if (typeof t == "string") return t;
|
|
3569
3551
|
let n = e.from;
|
|
3570
3552
|
return typeof n == "string" ? n : void 0;
|
|
3571
|
-
},
|
|
3553
|
+
}, Na = (e) => ({
|
|
3572
3554
|
kind: e.op.kind,
|
|
3573
|
-
table:
|
|
3555
|
+
table: Ma(e.op),
|
|
3574
3556
|
classification: e.classification,
|
|
3575
3557
|
reason: e.reason,
|
|
3576
3558
|
blockedFix: e.blocked?.fix
|
|
3577
|
-
}),
|
|
3559
|
+
}), Pa = (e) => e.operations.map(Na), Fa = async (e) => {
|
|
3578
3560
|
let t = e.log ?? (() => {}), n = {
|
|
3579
3561
|
branchId: e.branchId,
|
|
3580
3562
|
mechanism: e.mechanism,
|
|
@@ -3593,10 +3575,10 @@ BEGIN
|
|
|
3593
3575
|
applied: !1,
|
|
3594
3576
|
converged: !1,
|
|
3595
3577
|
residual: r,
|
|
3596
|
-
infidelity:
|
|
3578
|
+
infidelity: Pa(o)
|
|
3597
3579
|
};
|
|
3598
3580
|
else {
|
|
3599
|
-
let i = await e.plan(), o =
|
|
3581
|
+
let i = await e.plan(), o = Pa(i), s = o.filter((e) => e.classification === "lossy"), c = ua(i), l = c.operations.filter((e) => e.blocked !== void 0).map(Na);
|
|
3600
3582
|
if (l.length > 0) a = {
|
|
3601
3583
|
...n,
|
|
3602
3584
|
outcome: "blocked",
|
|
@@ -3621,7 +3603,7 @@ BEGIN
|
|
|
3621
3603
|
};
|
|
3622
3604
|
else {
|
|
3623
3605
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3624
|
-
let i =
|
|
3606
|
+
let i = Pa(await e.replan());
|
|
3625
3607
|
a = {
|
|
3626
3608
|
...n,
|
|
3627
3609
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3659,7 +3641,7 @@ BEGIN
|
|
|
3659
3641
|
...a,
|
|
3660
3642
|
tornDown: o
|
|
3661
3643
|
};
|
|
3662
|
-
},
|
|
3644
|
+
}, Ia = (e) => {
|
|
3663
3645
|
switch (e.outcome) {
|
|
3664
3646
|
case "clean": return 0;
|
|
3665
3647
|
case "lossy": return 2;
|
|
@@ -3668,22 +3650,22 @@ BEGIN
|
|
|
3668
3650
|
case "infidelity": return 1;
|
|
3669
3651
|
case "failed": return 1;
|
|
3670
3652
|
}
|
|
3671
|
-
},
|
|
3653
|
+
}, La = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, Ra = (e) => {
|
|
3672
3654
|
let t = [];
|
|
3673
3655
|
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
3656
|
else if (e.outcome === "infidelity") {
|
|
3675
3657
|
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(
|
|
3658
|
+
for (let n of e.infidelity) t.push(La(n));
|
|
3677
3659
|
} else {
|
|
3678
3660
|
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(
|
|
3661
|
+
for (let n of e.operations) t.push(La(n));
|
|
3662
|
+
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(La(n));
|
|
3681
3663
|
}
|
|
3682
3664
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3683
|
-
},
|
|
3665
|
+
}, za = (e, ...t) => ({
|
|
3684
3666
|
_tag: "RawSqlFragment",
|
|
3685
3667
|
strings: [...e],
|
|
3686
3668
|
values: [...t]
|
|
3687
|
-
}),
|
|
3669
|
+
}), Ba = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3688
3670
|
//#endregion
|
|
3689
|
-
export {
|
|
3671
|
+
export { k as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN, ba as FileMigrationLedgerError, Qe as REACTIVE_TRIGGER_PREFIX, ge as VOLTRO_MIGRATION_LOCK_KEY, Ie as acquireMigrationLock, U as appliedAtValue, Ht as applyNamespacedSchema, Qi as applyPlan, Mt as applySchema, ja as assessRollingDeployGate, Ia as branchRehearsalExitCode, Xn as chunkTables, ka as classifyRollingDeploySafety, F as declaredSnapshot, at as defaultArrayClause, it as defaultClause, M as defaultJsonClause, ma as describeOutcome, ca as destructiveScope, on as detectReactiveTriggerDrift, fi as emitAddIndexMysql, qr as emitCreateTableMysql, Dr as emitDropColumnDdl, Or as emitDropColumnDdlMysql, jt as emitFrameworkBootstrapSql, kt as emitNamespaceProvisionDdl, At as emitNamespacedSchemaSql, Ot as emitSchemaSql, ur as engineFromVersion, $t as fingerprintSchema, Se as fnv1a64, Ra as formatBranchRehearsal, sn as formatReactiveTriggerDrift, sa as ignoreTablesFromEnv, lr as introspectSchema, hr as isAlreadySatisfied, u as isFileMigration, Ba as isRawSqlFragment, Pt as isReRunSafeDdl, Wn as mapPgType, d as migration, Ce as migrationLockKeyForSchema, we as migrationLockNameForSchema, ci as mysqlIndexPrefixFor, et as notifyFunctionName, N as numericIdSql, Un as parseEnumCheck, Ca as pendingFileMigrationIds, Hn as planMigrations, Ut as provisionTenantNamespace, $e as reactiveTriggerName, yt as reactiveTriggerRepairSql, na as recordUpToDate, Fa as rehearseMigrationOnBranch, Na as rehearsedOperation, Gr as renderColumnMysql, Br as renderColumnPg, ve as resolveMigrationLockSchema, H as resolveMysqlEngine, Ea as rollbackFileBasedMigration, Aa as rollingDeployUnsafeOps, wa as runFileBasedMigrations, Wt as runFrameworkBootstrap, Vt as runMigrate, pa as runPlannedMigrations, en as shortFingerprint, tn as snapshotColumn, za as sql, j as sqlType, Da as squashMigrationPlans, ua as unblockLossy, Le as withMigrationLock };
|