@voltro/database 0.34.0 → 0.36.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 +235 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +624 -620
- package/dist/sql.d.ts +155 -23
- package/dist/sql.js +690 -645
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { It as e, Jt as t, Lt as n, X as r, Z as i, _ as a, a as o, bt as s, c, et as l, i as u, l as d, m as f, mt as p, n as m, o as h, p as g, qt as _, r as v, tt as y } from "./frameworkLiveTables-CeuTYhWm.js";
|
|
2
|
-
import { Effect as b } from "effect";
|
|
3
|
-
import { createLogger as
|
|
4
|
-
import { SqlClient as
|
|
5
|
-
import { createHash as
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
2
|
+
import { Effect as b, Schedule as x } from "effect";
|
|
3
|
+
import { createLogger as S } from "@voltro/logger";
|
|
4
|
+
import { SqlClient as C } from "@effect/sql";
|
|
5
|
+
import { createHash as ee } from "node:crypto";
|
|
6
|
+
import { promises as te } from "node:fs";
|
|
7
|
+
import { join as ne } from "node:path";
|
|
8
|
+
import { pathToFileURL as re } from "node:url";
|
|
9
9
|
//#region src/migrations/ddlError.ts
|
|
10
|
-
var
|
|
10
|
+
var ie = (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);
|
|
@@ -39,19 +39,19 @@ var re = (e, t, n, r = 400) => {
|
|
|
39
39
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
40
40
|
}
|
|
41
41
|
return s.push(""), s.join("\n");
|
|
42
|
-
},
|
|
43
|
-
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(
|
|
42
|
+
}, ae = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, oe = (e) => e.replace(/"/g, "`"), se = (e) => typeof e == "string" ? e : e.name ?? String(e), ce = (e, t) => `_ua_${t}_${e}`.slice(0, 64), le = (e, t) => {
|
|
43
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(ae)) return e;
|
|
44
44
|
let n = { ...e.fields }, r = [], i = [];
|
|
45
45
|
for (let t of e.appliedIndexes) {
|
|
46
|
-
if (!
|
|
46
|
+
if (!ae(t)) {
|
|
47
47
|
r.push(t);
|
|
48
48
|
continue;
|
|
49
49
|
}
|
|
50
|
-
let a =
|
|
50
|
+
let a = oe(t.where), o = [];
|
|
51
51
|
for (let r of t.fields) {
|
|
52
|
-
let i =
|
|
52
|
+
let i = se(r);
|
|
53
53
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
54
|
-
let s =
|
|
54
|
+
let s = ce(t.name, i);
|
|
55
55
|
o.push(s), n[s] = {
|
|
56
56
|
type: "text",
|
|
57
57
|
nullable: !0,
|
|
@@ -74,7 +74,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
74
74
|
appliedIndexes: r,
|
|
75
75
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
76
76
|
};
|
|
77
|
-
}, w = (e, t) => `${e}::${t}`,
|
|
77
|
+
}, w = (e, t) => `${e}::${t}`, ue = (e, t) => {
|
|
78
78
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
79
79
|
n.add(e);
|
|
80
80
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
@@ -83,45 +83,142 @@ var re = (e, t, n, r = 400) => {
|
|
|
83
83
|
};
|
|
84
84
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
85
85
|
return i;
|
|
86
|
-
},
|
|
86
|
+
}, de = 6322741009312437n, fe = (e) => {
|
|
87
|
+
let t = e?.trim();
|
|
88
|
+
return t === void 0 || t === "" || t === "public" ? void 0 : t;
|
|
89
|
+
}, pe = (e) => e?.schema === void 0 ? fe(process.env.DB_SCHEMA) : fe(e.schema), me = 14695981039346656037n, he = 1099511628211n, ge = 18446744073709551615n, _e = (e) => {
|
|
90
|
+
let t = me;
|
|
91
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * he & ge;
|
|
92
|
+
return t;
|
|
93
|
+
}, ve = (e) => {
|
|
94
|
+
let t = fe(e);
|
|
95
|
+
return t === void 0 ? de : _e(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
96
|
+
}, ye = (e) => {
|
|
97
|
+
let t = `voltro_migration_${de.toString(36)}`, n = fe(e);
|
|
98
|
+
if (n === void 0) return t;
|
|
99
|
+
let r = `${t}_${n}`;
|
|
100
|
+
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(_e(`voltro_migration_lock:${n}`) & ge).toString(16)}`;
|
|
101
|
+
}, be = 250, xe = () => {
|
|
87
102
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
88
103
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
89
|
-
},
|
|
90
|
-
let
|
|
104
|
+
}, Se = (e, t) => b.gen(function* () {
|
|
105
|
+
let n = xe(), r = Date.now();
|
|
91
106
|
for (;;) {
|
|
92
107
|
if ((yield* e`
|
|
93
|
-
SELECT pg_try_advisory_lock(${
|
|
94
|
-
Date.now() -
|
|
108
|
+
SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`)[0]?.got) return;
|
|
109
|
+
Date.now() - r >= n && (yield* b.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* b.sleep(`${be} millis`);
|
|
95
110
|
}
|
|
96
|
-
}),
|
|
97
|
-
yield* e`SELECT pg_advisory_unlock(${
|
|
98
|
-
}),
|
|
111
|
+
}), Ce = (e, t) => b.gen(function* () {
|
|
112
|
+
yield* e`SELECT pg_advisory_unlock(${t.toString()}::bigint)`;
|
|
113
|
+
}), we = 30, Te = (e, t) => b.gen(function* () {
|
|
99
114
|
(yield* e`
|
|
100
|
-
SELECT GET_LOCK(${
|
|
101
|
-
}),
|
|
102
|
-
yield* e`SELECT RELEASE_LOCK(${
|
|
103
|
-
}),
|
|
104
|
-
let
|
|
115
|
+
SELECT GET_LOCK(${t}, ${we}) AS got`)[0]?.got !== 1 && (yield* b.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${we}s (another migration is in progress, or a prior one left it held).`)));
|
|
116
|
+
}), Ee = (e, t) => b.gen(function* () {
|
|
117
|
+
yield* e`SELECT RELEASE_LOCK(${t})`;
|
|
118
|
+
}), De = 3e4, Oe = (e, t) => b.gen(function* () {
|
|
119
|
+
let n = yield* e`
|
|
105
120
|
DECLARE @res int;
|
|
106
|
-
EXEC @res = sp_getapplock @Resource = ${
|
|
107
|
-
@LockOwner = 'Session', @LockTimeout = ${
|
|
121
|
+
EXEC @res = sp_getapplock @Resource = ${t}, @LockMode = 'Exclusive',
|
|
122
|
+
@LockOwner = 'Session', @LockTimeout = ${De};
|
|
108
123
|
SELECT @res AS res`;
|
|
109
|
-
(
|
|
110
|
-
}),
|
|
111
|
-
yield* e`EXEC sp_releaseapplock @Resource = ${
|
|
112
|
-
}),
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
(n[0]?.res ?? -999) < 0 && (yield* b.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
125
|
+
}), ke = (e, t) => b.gen(function* () {
|
|
126
|
+
yield* e`EXEC sp_releaseapplock @Resource = ${t}, @LockOwner = 'Session'`;
|
|
127
|
+
}), Ae = b.void, T = (e, t) => {
|
|
128
|
+
let n = pe(t);
|
|
129
|
+
return e.onDialectOrElse({
|
|
130
|
+
mysql: () => Te(e, ye(n)),
|
|
131
|
+
mssql: () => Oe(e, ye(n)),
|
|
132
|
+
sqlite: () => Ae,
|
|
133
|
+
orElse: () => Se(e, ve(n))
|
|
134
|
+
});
|
|
135
|
+
}, E = (e, t) => {
|
|
136
|
+
let n = pe(t);
|
|
137
|
+
return e.onDialectOrElse({
|
|
138
|
+
mysql: () => Ee(e, ye(n)),
|
|
139
|
+
mssql: () => ke(e, ye(n)),
|
|
140
|
+
sqlite: () => Ae,
|
|
141
|
+
orElse: () => Ce(e, ve(n))
|
|
142
|
+
});
|
|
143
|
+
}, je = (e, t, n) => b.acquireUseRelease(T(e, n), () => t, () => E(e, n).pipe(b.orDie)), Me = (e) => e.onDialectOrElse({
|
|
144
|
+
pg: () => "postgres",
|
|
145
|
+
mysql: () => "mysql",
|
|
146
|
+
mssql: () => "mssql",
|
|
147
|
+
sqlite: () => "sqlite",
|
|
148
|
+
orElse: () => "sqlite"
|
|
149
|
+
}), Ne = {
|
|
150
|
+
postgres: "plan-transactional",
|
|
151
|
+
mssql: "plan-transactional",
|
|
152
|
+
mysql: "per-operation",
|
|
153
|
+
mariadb: "per-operation",
|
|
154
|
+
sqlite: "per-operation",
|
|
155
|
+
turso: "per-operation"
|
|
156
|
+
}, Pe = (e) => Ne[e], D = "_voltro_migration_ops", Fe = l(D, {
|
|
157
|
+
id: e({ prefix: "mop" }),
|
|
158
|
+
runId: _(),
|
|
159
|
+
planFingerprint: _(),
|
|
160
|
+
opIndex: n(),
|
|
161
|
+
opKind: _(),
|
|
162
|
+
opTarget: _(),
|
|
163
|
+
status: _(),
|
|
164
|
+
payload: _(),
|
|
165
|
+
startedAt: t().nullable(),
|
|
166
|
+
appliedAt: t().nullable(),
|
|
167
|
+
durationMs: n().nullable(),
|
|
168
|
+
createdAt: t().default("now")
|
|
169
|
+
}), Ie = (e) => {
|
|
170
|
+
switch (e.kind) {
|
|
171
|
+
case "create-table": return /* @__PURE__ */ new Set([
|
|
172
|
+
`table:${e.table}`,
|
|
173
|
+
...e.columns.map((t) => `column:${e.table}.${t.name}`),
|
|
174
|
+
...e.indexes.map((t) => `index:${e.table}.${t.name}`)
|
|
175
|
+
]);
|
|
176
|
+
case "drop-table": return /* @__PURE__ */ new Set([`table:${e.table}`]);
|
|
177
|
+
case "rename-table": return /* @__PURE__ */ new Set([`table:${e.from}`, `table:${e.to}`]);
|
|
178
|
+
case "add-column": return /* @__PURE__ */ new Set([`column:${e.table}.${e.column.name}`]);
|
|
179
|
+
case "rename-column": return /* @__PURE__ */ new Set([`column:${e.table}.${e.from}`, `column:${e.table}.${e.to}`]);
|
|
180
|
+
case "drop-column":
|
|
181
|
+
case "alter-column-nullability":
|
|
182
|
+
case "alter-column-type":
|
|
183
|
+
case "alter-column-default":
|
|
184
|
+
case "add-unique":
|
|
185
|
+
case "drop-unique":
|
|
186
|
+
case "add-foreign-key":
|
|
187
|
+
case "drop-foreign-key":
|
|
188
|
+
case "add-check":
|
|
189
|
+
case "drop-check": return /* @__PURE__ */ new Set([`column:${e.table}.${e.column}`]);
|
|
190
|
+
case "add-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index.name}`]);
|
|
191
|
+
case "drop-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index}`]);
|
|
192
|
+
case "rename-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.from}`, `index:${e.table}.${e.to}`]);
|
|
193
|
+
case "add-unique-composite":
|
|
194
|
+
case "drop-unique-composite": return /* @__PURE__ */ new Set([`unique:${e.table}.${e.name}`]);
|
|
195
|
+
}
|
|
196
|
+
}, Le = (e) => [...Ie(e)].join(" "), Re = (e, t) => {
|
|
197
|
+
let n = Ie(t);
|
|
198
|
+
for (let t of Ie(e)) if (n.has(t)) return !0;
|
|
199
|
+
return !1;
|
|
200
|
+
}, ze = (e, t) => e.operations.some((e) => Re(e.op, t)), Be = "__voltro_rebuild", Ve = "__shadow", He = "__old", Ue = /* @__PURE__ */ new Set([
|
|
201
|
+
"add-unique",
|
|
202
|
+
"drop-unique",
|
|
203
|
+
"add-unique-composite",
|
|
204
|
+
"drop-unique-composite",
|
|
205
|
+
"add-foreign-key",
|
|
206
|
+
"drop-foreign-key",
|
|
207
|
+
"add-check",
|
|
208
|
+
"drop-check",
|
|
209
|
+
"alter-column-nullability",
|
|
210
|
+
"alter-column-type",
|
|
211
|
+
"alter-column-default"
|
|
212
|
+
]), We = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Ge = (e, t, n) => {
|
|
213
|
+
let r = n === "sqlite" || n === "turso";
|
|
214
|
+
return e.kind === "alter-column-type" && t === "online-required" || r && Ue.has(e.kind) ? "artefact-repair" : We.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
215
|
+
};
|
|
216
|
+
Object.keys(Ne);
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/migrations/reactiveTriggerName.ts
|
|
219
|
+
var O = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "framework_changes" ? `${Ke}${e}` : `${Ke}${t}_${e}`, Je = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, Ye = "voltro:notify:v2", Xe = S({ scope: "voltro:migrate" }), k = (e) => {
|
|
220
|
+
Xe.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
221
|
+
}, A = (e, t) => {
|
|
125
222
|
let n = e.type;
|
|
126
223
|
if (e.spatial) {
|
|
127
224
|
if (t === "postgres") return `${e.spatial.kind}(${e.spatial.geomKind},${e.spatial.srid})`;
|
|
@@ -132,7 +229,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
132
229
|
return e.rawDdl;
|
|
133
230
|
}
|
|
134
231
|
if (n === "array" && e.arrayElement) {
|
|
135
|
-
if (t === "postgres") return `${
|
|
232
|
+
if (t === "postgres") return `${A({
|
|
136
233
|
...e,
|
|
137
234
|
type: e.arrayElement,
|
|
138
235
|
arrayElement: void 0
|
|
@@ -232,22 +329,22 @@ var re = (e, t, n, r = 400) => {
|
|
|
232
329
|
case "array": return "TEXT[]";
|
|
233
330
|
case "interval": return "INTERVAL";
|
|
234
331
|
}
|
|
235
|
-
},
|
|
332
|
+
}, Ze = (e, t) => {
|
|
236
333
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
237
334
|
let n = e.defaultValue;
|
|
238
|
-
return n === "now" ? r(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) ?
|
|
239
|
-
},
|
|
240
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
241
|
-
let r =
|
|
335
|
+
return n === "now" ? r(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) ? Qe(n, e, t) : typeof n == "object" && n ? j(n, t) : null;
|
|
336
|
+
}, Qe = (e, t, n) => {
|
|
337
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return j(e, n);
|
|
338
|
+
let r = A({
|
|
242
339
|
...t,
|
|
243
340
|
type: t.arrayElement,
|
|
244
341
|
arrayElement: void 0
|
|
245
342
|
}, n);
|
|
246
343
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
247
|
-
},
|
|
344
|
+
}, j = (e, t) => {
|
|
248
345
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
249
346
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
250
|
-
},
|
|
347
|
+
}, M = (e, t) => {
|
|
251
348
|
switch (t) {
|
|
252
349
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
253
350
|
case "mysql":
|
|
@@ -256,7 +353,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
256
353
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
257
354
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
258
355
|
}
|
|
259
|
-
},
|
|
356
|
+
}, $e = (e, t) => {
|
|
260
357
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
261
358
|
switch (e) {
|
|
262
359
|
case "cascade": return "CASCADE";
|
|
@@ -264,38 +361,38 @@ var re = (e, t, n, r = 400) => {
|
|
|
264
361
|
case "setNull": return "SET NULL";
|
|
265
362
|
case "noAction": return "NO ACTION";
|
|
266
363
|
}
|
|
267
|
-
},
|
|
364
|
+
}, et = (e, t, n) => n === null ? i(e, t) : `${i(n, t)}.${i(e, t)}`, tt = 191, nt = (e, t, n) => {
|
|
268
365
|
let r = i(e, n);
|
|
269
366
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
270
367
|
let a = t[e];
|
|
271
368
|
if (!a) return r;
|
|
272
|
-
let o =
|
|
273
|
-
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${r}(${
|
|
274
|
-
},
|
|
369
|
+
let o = A(a, n).toUpperCase();
|
|
370
|
+
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${r}(${tt})` : r;
|
|
371
|
+
}, rt = (e, t) => {
|
|
275
372
|
if (!e.generatedAs) return null;
|
|
276
373
|
let { expr: n, stored: r } = e.generatedAs;
|
|
277
|
-
if (t === "postgres") return r ||
|
|
374
|
+
if (t === "postgres") return r || k("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
278
375
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
279
376
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
280
377
|
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.");
|
|
281
378
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
282
|
-
},
|
|
283
|
-
if (t.type === "id" && t.idScheme?.kind === "numeric") return
|
|
284
|
-
let c = n === "mssql" && t.type === "text" && !t.generatedAs && t.maxLength === void 0 && a?.has(e) ? "NVARCHAR(450)" :
|
|
379
|
+
}, it = (e, t, n, a, o = !1, s = !1) => {
|
|
380
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return M(e, n);
|
|
381
|
+
let c = n === "mssql" && t.type === "text" && !t.generatedAs && t.maxLength === void 0 && a?.has(e) ? "NVARCHAR(450)" : A(t, n), l = [i(e, n), c];
|
|
285
382
|
t.type === "id" && !s && l.push("PRIMARY KEY");
|
|
286
|
-
let u =
|
|
383
|
+
let u = rt(t, n);
|
|
287
384
|
if (u) l.push(u);
|
|
288
385
|
else {
|
|
289
386
|
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && l.push("UNIQUE");
|
|
290
|
-
let e =
|
|
387
|
+
let e = Ze(t, n);
|
|
291
388
|
e && l.push(e);
|
|
292
389
|
}
|
|
293
390
|
if (t.type === "reference" && t.references && !o) {
|
|
294
391
|
let e = t.references();
|
|
295
392
|
l.push(`REFERENCES ${i(e.tableName, n)} (${i("id", n)})`);
|
|
296
|
-
let r =
|
|
393
|
+
let r = $e(t.onDelete ?? "restrict", n);
|
|
297
394
|
l.push(`ON DELETE ${r}`);
|
|
298
|
-
let a =
|
|
395
|
+
let a = $e(t.refOnUpdate ?? "noAction", n);
|
|
299
396
|
a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
|
|
300
397
|
}
|
|
301
398
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
@@ -312,18 +409,18 @@ var re = (e, t, n, r = 400) => {
|
|
|
312
409
|
r(n) ? l.push(`CHECK (${t} IS NULL OR json_valid(${t}))`) : n === "mssql" && l.push(`CHECK (${t} IS NULL OR ISJSON(${t}) = 1)`);
|
|
313
410
|
}
|
|
314
411
|
return l.join(" ");
|
|
315
|
-
},
|
|
412
|
+
}, at = (e, t, n = null, r) => {
|
|
316
413
|
let a = /* @__PURE__ */ new Set();
|
|
317
414
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
318
415
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
319
|
-
let o = e.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${
|
|
320
|
-
let r = n.fields.map((n) =>
|
|
416
|
+
let o = e.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${it(e, n, t, a, r?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((n) => {
|
|
417
|
+
let r = n.fields.map((n) => nt(n, e.fields, t)).join(", ");
|
|
321
418
|
return ` CONSTRAINT ${i(n.name, t)} UNIQUE (${r})`;
|
|
322
419
|
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${i(e.name, t)} CHECK (${e.expr})`), d = [
|
|
323
|
-
...s ? [` PRIMARY KEY (${o.map((n) =>
|
|
420
|
+
...s ? [` PRIMARY KEY (${o.map((n) => nt(n, e.fields, t)).join(", ")})`] : [],
|
|
324
421
|
...l,
|
|
325
422
|
...u
|
|
326
|
-
], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p =
|
|
423
|
+
], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p = et(e.tableName, t, n);
|
|
327
424
|
if (t === "mssql") {
|
|
328
425
|
let t = n === null ? e.tableName : `${n}.${e.tableName}`, r = `CREATE TABLE ${p} (\n${f}\n)`;
|
|
329
426
|
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${r.replace(/'/g, "''")}');`;
|
|
@@ -333,10 +430,10 @@ var re = (e, t, n, r = 400) => {
|
|
|
333
430
|
f,
|
|
334
431
|
");"
|
|
335
432
|
].join("\n");
|
|
336
|
-
},
|
|
433
|
+
}, ot = (e, t, n) => {
|
|
337
434
|
let r = `${e}_${t.name}_fts`, a = (e) => i(e, n), o = t.columns.map(a).join(", "), s = t.columns.map((e) => `new.${a(e)}`).join(", "), c = [];
|
|
338
435
|
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${a(r)} USING fts5(${o}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_ai`)} AFTER INSERT ON ${a(e)} BEGIN\n INSERT INTO ${a(r)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_ad`)} AFTER DELETE ON ${a(e)} BEGIN\n DELETE FROM ${a(r)} WHERE row_id = old.${a("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_au`)} AFTER UPDATE ON ${a(e)} BEGIN\n DELETE FROM ${a(r)} WHERE row_id = old.${a("id")};\n INSERT INTO ${a(r)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c;
|
|
339
|
-
},
|
|
436
|
+
}, st = (e, t, n = null) => {
|
|
340
437
|
let r = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, n, r, i) => {
|
|
341
438
|
let a = {
|
|
342
439
|
using: "",
|
|
@@ -348,21 +445,21 @@ var re = (e, t, n, r = 400) => {
|
|
|
348
445
|
using: " USING GIST",
|
|
349
446
|
withSuffix: "",
|
|
350
447
|
skip: !1
|
|
351
|
-
} : (
|
|
448
|
+
} : (k(`[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);
|
|
352
449
|
if (r === "gin") return t === "postgres" ? {
|
|
353
450
|
using: " USING GIN",
|
|
354
451
|
withSuffix: "",
|
|
355
452
|
skip: !1
|
|
356
|
-
} : t === "mysql" || t === "mariadb" ? (
|
|
453
|
+
} : t === "mysql" || t === "mariadb" ? (k(`[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(...).`), {
|
|
357
454
|
using: "",
|
|
358
455
|
withSuffix: "",
|
|
359
456
|
skip: !0
|
|
360
|
-
}) : (
|
|
457
|
+
}) : (k(`[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);
|
|
361
458
|
if (r === "brin") return t === "postgres" ? {
|
|
362
459
|
using: " USING BRIN",
|
|
363
460
|
withSuffix: "",
|
|
364
461
|
skip: !1
|
|
365
|
-
} : (
|
|
462
|
+
} : (k(`[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);
|
|
366
463
|
if (r === "hnsw") {
|
|
367
464
|
if (t === "postgres") {
|
|
368
465
|
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? y(i?.hnsw?.distance);
|
|
@@ -373,7 +470,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
373
470
|
skip: !1
|
|
374
471
|
};
|
|
375
472
|
}
|
|
376
|
-
return
|
|
473
|
+
return k(`[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.`), {
|
|
377
474
|
using: "",
|
|
378
475
|
withSuffix: "",
|
|
379
476
|
skip: !0
|
|
@@ -382,7 +479,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
382
479
|
return a;
|
|
383
480
|
}, c = (n, r) => {
|
|
384
481
|
let i = n.map((n) => {
|
|
385
|
-
if (typeof n == "string") return
|
|
482
|
+
if (typeof n == "string") return nt(n, e.fields, t);
|
|
386
483
|
if ("jsonPath" in n) {
|
|
387
484
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
388
485
|
return `(${g(e, r, t, { numeric: i })})`;
|
|
@@ -393,7 +490,7 @@ var re = (e, t, n, r = 400) => {
|
|
|
393
490
|
}, l = (e, r, a, o, l, u = "", d = !1) => {
|
|
394
491
|
let f = s(e, r, o, l);
|
|
395
492
|
if (f.skip) return "";
|
|
396
|
-
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h =
|
|
493
|
+
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h = et(r, t, n), g = d ? "UNIQUE " : "";
|
|
397
494
|
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${i(e, t)} ON ${h}${f.using} (${p})${m};` : t === "mysql" ? `CREATE ${g}INDEX ${i(e, t)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${i(e, t)} ON ${h}${f.using} (${p})${m};`;
|
|
398
495
|
};
|
|
399
496
|
for (let n of e.appliedFullText ?? []) if (t === "postgres") {
|
|
@@ -406,15 +503,15 @@ var re = (e, t, n, r = 400) => {
|
|
|
406
503
|
let a = n.columns.map((e) => i(e, t)).join(", ");
|
|
407
504
|
r.push(`CREATE FULLTEXT INDEX ${i(n.name, t)} ON ${i(e.tableName, t)} (${a});`);
|
|
408
505
|
} 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.`);
|
|
409
|
-
else t === "sqlite" ? r.push(...
|
|
506
|
+
else t === "sqlite" ? r.push(...ot(e.tableName, n, t)) : k(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
410
507
|
for (let n of e.appliedIndexes) {
|
|
411
508
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
412
|
-
|
|
509
|
+
k(`[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(...).`);
|
|
413
510
|
continue;
|
|
414
511
|
}
|
|
415
512
|
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.`);
|
|
416
513
|
let i = "";
|
|
417
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ?
|
|
514
|
+
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? k(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) : i = ` WHERE ${n.where}`);
|
|
418
515
|
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions, i, n.unique === !0);
|
|
419
516
|
s !== "" && r.push(s), n.fields.every((e) => typeof e == "string") && a.add(o(n.fields));
|
|
420
517
|
}
|
|
@@ -424,17 +521,17 @@ var re = (e, t, n, r = 400) => {
|
|
|
424
521
|
r.push(l(i, e.tableName, [t])), a.add(o([t]));
|
|
425
522
|
}
|
|
426
523
|
return r.join("\n");
|
|
427
|
-
},
|
|
524
|
+
}, ct = (e, t, n = O) => {
|
|
428
525
|
if (t !== "postgres") return [];
|
|
429
526
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
430
|
-
return r.length === 0 ? [] : [
|
|
431
|
-
},
|
|
432
|
-
CREATE OR REPLACE FUNCTION ${
|
|
527
|
+
return r.length === 0 ? [] : [lt(n), ...r.map((e) => dt(e, n))];
|
|
528
|
+
}, lt = (e) => `
|
|
529
|
+
CREATE OR REPLACE FUNCTION ${Je(e)}() RETURNS trigger AS $$
|
|
433
530
|
DECLARE
|
|
434
531
|
payload TEXT;
|
|
435
532
|
pk JSONB;
|
|
436
533
|
BEGIN
|
|
437
|
-
-- ${
|
|
534
|
+
-- ${Ye}
|
|
438
535
|
payload := json_build_object(
|
|
439
536
|
'table', TG_TABLE_NAME,
|
|
440
537
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -488,22 +585,22 @@ BEGIN
|
|
|
488
585
|
RETURN COALESCE(NEW, OLD);
|
|
489
586
|
END;
|
|
490
587
|
$$ LANGUAGE plpgsql;
|
|
491
|
-
`.trim(),
|
|
492
|
-
let n =
|
|
588
|
+
`.trim(), ut = (e, t) => {
|
|
589
|
+
let n = qe(e.tableName, t);
|
|
493
590
|
return [
|
|
494
591
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
495
592
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
496
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
593
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${Je(t)}()`
|
|
497
594
|
];
|
|
498
|
-
},
|
|
595
|
+
}, dt = (e, t) => ut(e, t).map((e) => `${e};`).join("\n"), ft = (e) => {
|
|
499
596
|
if (e.dialect !== "postgres") return [];
|
|
500
597
|
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));
|
|
501
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
502
|
-
for (let e of i) r.push(...
|
|
503
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
598
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(lt(t));
|
|
599
|
+
for (let e of i) r.push(...ut(n.get(e), t));
|
|
600
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${qe(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
504
601
|
return r;
|
|
505
|
-
},
|
|
506
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
602
|
+
}, pt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), mt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), ht = (e) => {
|
|
603
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = ue(e.map((e) => e.tableName), (e) => {
|
|
507
604
|
let n = t.get(e);
|
|
508
605
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
509
606
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -539,8 +636,8 @@ $$ LANGUAGE plpgsql;
|
|
|
539
636
|
sorted: o,
|
|
540
637
|
cyclic: r
|
|
541
638
|
};
|
|
542
|
-
},
|
|
543
|
-
let r = (e) => n ? `${i(n, t)}.${i(e, t)}` : i(e, t), a = `${e.table}_${e.column}_fkey`, o =
|
|
639
|
+
}, gt = (e, t, n = null) => {
|
|
640
|
+
let r = (e) => n ? `${i(n, t)}.${i(e, t)}` : i(e, t), a = `${e.table}_${e.column}_fkey`, o = $e(e.onDelete, t), s = $e(e.onUpdate, t), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (n) => `ADD CONSTRAINT ${i(a, t)} FOREIGN KEY ${n ? "IF NOT EXISTS " : ""}(${i(e.column, t)}) REFERENCES ${r(e.targetTable)} (${i("id", t)})${c}`;
|
|
544
641
|
switch (t) {
|
|
545
642
|
case "postgres": return [
|
|
546
643
|
"DO $$ BEGIN",
|
|
@@ -554,7 +651,7 @@ $$ LANGUAGE plpgsql;
|
|
|
554
651
|
case "mariadb": return `ALTER TABLE ${r(e.table)} ${l(!0)};`;
|
|
555
652
|
default: return `ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
556
653
|
}
|
|
557
|
-
},
|
|
654
|
+
}, _t = (e, t) => {
|
|
558
655
|
let n = /* @__PURE__ */ new Map();
|
|
559
656
|
if (r(t)) return n;
|
|
560
657
|
for (let t of e) {
|
|
@@ -562,7 +659,7 @@ $$ LANGUAGE plpgsql;
|
|
|
562
659
|
e.add(t.column), n.set(t.table, e);
|
|
563
660
|
}
|
|
564
661
|
return n;
|
|
565
|
-
},
|
|
662
|
+
}, vt = (e, t) => {
|
|
566
663
|
if (t !== "postgres") return "";
|
|
567
664
|
let n = /* @__PURE__ */ new Map();
|
|
568
665
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -578,7 +675,7 @@ $$ LANGUAGE plpgsql;
|
|
|
578
675
|
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 $$;`);
|
|
579
676
|
}
|
|
580
677
|
return r.join("\n\n");
|
|
581
|
-
},
|
|
678
|
+
}, yt = (e, t) => {
|
|
582
679
|
if (t !== "postgres") return "";
|
|
583
680
|
let n = /* @__PURE__ */ new Set();
|
|
584
681
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
|
|
@@ -592,30 +689,30 @@ BEGIN
|
|
|
592
689
|
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${i}';\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', '${i}', '${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 $$;`);
|
|
593
690
|
}
|
|
594
691
|
return r.join("\n\n");
|
|
595
|
-
},
|
|
692
|
+
}, bt = (e) => {
|
|
596
693
|
let t = [], n = [];
|
|
597
694
|
for (let r of e) f(r) ? n.push(r) : t.push(r);
|
|
598
695
|
return {
|
|
599
696
|
tables: t,
|
|
600
697
|
views: n
|
|
601
698
|
};
|
|
602
|
-
},
|
|
603
|
-
let { tables: i, views: o } =
|
|
604
|
-
t === "postgres" &&
|
|
605
|
-
let d =
|
|
699
|
+
}, xt = (e, t, n = O) => {
|
|
700
|
+
let { tables: i, views: o } = bt(e), { sorted: s, cyclic: c } = ht(i.map((e) => le(e, t))), l = _t(c, t), u = [];
|
|
701
|
+
t === "postgres" && pt(s) && u.push("CREATE EXTENSION IF NOT EXISTS vector;"), t === "postgres" && mt(s) && u.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
702
|
+
let d = yt(s, t);
|
|
606
703
|
d && u.push(d);
|
|
607
|
-
let f =
|
|
704
|
+
let f = vt(s, t);
|
|
608
705
|
f && u.push(f);
|
|
609
|
-
for (let e of s) u.push(
|
|
610
|
-
if (!r(t)) for (let e of c) u.push(
|
|
706
|
+
for (let e of s) u.push(at(e, t, null, l.get(e.tableName)));
|
|
707
|
+
if (!r(t)) for (let e of c) u.push(gt(e, t));
|
|
611
708
|
for (let e of s) {
|
|
612
|
-
let n =
|
|
709
|
+
let n = st(e, t);
|
|
613
710
|
n && u.push(n);
|
|
614
711
|
}
|
|
615
|
-
u.push(...
|
|
712
|
+
u.push(...ct(s, t, n));
|
|
616
713
|
for (let e of o) u.push(a(e, t));
|
|
617
714
|
return u.join("\n\n") + "\n";
|
|
618
|
-
},
|
|
715
|
+
}, St = (e, t, n) => {
|
|
619
716
|
let r = i(e, t);
|
|
620
717
|
switch (t) {
|
|
621
718
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${r};`;
|
|
@@ -625,38 +722,62 @@ BEGIN
|
|
|
625
722
|
case "turso":
|
|
626
723
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${r};`;
|
|
627
724
|
}
|
|
628
|
-
},
|
|
629
|
-
let o =
|
|
630
|
-
if (t === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${
|
|
631
|
-
if (t === "mysql" || t === "mariadb") return `${o}\n\nUSE ${s};\n\n${
|
|
632
|
-
let { sorted: c, cyclic: l } =
|
|
633
|
-
for (let e of c) d.push(
|
|
634
|
-
if (!r(t)) for (let e of l) d.push(
|
|
725
|
+
}, Ct = (e, t, n, a) => {
|
|
726
|
+
let o = St(n, t, a), s = i(n, t);
|
|
727
|
+
if (t === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${xt(e, t)}`;
|
|
728
|
+
if (t === "mysql" || t === "mariadb") return `${o}\n\nUSE ${s};\n\n${xt(e, t)}`;
|
|
729
|
+
let { sorted: c, cyclic: l } = ht(e), u = _t(l, t), d = [o];
|
|
730
|
+
for (let e of c) d.push(at(e, t, n, u.get(e.tableName)));
|
|
731
|
+
if (!r(t)) for (let e of l) d.push(gt(e, t, n));
|
|
635
732
|
for (let e of c) {
|
|
636
|
-
let r =
|
|
733
|
+
let r = st(e, t, n);
|
|
637
734
|
r && d.push(r);
|
|
638
735
|
}
|
|
639
736
|
return d.join("\n\n") + "\n";
|
|
640
|
-
},
|
|
641
|
-
let { sorted: r, cyclic: i } =
|
|
737
|
+
}, wt = (e, t, n = O) => {
|
|
738
|
+
let { sorted: r, cyclic: i } = ht(e), a = _t(i, t), o = [], s = yt(r, t);
|
|
642
739
|
s && o.push(s);
|
|
643
|
-
let c =
|
|
740
|
+
let c = vt(r, t);
|
|
644
741
|
c && o.push(c);
|
|
645
|
-
for (let e of r) o.push(
|
|
646
|
-
for (let e of i) o.push(
|
|
647
|
-
return o.push(...
|
|
648
|
-
},
|
|
649
|
-
let
|
|
650
|
-
yield*
|
|
651
|
-
}),
|
|
742
|
+
for (let e of r) o.push(at(e, t, null, a.get(e.tableName)));
|
|
743
|
+
for (let e of i) o.push(gt(e, t));
|
|
744
|
+
return o.push(...ct(r, t, n)), o.join("\n\n") + "\n";
|
|
745
|
+
}, Tt = (e, t = "postgres", n = O, r = {}) => b.gen(function* () {
|
|
746
|
+
let i = yield* C.SqlClient;
|
|
747
|
+
yield* je(i, Mt(i, xt(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(b.orDie);
|
|
748
|
+
}), Et = (e, t) => {
|
|
652
749
|
let n = t.cause ?? {};
|
|
653
750
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
654
|
-
},
|
|
655
|
-
let
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
751
|
+
}, Dt = (e, t) => {
|
|
752
|
+
let n = e.trimStart();
|
|
753
|
+
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));
|
|
754
|
+
}, Ot = () => {
|
|
755
|
+
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
756
|
+
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
757
|
+
}, kt = (e) => ({
|
|
758
|
+
while: e,
|
|
759
|
+
times: Ot(),
|
|
760
|
+
schedule: x.jittered(x.exponential("50 millis"))
|
|
761
|
+
}), At = class {
|
|
762
|
+
statement;
|
|
763
|
+
error;
|
|
764
|
+
_tag = "DdlStatementFailed";
|
|
765
|
+
constructor(e, t) {
|
|
766
|
+
this.statement = e, this.error = t;
|
|
767
|
+
}
|
|
768
|
+
}, jt = (e, t, n) => b.gen(function* () {
|
|
769
|
+
let r = yield* C.SqlClient, i = n !== void 0 && Pe(t) === "per-operation";
|
|
770
|
+
for (let a of Nt(e)) {
|
|
771
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && Xe.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
772
|
+
let e = r.unsafe(a).pipe(b.catchIf((e) => Et(a, e), () => b.succeed([])), b.tapError((e) => b.sync(() => {
|
|
773
|
+
Xe.error(ie("migrate: statement failed", a, e, 200));
|
|
774
|
+
})));
|
|
775
|
+
yield* (i && n !== void 0 && Dt(a, t) ? e.pipe(b.retry(kt((e) => n(e) === "retry"))) : e).pipe(b.mapError((e) => new At(a, e)));
|
|
776
|
+
}
|
|
777
|
+
}), Mt = (e, t, n, r) => {
|
|
778
|
+
let i = n === "turso" ? jt(t, n, r) : e.withTransaction(jt(t, n, r)), a = (e) => e instanceof At ? e.error : e;
|
|
779
|
+
return (r !== void 0 && Pe(n) === "plan-transactional" ? i.pipe(b.retry(kt((e) => r(a(e)) === "retry"))) : i).pipe(b.orDieWith((e) => e instanceof At ? Error(ie("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
780
|
+
}, Nt = (e) => {
|
|
660
781
|
let t = [], n = "", r = !1;
|
|
661
782
|
for (let i = 0; i < e.length; i++) {
|
|
662
783
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -671,43 +792,43 @@ BEGIN
|
|
|
671
792
|
}
|
|
672
793
|
let i = n.trim();
|
|
673
794
|
return i.length > 0 && t.push(i), t;
|
|
674
|
-
},
|
|
675
|
-
await b.runPromise(
|
|
676
|
-
},
|
|
677
|
-
let
|
|
678
|
-
yield*
|
|
679
|
-
}),
|
|
680
|
-
await b.runPromise(
|
|
795
|
+
}, Pt = async (e, t, n = "postgres", r = {}) => {
|
|
796
|
+
await b.runPromise(Tt(e, n, void 0, r).pipe(b.provide(t)));
|
|
797
|
+
}, Ft = (e, t, n = "postgres", r = {}) => b.gen(function* () {
|
|
798
|
+
let i = Ct(e, n, t), a = yield* C.SqlClient;
|
|
799
|
+
yield* je(a, Mt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(b.orDie);
|
|
800
|
+
}), It = async (e, t, n, r = "postgres", i = {}) => {
|
|
801
|
+
await b.runPromise(Ft(e, t, r, i).pipe(b.provide(n))), await d({
|
|
681
802
|
namespace: t,
|
|
682
803
|
dialect: r
|
|
683
804
|
});
|
|
684
|
-
},
|
|
805
|
+
}, Lt = async (e, t, n = "postgres", r = {}) => {
|
|
685
806
|
await b.runPromise(b.gen(function* () {
|
|
686
|
-
let t =
|
|
687
|
-
yield*
|
|
807
|
+
let t = wt(e, n), i = yield* C.SqlClient;
|
|
808
|
+
yield* je(i, Mt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(b.orDie);
|
|
688
809
|
}).pipe(b.provide(t)));
|
|
689
|
-
},
|
|
810
|
+
}, Rt = (e) => {
|
|
690
811
|
if (e == null) return e;
|
|
691
|
-
if (Array.isArray(e)) return e.map(
|
|
812
|
+
if (Array.isArray(e)) return e.map(Rt);
|
|
692
813
|
if (typeof e != "object") return e;
|
|
693
814
|
let t = {};
|
|
694
815
|
for (let n of Object.keys(e).sort()) {
|
|
695
816
|
let r = e[n];
|
|
696
|
-
r !== void 0 && (t[n] =
|
|
817
|
+
r !== void 0 && (t[n] = Rt(r));
|
|
697
818
|
}
|
|
698
819
|
return t;
|
|
699
|
-
},
|
|
820
|
+
}, zt = (e) => {
|
|
700
821
|
if (!e.idScheme && !e.sensitive && !e.safe) return e;
|
|
701
822
|
let { idScheme: t, sensitive: n, safe: r, ...i } = e;
|
|
702
823
|
return i;
|
|
703
|
-
},
|
|
824
|
+
}, Bt = (e) => [...e].map(zt).sort((e, t) => e.name.localeCompare(t.name)), Vt = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), Ht = (e) => [...e].map((e) => ({
|
|
704
825
|
name: e.name,
|
|
705
|
-
columns:
|
|
706
|
-
indexes:
|
|
707
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
708
|
-
let t = { tables:
|
|
709
|
-
return
|
|
710
|
-
},
|
|
826
|
+
columns: Bt(e.columns),
|
|
827
|
+
indexes: Vt(e.indexes)
|
|
828
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), N = (e) => {
|
|
829
|
+
let t = { tables: Ht(e.tables) }, n = JSON.stringify(Rt(t));
|
|
830
|
+
return ee("sha256").update(n).digest("hex");
|
|
831
|
+
}, P = (e) => e.slice(0, 16), Ut = (e, t) => {
|
|
711
832
|
let n = t.references ? {
|
|
712
833
|
table: t.references().tableName,
|
|
713
834
|
column: "id",
|
|
@@ -746,7 +867,7 @@ BEGIN
|
|
|
746
867
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
747
868
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
748
869
|
};
|
|
749
|
-
},
|
|
870
|
+
}, Wt = (e) => {
|
|
750
871
|
let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
751
872
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
752
873
|
}, i = e.appliedPrimaryKey ?? [];
|
|
@@ -794,11 +915,11 @@ BEGIN
|
|
|
794
915
|
});
|
|
795
916
|
}
|
|
796
917
|
return t;
|
|
797
|
-
},
|
|
918
|
+
}, Gt = (e) => {
|
|
798
919
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
799
920
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
800
921
|
if (i.dropped) continue;
|
|
801
|
-
let e =
|
|
922
|
+
let e = Ut(r, i);
|
|
802
923
|
n.push(t.has(r) ? {
|
|
803
924
|
...e,
|
|
804
925
|
unique: !0
|
|
@@ -808,27 +929,27 @@ BEGIN
|
|
|
808
929
|
return {
|
|
809
930
|
name: e.tableName,
|
|
810
931
|
columns: n,
|
|
811
|
-
indexes:
|
|
932
|
+
indexes: Wt(e),
|
|
812
933
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
813
934
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
814
935
|
};
|
|
815
|
-
},
|
|
936
|
+
}, Kt = (e) => {
|
|
816
937
|
let t = /* @__PURE__ */ new Map();
|
|
817
938
|
for (let n of e) for (let e of n.indexes) {
|
|
818
939
|
let r = t.get(e.name);
|
|
819
940
|
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}').`);
|
|
820
941
|
t.set(e.name, n.name);
|
|
821
942
|
}
|
|
822
|
-
},
|
|
823
|
-
let n = e.map((e) =>
|
|
824
|
-
return
|
|
825
|
-
},
|
|
943
|
+
}, F = (e, t) => {
|
|
944
|
+
let n = e.map((e) => Gt(le(e, t)));
|
|
945
|
+
return Kt(n), { tables: n };
|
|
946
|
+
}, qt = (e, t, n = O) => b.gen(function* () {
|
|
826
947
|
let r = (yield* e`
|
|
827
948
|
SELECT p.prosrc
|
|
828
949
|
FROM pg_proc p
|
|
829
950
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
830
951
|
WHERE n.nspname = current_schema()
|
|
831
|
-
AND p.proname = ${
|
|
952
|
+
AND p.proname = ${Je(n)}
|
|
832
953
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
833
954
|
if (a.length === 0) return {
|
|
834
955
|
missing: [],
|
|
@@ -842,10 +963,10 @@ BEGIN
|
|
|
842
963
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
843
964
|
WHERE NOT t.tgisinternal
|
|
844
965
|
AND n.nspname = current_schema()
|
|
845
|
-
AND t.tgname LIKE ${`${
|
|
966
|
+
AND t.tgname LIKE ${`${Ke}%`}
|
|
846
967
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
847
968
|
for (let e of a) {
|
|
848
|
-
let t = s.has(
|
|
969
|
+
let t = s.has(qe(e.tableName, n)), r = e.isReactive !== !1;
|
|
849
970
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
850
971
|
}
|
|
851
972
|
return {
|
|
@@ -853,7 +974,7 @@ BEGIN
|
|
|
853
974
|
stale: l.sort(),
|
|
854
975
|
functionOutdated: i
|
|
855
976
|
};
|
|
856
|
-
}),
|
|
977
|
+
}), Jt = (e) => {
|
|
857
978
|
let t = [];
|
|
858
979
|
if (e.missing.length > 0) {
|
|
859
980
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -864,19 +985,19 @@ BEGIN
|
|
|
864
985
|
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.`);
|
|
865
986
|
}
|
|
866
987
|
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;
|
|
867
|
-
},
|
|
988
|
+
}, Yt = {
|
|
868
989
|
postgres: !0,
|
|
869
990
|
mysql: !0,
|
|
870
991
|
mariadb: !0,
|
|
871
992
|
mssql: !0,
|
|
872
993
|
sqlite: !0
|
|
873
|
-
},
|
|
994
|
+
}, Xt = {
|
|
874
995
|
postgres: !0,
|
|
875
996
|
mysql: !1,
|
|
876
997
|
mariadb: !1,
|
|
877
998
|
mssql: !0,
|
|
878
999
|
sqlite: !0
|
|
879
|
-
},
|
|
1000
|
+
}, Zt = (e) => {
|
|
880
1001
|
switch (e) {
|
|
881
1002
|
case "add-column":
|
|
882
1003
|
case "drop-column":
|
|
@@ -886,47 +1007,47 @@ BEGIN
|
|
|
886
1007
|
case "add-foreign-key":
|
|
887
1008
|
case "add-unique":
|
|
888
1009
|
case "add-unique-composite":
|
|
889
|
-
case "add-check": return
|
|
890
|
-
default: return
|
|
1010
|
+
case "add-check": return Xt;
|
|
1011
|
+
default: return Yt;
|
|
891
1012
|
}
|
|
892
|
-
},
|
|
1013
|
+
}, Qt = (e, t) => {
|
|
893
1014
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
894
1015
|
return new Map(e.map((e) => [e.tableName, {
|
|
895
1016
|
table: e,
|
|
896
1017
|
snapshot: n.get(e.tableName),
|
|
897
1018
|
columnDefs: e.fields
|
|
898
1019
|
}]));
|
|
899
|
-
},
|
|
1020
|
+
}, I = (e) => {
|
|
900
1021
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
901
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
1022
|
+
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
902
1023
|
let t = e;
|
|
903
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
904
|
-
},
|
|
1024
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
1025
|
+
}, $t = (e) => {
|
|
905
1026
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
906
1027
|
let t = e.defaultValue;
|
|
907
1028
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
908
1029
|
if (typeof t == "number") return String(t);
|
|
909
|
-
if (typeof t != "string") return
|
|
1030
|
+
if (typeof t != "string") return I(t);
|
|
910
1031
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
911
1032
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
912
1033
|
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);
|
|
913
1034
|
if (o) try {
|
|
914
|
-
return
|
|
1035
|
+
return I(JSON.parse(o[1]));
|
|
915
1036
|
} catch {}
|
|
916
1037
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
917
1038
|
if (s) try {
|
|
918
|
-
return
|
|
1039
|
+
return I(JSON.parse(s[1]));
|
|
919
1040
|
} catch {}
|
|
920
1041
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
921
|
-
return
|
|
1042
|
+
return I(JSON.parse(a));
|
|
922
1043
|
} catch {}
|
|
923
1044
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
924
|
-
},
|
|
925
|
-
let n =
|
|
1045
|
+
}, en = (e, t) => {
|
|
1046
|
+
let n = $t(e), r = $t(t);
|
|
926
1047
|
if (n === r) return !0;
|
|
927
1048
|
let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
928
1049
|
return i(n) === i(r);
|
|
929
|
-
},
|
|
1050
|
+
}, tn = (e) => {
|
|
930
1051
|
if (!e) return null;
|
|
931
1052
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
932
1053
|
return {
|
|
@@ -935,25 +1056,25 @@ BEGIN
|
|
|
935
1056
|
onDelete: t(e.onDelete),
|
|
936
1057
|
onUpdate: t(e.onUpdate)
|
|
937
1058
|
};
|
|
938
|
-
},
|
|
1059
|
+
}, nn = (e, t) => {
|
|
939
1060
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
940
1061
|
if (!n && !r) return !0;
|
|
941
1062
|
if (!n || !r || n.length !== r.length) return !1;
|
|
942
1063
|
let i = [...n].sort(), a = [...r].sort();
|
|
943
1064
|
return i.every((e, t) => e === a[t]);
|
|
944
|
-
},
|
|
1065
|
+
}, rn = (e, t) => {
|
|
945
1066
|
try {
|
|
946
|
-
let n = /\((\d+)\)/.exec(
|
|
1067
|
+
let n = /\((\d+)\)/.exec(A(e, t));
|
|
947
1068
|
return n ? Number(n[1]) : void 0;
|
|
948
1069
|
} catch {
|
|
949
1070
|
return;
|
|
950
1071
|
}
|
|
951
|
-
},
|
|
1072
|
+
}, an = (e, t, n) => n === void 0 || r(n) ? !0 : e.type !== "text" || t.type !== "text" || rn(e, n) === t.maxLength, on = (e, t, n) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && en(e, t) && an(e, t, n) && JSON.stringify(tn(e.references)) === JSON.stringify(tn(t.references)) && nn(e.oneOf, t.oneOf), sn = (e, t) => t.oneOf && t.oneOf.length > 0 ? L({
|
|
952
1073
|
kind: "add-check",
|
|
953
1074
|
table: e,
|
|
954
1075
|
column: t.name,
|
|
955
1076
|
values: t.oneOf
|
|
956
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1077
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, cn = (e, t) => e.unique === t.unique && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), ln = (e, t, n) => {
|
|
957
1078
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [];
|
|
958
1079
|
for (let t of e.columns) {
|
|
959
1080
|
let e = r.get(t.name);
|
|
@@ -961,7 +1082,7 @@ BEGIN
|
|
|
961
1082
|
a.push(t);
|
|
962
1083
|
continue;
|
|
963
1084
|
}
|
|
964
|
-
|
|
1085
|
+
on(t, e, n) || s.push({
|
|
965
1086
|
declared: t,
|
|
966
1087
|
live: e
|
|
967
1088
|
});
|
|
@@ -972,47 +1093,47 @@ BEGIN
|
|
|
972
1093
|
removed: o,
|
|
973
1094
|
changed: s
|
|
974
1095
|
};
|
|
975
|
-
},
|
|
1096
|
+
}, un = (e, t) => {
|
|
976
1097
|
let n = new Map(t.indexes.map((e) => [e.name, e])), r = new Map(e.indexes.map((e) => [e.name, e])), i = [], a = [];
|
|
977
1098
|
for (let t of e.indexes) {
|
|
978
1099
|
let e = n.get(t.name);
|
|
979
|
-
(!e || !
|
|
1100
|
+
(!e || !cn(t, e)) && i.push(t);
|
|
980
1101
|
}
|
|
981
1102
|
for (let e of t.indexes) r.has(e.name) || a.push(e);
|
|
982
1103
|
return {
|
|
983
1104
|
added: i,
|
|
984
1105
|
removed: a
|
|
985
1106
|
};
|
|
986
|
-
},
|
|
1107
|
+
}, L = (e, t, n, r) => ({
|
|
987
1108
|
op: e,
|
|
988
1109
|
classification: t,
|
|
989
|
-
atomicByDialect:
|
|
1110
|
+
atomicByDialect: Zt(e.kind),
|
|
990
1111
|
...n ? { reason: n } : {},
|
|
991
1112
|
...r ? { blocked: r } : {}
|
|
992
|
-
}),
|
|
1113
|
+
}), dn = (e, t, n) => {
|
|
993
1114
|
let r = {
|
|
994
1115
|
kind: "add-column",
|
|
995
1116
|
table: e,
|
|
996
1117
|
column: t
|
|
997
1118
|
};
|
|
998
|
-
return t.nullable ?
|
|
999
|
-
},
|
|
1119
|
+
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` });
|
|
1120
|
+
}, fn = (e, t, n) => {
|
|
1000
1121
|
let r = {
|
|
1001
1122
|
kind: "drop-column",
|
|
1002
1123
|
table: e,
|
|
1003
1124
|
column: t.name
|
|
1004
1125
|
};
|
|
1005
|
-
return n?.dropped ?
|
|
1006
|
-
},
|
|
1126
|
+
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` });
|
|
1127
|
+
}, pn = (e, t, n, r, i) => L({
|
|
1007
1128
|
kind: "create-table",
|
|
1008
1129
|
table: e,
|
|
1009
1130
|
columns: t,
|
|
1010
1131
|
indexes: n,
|
|
1011
1132
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1012
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1133
|
+
}, "safe", i ?? "new table — no data to preserve"), mn = (e) => L({
|
|
1013
1134
|
kind: "drop-table",
|
|
1014
1135
|
table: e
|
|
1015
|
-
}, "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" }),
|
|
1136
|
+
}, "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" }), hn = 5e4, gn = (e, t, n, r) => {
|
|
1016
1137
|
let i = (n ?? 0) >= r, a;
|
|
1017
1138
|
return a = t.unique ? t.columns.length === 1 ? {
|
|
1018
1139
|
kind: "add-unique",
|
|
@@ -1027,16 +1148,16 @@ BEGIN
|
|
|
1027
1148
|
kind: "add-index",
|
|
1028
1149
|
table: e,
|
|
1029
1150
|
index: t
|
|
1030
|
-
}, i ?
|
|
1031
|
-
},
|
|
1151
|
+
}, i ? L(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : L(a, "safe", t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index");
|
|
1152
|
+
}, _n = (e, t) => t.unique && t.columns.length > 1 ? L({
|
|
1032
1153
|
kind: "drop-unique-composite",
|
|
1033
1154
|
table: e,
|
|
1034
1155
|
name: t.name
|
|
1035
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1156
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : L({
|
|
1036
1157
|
kind: "drop-index",
|
|
1037
1158
|
table: e,
|
|
1038
1159
|
index: t.name
|
|
1039
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1160
|
+
}, "safe", "drop index (no data loss — index is derived data)"), vn = (e, t) => {
|
|
1040
1161
|
if (e === "reference") return "text";
|
|
1041
1162
|
switch (t) {
|
|
1042
1163
|
case "sqlite":
|
|
@@ -1044,7 +1165,7 @@ BEGIN
|
|
|
1044
1165
|
case "mssql": return e === "json" ? "text" : e;
|
|
1045
1166
|
default: return e;
|
|
1046
1167
|
}
|
|
1047
|
-
},
|
|
1168
|
+
}, yn = (e, t, n, i, a, o) => {
|
|
1048
1169
|
let s = [];
|
|
1049
1170
|
if (t.nullable !== n.nullable) {
|
|
1050
1171
|
let n = {
|
|
@@ -1053,7 +1174,7 @@ BEGIN
|
|
|
1053
1174
|
column: t.name,
|
|
1054
1175
|
toNullable: t.nullable
|
|
1055
1176
|
};
|
|
1056
|
-
s.push(t.nullable ?
|
|
1177
|
+
s.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`));
|
|
1057
1178
|
}
|
|
1058
1179
|
if (t.unique !== n.unique) if (t.unique) {
|
|
1059
1180
|
let n = {
|
|
@@ -1061,13 +1182,13 @@ BEGIN
|
|
|
1061
1182
|
table: e,
|
|
1062
1183
|
column: t.name
|
|
1063
1184
|
}, r = (a ?? 0) >= o;
|
|
1064
|
-
s.push(r ?
|
|
1065
|
-
} else s.push(
|
|
1185
|
+
s.push(r ? L(n, "online-required", `online unique build on ${a} 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)`));
|
|
1186
|
+
} else s.push(L({
|
|
1066
1187
|
kind: "drop-unique",
|
|
1067
1188
|
table: e,
|
|
1068
1189
|
column: t.name
|
|
1069
1190
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1070
|
-
if (
|
|
1191
|
+
if (vn(t.type, i) !== vn(n.type, i)) {
|
|
1071
1192
|
let r = t.narrowedFrom;
|
|
1072
1193
|
if (r && r.from === n.type) {
|
|
1073
1194
|
let i = {
|
|
@@ -1078,7 +1199,7 @@ BEGIN
|
|
|
1078
1199
|
to: t.type,
|
|
1079
1200
|
...r.using === void 0 ? {} : { using: r.using }
|
|
1080
1201
|
};
|
|
1081
|
-
s.push(
|
|
1202
|
+
s.push(L(i, "needs-backfill", `type change ${n.type} → ${t.type} on ${e}.${t.name} — narrowedFrom('${r.from}') declared` + (r.using ? ` with USING ${r.using}` : " (implicit cast)")));
|
|
1082
1203
|
} else {
|
|
1083
1204
|
let r = {
|
|
1084
1205
|
kind: "alter-column-type",
|
|
@@ -1087,12 +1208,12 @@ BEGIN
|
|
|
1087
1208
|
from: n.type,
|
|
1088
1209
|
to: t.type
|
|
1089
1210
|
};
|
|
1090
|
-
s.push(
|
|
1211
|
+
s.push(L(r, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: `acknowledge it on the column: \`.narrowedFrom('${n.type}', { using: '${t.name}::${t.type}' })\` (drop \`using\` if the cast is implicit), or use a file-based migration` }));
|
|
1091
1212
|
}
|
|
1092
1213
|
}
|
|
1093
1214
|
if (t.type === "text" && n.type === "text" && !r(i ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1094
1215
|
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})`;
|
|
1095
|
-
s.push(
|
|
1216
|
+
s.push(L({
|
|
1096
1217
|
kind: "alter-column-type",
|
|
1097
1218
|
table: e,
|
|
1098
1219
|
column: t.name,
|
|
@@ -1100,7 +1221,7 @@ BEGIN
|
|
|
1100
1221
|
to: "text"
|
|
1101
1222
|
}, 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)}`));
|
|
1102
1223
|
}
|
|
1103
|
-
if (!
|
|
1224
|
+
if (!en(t, n)) {
|
|
1104
1225
|
let n = {
|
|
1105
1226
|
kind: "alter-column-default",
|
|
1106
1227
|
table: e,
|
|
@@ -1108,23 +1229,23 @@ BEGIN
|
|
|
1108
1229
|
hasDefault: t.hasDefault,
|
|
1109
1230
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1110
1231
|
};
|
|
1111
|
-
s.push(
|
|
1232
|
+
s.push(L(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1112
1233
|
}
|
|
1113
|
-
if (!
|
|
1114
|
-
n.oneOf && n.oneOf.length > 0 && s.push(
|
|
1234
|
+
if (!nn(t.oneOf, n.oneOf)) {
|
|
1235
|
+
n.oneOf && n.oneOf.length > 0 && s.push(L({
|
|
1115
1236
|
kind: "drop-check",
|
|
1116
1237
|
table: e,
|
|
1117
1238
|
column: t.name
|
|
1118
1239
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1119
|
-
let r =
|
|
1240
|
+
let r = sn(e, t);
|
|
1120
1241
|
r && s.push(r);
|
|
1121
1242
|
}
|
|
1122
|
-
return JSON.stringify(
|
|
1243
|
+
return JSON.stringify(tn(t.references)) !== JSON.stringify(tn(n.references)) && (n.references && s.push(L({
|
|
1123
1244
|
kind: "drop-foreign-key",
|
|
1124
1245
|
table: e,
|
|
1125
1246
|
column: t.name
|
|
1126
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), s.push(...
|
|
1127
|
-
},
|
|
1247
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), s.push(...bn(e, t))), s;
|
|
1248
|
+
}, bn = (e, t) => {
|
|
1128
1249
|
let n = [];
|
|
1129
1250
|
if (!t.references) return n;
|
|
1130
1251
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1136,15 +1257,15 @@ BEGIN
|
|
|
1136
1257
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1137
1258
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1138
1259
|
};
|
|
1139
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1260
|
+
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({
|
|
1140
1261
|
...a,
|
|
1141
1262
|
orphanPolicy: i
|
|
1142
|
-
}, "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(
|
|
1143
|
-
},
|
|
1263
|
+
}, "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;
|
|
1264
|
+
}, xn = (e, t, n) => {
|
|
1144
1265
|
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));
|
|
1145
1266
|
for (let [n, c] of Object.entries(t)) {
|
|
1146
1267
|
let t = c.renamedFrom;
|
|
1147
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1268
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(L({
|
|
1148
1269
|
kind: "rename-column",
|
|
1149
1270
|
table: e.tableName,
|
|
1150
1271
|
from: t,
|
|
@@ -1156,26 +1277,26 @@ BEGIN
|
|
|
1156
1277
|
consumedAddedNames: i,
|
|
1157
1278
|
consumedRemovedNames: a
|
|
1158
1279
|
};
|
|
1159
|
-
},
|
|
1280
|
+
}, Sn = /* @__PURE__ */ new Set([
|
|
1160
1281
|
"postgres",
|
|
1161
1282
|
"mysql",
|
|
1162
1283
|
"mariadb",
|
|
1163
1284
|
"mssql"
|
|
1164
|
-
]),
|
|
1285
|
+
]), Cn = {
|
|
1165
1286
|
ops: [],
|
|
1166
1287
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1167
1288
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1168
|
-
},
|
|
1169
|
-
if (i === void 0 || !
|
|
1170
|
-
let a = t.added.filter((e) =>
|
|
1171
|
-
if (a.length === 0) return
|
|
1289
|
+
}, wn = (e) => !e.unique && !e.expression, Tn = (e, t, n, r, i) => {
|
|
1290
|
+
if (i === void 0 || !Sn.has(i)) return Cn;
|
|
1291
|
+
let a = t.added.filter((e) => wn(e) && !r.has(e.name));
|
|
1292
|
+
if (a.length === 0) return Cn;
|
|
1172
1293
|
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();
|
|
1173
1294
|
for (let n of t.removed) {
|
|
1174
|
-
if (!
|
|
1295
|
+
if (!wn(n)) continue;
|
|
1175
1296
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1176
1297
|
if (r.length !== 1) continue;
|
|
1177
1298
|
let i = r[0];
|
|
1178
|
-
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(
|
|
1299
|
+
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(L({
|
|
1179
1300
|
kind: "rename-index",
|
|
1180
1301
|
table: e,
|
|
1181
1302
|
from: n.name,
|
|
@@ -1187,7 +1308,7 @@ BEGIN
|
|
|
1187
1308
|
consumedAddedNames: l,
|
|
1188
1309
|
consumedRemovedNames: u
|
|
1189
1310
|
};
|
|
1190
|
-
},
|
|
1311
|
+
}, En = (e, t, n) => {
|
|
1191
1312
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1192
1313
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1193
1314
|
for (let c of e.tables) {
|
|
@@ -1198,7 +1319,7 @@ BEGIN
|
|
|
1198
1319
|
continue;
|
|
1199
1320
|
}
|
|
1200
1321
|
if (t.has(c.name)) {
|
|
1201
|
-
r.push(
|
|
1322
|
+
r.push(L({
|
|
1202
1323
|
kind: "rename-table",
|
|
1203
1324
|
from: e,
|
|
1204
1325
|
to: c.name
|
|
@@ -1206,14 +1327,14 @@ BEGIN
|
|
|
1206
1327
|
continue;
|
|
1207
1328
|
}
|
|
1208
1329
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1209
|
-
r.push(
|
|
1330
|
+
r.push(L({
|
|
1210
1331
|
kind: "rename-table",
|
|
1211
1332
|
from: e,
|
|
1212
1333
|
to: c.name
|
|
1213
1334
|
}, "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.` }));
|
|
1214
1335
|
continue;
|
|
1215
1336
|
}
|
|
1216
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1337
|
+
i.set(c.name, e), a.add(e), r.push(L({
|
|
1217
1338
|
kind: "rename-table",
|
|
1218
1339
|
from: e,
|
|
1219
1340
|
to: c.name
|
|
@@ -1227,19 +1348,19 @@ BEGIN
|
|
|
1227
1348
|
claimedOldNames: c,
|
|
1228
1349
|
refusals: o
|
|
1229
1350
|
};
|
|
1230
|
-
},
|
|
1351
|
+
}, Dn = (e, t, n, r) => {
|
|
1231
1352
|
if (t === void 0) return {
|
|
1232
1353
|
live: e,
|
|
1233
1354
|
ops: []
|
|
1234
1355
|
};
|
|
1235
|
-
let i = r !== void 0 &&
|
|
1356
|
+
let i = r !== void 0 && Sn.has(r), a = [], o = e.indexes.map((e) => {
|
|
1236
1357
|
if (!e.name.startsWith(t)) return e;
|
|
1237
1358
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1238
1359
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1239
1360
|
...e,
|
|
1240
1361
|
name: r,
|
|
1241
1362
|
table: n
|
|
1242
|
-
} : i ? (a.push(
|
|
1363
|
+
} : i ? (a.push(L({
|
|
1243
1364
|
kind: "rename-index",
|
|
1244
1365
|
table: n,
|
|
1245
1366
|
from: e.name,
|
|
@@ -1258,7 +1379,7 @@ BEGIN
|
|
|
1258
1379
|
},
|
|
1259
1380
|
ops: a
|
|
1260
1381
|
};
|
|
1261
|
-
},
|
|
1382
|
+
}, On = (e) => {
|
|
1262
1383
|
let t = {
|
|
1263
1384
|
safe: 0,
|
|
1264
1385
|
needsDefault: 0,
|
|
@@ -1293,42 +1414,42 @@ BEGIN
|
|
|
1293
1414
|
break;
|
|
1294
1415
|
}
|
|
1295
1416
|
return t;
|
|
1296
|
-
},
|
|
1297
|
-
let t =
|
|
1417
|
+
}, kn = (e) => {
|
|
1418
|
+
let t = F(e.declared, e.dialect), n = Qt(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? hn, a = [], o = En(t, r, n);
|
|
1298
1419
|
a.push(...o.ops);
|
|
1299
1420
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1300
|
-
a.push(
|
|
1421
|
+
a.push(pn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1301
1422
|
for (let t of e.columns) {
|
|
1302
|
-
let n =
|
|
1423
|
+
let n = sn(e.name, t);
|
|
1303
1424
|
n && a.push(n);
|
|
1304
1425
|
}
|
|
1305
1426
|
}
|
|
1306
1427
|
let s = new Set(e.ignoreTables ?? []);
|
|
1307
|
-
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || m(t.name) || v(t.name) || s.has(t.name) || a.push(
|
|
1428
|
+
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || m(t.name) || v(t.name) || s.has(t.name) || a.push(mn(t.name));
|
|
1308
1429
|
for (let s of t.tables) {
|
|
1309
1430
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1310
1431
|
if (!c) continue;
|
|
1311
|
-
let l =
|
|
1432
|
+
let l = Dn(c, t, s.name, e.dialect);
|
|
1312
1433
|
a.push(...l.ops);
|
|
1313
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1434
|
+
let u = l.live, d = n.get(s.name), f = ln(s, u, e.dialect), p = un(s, u), m = xn(d.table, d.columnDefs, f);
|
|
1314
1435
|
a.push(...m.ops);
|
|
1315
1436
|
for (let e of f.removed) {
|
|
1316
1437
|
if (m.consumedRemovedNames.has(e.name) || v(e.name)) continue;
|
|
1317
1438
|
let t = d.columnDefs[e.name];
|
|
1318
|
-
a.push(
|
|
1439
|
+
a.push(fn(s.name, e, t));
|
|
1319
1440
|
}
|
|
1320
1441
|
for (let e of f.added) {
|
|
1321
1442
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1322
1443
|
let t = d.columnDefs[e.name];
|
|
1323
|
-
a.push(
|
|
1324
|
-
let n =
|
|
1325
|
-
n && a.push(n), a.push(...
|
|
1444
|
+
a.push(dn(s.name, e, t));
|
|
1445
|
+
let n = sn(s.name, e);
|
|
1446
|
+
n && a.push(n), a.push(...bn(s.name, e));
|
|
1326
1447
|
}
|
|
1327
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1448
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Tn(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1328
1449
|
a.push(...g.ops);
|
|
1329
|
-
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(
|
|
1330
|
-
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(
|
|
1331
|
-
for (let { declared: t, live: n } of f.changed) a.push(...
|
|
1450
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(gn(s.name, e, u.rowCount, i));
|
|
1451
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(_n(s.name, e));
|
|
1452
|
+
for (let { declared: t, live: n } of f.changed) a.push(...yn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1332
1453
|
}
|
|
1333
1454
|
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) => {
|
|
1334
1455
|
let t = l.get(e);
|
|
@@ -1336,8 +1457,8 @@ BEGIN
|
|
|
1336
1457
|
column: e.name,
|
|
1337
1458
|
target: e.references.table
|
|
1338
1459
|
}] : []) : [];
|
|
1339
|
-
}, d =
|
|
1340
|
-
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(w(e.name, t.name)) || f.push(
|
|
1460
|
+
}, d = ue([...c], u), f = [];
|
|
1461
|
+
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(w(e.name, t.name)) || f.push(L({
|
|
1341
1462
|
kind: "add-foreign-key",
|
|
1342
1463
|
table: e.name,
|
|
1343
1464
|
column: t.name,
|
|
@@ -1409,87 +1530,11 @@ BEGIN
|
|
|
1409
1530
|
});
|
|
1410
1531
|
return {
|
|
1411
1532
|
operations: S,
|
|
1412
|
-
fromFingerprint:
|
|
1413
|
-
toFingerprint:
|
|
1414
|
-
summary:
|
|
1533
|
+
fromFingerprint: N(e.live),
|
|
1534
|
+
toFingerprint: N(t),
|
|
1535
|
+
summary: On(S)
|
|
1415
1536
|
};
|
|
1416
|
-
},
|
|
1417
|
-
pg: () => "postgres",
|
|
1418
|
-
mysql: () => "mysql",
|
|
1419
|
-
mssql: () => "mssql",
|
|
1420
|
-
sqlite: () => "sqlite",
|
|
1421
|
-
orElse: () => "sqlite"
|
|
1422
|
-
}), on = {
|
|
1423
|
-
postgres: "plan-transactional",
|
|
1424
|
-
mssql: "plan-transactional",
|
|
1425
|
-
mysql: "per-operation",
|
|
1426
|
-
mariadb: "per-operation",
|
|
1427
|
-
sqlite: "per-operation",
|
|
1428
|
-
turso: "per-operation"
|
|
1429
|
-
}, sn = (e) => on[e], L = "_voltro_migration_ops", cn = l(L, {
|
|
1430
|
-
id: e({ prefix: "mop" }),
|
|
1431
|
-
runId: _(),
|
|
1432
|
-
planFingerprint: _(),
|
|
1433
|
-
opIndex: n(),
|
|
1434
|
-
opKind: _(),
|
|
1435
|
-
opTarget: _(),
|
|
1436
|
-
status: _(),
|
|
1437
|
-
payload: _(),
|
|
1438
|
-
startedAt: t().nullable(),
|
|
1439
|
-
appliedAt: t().nullable(),
|
|
1440
|
-
durationMs: n().nullable(),
|
|
1441
|
-
createdAt: t().default("now")
|
|
1442
|
-
}), ln = (e) => {
|
|
1443
|
-
switch (e.kind) {
|
|
1444
|
-
case "create-table": return /* @__PURE__ */ new Set([
|
|
1445
|
-
`table:${e.table}`,
|
|
1446
|
-
...e.columns.map((t) => `column:${e.table}.${t.name}`),
|
|
1447
|
-
...e.indexes.map((t) => `index:${e.table}.${t.name}`)
|
|
1448
|
-
]);
|
|
1449
|
-
case "drop-table": return /* @__PURE__ */ new Set([`table:${e.table}`]);
|
|
1450
|
-
case "rename-table": return /* @__PURE__ */ new Set([`table:${e.from}`, `table:${e.to}`]);
|
|
1451
|
-
case "add-column": return /* @__PURE__ */ new Set([`column:${e.table}.${e.column.name}`]);
|
|
1452
|
-
case "rename-column": return /* @__PURE__ */ new Set([`column:${e.table}.${e.from}`, `column:${e.table}.${e.to}`]);
|
|
1453
|
-
case "drop-column":
|
|
1454
|
-
case "alter-column-nullability":
|
|
1455
|
-
case "alter-column-type":
|
|
1456
|
-
case "alter-column-default":
|
|
1457
|
-
case "add-unique":
|
|
1458
|
-
case "drop-unique":
|
|
1459
|
-
case "add-foreign-key":
|
|
1460
|
-
case "drop-foreign-key":
|
|
1461
|
-
case "add-check":
|
|
1462
|
-
case "drop-check": return /* @__PURE__ */ new Set([`column:${e.table}.${e.column}`]);
|
|
1463
|
-
case "add-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index.name}`]);
|
|
1464
|
-
case "drop-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.index}`]);
|
|
1465
|
-
case "rename-index": return /* @__PURE__ */ new Set([`index:${e.table}.${e.from}`, `index:${e.table}.${e.to}`]);
|
|
1466
|
-
case "add-unique-composite":
|
|
1467
|
-
case "drop-unique-composite": return /* @__PURE__ */ new Set([`unique:${e.table}.${e.name}`]);
|
|
1468
|
-
}
|
|
1469
|
-
}, un = (e) => [...ln(e)].join(" "), dn = (e, t) => {
|
|
1470
|
-
let n = ln(t);
|
|
1471
|
-
for (let t of ln(e)) if (n.has(t)) return !0;
|
|
1472
|
-
return !1;
|
|
1473
|
-
}, fn = (e, t) => e.operations.some((e) => dn(e.op, t)), pn = "__voltro_rebuild", mn = "__shadow", hn = "__old", gn = /* @__PURE__ */ new Set([
|
|
1474
|
-
"add-unique",
|
|
1475
|
-
"drop-unique",
|
|
1476
|
-
"add-unique-composite",
|
|
1477
|
-
"drop-unique-composite",
|
|
1478
|
-
"add-foreign-key",
|
|
1479
|
-
"drop-foreign-key",
|
|
1480
|
-
"add-check",
|
|
1481
|
-
"drop-check",
|
|
1482
|
-
"alter-column-nullability",
|
|
1483
|
-
"alter-column-type",
|
|
1484
|
-
"alter-column-default"
|
|
1485
|
-
]), _n = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), vn = (e, t, n) => {
|
|
1486
|
-
let r = n === "sqlite" || n === "turso";
|
|
1487
|
-
return e.kind === "alter-column-type" && t === "online-required" || r && gn.has(e.kind) ? "artefact-repair" : _n.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
1488
|
-
};
|
|
1489
|
-
Object.keys(on);
|
|
1490
|
-
//#endregion
|
|
1491
|
-
//#region src/migrations/introspect.ts
|
|
1492
|
-
var yn = (e) => {
|
|
1537
|
+
}, An = (e) => {
|
|
1493
1538
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1494
1539
|
if (!t) return null;
|
|
1495
1540
|
let n = [...e.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
|
|
@@ -1497,7 +1542,7 @@ var yn = (e) => {
|
|
|
1497
1542
|
column: t[1],
|
|
1498
1543
|
values: n
|
|
1499
1544
|
};
|
|
1500
|
-
},
|
|
1545
|
+
}, jn = (e, t) => {
|
|
1501
1546
|
if (t === "vector") return "vector";
|
|
1502
1547
|
switch (e) {
|
|
1503
1548
|
case "text":
|
|
@@ -1532,25 +1577,25 @@ var yn = (e) => {
|
|
|
1532
1577
|
case "SET DEFAULT": return "noAction";
|
|
1533
1578
|
default: return "noAction";
|
|
1534
1579
|
}
|
|
1535
|
-
},
|
|
1580
|
+
}, Mn = (e, t) => {
|
|
1536
1581
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1537
1582
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1538
|
-
},
|
|
1583
|
+
}, Nn = () => Mn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Pn = 300, Fn = () => {
|
|
1539
1584
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1540
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1541
|
-
},
|
|
1585
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Mn(e, 3e4);
|
|
1586
|
+
}, In = (e, t) => {
|
|
1542
1587
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1543
1588
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1544
1589
|
return r;
|
|
1545
|
-
},
|
|
1546
|
-
let t =
|
|
1590
|
+
}, Ln = (e) => {
|
|
1591
|
+
let t = Fn(), n = b.gen(function* () {
|
|
1547
1592
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1548
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
1593
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Nn(), a = (e, t) => b.gen(function* () {
|
|
1549
1594
|
let r = [];
|
|
1550
|
-
for (let a of
|
|
1595
|
+
for (let a of In(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1551
1596
|
return r;
|
|
1552
1597
|
}), o = [];
|
|
1553
|
-
for (let t = 0;; t +=
|
|
1598
|
+
for (let t = 0;; t += Pn) {
|
|
1554
1599
|
let n = yield* e`
|
|
1555
1600
|
SELECT c.relname AS table_name,
|
|
1556
1601
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1558,9 +1603,9 @@ var yn = (e) => {
|
|
|
1558
1603
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1559
1604
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1560
1605
|
ORDER BY c.relname
|
|
1561
|
-
LIMIT ${r(
|
|
1606
|
+
LIMIT ${r(Pn)} OFFSET ${r(t)}
|
|
1562
1607
|
`;
|
|
1563
|
-
if (o.push(...n), n.length <
|
|
1608
|
+
if (o.push(...n), n.length < Pn) break;
|
|
1564
1609
|
}
|
|
1565
1610
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1566
1611
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1694,7 +1739,7 @@ var yn = (e) => {
|
|
|
1694
1739
|
let te = [];
|
|
1695
1740
|
for (let e of c) {
|
|
1696
1741
|
let t = /* @__PURE__ */ new Set(), n = (_.get(e.table_name) ?? []).filter((e) => t.has(e.column_name) ? !1 : (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 = S.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) => {
|
|
1697
|
-
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" :
|
|
1742
|
+
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" : jn(t.data_type, t.udt_name), c = a ? {
|
|
1698
1743
|
table: a.target_table,
|
|
1699
1744
|
column: a.target_column,
|
|
1700
1745
|
onDelete: R(a.delete_rule),
|
|
@@ -1748,7 +1793,7 @@ var yn = (e) => {
|
|
|
1748
1793
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1749
1794
|
return n.includes("statement timeout") || n.includes("57014") ? b.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.`)) : b.fail(e);
|
|
1750
1795
|
}));
|
|
1751
|
-
},
|
|
1796
|
+
}, Rn = (e, t) => {
|
|
1752
1797
|
switch (e.toLowerCase()) {
|
|
1753
1798
|
case "varchar":
|
|
1754
1799
|
case "char":
|
|
@@ -1784,7 +1829,7 @@ var yn = (e) => {
|
|
|
1784
1829
|
let t = e, n = {};
|
|
1785
1830
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1786
1831
|
return n;
|
|
1787
|
-
}),
|
|
1832
|
+
}), zn = (e) => b.gen(function* () {
|
|
1788
1833
|
let t = z(yield* e`
|
|
1789
1834
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1790
1835
|
FROM information_schema.tables
|
|
@@ -1818,7 +1863,7 @@ var yn = (e) => {
|
|
|
1818
1863
|
o.add(`${e.table_name}.${t[1]}`);
|
|
1819
1864
|
continue;
|
|
1820
1865
|
}
|
|
1821
|
-
let n =
|
|
1866
|
+
let n = An(e.check_clause);
|
|
1822
1867
|
n && s.set(`${e.table_name}.${n.column}`, n.values);
|
|
1823
1868
|
}
|
|
1824
1869
|
let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
|
|
@@ -1841,7 +1886,7 @@ var yn = (e) => {
|
|
|
1841
1886
|
let t = c.get(e.table_name) ?? [], n = l.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(), f = u.get(e.table_name);
|
|
1842
1887
|
if (f) for (let e of f.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1843
1888
|
let p = t.map((t) => {
|
|
1844
|
-
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" :
|
|
1889
|
+
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" : Rn(t.data_type, t.column_type), u = c ? {
|
|
1845
1890
|
table: c.target_table,
|
|
1846
1891
|
column: c.target_column,
|
|
1847
1892
|
onDelete: R(c.delete_rule),
|
|
@@ -1883,10 +1928,10 @@ var yn = (e) => {
|
|
|
1883
1928
|
});
|
|
1884
1929
|
}
|
|
1885
1930
|
return { tables: d };
|
|
1886
|
-
}),
|
|
1931
|
+
}), Bn = (e) => {
|
|
1887
1932
|
let t = e.toUpperCase();
|
|
1888
1933
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
1889
|
-
},
|
|
1934
|
+
}, Vn = (e) => b.gen(function* () {
|
|
1890
1935
|
let t = yield* e`
|
|
1891
1936
|
SELECT name, sql FROM sqlite_master
|
|
1892
1937
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -1903,7 +1948,7 @@ var yn = (e) => {
|
|
|
1903
1948
|
d.set(t.name, r), t.unique === 1 && r.length === 1 && f.add(r[0]);
|
|
1904
1949
|
}
|
|
1905
1950
|
let p = o.map((e) => {
|
|
1906
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
1951
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : Bn(e.type), a = r ? {
|
|
1907
1952
|
table: r.table,
|
|
1908
1953
|
column: r.to,
|
|
1909
1954
|
onDelete: R(r.on_delete),
|
|
@@ -1942,7 +1987,7 @@ var yn = (e) => {
|
|
|
1942
1987
|
});
|
|
1943
1988
|
}
|
|
1944
1989
|
return { tables: r };
|
|
1945
|
-
}),
|
|
1990
|
+
}), Hn = (e) => {
|
|
1946
1991
|
switch (e.toLowerCase()) {
|
|
1947
1992
|
case "int":
|
|
1948
1993
|
case "smallint":
|
|
@@ -1964,7 +2009,7 @@ var yn = (e) => {
|
|
|
1964
2009
|
case "image": return "bytes";
|
|
1965
2010
|
default: return "text";
|
|
1966
2011
|
}
|
|
1967
|
-
}, B = (e) => e === !0 || e === 1,
|
|
2012
|
+
}, B = (e) => e === !0 || e === 1, Un = (e) => b.gen(function* () {
|
|
1968
2013
|
let t = yield* e`
|
|
1969
2014
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
1970
2015
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -2025,12 +2070,12 @@ var yn = (e) => {
|
|
|
2025
2070
|
else B(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
|
|
2026
2071
|
}
|
|
2027
2072
|
let p = t.map((t) => {
|
|
2028
|
-
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" :
|
|
2073
|
+
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" : Hn(t.data_type), s = i ? {
|
|
2029
2074
|
table: i.target_table,
|
|
2030
2075
|
column: i.target_column,
|
|
2031
|
-
onDelete:
|
|
2032
|
-
onUpdate:
|
|
2033
|
-
} : void 0, c = t.column_default === null ? null :
|
|
2076
|
+
onDelete: Wn(i.delete_rule),
|
|
2077
|
+
onUpdate: Wn(i.update_rule)
|
|
2078
|
+
} : void 0, c = t.column_default === null ? null : Gn(t.column_default), l = o.get(`${e}.${t.column_name}`);
|
|
2034
2079
|
return {
|
|
2035
2080
|
name: t.column_name,
|
|
2036
2081
|
type: a,
|
|
@@ -2064,18 +2109,18 @@ var yn = (e) => {
|
|
|
2064
2109
|
});
|
|
2065
2110
|
}
|
|
2066
2111
|
return { tables: u };
|
|
2067
|
-
}),
|
|
2112
|
+
}), Wn = (e) => {
|
|
2068
2113
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2069
2114
|
case "CASCADE": return "cascade";
|
|
2070
2115
|
case "SET NULL": return "setNull";
|
|
2071
2116
|
case "SET DEFAULT": return "noAction";
|
|
2072
2117
|
default: return "noAction";
|
|
2073
2118
|
}
|
|
2074
|
-
},
|
|
2119
|
+
}, Gn = (e) => {
|
|
2075
2120
|
let t = e.trim();
|
|
2076
2121
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2077
2122
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2078
|
-
},
|
|
2123
|
+
}, Kn = /* @__PURE__ */ new Set([
|
|
2079
2124
|
"character varying",
|
|
2080
2125
|
"varchar",
|
|
2081
2126
|
"nvarchar",
|
|
@@ -2083,35 +2128,35 @@ var yn = (e) => {
|
|
|
2083
2128
|
"character",
|
|
2084
2129
|
"nchar"
|
|
2085
2130
|
]), V = (e, t) => {
|
|
2086
|
-
if (!
|
|
2131
|
+
if (!Kn.has(e.toLowerCase())) return;
|
|
2087
2132
|
let n = Number(t);
|
|
2088
2133
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2089
|
-
},
|
|
2090
|
-
mysql: () =>
|
|
2091
|
-
mssql: () =>
|
|
2092
|
-
sqlite: () =>
|
|
2093
|
-
orElse: () =>
|
|
2134
|
+
}, qn = /* @__PURE__ */ new Set([D]), Jn = (e) => e.onDialectOrElse({
|
|
2135
|
+
mysql: () => zn(e),
|
|
2136
|
+
mssql: () => Un(e),
|
|
2137
|
+
sqlite: () => Vn(e),
|
|
2138
|
+
orElse: () => Ln(e)
|
|
2094
2139
|
}).pipe(b.map((e) => ({
|
|
2095
2140
|
...e,
|
|
2096
|
-
tables: e.tables.filter((e) => !
|
|
2141
|
+
tables: e.tables.filter((e) => !qn.has(e.name))
|
|
2097
2142
|
}))), H = (e, t) => e.onDialectOrElse({
|
|
2098
2143
|
mysql: () => b.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2099
2144
|
orElse: () => b.succeed(t)
|
|
2100
|
-
}),
|
|
2145
|
+
}), Yn = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, Xn = (e, t) => {
|
|
2101
2146
|
if (!(e.type === "text" && e.maxLength !== void 0) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2102
2147
|
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;
|
|
2103
2148
|
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.`);
|
|
2104
|
-
return
|
|
2105
|
-
},
|
|
2106
|
-
let t =
|
|
2107
|
-
return t === void 0 ?
|
|
2108
|
-
},
|
|
2149
|
+
return A(e, t);
|
|
2150
|
+
}, Zn = (e) => {
|
|
2151
|
+
let t = Xn(e, "postgres");
|
|
2152
|
+
return t === void 0 ? Qn(e) : t;
|
|
2153
|
+
}, Qn = (e) => {
|
|
2109
2154
|
switch (e.type) {
|
|
2110
2155
|
case "id": return "text";
|
|
2111
2156
|
case "text": return "text";
|
|
2112
2157
|
case "integer": return "integer";
|
|
2113
2158
|
case "real": return "double precision";
|
|
2114
|
-
case "decimal": return
|
|
2159
|
+
case "decimal": return Yn(e, "NUMERIC");
|
|
2115
2160
|
case "bigint": return "bigint";
|
|
2116
2161
|
case "boolean": return "boolean";
|
|
2117
2162
|
case "timestamp": return "timestamptz";
|
|
@@ -2125,15 +2170,15 @@ var yn = (e) => {
|
|
|
2125
2170
|
case "interval": return "interval";
|
|
2126
2171
|
case "raw": return e.rawDdl ?? "text";
|
|
2127
2172
|
}
|
|
2128
|
-
},
|
|
2129
|
-
let t =
|
|
2173
|
+
}, $n = (e) => {
|
|
2174
|
+
let t = Xn(e, "mariadb");
|
|
2130
2175
|
if (t !== void 0) return t;
|
|
2131
2176
|
switch (e.type) {
|
|
2132
2177
|
case "id": return "VARCHAR(64)";
|
|
2133
2178
|
case "text": return e.hasDefault && e.defaultValue !== void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : "LONGTEXT";
|
|
2134
2179
|
case "integer": return "INT";
|
|
2135
2180
|
case "real": return "DOUBLE";
|
|
2136
|
-
case "decimal": return
|
|
2181
|
+
case "decimal": return Yn(e, "DECIMAL");
|
|
2137
2182
|
case "bigint": return "BIGINT";
|
|
2138
2183
|
case "boolean": return "TINYINT(1)";
|
|
2139
2184
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2147,32 +2192,32 @@ var yn = (e) => {
|
|
|
2147
2192
|
case "interval": return "BIGINT";
|
|
2148
2193
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2149
2194
|
}
|
|
2150
|
-
}, U = (e) => `"${e}"`, W = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2195
|
+
}, U = (e) => `"${e}"`, W = (e) => `\`${e.replace(/`/g, "``")}\``, er = (e, t) => `ALTER TABLE ${t(e.table)} DROP COLUMN IF EXISTS ${t(e.column)};`, tr = (e) => `ALTER TABLE ${W(e.table)} DROP COLUMN IF EXISTS ${W(e.column)}, ALGORITHM=COPY;`, nr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, rr = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${Or(t)}`)};`, ir = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${ar(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, ar = (e, t) => {
|
|
2151
2196
|
let n = t(e.defaultValue);
|
|
2152
2197
|
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.`);
|
|
2153
2198
|
return n;
|
|
2154
|
-
}, G = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2199
|
+
}, G = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], or = (e, t, n) => {
|
|
2155
2200
|
let r = G(e, t, n);
|
|
2156
|
-
return r ?
|
|
2157
|
-
},
|
|
2158
|
-
let r = n ?? e.nullable, i =
|
|
2201
|
+
return r ? Ut(n, r) : void 0;
|
|
2202
|
+
}, sr = (e, t, n) => {
|
|
2203
|
+
let r = n ?? e.nullable, i = Ze(e, "mariadb");
|
|
2159
2204
|
return [
|
|
2160
2205
|
W(t),
|
|
2161
|
-
|
|
2206
|
+
A(e, "mariadb"),
|
|
2162
2207
|
r ? null : "NOT NULL",
|
|
2163
2208
|
i
|
|
2164
2209
|
].filter(Boolean).join(" ");
|
|
2165
|
-
},
|
|
2210
|
+
}, cr = (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" ? j(e, "mariadb") : null, lr = (e, t, n) => Qe(e, t ?? { type: "json" }, n), ur = (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" ? j(e, "postgres") : null, K = (e, t) => {
|
|
2166
2211
|
if (!e.generatedAs) return null;
|
|
2167
2212
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2168
2213
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2169
|
-
},
|
|
2170
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2214
|
+
}, dr = (e) => {
|
|
2215
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return M(e.name, "postgres");
|
|
2171
2216
|
let t = K(e, "postgres");
|
|
2172
|
-
if (t) return `${U(e.name)} ${
|
|
2173
|
-
let n = [U(e.name),
|
|
2217
|
+
if (t) return `${U(e.name)} ${Zn(e)} ${t}`;
|
|
2218
|
+
let n = [U(e.name), Zn(e)];
|
|
2174
2219
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2175
|
-
let t =
|
|
2220
|
+
let t = ur(e.defaultValue, e);
|
|
2176
2221
|
t && n.push(t);
|
|
2177
2222
|
}
|
|
2178
2223
|
return e.references && (n.push(`REFERENCES ${U(e.references.table)} (${U(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
@@ -2181,20 +2226,20 @@ var yn = (e) => {
|
|
|
2181
2226
|
setNull: "SET NULL",
|
|
2182
2227
|
noAction: "NO ACTION"
|
|
2183
2228
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2184
|
-
},
|
|
2185
|
-
let t = e.columns.map((e) => ` ${
|
|
2186
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(t.name)} ON ${U(e.table)} (${t.columns.map(
|
|
2229
|
+
}, fr = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", pr = (e) => {
|
|
2230
|
+
let t = e.columns.map((e) => ` ${dr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${U(e.table)} (\n${t}${fr(e, U)}\n)`];
|
|
2231
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(t.name)} ON ${U(e.table)} (${t.columns.map(Nr).join(", ")})`);
|
|
2187
2232
|
return n;
|
|
2188
|
-
},
|
|
2189
|
-
let t =
|
|
2233
|
+
}, mr = 191, hr = (e) => {
|
|
2234
|
+
let t = $n(e).toUpperCase();
|
|
2190
2235
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2191
|
-
},
|
|
2192
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2236
|
+
}, gr = (e) => {
|
|
2237
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return M(e.name, "mariadb");
|
|
2193
2238
|
let t = K(e, "mariadb");
|
|
2194
|
-
if (t) return `${W(e.name)} ${
|
|
2195
|
-
let n = [W(e.name),
|
|
2196
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2197
|
-
let t =
|
|
2239
|
+
if (t) return `${W(e.name)} ${$n(e)} ${t}`;
|
|
2240
|
+
let n = [W(e.name), $n(e)];
|
|
2241
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !hr(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2242
|
+
let t = cr(e.defaultValue, e);
|
|
2198
2243
|
t && n.push(t);
|
|
2199
2244
|
}
|
|
2200
2245
|
return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
@@ -2203,26 +2248,26 @@ var yn = (e) => {
|
|
|
2203
2248
|
setNull: "SET NULL",
|
|
2204
2249
|
noAction: "NO ACTION"
|
|
2205
2250
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2206
|
-
},
|
|
2251
|
+
}, _r = (e) => {
|
|
2207
2252
|
let t = new Map(e.columns.map((e) => [e.name, e])), n = (e) => {
|
|
2208
|
-
let n =
|
|
2253
|
+
let n = jr(t.get(e));
|
|
2209
2254
|
return n === void 0 ? W(e) : `${W(e)}(${n})`;
|
|
2210
|
-
}, r = e.columns.map((e) => ` ${
|
|
2211
|
-
for (let t of e.columns) t.unique && t.type !== "id" &&
|
|
2255
|
+
}, r = e.columns.map((e) => ` ${gr(e)}`).join(",\n"), i = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${r}${fr(e, n)}\n)`];
|
|
2256
|
+
for (let t of e.columns) t.unique && t.type !== "id" && hr(t) && i.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${W(`${e.table}_${t.name}_key`)} ON ${W(e.table)} (${n(t.name)})`);
|
|
2212
2257
|
for (let t of e.indexes) t.name !== `${e.table}_pkey` && i.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(n).join(", ")})`);
|
|
2213
2258
|
return i;
|
|
2214
|
-
},
|
|
2259
|
+
}, vr = {
|
|
2215
2260
|
cascade: "CASCADE",
|
|
2216
2261
|
restrict: "RESTRICT",
|
|
2217
2262
|
setNull: "SET NULL",
|
|
2218
2263
|
noAction: "NO ACTION"
|
|
2219
|
-
},
|
|
2264
|
+
}, yr = {
|
|
2220
2265
|
cascade: "CASCADE",
|
|
2221
2266
|
restrict: "NO ACTION",
|
|
2222
2267
|
setNull: "SET NULL",
|
|
2223
2268
|
noAction: "NO ACTION"
|
|
2224
|
-
},
|
|
2225
|
-
let t =
|
|
2269
|
+
}, br = (e) => {
|
|
2270
|
+
let t = Xn(e, "sqlite");
|
|
2226
2271
|
if (t !== void 0) return t;
|
|
2227
2272
|
switch (e.type) {
|
|
2228
2273
|
case "integer":
|
|
@@ -2233,29 +2278,29 @@ var yn = (e) => {
|
|
|
2233
2278
|
case "bytes": return "BLOB";
|
|
2234
2279
|
default: return "TEXT";
|
|
2235
2280
|
}
|
|
2236
|
-
}, q = (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" ?
|
|
2237
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2281
|
+
}, q = (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" ? j(e, "sqlite") : null, xr = (e) => {
|
|
2282
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return M(e.name, "sqlite");
|
|
2238
2283
|
let t = K(e, "sqlite");
|
|
2239
|
-
if (t) return `${U(e.name)} ${
|
|
2240
|
-
let n = [U(e.name),
|
|
2284
|
+
if (t) return `${U(e.name)} ${br(e)} ${t}`;
|
|
2285
|
+
let n = [U(e.name), br(e)];
|
|
2241
2286
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2242
2287
|
let t = q(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2243
2288
|
t && n.push(t);
|
|
2244
2289
|
}
|
|
2245
|
-
if (e.references && (n.push(`REFERENCES ${U(e.references.table)} (${U(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${
|
|
2290
|
+
if (e.references && (n.push(`REFERENCES ${U(e.references.table)} (${U(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${vr[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2246
2291
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2247
2292
|
n.push(`CHECK (${U(e.name)} IN (${t}))`);
|
|
2248
2293
|
}
|
|
2249
2294
|
return n.join(" ");
|
|
2250
|
-
},
|
|
2251
|
-
let t = e.columns.map((e) => ` ${
|
|
2295
|
+
}, Sr = (e) => {
|
|
2296
|
+
let t = e.columns.map((e) => ` ${xr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${U(e.table)} (\n${t}${fr(e, U)}\n)`];
|
|
2252
2297
|
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(t.name)} ON ${U(e.table)} (${t.columns.map(U).join(", ")})`);
|
|
2253
2298
|
return n;
|
|
2254
2299
|
}, J = (e, t) => {
|
|
2255
2300
|
let n = t.find((t) => t.tableName === e);
|
|
2256
2301
|
if (!n) return [];
|
|
2257
|
-
let r =
|
|
2258
|
-
...
|
|
2302
|
+
let r = F([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => U(e.name)).join(", "), o = [
|
|
2303
|
+
...Sr({
|
|
2259
2304
|
kind: "create-table",
|
|
2260
2305
|
table: i,
|
|
2261
2306
|
columns: r.columns,
|
|
@@ -2268,25 +2313,25 @@ var yn = (e) => {
|
|
|
2268
2313
|
];
|
|
2269
2314
|
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(t.name)} ON ${U(e)} (${t.columns.map(U).join(", ")})`);
|
|
2270
2315
|
return o;
|
|
2271
|
-
},
|
|
2316
|
+
}, Cr = (e, t, n, r) => {
|
|
2272
2317
|
let i = r ?? e.nullable;
|
|
2273
|
-
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${
|
|
2274
|
-
},
|
|
2318
|
+
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${A(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2319
|
+
}, wr = (e) => {
|
|
2275
2320
|
let t = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${Y(e.table)} DROP CONSTRAINT [' + @dc + ']');`;
|
|
2276
2321
|
if (!e.hasDefault) return t;
|
|
2277
2322
|
let n = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2278
2323
|
if (!n) return t;
|
|
2279
2324
|
let r = n.replace(/^DEFAULT\s+/i, "");
|
|
2280
2325
|
return `${t} ALTER TABLE ${Y(e.table)} ADD DEFAULT ${r} FOR ${Y(e.column)};`;
|
|
2281
|
-
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2282
|
-
let t =
|
|
2326
|
+
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`, Tr = (e) => {
|
|
2327
|
+
let t = Xn(e, "mssql");
|
|
2283
2328
|
if (t !== void 0) return t;
|
|
2284
2329
|
switch (e.type) {
|
|
2285
2330
|
case "id":
|
|
2286
2331
|
case "reference": return "NVARCHAR(64)";
|
|
2287
2332
|
case "integer": return "INT";
|
|
2288
2333
|
case "real": return "FLOAT";
|
|
2289
|
-
case "decimal": return
|
|
2334
|
+
case "decimal": return Yn(e, "DECIMAL");
|
|
2290
2335
|
case "bigint": return "BIGINT";
|
|
2291
2336
|
case "boolean": return "BIT";
|
|
2292
2337
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2294,44 +2339,44 @@ var yn = (e) => {
|
|
|
2294
2339
|
case "bytes": return "VARBINARY(MAX)";
|
|
2295
2340
|
default: return "NVARCHAR(MAX)";
|
|
2296
2341
|
}
|
|
2297
|
-
},
|
|
2298
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2299
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2342
|
+
}, Er = (e, t) => {
|
|
2343
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return M(e.name, "mssql");
|
|
2344
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Tr(e), r = K(e, "mssql");
|
|
2300
2345
|
if (r) return `${Y(e.name)} ${r}`;
|
|
2301
2346
|
let i = [Y(e.name), n];
|
|
2302
2347
|
if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
|
|
2303
2348
|
let t = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2304
2349
|
t && i.push(t);
|
|
2305
2350
|
}
|
|
2306
|
-
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2307
|
-
},
|
|
2308
|
-
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${
|
|
2351
|
+
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${yr[e.references.onDelete]}`)), i.join(" ");
|
|
2352
|
+
}, Dr = (e) => {
|
|
2353
|
+
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${Er(e, n)}`).join(",\n"), i = `CREATE TABLE ${Y(e.table)} (\n${r}${fr(e, Y)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2309
2354
|
for (let n of e.indexes) {
|
|
2310
2355
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2311
2356
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Y(n.name)} ON ${Y(e.table)} (${n.columns.map(Y).join(", ")})`;
|
|
2312
2357
|
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)}')`);
|
|
2313
2358
|
}
|
|
2314
2359
|
return a;
|
|
2315
|
-
},
|
|
2316
|
-
let r = `${e.table}${
|
|
2360
|
+
}, Or = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, kr = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Ar = (e, t, n) => {
|
|
2361
|
+
let r = `${e.table}${Or(t)}`;
|
|
2317
2362
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2318
|
-
},
|
|
2319
|
-
if (e === void 0 || !
|
|
2363
|
+
}, jr = (e) => {
|
|
2364
|
+
if (e === void 0 || !hr(e)) return;
|
|
2320
2365
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2321
|
-
return t === void 0 ?
|
|
2322
|
-
},
|
|
2323
|
-
let r =
|
|
2366
|
+
return t === void 0 ? mr : Math.min(mr, t);
|
|
2367
|
+
}, Mr = (e, t, n) => {
|
|
2368
|
+
let r = jr(or(e, t, n));
|
|
2324
2369
|
return r === void 0 ? W(n) : `${W(n)}(${r})`;
|
|
2325
|
-
},
|
|
2370
|
+
}, Nr = (e) => e.startsWith("(") ? e : U(e), Pr = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${U(e.index.name)} ON ${U(e.table)} (${e.index.columns.map(Nr).join(", ")});`, Fr = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)} (${e.index.columns.map((n) => Mr(t, e.table, n)).join(", ")});`, Ir = (e) => `DROP INDEX IF EXISTS ${U(e.index)};`, Lr = (e) => `DROP INDEX ${W(e.index)} ON ${W(e.table)};`, Rr = (e) => `DROP INDEX IF EXISTS ${Y(e.index)} ON ${Y(e.table)};`, zr = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, Br = (e) => {
|
|
2326
2371
|
let t = (e) => e.replace(/'/g, "''");
|
|
2327
2372
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2328
|
-
},
|
|
2373
|
+
}, Vr = (e) => `ALTER INDEX ${U(e.from)} RENAME TO ${U(e.to)};`, Hr = (e) => `ALTER TABLE ${W(e.table)} RENAME INDEX ${W(e.from)} TO ${W(e.to)};`, Ur = (e) => {
|
|
2329
2374
|
let t = (e) => e.replace(/'/g, "''");
|
|
2330
2375
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2331
|
-
},
|
|
2376
|
+
}, Wr = (e) => {
|
|
2332
2377
|
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Y(e.index.name)} ON ${Y(e.table)} (${e.index.columns.map(Y).join(", ")})`;
|
|
2333
2378
|
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)}');`;
|
|
2334
|
-
},
|
|
2379
|
+
}, Gr = (e, t, n) => {
|
|
2335
2380
|
let r = n.find((t) => t.tableName === e);
|
|
2336
2381
|
if (!r) return [];
|
|
2337
2382
|
let i = [];
|
|
@@ -2340,13 +2385,13 @@ var yn = (e) => {
|
|
|
2340
2385
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Y(e)} ALTER COLUMN ${Y(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2341
2386
|
}
|
|
2342
2387
|
return i;
|
|
2343
|
-
},
|
|
2388
|
+
}, Kr = (e) => `ALTER TABLE ${U(e.table)} ADD CONSTRAINT ${U(`${e.table}_${e.column}_key`)} UNIQUE (${U(e.column)});`, qr = (e, t) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${Mr(t, e.table, e.column)});`, Jr = (e) => {
|
|
2344
2389
|
let t = e.fields.map((e) => U(e)).join(", ");
|
|
2345
2390
|
return `ALTER TABLE ${U(e.table)} ADD CONSTRAINT ${U(e.name)} UNIQUE (${t});`;
|
|
2346
|
-
},
|
|
2347
|
-
let n = e.fields.map((n) =>
|
|
2391
|
+
}, Yr = (e, t) => {
|
|
2392
|
+
let n = e.fields.map((n) => Mr(t, e.table, n)).join(", ");
|
|
2348
2393
|
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${n});`;
|
|
2349
|
-
},
|
|
2394
|
+
}, Xr = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(e.name)};`, Zr = (e) => `ALTER TABLE ${W(e.table)} DROP INDEX ${W(e.name)};`, Qr = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(`${e.table}_${e.column}_key`)};`, $r = (e) => `ALTER TABLE ${W(e.table)} DROP INDEX ${W(`${e.table}_${e.column}_key`)};`, ei = (e, t) => {
|
|
2350
2395
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2351
2396
|
if (e.orphanPolicy) {
|
|
2352
2397
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2364,11 +2409,11 @@ var yn = (e) => {
|
|
|
2364
2409
|
setNull: "SET NULL",
|
|
2365
2410
|
noAction: "NO ACTION"
|
|
2366
2411
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2367
|
-
},
|
|
2412
|
+
}, ti = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(`${e.table}_${e.column}_fkey`)};`, ni = (e) => `ALTER TABLE ${W(e.table)} DROP FOREIGN KEY ${W(`${e.table}_${e.column}_fkey`)};`, ri = (e, t) => {
|
|
2368
2413
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2369
2414
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2370
|
-
},
|
|
2371
|
-
let i = e.column, a = r === "mariadb", o = a ? W : r === "mssql" ? Y : U, s = a ?
|
|
2415
|
+
}, ii = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(`${e.table}_${e.column}_check`)};`, ai = (e) => `ALTER TABLE ${W(e.table)} DROP CHECK ${W(`${e.table}_${e.column}_check`)};`, oi = (e, t, n, r) => {
|
|
2416
|
+
let i = e.column, a = r === "mariadb", o = a ? W : r === "mssql" ? Y : U, s = a ? $n(i) : r === "mssql" ? Tr(i) : r === "sqlite" ? br(i) : Zn(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? cr(e, i) : r === "mssql" ? q(e, "SYSUTCDATETIME()") : r === "sqlite" ? q(e, "CURRENT_TIMESTAMP") : ur(e, i), u = K(i, r);
|
|
2372
2417
|
if (u) {
|
|
2373
2418
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2374
2419
|
return {
|
|
@@ -2396,7 +2441,7 @@ var yn = (e) => {
|
|
|
2396
2441
|
post: f ? [f] : []
|
|
2397
2442
|
};
|
|
2398
2443
|
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;
|
|
2399
|
-
},
|
|
2444
|
+
}, si = (e) => {
|
|
2400
2445
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2401
2446
|
return (e, n) => {
|
|
2402
2447
|
let r = t.get(e);
|
|
@@ -2417,46 +2462,46 @@ var yn = (e) => {
|
|
|
2417
2462
|
};
|
|
2418
2463
|
};
|
|
2419
2464
|
}, X = (e, t, n) => e.unsafe(t).pipe(b.tapError((e) => b.sync(() => {
|
|
2420
|
-
process.stderr.write(
|
|
2465
|
+
process.stderr.write(ie(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2421
2466
|
})), b.mapError((e) => {
|
|
2422
|
-
let r =
|
|
2467
|
+
let r = ie(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2423
2468
|
return Object.assign(e, { message: r });
|
|
2424
|
-
}), b.map(() => void 0)), Z = (e, t, n) => b.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 ? "*" : i(r, t)} FROM ${i(n, t)} WHERE 1=0`).pipe(b.as(!0), b.catchAll(() => b.succeed(!1))),
|
|
2425
|
-
let n =
|
|
2469
|
+
}), b.map(() => void 0)), Z = (e, t, n) => b.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 ? "*" : i(r, t)} FROM ${i(n, t)} WHERE 1=0`).pipe(b.as(!0), b.catchAll(() => b.succeed(!1))), ci = (e, t) => b.gen(function* () {
|
|
2470
|
+
let n = F([Fe], t).tables[0];
|
|
2426
2471
|
if (!n) return yield* b.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2427
2472
|
let r = {
|
|
2428
2473
|
kind: "create-table",
|
|
2429
|
-
table:
|
|
2474
|
+
table: D,
|
|
2430
2475
|
columns: n.columns,
|
|
2431
2476
|
indexes: []
|
|
2432
2477
|
}, i = yield* e.onDialectOrElse({
|
|
2433
|
-
mysql: () => b.succeed(
|
|
2434
|
-
mssql: () => b.succeed(
|
|
2435
|
-
sqlite: () => b.succeed(
|
|
2436
|
-
orElse: () => b.succeed(
|
|
2478
|
+
mysql: () => b.succeed(_r(r)),
|
|
2479
|
+
mssql: () => b.succeed(Dr(r)),
|
|
2480
|
+
sqlite: () => b.succeed(Sr(r)),
|
|
2481
|
+
orElse: () => b.succeed(pr(r))
|
|
2437
2482
|
});
|
|
2438
2483
|
yield* b.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2439
|
-
}),
|
|
2484
|
+
}), li = (e) => e`
|
|
2440
2485
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2441
2486
|
${e("status")}, ${e("payload")}
|
|
2442
|
-
FROM ${e(
|
|
2443
|
-
`,
|
|
2487
|
+
FROM ${e(D)}
|
|
2488
|
+
`, ui = (e, t, n, r) => b.gen(function* () {
|
|
2444
2489
|
let i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2445
2490
|
yield* b.forEach(r, ({ index: r, planned: a }) => e`
|
|
2446
|
-
INSERT INTO ${e(
|
|
2491
|
+
INSERT INTO ${e(D)}
|
|
2447
2492
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2448
2493
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2449
2494
|
${e("createdAt")})
|
|
2450
2495
|
VALUES
|
|
2451
2496
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2452
|
-
${a.op.kind}, ${
|
|
2497
|
+
${a.op.kind}, ${Le(a.op)}, ${"pending"},
|
|
2453
2498
|
${JSON.stringify(a)}, ${i})
|
|
2454
2499
|
`, { discard: !0 });
|
|
2455
|
-
}),
|
|
2500
|
+
}), di = (e, t, n, r, i) => b.gen(function* () {
|
|
2456
2501
|
let a = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2457
2502
|
if (r === "applied") {
|
|
2458
2503
|
yield* e`
|
|
2459
|
-
UPDATE ${e(
|
|
2504
|
+
UPDATE ${e(D)}
|
|
2460
2505
|
SET ${e("status")} = ${r}, ${e("appliedAt")} = ${a},
|
|
2461
2506
|
${e("durationMs")} = ${i ?? null}
|
|
2462
2507
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
@@ -2464,47 +2509,47 @@ var yn = (e) => {
|
|
|
2464
2509
|
return;
|
|
2465
2510
|
}
|
|
2466
2511
|
yield* e`
|
|
2467
|
-
UPDATE ${e(
|
|
2512
|
+
UPDATE ${e(D)}
|
|
2468
2513
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2469
2514
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2470
2515
|
`;
|
|
2471
|
-
}),
|
|
2516
|
+
}), fi = (e, t, n, r) => b.gen(function* () {
|
|
2472
2517
|
let i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2473
2518
|
r.length > 0 && (yield* e`
|
|
2474
|
-
UPDATE ${e(
|
|
2519
|
+
UPDATE ${e(D)}
|
|
2475
2520
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
2476
2521
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(r)}
|
|
2477
2522
|
`), n.length > 0 && (yield* e`
|
|
2478
|
-
UPDATE ${e(
|
|
2523
|
+
UPDATE ${e(D)}
|
|
2479
2524
|
SET ${e("status")} = ${"pending"}
|
|
2480
2525
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2481
2526
|
`);
|
|
2482
|
-
}),
|
|
2483
|
-
if (
|
|
2527
|
+
}), pi = (e, t) => t === void 0 ? e`DELETE FROM ${e(D)}`.pipe(b.asVoid) : e`DELETE FROM ${e(D)} WHERE ${e("runId")} = ${t}`.pipe(b.asVoid), mi = (e, t, n) => b.gen(function* () {
|
|
2528
|
+
if (Ge(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
2484
2529
|
let r = n.op, a = (e) => i(e, t);
|
|
2485
2530
|
if (t === "sqlite" || t === "turso") {
|
|
2486
2531
|
if (!("table" in r)) return "clean";
|
|
2487
|
-
let n = `${r.table}${
|
|
2532
|
+
let n = `${r.table}${Be}`;
|
|
2488
2533
|
return (yield* $(e, t, n)) ? ((yield* $(e, t, r.table)) ? yield* X(e, `DROP TABLE ${a(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${a(n)} RENAME TO ${a(r.table)}`, "resume-repair"), yield* b.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(b.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
2489
2534
|
}
|
|
2490
2535
|
if (r.kind !== "alter-column-type") return "clean";
|
|
2491
|
-
let o = `${r.column}${
|
|
2536
|
+
let o = `${r.column}${Ve}`, s = `${r.column}${He}`, c = yield* $(e, t, r.table, r.column), l = yield* $(e, t, r.table, o), u = yield* $(e, t, r.table, s), d = (e) => b.logWarning(`migration resume: ${e}`).pipe(b.annotateLogs({ scope: "voltro:migrate" }));
|
|
2492
2537
|
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(o)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${r.table}.${o}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* X(e, `ALTER TABLE ${a(r.table)} RENAME COLUMN ${a(o)} TO ${a(r.column)}`, "resume-repair"), yield* X(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : c && !l && u ? (yield* X(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${r.table}.${s}'`), "applied") : yield* b.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}, ${o}=${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.`));
|
|
2493
|
-
}),
|
|
2494
|
-
let i = process.hrtime.bigint(), a =
|
|
2538
|
+
}), hi = (e, t, n, r = "fresh") => b.gen(function* () {
|
|
2539
|
+
let i = process.hrtime.bigint(), a = si(n.declared), o = t.op;
|
|
2495
2540
|
switch (o.kind) {
|
|
2496
2541
|
case "create-table": {
|
|
2497
2542
|
let t = yield* e.onDialectOrElse({
|
|
2498
|
-
mysql: () => b.succeed(
|
|
2499
|
-
mssql: () => b.succeed(
|
|
2500
|
-
sqlite: () => b.succeed(
|
|
2501
|
-
orElse: () => b.succeed(
|
|
2543
|
+
mysql: () => b.succeed(_r(o)),
|
|
2544
|
+
mssql: () => b.succeed(Dr(o)),
|
|
2545
|
+
sqlite: () => b.succeed(Sr(o)),
|
|
2546
|
+
orElse: () => b.succeed(pr(o))
|
|
2502
2547
|
});
|
|
2503
2548
|
for (let n of t) yield* X(e, n, o.kind);
|
|
2504
2549
|
break;
|
|
2505
2550
|
}
|
|
2506
2551
|
case "drop-table": {
|
|
2507
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2552
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Ar(o, n, e) : kr(o, e);
|
|
2508
2553
|
yield* e.onDialectOrElse({
|
|
2509
2554
|
mysql: () => X(e, r(W), o.kind),
|
|
2510
2555
|
orElse: () => X(e, r(U), o.kind)
|
|
@@ -2514,91 +2559,91 @@ var yn = (e) => {
|
|
|
2514
2559
|
case "drop-column": {
|
|
2515
2560
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2516
2561
|
yield* e.onDialectOrElse({
|
|
2517
|
-
mysql: () => X(e, t ?
|
|
2518
|
-
orElse: () => X(e, t ?
|
|
2562
|
+
mysql: () => X(e, t ? rr(o, n, W) : tr(o), o.kind),
|
|
2563
|
+
orElse: () => X(e, t ? rr(o, n, U) : er(o, U), o.kind)
|
|
2519
2564
|
});
|
|
2520
2565
|
break;
|
|
2521
2566
|
}
|
|
2522
2567
|
case "rename-column":
|
|
2523
2568
|
yield* e.onDialectOrElse({
|
|
2524
|
-
mysql: () => X(e,
|
|
2569
|
+
mysql: () => X(e, nr(o, W), o.kind),
|
|
2525
2570
|
mssql: () => X(e, `EXEC sp_rename N'${o.table.replace(/'/g, "''")}.${o.from.replace(/'/g, "''")}', N'${o.to.replace(/'/g, "''")}', 'COLUMN';`, o.kind),
|
|
2526
|
-
orElse: () => X(e,
|
|
2571
|
+
orElse: () => X(e, nr(o, U), o.kind)
|
|
2527
2572
|
});
|
|
2528
2573
|
break;
|
|
2529
2574
|
case "add-index":
|
|
2530
2575
|
yield* e.onDialectOrElse({
|
|
2531
|
-
mysql: () => X(e,
|
|
2532
|
-
mssql: () => Z(e, [...
|
|
2533
|
-
orElse: () => X(e,
|
|
2576
|
+
mysql: () => X(e, Fr(o, n.declared), o.kind),
|
|
2577
|
+
mssql: () => Z(e, [...Gr(o.table, o.index.columns, n.declared), Wr(o)], o.kind),
|
|
2578
|
+
orElse: () => X(e, Pr(o, t.classification === "online-required"), o.kind)
|
|
2534
2579
|
});
|
|
2535
2580
|
break;
|
|
2536
2581
|
case "drop-index":
|
|
2537
2582
|
yield* e.onDialectOrElse({
|
|
2538
|
-
mysql: () => X(e,
|
|
2539
|
-
mssql: () => X(e,
|
|
2540
|
-
orElse: () => X(e,
|
|
2583
|
+
mysql: () => X(e, Lr(o), o.kind),
|
|
2584
|
+
mssql: () => X(e, Rr(o), o.kind),
|
|
2585
|
+
orElse: () => X(e, Ir(o), o.kind)
|
|
2541
2586
|
});
|
|
2542
2587
|
break;
|
|
2543
2588
|
case "rename-table":
|
|
2544
2589
|
yield* e.onDialectOrElse({
|
|
2545
|
-
mysql: () => X(e,
|
|
2546
|
-
mssql: () => X(e,
|
|
2547
|
-
orElse: () => X(e,
|
|
2590
|
+
mysql: () => X(e, zr(o, W), o.kind),
|
|
2591
|
+
mssql: () => X(e, Br(o), o.kind),
|
|
2592
|
+
orElse: () => X(e, zr(o, U), o.kind)
|
|
2548
2593
|
});
|
|
2549
2594
|
break;
|
|
2550
2595
|
case "rename-index":
|
|
2551
2596
|
yield* e.onDialectOrElse({
|
|
2552
|
-
mysql: () => X(e,
|
|
2553
|
-
mssql: () => X(e,
|
|
2554
|
-
orElse: () => X(e,
|
|
2597
|
+
mysql: () => X(e, Hr(o), o.kind),
|
|
2598
|
+
mssql: () => X(e, Ur(o), o.kind),
|
|
2599
|
+
orElse: () => X(e, Vr(o), o.kind)
|
|
2555
2600
|
});
|
|
2556
2601
|
break;
|
|
2557
2602
|
case "add-unique":
|
|
2558
2603
|
yield* e.onDialectOrElse({
|
|
2559
|
-
mysql: () => X(e,
|
|
2604
|
+
mysql: () => X(e, qr(o, n.declared), o.kind),
|
|
2560
2605
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2561
|
-
mssql: () => Z(e, [...
|
|
2562
|
-
orElse: () => X(e,
|
|
2606
|
+
mssql: () => Z(e, [...Gr(o.table, [o.column], n.declared), Kr(o)], o.kind),
|
|
2607
|
+
orElse: () => X(e, Kr(o), o.kind)
|
|
2563
2608
|
});
|
|
2564
2609
|
break;
|
|
2565
2610
|
case "drop-unique":
|
|
2566
2611
|
yield* e.onDialectOrElse({
|
|
2567
|
-
mysql: () => X(e,
|
|
2612
|
+
mysql: () => X(e, $r(o), o.kind),
|
|
2568
2613
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2569
|
-
orElse: () => X(e,
|
|
2614
|
+
orElse: () => X(e, Qr(o), o.kind)
|
|
2570
2615
|
});
|
|
2571
2616
|
break;
|
|
2572
2617
|
case "add-unique-composite":
|
|
2573
2618
|
yield* e.onDialectOrElse({
|
|
2574
|
-
mysql: () => X(e,
|
|
2619
|
+
mysql: () => X(e, Yr(o, n.declared), o.kind),
|
|
2575
2620
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2576
|
-
mssql: () => Z(e, [...
|
|
2577
|
-
orElse: () => X(e,
|
|
2621
|
+
mssql: () => Z(e, [...Gr(o.table, o.fields, n.declared), Jr(o)], o.kind),
|
|
2622
|
+
orElse: () => X(e, Jr(o), o.kind)
|
|
2578
2623
|
});
|
|
2579
2624
|
break;
|
|
2580
2625
|
case "drop-unique-composite":
|
|
2581
2626
|
yield* e.onDialectOrElse({
|
|
2582
|
-
mysql: () => X(e,
|
|
2627
|
+
mysql: () => X(e, Zr(o), o.kind),
|
|
2583
2628
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2584
|
-
orElse: () => X(e,
|
|
2629
|
+
orElse: () => X(e, Xr(o), o.kind)
|
|
2585
2630
|
});
|
|
2586
2631
|
break;
|
|
2587
2632
|
case "add-foreign-key":
|
|
2588
2633
|
yield* e.onDialectOrElse({
|
|
2589
|
-
mysql: () => Z(e,
|
|
2634
|
+
mysql: () => Z(e, ei(o, W), o.kind),
|
|
2590
2635
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2591
|
-
orElse: () => Z(e,
|
|
2636
|
+
orElse: () => Z(e, ei(o, U), o.kind)
|
|
2592
2637
|
});
|
|
2593
2638
|
break;
|
|
2594
2639
|
case "add-column": {
|
|
2595
|
-
let n =
|
|
2640
|
+
let n = oi(o, t, a, yield* e.onDialectOrElse({
|
|
2596
2641
|
mysql: () => b.succeed("mariadb"),
|
|
2597
2642
|
mssql: () => b.succeed("mssql"),
|
|
2598
2643
|
sqlite: () => b.succeed("sqlite"),
|
|
2599
2644
|
orElse: () => b.succeed("postgres")
|
|
2600
2645
|
}));
|
|
2601
|
-
if (!(r === "resume" && (yield* $(e,
|
|
2646
|
+
if (!(r === "resume" && (yield* $(e, Me(e), o.table, o.column.name)))) for (let t of n.pre) yield* X(e, t, o.kind);
|
|
2602
2647
|
if (n.backfillKind === "sql" && n.backfillSql) if (!(t.classification === "online-required" || n.batchSize !== void 0)) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2603
2648
|
else {
|
|
2604
2649
|
let t = n.batchSize ?? 5e3, r = n.sleepMs ?? 0, i, a = 0;
|
|
@@ -2638,37 +2683,37 @@ var yn = (e) => {
|
|
|
2638
2683
|
yield* e.onDialectOrElse({
|
|
2639
2684
|
mysql: () => {
|
|
2640
2685
|
let t = G(n.declared, o.table, o.column);
|
|
2641
|
-
return t ? X(e, `ALTER TABLE ${W(o.table)} MODIFY COLUMN ${
|
|
2686
|
+
return t ? X(e, `ALTER TABLE ${W(o.table)} MODIFY COLUMN ${sr(t, o.column, o.toNullable)};`, o.kind) : b.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.`));
|
|
2642
2687
|
},
|
|
2643
2688
|
mssql: () => {
|
|
2644
2689
|
let t = G(n.declared, o.table, o.column);
|
|
2645
|
-
return t ? X(e,
|
|
2690
|
+
return t ? X(e, Cr(t, o.column, o.table, o.toNullable), o.kind) : b.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2646
2691
|
},
|
|
2647
2692
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2648
2693
|
orElse: () => X(e, `ALTER TABLE ${U(o.table)} ALTER COLUMN ${U(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2649
2694
|
});
|
|
2650
2695
|
break;
|
|
2651
2696
|
case "alter-column-default": {
|
|
2652
|
-
let t =
|
|
2697
|
+
let t = or(n.declared, o.table, o.column);
|
|
2653
2698
|
yield* e.onDialectOrElse({
|
|
2654
|
-
mysql: () => X(e,
|
|
2655
|
-
mssql: () => X(e,
|
|
2699
|
+
mysql: () => X(e, ir(o, W, (e) => cr(e, t)), o.kind),
|
|
2700
|
+
mssql: () => X(e, wr(o), o.kind),
|
|
2656
2701
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2657
|
-
orElse: () => X(e,
|
|
2702
|
+
orElse: () => X(e, ir(o, U, (e) => ur(e, t)), o.kind)
|
|
2658
2703
|
});
|
|
2659
2704
|
break;
|
|
2660
2705
|
}
|
|
2661
2706
|
case "alter-column-type": {
|
|
2662
|
-
let r =
|
|
2707
|
+
let r = Zn(or(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2663
2708
|
if (t.classification !== "online-required") {
|
|
2664
2709
|
yield* e.onDialectOrElse({
|
|
2665
2710
|
mysql: () => {
|
|
2666
2711
|
let t = G(n.declared, o.table, o.column);
|
|
2667
|
-
return t ? X(e, `ALTER TABLE ${W(o.table)} MODIFY COLUMN ${
|
|
2712
|
+
return t ? X(e, `ALTER TABLE ${W(o.table)} MODIFY COLUMN ${sr(t, o.column)};`, o.kind) : b.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.`));
|
|
2668
2713
|
},
|
|
2669
2714
|
mssql: () => {
|
|
2670
2715
|
let t = G(n.declared, o.table, o.column);
|
|
2671
|
-
return t ? X(e,
|
|
2716
|
+
return t ? X(e, Cr(t, o.column, o.table), o.kind) : b.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2672
2717
|
},
|
|
2673
2718
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2674
2719
|
orElse: () => X(e, `ALTER TABLE ${U(o.table)} ALTER COLUMN ${U(o.column)} TYPE ${r}${i};`, o.kind)
|
|
@@ -2692,23 +2737,23 @@ var yn = (e) => {
|
|
|
2692
2737
|
}
|
|
2693
2738
|
case "drop-foreign-key":
|
|
2694
2739
|
yield* e.onDialectOrElse({
|
|
2695
|
-
mysql: () => X(e,
|
|
2740
|
+
mysql: () => X(e, ni(o), o.kind),
|
|
2696
2741
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2697
|
-
orElse: () => X(e,
|
|
2742
|
+
orElse: () => X(e, ti(o), o.kind)
|
|
2698
2743
|
});
|
|
2699
2744
|
break;
|
|
2700
2745
|
case "add-check":
|
|
2701
2746
|
yield* e.onDialectOrElse({
|
|
2702
|
-
mysql: () => X(e,
|
|
2747
|
+
mysql: () => X(e, ri(o, W), o.kind),
|
|
2703
2748
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2704
|
-
orElse: () => X(e,
|
|
2749
|
+
orElse: () => X(e, ri(o, U), o.kind)
|
|
2705
2750
|
});
|
|
2706
2751
|
break;
|
|
2707
2752
|
case "drop-check":
|
|
2708
2753
|
yield* e.onDialectOrElse({
|
|
2709
|
-
mysql: () => X(e,
|
|
2754
|
+
mysql: () => X(e, ai(o), o.kind),
|
|
2710
2755
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2711
|
-
orElse: () => X(e,
|
|
2756
|
+
orElse: () => X(e, ii(o), o.kind)
|
|
2712
2757
|
});
|
|
2713
2758
|
break;
|
|
2714
2759
|
}
|
|
@@ -2717,32 +2762,32 @@ var yn = (e) => {
|
|
|
2717
2762
|
status: "applied",
|
|
2718
2763
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2719
2764
|
};
|
|
2720
|
-
}),
|
|
2765
|
+
}), gi = (e, t, n, r) => b.gen(function* () {
|
|
2721
2766
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2722
|
-
if (i.length > 1) return yield* b.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 \`${
|
|
2767
|
+
if (i.length > 1) return yield* b.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 \`${D}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
2723
2768
|
let a = i[0], o = [...r].map((e) => ({
|
|
2724
2769
|
index: Number(e.opIndex),
|
|
2725
2770
|
status: e.status,
|
|
2726
2771
|
planned: JSON.parse(e.payload)
|
|
2727
2772
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
2728
|
-
if (c > 1) return yield* b.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 \`${
|
|
2729
|
-
if (yield* b.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} ${
|
|
2773
|
+
if (c > 1) return yield* b.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 \`${D}\` by hand before re-running.`));
|
|
2774
|
+
if (yield* b.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} ${Le(s.planned.op)}` : ""}`).pipe(b.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
2730
2775
|
kind: "discard",
|
|
2731
2776
|
runId: a,
|
|
2732
2777
|
why: "no operation had started — no DDL ran"
|
|
2733
2778
|
};
|
|
2734
|
-
let l = s ? yield*
|
|
2779
|
+
let l = s ? yield* mi(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2735
2780
|
if (u !== n.toFingerprint) return {
|
|
2736
2781
|
kind: "discard",
|
|
2737
2782
|
runId: a,
|
|
2738
2783
|
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`
|
|
2739
2784
|
};
|
|
2740
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
2785
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : ze(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
2741
2786
|
return f.length === 0 ? {
|
|
2742
2787
|
kind: "discard",
|
|
2743
2788
|
runId: a,
|
|
2744
2789
|
why: "every recorded operation had already taken effect"
|
|
2745
|
-
} : (yield*
|
|
2790
|
+
} : (yield* fi(e, a, f.map((e) => e.index), p.map((e) => e.index)), yield* b.logWarning(`migration resume: continuing run ${a} — replaying ${f.length} operation(s), ${o.length - f.length} already applied`).pipe(b.annotateLogs({ scope: "voltro:migrate" })), {
|
|
2746
2791
|
kind: "resume",
|
|
2747
2792
|
runId: a,
|
|
2748
2793
|
ops: f.map((e) => ({
|
|
@@ -2750,32 +2795,32 @@ var yn = (e) => {
|
|
|
2750
2795
|
planned: e.planned
|
|
2751
2796
|
}))
|
|
2752
2797
|
});
|
|
2753
|
-
}),
|
|
2798
|
+
}), _i = (e, t, n) => b.gen(function* () {
|
|
2754
2799
|
let r = t.operations.filter((e) => e.blocked);
|
|
2755
2800
|
if (r.length > 0) return yield* b.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
2756
|
-
yield* T(e);
|
|
2757
|
-
let i = Date.now(), a = [], o =
|
|
2801
|
+
yield* T(e, { schema: n.lockSchema });
|
|
2802
|
+
let i = Date.now(), a = [], o = Me(e), s = Pe(o) === "plan-transactional", l = s ? t.operations.filter((e) => e.classification !== "online-required") : [], u = s ? t.operations.filter((e) => e.classification === "online-required") : t.operations, d = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, f = u.map((e, t) => ({
|
|
2758
2803
|
index: t,
|
|
2759
2804
|
planned: e
|
|
2760
2805
|
})), p = "fresh";
|
|
2761
2806
|
try {
|
|
2762
|
-
yield*
|
|
2763
|
-
let r = yield*
|
|
2807
|
+
yield* ci(e, o);
|
|
2808
|
+
let r = yield* li(e);
|
|
2764
2809
|
if (r.length > 0) {
|
|
2765
|
-
let n = yield*
|
|
2766
|
-
n.kind === "resume" ? (d = n.runId, f = n.ops, p = "resume") : (yield* b.logWarning(`migration resume: discarding the ledger of run ${n.runId} — ${n.why}`).pipe(b.annotateLogs({ scope: "voltro:migrate" })), yield*
|
|
2810
|
+
let n = yield* gi(e, o, t, r);
|
|
2811
|
+
n.kind === "resume" ? (d = n.runId, f = n.ops, p = "resume") : (yield* b.logWarning(`migration resume: discarding the ledger of run ${n.runId} — ${n.why}`).pipe(b.annotateLogs({ scope: "voltro:migrate" })), yield* pi(e, n.runId));
|
|
2767
2812
|
}
|
|
2768
|
-
p === "fresh" && f.length > 0 && (yield*
|
|
2769
|
-
let e = yield*
|
|
2770
|
-
for (let t of l) a.push(yield*
|
|
2813
|
+
p === "fresh" && f.length > 0 && (yield* ui(e, d, t.toFingerprint, f)), l.length > 0 && (yield* e.withTransaction(b.gen(function* () {
|
|
2814
|
+
let e = yield* C.SqlClient;
|
|
2815
|
+
for (let t of l) a.push(yield* hi(e, t, n));
|
|
2771
2816
|
})));
|
|
2772
2817
|
for (let { index: t, planned: r } of f) {
|
|
2773
|
-
yield*
|
|
2774
|
-
let i = yield*
|
|
2775
|
-
a.push(i), yield*
|
|
2818
|
+
yield* di(e, d, t, "started");
|
|
2819
|
+
let i = yield* hi(e, r, n, p);
|
|
2820
|
+
a.push(i), yield* di(e, d, t, "applied", i.durationMs);
|
|
2776
2821
|
}
|
|
2777
2822
|
} finally {
|
|
2778
|
-
yield* E(e).pipe(b.orDie);
|
|
2823
|
+
yield* E(e, { schema: n.lockSchema }).pipe(b.orDie);
|
|
2779
2824
|
}
|
|
2780
2825
|
let m = yield* n.replan(e);
|
|
2781
2826
|
if (m.operations.length > 0) {
|
|
@@ -2792,9 +2837,9 @@ var yn = (e) => {
|
|
|
2792
2837
|
(${_}, ${t.toFingerprint}, ${m.fromFingerprint}, ${JSON.stringify(x)},
|
|
2793
2838
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2794
2839
|
${g}, ${y}, ${n.notes ?? null})
|
|
2795
|
-
`, yield*
|
|
2796
|
-
let
|
|
2797
|
-
return yield* b.promise(() => c({ changedTables:
|
|
2840
|
+
`, yield* pi(e, d);
|
|
2841
|
+
let S = [...new Set(x.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
2842
|
+
return yield* b.promise(() => c({ changedTables: S }).catch(() => {})), {
|
|
2798
2843
|
id: _,
|
|
2799
2844
|
appliedAt: v,
|
|
2800
2845
|
fingerprint: t.toFingerprint,
|
|
@@ -2806,13 +2851,13 @@ var yn = (e) => {
|
|
|
2806
2851
|
source: n.source,
|
|
2807
2852
|
...n.notes ? { notes: n.notes } : {}
|
|
2808
2853
|
};
|
|
2809
|
-
}),
|
|
2854
|
+
}), vi = (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"), yi = (e) => e`
|
|
2810
2855
|
SELECT fingerprint
|
|
2811
2856
|
FROM _voltro_migration_plans
|
|
2812
2857
|
ORDER BY ${e("appliedAt")} DESC
|
|
2813
2858
|
LIMIT 1
|
|
2814
|
-
`.pipe(b.map((e) => e.length > 0 ? e[0].fingerprint : void 0), b.catchAll(() => b.succeed(void 0))),
|
|
2815
|
-
if ((yield*
|
|
2859
|
+
`.pipe(b.map((e) => e.length > 0 ? e[0].fingerprint : void 0), b.catchAll(() => b.succeed(void 0))), bi = (e, t, n) => b.gen(function* () {
|
|
2860
|
+
if ((yield* yi(e)) === t.toFingerprint) return "already-current";
|
|
2816
2861
|
let r = `plan_${Date.now().toString(36)}`, i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2817
2862
|
return yield* e`
|
|
2818
2863
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -2824,8 +2869,8 @@ var yn = (e) => {
|
|
|
2824
2869
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2825
2870
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
2826
2871
|
`, "recorded";
|
|
2827
|
-
}).pipe(b.catchAll(() => b.succeed("already-current"))),
|
|
2828
|
-
let n =
|
|
2872
|
+
}).pipe(b.catchAll(() => b.succeed("already-current"))), xi = (e, t) => b.gen(function* () {
|
|
2873
|
+
let n = N(F(t, Me(e))), r = yield* yi(e);
|
|
2829
2874
|
return r === n ? {
|
|
2830
2875
|
kind: "up-to-date",
|
|
2831
2876
|
fingerprint: n
|
|
@@ -2834,23 +2879,23 @@ var yn = (e) => {
|
|
|
2834
2879
|
expected: n,
|
|
2835
2880
|
...r === void 0 ? {} : { actual: r }
|
|
2836
2881
|
};
|
|
2837
|
-
}),
|
|
2882
|
+
}), Si = [
|
|
2838
2883
|
"pgeagertest_",
|
|
2839
2884
|
"mig_e2e_",
|
|
2840
2885
|
"mig_test_",
|
|
2841
2886
|
"mysqleagertest_",
|
|
2842
2887
|
"mssqleagertest_",
|
|
2843
2888
|
"sqliteeagertest_"
|
|
2844
|
-
],
|
|
2889
|
+
], Ci = (e) => Si.some((t) => e.startsWith(t)), wi = (e, t) => b.gen(function* () {
|
|
2845
2890
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
2846
|
-
let n = t.filter((e) =>
|
|
2891
|
+
let n = t.filter((e) => Ci(e.name)).map((e) => e.name);
|
|
2847
2892
|
if (n.length === 0) return [];
|
|
2848
2893
|
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(b.catchAll(() => b.void));
|
|
2849
2894
|
return n;
|
|
2850
|
-
}),
|
|
2895
|
+
}), Ti = () => {
|
|
2851
2896
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
2852
2897
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
2853
|
-
},
|
|
2898
|
+
}, Ei = (e) => {
|
|
2854
2899
|
if (e === void 0) return;
|
|
2855
2900
|
let t = e.trim();
|
|
2856
2901
|
if (t === "") return;
|
|
@@ -2860,48 +2905,48 @@ var yn = (e) => {
|
|
|
2860
2905
|
kind: "tables",
|
|
2861
2906
|
tables: new Set(n)
|
|
2862
2907
|
} : void 0;
|
|
2863
|
-
},
|
|
2908
|
+
}, Di = (e) => typeof e.table == "string" ? e.table : void 0, Oi = (e, t = { kind: "all" }) => ({
|
|
2864
2909
|
...e,
|
|
2865
2910
|
operations: e.operations.map((e) => {
|
|
2866
2911
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
2867
2912
|
if (t?.kind === "tables") {
|
|
2868
|
-
let n =
|
|
2913
|
+
let n = Di(e.op);
|
|
2869
2914
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
2870
2915
|
}
|
|
2871
2916
|
let { blocked: n, ...r } = e;
|
|
2872
2917
|
return r;
|
|
2873
2918
|
})
|
|
2874
|
-
}),
|
|
2875
|
-
let t =
|
|
2919
|
+
}), ki = (e, t, n) => t === "postgres" ? qt(e, n).pipe(b.flatMap((e) => {
|
|
2920
|
+
let t = Jt(e);
|
|
2876
2921
|
return t === void 0 ? b.void : b.logWarning(`auto-migrate: ${t}`).pipe(b.annotateLogs({ scope: "voltro:migrate" }));
|
|
2877
|
-
}), b.catchAll(() => b.void)) : b.void,
|
|
2878
|
-
let r =
|
|
2922
|
+
}), b.catchAll(() => b.void)) : b.void, Ai = (e, t, n) => b.gen(function* () {
|
|
2923
|
+
let r = Me(e), i = t;
|
|
2879
2924
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
2880
|
-
let t =
|
|
2881
|
-
if ((yield*
|
|
2925
|
+
let t = N(F(i, r));
|
|
2926
|
+
if ((yield* yi(e)) === t) return yield* ki(e, r, i), {
|
|
2882
2927
|
kind: "up-to-date",
|
|
2883
2928
|
fingerprint: t
|
|
2884
2929
|
};
|
|
2885
2930
|
}
|
|
2886
|
-
let a = yield*
|
|
2931
|
+
let a = yield* Jn(e), o = yield* wi(e, a.tables);
|
|
2887
2932
|
o.length > 0 && (yield* b.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(b.annotateLogs({
|
|
2888
2933
|
scope: "voltro:migrate",
|
|
2889
2934
|
count: o.length
|
|
2890
|
-
})), a = yield*
|
|
2891
|
-
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !m(e.name) || s.has(e.name)), l =
|
|
2935
|
+
})), a = yield* Jn(e));
|
|
2936
|
+
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !m(e.name) || s.has(e.name)), l = kn({
|
|
2892
2937
|
declared: i,
|
|
2893
2938
|
live: { tables: c(a.tables) },
|
|
2894
2939
|
dialect: r,
|
|
2895
|
-
...
|
|
2940
|
+
...Ti()
|
|
2896
2941
|
});
|
|
2897
2942
|
if (l.summary.blocked > 0) {
|
|
2898
|
-
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
2899
|
-
if (t === void 0 || !e || (l =
|
|
2943
|
+
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Ei(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
2944
|
+
if (t === void 0 || !e || (l = Oi(l, t), l.operations.some((e) => e.blocked))) return {
|
|
2900
2945
|
kind: "refused-blocked",
|
|
2901
2946
|
plan: l
|
|
2902
2947
|
};
|
|
2903
2948
|
}
|
|
2904
|
-
return l.operations.length === 0 ? (yield*
|
|
2949
|
+
return l.operations.length === 0 ? (yield* bi(e, l, {
|
|
2905
2950
|
appliedBy: n.appliedBy,
|
|
2906
2951
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
2907
2952
|
source: "auto-diff"
|
|
@@ -2910,37 +2955,37 @@ var yn = (e) => {
|
|
|
2910
2955
|
fingerprint: l.toFingerprint
|
|
2911
2956
|
}) : {
|
|
2912
2957
|
kind: "applied",
|
|
2913
|
-
applied: yield*
|
|
2958
|
+
applied: yield* _i(e, l, {
|
|
2914
2959
|
declared: t,
|
|
2915
2960
|
appliedBy: n.appliedBy,
|
|
2916
2961
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
2917
2962
|
source: "auto-diff",
|
|
2918
2963
|
replan: (e) => b.gen(function* () {
|
|
2919
|
-
let t = yield*
|
|
2920
|
-
return
|
|
2964
|
+
let t = yield* Jn(e);
|
|
2965
|
+
return kn({
|
|
2921
2966
|
declared: i,
|
|
2922
2967
|
live: { tables: c(t.tables) },
|
|
2923
2968
|
dialect: r,
|
|
2924
|
-
...
|
|
2969
|
+
...Ti()
|
|
2925
2970
|
});
|
|
2926
2971
|
})
|
|
2927
2972
|
}),
|
|
2928
2973
|
plan: l
|
|
2929
2974
|
};
|
|
2930
|
-
}),
|
|
2975
|
+
}), ji = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? b.succeed({
|
|
2931
2976
|
kind: "skipped",
|
|
2932
2977
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
2933
|
-
}) : n.environment === "prod" ?
|
|
2978
|
+
}) : n.environment === "prod" ? xi(e, t) : Ai(e, t, n), Mi = (e, t) => {
|
|
2934
2979
|
switch (e.kind) {
|
|
2935
2980
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
2936
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
2981
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${P(e.fingerprint)})`;
|
|
2937
2982
|
case "applied": {
|
|
2938
2983
|
let t = e.plan.summary;
|
|
2939
|
-
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=${
|
|
2984
|
+
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=${P(e.applied.fingerprint)}`;
|
|
2940
2985
|
}
|
|
2941
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
2986
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${P(e.expected)}` + (e.actual ? ` live=${P(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
2942
2987
|
case "refused-blocked": {
|
|
2943
|
-
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` +
|
|
2988
|
+
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` + vi(e.plan), c = [""];
|
|
2944
2989
|
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) {
|
|
2945
2990
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2946
2991
|
for (let r of e.plan.operations) {
|
|
@@ -2957,7 +3002,7 @@ var yn = (e) => {
|
|
|
2957
3002
|
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");
|
|
2958
3003
|
}
|
|
2959
3004
|
}
|
|
2960
|
-
},
|
|
3005
|
+
}, Ni = /* @__PURE__ */ new Set([
|
|
2961
3006
|
"node_modules",
|
|
2962
3007
|
"dist",
|
|
2963
3008
|
"build",
|
|
@@ -2966,12 +3011,12 @@ var yn = (e) => {
|
|
|
2966
3011
|
".next",
|
|
2967
3012
|
".git",
|
|
2968
3013
|
".framework"
|
|
2969
|
-
]),
|
|
3014
|
+
]), Pi = async (e) => {
|
|
2970
3015
|
let t = [], n = async (e) => {
|
|
2971
|
-
let r = await
|
|
3016
|
+
let r = await te.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
2972
3017
|
for (let i of r) {
|
|
2973
|
-
if (
|
|
2974
|
-
let r =
|
|
3018
|
+
if (Ni.has(i.name)) continue;
|
|
3019
|
+
let r = ne(e, i.name);
|
|
2975
3020
|
i.isDirectory() ? await n(r) : i.isFile() && u.test(i.name) && t.push(r);
|
|
2976
3021
|
}
|
|
2977
3022
|
};
|
|
@@ -2979,10 +3024,10 @@ var yn = (e) => {
|
|
|
2979
3024
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
2980
3025
|
return n.localeCompare(r);
|
|
2981
3026
|
});
|
|
2982
|
-
},
|
|
3027
|
+
}, Fi = async (e) => {
|
|
2983
3028
|
let t = [];
|
|
2984
3029
|
for (let n of e) {
|
|
2985
|
-
let e = (await import(
|
|
3030
|
+
let e = (await import(re(n).href)).default;
|
|
2986
3031
|
if (!o(e)) {
|
|
2987
3032
|
process.stderr.write(`[voltro:migrate] ${n} has no default-exported \`migration(...)\` — skipped\n`);
|
|
2988
3033
|
continue;
|
|
@@ -2993,11 +3038,11 @@ var yn = (e) => {
|
|
|
2993
3038
|
});
|
|
2994
3039
|
}
|
|
2995
3040
|
return t;
|
|
2996
|
-
},
|
|
3041
|
+
}, Ii = (e) => e`
|
|
2997
3042
|
SELECT ${e("id")}
|
|
2998
3043
|
FROM ${e("_voltro_migration_plans")}
|
|
2999
3044
|
WHERE ${e("source")} = 'file'
|
|
3000
|
-
`.pipe(b.map((e) => e.map((e) => e.id)), b.catchAll(() => b.succeed([]))),
|
|
3045
|
+
`.pipe(b.map((e) => e.map((e) => e.id)), b.catchAll(() => b.succeed([]))), Li = class extends Error {
|
|
3001
3046
|
migrationId;
|
|
3002
3047
|
file;
|
|
3003
3048
|
cause;
|
|
@@ -3005,7 +3050,7 @@ var yn = (e) => {
|
|
|
3005
3050
|
constructor(e, t, n) {
|
|
3006
3051
|
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";
|
|
3007
3052
|
}
|
|
3008
|
-
},
|
|
3053
|
+
}, Ri = (e, t, n, r) => b.gen(function* () {
|
|
3009
3054
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3010
3055
|
sql: e,
|
|
3011
3056
|
log: {
|
|
@@ -3039,10 +3084,10 @@ var yn = (e) => {
|
|
|
3039
3084
|
}])},
|
|
3040
3085
|
${r}, ${n}, ${"file"},
|
|
3041
3086
|
${c}, ${l}, ${t.migration.description})
|
|
3042
|
-
`.pipe(b.mapError((e) => new
|
|
3043
|
-
}),
|
|
3087
|
+
`.pipe(b.mapError((e) => new Li(t.migration.id, t.file, e))), { durationMs: c };
|
|
3088
|
+
}), zi = (e, t) => b.gen(function* () {
|
|
3044
3089
|
let n = yield* b.tryPromise({
|
|
3045
|
-
try: () =>
|
|
3090
|
+
try: () => Pi(ne(t, "migrations")),
|
|
3046
3091
|
catch: (e) => e
|
|
3047
3092
|
});
|
|
3048
3093
|
if (n.length === 0) return {
|
|
@@ -3050,25 +3095,25 @@ var yn = (e) => {
|
|
|
3050
3095
|
skipped: []
|
|
3051
3096
|
};
|
|
3052
3097
|
let r = yield* b.tryPromise({
|
|
3053
|
-
try: () =>
|
|
3098
|
+
try: () => Fi(n),
|
|
3054
3099
|
catch: (e) => e
|
|
3055
3100
|
});
|
|
3056
3101
|
if (r.length === 0) return {
|
|
3057
3102
|
pending: [],
|
|
3058
3103
|
skipped: []
|
|
3059
3104
|
};
|
|
3060
|
-
let i = new Set(yield*
|
|
3105
|
+
let i = new Set(yield* Ii(e));
|
|
3061
3106
|
return {
|
|
3062
3107
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3063
3108
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3064
3109
|
};
|
|
3065
|
-
}),
|
|
3066
|
-
let { pending: n, skipped: r } = yield*
|
|
3110
|
+
}), Bi = (e, t) => zi(e, t).pipe(b.map((e) => e.pending.map((e) => e.migration.id))), Vi = (e, t) => b.gen(function* () {
|
|
3111
|
+
let { pending: n, skipped: r } = yield* zi(e, t.projectRoot);
|
|
3067
3112
|
if (n.length === 0) return {
|
|
3068
3113
|
applied: [],
|
|
3069
3114
|
skipped: r
|
|
3070
3115
|
};
|
|
3071
|
-
yield* T(e);
|
|
3116
|
+
yield* T(e, { schema: t.lockSchema });
|
|
3072
3117
|
let i = [];
|
|
3073
3118
|
try {
|
|
3074
3119
|
for (let r of n) {
|
|
@@ -3077,7 +3122,7 @@ var yn = (e) => {
|
|
|
3077
3122
|
id: r.migration.id,
|
|
3078
3123
|
file: r.file
|
|
3079
3124
|
}));
|
|
3080
|
-
let { durationMs: n } = yield*
|
|
3125
|
+
let { durationMs: n } = yield* Ri(e, r, t.env, t.appliedBy);
|
|
3081
3126
|
i.push({
|
|
3082
3127
|
id: r.migration.id,
|
|
3083
3128
|
durationMs: n
|
|
@@ -3088,28 +3133,28 @@ var yn = (e) => {
|
|
|
3088
3133
|
}));
|
|
3089
3134
|
}
|
|
3090
3135
|
} finally {
|
|
3091
|
-
yield* E(e).pipe(b.orDie);
|
|
3136
|
+
yield* E(e, { schema: t.lockSchema }).pipe(b.orDie);
|
|
3092
3137
|
}
|
|
3093
3138
|
return {
|
|
3094
3139
|
applied: i,
|
|
3095
3140
|
skipped: r
|
|
3096
3141
|
};
|
|
3097
|
-
}),
|
|
3142
|
+
}), Hi = (e, t) => e`
|
|
3098
3143
|
SELECT ${e("id")}
|
|
3099
3144
|
FROM ${e("_voltro_migration_plans")}
|
|
3100
3145
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3101
3146
|
LIMIT 1
|
|
3102
|
-
`,
|
|
3103
|
-
if (!(yield*
|
|
3147
|
+
`, Ui = (e, t) => b.gen(function* () {
|
|
3148
|
+
if (!(yield* Hi(e, t.id))[0]) return yield* b.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3104
3149
|
let n = yield* b.tryPromise({
|
|
3105
|
-
try: () =>
|
|
3150
|
+
try: () => Pi(ne(t.projectRoot, "migrations")),
|
|
3106
3151
|
catch: (e) => e
|
|
3107
3152
|
}), r = (yield* b.tryPromise({
|
|
3108
|
-
try: () =>
|
|
3153
|
+
try: () => Fi(n),
|
|
3109
3154
|
catch: (e) => e
|
|
3110
3155
|
})).find((e) => e.migration.id === t.id);
|
|
3111
3156
|
if (!r) return yield* b.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
3112
|
-
yield* T(e);
|
|
3157
|
+
yield* T(e, { schema: t.lockSchema });
|
|
3113
3158
|
let i = Date.now();
|
|
3114
3159
|
try {
|
|
3115
3160
|
let n = {
|
|
@@ -3136,10 +3181,10 @@ var yn = (e) => {
|
|
|
3136
3181
|
durationMs: o
|
|
3137
3182
|
};
|
|
3138
3183
|
} finally {
|
|
3139
|
-
yield* E(e).pipe(b.orDie);
|
|
3184
|
+
yield* E(e, { schema: t.lockSchema }).pipe(b.orDie);
|
|
3140
3185
|
}
|
|
3141
|
-
}),
|
|
3142
|
-
let t = yield*
|
|
3186
|
+
}), Wi = (e) => b.gen(function* () {
|
|
3187
|
+
let t = yield* C.SqlClient, n = yield* t`
|
|
3143
3188
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3144
3189
|
WHERE source = 'auto-diff'
|
|
3145
3190
|
AND squashedAt IS NULL
|
|
@@ -3183,7 +3228,7 @@ var yn = (e) => {
|
|
|
3183
3228
|
snapshotFingerprint: e.fingerprint,
|
|
3184
3229
|
snapshotId: i
|
|
3185
3230
|
};
|
|
3186
|
-
}),
|
|
3231
|
+
}), Gi = { safe: !0 }, Ki = (e) => {
|
|
3187
3232
|
switch (e.kind) {
|
|
3188
3233
|
case "drop-column": return {
|
|
3189
3234
|
safe: !1,
|
|
@@ -3210,7 +3255,7 @@ var yn = (e) => {
|
|
|
3210
3255
|
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`,
|
|
3211
3256
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
3212
3257
|
};
|
|
3213
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3258
|
+
case "alter-column-nullability": return e.toNullable ? Gi : {
|
|
3214
3259
|
safe: !1,
|
|
3215
3260
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3216
3261
|
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)`
|
|
@@ -3240,12 +3285,12 @@ var yn = (e) => {
|
|
|
3240
3285
|
case "drop-unique":
|
|
3241
3286
|
case "drop-unique-composite":
|
|
3242
3287
|
case "drop-foreign-key":
|
|
3243
|
-
case "drop-check": return
|
|
3288
|
+
case "drop-check": return Gi;
|
|
3244
3289
|
}
|
|
3245
|
-
},
|
|
3290
|
+
}, qi = (e) => {
|
|
3246
3291
|
let t = [];
|
|
3247
3292
|
for (let n of e) {
|
|
3248
|
-
let e =
|
|
3293
|
+
let e = Ki(n.op);
|
|
3249
3294
|
e.safe || t.push({
|
|
3250
3295
|
op: n,
|
|
3251
3296
|
reason: e.reason,
|
|
@@ -3253,7 +3298,7 @@ var yn = (e) => {
|
|
|
3253
3298
|
});
|
|
3254
3299
|
}
|
|
3255
3300
|
return t;
|
|
3256
|
-
},
|
|
3301
|
+
}, Ji = (e) => {
|
|
3257
3302
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3258
3303
|
refuse: !1,
|
|
3259
3304
|
warnForced: !1,
|
|
@@ -3269,18 +3314,18 @@ var yn = (e) => {
|
|
|
3269
3314
|
warnForced: !1,
|
|
3270
3315
|
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.`
|
|
3271
3316
|
};
|
|
3272
|
-
},
|
|
3317
|
+
}, Yi = (e) => {
|
|
3273
3318
|
let t = e.table;
|
|
3274
3319
|
if (typeof t == "string") return t;
|
|
3275
3320
|
let n = e.from;
|
|
3276
3321
|
return typeof n == "string" ? n : void 0;
|
|
3277
|
-
},
|
|
3322
|
+
}, Xi = (e) => ({
|
|
3278
3323
|
kind: e.op.kind,
|
|
3279
|
-
table:
|
|
3324
|
+
table: Yi(e.op),
|
|
3280
3325
|
classification: e.classification,
|
|
3281
3326
|
reason: e.reason,
|
|
3282
3327
|
blockedFix: e.blocked?.fix
|
|
3283
|
-
}),
|
|
3328
|
+
}), Zi = (e) => e.operations.map(Xi), Qi = async (e) => {
|
|
3284
3329
|
let t = e.log ?? (() => {}), n = {
|
|
3285
3330
|
branchId: e.branchId,
|
|
3286
3331
|
mechanism: e.mechanism,
|
|
@@ -3299,10 +3344,10 @@ var yn = (e) => {
|
|
|
3299
3344
|
applied: !1,
|
|
3300
3345
|
converged: !1,
|
|
3301
3346
|
residual: r,
|
|
3302
|
-
infidelity:
|
|
3347
|
+
infidelity: Zi(o)
|
|
3303
3348
|
};
|
|
3304
3349
|
else {
|
|
3305
|
-
let i = await e.plan(), o =
|
|
3350
|
+
let i = await e.plan(), o = Zi(i), s = o.filter((e) => e.classification === "lossy"), c = Oi(i), l = c.operations.filter((e) => e.blocked !== void 0).map(Xi);
|
|
3306
3351
|
if (l.length > 0) a = {
|
|
3307
3352
|
...n,
|
|
3308
3353
|
outcome: "blocked",
|
|
@@ -3327,7 +3372,7 @@ var yn = (e) => {
|
|
|
3327
3372
|
};
|
|
3328
3373
|
else {
|
|
3329
3374
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3330
|
-
let i =
|
|
3375
|
+
let i = Zi(await e.replan());
|
|
3331
3376
|
a = {
|
|
3332
3377
|
...n,
|
|
3333
3378
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3365,7 +3410,7 @@ var yn = (e) => {
|
|
|
3365
3410
|
...a,
|
|
3366
3411
|
tornDown: o
|
|
3367
3412
|
};
|
|
3368
|
-
},
|
|
3413
|
+
}, $i = (e) => {
|
|
3369
3414
|
switch (e.outcome) {
|
|
3370
3415
|
case "clean": return 0;
|
|
3371
3416
|
case "lossy": return 2;
|
|
@@ -3374,22 +3419,22 @@ var yn = (e) => {
|
|
|
3374
3419
|
case "infidelity": return 1;
|
|
3375
3420
|
case "failed": return 1;
|
|
3376
3421
|
}
|
|
3377
|
-
},
|
|
3422
|
+
}, ea = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, ta = (e) => {
|
|
3378
3423
|
let t = [];
|
|
3379
3424
|
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"}`);
|
|
3380
3425
|
else if (e.outcome === "infidelity") {
|
|
3381
3426
|
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:");
|
|
3382
|
-
for (let n of e.infidelity) t.push(
|
|
3427
|
+
for (let n of e.infidelity) t.push(ea(n));
|
|
3383
3428
|
} else {
|
|
3384
3429
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3385
|
-
for (let n of e.operations) t.push(
|
|
3386
|
-
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(
|
|
3430
|
+
for (let n of e.operations) t.push(ea(n));
|
|
3431
|
+
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(ea(n));
|
|
3387
3432
|
}
|
|
3388
3433
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3389
|
-
},
|
|
3434
|
+
}, na = (e, ...t) => ({
|
|
3390
3435
|
_tag: "RawSqlFragment",
|
|
3391
3436
|
strings: [...e],
|
|
3392
3437
|
values: [...t]
|
|
3393
|
-
}),
|
|
3438
|
+
}), ra = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3394
3439
|
//#endregion
|
|
3395
|
-
export {
|
|
3440
|
+
export { O as DEFAULT_CDC_CHANNEL, u as FILE_MIGRATION_PATTERN, Li as FileMigrationLedgerError, Ke as REACTIVE_TRIGGER_PREFIX, de as VOLTRO_MIGRATION_LOCK_KEY, T as acquireMigrationLock, H as appliedAtValue, Ft as applyNamespacedSchema, _i as applyPlan, Tt as applySchema, Ji as assessRollingDeployGate, $i as branchRehearsalExitCode, In as chunkTables, Ki as classifyRollingDeploySafety, F as declaredSnapshot, Qe as defaultArrayClause, Ze as defaultClause, j as defaultJsonClause, Mi as describeOutcome, Ei as destructiveScope, qt as detectReactiveTriggerDrift, Fr as emitAddIndexMysql, _r as emitCreateTableMysql, er as emitDropColumnDdl, tr as emitDropColumnDdlMysql, wt as emitFrameworkBootstrapSql, St as emitNamespaceProvisionDdl, Ct as emitNamespacedSchemaSql, xt as emitSchemaSql, N as fingerprintSchema, _e as fnv1a64, ta as formatBranchRehearsal, Jt as formatReactiveTriggerDrift, Ti as ignoreTablesFromEnv, Jn as introspectSchema, o as isFileMigration, ra as isRawSqlFragment, Dt as isReRunSafeDdl, jn as mapPgType, h as migration, ve as migrationLockKeyForSchema, ye as migrationLockNameForSchema, jr as mysqlIndexPrefixFor, Je as notifyFunctionName, M as numericIdSql, An as parseEnumCheck, Bi as pendingFileMigrationIds, kn as planMigrations, It as provisionTenantNamespace, qe as reactiveTriggerName, ft as reactiveTriggerRepairSql, bi as recordUpToDate, Qi as rehearseMigrationOnBranch, Xi as rehearsedOperation, E as releaseMigrationLock, gr as renderColumnMysql, dr as renderColumnPg, pe as resolveMigrationLockSchema, Ui as rollbackFileBasedMigration, qi as rollingDeployUnsafeOps, Vi as runFileBasedMigrations, Lt as runFrameworkBootstrap, Pt as runMigrate, ji as runPlannedMigrations, P as shortFingerprint, Ut as snapshotColumn, na as sql, A as sqlType, Wi as squashMigrationPlans, Oi as unblockLossy, je as withMigrationLock };
|