@voltro/database 0.82.0 → 0.83.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 +286 -0
- package/dist/index.d.ts +31 -11
- package/dist/index.js +634 -633
- package/dist/{replaceInProgress-BbN7p1Q-.js → replaceInProgress-CncEA_Sx.js} +386 -337
- package/dist/sql.d.ts +11 -0
- package/dist/sql.js +904 -862
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as e,
|
|
1
|
+
import { A as e, B as t, Br as n, D as r, Dn as i, Dt as a, E as o, F as s, G as c, H as l, Ht as u, I as d, It as f, Kn as p, L as m, M as h, Mn as g, Mr as _, N as v, Nn as y, O as ee, On as b, Or as x, P as S, Qn as C, R as w, T as te, V as T, Vr as E, Vt as ne, W as re, Wt as D, X as ie, Zn as ae, _ as oe, at as se, h as ce, j as le, k as ue, kn as O, kr as de, lr as fe, nr as pe, nt as me, p as he, qt as ge, r as _e, t as ve, ut as ye, w as be, xn as xe, z as Se } from "./replaceInProgress-CncEA_Sx.js";
|
|
2
2
|
import { Cause as Ce, Effect as k, Equal as we, Exit as Te, Schedule as Ee, Scope as De } from "effect";
|
|
3
3
|
import { createHash as Oe, randomUUID as ke } from "node:crypto";
|
|
4
4
|
import { createLogger as Ae } from "@voltro/logger";
|
|
@@ -14,7 +14,7 @@ var Fe = (e, t = "float32") => {
|
|
|
14
14
|
m: r,
|
|
15
15
|
efConstruction: i
|
|
16
16
|
})) if (!Number.isSafeInteger(t) || t <= 0) throw Error(`HNSW ${e} must be a positive safe integer`);
|
|
17
|
-
let a = n?.opclass ??
|
|
17
|
+
let a = n?.opclass ?? y(n?.distance, t);
|
|
18
18
|
if (!/^[a-z_][a-z0-9_$]*(?:\.[a-z_][a-z0-9_$]*)?$/i.test(a)) throw Error("HNSW opclass must be an unquoted, optionally schema-qualified identifier");
|
|
19
19
|
return {
|
|
20
20
|
m: r,
|
|
@@ -196,19 +196,19 @@ var Fe = (e, t = "float32") => {
|
|
|
196
196
|
mariadb: "per-operation",
|
|
197
197
|
sqlite: "per-operation",
|
|
198
198
|
turso: "per-operation"
|
|
199
|
-
}, St = (e) => xt[e], N = "_voltro_migration_ops", Ct =
|
|
200
|
-
id:
|
|
201
|
-
runId:
|
|
202
|
-
planFingerprint:
|
|
203
|
-
opIndex:
|
|
204
|
-
opKind:
|
|
205
|
-
opTarget:
|
|
206
|
-
status:
|
|
207
|
-
payload:
|
|
208
|
-
startedAt:
|
|
209
|
-
appliedAt:
|
|
210
|
-
durationMs:
|
|
211
|
-
createdAt:
|
|
199
|
+
}, St = (e) => xt[e], N = "_voltro_migration_ops", Ct = g(N, {
|
|
200
|
+
id: x({ prefix: "mop" }),
|
|
201
|
+
runId: n(),
|
|
202
|
+
planFingerprint: n(),
|
|
203
|
+
opIndex: de(),
|
|
204
|
+
opKind: n(),
|
|
205
|
+
opTarget: n(),
|
|
206
|
+
status: n(),
|
|
207
|
+
payload: n(),
|
|
208
|
+
startedAt: E().nullable(),
|
|
209
|
+
appliedAt: E().nullable(),
|
|
210
|
+
durationMs: de().nullable(),
|
|
211
|
+
createdAt: E().default("now")
|
|
212
212
|
}), wt = (e) => {
|
|
213
213
|
switch (e.kind) {
|
|
214
214
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
@@ -261,7 +261,7 @@ var Fe = (e, t = "float32") => {
|
|
|
261
261
|
"alter-column-default"
|
|
262
262
|
]), Mt = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Nt = (e, t, n) => {
|
|
263
263
|
let r = n === "sqlite" || n === "turso";
|
|
264
|
-
return e.kind === "alter-column-type" && t === "online-required" || r && jt.has(e.kind) ? "artefact-repair" : Mt.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
264
|
+
return n === "postgres" && e.kind === "add-index" && t === "online-required" || e.kind === "alter-column-type" && t === "online-required" || r && jt.has(e.kind) ? "artefact-repair" : Mt.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
265
265
|
};
|
|
266
266
|
Object.keys(xt);
|
|
267
267
|
//#endregion
|
|
@@ -332,7 +332,7 @@ var Pt = (e) => {
|
|
|
332
332
|
}, t)}[]`;
|
|
333
333
|
if (t === "mysql" || t === "mariadb") return "JSON";
|
|
334
334
|
if (t === "mssql") return "NVARCHAR(MAX)";
|
|
335
|
-
if (
|
|
335
|
+
if (b(t)) return "TEXT";
|
|
336
336
|
}
|
|
337
337
|
if (n === "vector") {
|
|
338
338
|
let n = e.vectorDim;
|
|
@@ -341,27 +341,27 @@ var Pt = (e) => {
|
|
|
341
341
|
if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
|
|
342
342
|
if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
|
|
343
343
|
if (t === "mssql") return "VARBINARY(MAX)";
|
|
344
|
-
if (
|
|
344
|
+
if (b(t)) return "BLOB";
|
|
345
345
|
}
|
|
346
346
|
if (n === "interval") {
|
|
347
347
|
if (t === "postgres") return "INTERVAL";
|
|
348
348
|
if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
|
|
349
|
-
if (
|
|
349
|
+
if (b(t)) return "INTEGER";
|
|
350
350
|
}
|
|
351
351
|
if (n === "decimal") {
|
|
352
352
|
let n = e.precision, r = e.scale ?? 0;
|
|
353
353
|
if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
|
|
354
|
-
return
|
|
354
|
+
return b(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
|
|
355
355
|
}
|
|
356
|
-
if (n === "bigint") return
|
|
356
|
+
if (n === "bigint") return b(t) ? "INTEGER" : "BIGINT";
|
|
357
357
|
if (n === "enum") {
|
|
358
358
|
if (t === "postgres") return e.enumName ?? "TEXT";
|
|
359
359
|
if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
|
|
360
360
|
if (t === "mssql") return "NVARCHAR(255)";
|
|
361
|
-
if (
|
|
361
|
+
if (b(t)) return "TEXT";
|
|
362
362
|
}
|
|
363
|
-
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` :
|
|
364
|
-
if (
|
|
363
|
+
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` : b(t) ? "TEXT" : `VARCHAR(${e.maxLength})`;
|
|
364
|
+
if (b(t)) switch (n) {
|
|
365
365
|
case "id": return "TEXT";
|
|
366
366
|
case "text": return "TEXT";
|
|
367
367
|
case "integer": return "INTEGER";
|
|
@@ -431,7 +431,7 @@ var Pt = (e) => {
|
|
|
431
431
|
}, Jt = (e, t) => {
|
|
432
432
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
433
433
|
let n = e.defaultValue;
|
|
434
|
-
return n === "now" ?
|
|
434
|
+
return n === "now" ? b(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) ? Yt(n, e, t) : typeof n == "object" && n ? Xt(n, t) : null;
|
|
435
435
|
}, Yt = (e, t, n) => {
|
|
436
436
|
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return Xt(e, n);
|
|
437
437
|
let r = F({
|
|
@@ -460,12 +460,12 @@ var Pt = (e) => {
|
|
|
460
460
|
case "setNull": return "SET NULL";
|
|
461
461
|
case "noAction": return "NO ACTION";
|
|
462
462
|
}
|
|
463
|
-
}, $t = (e, t, n) => n === null ?
|
|
463
|
+
}, $t = (e, t, n) => n === null ? O(e, t) : `${O(n, t)}.${O(e, t)}`, en = 191, tn = (e, t) => {
|
|
464
464
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
465
465
|
let n = F(e, t).toUpperCase();
|
|
466
466
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
467
467
|
}, nn = (e, t, n) => {
|
|
468
|
-
let r =
|
|
468
|
+
let r = O(e, n);
|
|
469
469
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
470
470
|
let i = t[e];
|
|
471
471
|
if (!i) return r;
|
|
@@ -479,20 +479,20 @@ var Pt = (e) => {
|
|
|
479
479
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
480
480
|
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.");
|
|
481
481
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
482
|
-
}, an = (e, t, n, r,
|
|
482
|
+
}, an = (e, t, n, r, a = !1, o = !1) => {
|
|
483
483
|
if (t.type === "id" && t.idScheme?.kind === "numeric") return Zt(e, n);
|
|
484
|
-
let s = n === "mssql" ? Kt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? F(t, n) : `NVARCHAR(${s})`, l = [
|
|
485
|
-
t.type === "id" && !
|
|
486
|
-
let
|
|
487
|
-
if (
|
|
484
|
+
let s = n === "mssql" ? Kt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? F(t, n) : `NVARCHAR(${s})`, l = [O(e, n), c];
|
|
485
|
+
t.type === "id" && !o && l.push("PRIMARY KEY");
|
|
486
|
+
let u = rn(t, n);
|
|
487
|
+
if (u) l.push(u);
|
|
488
488
|
else {
|
|
489
489
|
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !tn(t, n) && l.push("UNIQUE");
|
|
490
490
|
let e = Jt(t, n);
|
|
491
491
|
e && l.push(e);
|
|
492
492
|
}
|
|
493
|
-
if (t.type === "reference" && t.references && !
|
|
493
|
+
if (t.type === "reference" && t.references && !a && !i(n)) {
|
|
494
494
|
let e = t.references();
|
|
495
|
-
l.push(`REFERENCES ${
|
|
495
|
+
l.push(`REFERENCES ${O(e.tableName, n)} (${O(t.referenceColumn ?? "id", n)})`);
|
|
496
496
|
let r = Qt(t.onDelete ?? "restrict", n);
|
|
497
497
|
l.push(`ON DELETE ${r}`);
|
|
498
498
|
let i = Qt(t.refOnUpdate ?? "noAction", n);
|
|
@@ -500,37 +500,37 @@ var Pt = (e) => {
|
|
|
500
500
|
}
|
|
501
501
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
502
502
|
let r = t.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
503
|
-
l.push(`CHECK (${
|
|
503
|
+
l.push(`CHECK (${O(e, n)} IN (${r}))`);
|
|
504
504
|
}
|
|
505
505
|
if (t.checks && t.checks.length > 0) for (let e of t.checks) l.push(`CHECK (${e})`);
|
|
506
|
-
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (n === "mssql" ||
|
|
506
|
+
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (n === "mssql" || b(n))) {
|
|
507
507
|
let r = t.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
508
|
-
l.push(`CHECK (${
|
|
508
|
+
l.push(`CHECK (${O(e, n)} IN (${r}))`);
|
|
509
509
|
}
|
|
510
510
|
if (t.type === "json" || t.type === "array") {
|
|
511
|
-
let r =
|
|
512
|
-
|
|
511
|
+
let r = O(e, n);
|
|
512
|
+
b(n) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : n === "mssql" && l.push(t.type === "json" ? `CHECK ${Pt(r)}` : `CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
|
|
513
513
|
}
|
|
514
514
|
return l.join(" ");
|
|
515
515
|
}, on = (e, t) => {
|
|
516
516
|
if (t.charset !== void 0) {
|
|
517
|
-
if (!
|
|
517
|
+
if (!i(e)) throw Error(`store charset '${t.charset}' is declared for a ${e} store — a character set is a MySQL / MariaDB setting. Remove \`charset\` from \`store\` in app.config.ts, or declare \`store: { dialect: 'mysql' | 'mariadb', charset }\`.`);
|
|
518
518
|
return t.charset;
|
|
519
519
|
}
|
|
520
|
-
}, sn = (e, t, n = null, r,
|
|
521
|
-
let
|
|
522
|
-
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" &&
|
|
523
|
-
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" &&
|
|
524
|
-
for (let [t, n] of Object.entries(e.fields)) n.unique &&
|
|
520
|
+
}, sn = (e, t, n = null, r, a) => {
|
|
521
|
+
let o = /* @__PURE__ */ new Set();
|
|
522
|
+
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
523
|
+
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
524
|
+
for (let [t, n] of Object.entries(e.fields)) n.unique && o.add(t);
|
|
525
525
|
let s = e.appliedPrimaryKey ?? [];
|
|
526
|
-
for (let e of s)
|
|
527
|
-
let c = s.length > 0, l = Object.entries(e.fields).map(([e, n]) => ` ${an(e, n, t,
|
|
526
|
+
for (let e of s) o.add(e);
|
|
527
|
+
let c = s.length > 0, l = Object.entries(e.fields).map(([e, n]) => ` ${an(e, n, t, o, r?.has(e) ?? !1, c)}`).join(",\n"), u = (e.appliedUniques ?? []).map((n) => {
|
|
528
528
|
let r = n.fields.map((n) => nn(n, e.fields, t)).join(", ");
|
|
529
|
-
return ` CONSTRAINT ${
|
|
530
|
-
}), d = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${
|
|
529
|
+
return ` CONSTRAINT ${O(n.name, t)} UNIQUE (${r})`;
|
|
530
|
+
}), d = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${O(e.name, t)} CHECK (${e.expr})`), f = c ? [` PRIMARY KEY (${s.map((n) => nn(n, e.fields, t)).join(", ")})`] : [], p = i(t) ? Object.entries(e.fields).flatMap(([i, a]) => {
|
|
531
531
|
if (a.type !== "reference" || !a.references || (r?.has(i) ?? !1)) return [];
|
|
532
|
-
let
|
|
533
|
-
return [` CONSTRAINT ${
|
|
532
|
+
let o = a.references(), s = Qt(a.onDelete ?? "restrict", t), c = Qt(a.refOnUpdate ?? "noAction", t);
|
|
533
|
+
return [` CONSTRAINT ${O(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${O(i, t)}) REFERENCES ${$t(o.tableName, t, n)} (${O(a.referenceColumn ?? "id", t)}) ON DELETE ${s}${c === "NO ACTION" ? "" : ` ON UPDATE ${c}`}`];
|
|
534
534
|
}) : [], m = [
|
|
535
535
|
...f,
|
|
536
536
|
...u,
|
|
@@ -544,26 +544,26 @@ var Pt = (e) => {
|
|
|
544
544
|
return [
|
|
545
545
|
`CREATE TABLE IF NOT EXISTS ${g} (`,
|
|
546
546
|
h,
|
|
547
|
-
`)${
|
|
547
|
+
`)${a !== void 0 && i(t) ? ` DEFAULT CHARACTER SET ${a}` : ""};`
|
|
548
548
|
].join("\n");
|
|
549
549
|
}, cn = (e, t, n) => {
|
|
550
|
-
let r = `${e}_${t.name}_fts`, i = (e) =>
|
|
551
|
-
return
|
|
550
|
+
let r = `${e}_${t.name}_fts`, i = (e) => O(e, n), a = t.columns.map(i).join(", "), o = t.columns.map((e) => `new.${i(e)}`).join(", "), s = [];
|
|
551
|
+
return s.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${i(r)} USING fts5(${a}, row_id UNINDEXED, tokenize='porter');`), s.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ai`)} AFTER INSERT ON ${i(e)} BEGIN\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${o}, new.${i("id")});\nEND;`), s.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ad`)} AFTER DELETE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\nEND;`), s.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_au`)} AFTER UPDATE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${o}, new.${i("id")});\nEND;`), s;
|
|
552
552
|
}, ln = (e) => e.appliedFullText ?? [], un = (e, t) => {
|
|
553
553
|
let n = [];
|
|
554
554
|
for (let r of ln(e)) if (t === "postgres") {
|
|
555
|
-
let i = r.config ?? "english", a = `${r.name}_tsv`,
|
|
555
|
+
let i = r.config ?? "english", a = `${r.name}_tsv`, o = r.columns.map((e) => {
|
|
556
556
|
let n = r.weights?.[e] ?? "A";
|
|
557
|
-
return `setweight(to_tsvector('${i}', coalesce(${
|
|
557
|
+
return `setweight(to_tsvector('${i}', coalesce(${O(e, t)}, '')), '${n}')`;
|
|
558
558
|
}).join(" || ");
|
|
559
|
-
n.push(`ALTER TABLE ${
|
|
559
|
+
n.push(`ALTER TABLE ${O(e.tableName, t)} ADD COLUMN IF NOT EXISTS ${O(a, t)} tsvector GENERATED ALWAYS AS (${o}) STORED;`), n.push(`CREATE INDEX IF NOT EXISTS ${O(r.name, t)} ON ${O(e.tableName, t)} USING GIN (${O(a, t)});`);
|
|
560
560
|
} else if (t === "mysql" || t === "mariadb") {
|
|
561
|
-
let i = r.columns.map((e) =>
|
|
562
|
-
n.push(`CREATE FULLTEXT INDEX ${
|
|
561
|
+
let i = r.columns.map((e) => O(e, t)).join(", ");
|
|
562
|
+
n.push(`CREATE FULLTEXT INDEX ${O(r.name, t)} ON ${O(e.tableName, t)} (${i});`);
|
|
563
563
|
} else t === "turso" || t === "sqlite" && n.push(...cn(e.tableName, r, t));
|
|
564
564
|
return n;
|
|
565
565
|
}, dn = (e, t, n = null) => {
|
|
566
|
-
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"),
|
|
566
|
+
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"), o = (e, n, r, i, a) => {
|
|
567
567
|
if (t === "postgres") return Re(r, i, a);
|
|
568
568
|
let o = {
|
|
569
569
|
using: "",
|
|
@@ -579,25 +579,25 @@ var Pt = (e) => {
|
|
|
579
579
|
withSuffix: "",
|
|
580
580
|
skip: !0
|
|
581
581
|
}) : o;
|
|
582
|
-
},
|
|
582
|
+
}, s = (n, r) => {
|
|
583
583
|
let i = n.map((n) => {
|
|
584
584
|
if (typeof n == "string") return nn(n, e.fields, t);
|
|
585
585
|
if ("jsonPath" in n) {
|
|
586
586
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
587
|
-
return `(${
|
|
587
|
+
return `(${f(e, r, t, { numeric: i })})`;
|
|
588
588
|
}
|
|
589
589
|
return `(${n.expr})`;
|
|
590
590
|
});
|
|
591
591
|
return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
|
|
592
|
-
},
|
|
593
|
-
let
|
|
594
|
-
if (
|
|
595
|
-
let
|
|
596
|
-
return
|
|
592
|
+
}, c = (r, i, a, c, l, u = "", d = !1) => {
|
|
593
|
+
let f = a[0], p = typeof f == "string" ? e.fields[f]?.vectorPrecision : void 0, m = o(r, i, c, l, p);
|
|
594
|
+
if (m.skip) return "";
|
|
595
|
+
let h = s(a, m.opclass), g = `${m.withSuffix}${u}`, _ = $t(i, t, n), v = d ? "UNIQUE " : "";
|
|
596
|
+
return b(t) && n !== null ? `CREATE ${v}INDEX IF NOT EXISTS ${$t(r, t, n)} ON ${O(i, t)} (${h})${g};` : t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${r}') CREATE ${v}INDEX ${O(r, t)} ON ${_}${m.using} (${h})${g};` : t === "mysql" ? `CREATE ${v}INDEX ${O(r, t)} ON ${_}${m.using} (${h})${g};` : `CREATE ${v}INDEX IF NOT EXISTS ${O(r, t)} ON ${_}${m.using} (${h})${g};`;
|
|
597
597
|
};
|
|
598
598
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
599
599
|
if (!i.unique || i.type === "id" || !tn(i, t)) continue;
|
|
600
|
-
let a =
|
|
600
|
+
let a = c(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
601
601
|
a && r.push(a);
|
|
602
602
|
}
|
|
603
603
|
if (r.push(...un(e, t)), t === "mssql") for (let n of ln(e)) P(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
@@ -609,13 +609,13 @@ var Pt = (e) => {
|
|
|
609
609
|
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.`);
|
|
610
610
|
let o = "";
|
|
611
611
|
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? P(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) : o = ` WHERE ${n.where}`);
|
|
612
|
-
let s =
|
|
612
|
+
let s = c(n.name, e.tableName, n.fields, n.kind, n.kindOptions, o, n.unique === !0);
|
|
613
613
|
s !== "" && r.push(s), n.fields.every((e) => typeof e == "string") && i.add(a(n.fields));
|
|
614
614
|
}
|
|
615
615
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
616
616
|
if (n.type !== "reference" || n.fkAutoIndex === !1 || i.has(a([t]))) continue;
|
|
617
617
|
let o = `${e.tableName}_${t}_idx`;
|
|
618
|
-
r.push(
|
|
618
|
+
r.push(c(o, e.tableName, [t])), i.add(a([t]));
|
|
619
619
|
}
|
|
620
620
|
return r.join("\n");
|
|
621
621
|
}, fn = (e, t, n = Rt) => {
|
|
@@ -739,23 +739,23 @@ $$ LANGUAGE plpgsql;
|
|
|
739
739
|
cyclic: r
|
|
740
740
|
};
|
|
741
741
|
}, xn = (e, t, n = null) => {
|
|
742
|
-
let r = (e) => n ? `${
|
|
742
|
+
let r = (e) => n ? `${O(n, t)}.${O(e, t)}` : O(e, t), i = `${e.table}_${e.column}_fkey`, a = Qt(e.onDelete, t), o = Qt(e.onUpdate, t), s = ` ON DELETE ${a}${o === "NO ACTION" ? "" : ` ON UPDATE ${o}`}`, c = (n) => `ADD CONSTRAINT ${O(i, t)} FOREIGN KEY ${n ? "IF NOT EXISTS " : ""}(${O(e.column, t)}) REFERENCES ${r(e.targetTable)} (${O(e.targetColumn, t)})${s}`;
|
|
743
743
|
switch (t) {
|
|
744
744
|
case "postgres": return [
|
|
745
745
|
"DO $$ BEGIN",
|
|
746
746
|
" IF NOT EXISTS (SELECT 1 FROM pg_constraint",
|
|
747
747
|
` WHERE conname = '${i}' AND conrelid = '${n ? `${n}.` : ""}${e.table}'::regclass) THEN`,
|
|
748
|
-
` ALTER TABLE ${r(e.table)} ${
|
|
748
|
+
` ALTER TABLE ${r(e.table)} ${c(!1)};`,
|
|
749
749
|
" END IF;",
|
|
750
750
|
"END $$;"
|
|
751
751
|
].join("\n");
|
|
752
|
-
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${i}') ALTER TABLE ${r(e.table)} ${
|
|
753
|
-
case "mariadb": return `ALTER TABLE ${r(e.table)} ${
|
|
754
|
-
default: return `ALTER TABLE ${r(e.table)} ${
|
|
752
|
+
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${i}') ALTER TABLE ${r(e.table)} ${c(!1)};`;
|
|
753
|
+
case "mariadb": return `ALTER TABLE ${r(e.table)} ${c(!0)};`;
|
|
754
|
+
default: return `ALTER TABLE ${r(e.table)} ${c(!1)};`;
|
|
755
755
|
}
|
|
756
756
|
}, Sn = (e, t) => {
|
|
757
757
|
let n = /* @__PURE__ */ new Map();
|
|
758
|
-
if (
|
|
758
|
+
if (b(t)) return n;
|
|
759
759
|
for (let t of e) {
|
|
760
760
|
let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
|
|
761
761
|
e.add(t.column), n.set(t.table, e);
|
|
@@ -782,7 +782,7 @@ $$ LANGUAGE plpgsql;
|
|
|
782
782
|
let n = /* @__PURE__ */ new Set();
|
|
783
783
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
|
|
784
784
|
let r = [];
|
|
785
|
-
for (let e of n) for (let { from: t, to: n } of
|
|
785
|
+
for (let e of n) for (let { from: t, to: n } of fe(e)) {
|
|
786
786
|
let i = e.replace(/'/g, "''"), a = t.replace(/'/g, "''"), o = n.replace(/'/g, "''");
|
|
787
787
|
r.push(`DO \$\$
|
|
788
788
|
DECLARE
|
|
@@ -793,29 +793,29 @@ BEGIN
|
|
|
793
793
|
return r.join("\n\n");
|
|
794
794
|
}, Tn = (e) => {
|
|
795
795
|
let t = [], n = [];
|
|
796
|
-
for (let r of e)
|
|
796
|
+
for (let r of e) D(r) ? n.push(r) : t.push(r);
|
|
797
797
|
return {
|
|
798
798
|
tables: t,
|
|
799
799
|
views: n
|
|
800
800
|
};
|
|
801
801
|
}, En = (e, t, n = Rt, r = {}) => {
|
|
802
|
-
let i = on(t, r), { tables: a, views: o } = Tn(e), { sorted: s, cyclic: c } = bn(a.map((e) => Ge(e, t))), l = Sn(c, t),
|
|
803
|
-
|
|
804
|
-
let
|
|
805
|
-
|
|
806
|
-
let
|
|
807
|
-
|
|
808
|
-
for (let e of s)
|
|
809
|
-
if (!
|
|
802
|
+
let i = on(t, r), { tables: a, views: o } = Tn(e), { sorted: s, cyclic: c } = bn(a.map((e) => Ge(e, t))), l = Sn(c, t), u = [], d = _n(s, t);
|
|
803
|
+
d && u.push(d);
|
|
804
|
+
let f = wn(s, t);
|
|
805
|
+
f && u.push(f);
|
|
806
|
+
let p = Cn(s, t);
|
|
807
|
+
p && u.push(p);
|
|
808
|
+
for (let e of s) u.push(sn(e, t, null, l.get(e.tableName), i));
|
|
809
|
+
if (!b(t)) for (let e of c) u.push(xn(e, t));
|
|
810
810
|
for (let e of s) {
|
|
811
811
|
let n = dn(e, t);
|
|
812
|
-
n &&
|
|
812
|
+
n && u.push(n);
|
|
813
813
|
}
|
|
814
|
-
|
|
815
|
-
for (let e of o)
|
|
816
|
-
return
|
|
814
|
+
u.push(...fn(s, t, n));
|
|
815
|
+
for (let e of o) u.push(ge(e, t));
|
|
816
|
+
return u.join("\n\n") + "\n";
|
|
817
817
|
}, Dn = (e, t, n, r) => {
|
|
818
|
-
let i =
|
|
818
|
+
let i = O(e, t);
|
|
819
819
|
switch (t) {
|
|
820
820
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
|
|
821
821
|
case "mysql":
|
|
@@ -825,16 +825,16 @@ BEGIN
|
|
|
825
825
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
|
|
826
826
|
}
|
|
827
827
|
}, On = (e, t, n, r, i = {}) => {
|
|
828
|
-
let a = on(t, i),
|
|
829
|
-
if (t === "postgres") return `${
|
|
830
|
-
let { sorted:
|
|
831
|
-
for (let e of
|
|
832
|
-
if (!
|
|
833
|
-
for (let e of
|
|
828
|
+
let a = on(t, i), o = Dn(n, t, r, a), s = O(n, t);
|
|
829
|
+
if (t === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${En(e, t)}`;
|
|
830
|
+
let { sorted: c, cyclic: l } = bn(e), u = Sn(l, t), d = [o];
|
|
831
|
+
for (let e of c) d.push(sn(e, t, n, u.get(e.tableName), a));
|
|
832
|
+
if (!b(t)) for (let e of l) d.push(xn(e, t, n));
|
|
833
|
+
for (let e of c) {
|
|
834
834
|
let r = dn(e, t, n);
|
|
835
|
-
r &&
|
|
835
|
+
r && d.push(r);
|
|
836
836
|
}
|
|
837
|
-
return
|
|
837
|
+
return d.join("\n\n") + "\n";
|
|
838
838
|
}, kn = (e, t, n = Rt) => {
|
|
839
839
|
let { sorted: r, cyclic: i } = bn(e), a = Sn(i, t), o = [], s = wn(r, t);
|
|
840
840
|
s && o.push(s);
|
|
@@ -904,7 +904,7 @@ BEGIN
|
|
|
904
904
|
let i = On(e, n, t, void 0, { charset: r.charset }), a = yield* A.SqlClient;
|
|
905
905
|
yield* bt(a, Rn(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(k.orDie);
|
|
906
906
|
}), Hn = async (e, t, n, r = "postgres", i = {}) => {
|
|
907
|
-
await k.runPromise(Vn(e, t, r, i).pipe(k.provide(n))), await
|
|
907
|
+
await k.runPromise(Vn(e, t, r, i).pipe(k.provide(n))), await c({
|
|
908
908
|
namespace: t,
|
|
909
909
|
dialect: r
|
|
910
910
|
});
|
|
@@ -1068,7 +1068,7 @@ BEGIN
|
|
|
1068
1068
|
...t.spatial === void 0 ? {} : { spatial: rr(t.spatial) },
|
|
1069
1069
|
...t.enumValues === void 0 ? {} : { enumValues: [...t.enumValues].sort() }
|
|
1070
1070
|
};
|
|
1071
|
-
}, hr = (e) => e.columns.filter((e) => !
|
|
1071
|
+
}, hr = (e) => e.columns.filter((e) => !r(e.name)).map((t) => mr(er(t, qn(e, t)))).sort((e, t) => e.name.localeCompare(t.name)), gr = (e) => [...e].map(ar).sort((e, t) => e.name.localeCompare(t.name)), _r = (e) => [...e].filter((e) => !r(e.name)).map((e) => ({
|
|
1072
1072
|
name: e.name,
|
|
1073
1073
|
columns: hr(e),
|
|
1074
1074
|
indexes: gr(e.indexes)
|
|
@@ -1093,24 +1093,24 @@ BEGIN
|
|
|
1093
1093
|
column: e.name,
|
|
1094
1094
|
charset: e.charset
|
|
1095
1095
|
}]), wr = "utf8mb4", Tr = (e) => e.columns.some((e) => e.type === "json" || e.type === "array" || e.storageType === "json"), Er = (e) => {
|
|
1096
|
-
if (!
|
|
1096
|
+
if (!i(e.dialect)) return [];
|
|
1097
1097
|
let t = [];
|
|
1098
1098
|
for (let n of [...e.live.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1099
|
-
if (
|
|
1100
|
-
let
|
|
1101
|
-
if (
|
|
1099
|
+
if (r(n.name)) continue;
|
|
1100
|
+
let i = Cr(n);
|
|
1101
|
+
if (i.length === 0) continue;
|
|
1102
1102
|
if (e.charset !== void 0) {
|
|
1103
|
-
let
|
|
1104
|
-
|
|
1103
|
+
let r = i.filter((t) => t.charset !== e.charset);
|
|
1104
|
+
r.length > 0 && t.push({
|
|
1105
1105
|
table: n.name,
|
|
1106
1106
|
kind: "disagrees-with-declaration",
|
|
1107
|
-
columns:
|
|
1107
|
+
columns: r,
|
|
1108
1108
|
expected: e.charset
|
|
1109
1109
|
});
|
|
1110
1110
|
continue;
|
|
1111
1111
|
}
|
|
1112
1112
|
if (Tr(n)) {
|
|
1113
|
-
let e =
|
|
1113
|
+
let e = i.filter((e) => e.charset !== wr);
|
|
1114
1114
|
e.length > 0 && t.push({
|
|
1115
1115
|
table: n.name,
|
|
1116
1116
|
kind: "json-outruns-text",
|
|
@@ -1119,12 +1119,12 @@ BEGIN
|
|
|
1119
1119
|
});
|
|
1120
1120
|
continue;
|
|
1121
1121
|
}
|
|
1122
|
-
let
|
|
1123
|
-
|
|
1122
|
+
let a = new Set(i.map((e) => e.charset));
|
|
1123
|
+
a.size > 1 && t.push({
|
|
1124
1124
|
table: n.name,
|
|
1125
1125
|
kind: "mixed",
|
|
1126
|
-
columns:
|
|
1127
|
-
expected: [...
|
|
1126
|
+
columns: i,
|
|
1127
|
+
expected: [...a].sort().join(" / ")
|
|
1128
1128
|
});
|
|
1129
1129
|
}
|
|
1130
1130
|
return t;
|
|
@@ -1221,7 +1221,7 @@ BEGIN
|
|
|
1221
1221
|
let r = n;
|
|
1222
1222
|
if (r.dropped || !r.references || r.fkAutoIndex === !1 || c.has(t)) continue;
|
|
1223
1223
|
let a = `${e.tableName}_${t}_idx`;
|
|
1224
|
-
|
|
1224
|
+
p(e.tableName, a, !0, [t]), i({
|
|
1225
1225
|
name: a,
|
|
1226
1226
|
table: e.tableName,
|
|
1227
1227
|
columns: [t],
|
|
@@ -1256,7 +1256,7 @@ BEGIN
|
|
|
1256
1256
|
}
|
|
1257
1257
|
}, Nr = (e, t, n = {}) => {
|
|
1258
1258
|
if (n.charset !== void 0 && t !== "mysql" && t !== "mariadb") throw Error(`store charset '${n.charset}' is declared for a ${t ?? "dialect-less"} store — a character set is a MySQL / MariaDB setting. Remove \`charset\` from \`store\` in app.config.ts, or declare \`store: { dialect: 'mysql' | 'mariadb', charset }\`.`);
|
|
1259
|
-
let r = e.filter((e) => !
|
|
1259
|
+
let r = e.filter((e) => !ee(e.tableName)).map((e) => jr(Ge(e, t), t));
|
|
1260
1260
|
if (t === "mysql" || t === "mariadb") {
|
|
1261
1261
|
for (let e of r) for (let n of e.indexes) if (n.where !== void 0) throw Error(`Partial index '${n.name}' on '${e.name}' is not supported by ${t}. Use uniqueActive for portable conditional uniqueness.`);
|
|
1262
1262
|
}
|
|
@@ -1271,7 +1271,7 @@ BEGIN
|
|
|
1271
1271
|
if (t === "mssql" && !e.generatedAs && (e.type === "json" || e.type === "array") && (e = {
|
|
1272
1272
|
...e,
|
|
1273
1273
|
jsonValidation: e.type === "json" ? "value" : "container"
|
|
1274
|
-
}),
|
|
1274
|
+
}), b(t)) {
|
|
1275
1275
|
if (e.maxLength === void 0) return e;
|
|
1276
1276
|
let { maxLength: t, ...n } = e;
|
|
1277
1277
|
return n;
|
|
@@ -1380,7 +1380,7 @@ BEGIN
|
|
|
1380
1380
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1381
1381
|
let i = [...n].sort(), a = [...r].sort();
|
|
1382
1382
|
return i.every((e, t) => e === a[t]);
|
|
1383
|
-
}, Ur = (e, t, n, r) => n === void 0 ||
|
|
1383
|
+
}, Ur = (e, t, n, r) => n === void 0 || b(n) ? !0 : e.type !== "text" || !$n(t) || dr(e, n, r) === t.maxLength, Wr = (e, t, n, r, i = !1) => (!nr(e) || e.type === t.type || tr(e, t, i)) && er(e, i).idStorage === er(t, !1).idStorage && e.nullable === t.nullable && (e.unique === t.unique || tr(e, t, i)) && e.jsonValidation === t.jsonValidation && (t.enumValues === void 0 || e.enumValues === void 0 || e.enumValues.length === t.enumValues.length && e.enumValues.every((e) => t.enumValues.includes(e))) && (t.precision === void 0 || e.precision === t.precision && (e.scale ?? 0) === (t.scale ?? 0)) && ir(e.spatial, t.spatial) && (e.storageType !== void 0 || t.storageType !== void 0 || t.arrayElement === void 0 || e.arrayElement === void 0 || e.arrayElement === t.arrayElement) && (t.vectorDim === void 0 || e.vectorDim === t.vectorDim) && (e.vectorPrecision ?? "float32") === (t.vectorPrecision ?? "float32") && Vr(e, t) && Ur(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(ur(e.references)) === JSON.stringify(ur(t.references)) && Hr(e.oneOf, t.oneOf), Gr = (e, t) => t.oneOf && t.oneOf.length > 0 ? L({
|
|
1384
1384
|
kind: "add-check",
|
|
1385
1385
|
table: e,
|
|
1386
1386
|
column: t.name,
|
|
@@ -1475,7 +1475,7 @@ BEGIN
|
|
|
1475
1475
|
let n = e.type;
|
|
1476
1476
|
if (n === "id") return Qn(e) === "numeric" ? "bigint" : "text";
|
|
1477
1477
|
if (n === "array") return t === void 0 || t === "postgres" ? "array" : t === "mysql" || t === "mariadb" ? "json" : "text";
|
|
1478
|
-
if (n === "enum") return t === "mssql" ||
|
|
1478
|
+
if (n === "enum") return t === "mssql" || b(t ?? "postgres") ? "text" : "enum";
|
|
1479
1479
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
1480
1480
|
switch (t) {
|
|
1481
1481
|
case "sqlite":
|
|
@@ -1534,7 +1534,7 @@ BEGIN
|
|
|
1534
1534
|
o.push(L(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: ri(n.type, t, r) }));
|
|
1535
1535
|
}
|
|
1536
1536
|
}
|
|
1537
|
-
if (t.type === "text" && $n(n) && !
|
|
1537
|
+
if (t.type === "text" && $n(n) && !b(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1538
1538
|
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})`;
|
|
1539
1539
|
o.push(L({
|
|
1540
1540
|
kind: "alter-column-type",
|
|
@@ -1806,18 +1806,18 @@ BEGIN
|
|
|
1806
1806
|
return n === void 0 ? [] : [n.getTime()];
|
|
1807
1807
|
}), i = new Date(Math.max(...r)), a = new Date(Date.UTC(i.getUTCFullYear(), i.getUTCMonth(), i.getUTCDate() + 1)).toISOString().slice(0, 10);
|
|
1808
1808
|
return `${t.join("; ")}. Reclaim the snapshots first — \`voltro db gc-snapshots --before ${a}\` drops every snapshot older than that date, so run it with --dry-run to see the list — or, if a snapshot's data is still wanted, bring it back with \`voltro db restore-snapshot <plan-id>\` and declare it, so it converts in the same plan.`;
|
|
1809
|
-
}, hi = (e, t, n,
|
|
1810
|
-
let
|
|
1811
|
-
for (let
|
|
1812
|
-
let e = t.get(
|
|
1809
|
+
}, hi = (e, t, n, i) => {
|
|
1810
|
+
let a = /* @__PURE__ */ new Map();
|
|
1811
|
+
for (let r of e.tables) {
|
|
1812
|
+
let e = t.get(r.name) ?? (n.has(r.name) ? t.get(n.get(r.name)) : void 0);
|
|
1813
1813
|
if (e === void 0) continue;
|
|
1814
|
-
let o = new Set(
|
|
1815
|
-
Cr(e).filter((e) => o.has(e.column) && e.charset !==
|
|
1816
|
-
declared:
|
|
1814
|
+
let o = new Set(r.columns.filter(xr).map((e) => e.name));
|
|
1815
|
+
Cr(e).filter((e) => o.has(e.column) && e.charset !== i).length > 0 && a.set(r.name, {
|
|
1816
|
+
declared: r,
|
|
1817
1817
|
live: e
|
|
1818
1818
|
});
|
|
1819
1819
|
}
|
|
1820
|
-
if (
|
|
1820
|
+
if (a.size === 0) return [];
|
|
1821
1821
|
let o = [];
|
|
1822
1822
|
for (let e of t.values()) for (let n of e.columns) {
|
|
1823
1823
|
if (n.references === void 0) continue;
|
|
@@ -1836,110 +1836,110 @@ BEGIN
|
|
|
1836
1836
|
});
|
|
1837
1837
|
}
|
|
1838
1838
|
let s = [];
|
|
1839
|
-
for (let [e, { declared: t, live: n }] of
|
|
1839
|
+
for (let [e, { declared: t, live: n }] of a) {
|
|
1840
1840
|
let c = t.columns.filter(xr).map((e) => e.name), l = new Map(n.columns.map((e) => [e.name, e])), u = [...new Set(c.flatMap((e) => {
|
|
1841
1841
|
let t = l.get(e);
|
|
1842
1842
|
return t?.charset === void 0 ? [] : [t.charset];
|
|
1843
1843
|
}))].sort(), d = c.filter((e) => l.has(e)), f = o.filter((t) => t.table === e || t.targetTable === e), p = [], m = [], h = f.map((t) => {
|
|
1844
|
-
let n = t.table === e ? t.targetTable : t.table, o = n === e ||
|
|
1845
|
-
if (!o && s !== void 0 && s !==
|
|
1844
|
+
let n = t.table === e ? t.targetTable : t.table, o = n === e || a.has(n), s = t.table === e ? t.targetCharset : t.sourceCharset;
|
|
1845
|
+
if (!o && s !== void 0 && s !== i) {
|
|
1846
1846
|
let e = `${t.name} (${t.table}.${t.column} → ${t.targetTable}.${t.targetColumn})`;
|
|
1847
|
-
|
|
1847
|
+
r(n) ? m.push(`${e}: "${n}" is a soft-drop snapshot, stored ${s}`) : p.push(`${e}: "${n}" stays ${s} — it is not a declared table, so the plan does not convert it`);
|
|
1848
1848
|
}
|
|
1849
1849
|
let { sourceCharset: c, targetCharset: l, ...u } = t, d = o && n !== e && n.localeCompare(e) > 0 ? "peer" : "here";
|
|
1850
1850
|
return {
|
|
1851
1851
|
...u,
|
|
1852
1852
|
restore: d
|
|
1853
1853
|
};
|
|
1854
|
-
}), g =
|
|
1854
|
+
}), g = i === "utf8mb4", _ = `table rewrite: ${d.length} string column${d.length === 1 ? "" : "s"} ${u.join("/")} → ${i}` + (h.length > 0 ? `; ${h.length} foreign key${h.length === 1 ? "" : "s"} dropped and re-created around it` : ""), v = {
|
|
1855
1855
|
kind: "convert-charset",
|
|
1856
1856
|
table: e,
|
|
1857
|
-
charset:
|
|
1857
|
+
charset: i,
|
|
1858
1858
|
columns: d,
|
|
1859
1859
|
from: u,
|
|
1860
1860
|
foreignKeys: h
|
|
1861
1861
|
};
|
|
1862
1862
|
if (p.length > 0 || m.length > 0) {
|
|
1863
1863
|
let t = [...p.length > 0 ? [`${p.join("; ")}. Declare that table so it converts in the same plan, convert it by hand first, or leave the store charset undeclared.`] : [], ...m.length > 0 ? [mi(m, f)] : []];
|
|
1864
|
-
s.push(L(v, "lossy", _, { fix: `converting "${e}" to ${
|
|
1864
|
+
s.push(L(v, "lossy", _, { fix: `converting "${e}" to ${i} would break a foreign key the plan cannot carry: ${t.join(" ")}` }));
|
|
1865
1865
|
continue;
|
|
1866
1866
|
}
|
|
1867
|
-
s.push(g ? L(v, "safe", _) : L(v, "lossy", _, { fix: `${e}: narrowing to ${
|
|
1867
|
+
s.push(g ? L(v, "safe", _) : L(v, "lossy", _, { fix: `${e}: narrowing to ${i} can refuse or truncate 4-byte characters the columns already hold. Declare charset: 'utf8mb4' instead, or — after checking the data — allow it with the destructive opt-in (VOLTRO_DESTRUCTIVE_OK=1).` }));
|
|
1868
1868
|
}
|
|
1869
1869
|
return s;
|
|
1870
1870
|
}, gi = (e) => {
|
|
1871
|
-
let t = Nr(e.declared, e.dialect, { charset: e.charset }), n = Br(e.declared, t),
|
|
1872
|
-
|
|
1873
|
-
for (let e of t.tables) if (!
|
|
1874
|
-
|
|
1871
|
+
let t = Nr(e.declared, e.dialect, { charset: e.charset }), n = Br(e.declared, t), i = new Map(e.live.tables.map((e) => [e.name, e])), a = e.onlineAfter ?? $r, s = [], c = di(t, i, n);
|
|
1872
|
+
s.push(...c.ops);
|
|
1873
|
+
for (let e of t.tables) if (!c.renamedInto.has(e.name) && !i.has(e.name)) {
|
|
1874
|
+
s.push(Zr(e.name, e.columns, e.indexes, e.primaryKey, c.refusals.get(e.name)));
|
|
1875
1875
|
for (let t of e.columns) {
|
|
1876
1876
|
let n = Gr(e.name, t);
|
|
1877
|
-
n &&
|
|
1877
|
+
n && s.push(n);
|
|
1878
1878
|
}
|
|
1879
1879
|
}
|
|
1880
|
-
let
|
|
1880
|
+
let l = new Set(e.ignoreTables ?? []), u = [];
|
|
1881
1881
|
for (let t of e.live.tables) if (!n.has(t.name)) {
|
|
1882
|
-
if (
|
|
1882
|
+
if (c.claimedOldNames.has(t.name)) {
|
|
1883
1883
|
u.push(t.name);
|
|
1884
1884
|
continue;
|
|
1885
1885
|
}
|
|
1886
|
-
if (
|
|
1886
|
+
if (o(t.name)) {
|
|
1887
1887
|
u.push(t.name);
|
|
1888
1888
|
continue;
|
|
1889
1889
|
}
|
|
1890
|
-
if (
|
|
1890
|
+
if (r(t.name)) {
|
|
1891
1891
|
u.push(t.name);
|
|
1892
1892
|
continue;
|
|
1893
1893
|
}
|
|
1894
|
-
if (
|
|
1894
|
+
if (l.has(t.name)) {
|
|
1895
1895
|
u.push(t.name);
|
|
1896
1896
|
continue;
|
|
1897
1897
|
}
|
|
1898
|
-
|
|
1898
|
+
s.push(Qr(t.name));
|
|
1899
1899
|
}
|
|
1900
|
-
for (let
|
|
1901
|
-
let t =
|
|
1900
|
+
for (let o of t.tables) {
|
|
1901
|
+
let t = c.renamedInto.get(o.name), l = i.get(o.name) ?? (t === void 0 ? void 0 : i.get(t));
|
|
1902
1902
|
if (!l) continue;
|
|
1903
|
-
let u = fi(l, t,
|
|
1904
|
-
|
|
1905
|
-
let d = u.live, f = n.get(
|
|
1906
|
-
|
|
1903
|
+
let u = fi(l, t, o.name, e.dialect);
|
|
1904
|
+
s.push(...u.ops);
|
|
1905
|
+
let d = u.live, f = n.get(o.name), p = qr(o, d, e.dialect), m = Jr(o, d, e.dialect), h = oi(f.table, f.columnDefs, p);
|
|
1906
|
+
s.push(...h.ops);
|
|
1907
1907
|
for (let { op: t } of h.ops) {
|
|
1908
1908
|
if (t.kind !== "rename-column") continue;
|
|
1909
|
-
let n =
|
|
1910
|
-
n && r &&
|
|
1909
|
+
let n = o.columns.find((e) => e.name === t.to), r = d.columns.find((e) => e.name === t.from);
|
|
1910
|
+
n && r && s.push(...ii(o.name, n, {
|
|
1911
1911
|
...r,
|
|
1912
1912
|
name: t.to
|
|
1913
|
-
}, e.dialect, d.rowCount,
|
|
1913
|
+
}, e.dialect, d.rowCount, a));
|
|
1914
1914
|
}
|
|
1915
1915
|
for (let e of p.removed) {
|
|
1916
|
-
if (h.consumedRemovedNames.has(e.name) ||
|
|
1917
|
-
let t = f.columnDefs[e.name], n = Xr(
|
|
1918
|
-
e.references !== void 0 &&
|
|
1916
|
+
if (h.consumedRemovedNames.has(e.name) || r(e.name)) continue;
|
|
1917
|
+
let t = f.columnDefs[e.name], n = Xr(o.name, e, t);
|
|
1918
|
+
e.references !== void 0 && s.push({
|
|
1919
1919
|
...L({
|
|
1920
1920
|
kind: "drop-foreign-key",
|
|
1921
|
-
table:
|
|
1921
|
+
table: o.name,
|
|
1922
1922
|
column: e.name,
|
|
1923
1923
|
...e.references.constraintName === void 0 ? {} : { name: e.references.constraintName }
|
|
1924
|
-
}, n.blocked === void 0 ? "safe" : n.classification, `drop FK on ${
|
|
1924
|
+
}, n.blocked === void 0 ? "safe" : n.classification, `drop FK on ${o.name}.${e.name} (→ ${e.references.table}) before dropping the column`),
|
|
1925
1925
|
...n.blocked === void 0 ? {} : { blocked: n.blocked }
|
|
1926
|
-
}),
|
|
1926
|
+
}), s.push(n);
|
|
1927
1927
|
}
|
|
1928
1928
|
for (let e of p.added) {
|
|
1929
1929
|
if (h.consumedAddedNames.has(e.name)) continue;
|
|
1930
1930
|
let t = f.columnDefs[e.name];
|
|
1931
|
-
|
|
1932
|
-
let n = Gr(
|
|
1933
|
-
n &&
|
|
1931
|
+
s.push(Yr(o.name, e, t));
|
|
1932
|
+
let n = Gr(o.name, e);
|
|
1933
|
+
n && s.push(n), s.push(...ai(o.name, e));
|
|
1934
1934
|
}
|
|
1935
|
-
let g = new Map(h.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), _ = ui(
|
|
1936
|
-
|
|
1937
|
-
for (let e of m.added) _.consumedAddedNames.has(e.name) ||
|
|
1938
|
-
for (let e of m.removed) _.consumedRemovedNames.has(e.name) ||
|
|
1939
|
-
for (let { declared: t, live: n } of p.changed)
|
|
1940
|
-
}
|
|
1941
|
-
e.charset !== void 0 &&
|
|
1942
|
-
let d = new Set(
|
|
1935
|
+
let g = new Map(h.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), _ = ui(o.name, m, g, new Set(d.indexes.map((e) => e.name)), e.dialect);
|
|
1936
|
+
s.push(..._.ops);
|
|
1937
|
+
for (let e of m.added) _.consumedAddedNames.has(e.name) || s.push(ei(o.name, e, d.rowCount, a));
|
|
1938
|
+
for (let e of m.removed) _.consumedRemovedNames.has(e.name) || s.push(ti(o.name, e));
|
|
1939
|
+
for (let { declared: t, live: n } of p.changed) s.push(...ii(o.name, t, n, e.dialect, d.rowCount, a));
|
|
1940
|
+
}
|
|
1941
|
+
e.charset !== void 0 && s.push(...hi(t, i, c.renamedInto, e.charset));
|
|
1942
|
+
let d = new Set(s.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), f = new Map(t.tables.map((e) => [e.name, e])), p = (e) => {
|
|
1943
1943
|
let t = f.get(e);
|
|
1944
1944
|
return t ? t.columns.flatMap((e) => e.references && d.has(e.references.table) ? [{
|
|
1945
1945
|
column: e.name,
|
|
@@ -1957,13 +1957,13 @@ BEGIN
|
|
|
1957
1957
|
}, "safe", `deferred FK ${e.name}.${t.name} → ${t.references.table} — breaks a create-time table cycle`));
|
|
1958
1958
|
if (m.size > 0) {
|
|
1959
1959
|
let e = (e) => e.references ? Object.fromEntries(Object.entries(e).filter(([e]) => e !== "references")) : e;
|
|
1960
|
-
for (let t = 0; t <
|
|
1961
|
-
let n =
|
|
1960
|
+
for (let t = 0; t < s.length; t += 1) {
|
|
1961
|
+
let n = s[t];
|
|
1962
1962
|
if (n.op.kind !== "create-table") continue;
|
|
1963
1963
|
let r = n.op;
|
|
1964
1964
|
if (!r.columns.some((e) => m.has(j(r.table, e.name)))) continue;
|
|
1965
1965
|
let i = r.columns.map((t) => m.has(j(r.table, t.name)) ? e(t) : t);
|
|
1966
|
-
|
|
1966
|
+
s[t] = {
|
|
1967
1967
|
...n,
|
|
1968
1968
|
op: {
|
|
1969
1969
|
...r,
|
|
@@ -1971,7 +1971,7 @@ BEGIN
|
|
|
1971
1971
|
}
|
|
1972
1972
|
};
|
|
1973
1973
|
}
|
|
1974
|
-
|
|
1974
|
+
s.push(...h);
|
|
1975
1975
|
}
|
|
1976
1976
|
let g = new Map(t.tables.map((e) => [e.name, e])), _ = /* @__PURE__ */ new Map(), v = (e, t = /* @__PURE__ */ new Set()) => {
|
|
1977
1977
|
let n = _.get(e);
|
|
@@ -1985,10 +1985,10 @@ BEGIN
|
|
|
1985
1985
|
n && n !== e && !m.has(j(e, t.name)) && (a = Math.max(a, v(n, i) + 1));
|
|
1986
1986
|
}
|
|
1987
1987
|
return _.set(e, a), a;
|
|
1988
|
-
}, y = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1,
|
|
1988
|
+
}, y = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, ee = (e) => {
|
|
1989
1989
|
let t = "table" in e ? e.table : "";
|
|
1990
1990
|
return e.kind === "create-table" ? v(t) : e.kind === "drop-table" ? -v(t) : 0;
|
|
1991
|
-
},
|
|
1991
|
+
}, b = {
|
|
1992
1992
|
"add-column": 0,
|
|
1993
1993
|
"rename-column": 1,
|
|
1994
1994
|
"rename-index": 1,
|
|
@@ -2008,41 +2008,41 @@ BEGIN
|
|
|
2008
2008
|
"add-foreign-key": 6,
|
|
2009
2009
|
"add-check": 6,
|
|
2010
2010
|
"reconcile-json-check": 6
|
|
2011
|
-
},
|
|
2011
|
+
}, x = (e) => b[e] ?? 9, S = [...s].sort((e, t) => {
|
|
2012
2012
|
let n = y(e.op.kind), r = y(t.op.kind);
|
|
2013
2013
|
if (n !== r) return n - r;
|
|
2014
|
-
let i =
|
|
2014
|
+
let i = ee(e.op), a = ee(t.op);
|
|
2015
2015
|
if (i !== a) return i - a;
|
|
2016
2016
|
let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
|
|
2017
2017
|
if (o !== s) return o.localeCompare(s);
|
|
2018
|
-
let c =
|
|
2018
|
+
let c = x(e.op.kind), l = x(t.op.kind);
|
|
2019
2019
|
return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
|
|
2020
|
-
}),
|
|
2021
|
-
for (let e of
|
|
2022
|
-
let
|
|
2020
|
+
}), C = /* @__PURE__ */ new Set();
|
|
2021
|
+
for (let e of S) "table" in e.op && C.add(e.op.table);
|
|
2022
|
+
let w = [];
|
|
2023
2023
|
for (let e of t.tables) {
|
|
2024
|
-
if (
|
|
2025
|
-
let t =
|
|
2026
|
-
t !== void 0 && I({ tables: [t] }) !== I({ tables: [e] }) &&
|
|
2024
|
+
if (C.has(e.name) || c.renamedInto.has(e.name)) continue;
|
|
2025
|
+
let t = i.get(e.name);
|
|
2026
|
+
t !== void 0 && I({ tables: [t] }) !== I({ tables: [e] }) && w.push(e.name);
|
|
2027
2027
|
}
|
|
2028
2028
|
return {
|
|
2029
|
-
operations:
|
|
2029
|
+
operations: S,
|
|
2030
2030
|
fromFingerprint: I(e.live),
|
|
2031
2031
|
toFingerprint: I(t),
|
|
2032
|
-
summary: pi(
|
|
2032
|
+
summary: pi(S),
|
|
2033
2033
|
fingerprintDivergence: {
|
|
2034
2034
|
outsideDiff: u,
|
|
2035
|
-
diffEquivalent:
|
|
2035
|
+
diffEquivalent: w
|
|
2036
2036
|
}
|
|
2037
2037
|
};
|
|
2038
|
-
}, R = "_voltro_deploys", _i =
|
|
2039
|
-
id:
|
|
2040
|
-
status:
|
|
2041
|
-
dialect:
|
|
2042
|
-
appliedBy:
|
|
2043
|
-
startedAt:
|
|
2044
|
-
baseline:
|
|
2045
|
-
report:
|
|
2038
|
+
}, R = "_voltro_deploys", _i = g(R, {
|
|
2039
|
+
id: x({ prefix: "dpl" }),
|
|
2040
|
+
status: n(),
|
|
2041
|
+
dialect: n(),
|
|
2042
|
+
appliedBy: n(),
|
|
2043
|
+
startedAt: n(),
|
|
2044
|
+
baseline: n(),
|
|
2045
|
+
report: n().nullable()
|
|
2046
2046
|
}), vi = (e, t) => e`INSERT INTO ${e(R)} (${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")})
|
|
2047
2047
|
VALUES (${t.id}, ${"running"}, ${t.dialect}, ${t.appliedBy}, ${(/* @__PURE__ */ new Date()).toISOString()}, ${t.baseline}, ${null})`.pipe(k.asVoid), yi = (e, t) => e`DELETE FROM ${e(R)} WHERE ${e("id")} = ${t}`.pipe(k.asVoid), bi = (e, t, n) => e`UPDATE ${e(R)} SET ${e("status")} = ${"failed"}, ${e("report")} = ${n} WHERE ${e("id")} = ${t}`.pipe(k.asVoid), xi = (e) => e`SELECT ${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")} FROM ${e(R)}`.pipe(k.map((e) => e.map((e) => ({
|
|
2048
2048
|
...e,
|
|
@@ -2219,7 +2219,7 @@ BEGIN
|
|
|
2219
2219
|
let t = Ci(e.def, e.column_name);
|
|
2220
2220
|
t !== null && y.set(`${e.table_name}.${e.column_name}`, t);
|
|
2221
2221
|
}
|
|
2222
|
-
let
|
|
2222
|
+
let ee = yield* a(l, (t) => e`
|
|
2223
2223
|
SELECT
|
|
2224
2224
|
rel.relname AS source_table,
|
|
2225
2225
|
att.attname AS source_column,
|
|
@@ -2245,7 +2245,7 @@ BEGIN
|
|
|
2245
2245
|
WHERE con.contype = 'f' AND nsp.nspname = current_schema()
|
|
2246
2246
|
AND rel.relname IN ${t}
|
|
2247
2247
|
ORDER BY rel.relname, con.conname, ck.ord
|
|
2248
|
-
`),
|
|
2248
|
+
`), b = yield* a(l, (t) => e`
|
|
2249
2249
|
WITH ix AS (
|
|
2250
2250
|
SELECT
|
|
2251
2251
|
c.relname AS table_name,
|
|
@@ -2286,34 +2286,34 @@ BEGIN
|
|
|
2286
2286
|
AND c.relname IN ${t}
|
|
2287
2287
|
)
|
|
2288
2288
|
SELECT * FROM ix ORDER BY table_name, index_name, position
|
|
2289
|
-
`),
|
|
2289
|
+
`), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), te = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Map();
|
|
2290
2290
|
for (let e of u) {
|
|
2291
|
-
let t =
|
|
2292
|
-
t || (t = [],
|
|
2291
|
+
let t = x.get(e.table_name);
|
|
2292
|
+
t || (t = [], x.set(e.table_name, t)), t.push(e);
|
|
2293
2293
|
}
|
|
2294
2294
|
for (let e of d) {
|
|
2295
|
-
let t =
|
|
2296
|
-
t || (t = /* @__PURE__ */ new Set(),
|
|
2295
|
+
let t = S.get(e.table_name);
|
|
2296
|
+
t || (t = /* @__PURE__ */ new Set(), S.set(e.table_name, t)), t.add(e.column_name);
|
|
2297
2297
|
}
|
|
2298
|
-
let
|
|
2298
|
+
let E = /* @__PURE__ */ new Map();
|
|
2299
2299
|
for (let e of f) {
|
|
2300
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
2300
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = E.get(t);
|
|
2301
2301
|
n || (n = {
|
|
2302
2302
|
table: e.table_name,
|
|
2303
2303
|
columns: []
|
|
2304
|
-
},
|
|
2304
|
+
}, E.set(t, n)), n.columns.push({
|
|
2305
2305
|
name: e.column_name,
|
|
2306
2306
|
position: e.position
|
|
2307
2307
|
});
|
|
2308
2308
|
}
|
|
2309
|
-
for (let [e, t] of
|
|
2309
|
+
for (let [e, t] of E) {
|
|
2310
2310
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
2311
2311
|
if (n.length === 1) {
|
|
2312
|
-
let e =
|
|
2313
|
-
e || (e = /* @__PURE__ */ new Set(),
|
|
2312
|
+
let e = C.get(t.table);
|
|
2313
|
+
e || (e = /* @__PURE__ */ new Set(), C.set(t.table, e)), e.add(n[0]);
|
|
2314
2314
|
} else {
|
|
2315
|
-
let r =
|
|
2316
|
-
r || (r = [],
|
|
2315
|
+
let r = w.get(t.table);
|
|
2316
|
+
r || (r = [], w.set(t.table, r)), r.push({
|
|
2317
2317
|
name: e.slice(e.indexOf("\0") + 1),
|
|
2318
2318
|
table: t.table,
|
|
2319
2319
|
columns: n,
|
|
@@ -2321,19 +2321,19 @@ BEGIN
|
|
|
2321
2321
|
});
|
|
2322
2322
|
}
|
|
2323
2323
|
}
|
|
2324
|
-
for (let e of
|
|
2325
|
-
let t =
|
|
2326
|
-
t || (t = [],
|
|
2324
|
+
for (let e of ee) {
|
|
2325
|
+
let t = te.get(e.source_table);
|
|
2326
|
+
t || (t = [], te.set(e.source_table, t)), t.push(e);
|
|
2327
2327
|
}
|
|
2328
|
-
for (let e of
|
|
2329
|
-
let t =
|
|
2330
|
-
t || (t = /* @__PURE__ */ new Map(),
|
|
2328
|
+
for (let e of b) {
|
|
2329
|
+
let t = T.get(e.table_name);
|
|
2330
|
+
t || (t = /* @__PURE__ */ new Map(), T.set(e.table_name, t));
|
|
2331
2331
|
let n = t.get(e.index_name);
|
|
2332
2332
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
2333
2333
|
}
|
|
2334
|
-
let
|
|
2334
|
+
let ne = [];
|
|
2335
2335
|
for (let e of c) {
|
|
2336
|
-
let t = /* @__PURE__ */ new Set(), n = (
|
|
2336
|
+
let t = /* @__PURE__ */ new Set(), n = (x.get(e.table_name) ?? []).filter((e) => !t.has(e.column_name) && (t.add(e.column_name), !0)), r = S.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = C.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = te.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) => {
|
|
2337
2337
|
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = t.data_type === "USER-DEFINED" && t.udt_name !== void 0 && g.has(t.udt_name), c = s ? "enum" : Ti(t.data_type, t.udt_name), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : c, d = a ? {
|
|
2338
2338
|
table: a.target_table,
|
|
2339
2339
|
column: a.target_column,
|
|
@@ -2355,7 +2355,7 @@ BEGIN
|
|
|
2355
2355
|
vectorPrecision: t.udt_name === "halfvec" ? "half" : "float32",
|
|
2356
2356
|
...t.type_modifier !== void 0 && t.type_modifier > 0 ? { vectorDim: t.type_modifier } : {}
|
|
2357
2357
|
} : {},
|
|
2358
|
-
...
|
|
2358
|
+
...Ji(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ji(t.data_type, t.character_maximum_length) },
|
|
2359
2359
|
...c === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2360
2360
|
precision: t.numeric_precision,
|
|
2361
2361
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2369,7 +2369,7 @@ BEGIN
|
|
|
2369
2369
|
...f ? { oneOf: f } : {},
|
|
2370
2370
|
...Oi(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
2371
2371
|
};
|
|
2372
|
-
}), l = [], u =
|
|
2372
|
+
}), l = [], u = T.get(e.table_name);
|
|
2373
2373
|
if (u) for (let [t, n] of u) {
|
|
2374
2374
|
let r = /* @__PURE__ */ new Set(), i = [...n].filter((e) => e.column_name !== null && e.position !== null).sort((e, t) => (e.position ?? 0) - (t.position ?? 0)).filter((e) => {
|
|
2375
2375
|
let t = e.position;
|
|
@@ -2396,7 +2396,7 @@ BEGIN
|
|
|
2396
2396
|
...a ? { expression: !0 } : {}
|
|
2397
2397
|
});
|
|
2398
2398
|
}
|
|
2399
|
-
for (let t of
|
|
2399
|
+
for (let t of w.get(e.table_name) ?? []) l.push(t);
|
|
2400
2400
|
r.size > 0 && l.push({
|
|
2401
2401
|
name: `${e.table_name}_pkey`,
|
|
2402
2402
|
table: e.table_name,
|
|
@@ -2404,14 +2404,14 @@ BEGIN
|
|
|
2404
2404
|
unique: !0
|
|
2405
2405
|
});
|
|
2406
2406
|
let d = Number(e.row_count ?? 0);
|
|
2407
|
-
|
|
2407
|
+
ne.push({
|
|
2408
2408
|
name: e.table_name,
|
|
2409
2409
|
columns: c,
|
|
2410
2410
|
indexes: l,
|
|
2411
2411
|
...d > 0 ? { rowCount: d } : {}
|
|
2412
2412
|
});
|
|
2413
2413
|
}
|
|
2414
|
-
return { tables:
|
|
2414
|
+
return { tables: ne };
|
|
2415
2415
|
});
|
|
2416
2416
|
return (t > 0 ? e.withTransaction(n) : n).pipe(k.catchAll((e) => {
|
|
2417
2417
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
@@ -2478,7 +2478,7 @@ BEGIN
|
|
|
2478
2478
|
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = Li(yield* e`
|
|
2479
2479
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
2480
2480
|
FROM information_schema.statistics
|
|
2481
|
-
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
2481
|
+
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY' AND index_type <> 'FULLTEXT'
|
|
2482
2482
|
ORDER BY table_name, index_name, seq_in_index`), a = e`
|
|
2483
2483
|
SELECT cc.table_name AS table_name, cc.check_clause AS check_clause
|
|
2484
2484
|
FROM information_schema.check_constraints cc
|
|
@@ -2531,7 +2531,7 @@ BEGIN
|
|
|
2531
2531
|
...u ? { idStorage: Yn(s) } : {},
|
|
2532
2532
|
...d === "enum" && g !== void 0 ? { enumValues: g } : {},
|
|
2533
2533
|
nullable: t.is_nullable === "YES",
|
|
2534
|
-
...
|
|
2534
|
+
...Ji(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ji(t.data_type, t.character_maximum_length) },
|
|
2535
2535
|
...s === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2536
2536
|
precision: t.numeric_precision,
|
|
2537
2537
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2573,18 +2573,27 @@ BEGIN
|
|
|
2573
2573
|
}), zi = (e) => {
|
|
2574
2574
|
let t = e.toUpperCase();
|
|
2575
2575
|
return t.includes("INT") ? "integer" : t.includes("CHAR") || t.includes("CLOB") || t.includes("TEXT") ? "text" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : /^(NUMERIC|DECIMAL)\b/.test(t.trim()) ? "decimal" : "text";
|
|
2576
|
-
}, Bi = (e) => e === 1 || e === !0, Vi =
|
|
2576
|
+
}, Bi = (e) => e === 1 || e === !0, Vi = [
|
|
2577
|
+
"content",
|
|
2578
|
+
"data",
|
|
2579
|
+
"idx",
|
|
2580
|
+
"config",
|
|
2581
|
+
"docsize",
|
|
2582
|
+
"segments",
|
|
2583
|
+
"segdir",
|
|
2584
|
+
"stat"
|
|
2585
|
+
], Hi = (e) => k.gen(function* () {
|
|
2577
2586
|
let t = yield* e`
|
|
2578
2587
|
SELECT name, sql FROM sqlite_master
|
|
2579
2588
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
2580
|
-
ORDER BY name`, n = (e) => `'${e.replace(/'/g, "''")}'`, r = [];
|
|
2581
|
-
for (let { name: i, sql:
|
|
2589
|
+
ORDER BY name`, n = (e) => `'${e.replace(/'/g, "''")}'`, r = [], i = t.filter((e) => /^\s*CREATE\s+VIRTUAL\s+TABLE\b/i.test(e.sql ?? "")).map((e) => e.name), a = (e) => i.includes(e) || i.some((t) => Vi.some((n) => e === `${t}_${n}`));
|
|
2590
|
+
for (let { name: i, sql: o } of t.filter((e) => !a(e.name))) {
|
|
2582
2591
|
let t = /* @__PURE__ */ new Map();
|
|
2583
|
-
for (let e of (
|
|
2592
|
+
for (let e of (o ?? "").matchAll(/CHECK\s*\(\s*"([^"]+)"\s+IN\s*\(([^)]*)\)/gi)) {
|
|
2584
2593
|
let n = [...e[2].matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
|
|
2585
2594
|
n.length > 0 && t.set(e[1], n);
|
|
2586
2595
|
}
|
|
2587
|
-
let
|
|
2596
|
+
let a = yield* e.unsafe(`PRAGMA table_xinfo(${n(i)})`), s = yield* e.unsafe(`PRAGMA foreign_key_list(${n(i)})`), c = yield* e.unsafe(`PRAGMA index_list(${n(i)})`), l = new Map(s.map((e) => [e.from, e])), u = a.filter((e) => e.pk > 0).sort((e, t) => e.pk - t.pk).map((e) => e.name), d = new Map(a.map((e) => [e.name.toLowerCase(), e.name])), f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set();
|
|
2588
2597
|
for (let t of c) {
|
|
2589
2598
|
let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null).map((e) => d.get(e.toLowerCase()) ?? e);
|
|
2590
2599
|
if (f.set(t.name, r), t.partial !== void 0 && Bi(t.partial)) {
|
|
@@ -2593,7 +2602,7 @@ BEGIN
|
|
|
2593
2602
|
}
|
|
2594
2603
|
!p.has(t.name) && Bi(t.unique) && r.length === 1 && m.add(r[0]);
|
|
2595
2604
|
}
|
|
2596
|
-
let h =
|
|
2605
|
+
let h = a.map((e) => {
|
|
2597
2606
|
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = zi(e.type), a = !r && n && e.name === "id", o = r ? "reference" : a ? "id" : i, s = r ? {
|
|
2598
2607
|
table: r.table,
|
|
2599
2608
|
column: r.to,
|
|
@@ -2637,7 +2646,7 @@ BEGIN
|
|
|
2637
2646
|
});
|
|
2638
2647
|
}
|
|
2639
2648
|
return { tables: r };
|
|
2640
|
-
}),
|
|
2649
|
+
}), Ui = (e) => {
|
|
2641
2650
|
switch (e.toLowerCase()) {
|
|
2642
2651
|
case "int":
|
|
2643
2652
|
case "smallint":
|
|
@@ -2659,7 +2668,7 @@ BEGIN
|
|
|
2659
2668
|
case "image": return "bytes";
|
|
2660
2669
|
default: return "text";
|
|
2661
2670
|
}
|
|
2662
|
-
}, z = (e) => e === !0 || e === 1,
|
|
2671
|
+
}, z = (e) => e === !0 || e === 1, Wi = (e) => k.gen(function* () {
|
|
2663
2672
|
let t = yield* e`
|
|
2664
2673
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2665
2674
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -2728,13 +2737,13 @@ BEGIN
|
|
|
2728
2737
|
else t[0].predicate == null && z(t[0].is_unique) && t.length === 1 && m.add(t[0].column_name);
|
|
2729
2738
|
}
|
|
2730
2739
|
let h = t.map((t) => {
|
|
2731
|
-
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o =
|
|
2740
|
+
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o = Ui(t.data_type), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : o, d = a ? {
|
|
2732
2741
|
table: a.target_table,
|
|
2733
2742
|
column: a.target_column,
|
|
2734
|
-
onDelete:
|
|
2735
|
-
onUpdate:
|
|
2743
|
+
onDelete: Gi(a.delete_rule),
|
|
2744
|
+
onUpdate: Gi(a.update_rule),
|
|
2736
2745
|
constraintName: a.constraint_name
|
|
2737
|
-
} : void 0, f = t.column_default === null ? null :
|
|
2746
|
+
} : void 0, f = t.column_default === null ? null : Ki(t.column_default), h = c.get(`${e}.${t.column_name}`), g = s.flatMap((n) => {
|
|
2738
2747
|
if (n.table_name !== e || n.column_name !== null && n.column_name !== t.column_name) return [];
|
|
2739
2748
|
let r = It(t.column_name, n.def);
|
|
2740
2749
|
return r ? [{
|
|
@@ -2749,7 +2758,7 @@ BEGIN
|
|
|
2749
2758
|
type: u,
|
|
2750
2759
|
...l ? { idStorage: Yn(o) } : {},
|
|
2751
2760
|
nullable: t.is_nullable === "YES",
|
|
2752
|
-
...
|
|
2761
|
+
...Ji(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ji(t.data_type, t.character_maximum_length) },
|
|
2753
2762
|
...o === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2754
2763
|
precision: t.numeric_precision,
|
|
2755
2764
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2758,7 +2767,7 @@ BEGIN
|
|
|
2758
2767
|
hasDefault: f !== null,
|
|
2759
2768
|
...f === null ? {} : { defaultValue: f },
|
|
2760
2769
|
...d ? { references: d } : {},
|
|
2761
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2770
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(Ui(t.data_type)) ? "numeric" : "text" } : {},
|
|
2762
2771
|
...h ? { oneOf: h } : {},
|
|
2763
2772
|
...g.length > 0 ? { jsonChecks: g } : {},
|
|
2764
2773
|
..._ ? { jsonValidation: _ } : {},
|
|
@@ -2789,45 +2798,45 @@ BEGIN
|
|
|
2789
2798
|
});
|
|
2790
2799
|
}
|
|
2791
2800
|
return { tables: f };
|
|
2792
|
-
}),
|
|
2801
|
+
}), Gi = (e) => {
|
|
2793
2802
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2794
2803
|
case "CASCADE": return "cascade";
|
|
2795
2804
|
case "SET NULL": return "setNull";
|
|
2796
2805
|
case "SET DEFAULT": return "noAction";
|
|
2797
2806
|
default: return "noAction";
|
|
2798
2807
|
}
|
|
2799
|
-
},
|
|
2808
|
+
}, Ki = (e) => {
|
|
2800
2809
|
let t = e.trim();
|
|
2801
2810
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2802
2811
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2803
|
-
},
|
|
2812
|
+
}, qi = /* @__PURE__ */ new Set([
|
|
2804
2813
|
"character varying",
|
|
2805
2814
|
"varchar",
|
|
2806
2815
|
"nvarchar",
|
|
2807
2816
|
"char",
|
|
2808
2817
|
"character",
|
|
2809
2818
|
"nchar"
|
|
2810
|
-
]),
|
|
2811
|
-
if (!
|
|
2819
|
+
]), Ji = (e, t) => {
|
|
2820
|
+
if (!qi.has(e.toLowerCase())) return;
|
|
2812
2821
|
let n = Number(t);
|
|
2813
2822
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2814
|
-
},
|
|
2823
|
+
}, Yi = /* @__PURE__ */ new Set([
|
|
2815
2824
|
N,
|
|
2816
2825
|
R,
|
|
2817
2826
|
Si,
|
|
2818
2827
|
"_voltro_plugin_migrations"
|
|
2819
2828
|
]), B = (e) => e.onDialectOrElse({
|
|
2820
2829
|
mysql: () => Ri(e),
|
|
2821
|
-
mssql: () =>
|
|
2822
|
-
sqlite: () =>
|
|
2830
|
+
mssql: () => Wi(e),
|
|
2831
|
+
sqlite: () => Hi(e),
|
|
2823
2832
|
orElse: () => Fi(e)
|
|
2824
2833
|
}).pipe(k.map((e) => ({
|
|
2825
2834
|
...e,
|
|
2826
|
-
tables: e.tables.filter((e) => !
|
|
2827
|
-
}))),
|
|
2835
|
+
tables: e.tables.filter((e) => !Yi.has(e.name))
|
|
2836
|
+
}))), Xi = (e, t) => {
|
|
2828
2837
|
let n = M(e);
|
|
2829
2838
|
return (n === "sqlite" ? e`SELECT COUNT(*) AS n FROM sqlite_master WHERE type = 'table' AND name = ${t}` : n === "mysql" ? e`SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ${t}` : n === "mssql" ? e`SELECT COUNT(*) AS n FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = ${t}` : e`SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = ${t}`).pipe(k.map((e) => Number(e[0]?.n ?? 0) > 0));
|
|
2830
|
-
},
|
|
2839
|
+
}, Zi = (e, t) => {
|
|
2831
2840
|
let n = e.op;
|
|
2832
2841
|
if (n.kind !== "drop-column" && n.kind !== "drop-table") return e;
|
|
2833
2842
|
let r = n.kind === "drop-column" ? n.column : n.table, i = t.replace(/[-:T.Z]/g, "").slice(0, 14);
|
|
@@ -2836,7 +2845,7 @@ BEGIN
|
|
|
2836
2845
|
...e,
|
|
2837
2846
|
softDropSnapshot: `${r}__dropped_${i}`
|
|
2838
2847
|
};
|
|
2839
|
-
},
|
|
2848
|
+
}, Qi = (e) => {
|
|
2840
2849
|
if (e.softDropSnapshot === void 0) return;
|
|
2841
2850
|
let t = e.op;
|
|
2842
2851
|
if (t.kind !== "drop-column" && t.kind !== "drop-table") throw Error("Soft-drop snapshot belongs to a non-drop operation");
|
|
@@ -2846,51 +2855,51 @@ BEGIN
|
|
|
2846
2855
|
}, V = (e, t) => {
|
|
2847
2856
|
let n = Math.max(1, Math.floor(Number.isFinite(t) ? t : 1));
|
|
2848
2857
|
return e.literal(M(e) === "mssql" ? `OFFSET 0 ROWS FETCH NEXT ${n} ROWS ONLY` : `LIMIT ${n}`);
|
|
2849
|
-
},
|
|
2850
|
-
let t =
|
|
2851
|
-
return t === void 0 ?
|
|
2852
|
-
}),
|
|
2858
|
+
}, $i = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", ea = /* @__PURE__ */ new WeakMap(), H = (e) => k.suspend(() => {
|
|
2859
|
+
let t = ea.get(e);
|
|
2860
|
+
return t === void 0 ? ta(e).pipe(k.tap((t) => k.sync(() => ea.set(e, t)))) : k.succeed(t);
|
|
2861
|
+
}), ta = (e) => e.unsafe("SELECT VERSION() AS v").pipe(k.map((e) => {
|
|
2853
2862
|
let t = e[0]?.v;
|
|
2854
|
-
return typeof t == "string" ?
|
|
2855
|
-
}), k.catchAll(() => k.succeed("mysql"))),
|
|
2863
|
+
return typeof t == "string" ? $i(t) : "mysql";
|
|
2864
|
+
}), k.catchAll(() => k.succeed("mysql"))), na = (e) => {
|
|
2856
2865
|
let t = e;
|
|
2857
2866
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2858
2867
|
let e = t;
|
|
2859
2868
|
if (typeof e.errno == "number") return e.errno;
|
|
2860
2869
|
t = e.cause;
|
|
2861
2870
|
}
|
|
2862
|
-
},
|
|
2871
|
+
}, ra = (e) => {
|
|
2863
2872
|
let t = [], n = e;
|
|
2864
2873
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2865
2874
|
let e = n;
|
|
2866
2875
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2867
2876
|
}
|
|
2868
2877
|
return t.join(" | ");
|
|
2869
|
-
},
|
|
2878
|
+
}, ia = (e, t) => {
|
|
2870
2879
|
if (t.length === 0) return !1;
|
|
2871
|
-
let n =
|
|
2880
|
+
let n = na(e), r = ra(e);
|
|
2872
2881
|
return t.some((e) => e.errno !== void 0 && n !== void 0 && e.errno.includes(n) || e.messageIncludes !== void 0 && e.messageIncludes.some((e) => r.includes(e)));
|
|
2873
|
-
},
|
|
2882
|
+
}, aa = {
|
|
2874
2883
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2875
2884
|
errno: [1061]
|
|
2876
|
-
},
|
|
2885
|
+
}, oa = {
|
|
2877
2886
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2878
2887
|
errno: [1091]
|
|
2879
|
-
},
|
|
2888
|
+
}, sa = {
|
|
2880
2889
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2881
2890
|
messageIncludes: ["no such column"]
|
|
2882
|
-
},
|
|
2891
|
+
}, ca = {
|
|
2883
2892
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2884
2893
|
errno: [1091, 3940]
|
|
2885
|
-
},
|
|
2894
|
+
}, la = {
|
|
2886
2895
|
why: "mysql/mariadb ADD CONSTRAINT has no IF NOT EXISTS; 1826 is exactly \"already there\"",
|
|
2887
2896
|
errno: [1826]
|
|
2888
|
-
},
|
|
2897
|
+
}, ua = (e, t) => k.suspend(() => {
|
|
2889
2898
|
let n;
|
|
2890
2899
|
return e.withTransaction(t.pipe(k.tapErrorCause((e) => k.sync(() => {
|
|
2891
2900
|
n = e;
|
|
2892
2901
|
})))).pipe(k.catchAllCause((e) => k.failCause(n !== void 0 && !we.equals(n, e) ? Ce.sequential(n, e) : e)));
|
|
2893
|
-
}),
|
|
2902
|
+
}), da = (e, t, n) => {
|
|
2894
2903
|
let r = e.match(/'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|\s+|[^'\[\s]+/g) ?? [];
|
|
2895
2904
|
if (r.join("") !== e || r.some((e) => !e.startsWith("'") && !e.startsWith("[") && /"|\/\*|--/.test(e))) throw Error("Cannot safely rename CHECK: unsupported catalog SQL; use an explicit migration");
|
|
2896
2905
|
let i = r.map((e, t) => ({
|
|
@@ -2898,32 +2907,32 @@ BEGIN
|
|
|
2898
2907
|
index: t
|
|
2899
2908
|
})).filter((e) => e.value.trim() !== ""), a = 0;
|
|
2900
2909
|
for (let e = 0; e < i.length; e++) {
|
|
2901
|
-
let
|
|
2902
|
-
if (
|
|
2903
|
-
let
|
|
2904
|
-
if (
|
|
2905
|
-
r[
|
|
2910
|
+
let o = i[e];
|
|
2911
|
+
if (o.value !== O(t, "mssql")) continue;
|
|
2912
|
+
let s = i[e - 1]?.value ?? "", c = i[e + 1]?.value ?? "";
|
|
2913
|
+
if (s.endsWith(".") || c.startsWith(".") || c.startsWith("(")) throw Error(`Cannot safely rename CHECK reference '${t}': qualified or callable identifier; use an explicit migration`);
|
|
2914
|
+
r[o.index] = O(n, "mssql"), a++;
|
|
2906
2915
|
}
|
|
2907
2916
|
if (a === 0 || r.join("").length === 0) throw Error(`Cannot safely rename CHECK reference '${t}': no exact catalog column token; use an explicit migration`);
|
|
2908
2917
|
return r.join("");
|
|
2909
2918
|
}, U = (e, t) => e.onDialectOrElse({
|
|
2910
2919
|
mysql: () => k.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2911
2920
|
orElse: () => k.succeed(t)
|
|
2912
|
-
}),
|
|
2913
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2921
|
+
}), fa = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, pa = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), ma = (e, t) => {
|
|
2922
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !pa(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2914
2923
|
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;
|
|
2915
2924
|
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.`);
|
|
2916
2925
|
return F(e, t);
|
|
2917
|
-
}, ma = (e) => {
|
|
2918
|
-
let t = pa(e, "postgres");
|
|
2919
|
-
return t === void 0 ? ha(e) : t;
|
|
2920
2926
|
}, ha = (e) => {
|
|
2927
|
+
let t = ma(e, "postgres");
|
|
2928
|
+
return t === void 0 ? ga(e) : t;
|
|
2929
|
+
}, ga = (e) => {
|
|
2921
2930
|
switch (e.type) {
|
|
2922
2931
|
case "id": return "text";
|
|
2923
2932
|
case "text": return "text";
|
|
2924
2933
|
case "integer": return "integer";
|
|
2925
2934
|
case "real": return "double precision";
|
|
2926
|
-
case "decimal": return
|
|
2935
|
+
case "decimal": return fa(e, "NUMERIC");
|
|
2927
2936
|
case "bigint": return "bigint";
|
|
2928
2937
|
case "boolean": return "boolean";
|
|
2929
2938
|
case "timestamp": return "timestamptz";
|
|
@@ -2937,15 +2946,15 @@ BEGIN
|
|
|
2937
2946
|
case "interval": return "interval";
|
|
2938
2947
|
case "raw": return e.rawDdl ?? "text";
|
|
2939
2948
|
}
|
|
2940
|
-
},
|
|
2941
|
-
let t =
|
|
2949
|
+
}, _a = (e) => {
|
|
2950
|
+
let t = ma(e, "mariadb");
|
|
2942
2951
|
if (t !== void 0) return t;
|
|
2943
2952
|
switch (e.type) {
|
|
2944
2953
|
case "id": return "VARCHAR(64)";
|
|
2945
2954
|
case "text": return "LONGTEXT";
|
|
2946
2955
|
case "integer": return "INT";
|
|
2947
2956
|
case "real": return "DOUBLE";
|
|
2948
|
-
case "decimal": return
|
|
2957
|
+
case "decimal": return fa(e, "DECIMAL");
|
|
2949
2958
|
case "bigint": return "BIGINT";
|
|
2950
2959
|
case "boolean": return "TINYINT(1)";
|
|
2951
2960
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2959,20 +2968,20 @@ BEGIN
|
|
|
2959
2968
|
case "interval": return "BIGINT";
|
|
2960
2969
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2961
2970
|
}
|
|
2962
|
-
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2971
|
+
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``, va = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", ya = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, ba = (e, t = "mariadb") => `ALTER TABLE ${G(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${G(e.column)}, ALGORITHM=COPY;`, xa = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Sa = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(t)};`, Ca = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Ta(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, wa = (e, t) => {
|
|
2963
2972
|
let { defaultFactory: n, ...r } = e;
|
|
2964
2973
|
return F(e, t) !== F({
|
|
2965
2974
|
...r,
|
|
2966
2975
|
hasDefault: !1
|
|
2967
2976
|
}, t);
|
|
2968
|
-
},
|
|
2977
|
+
}, Ta = (e, t) => {
|
|
2969
2978
|
let n = t(e.defaultValue);
|
|
2970
2979
|
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.`);
|
|
2971
2980
|
return n;
|
|
2972
|
-
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2981
|
+
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Ea = (e, t, n) => {
|
|
2973
2982
|
let r = K(e, t, n);
|
|
2974
2983
|
return r ? kr(n, r) : void 0;
|
|
2975
|
-
},
|
|
2984
|
+
}, Da = (e, t, n, r) => {
|
|
2976
2985
|
let i = n ?? e.nullable, a = Jt(e, "mariadb");
|
|
2977
2986
|
return [
|
|
2978
2987
|
G(t),
|
|
@@ -2981,20 +2990,20 @@ BEGIN
|
|
|
2981
2990
|
a,
|
|
2982
2991
|
r === void 0 ? null : `CHECK (${r})`
|
|
2983
2992
|
].filter(Boolean).join(" ");
|
|
2984
|
-
},
|
|
2993
|
+
}, Oa = /^json_valid\(`[^`]+`\)$/i, ka = (e, t) => H(e).pipe(k.flatMap((n) => n === "mariadb" ? e`
|
|
2985
2994
|
SELECT constraint_name AS n, check_clause AS c
|
|
2986
2995
|
FROM information_schema.check_constraints
|
|
2987
|
-
WHERE constraint_schema = DATABASE() AND table_name = ${t} AND level = 'Column'`.pipe(k.map((e) => new Map(e.map((e) => [String(e.n ?? ""), String(e.c ?? "")]).filter(([e, t]) => e !== "" && t !== "" && !
|
|
2996
|
+
WHERE constraint_schema = DATABASE() AND table_name = ${t} AND level = 'Column'`.pipe(k.map((e) => new Map(e.map((e) => [String(e.n ?? ""), String(e.c ?? "")]).filter(([e, t]) => e !== "" && t !== "" && !Oa.test(t.trim()))))) : k.succeed(/* @__PURE__ */ new Map()))), Aa = (e, t, n, r, i) => k.map(ka(e, t), (e) => `ALTER TABLE ${G(t)} MODIFY COLUMN ${Da(n, r, i, e.get(r))};`), ja = (e, t) => e == null ? null : Array.isArray(e) ? Ma(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" ? Xt(e, "mariadb") : null, Ma = (e, t, n) => Yt(e, t ?? { type: "json" }, n), Na = (e, t) => e == null ? null : Array.isArray(e) ? Ma(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" ? Xt(e, "postgres") : null, Pa = (e, t) => {
|
|
2988
2997
|
if (!e.generatedAs) return null;
|
|
2989
2998
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2990
2999
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2991
|
-
},
|
|
3000
|
+
}, Fa = (e, t = !1) => {
|
|
2992
3001
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return Zt(e.name, "postgres");
|
|
2993
|
-
let n =
|
|
2994
|
-
if (n) return `${W(e.name)} ${
|
|
2995
|
-
let r = [W(e.name),
|
|
3002
|
+
let n = Pa(e, "postgres");
|
|
3003
|
+
if (n) return `${W(e.name)} ${ha(e)} ${n}`;
|
|
3004
|
+
let r = [W(e.name), ha(e)];
|
|
2996
3005
|
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
2997
|
-
let t =
|
|
3006
|
+
let t = Na(e.defaultValue, e);
|
|
2998
3007
|
t && r.push(t);
|
|
2999
3008
|
}
|
|
3000
3009
|
return e.references && (r.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${{
|
|
@@ -3003,28 +3012,28 @@ BEGIN
|
|
|
3003
3012
|
setNull: "SET NULL",
|
|
3004
3013
|
noAction: "NO ACTION"
|
|
3005
3014
|
}[e.references.onDelete]}`)), r.join(" ");
|
|
3006
|
-
},
|
|
3007
|
-
let t = e.columns.map((t) => ` ${
|
|
3008
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(
|
|
3015
|
+
}, Ia = (e) => (e.primaryKey?.length ?? 0) > 0, La = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Ra = (e) => {
|
|
3016
|
+
let t = e.columns.map((t) => ` ${Fa(t, Ia(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${La(e, W)}\n)`];
|
|
3017
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(fo({
|
|
3009
3018
|
kind: "add-index",
|
|
3010
3019
|
table: e.table,
|
|
3011
3020
|
index: t
|
|
3012
3021
|
}, !1));
|
|
3013
3022
|
return n;
|
|
3014
|
-
},
|
|
3015
|
-
let t =
|
|
3023
|
+
}, za = 191, Ba = (e) => {
|
|
3024
|
+
let t = _a(e).toUpperCase();
|
|
3016
3025
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
3017
|
-
},
|
|
3026
|
+
}, Va = (e, t = !1) => {
|
|
3018
3027
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return Zt(e.name, "mariadb");
|
|
3019
|
-
let n = e.charset === void 0 ?
|
|
3028
|
+
let n = e.charset === void 0 ? _a(e) : `${_a(e)} CHARACTER SET ${e.charset}`, r = Pa(e, "mariadb");
|
|
3020
3029
|
if (r) return `${G(e.name)} ${n} ${r}`;
|
|
3021
3030
|
let i = [G(e.name), n];
|
|
3022
|
-
if (e.type === "id" && !t && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
3023
|
-
let t =
|
|
3031
|
+
if (e.type === "id" && !t && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && !Ba(e) && i.push("UNIQUE"), e.hasDefault) {
|
|
3032
|
+
let t = ja(e.defaultValue, e);
|
|
3024
3033
|
t && i.push(t);
|
|
3025
3034
|
}
|
|
3026
3035
|
return i.join(" ");
|
|
3027
|
-
},
|
|
3036
|
+
}, Ha = (e) => e.columns.flatMap((t) => {
|
|
3028
3037
|
if (!t.references) return [];
|
|
3029
3038
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
3030
3039
|
cascade: "CASCADE",
|
|
@@ -3033,14 +3042,14 @@ BEGIN
|
|
|
3033
3042
|
noAction: "NO ACTION"
|
|
3034
3043
|
}[t.references.onDelete]}` : "";
|
|
3035
3044
|
return [` CONSTRAINT ${G(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${G(t.name)}) REFERENCES ${G(t.references.table)} (${G(t.references.column)})${n}`];
|
|
3036
|
-
}),
|
|
3045
|
+
}), Ua = (e) => {
|
|
3037
3046
|
let t = e.find((e) => e.charset !== void 0)?.charset;
|
|
3038
3047
|
return t === void 0 ? "" : ` DEFAULT CHARACTER SET ${t}`;
|
|
3039
|
-
},
|
|
3048
|
+
}, Wa = (e, t, n = /* @__PURE__ */ new Map()) => {
|
|
3040
3049
|
let r = e.foreignKeys.map((e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(e.name)}`), i = e.columns.map((r) => {
|
|
3041
|
-
let i = K(t, e.table, r), a =
|
|
3050
|
+
let i = K(t, e.table, r), a = Ea(t, e.table, r);
|
|
3042
3051
|
if (i === void 0 || a === void 0) throw Error(`convert-charset: no declared column '${e.table}.${r}' to render MODIFY COLUMN from; it was not in ctx.declared.`);
|
|
3043
|
-
let o =
|
|
3052
|
+
let o = Pa(a, "mariadb"), s = `${G(r)} ${F(i, "mariadb")} CHARACTER SET ${e.charset}`, c = n.get(r), l = c === void 0 ? null : `CHECK (${c})`;
|
|
3044
3053
|
if (o) return `MODIFY COLUMN ${[
|
|
3045
3054
|
s,
|
|
3046
3055
|
o,
|
|
@@ -3057,29 +3066,29 @@ BEGIN
|
|
|
3057
3066
|
return {
|
|
3058
3067
|
drops: r,
|
|
3059
3068
|
rewrite: `ALTER TABLE ${G(e.table)} ${[...i, `DEFAULT CHARACTER SET ${e.charset}`].join(", ")}`,
|
|
3060
|
-
restores: e.foreignKeys.filter((e) => e.restore === "here").map((e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} FOREIGN KEY (${G(e.column)}) REFERENCES ${G(e.targetTable)} (${G(e.targetColumn)})` + (e.onDelete ? ` ON DELETE ${
|
|
3069
|
+
restores: e.foreignKeys.filter((e) => e.restore === "here").map((e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} FOREIGN KEY (${G(e.column)}) REFERENCES ${G(e.targetTable)} (${G(e.targetColumn)})` + (e.onDelete ? ` ON DELETE ${Ka[e.onDelete]}` : "") + (e.onUpdate && e.onUpdate !== "noAction" ? ` ON UPDATE ${Ka[e.onUpdate]}` : ""))
|
|
3061
3070
|
};
|
|
3062
|
-
},
|
|
3063
|
-
for (let n of e.indexes)
|
|
3071
|
+
}, Ga = (e, t = "mariadb") => {
|
|
3072
|
+
for (let n of e.indexes) mo(n, t);
|
|
3064
3073
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
3065
|
-
let t =
|
|
3074
|
+
let t = so(n.get(e));
|
|
3066
3075
|
return t === void 0 ? G(e) : `${G(e)}(${t})`;
|
|
3067
|
-
}, i = e.columns.map((t) => ` ${
|
|
3068
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
3069
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
3076
|
+
}, i = e.columns.map((t) => ` ${Va(t, Ia(e))}`).join(",\n"), a = Ha(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${o}${La(e, r)}\n)${Ua(e.columns)}`];
|
|
3077
|
+
for (let n of e.columns) n.unique && n.type !== "id" && Ba(n) && s.push(`CREATE UNIQUE INDEX ${va(t)}${G(`${e.table}_${n.name}_key`)} ON ${G(e.table)} (${r(n.name)})`);
|
|
3078
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${va(t)}${G(n.name)} ON ${G(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
3070
3079
|
return s;
|
|
3071
|
-
},
|
|
3080
|
+
}, Ka = {
|
|
3072
3081
|
cascade: "CASCADE",
|
|
3073
3082
|
restrict: "RESTRICT",
|
|
3074
3083
|
setNull: "SET NULL",
|
|
3075
3084
|
noAction: "NO ACTION"
|
|
3076
|
-
},
|
|
3085
|
+
}, qa = {
|
|
3077
3086
|
cascade: "CASCADE",
|
|
3078
3087
|
restrict: "NO ACTION",
|
|
3079
3088
|
setNull: "SET NULL",
|
|
3080
3089
|
noAction: "NO ACTION"
|
|
3081
|
-
},
|
|
3082
|
-
let t =
|
|
3090
|
+
}, Ja = (e) => {
|
|
3091
|
+
let t = ma(e, "sqlite");
|
|
3083
3092
|
if (t !== void 0) return t;
|
|
3084
3093
|
switch (e.type) {
|
|
3085
3094
|
case "integer":
|
|
@@ -3091,30 +3100,30 @@ BEGIN
|
|
|
3091
3100
|
case "bytes": return "BLOB";
|
|
3092
3101
|
default: return "TEXT";
|
|
3093
3102
|
}
|
|
3094
|
-
},
|
|
3103
|
+
}, Ya = (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" ? Xt(e, "sqlite") : null, Xa = (e, t = !1) => {
|
|
3095
3104
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return Zt(e.name, "sqlite");
|
|
3096
|
-
let n =
|
|
3097
|
-
if (n) return `${W(e.name)} ${
|
|
3098
|
-
let r = [W(e.name),
|
|
3105
|
+
let n = Pa(e, "sqlite");
|
|
3106
|
+
if (n) return `${W(e.name)} ${Ja(e)} ${n}`;
|
|
3107
|
+
let r = [W(e.name), Ja(e)];
|
|
3099
3108
|
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
3100
|
-
let t =
|
|
3109
|
+
let t = Ya(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
3101
3110
|
t && r.push(t);
|
|
3102
3111
|
}
|
|
3103
|
-
if (e.references && (r.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${
|
|
3112
|
+
if (e.references && (r.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${Ka[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
3104
3113
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
3105
3114
|
r.push(`CHECK (${W(e.name)} IN (${t}))`);
|
|
3106
3115
|
}
|
|
3107
3116
|
return r.join(" ");
|
|
3108
|
-
},
|
|
3109
|
-
let t = e.columns.map((t) => ` ${
|
|
3110
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(W).join(", ")})${
|
|
3117
|
+
}, Za = (e) => {
|
|
3118
|
+
let t = e.columns.map((t) => ` ${Xa(t, Ia(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${La(e, W)}\n)`];
|
|
3119
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(W).join(", ")})${uo(t)}`);
|
|
3111
3120
|
return n;
|
|
3112
|
-
},
|
|
3121
|
+
}, Qa = (e, t) => {
|
|
3113
3122
|
let n = t.find((t) => t.tableName === e);
|
|
3114
|
-
return n ?
|
|
3115
|
-
},
|
|
3123
|
+
return n ? $a(Nr([n], "sqlite").tables[0]) : [];
|
|
3124
|
+
}, $a = (e) => {
|
|
3116
3125
|
let t = e.name, n = `${t}__voltro_rebuild`, r = e.columns.map((e) => W(e.name)).join(", "), i = [
|
|
3117
|
-
...
|
|
3126
|
+
...Za({
|
|
3118
3127
|
kind: "create-table",
|
|
3119
3128
|
table: n,
|
|
3120
3129
|
columns: e.columns,
|
|
@@ -3125,27 +3134,27 @@ BEGIN
|
|
|
3125
3134
|
`DROP TABLE ${W(t)}`,
|
|
3126
3135
|
`ALTER TABLE ${W(n)} RENAME TO ${W(t)}`
|
|
3127
3136
|
];
|
|
3128
|
-
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(n.name)} ON ${W(t)} (${n.columns.map(W).join(", ")})${
|
|
3137
|
+
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(n.name)} ON ${W(t)} (${n.columns.map(W).join(", ")})${uo(n)}`);
|
|
3129
3138
|
return i;
|
|
3130
|
-
},
|
|
3139
|
+
}, eo = (e, t, n, r) => {
|
|
3131
3140
|
let i = r ?? e.nullable;
|
|
3132
3141
|
return `ALTER TABLE ${q(n)} ALTER COLUMN ${q(t)} ${F(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
3133
|
-
},
|
|
3142
|
+
}, to = (e, t) => {
|
|
3134
3143
|
let n = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${q(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
3135
3144
|
if (!e.hasDefault) return n;
|
|
3136
|
-
let r =
|
|
3145
|
+
let r = Ya(e.defaultValue, "SYSUTCDATETIME()");
|
|
3137
3146
|
if (!r) return n;
|
|
3138
3147
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
3139
3148
|
return `${n} ALTER TABLE ${q(e.table)} ADD DEFAULT ${i} FOR ${q(e.column)};`;
|
|
3140
|
-
}, q = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
3141
|
-
let t =
|
|
3149
|
+
}, q = (e) => `[${e.replace(/]/g, "]]")}]`, no = (e) => {
|
|
3150
|
+
let t = ma(e, "mssql");
|
|
3142
3151
|
if (t !== void 0) return t;
|
|
3143
3152
|
switch (e.type) {
|
|
3144
3153
|
case "id": return "NVARCHAR(64)";
|
|
3145
3154
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
3146
3155
|
case "integer": return "INT";
|
|
3147
3156
|
case "real": return "FLOAT";
|
|
3148
|
-
case "decimal": return
|
|
3157
|
+
case "decimal": return fa(e, "DECIMAL");
|
|
3149
3158
|
case "bigint": return "BIGINT";
|
|
3150
3159
|
case "boolean": return "BIT";
|
|
3151
3160
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -3153,50 +3162,50 @@ BEGIN
|
|
|
3153
3162
|
case "bytes": return "VARBINARY(MAX)";
|
|
3154
3163
|
default: return "NVARCHAR(MAX)";
|
|
3155
3164
|
}
|
|
3156
|
-
},
|
|
3165
|
+
}, ro = (e, t, n = !1) => {
|
|
3157
3166
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return Zt(e.name, "mssql");
|
|
3158
|
-
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` :
|
|
3167
|
+
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` : no(e), i = Pa(e, "mssql");
|
|
3159
3168
|
if (i) return `${q(e.name)} ${i}`;
|
|
3160
3169
|
let a = [q(e.name), r];
|
|
3161
3170
|
if (e.type === "json" && a.push(`CHECK ${Pt(q(e.name))}`), e.type === "array" && a.push(`CHECK (${q(e.name)} IS NULL OR ISJSON(${q(e.name)}) = 1)`), e.type === "id" && !n && a.push("PRIMARY KEY"), e.nullable || a.push("NOT NULL"), e.unique && e.type !== "id" && a.push("UNIQUE"), e.hasDefault) {
|
|
3162
|
-
let t =
|
|
3171
|
+
let t = Ya(e.defaultValue, "SYSUTCDATETIME()");
|
|
3163
3172
|
t && a.push(t);
|
|
3164
3173
|
}
|
|
3165
|
-
return e.references && (a.push(`REFERENCES ${q(e.references.table)} (${q(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${
|
|
3166
|
-
},
|
|
3167
|
-
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((t) => ` ${
|
|
3174
|
+
return e.references && (a.push(`REFERENCES ${q(e.references.table)} (${q(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${qa[e.references.onDelete]}`)), a.join(" ");
|
|
3175
|
+
}, io = (e) => {
|
|
3176
|
+
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((t) => ` ${ro(t, n, Ia(e))}`).join(",\n"), i = `CREATE TABLE ${q(e.table)} (\n${r}${La(e, q)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
3168
3177
|
for (let n of e.indexes) {
|
|
3169
3178
|
if (n.name === `${e.table}_pkey`) continue;
|
|
3170
|
-
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${q(n.name)} ON ${q(e.table)} (${n.columns.map(q).join(", ")})${
|
|
3179
|
+
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${q(n.name)} ON ${q(e.table)} (${n.columns.map(q).join(", ")})${uo(n)}`;
|
|
3171
3180
|
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)}')`);
|
|
3172
3181
|
}
|
|
3173
3182
|
return a;
|
|
3174
|
-
},
|
|
3175
|
-
if (e === void 0 || !
|
|
3183
|
+
}, ao = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, oo = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME TO ${n(t)};`, so = (e) => {
|
|
3184
|
+
if (e === void 0 || !Ba(e)) return;
|
|
3176
3185
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
3177
|
-
return t === void 0 ?
|
|
3178
|
-
},
|
|
3179
|
-
let r =
|
|
3186
|
+
return t === void 0 ? za : Math.min(za, t);
|
|
3187
|
+
}, co = (e, t, n) => {
|
|
3188
|
+
let r = so(Ea(e, t, n));
|
|
3180
3189
|
return r === void 0 ? G(n) : `${G(n)}(${r})`;
|
|
3181
|
-
},
|
|
3182
|
-
let n = Re(e.index.kind, e.index.kindOptions), r = e.index.columns.map(
|
|
3190
|
+
}, lo = (e) => e.startsWith("(") ? e : W(e), uo = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, fo = (e, t) => {
|
|
3191
|
+
let n = Re(e.index.kind, e.index.kindOptions), r = e.index.columns.map(lo);
|
|
3183
3192
|
if (n.opclass !== void 0) {
|
|
3184
3193
|
if (r.length !== 1) throw Error("HNSW index requires exactly one column");
|
|
3185
3194
|
r[0] = `${r[0]} ${n.opclass}`;
|
|
3186
3195
|
}
|
|
3187
|
-
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${
|
|
3188
|
-
},
|
|
3196
|
+
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${uo(e.index)};`;
|
|
3197
|
+
}, po = (e, t, n = "mariadb") => (mo(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${va(n)}${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map((n) => co(t, e.table, n)).join(", ")});`), mo = (e, t) => {
|
|
3189
3198
|
if (e.where !== void 0) throw Error(`Partial index '${e.name}' is not supported by ${t}; uniqueActive must be lowered before applying the plan.`);
|
|
3190
|
-
},
|
|
3199
|
+
}, ho = (e) => `DROP INDEX IF EXISTS ${W(e.index)};`, go = (e) => `DROP INDEX ${G(e.index)} ON ${G(e.table)};`, _o = (e) => `DROP INDEX IF EXISTS ${q(e.index)} ON ${q(e.table)};`, vo = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, yo = (e) => {
|
|
3191
3200
|
let t = (e) => e.replace(/'/g, "''");
|
|
3192
3201
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
3193
|
-
},
|
|
3202
|
+
}, bo = (e) => `ALTER INDEX ${W(e.from)} RENAME TO ${W(e.to)};`, xo = (e) => `ALTER TABLE ${G(e.table)} RENAME INDEX ${G(e.from)} TO ${G(e.to)};`, So = (e) => {
|
|
3194
3203
|
let t = (e) => e.replace(/'/g, "''");
|
|
3195
3204
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
3196
|
-
},
|
|
3197
|
-
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${q(e.index.name)} ON ${q(e.table)} (${e.index.columns.map(q).join(", ")})${
|
|
3205
|
+
}, Co = (e) => {
|
|
3206
|
+
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${q(e.index.name)} ON ${q(e.table)} (${e.index.columns.map(q).join(", ")})${uo(e.index)}`;
|
|
3198
3207
|
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)}');`;
|
|
3199
|
-
},
|
|
3208
|
+
}, wo = (e, t, n) => {
|
|
3200
3209
|
let r = n.find((t) => t.tableName === e);
|
|
3201
3210
|
if (!r) return [];
|
|
3202
3211
|
let i = [];
|
|
@@ -3208,13 +3217,13 @@ BEGIN
|
|
|
3208
3217
|
}
|
|
3209
3218
|
}
|
|
3210
3219
|
return i;
|
|
3211
|
-
},
|
|
3220
|
+
}, To = (e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${W(e.column)});`, Eo = (e, t) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${co(t, e.table, e.column)});`, Do = (e) => {
|
|
3212
3221
|
let t = e.fields.map((e) => W(e)).join(", ");
|
|
3213
3222
|
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
|
|
3214
|
-
},
|
|
3215
|
-
let n = e.fields.map((n) =>
|
|
3223
|
+
}, Oo = (e, t) => {
|
|
3224
|
+
let n = e.fields.map((n) => co(t, e.table, n)).join(", ");
|
|
3216
3225
|
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
|
|
3217
|
-
},
|
|
3226
|
+
}, ko = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(e.name)};`, Ao = (e) => [ko(e), `DROP INDEX IF EXISTS ${W(e.name)};`], jo = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(e.name)};`, Mo = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_key`)};`, No = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(`${e.table}_${e.column}_key`)};`, Po = (e, t, n = Ka) => {
|
|
3218
3227
|
let r = [], i = t(e.table), a = t(e.column), o = t(e.targetTable), s = t(e.targetColumn);
|
|
3219
3228
|
if (e.orphanPolicy) {
|
|
3220
3229
|
let t = `${a} IS NOT NULL AND ${a} NOT IN (SELECT ${s} FROM ${o})`;
|
|
@@ -3227,10 +3236,10 @@ BEGIN
|
|
|
3227
3236
|
`REFERENCES ${o} (${s})`
|
|
3228
3237
|
];
|
|
3229
3238
|
return e.onDelete && c.push(`ON DELETE ${n[e.onDelete]}`), r.push(c.join(" ") + ";"), r;
|
|
3230
|
-
},
|
|
3239
|
+
}, Fo = (e) => e.name ?? `${e.table}_${e.column}_fkey`, Io = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(Fo(e))};`, Lo = (e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(Fo(e))};`, Ro = (e, t) => {
|
|
3231
3240
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
3232
3241
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
3233
|
-
},
|
|
3242
|
+
}, zo = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Bo = (e, t) => k.gen(function* () {
|
|
3234
3243
|
let n = yield* e`
|
|
3235
3244
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
3236
3245
|
FROM information_schema.check_constraints cc
|
|
@@ -3245,16 +3254,16 @@ BEGIN
|
|
|
3245
3254
|
let n = String(e.n ?? "");
|
|
3246
3255
|
if (n !== "" && wi(String(e.c ?? ""))?.column === t.column) return n;
|
|
3247
3256
|
}
|
|
3248
|
-
}),
|
|
3249
|
-
let r = yield*
|
|
3250
|
-
r !== void 0 && (yield* J(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [
|
|
3251
|
-
let i = yield*
|
|
3257
|
+
}), Vo = (e, t, n) => k.gen(function* () {
|
|
3258
|
+
let r = yield* Bo(e, t);
|
|
3259
|
+
r !== void 0 && (yield* J(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [ca]));
|
|
3260
|
+
let i = yield* Bo(e, t);
|
|
3252
3261
|
if (i === void 0) return;
|
|
3253
3262
|
let a = K(n, t.table, t.column);
|
|
3254
3263
|
if (!a) return yield* k.die(/* @__PURE__ */ Error(`applier: cannot drop the CHECK on '${t.table}.${t.column}' — it is column-level (catalog name '${i}'), which this family removes only by redefining the column, and the declared column is not available to redefine it from.`));
|
|
3255
|
-
yield* J(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${
|
|
3256
|
-
}),
|
|
3257
|
-
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? q : W, s = a ?
|
|
3264
|
+
yield* J(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${Da(a, t.column)};`, t.kind);
|
|
3265
|
+
}), Ho = (e, t, n, r) => {
|
|
3266
|
+
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? q : W, s = a ? _a(i) : r === "mssql" ? no(i) : r === "sqlite" ? Ja(i) : ha(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = r === "mssql" ? i.type === "json" ? ` CHECK ${Pt(o(i.name))}` : i.type === "array" ? ` CHECK (${o(i.name)} IS NULL OR ISJSON(${o(i.name)}) = 1)` : "" : "", u = (e) => a ? ja(e, i) : r === "mssql" ? Ya(e, "SYSUTCDATETIME()") : r === "sqlite" ? Ya(e, "CURRENT_TIMESTAMP") : Na(e, i), d = Pa(i, r);
|
|
3258
3267
|
if (d) {
|
|
3259
3268
|
let t = r === "mssql" ? `${o(i.name)} ${d}` : `${o(i.name)} ${s} ${d}`;
|
|
3260
3269
|
return {
|
|
@@ -3283,7 +3292,7 @@ BEGIN
|
|
|
3283
3292
|
post: p ? [p] : []
|
|
3284
3293
|
};
|
|
3285
3294
|
return i.unique && i.type !== "id" && (m.uniquePending = !0), f?.sql && (m.backfillKind = "sql", m.backfillSql = f.sql), f?.js && (m.backfillKind = "js", m.backfillJs = f.js), f?.batchSize !== void 0 && (m.batchSize = f.batchSize), f?.sleepMs !== void 0 && (m.sleepMs = f.sleepMs), m;
|
|
3286
|
-
},
|
|
3295
|
+
}, Uo = /* @__PURE__ */ new Set([
|
|
3287
3296
|
"drop-index",
|
|
3288
3297
|
"drop-check",
|
|
3289
3298
|
"drop-unique",
|
|
@@ -3291,7 +3300,7 @@ BEGIN
|
|
|
3291
3300
|
"drop-foreign-key",
|
|
3292
3301
|
"drop-column",
|
|
3293
3302
|
"drop-table"
|
|
3294
|
-
]),
|
|
3303
|
+
]), Wo = (e) => {
|
|
3295
3304
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
3296
3305
|
return (e, n) => {
|
|
3297
3306
|
let r = t.get(e);
|
|
@@ -3311,12 +3320,12 @@ BEGIN
|
|
|
3311
3320
|
...o
|
|
3312
3321
|
};
|
|
3313
3322
|
};
|
|
3314
|
-
}, J = (e, t, n, r = []) => e.unsafe(t).pipe(k.catchIf((e) =>
|
|
3323
|
+
}, J = (e, t, n, r = []) => e.unsafe(t).pipe(k.catchIf((e) => ia(e, r), () => k.void), k.tapError((e) => k.sync(() => {
|
|
3315
3324
|
process.stderr.write(ze(`applier: statement failed (op=${n})`, t, e, 400));
|
|
3316
3325
|
})), k.mapError((e) => {
|
|
3317
3326
|
let r = ze(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
3318
3327
|
return Object.assign(e, { message: r });
|
|
3319
|
-
}), k.map(() => void 0)), Y = (e, t, n, r) =>
|
|
3328
|
+
}), k.map(() => void 0)), Y = (e, t, n, r) => Go(e, t, Qa(t, n), r), Go = (e, t, n, r) => {
|
|
3320
3329
|
if (n.length === 0) return k.void;
|
|
3321
3330
|
let i = (e) => (n) => {
|
|
3322
3331
|
let i = ze(`applier: statement failed (op=${r}, sqlite rebuild of ${t})`, e, n, 400).trim();
|
|
@@ -3333,7 +3342,7 @@ BEGIN
|
|
|
3333
3342
|
}
|
|
3334
3343
|
}), k.ignore(a("PRAGMA foreign_keys = ON")));
|
|
3335
3344
|
}));
|
|
3336
|
-
},
|
|
3345
|
+
}, Ko = (e, t) => k.gen(function* () {
|
|
3337
3346
|
let n = (yield* e`
|
|
3338
3347
|
SELECT ck.name, ck.definition, ck.is_disabled AS disabled,
|
|
3339
3348
|
ck.is_not_trusted AS untrusted, ck.is_not_for_replication AS notForReplication
|
|
@@ -3345,33 +3354,33 @@ BEGIN
|
|
|
3345
3354
|
) ORDER BY ck.name
|
|
3346
3355
|
`).map((e) => ({
|
|
3347
3356
|
...e,
|
|
3348
|
-
definition:
|
|
3349
|
-
})), r = (e) =>
|
|
3357
|
+
definition: da(e.definition, t.from, t.to)
|
|
3358
|
+
})), r = (e) => O(e, "mssql"), i = (e) => e.replace(/'/g, "''");
|
|
3350
3359
|
return yield* X(e, [
|
|
3351
3360
|
...n.map((e) => `ALTER TABLE ${r(t.table)} DROP CONSTRAINT ${r(e.name)}`),
|
|
3352
3361
|
`EXEC sp_rename N'${i(`${r(t.table)}.${r(t.from)}`)}', N'${i(t.to)}', 'COLUMN';`,
|
|
3353
3362
|
...n.flatMap((e) => [`ALTER TABLE ${r(t.table)} WITH ${e.untrusted ? "NOCHECK" : "CHECK"} ADD CONSTRAINT ${r(e.name)} CHECK ${e.notForReplication ? "NOT FOR REPLICATION " : ""}${e.definition}`, ...e.disabled ? [`ALTER TABLE ${r(t.table)} NOCHECK CONSTRAINT ${r(e.name)}`] : []])
|
|
3354
3363
|
], t.kind);
|
|
3355
|
-
}),
|
|
3356
|
-
let
|
|
3357
|
-
if (!
|
|
3358
|
-
let
|
|
3364
|
+
}), qo = (e, t, n) => e == null ? e : t.type === "json" ? JSON.stringify(e) : (t.type === "array" || t.type === "vector") && n !== "postgres" ? typeof e == "string" ? e : JSON.stringify(e) : e, X = (e, t, n) => k.forEach(t, (t) => J(e, t, n), { discard: !0 }), Jo = (e, t, n, r) => e.unsafe(`SELECT ${r === void 0 ? "*" : O(r, t)} FROM ${O(n, t)} WHERE 1=0`).pipe(k.as(!0), k.catchAll(() => k.succeed(!1))), Yo = (e, t, n) => ts(e, t, Ct, N, n), Xo = (e, t, n) => ts(e, t, he, "_voltro_migration_plans", n), Zo = (e, t, n) => ts(e, t, oe, "_voltro_schema_owner", n), Qo = (e, t, n) => ts(e, t, ce, "_voltro_plugin_migrations", n), $o = (e, t, n) => ts(e, t, _i, R, n), es = (e, t, n) => ts(e, t, _e, ve, n), ts = (e, t, n, r, a) => k.gen(function* () {
|
|
3365
|
+
let o = Nr([n], t, a !== void 0 && i(t) ? { charset: a } : {}).tables[0];
|
|
3366
|
+
if (!o) return yield* k.die(/* @__PURE__ */ Error(`migration applier: the ${r} table descriptor produced no snapshot. This is a framework bug.`));
|
|
3367
|
+
let s = {
|
|
3359
3368
|
kind: "create-table",
|
|
3360
3369
|
table: r,
|
|
3361
|
-
columns:
|
|
3370
|
+
columns: o.columns,
|
|
3362
3371
|
indexes: []
|
|
3363
|
-
},
|
|
3364
|
-
mysql: () => H(e).pipe(k.map((e) =>
|
|
3365
|
-
mssql: () => k.succeed(
|
|
3366
|
-
sqlite: () => k.succeed(
|
|
3367
|
-
orElse: () => k.succeed(
|
|
3372
|
+
}, c = yield* e.onDialectOrElse({
|
|
3373
|
+
mysql: () => H(e).pipe(k.map((e) => Ga(s, e))),
|
|
3374
|
+
mssql: () => k.succeed(io(s)),
|
|
3375
|
+
sqlite: () => k.succeed(Za(s)),
|
|
3376
|
+
orElse: () => k.succeed(Ra(s))
|
|
3368
3377
|
});
|
|
3369
|
-
yield* k.forEach(
|
|
3370
|
-
}),
|
|
3378
|
+
yield* k.forEach(c, (t) => J(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
3379
|
+
}), ns = (e) => e`
|
|
3371
3380
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
3372
3381
|
${e("status")}, ${e("payload")}
|
|
3373
3382
|
FROM ${e(N)}
|
|
3374
|
-
`,
|
|
3383
|
+
`, rs = (e) => Xi(e, N).pipe(k.flatMap((t) => t ? ns(e).pipe(k.map((e) => e.length > 0)) : k.succeed(!1))), is = (e, t, n, r) => k.gen(function* () {
|
|
3375
3384
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3376
3385
|
yield* k.forEach(r, ({ index: r, planned: a }) => e`
|
|
3377
3386
|
INSERT INTO ${e(N)}
|
|
@@ -3383,7 +3392,7 @@ BEGIN
|
|
|
3383
3392
|
${a.op.kind}, ${Tt(a.op)}, ${"pending"},
|
|
3384
3393
|
${JSON.stringify(a)}, ${i})
|
|
3385
3394
|
`, { discard: !0 });
|
|
3386
|
-
}),
|
|
3395
|
+
}), as = (e, t, n, r, i) => k.gen(function* () {
|
|
3387
3396
|
let a = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3388
3397
|
if (r === "applied") {
|
|
3389
3398
|
yield* e`
|
|
@@ -3399,7 +3408,7 @@ BEGIN
|
|
|
3399
3408
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
3400
3409
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
3401
3410
|
`;
|
|
3402
|
-
}),
|
|
3411
|
+
}), os = (e, t, n, r) => k.gen(function* () {
|
|
3403
3412
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3404
3413
|
r.length > 0 && (yield* e`
|
|
3405
3414
|
UPDATE ${e(N)}
|
|
@@ -3410,346 +3419,360 @@ BEGIN
|
|
|
3410
3419
|
SET ${e("status")} = ${"pending"}
|
|
3411
3420
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
3412
3421
|
`);
|
|
3413
|
-
}),
|
|
3422
|
+
}), ss = (e, t) => t === void 0 ? e`DELETE FROM ${e(N)}`.pipe(k.asVoid) : e`DELETE FROM ${e(N)} WHERE ${e("runId")} = ${t}`.pipe(k.asVoid), cs = (e) => ns(e).pipe(k.map((e) => e.filter((e) => e.status === "started" || e.status === "added" || e.status === "applied").map((e) => JSON.parse(e.payload))), k.catchAll(() => k.succeed([]))), ls = (e) => ss(e).pipe(k.catchAll(() => k.void)), us = (e, t, n) => k.gen(function* () {
|
|
3414
3423
|
if (Nt(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
3415
|
-
let r = n.op, i = (e) =>
|
|
3424
|
+
let r = n.op, i = (e) => O(e, t);
|
|
3425
|
+
if (t === "postgres" && r.kind === "add-index") {
|
|
3426
|
+
let t = yield* e`
|
|
3427
|
+
SELECT ns.nspname AS schema_name
|
|
3428
|
+
FROM pg_index ix
|
|
3429
|
+
JOIN pg_class idx ON idx.oid = ix.indexrelid
|
|
3430
|
+
JOIN pg_namespace ns ON ns.oid = idx.relnamespace
|
|
3431
|
+
WHERE ix.indrelid = to_regclass(${i(r.table)})
|
|
3432
|
+
AND idx.relname = ${r.index.name}
|
|
3433
|
+
AND NOT ix.indisvalid
|
|
3434
|
+
`;
|
|
3435
|
+
return t.length === 0 ? "clean" : (yield* J(e, `DROP INDEX CONCURRENTLY ${i(t[0].schema_name)}.${i(r.index.name)}`, "resume-repair"), "outstanding");
|
|
3436
|
+
}
|
|
3416
3437
|
if (t === "sqlite" || t === "turso") {
|
|
3417
3438
|
if (!("table" in r)) return "clean";
|
|
3418
3439
|
let n = `${r.table}${Ot}`;
|
|
3419
|
-
return (yield*
|
|
3440
|
+
return (yield* Jo(e, t, n)) ? ((yield* Jo(e, t, r.table)) ? yield* J(e, `DROP TABLE ${i(n)}`, "resume-repair") : yield* J(e, `ALTER TABLE ${i(n)} RENAME TO ${i(r.table)}`, "resume-repair"), yield* k.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
3420
3441
|
}
|
|
3421
3442
|
if (r.kind !== "alter-column-type") return "clean";
|
|
3422
|
-
let a = `${r.column}${kt}`,
|
|
3423
|
-
return !
|
|
3424
|
-
}),
|
|
3425
|
-
let a = process.hrtime.bigint(),
|
|
3426
|
-
switch (
|
|
3443
|
+
let a = `${r.column}${kt}`, o = `${r.column}${At}`, s = yield* Jo(e, t, r.table, r.column), c = yield* Jo(e, t, r.table, a), l = yield* Jo(e, t, r.table, o), u = (e) => k.logWarning(`migration resume: ${e}`).pipe(k.annotateLogs({ scope: "voltro:migrate" }));
|
|
3444
|
+
return !c && !l ? "clean" : s && c && !l ? (yield* J(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(a)}`, "resume-repair"), yield* u(`dropped a half-populated shadow column '${r.table}.${a}' — replaying the type change`), "outstanding") : !s && c && l ? (yield* J(e, `ALTER TABLE ${i(r.table)} RENAME COLUMN ${i(a)} TO ${i(r.column)}`, "resume-repair"), yield* J(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(o)}`, "resume-repair"), yield* u(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : s && !c && l ? (yield* J(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(o)}`, "resume-repair"), yield* u(`dropped the leftover pre-swap column '${r.table}.${o}'`), "applied") : yield* k.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${r.table}.${r.column}' left a shadow-swap state this resume cannot classify (column=${s}, ${a}=${c}, ${o}=${l}).\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.`));
|
|
3445
|
+
}), ds = (e, t, n, r = "fresh", i) => k.gen(function* () {
|
|
3446
|
+
let a = process.hrtime.bigint(), o = Wo(n.declared), s = t.op, c = M(e);
|
|
3447
|
+
switch (s.kind) {
|
|
3427
3448
|
case "create-table": {
|
|
3428
3449
|
let t = yield* e.onDialectOrElse({
|
|
3429
|
-
mysql: () => H(e).pipe(k.map((e) =>
|
|
3430
|
-
mssql: () => k.succeed(
|
|
3431
|
-
sqlite: () => k.succeed(
|
|
3432
|
-
orElse: () => k.succeed(
|
|
3450
|
+
mysql: () => H(e).pipe(k.map((e) => Ga(s, e))),
|
|
3451
|
+
mssql: () => k.succeed(io(s)),
|
|
3452
|
+
sqlite: () => k.succeed(Za(s)),
|
|
3453
|
+
orElse: () => k.succeed(Ra(s))
|
|
3433
3454
|
}), n = yield* e.onDialectOrElse({
|
|
3434
|
-
mysql: () => k.succeed([
|
|
3455
|
+
mysql: () => k.succeed([aa]),
|
|
3435
3456
|
orElse: () => k.succeed([])
|
|
3436
3457
|
});
|
|
3437
|
-
for (let r of t) yield* J(e, r,
|
|
3458
|
+
for (let r of t) yield* J(e, r, s.kind, n);
|
|
3438
3459
|
break;
|
|
3439
3460
|
}
|
|
3440
3461
|
case "drop-table": {
|
|
3441
|
-
let n =
|
|
3462
|
+
let n = Qi(t), r = n !== void 0 || process.env.VOLTRO_SOFT_DROP === "1", i = n ?? Zi(t, (/* @__PURE__ */ new Date()).toISOString()).softDropSnapshot, a = (e) => r ? oo(s, i, e) : ao(s, e);
|
|
3442
3463
|
yield* e.onDialectOrElse({
|
|
3443
|
-
mysql: () => J(e, a(G),
|
|
3444
|
-
orElse: () => J(e, a(W),
|
|
3464
|
+
mysql: () => J(e, a(G), s.kind),
|
|
3465
|
+
orElse: () => J(e, a(W), s.kind)
|
|
3445
3466
|
});
|
|
3446
3467
|
break;
|
|
3447
3468
|
}
|
|
3448
3469
|
case "drop-column": {
|
|
3449
|
-
let n =
|
|
3470
|
+
let n = Qi(t), r = n !== void 0 || process.env.VOLTRO_SOFT_DROP === "1", i = n ?? Zi(t, (/* @__PURE__ */ new Date()).toISOString()).softDropSnapshot;
|
|
3450
3471
|
yield* e.onDialectOrElse({
|
|
3451
|
-
mysql: () => H(e).pipe(k.flatMap((t) => J(e, r ?
|
|
3452
|
-
sqlite: () => J(e, r ?
|
|
3453
|
-
orElse: () => J(e, r ?
|
|
3472
|
+
mysql: () => H(e).pipe(k.flatMap((t) => J(e, r ? Sa(s, i, G) : ba(s, t), s.kind, r ? [] : [oa]))),
|
|
3473
|
+
sqlite: () => J(e, r ? Sa(s, i, W) : ya(s, W, !1), s.kind, r ? [] : [sa]),
|
|
3474
|
+
orElse: () => J(e, r ? Sa(s, i, W) : ya(s, W), s.kind)
|
|
3454
3475
|
});
|
|
3455
3476
|
break;
|
|
3456
3477
|
}
|
|
3457
3478
|
case "rename-column":
|
|
3458
3479
|
yield* e.onDialectOrElse({
|
|
3459
|
-
mysql: () => J(e,
|
|
3460
|
-
mssql: () =>
|
|
3461
|
-
orElse: () => J(e,
|
|
3480
|
+
mysql: () => J(e, xa(s, G), s.kind),
|
|
3481
|
+
mssql: () => Ko(e, s),
|
|
3482
|
+
orElse: () => J(e, xa(s, W), s.kind)
|
|
3462
3483
|
});
|
|
3463
3484
|
break;
|
|
3464
3485
|
case "add-index":
|
|
3465
3486
|
yield* e.onDialectOrElse({
|
|
3466
|
-
sqlite: () => J(e,
|
|
3467
|
-
mysql: () => H(e).pipe(k.flatMap((t) => J(e,
|
|
3468
|
-
mssql: () => X(e, [...
|
|
3469
|
-
orElse: () => J(e,
|
|
3487
|
+
sqlite: () => J(e, fo(s, !1), s.kind),
|
|
3488
|
+
mysql: () => H(e).pipe(k.flatMap((t) => J(e, po(s, n.declared, t), s.kind, [aa]))),
|
|
3489
|
+
mssql: () => X(e, [...wo(s.table, s.index.columns, n.declared), Co(s)], s.kind),
|
|
3490
|
+
orElse: () => J(e, fo(s, t.classification === "online-required"), s.kind)
|
|
3470
3491
|
});
|
|
3471
3492
|
break;
|
|
3472
3493
|
case "drop-index":
|
|
3473
3494
|
yield* e.onDialectOrElse({
|
|
3474
|
-
mysql: () => J(e,
|
|
3475
|
-
mssql: () => J(e,
|
|
3476
|
-
orElse: () => J(e,
|
|
3495
|
+
mysql: () => J(e, go(s), s.kind),
|
|
3496
|
+
mssql: () => J(e, _o(s), s.kind),
|
|
3497
|
+
orElse: () => J(e, ho(s), s.kind)
|
|
3477
3498
|
});
|
|
3478
3499
|
break;
|
|
3479
3500
|
case "rename-table":
|
|
3480
3501
|
yield* e.onDialectOrElse({
|
|
3481
|
-
mysql: () => J(e,
|
|
3482
|
-
mssql: () => J(e,
|
|
3483
|
-
orElse: () => J(e,
|
|
3502
|
+
mysql: () => J(e, vo(s, G), s.kind),
|
|
3503
|
+
mssql: () => J(e, yo(s), s.kind),
|
|
3504
|
+
orElse: () => J(e, vo(s, W), s.kind)
|
|
3484
3505
|
});
|
|
3485
3506
|
break;
|
|
3486
3507
|
case "rename-index":
|
|
3487
3508
|
yield* e.onDialectOrElse({
|
|
3488
|
-
mysql: () => J(e,
|
|
3489
|
-
mssql: () => J(e,
|
|
3490
|
-
orElse: () => J(e,
|
|
3509
|
+
mysql: () => J(e, xo(s), s.kind),
|
|
3510
|
+
mssql: () => J(e, So(s), s.kind),
|
|
3511
|
+
orElse: () => J(e, bo(s), s.kind)
|
|
3491
3512
|
});
|
|
3492
3513
|
break;
|
|
3493
3514
|
case "add-unique":
|
|
3494
3515
|
yield* e.onDialectOrElse({
|
|
3495
|
-
mysql: () => J(e,
|
|
3496
|
-
sqlite: () => Y(e,
|
|
3497
|
-
mssql: () => X(e, [...
|
|
3498
|
-
orElse: () => J(e,
|
|
3516
|
+
mysql: () => J(e, Eo(s, n.declared), s.kind),
|
|
3517
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3518
|
+
mssql: () => X(e, [...wo(s.table, [s.column], n.declared), To(s)], s.kind),
|
|
3519
|
+
orElse: () => J(e, To(s), s.kind)
|
|
3499
3520
|
});
|
|
3500
3521
|
break;
|
|
3501
3522
|
case "drop-unique":
|
|
3502
3523
|
yield* e.onDialectOrElse({
|
|
3503
|
-
mysql: () => J(e,
|
|
3504
|
-
sqlite: () => Y(e,
|
|
3505
|
-
orElse: () => J(e,
|
|
3524
|
+
mysql: () => J(e, No(s), s.kind),
|
|
3525
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3526
|
+
orElse: () => J(e, Mo(s), s.kind)
|
|
3506
3527
|
});
|
|
3507
3528
|
break;
|
|
3508
3529
|
case "add-enum-value":
|
|
3509
3530
|
yield* e.onDialectOrElse({
|
|
3510
|
-
pg: () =>
|
|
3531
|
+
pg: () => s.enumName === void 0 ? k.die(/* @__PURE__ */ Error(`add-enum-value on postgres needs the type name for ${s.table}.${s.column}; the plan carries none.`)) : J(e, `ALTER TYPE ${O(s.enumName, "postgres")} ADD VALUE IF NOT EXISTS '${s.value.replace(/'/g, "''")}'`, s.kind),
|
|
3511
3532
|
mysql: () => {
|
|
3512
|
-
let t = K(n.declared,
|
|
3513
|
-
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? k.die(/* @__PURE__ */ Error(`add-enum-value on the mysql family needs the declared column ${
|
|
3533
|
+
let t = K(n.declared, s.table, s.column);
|
|
3534
|
+
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? k.die(/* @__PURE__ */ Error(`add-enum-value on the mysql family needs the declared column ${s.table}.${s.column} and its labels; the declaration carries none.`)) : k.flatMap(Aa(e, s.table, t, s.column), (t) => J(e, t, s.kind));
|
|
3514
3535
|
},
|
|
3515
3536
|
orElse: () => k.void
|
|
3516
3537
|
});
|
|
3517
3538
|
break;
|
|
3518
3539
|
case "add-unique-composite":
|
|
3519
3540
|
yield* e.onDialectOrElse({
|
|
3520
|
-
mysql: () => J(e,
|
|
3521
|
-
sqlite: () => Y(e,
|
|
3522
|
-
mssql: () => X(e, [...
|
|
3523
|
-
orElse: () => J(e,
|
|
3541
|
+
mysql: () => J(e, Oo(s, n.declared), s.kind),
|
|
3542
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3543
|
+
mssql: () => X(e, [...wo(s.table, s.fields, n.declared), Do(s)], s.kind),
|
|
3544
|
+
orElse: () => J(e, Do(s), s.kind)
|
|
3524
3545
|
});
|
|
3525
3546
|
break;
|
|
3526
3547
|
case "drop-unique-composite":
|
|
3527
3548
|
yield* e.onDialectOrElse({
|
|
3528
|
-
mysql: () => J(e,
|
|
3529
|
-
sqlite: () => Y(e,
|
|
3530
|
-
mssql: () => J(e,
|
|
3531
|
-
orElse: () => X(e,
|
|
3549
|
+
mysql: () => J(e, jo(s), s.kind),
|
|
3550
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3551
|
+
mssql: () => J(e, ko(s), s.kind),
|
|
3552
|
+
orElse: () => X(e, Ao(s), s.kind)
|
|
3532
3553
|
});
|
|
3533
3554
|
break;
|
|
3534
3555
|
case "add-foreign-key":
|
|
3535
3556
|
yield* e.onDialectOrElse({
|
|
3536
|
-
mysql: () => X(e,
|
|
3537
|
-
sqlite: () => Y(e,
|
|
3538
|
-
mssql: () => X(e,
|
|
3539
|
-
orElse: () => X(e,
|
|
3557
|
+
mysql: () => X(e, Po(s, G), s.kind),
|
|
3558
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3559
|
+
mssql: () => X(e, Po(s, q, qa), s.kind),
|
|
3560
|
+
orElse: () => X(e, Po(s, W), s.kind)
|
|
3540
3561
|
});
|
|
3541
3562
|
break;
|
|
3542
3563
|
case "add-column": {
|
|
3543
|
-
let
|
|
3564
|
+
let l = Ho(s, t, o, yield* e.onDialectOrElse({
|
|
3544
3565
|
mysql: () => k.succeed("mariadb"),
|
|
3545
3566
|
mssql: () => k.succeed("mssql"),
|
|
3546
3567
|
sqlite: () => k.succeed("sqlite"),
|
|
3547
3568
|
orElse: () => k.succeed("postgres")
|
|
3548
3569
|
}));
|
|
3549
|
-
if (!(r === "resume" && (yield*
|
|
3550
|
-
let
|
|
3551
|
-
if (
|
|
3552
|
-
if (t.classification !== "online-required" &&
|
|
3570
|
+
if (!(r === "resume" && (yield* Jo(e, M(e), s.table, s.column.name)))) for (let t of l.pre) yield* J(e, t, s.kind);
|
|
3571
|
+
let u = t.classification === "online-required" || l.batchSize !== void 0 || l.sleepMs !== void 0, d = k.gen(function* () {
|
|
3572
|
+
if (l.backfillKind === "sql" && l.backfillSql) {
|
|
3573
|
+
if (t.classification !== "online-required" && l.batchSize === void 0) yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${l.backfillSql}`;
|
|
3553
3574
|
else {
|
|
3554
|
-
let t =
|
|
3575
|
+
let t = l.batchSize ?? 5e3, n = l.sleepMs ?? 0, r, i = 0;
|
|
3555
3576
|
for (;;) {
|
|
3556
|
-
let a = r === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(
|
|
3577
|
+
let a = r === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL ORDER BY ${e("id")} ${V(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL AND ${e("id")} > ${r} ORDER BY ${e("id")} ${V(e, t)}`;
|
|
3557
3578
|
if (a.length === 0) break;
|
|
3558
|
-
let
|
|
3559
|
-
yield* e`UPDATE ${e(
|
|
3579
|
+
let o = a.map((e) => e.id);
|
|
3580
|
+
yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${l.backfillSql} WHERE ${e("id")} IN ${e.in(o)}`, i += a.length, yield* k.logInfo(`backfill ${s.table}.${s.column.name}: ${i} rows`).pipe(k.annotateLogs({
|
|
3560
3581
|
scope: "voltro:migrate",
|
|
3561
3582
|
mode: "sql-batched"
|
|
3562
3583
|
})), r = a[a.length - 1].id, n > 0 && (yield* k.sleep(`${n} millis`));
|
|
3563
3584
|
}
|
|
3564
3585
|
}
|
|
3565
|
-
} else if (
|
|
3566
|
-
let t =
|
|
3586
|
+
} else if (l.backfillKind === "js" && l.backfillJs) {
|
|
3587
|
+
let t = l.batchSize ?? 1e3, r = l.sleepMs ?? 0, i = n.declared.find((e) => e.tableName === s.table), a, o = 0;
|
|
3567
3588
|
for (;;) {
|
|
3568
|
-
let n = a === void 0 ? yield* e`SELECT * FROM ${e(
|
|
3589
|
+
let n = a === void 0 ? yield* e`SELECT * FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL ORDER BY ${e("id")} ${V(e, t)}` : yield* e`SELECT * FROM ${e(s.table)} WHERE ${e(s.column.name)} IS NULL AND ${e("id")} > ${a} ORDER BY ${e("id")} ${V(e, t)}`;
|
|
3569
3590
|
if (n.length === 0) break;
|
|
3570
|
-
let u = i === void 0 ? n :
|
|
3591
|
+
let u = i === void 0 ? n : ne(n, i, c);
|
|
3571
3592
|
for (let t of u) {
|
|
3572
3593
|
let n = yield* k.tryPromise({
|
|
3573
|
-
try: () => Promise.resolve(
|
|
3594
|
+
try: () => Promise.resolve(l.backfillJs(t)),
|
|
3574
3595
|
catch: (e) => e
|
|
3575
3596
|
}).pipe(k.orDie);
|
|
3576
|
-
yield* e`UPDATE ${e(
|
|
3597
|
+
yield* e`UPDATE ${e(s.table)} SET ${e(s.column.name)} = ${qo(n, s.column, c)} WHERE ${e("id")} = ${t.id}`;
|
|
3577
3598
|
}
|
|
3578
|
-
|
|
3599
|
+
o += u.length, yield* k.logInfo(`backfill ${s.table}.${s.column.name}: ${o} rows processed`).pipe(k.annotateLogs({
|
|
3579
3600
|
scope: "voltro:migrate",
|
|
3580
|
-
table:
|
|
3581
|
-
column:
|
|
3601
|
+
table: s.table,
|
|
3602
|
+
column: s.column.name
|
|
3582
3603
|
})), a = u[u.length - 1].id, r > 0 && (yield* k.sleep(`${r} millis`));
|
|
3583
3604
|
}
|
|
3584
3605
|
}
|
|
3585
|
-
}),
|
|
3586
|
-
for (let t of
|
|
3587
|
-
if (
|
|
3588
|
-
else if (
|
|
3606
|
+
}), f = k.gen(function* () {
|
|
3607
|
+
for (let t of l.post) yield* J(e, t, s.kind);
|
|
3608
|
+
if (b(c) && (l.uniquePending === !0 || l.backfillKind !== void 0 && !s.column.nullable)) yield* Y(e, s.table, n.declared, s.kind);
|
|
3609
|
+
else if (l.uniquePending === !0) {
|
|
3589
3610
|
let t = {
|
|
3590
3611
|
kind: "add-unique",
|
|
3591
|
-
table:
|
|
3592
|
-
column:
|
|
3612
|
+
table: s.table,
|
|
3613
|
+
column: s.column.name
|
|
3593
3614
|
};
|
|
3594
3615
|
yield* e.onDialectOrElse({
|
|
3595
|
-
mysql: () => J(e,
|
|
3596
|
-
mssql: () => X(e, [...
|
|
3597
|
-
orElse: () => J(e,
|
|
3616
|
+
mysql: () => J(e, Eo(t, n.declared), s.kind),
|
|
3617
|
+
mssql: () => X(e, [...wo(s.table, [s.column.name], n.declared), To(t)], s.kind),
|
|
3618
|
+
orElse: () => J(e, To(t), s.kind)
|
|
3598
3619
|
});
|
|
3599
3620
|
}
|
|
3600
3621
|
});
|
|
3601
|
-
if (i !== void 0 &&
|
|
3602
|
-
table:
|
|
3603
|
-
op:
|
|
3604
|
-
data:
|
|
3605
|
-
after:
|
|
3622
|
+
if (i !== void 0 && l.backfillKind !== void 0 && !u) return i({
|
|
3623
|
+
table: s.table,
|
|
3624
|
+
op: s,
|
|
3625
|
+
data: d,
|
|
3626
|
+
after: f
|
|
3606
3627
|
}), {
|
|
3607
|
-
op:
|
|
3628
|
+
op: s,
|
|
3608
3629
|
status: "applied",
|
|
3609
3630
|
deferred: !0,
|
|
3610
3631
|
durationMs: Number(process.hrtime.bigint() - a) / 1e6
|
|
3611
3632
|
};
|
|
3612
|
-
yield*
|
|
3633
|
+
yield* d, yield* f;
|
|
3613
3634
|
break;
|
|
3614
3635
|
}
|
|
3615
3636
|
case "alter-column-nullability":
|
|
3616
3637
|
yield* e.onDialectOrElse({
|
|
3617
3638
|
mysql: () => {
|
|
3618
|
-
let t = K(n.declared,
|
|
3619
|
-
return t ? k.flatMap(
|
|
3639
|
+
let t = K(n.declared, s.table, s.column);
|
|
3640
|
+
return t ? k.flatMap(Aa(e, s.table, t, s.column, s.toNullable), (t) => J(e, t, s.kind)) : k.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${s.table}.${s.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
3620
3641
|
},
|
|
3621
3642
|
mssql: () => {
|
|
3622
|
-
let t = K(n.declared,
|
|
3623
|
-
return t ? J(e,
|
|
3643
|
+
let t = K(n.declared, s.table, s.column);
|
|
3644
|
+
return t ? J(e, eo(t, s.column, s.table, s.toNullable), s.kind) : k.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${s.table}.${s.column}'.`));
|
|
3624
3645
|
},
|
|
3625
|
-
sqlite: () => Y(e,
|
|
3626
|
-
orElse: () => J(e, `ALTER TABLE ${W(
|
|
3646
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3647
|
+
orElse: () => J(e, `ALTER TABLE ${W(s.table)} ALTER COLUMN ${W(s.column)} ${s.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, s.kind)
|
|
3627
3648
|
});
|
|
3628
3649
|
break;
|
|
3629
3650
|
case "alter-column-default": {
|
|
3630
|
-
let t =
|
|
3651
|
+
let t = Ea(n.declared, s.table, s.column), r = K(n.declared, s.table, s.column), i = (e) => s.hasDefault && r !== void 0 && wa(r, e) ? r : void 0;
|
|
3631
3652
|
yield* e.onDialectOrElse({
|
|
3632
3653
|
mysql: () => {
|
|
3633
3654
|
let n = i("mariadb");
|
|
3634
|
-
return k.flatMap(n ?
|
|
3655
|
+
return k.flatMap(n ? Aa(e, s.table, n, s.column) : k.succeed(Ca(s, G, (e) => ja(e, t))), (t) => J(e, t, s.kind));
|
|
3635
3656
|
},
|
|
3636
3657
|
mssql: () => {
|
|
3637
3658
|
let t = i("mssql");
|
|
3638
|
-
return J(e,
|
|
3659
|
+
return J(e, to(s, t ? eo(t, s.column, s.table) : void 0), s.kind);
|
|
3639
3660
|
},
|
|
3640
|
-
sqlite: () => Y(e,
|
|
3641
|
-
orElse: () => J(e,
|
|
3661
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3662
|
+
orElse: () => J(e, Ca(s, W, (e) => Na(e, t)), s.kind)
|
|
3642
3663
|
});
|
|
3643
3664
|
break;
|
|
3644
3665
|
}
|
|
3645
3666
|
case "alter-column-type": {
|
|
3646
|
-
let r =
|
|
3667
|
+
let r = ha(Ea(n.declared, s.table, s.column) ?? { type: s.to }), i = s.using ? ` USING ${s.using}` : "";
|
|
3647
3668
|
if (t.classification !== "online-required") {
|
|
3648
3669
|
yield* e.onDialectOrElse({
|
|
3649
3670
|
mysql: () => {
|
|
3650
|
-
let t = K(n.declared,
|
|
3651
|
-
return t ? k.flatMap(
|
|
3671
|
+
let t = K(n.declared, s.table, s.column);
|
|
3672
|
+
return t ? k.flatMap(Aa(e, s.table, t, s.column), (t) => J(e, t, s.kind)) : k.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${s.table}.${s.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
3652
3673
|
},
|
|
3653
3674
|
mssql: () => {
|
|
3654
|
-
let t = K(n.declared,
|
|
3655
|
-
return t ? J(e,
|
|
3675
|
+
let t = K(n.declared, s.table, s.column);
|
|
3676
|
+
return t ? J(e, eo(t, s.column, s.table), s.kind) : k.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${s.table}.${s.column}'.`));
|
|
3656
3677
|
},
|
|
3657
|
-
sqlite: () => Y(e,
|
|
3658
|
-
orElse: () => J(e, `ALTER TABLE ${W(
|
|
3678
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3679
|
+
orElse: () => J(e, `ALTER TABLE ${W(s.table)} ALTER COLUMN ${W(s.column)} TYPE ${r}${i};`, s.kind)
|
|
3659
3680
|
});
|
|
3660
3681
|
break;
|
|
3661
3682
|
}
|
|
3662
3683
|
yield* e.onDialectOrElse({
|
|
3663
|
-
mysql: () => k.die(/* @__PURE__ */ Error(`online-required alter-column-type on ${
|
|
3684
|
+
mysql: () => k.die(/* @__PURE__ */ Error(`online-required alter-column-type on ${s.table}.${s.column} is not supported on mariadb (the shadow-swap path is postgres-only). Use a smaller-table window or an external online-DDL tool.`)),
|
|
3664
3685
|
orElse: () => k.void
|
|
3665
3686
|
});
|
|
3666
|
-
let a = `${
|
|
3667
|
-
yield* e.unsafe(`ALTER TABLE ${W(
|
|
3668
|
-
let
|
|
3687
|
+
let a = `${s.column}__shadow`, o = `${s.column}__old`;
|
|
3688
|
+
yield* e.unsafe(`ALTER TABLE ${W(s.table)} ADD COLUMN ${W(a)} ${r}`);
|
|
3689
|
+
let c = s.using ?? W(s.column), l;
|
|
3669
3690
|
for (;;) {
|
|
3670
|
-
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(
|
|
3691
|
+
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${V(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(s.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${V(e, 5e3)}`;
|
|
3671
3692
|
if (t.length === 0) break;
|
|
3672
|
-
yield* e.unsafe(`UPDATE ${W(
|
|
3693
|
+
yield* e.unsafe(`UPDATE ${W(s.table)} SET ${W(a)} = ${c} WHERE ${W(s.column)} IS NOT NULL AND ${W(a)} IS NULL AND ${W("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
3673
3694
|
}
|
|
3674
|
-
yield* k.logInfo(`alter-column-type shadow ${
|
|
3695
|
+
yield* k.logInfo(`alter-column-type shadow ${s.table}.${s.column}: shadow populated`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${W(s.table)} RENAME COLUMN ${W(s.column)} TO ${W(o)}`), yield* e.unsafe(`ALTER TABLE ${W(s.table)} RENAME COLUMN ${W(a)} TO ${W(s.column)}`), yield* e.unsafe(`ALTER TABLE ${W(s.table)} DROP COLUMN ${W(o)}`);
|
|
3675
3696
|
break;
|
|
3676
3697
|
}
|
|
3677
3698
|
case "drop-foreign-key":
|
|
3678
3699
|
yield* e.onDialectOrElse({
|
|
3679
|
-
mysql: () => J(e,
|
|
3680
|
-
sqlite: () => Y(e,
|
|
3681
|
-
orElse: () => J(e,
|
|
3700
|
+
mysql: () => J(e, Lo(s), s.kind),
|
|
3701
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3702
|
+
orElse: () => J(e, Io(s), s.kind)
|
|
3682
3703
|
});
|
|
3683
3704
|
break;
|
|
3684
3705
|
case "add-check":
|
|
3685
3706
|
yield* e.onDialectOrElse({
|
|
3686
|
-
mysql: () => J(e,
|
|
3687
|
-
sqlite: () => Y(e,
|
|
3688
|
-
orElse: () => J(e,
|
|
3707
|
+
mysql: () => J(e, Ro(s, G), s.kind),
|
|
3708
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3709
|
+
orElse: () => J(e, Ro(s, W), s.kind)
|
|
3689
3710
|
});
|
|
3690
3711
|
break;
|
|
3691
3712
|
case "convert-charset":
|
|
3692
3713
|
yield* e.onDialectOrElse({
|
|
3693
3714
|
mysql: () => k.gen(function* () {
|
|
3694
|
-
let { drops: t, rewrite: r, restores: i } =
|
|
3695
|
-
for (let n of t) yield* J(e, n,
|
|
3696
|
-
yield* J(e, r,
|
|
3697
|
-
for (let t of i) yield* J(e, t,
|
|
3715
|
+
let { drops: t, rewrite: r, restores: i } = Wa(s, n.declared, yield* ka(e, s.table));
|
|
3716
|
+
for (let n of t) yield* J(e, n, s.kind, [ca]);
|
|
3717
|
+
yield* J(e, r, s.kind);
|
|
3718
|
+
for (let t of i) yield* J(e, t, s.kind, [la]);
|
|
3698
3719
|
}),
|
|
3699
3720
|
orElse: () => k.dieMessage("convert-charset requires MySQL or MariaDB")
|
|
3700
3721
|
});
|
|
3701
3722
|
break;
|
|
3702
3723
|
case "reconcile-json-check": {
|
|
3703
|
-
let t = q(
|
|
3724
|
+
let t = q(s.column), n = s.validation === "value" ? Pt(t) : `(${t} IS NULL OR ISJSON(${t}) = 1)`;
|
|
3704
3725
|
yield* e.onDialectOrElse({
|
|
3705
|
-
mssql: () => X(e, [...
|
|
3726
|
+
mssql: () => X(e, [...s.dropConstraints.map((e) => `ALTER TABLE ${q(s.table)} DROP CONSTRAINT ${q(e)}`), `ALTER TABLE ${q(s.table)} WITH CHECK ADD CHECK ${n}`], s.kind),
|
|
3706
3727
|
orElse: () => k.dieMessage("reconcile-json-check requires SQL Server")
|
|
3707
3728
|
});
|
|
3708
3729
|
break;
|
|
3709
3730
|
}
|
|
3710
3731
|
case "drop-check": yield* e.onDialectOrElse({
|
|
3711
|
-
mysql: () =>
|
|
3712
|
-
sqlite: () => Y(e,
|
|
3713
|
-
orElse: () => J(e,
|
|
3732
|
+
mysql: () => Vo(e, s, n.declared),
|
|
3733
|
+
sqlite: () => Y(e, s.table, n.declared, s.kind),
|
|
3734
|
+
orElse: () => J(e, zo(s), s.kind)
|
|
3714
3735
|
});
|
|
3715
3736
|
}
|
|
3716
3737
|
return {
|
|
3717
|
-
op:
|
|
3738
|
+
op: s,
|
|
3718
3739
|
status: "applied",
|
|
3719
3740
|
durationMs: Number((process.hrtime.bigint() - a) / 1000000n)
|
|
3720
3741
|
};
|
|
3721
|
-
}),
|
|
3722
|
-
let
|
|
3723
|
-
if (
|
|
3724
|
-
let
|
|
3742
|
+
}), fs = (e, t, n, r, i) => k.gen(function* () {
|
|
3743
|
+
let a = [...new Set(r.map((e) => e.runId))];
|
|
3744
|
+
if (a.length > 1) return yield* k.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger holds ${a.length} unfinished runs (${a.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 \`${N}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
3745
|
+
let o = a[0], s = [...r].map((e) => ({
|
|
3725
3746
|
index: Number(e.opIndex),
|
|
3726
3747
|
status: e.status,
|
|
3727
3748
|
planned: JSON.parse(e.payload)
|
|
3728
|
-
})).sort((e, t) => e.index - t.index),
|
|
3729
|
-
if (
|
|
3730
|
-
let
|
|
3731
|
-
if (yield* k.logWarning(`migration resume: found an interrupted run (${
|
|
3749
|
+
})).sort((e, t) => e.index - t.index), c = s.find((e) => e.status === "started"), l = s.filter((e) => e.status === "started").length;
|
|
3750
|
+
if (l > 1) return yield* k.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger records ${l} operations as in-flight for run ${o}. 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 \`${N}\` by hand before re-running.`));
|
|
3751
|
+
let u = s.filter((e) => e.status === "added");
|
|
3752
|
+
if (yield* k.logWarning(`migration resume: found an interrupted run (${o}) — ${s.filter((e) => e.status === "applied").length} of ${s.length} operation(s) completed${c ? `, in flight: ${c.planned.op.kind} ${Tt(c.planned.op)}` : ""}${u.length > 0 ? `, ${u.length} column(s) added with the backfill still owed` : ""}`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), s.every((e) => e.status === "pending")) return {
|
|
3732
3753
|
kind: "discard",
|
|
3733
|
-
runId:
|
|
3754
|
+
runId: o,
|
|
3734
3755
|
why: "no operation had started — no DDL ran"
|
|
3735
3756
|
};
|
|
3736
|
-
let
|
|
3737
|
-
|
|
3757
|
+
let d = c ? yield* us(e, t, c.planned) : "clean";
|
|
3758
|
+
d !== "clean" && (n = yield* i());
|
|
3759
|
+
let f = r[0].planFingerprint;
|
|
3760
|
+
if (f !== n.toFingerprint) return {
|
|
3738
3761
|
kind: "discard",
|
|
3739
|
-
runId:
|
|
3740
|
-
why: `the declared schema changed since the interruption (recorded target ${
|
|
3762
|
+
runId: o,
|
|
3763
|
+
why: `the declared schema changed since the interruption (recorded target ${f.slice(0, 12)}…, current ${n.toFingerprint.slice(0, 12)}…) — applying the freshly-diffed plan instead`
|
|
3741
3764
|
};
|
|
3742
|
-
let
|
|
3743
|
-
return yield*
|
|
3765
|
+
let p = (e) => e.status === "applied" ? !1 : c && e.index === c.index && d !== "clean" ? d === "outstanding" : Dt(n, e.planned.op), m = s.filter(p), h = s.filter((e) => e.status !== "applied" && !p(e));
|
|
3766
|
+
return yield* os(e, o, m.map((e) => e.index), h.map((e) => e.index)), yield* k.logWarning(`migration resume: continuing run ${o} — replaying ${m.length} operation(s), ${s.length - m.length} already applied`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), {
|
|
3744
3767
|
kind: "resume",
|
|
3745
|
-
runId:
|
|
3746
|
-
ops:
|
|
3768
|
+
runId: o,
|
|
3769
|
+
ops: m.map((e) => ({
|
|
3747
3770
|
index: e.index,
|
|
3748
3771
|
planned: e.planned
|
|
3749
3772
|
})),
|
|
3750
|
-
history:
|
|
3773
|
+
history: s.filter((e) => e.status !== "pending" || p(e)).map((e) => e.planned)
|
|
3751
3774
|
};
|
|
3752
|
-
}),
|
|
3775
|
+
}), ps = (e, t, n) => k.gen(function* () {
|
|
3753
3776
|
for (let r of t.operations) {
|
|
3754
3777
|
let i = r.op;
|
|
3755
3778
|
if (i.kind !== "add-index" || !i.index.unique || i.index.where === void 0 || t.operations.some((e) => e.op.kind === "rename-table" ? e.op.to === i.table : e.op.table === i.table && [
|
|
@@ -3757,10 +3780,10 @@ BEGIN
|
|
|
3757
3780
|
"add-column",
|
|
3758
3781
|
"rename-column"
|
|
3759
3782
|
].includes(e.op.kind))) continue;
|
|
3760
|
-
let a = i.index.columns.map((e) => e.startsWith("(") ? e :
|
|
3761
|
-
if ((yield* e.unsafe(`${
|
|
3783
|
+
let a = i.index.columns.map((e) => e.startsWith("(") ? e : O(e, n)), o = n === "mssql" ? "" : a.map((e) => ` AND ${e} IS NOT NULL`).join(""), s = n === "mssql" ? "SELECT TOP (1) 1" : "SELECT 1", c = n === "mssql" ? "" : " LIMIT 1";
|
|
3784
|
+
if ((yield* e.unsafe(`${s} FROM ${O(i.table, n)} WHERE (${i.index.where})${o} GROUP BY ${a.join(", ")} HAVING COUNT(*) > 1${c}`)).length > 0) return yield* k.die(/* @__PURE__ */ Error(`applyPlan: partial unique index '${i.index.name}' on '${i.table}' conflicts with existing qualifying rows. No schema or row changes were applied. Resolve the conflicting data explicitly before retrying.`));
|
|
3762
3785
|
}
|
|
3763
|
-
}),
|
|
3786
|
+
}), ms = (e) => {
|
|
3764
3787
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3765
3788
|
return [
|
|
3766
3789
|
t.kind,
|
|
@@ -3769,13 +3792,13 @@ BEGIN
|
|
|
3769
3792
|
n("name"),
|
|
3770
3793
|
n("to")
|
|
3771
3794
|
].join("\0");
|
|
3772
|
-
},
|
|
3795
|
+
}, hs = (e, t, n) => k.acquireUseRelease(_t(e, { schema: n.lockSchema }), () => gs(e, t, n), (e) => e.release.pipe(k.orDie)), gs = (e, t, n) => k.gen(function* () {
|
|
3773
3796
|
let r = t.operations.filter((e) => e.blocked);
|
|
3774
3797
|
if (r.length > 0) return yield* k.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
3775
|
-
let i = Date.now(), a = [], o = M(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) =>
|
|
3798
|
+
let i = Date.now(), a = [], o = M(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => ms(e))), l = {
|
|
3776
3799
|
...s,
|
|
3777
3800
|
operations: s.operations.map((e) => {
|
|
3778
|
-
if (!e.blocked || !c.has(
|
|
3801
|
+
if (!e.blocked || !c.has(ms(e))) return e;
|
|
3779
3802
|
let { blocked: t, ...n } = e;
|
|
3780
3803
|
return n;
|
|
3781
3804
|
})
|
|
@@ -3789,93 +3812,99 @@ BEGIN
|
|
|
3789
3812
|
f && (yield* J(e, f, "enum-types"));
|
|
3790
3813
|
let p = Cn(n.declared, o);
|
|
3791
3814
|
p && (yield* J(e, p, "enum-types"));
|
|
3792
|
-
let m = St(o) === "plan-transactional"
|
|
3793
|
-
|
|
3815
|
+
let m = St(o) === "plan-transactional";
|
|
3816
|
+
yield* ps(e, l, o), yield* Yo(e, o, n.charset);
|
|
3817
|
+
let h = yield* ns(e), g = h.length > 0 ? yield* fs(e, o, l, h, () => n.replan(e).pipe(k.map((e) => (l = {
|
|
3818
|
+
...e,
|
|
3819
|
+
operations: e.operations.map((e) => {
|
|
3820
|
+
if (!e.blocked || !c.has(ms(e))) return e;
|
|
3821
|
+
let { blocked: t, ...n } = e;
|
|
3822
|
+
return n;
|
|
3823
|
+
})
|
|
3824
|
+
}, l)))) : void 0;
|
|
3825
|
+
if (l.operations.some((e) => e.blocked)) return yield* k.die(/* @__PURE__ */ Error("applyPlan: refusing blocked operations after interrupted-run repair. Run `voltro db plan` to inspect the remaining work."));
|
|
3826
|
+
g?.kind === "discard" && (yield* k.logWarning(`migration resume: discarding ledger of run ${g.runId} — ${g.why}`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), yield* ss(e, g.runId));
|
|
3827
|
+
let _ = (/* @__PURE__ */ new Date()).toISOString(), v = process.env.VOLTRO_SOFT_DROP === "1" ? l.operations.map((e) => Zi(e, _)) : l.operations, y = m ? v.filter((e) => e.classification !== "online-required") : [], ee = m ? v.filter((e) => e.classification === "online-required") : v, b = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, x = ee.map((e, t) => ({
|
|
3828
|
+
index: y.length + t,
|
|
3794
3829
|
planned: e
|
|
3795
|
-
})),
|
|
3796
|
-
yield*
|
|
3797
|
-
let C = yield* ts(e);
|
|
3798
|
-
if (C.length > 0) {
|
|
3799
|
-
let t = yield* ds(e, o, l, C);
|
|
3800
|
-
t.kind === "resume" ? (y = t.runId, b = t.ops, S = t.history, x = "resume") : (yield* k.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(k.annotateLogs({ scope: "voltro:migrate" })), yield* os(e, t.runId));
|
|
3801
|
-
}
|
|
3802
|
-
(_.length > 0 || b.length > 0) && n.beforeExecute !== void 0 && (yield* n.beforeExecute), x === "fresh" && b.length > 0 && (yield* rs(e, y, l.toFingerprint, b)), _.length > 0 && (yield* la(e, k.gen(function* () {
|
|
3830
|
+
})), S = "fresh", C;
|
|
3831
|
+
g?.kind === "resume" && (b = g.runId, x = g.ops, C = g.history, S = "resume"), (y.length > 0 || x.length > 0) && n.beforeExecute !== void 0 && (yield* n.beforeExecute), S === "fresh" && x.length > 0 && (yield* is(e, b, l.toFingerprint, x)), y.length > 0 && (yield* ua(e, k.gen(function* () {
|
|
3803
3832
|
let e = yield* A.SqlClient;
|
|
3804
|
-
if (
|
|
3805
|
-
let t =
|
|
3833
|
+
if (S === "resume") return yield* k.die(/* @__PURE__ */ Error("applyPlan: transactional work appeared while resuming an interrupted run with the same target. Inspect the live schema and operation ledger before retrying."));
|
|
3834
|
+
let t = y.map((e, t) => ({
|
|
3806
3835
|
index: t,
|
|
3807
3836
|
planned: e
|
|
3808
3837
|
}));
|
|
3809
|
-
yield*
|
|
3838
|
+
yield* is(e, b, l.toFingerprint, t);
|
|
3810
3839
|
let r = [], i = () => k.gen(function* () {
|
|
3811
3840
|
for (let e of r.splice(0)) yield* e.data, yield* e.after;
|
|
3812
3841
|
});
|
|
3813
|
-
for (let t of
|
|
3842
|
+
for (let t of y) Uo.has(t.op.kind) && r.length > 0 && (yield* i()), a.push(yield* ds(e, t, n, "fresh", (e) => r.push(e)));
|
|
3814
3843
|
yield* i();
|
|
3815
|
-
for (let { index: n } of t) yield*
|
|
3844
|
+
for (let { index: n } of t) yield* as(e, b, n, "applied");
|
|
3816
3845
|
})));
|
|
3817
|
-
let w = [],
|
|
3846
|
+
let w = [], te = () => k.gen(function* () {
|
|
3818
3847
|
let t = w.splice(0);
|
|
3819
3848
|
if (t.length !== 0) {
|
|
3820
|
-
yield*
|
|
3849
|
+
yield* ua(e, k.gen(function* () {
|
|
3821
3850
|
for (let e of t) yield* e.data;
|
|
3822
3851
|
}));
|
|
3823
3852
|
for (let n of t) yield* n.after, a.push({
|
|
3824
3853
|
op: n.op,
|
|
3825
3854
|
status: "applied",
|
|
3826
3855
|
durationMs: Number(process.hrtime.bigint() - n.startedAt) / 1e6
|
|
3827
|
-
}), yield*
|
|
3856
|
+
}), yield* as(e, b, n.index, "applied", Number(process.hrtime.bigint() - n.startedAt) / 1e6);
|
|
3828
3857
|
}
|
|
3829
3858
|
});
|
|
3830
|
-
for (let { index: t, planned: r } of
|
|
3831
|
-
|
|
3832
|
-
let i = a.length, o = process.hrtime.bigint(), s = yield*
|
|
3859
|
+
for (let { index: t, planned: r } of x) {
|
|
3860
|
+
Uo.has(r.op.kind) && w.length > 0 && (yield* te()), yield* as(e, b, t, "started");
|
|
3861
|
+
let i = a.length, o = process.hrtime.bigint(), s = yield* ds(e, r, n, S, (e) => w.push({
|
|
3833
3862
|
...e,
|
|
3834
3863
|
index: t,
|
|
3835
3864
|
startedAt: o
|
|
3836
|
-
})).pipe(k.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${
|
|
3865
|
+
})).pipe(k.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${x.length + y.length} operation(s) applied before this one${y.length > 0 ? ` (${y.length} of them in a transaction)` : ""}.\n` + (m ? (y.length > 0 ? "The transactional batch completed before this phase; this failure does not roll it back.\n" : "This phase runs outside a transactional batch; completed operations are not rolled back by this failure.\n") + "An enclosing deployment transaction may still undo its own changes. Inspect the live schema and operation ledger before retrying.\nThe failing operation may also have made partial progress.\n" : ` This dialect does NOT apply a plan atomically: those ${i} are COMMITTED and there is no rollback.\n The ledger records how far it got (operation ${t} was in flight).\n`) })));
|
|
3837
3866
|
if (s.deferred === !0) {
|
|
3838
|
-
yield*
|
|
3867
|
+
yield* as(e, b, t, "added");
|
|
3839
3868
|
continue;
|
|
3840
3869
|
}
|
|
3841
|
-
a.push(s), yield*
|
|
3870
|
+
a.push(s), yield* as(e, b, t, "applied", s.durationMs);
|
|
3842
3871
|
}
|
|
3843
|
-
yield*
|
|
3844
|
-
let
|
|
3845
|
-
if (
|
|
3846
|
-
let e = (e) => "column" in e ? typeof e.column == "string" ? `.${e.column}` : `.${String(e.column.name ?? "")}` : "", t =
|
|
3847
|
-
return yield* k.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${
|
|
3872
|
+
yield* te();
|
|
3873
|
+
let T = yield* n.replan(e);
|
|
3874
|
+
if (T.operations.length > 0) {
|
|
3875
|
+
let e = (e) => "column" in e ? typeof e.column == "string" ? `.${e.column}` : `.${String(e.column.name ?? "")}` : "", t = T.operations.slice(0, 10).map((t) => ` - ${t.op.kind} ${"table" in t.op ? t.op.table : ""}${e(t.op)}`).join("\n"), n = a.filter((e) => e.status === "applied"), r = n.slice(0, 10).map((t) => ` - ${t.op.kind} ${"table" in t.op ? t.op.table : ""}${e(t.op)}`).join("\n") + (n.length > 10 ? `\n … and ${n.length - 10} more` : "");
|
|
3876
|
+
return yield* k.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${T.operations.length}:\n${t}${T.operations.length > 10 ? `\n … and ${T.operations.length - 10} more` : ""}\nNo fingerprint was recorded — recording one would make the next boot report "schema up to date" for a schema that was never applied. This is a framework bug.\n` + (m ? (y.length > 0 ? "The transactional batch completed before this convergence check; this check does not roll it back.\n" : "This convergence check does not roll back completed operations; this plan had no transactional batch.\n") + `An enclosing deployment transaction may still undo its own changes. Inspect the live schema and operation ledger before retrying.\nOperations reported applied before this check:\n${r}\n` : ` This dialect does NOT apply a plan atomically. The ${n.length} operation(s) below are COMMITTED\n and there is no rollback — the schema is PART-APPLIED, not unchanged:\n${r}\n Re-running plans from where the database now is, which is a different plan from the one that failed.\n`) + "Two causes look identical from here, so read the list before assuming either:\n - the DDL for those operations is a no-op (it succeeded and changed nothing), or\n - the planner cannot see what the DDL did, so it proposes the same work again — which is what an\n operation naming an object a PREVIOUS operation created or renamed usually means.\nReport the operation kinds above with the column types involved."));
|
|
3848
3877
|
}
|
|
3849
|
-
let
|
|
3850
|
-
FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${
|
|
3851
|
-
if (
|
|
3852
|
-
let e =
|
|
3853
|
-
if (e.fingerprint !== l.toFingerprint || !Array.isArray(t) || !
|
|
3878
|
+
let E = a.filter((e) => e.status === "applied").length, ne = Date.now() - i, D = b, ie = (/* @__PURE__ */ new Date()).toISOString(), ae = yield* U(e, ie), oe = [...y, ...C ?? x.map((e) => e.planned)], se = S === "resume" ? yield* e`SELECT ${e("fingerprint")}, ${e("operations")}
|
|
3879
|
+
FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${D}` : [];
|
|
3880
|
+
if (se.length > 0) {
|
|
3881
|
+
let e = se[0], t = typeof e.operations == "string" ? JSON.parse(e.operations) : e.operations;
|
|
3882
|
+
if (e.fingerprint !== l.toFingerprint || !Array.isArray(t) || !oe.every((e) => t.some((t) => je(t, e)))) return yield* k.die(/* @__PURE__ */ Error(`applyPlan: history for resumed run ${D} does not match its recorded operations; the resume ledger was retained.`));
|
|
3854
3883
|
}
|
|
3855
|
-
|
|
3884
|
+
se.length === 0 && (yield* e`
|
|
3856
3885
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3857
3886
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
3858
3887
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
3859
3888
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
3860
3889
|
VALUES
|
|
3861
|
-
(${
|
|
3890
|
+
(${D}, ${l.toFingerprint}, ${T.fromFingerprint}, ${JSON.stringify(oe)},
|
|
3862
3891
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3863
|
-
${
|
|
3864
|
-
|
|
3865
|
-
let
|
|
3866
|
-
return yield* k.promise(() =>
|
|
3867
|
-
id:
|
|
3868
|
-
appliedAt:
|
|
3892
|
+
${ne}, ${ae}, ${n.notes ?? null})
|
|
3893
|
+
`.pipe(k.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\nMigration ${D}: schema work completed, but writing its history failed.\nThe operation ledger is retained for recovery. This error does not establish whole-plan rollback; inspect the live schema before retrying.` })))), yield* ss(e, b).pipe(k.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\nMigration ${D}: the history row was written, but operation-ledger cleanup failed.\nAn enclosing transaction may still roll back its own changes. Inspect the recorded history and any remaining operation ledger before retrying; do not assume the schema is unchanged.` })));
|
|
3894
|
+
let ce = [...new Set(oe.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3895
|
+
return yield* k.promise(() => re({ changedTables: ce }).catch(() => {})), {
|
|
3896
|
+
id: D,
|
|
3897
|
+
appliedAt: ie,
|
|
3869
3898
|
fingerprint: l.toFingerprint,
|
|
3870
|
-
operations:
|
|
3899
|
+
operations: oe,
|
|
3871
3900
|
appliedBy: n.appliedBy,
|
|
3872
3901
|
environment: n.environment,
|
|
3873
|
-
durationMs:
|
|
3874
|
-
appliedOps:
|
|
3902
|
+
durationMs: ne,
|
|
3903
|
+
appliedOps: E,
|
|
3875
3904
|
source: n.source,
|
|
3876
3905
|
...n.notes ? { notes: n.notes } : {}
|
|
3877
3906
|
};
|
|
3878
|
-
}),
|
|
3907
|
+
}), _s = (e, t) => {
|
|
3879
3908
|
switch (t.kind) {
|
|
3880
3909
|
case "drop-foreign-key": return {
|
|
3881
3910
|
...e,
|
|
@@ -3908,36 +3937,36 @@ BEGIN
|
|
|
3908
3937
|
};
|
|
3909
3938
|
}
|
|
3910
3939
|
}, Z = (e, t, n) => {
|
|
3911
|
-
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? k.void :
|
|
3940
|
+
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? k.void : Go(e, t.table, $a(_s(r, t)), t.kind);
|
|
3912
3941
|
switch (t.kind) {
|
|
3913
3942
|
case "drop-foreign-key": return e.onDialectOrElse({
|
|
3914
|
-
mysql: () => J(e,
|
|
3943
|
+
mysql: () => J(e, Lo(t), t.kind),
|
|
3915
3944
|
sqlite: i,
|
|
3916
|
-
orElse: () => J(e,
|
|
3945
|
+
orElse: () => J(e, Io(t), t.kind)
|
|
3917
3946
|
});
|
|
3918
3947
|
case "drop-index": return e.onDialectOrElse({
|
|
3919
|
-
mysql: () => J(e,
|
|
3920
|
-
mssql: () => J(e,
|
|
3921
|
-
orElse: () => J(e,
|
|
3948
|
+
mysql: () => J(e, go(t), t.kind),
|
|
3949
|
+
mssql: () => J(e, _o(t), t.kind),
|
|
3950
|
+
orElse: () => J(e, ho(t), t.kind)
|
|
3922
3951
|
});
|
|
3923
3952
|
case "drop-column": return e.onDialectOrElse({
|
|
3924
|
-
mysql: () => H(e).pipe(k.flatMap((n) => J(e,
|
|
3953
|
+
mysql: () => H(e).pipe(k.flatMap((n) => J(e, ba(t, n), t.kind, [oa]))),
|
|
3925
3954
|
sqlite: i,
|
|
3926
|
-
orElse: () => J(e,
|
|
3955
|
+
orElse: () => J(e, ya(t, W), t.kind)
|
|
3927
3956
|
});
|
|
3928
3957
|
case "rename-column": return e.onDialectOrElse({
|
|
3929
|
-
mysql: () => J(e,
|
|
3930
|
-
mssql: () =>
|
|
3931
|
-
orElse: () => J(e,
|
|
3958
|
+
mysql: () => J(e, xa(t, G), t.kind),
|
|
3959
|
+
mssql: () => Ko(e, t),
|
|
3960
|
+
orElse: () => J(e, xa(t, W), t.kind)
|
|
3932
3961
|
});
|
|
3933
3962
|
}
|
|
3934
|
-
},
|
|
3935
|
-
if (n !==
|
|
3963
|
+
}, vs = (e, t, n) => ds(e, t, { declared: n }), ys = (e) => e.literal("(source = 'file' AND id NOT LIKE 'plan!_%' ESCAPE '!')"), bs = (e) => e.literal("(source IS NULL OR source <> 'file' OR id LIKE 'plan!_%' ESCAPE '!')"), xs = "utf8mb4", Ss = (e, t) => o(e) && !t.has(e) && !e.startsWith("_cloud_") && !e.startsWith("__turso_internal_") && !r(e) && !ee(e), Cs = (e) => e.columnDefault !== null && e.columnDefault.toUpperCase() !== "NULL", ws = (e, t, n, r) => {
|
|
3964
|
+
if (n !== xs) return {
|
|
3936
3965
|
tables: [],
|
|
3937
3966
|
left: []
|
|
3938
3967
|
};
|
|
3939
|
-
let i = e.filter((e) =>
|
|
3940
|
-
for (let e of i)
|
|
3968
|
+
let i = e.filter((e) => Ss(e.table, t) && (r === void 0 || r.has(e.table)) && e.charset !== xs), a = i.filter((e) => Cs(e) || e.generated), o = /* @__PURE__ */ new Map();
|
|
3969
|
+
for (let e of i) Cs(e) || e.generated || o.set(e.table, [...o.get(e.table) ?? [], e]);
|
|
3941
3970
|
return {
|
|
3942
3971
|
tables: [...o.entries()].sort(([e], [t]) => e.localeCompare(t)).map(([e, t]) => ({
|
|
3943
3972
|
table: e,
|
|
@@ -3945,7 +3974,7 @@ BEGIN
|
|
|
3945
3974
|
})),
|
|
3946
3975
|
left: a
|
|
3947
3976
|
};
|
|
3948
|
-
},
|
|
3977
|
+
}, Ts = (e) => e.tables.length === 0 && e.left.length === 0, Es = (e) => [...e.tables.map((e) => `${e.table}: ${e.columns.length} string column${e.columns.length === 1 ? "" : "s"} ${[...new Set(e.columns.map((e) => e.charset))].sort().join("/")} → ${xs}`), ...e.left.map((e) => `${e.table}.${e.column} stays ${e.charset}: it has a ${e.generated ? "generation expression" : "default"}, which this step does not rewrite — convert it by hand`)], Ds = (e) => e.map((e) => Object.fromEntries(Object.entries(e).map(([e, t]) => [e.toLowerCase(), t]))), Os = (e) => k.map(e.unsafe("SELECT c.table_name, c.column_name, c.character_set_name, c.column_type, c.is_nullable, c.column_default, c.extra\n FROM information_schema.columns c\n JOIN information_schema.tables t ON t.table_schema = c.table_schema AND t.table_name = c.table_name\n WHERE c.table_schema = DATABASE() AND t.table_type = 'BASE TABLE' AND c.character_set_name IS NOT NULL\n ORDER BY c.table_name, c.ordinal_position"), (e) => Ds(e).map((e) => ({
|
|
3949
3978
|
table: String(e.table_name),
|
|
3950
3979
|
column: String(e.column_name),
|
|
3951
3980
|
charset: String(e.character_set_name),
|
|
@@ -3953,26 +3982,27 @@ BEGIN
|
|
|
3953
3982
|
nullable: String(e.is_nullable).toUpperCase() === "YES",
|
|
3954
3983
|
columnDefault: e.column_default === null || e.column_default === void 0 ? null : String(e.column_default),
|
|
3955
3984
|
generated: /GENERATED/i.test(String(e.extra ?? "")) && !/DEFAULT_GENERATED/i.test(String(e.extra ?? ""))
|
|
3956
|
-
}))),
|
|
3985
|
+
}))), ks = (e) => `\`${e.replace(/`/g, "``")}\``, As = (e, t = /* @__PURE__ */ new Map()) => e.tables.map((e) => `ALTER TABLE ${ks(e.table)} ${e.columns.map((n) => {
|
|
3957
3986
|
let r = t.get(e.table)?.get(n.column);
|
|
3958
|
-
return `MODIFY COLUMN ${
|
|
3959
|
-
}).join(", ")}`),
|
|
3987
|
+
return `MODIFY COLUMN ${ks(n.column)} ${n.columnType} CHARACTER SET ${xs}${n.nullable ? "" : " NOT NULL"}${r === void 0 ? "" : ` CHECK (${r})`}`;
|
|
3988
|
+
}).join(", ")}`), js = (e, t) => k.gen(function* () {
|
|
3960
3989
|
let n = /* @__PURE__ */ new Map();
|
|
3961
|
-
for (let r of t.tables) n.set(r.table, yield*
|
|
3962
|
-
for (let r of
|
|
3963
|
-
}),
|
|
3964
|
-
let n =
|
|
3965
|
-
return yield*
|
|
3966
|
-
}), { schema: t.lockSchema }),
|
|
3990
|
+
for (let r of t.tables) n.set(r.table, yield* ka(e, r.table));
|
|
3991
|
+
for (let r of As(t, n)) yield* e.unsafe(r).unprepared;
|
|
3992
|
+
}), Ms = (e, t) => bt(e, k.gen(function* () {
|
|
3993
|
+
let n = ws(yield* Os(e), t.declaredNames, t.charset);
|
|
3994
|
+
return yield* js(e, n), n;
|
|
3995
|
+
}), { schema: t.lockSchema }), Ns = (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"), Ps = (e) => e`
|
|
3967
3996
|
SELECT fingerprint
|
|
3968
3997
|
FROM _voltro_migration_plans
|
|
3998
|
+
WHERE ${bs(e)}
|
|
3969
3999
|
ORDER BY ${e("appliedAt")} DESC
|
|
3970
4000
|
${V(e, 1)}
|
|
3971
4001
|
`.pipe(k.map((e) => e.length > 0 ? e[0].fingerprint : void 0), k.catchAll((t) => e`SELECT COUNT(*) AS n FROM _voltro_migration_plans`.pipe(k.matchEffect({
|
|
3972
4002
|
onFailure: () => k.succeed(void 0),
|
|
3973
4003
|
onSuccess: () => k.die(/* @__PURE__ */ Error(`reading the newest applied plan from _voltro_migration_plans failed while the table exists — this is a query defect, not a missing ledger: ${String(t)}`))
|
|
3974
|
-
})))),
|
|
3975
|
-
if ((yield*
|
|
4004
|
+
})))), Fs = (e, t, n) => k.gen(function* () {
|
|
4005
|
+
if ((yield* Ps(e)) === t.toFingerprint) return "already-current";
|
|
3976
4006
|
let r = `plan_${Date.now().toString(36)}`, i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3977
4007
|
return yield* e`
|
|
3978
4008
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3984,8 +4014,8 @@ BEGIN
|
|
|
3984
4014
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3985
4015
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3986
4016
|
`, "recorded";
|
|
3987
|
-
}).pipe(k.catchAll(() => k.succeed("already-current"))),
|
|
3988
|
-
let r = I(Nr(t, M(e), { charset: n.charset })), i = yield*
|
|
4017
|
+
}).pipe(k.catchAll(() => k.succeed("already-current"))), Is = (e, t, n) => k.gen(function* () {
|
|
4018
|
+
let r = I(Nr(t, M(e), { charset: n.charset })), i = yield* Ps(e);
|
|
3989
4019
|
return i === r ? {
|
|
3990
4020
|
kind: "up-to-date",
|
|
3991
4021
|
fingerprint: r
|
|
@@ -3994,23 +4024,23 @@ BEGIN
|
|
|
3994
4024
|
expected: r,
|
|
3995
4025
|
...i === void 0 ? {} : { actual: i }
|
|
3996
4026
|
};
|
|
3997
|
-
}),
|
|
4027
|
+
}), Ls = [
|
|
3998
4028
|
"pgeagertest_",
|
|
3999
4029
|
"mig_e2e_",
|
|
4000
4030
|
"mig_test_",
|
|
4001
4031
|
"mysqleagertest_",
|
|
4002
4032
|
"mssqleagertest_",
|
|
4003
4033
|
"sqliteeagertest_"
|
|
4004
|
-
],
|
|
4034
|
+
], Rs = (e) => Ls.some((t) => e.startsWith(t)), zs = (e, t) => k.gen(function* () {
|
|
4005
4035
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
4006
|
-
let n = t.filter((e) =>
|
|
4036
|
+
let n = t.filter((e) => Rs(e.name)).map((e) => e.name);
|
|
4007
4037
|
if (n.length === 0) return [];
|
|
4008
4038
|
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(k.catchAll(() => k.void));
|
|
4009
4039
|
return n;
|
|
4010
|
-
}),
|
|
4040
|
+
}), Bs = () => {
|
|
4011
4041
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
4012
4042
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
4013
|
-
},
|
|
4043
|
+
}, Vs = (e) => {
|
|
4014
4044
|
if (e === void 0) return;
|
|
4015
4045
|
let t = e.trim();
|
|
4016
4046
|
if (t === "") return;
|
|
@@ -4020,67 +4050,67 @@ BEGIN
|
|
|
4020
4050
|
kind: "tables",
|
|
4021
4051
|
tables: new Set(n)
|
|
4022
4052
|
} : void 0;
|
|
4023
|
-
},
|
|
4053
|
+
}, Hs = (e) => typeof e.table == "string" ? e.table : void 0, Us = (e, t = { kind: "all" }) => ({
|
|
4024
4054
|
...e,
|
|
4025
4055
|
operations: e.operations.map((e) => {
|
|
4026
4056
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
4027
4057
|
if (t?.kind === "tables") {
|
|
4028
|
-
let n =
|
|
4058
|
+
let n = Hs(e.op);
|
|
4029
4059
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
4030
4060
|
}
|
|
4031
4061
|
let { blocked: n, ...r } = e;
|
|
4032
4062
|
return r;
|
|
4033
4063
|
})
|
|
4034
|
-
}),
|
|
4064
|
+
}), Ws = (e, t, n) => t === "postgres" ? Fr(e, n).pipe(k.flatMap((e) => {
|
|
4035
4065
|
let t = Ir(e);
|
|
4036
4066
|
return t === void 0 ? k.void : k.logWarning(`auto-migrate: ${t}`).pipe(k.annotateLogs({ scope: "voltro:migrate" }));
|
|
4037
|
-
}), k.catchAll(() => k.void)) : k.void,
|
|
4067
|
+
}), k.catchAll(() => k.void)) : k.void, Gs = (e, t, n) => k.gen(function* () {
|
|
4038
4068
|
let r = M(e), i = t;
|
|
4039
4069
|
if (n.charset === "utf8mb4") {
|
|
4040
4070
|
let r = new Set(t.map((e) => e.tableName));
|
|
4041
|
-
if (!
|
|
4042
|
-
let t = yield*
|
|
4071
|
+
if (!Ts(ws(yield* Os(e), r, n.charset))) {
|
|
4072
|
+
let t = yield* Ms(e, {
|
|
4043
4073
|
declaredNames: r,
|
|
4044
4074
|
charset: n.charset
|
|
4045
4075
|
});
|
|
4046
|
-
for (let e of
|
|
4076
|
+
for (let e of Es(t)) yield* k.logInfo(`auto-migrate: store charset — ${e}`).pipe(k.annotateLogs({ scope: "voltro:migrate" }));
|
|
4047
4077
|
}
|
|
4048
4078
|
}
|
|
4049
|
-
let a = yield*
|
|
4079
|
+
let a = yield* rs(e);
|
|
4050
4080
|
if (!a && process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
4051
4081
|
let t = I(Nr(i, r, { charset: n.charset }));
|
|
4052
|
-
if ((yield*
|
|
4082
|
+
if ((yield* Ps(e)) === t) return yield* Ws(e, r, i), {
|
|
4053
4083
|
kind: "up-to-date",
|
|
4054
4084
|
fingerprint: t
|
|
4055
4085
|
};
|
|
4056
4086
|
}
|
|
4057
|
-
let o = yield* B(e), s = yield*
|
|
4087
|
+
let o = yield* B(e), s = yield* zs(e, o.tables);
|
|
4058
4088
|
s.length > 0 && (yield* k.logInfo(`auto-migrate: reaped ${s.length} test-fixture leftover(s)`).pipe(k.annotateLogs({
|
|
4059
4089
|
scope: "voltro:migrate",
|
|
4060
4090
|
count: s.length
|
|
4061
4091
|
})), o = yield* B(e));
|
|
4062
4092
|
{
|
|
4063
|
-
let e = n.softDropRetentionDays ?? 7, t =
|
|
4064
|
-
t.length > 0 && (yield* k.logWarning(`auto-migrate: ${
|
|
4093
|
+
let e = n.softDropRetentionDays ?? 7, t = be(o, { retentionDays: e });
|
|
4094
|
+
t.length > 0 && (yield* k.logWarning(`auto-migrate: ${te(t, e)}`).pipe(k.annotateLogs({
|
|
4065
4095
|
scope: "voltro:migrate",
|
|
4066
4096
|
snapshots: t.map((e) => e.name)
|
|
4067
4097
|
})));
|
|
4068
4098
|
}
|
|
4069
|
-
let c = new Set(t.map((e) => e.tableName)), l = (e) =>
|
|
4099
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => ue(e, c), u = gi({
|
|
4070
4100
|
declared: i,
|
|
4071
4101
|
live: { tables: l(o.tables) },
|
|
4072
4102
|
dialect: r,
|
|
4073
4103
|
charset: n.charset,
|
|
4074
|
-
...
|
|
4104
|
+
...Bs()
|
|
4075
4105
|
});
|
|
4076
4106
|
if (u.summary.blocked > 0) {
|
|
4077
|
-
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
4078
|
-
if (t === void 0 || !e || (u =
|
|
4107
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Vs(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
4108
|
+
if (t === void 0 || !e || (u = Us(u, t), u.operations.some((e) => e.blocked))) return {
|
|
4079
4109
|
kind: "refused-blocked",
|
|
4080
4110
|
plan: u
|
|
4081
4111
|
};
|
|
4082
4112
|
}
|
|
4083
|
-
return u.operations.length === 0 && !a ? (yield*
|
|
4113
|
+
return u.operations.length === 0 && !a ? (yield* Fs(e, u, {
|
|
4084
4114
|
appliedBy: n.appliedBy,
|
|
4085
4115
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
4086
4116
|
source: "auto-diff"
|
|
@@ -4089,7 +4119,7 @@ BEGIN
|
|
|
4089
4119
|
fingerprint: u.toFingerprint
|
|
4090
4120
|
}) : {
|
|
4091
4121
|
kind: "applied",
|
|
4092
|
-
applied: yield*
|
|
4122
|
+
applied: yield* hs(e, u, {
|
|
4093
4123
|
...n.beforeExecute === void 0 ? {} : { beforeExecute: n.beforeExecute },
|
|
4094
4124
|
declared: t,
|
|
4095
4125
|
charset: n.charset,
|
|
@@ -4103,16 +4133,16 @@ BEGIN
|
|
|
4103
4133
|
live: { tables: l(t.tables) },
|
|
4104
4134
|
dialect: r,
|
|
4105
4135
|
charset: n.charset,
|
|
4106
|
-
...
|
|
4136
|
+
...Bs()
|
|
4107
4137
|
});
|
|
4108
4138
|
})
|
|
4109
4139
|
}),
|
|
4110
4140
|
plan: u
|
|
4111
4141
|
};
|
|
4112
|
-
}),
|
|
4142
|
+
}), Ks = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? k.succeed({
|
|
4113
4143
|
kind: "skipped",
|
|
4114
4144
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
4115
|
-
}) : n.environment === "prod" ?
|
|
4145
|
+
}) : n.environment === "prod" ? Is(e, t, n) : Gs(e, t, n).pipe(k.tap((n) => n.kind === "applied" || n.kind === "up-to-date" ? Mn(t, M(e)) : k.void)), qs = (e, t) => {
|
|
4116
4146
|
switch (e.kind) {
|
|
4117
4147
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
4118
4148
|
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${vr(e.fingerprint)})`;
|
|
@@ -4122,7 +4152,7 @@ BEGIN
|
|
|
4122
4152
|
}
|
|
4123
4153
|
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${vr(e.expected)}` + (e.actual ? ` live=${vr(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
4124
4154
|
case "refused-blocked": {
|
|
4125
|
-
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` +
|
|
4155
|
+
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` + Ns(e.plan), c = [""];
|
|
4126
4156
|
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) {
|
|
4127
4157
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
4128
4158
|
for (let r of e.plan.operations) {
|
|
@@ -4139,7 +4169,7 @@ BEGIN
|
|
|
4139
4169
|
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");
|
|
4140
4170
|
}
|
|
4141
4171
|
}
|
|
4142
|
-
},
|
|
4172
|
+
}, Js = (e) => typeof e.__definition == "function" ? _({ c: e }).c : e, Ys = (e) => {
|
|
4143
4173
|
if (typeof e != "string") return e;
|
|
4144
4174
|
let t = e.trim().replace(/::[a-zA-Z0-9_ "]+$/, "").trim();
|
|
4145
4175
|
if (/^current_timestamp(\(\d*\))?$/i.test(t) || /^now\(\)$/i.test(t)) return "now";
|
|
@@ -4151,10 +4181,11 @@ BEGIN
|
|
|
4151
4181
|
let e = r.references, i = e === void 0 ? void 0 : t.get(e.table);
|
|
4152
4182
|
n[r.name] = {
|
|
4153
4183
|
type: r.type,
|
|
4184
|
+
...r.type === "id" && Zn(r) === "numeric" ? { idScheme: { kind: "numeric" } } : {},
|
|
4154
4185
|
nullable: r.nullable,
|
|
4155
4186
|
unique: r.unique,
|
|
4156
4187
|
hasDefault: r.hasDefault,
|
|
4157
|
-
...r.hasDefault ? { defaultValue:
|
|
4188
|
+
...r.hasDefault ? { defaultValue: Ys(r.defaultValue) } : {},
|
|
4158
4189
|
...r.maxLength === void 0 ? {} : { maxLength: r.maxLength },
|
|
4159
4190
|
...r.precision === void 0 ? {} : { precision: r.precision },
|
|
4160
4191
|
...r.scale === void 0 ? {} : { scale: r.scale },
|
|
@@ -4164,6 +4195,8 @@ BEGIN
|
|
|
4164
4195
|
...r.oneOf === void 0 ? {} : { oneOf: r.oneOf },
|
|
4165
4196
|
...r.referenceStorage === void 0 ? {} : { referenceStorage: r.referenceStorage },
|
|
4166
4197
|
...r.vectorDim === void 0 ? {} : { vectorDim: r.vectorDim },
|
|
4198
|
+
...r.vectorPrecision === void 0 ? {} : { vectorPrecision: r.vectorPrecision },
|
|
4199
|
+
...r.generatedAs === void 0 ? {} : { generatedAs: r.generatedAs },
|
|
4167
4200
|
...r.spatial === void 0 ? {} : { spatial: r.spatial },
|
|
4168
4201
|
...e === void 0 ? {} : {
|
|
4169
4202
|
references: () => i === void 0 ? {
|
|
@@ -4196,14 +4229,14 @@ BEGIN
|
|
|
4196
4229
|
})),
|
|
4197
4230
|
...e.primaryKey === void 0 ? {} : { appliedPrimaryKey: e.primaryKey }
|
|
4198
4231
|
};
|
|
4199
|
-
},
|
|
4232
|
+
}, Xs = (e) => {
|
|
4200
4233
|
let t = new Map(e.tables.map((e) => [e.name, e]));
|
|
4201
4234
|
return e.tables.map((e) => Q(e, t));
|
|
4202
|
-
},
|
|
4235
|
+
}, Zs = (e, t = "safe") => ({
|
|
4203
4236
|
op: e,
|
|
4204
4237
|
classification: t,
|
|
4205
4238
|
reason: "file migration schema operation"
|
|
4206
|
-
}), $ = "this context was built over an in-memory store without a `sql` client, and this needs a live connection. Run the migration against a database (the runner supplies the client), or keep a database-free test to `each`, `rewrite`, `expect`, `skipUnless`, `store`, `log`, `schema.tableExists`, `schema.columnExists` and a Promise body under `transactional`.",
|
|
4239
|
+
}), $ = "this context was built over an in-memory store without a `sql` client, and this needs a live connection. Run the migration against a database (the runner supplies the client), or keep a database-free test to `each`, `rewrite`, `expect`, `skipUnless`, `store`, `log`, `schema.tableExists`, `schema.columnExists` and a Promise body under `transactional`.", Qs = {
|
|
4207
4240
|
snapshot: "the in-memory store holds rows, not a catalog — it has no column types, defaults, indexes or constraints to report. `schema.tableExists` and `schema.columnExists` answer from the rows it holds; a body that needs the whole shape needs a database.",
|
|
4208
4241
|
indexExists: "the in-memory store has no indexes — every read of it is a scan — so there is no honest answer to give, and `false` would claim an index is absent from a store that could never have had one. Run this migration against a database, or guard on `schema.tableExists` / `schema.columnExists`, which the store can answer.",
|
|
4209
4242
|
foreignKeyExists: "the in-memory store has no constraints, so there is no honest answer to give, and `false` would claim a foreign key is absent from a store that could never have had one. Run this migration against a database, or guard on `schema.tableExists` / `schema.columnExists`, which the store can answer.",
|
|
@@ -4220,31 +4253,31 @@ BEGIN
|
|
|
4220
4253
|
dropColumn: $,
|
|
4221
4254
|
renameColumn: $,
|
|
4222
4255
|
truncate: $
|
|
4223
|
-
},
|
|
4256
|
+
}, $s = "this context was built over a store that cannot report the tables it holds (`DataStore.storedTables` is not implemented), so the question has no honest answer here. Use the in-memory store `@voltro/runtime` ships, or run the migration against a database.", ec = (e, t) => {
|
|
4224
4257
|
let n = () => {
|
|
4225
4258
|
let e = t.storedTables;
|
|
4226
4259
|
if (e !== void 0) return new Map(e.call(t).map((e) => [e.table, e]));
|
|
4227
|
-
}, r = (t, n) => k.fail(new
|
|
4260
|
+
}, r = (t, n) => k.fail(new s(e, t, n));
|
|
4228
4261
|
return {
|
|
4229
4262
|
tableExists: (e) => k.suspend(() => {
|
|
4230
4263
|
let t = n();
|
|
4231
|
-
return t === void 0 ? r("schema.tableExists()",
|
|
4264
|
+
return t === void 0 ? r("schema.tableExists()", $s) : k.succeed(t.has(e));
|
|
4232
4265
|
}),
|
|
4233
4266
|
columnExists: (e, t) => k.suspend(() => {
|
|
4234
4267
|
let i = n();
|
|
4235
|
-
if (i === void 0) return r("schema.columnExists()",
|
|
4268
|
+
if (i === void 0) return r("schema.columnExists()", $s);
|
|
4236
4269
|
let a = i.get(e);
|
|
4237
4270
|
return a === void 0 ? k.succeed(!1) : a.rowCount === 0 ? r(`schema.columnExists(${JSON.stringify(e)}, ${JSON.stringify(t)})`, `${e} is in this store and holds no rows, and a column exists in a store without a catalog only as a key on a row — so "no such column" and "no row has said yet" are the same observation, and answering either would be a guess. Seed ${e} with a row carrying the columns this migration guards on, or run the migration against a database.`) : k.succeed(a.columns.includes(t));
|
|
4238
4271
|
})
|
|
4239
4272
|
};
|
|
4240
|
-
},
|
|
4241
|
-
let n = { ...
|
|
4242
|
-
for (let [t, r] of Object.entries(
|
|
4273
|
+
}, tc = (e, t) => {
|
|
4274
|
+
let n = { ...ec(e, t) };
|
|
4275
|
+
for (let [t, r] of Object.entries(Qs)) n[t] = () => k.fail(new s(e, `schema.${t}()`, r));
|
|
4243
4276
|
return n;
|
|
4244
|
-
},
|
|
4277
|
+
}, nc = (e) => typeof e == "function" && typeof e.onDialectOrElse == "function", rc = (e) => k.isEffect(e) ? e : k.tryPromise({
|
|
4245
4278
|
try: () => e,
|
|
4246
4279
|
catch: (e) => e
|
|
4247
|
-
}),
|
|
4280
|
+
}), ic = (e, t, n) => t.run === void 0 ? Promise.reject(new s(e, "transactional() with an Effect body", "an Effect returned from `transactional` runs ON the transaction's connection, and this store has none. Return a Promise body that uses the transaction's `store`, or run the migration against a database.")) : t.run(n), ac = (e, t) => {
|
|
4248
4281
|
let n = e.run;
|
|
4249
4282
|
if (n === void 0) return t;
|
|
4250
4283
|
let r = {};
|
|
@@ -4256,19 +4289,19 @@ BEGIN
|
|
|
4256
4289
|
});
|
|
4257
4290
|
}
|
|
4258
4291
|
return r;
|
|
4259
|
-
},
|
|
4292
|
+
}, oc = (e, t, n) => {
|
|
4260
4293
|
let r = () => B(e), i = (e, t) => e.tables.find((e) => e.name === t), a = (e, t, n) => i(e, t)?.columns.find((e) => e.name === n), o = (e) => k.succeed(e), s = (e) => new Map(e.tables.map((e) => [e.name, e])), c = (e, t) => {
|
|
4261
4294
|
let n = i(e, t);
|
|
4262
4295
|
if (n === void 0) throw Error(`schema: table ${t} does not exist`);
|
|
4263
4296
|
return n;
|
|
4264
4297
|
}, l = (n) => k.gen(function* () {
|
|
4265
|
-
let i = () => r().pipe(k.map((e) => ({ tables: e.tables.filter((e) => e.name === n.tableName) }))), a =
|
|
4298
|
+
let i = () => r().pipe(k.map((e) => ({ tables: e.tables.filter((e) => e.name === n.tableName) }))), a = Us(gi({
|
|
4266
4299
|
declared: [n],
|
|
4267
4300
|
live: yield* i(),
|
|
4268
4301
|
dialect: t
|
|
4269
4302
|
})), o = a.operations.filter((e) => e.blocked !== void 0);
|
|
4270
4303
|
if (o.length > 0) return yield* k.fail(/* @__PURE__ */ Error(`evolve(${n.tableName}): ${o.length} operation(s) cannot be planned:\n` + o.map((e) => ` - ${e.op.kind}: ${e.blocked?.fix ?? e.reason}`).join("\n")));
|
|
4271
|
-
for (let t of a.operations) yield*
|
|
4304
|
+
for (let t of a.operations) yield* vs(e, t, [n]);
|
|
4272
4305
|
let s = gi({
|
|
4273
4306
|
declared: [n],
|
|
4274
4307
|
live: yield* i(),
|
|
@@ -4283,14 +4316,14 @@ BEGIN
|
|
|
4283
4316
|
return (yield* r()).tables.some((t) => t.name === e.tableName) ? yield* o("already-present") : (yield* l(e), "applied");
|
|
4284
4317
|
}),
|
|
4285
4318
|
dropTable: (t) => k.gen(function* () {
|
|
4286
|
-
return (yield* r()).tables.some((e) => e.name === t) ? (yield*
|
|
4319
|
+
return (yield* r()).tables.some((e) => e.name === t) ? (yield* vs(e, Zs({
|
|
4287
4320
|
kind: "drop-table",
|
|
4288
4321
|
table: t
|
|
4289
4322
|
}, "lossy"), []), "applied") : yield* o("already-absent");
|
|
4290
4323
|
}),
|
|
4291
4324
|
renameTable: (t, n) => k.gen(function* () {
|
|
4292
4325
|
let a = yield* r(), s = i(a, t) !== void 0, l = i(a, n) !== void 0;
|
|
4293
|
-
return !s && l ? yield* o("already-present") : s ? l ? yield* k.fail(/* @__PURE__ */ Error(`renameTable: ${n} already exists beside ${t}`)) : (yield*
|
|
4326
|
+
return !s && l ? yield* o("already-present") : s ? l ? yield* k.fail(/* @__PURE__ */ Error(`renameTable: ${n} already exists beside ${t}`)) : (yield* vs(e, Zs({
|
|
4294
4327
|
kind: "rename-table",
|
|
4295
4328
|
from: t,
|
|
4296
4329
|
to: n
|
|
@@ -4299,7 +4332,7 @@ BEGIN
|
|
|
4299
4332
|
addColumn: (t, n, i) => k.gen(function* () {
|
|
4300
4333
|
let a = yield* r(), u = c(a, t);
|
|
4301
4334
|
if (u.columns.some((e) => e.name === n)) return yield* o("already-present");
|
|
4302
|
-
let d =
|
|
4335
|
+
let d = Js(i);
|
|
4303
4336
|
if (!d.nullable && !d.hasDefault && d.backfill === void 0) {
|
|
4304
4337
|
let r = yield* e`SELECT COUNT(*) AS n FROM ${e(t)}`;
|
|
4305
4338
|
if (Number(r[0]?.n ?? 0) > 0) return yield* k.fail(/* @__PURE__ */ Error(`addColumn(${t}.${n}): a NOT NULL column without a default cannot be added to a table with rows on any dialect. Add it nullable or with a default, fill it (rewrite), then alterColumn(${JSON.stringify(t)}, ${JSON.stringify(n)}, { nullable: false }).`));
|
|
@@ -4435,13 +4468,13 @@ BEGIN
|
|
|
4435
4468
|
}, s), "applied") : yield* k.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${n} does not exist`));
|
|
4436
4469
|
})
|
|
4437
4470
|
};
|
|
4438
|
-
},
|
|
4471
|
+
}, sc = (e, t, n, r) => {
|
|
4439
4472
|
let i;
|
|
4440
4473
|
return (async function* () {
|
|
4441
4474
|
for (;;) {
|
|
4442
|
-
let a = [i === void 0 ? void 0 :
|
|
4475
|
+
let a = [i === void 0 ? void 0 : se("id", i), r].filter((e) => e !== void 0), o = await e.query({
|
|
4443
4476
|
table: t,
|
|
4444
|
-
predicate: a.length === 0 ? void 0 : a.length === 1 ? a[0] :
|
|
4477
|
+
predicate: a.length === 0 ? void 0 : a.length === 1 ? a[0] : ie(...a),
|
|
4445
4478
|
order: [{
|
|
4446
4479
|
column: "id",
|
|
4447
4480
|
direction: "asc"
|
|
@@ -4457,8 +4490,8 @@ BEGIN
|
|
|
4457
4490
|
if (i = s, yield o, o.length < n) return;
|
|
4458
4491
|
}
|
|
4459
4492
|
})();
|
|
4460
|
-
},
|
|
4461
|
-
let i = r.batchSize ?? 1e3, a = 0, o = 0, s =
|
|
4493
|
+
}, cc = (e) => e > 0 ? k.sleep(`${e} millis`) : k.void, lc = (e) => (t, n, r = {}) => k.gen(function* () {
|
|
4494
|
+
let i = r.batchSize ?? 1e3, a = 0, o = 0, s = sc(e, t, i);
|
|
4462
4495
|
for (;;) {
|
|
4463
4496
|
let e = yield* k.tryPromise({
|
|
4464
4497
|
try: () => s.next(),
|
|
@@ -4466,16 +4499,16 @@ BEGIN
|
|
|
4466
4499
|
});
|
|
4467
4500
|
if (e.done) break;
|
|
4468
4501
|
o++;
|
|
4469
|
-
for (let t of e.value) yield*
|
|
4470
|
-
yield*
|
|
4502
|
+
for (let t of e.value) yield* rc(n(t)), a++;
|
|
4503
|
+
yield* cc(r.sleepMs ?? 0);
|
|
4471
4504
|
}
|
|
4472
4505
|
return {
|
|
4473
4506
|
scanned: a,
|
|
4474
4507
|
pages: o
|
|
4475
4508
|
};
|
|
4476
|
-
}),
|
|
4509
|
+
}), uc = (e, t) => t == null ? ye(e) : me(e, t), dc = (e) => typeof e != "object" || !e || e instanceof Date, fc = (e, t) => k.gen(function* () {
|
|
4477
4510
|
if (e === void 0) return [];
|
|
4478
|
-
let n = (yield* B(e)).tables.find((e) => e.name === t)?.columns ?? [], r = new Set(n.map((e) => e.name)), i =
|
|
4511
|
+
let n = (yield* B(e)).tables.find((e) => e.name === t)?.columns ?? [], r = new Set(n.map((e) => e.name)), i = xe(t)?.fields;
|
|
4479
4512
|
return n.filter((e) => e.type === "timestamp" || e.type === "date" || i?.[e.name]?.type === "timestamp" || i?.[e.name]?.type === "date").map((e, t) => {
|
|
4480
4513
|
let n = `__voltro_rewrite_guard_${t}`;
|
|
4481
4514
|
for (; r.has(n);) n += "_";
|
|
@@ -4484,30 +4517,30 @@ BEGIN
|
|
|
4484
4517
|
alias: n
|
|
4485
4518
|
};
|
|
4486
4519
|
});
|
|
4487
|
-
}),
|
|
4488
|
-
let
|
|
4489
|
-
let s =
|
|
4520
|
+
}), pc = (e, t, n, r) => (i, o, s = {}) => k.gen(function* () {
|
|
4521
|
+
let c = s.batchSize ?? 1e3, l = s.maxPasses ?? 10, d = s.guard ?? [], f = yield* fc(n, i), p = /* @__PURE__ */ new WeakMap(), h = f.length === 0 || n === void 0 ? t : { query: async (o) => {
|
|
4522
|
+
let s = a(o, n), c = f.map(({ column: e, alias: t }) => n`${n.onDialectOrElse({
|
|
4490
4523
|
mysql: () => n`CAST(${n(e)} AS CHAR)`,
|
|
4491
4524
|
mssql: () => n`CONVERT(VARCHAR(40), ${n(e)}, 127)`,
|
|
4492
4525
|
orElse: () => n`CAST(${n(e)} AS TEXT)`
|
|
4493
4526
|
})} AS ${n(t)}`);
|
|
4494
|
-
return (await
|
|
4527
|
+
return (await ic(e, t, n`SELECT *, ${n.csv(c)} FROM (${s}) AS ${n("__voltro_rewrite_rows")} ORDER BY ${n("id")} ASC`)).map((e) => {
|
|
4495
4528
|
let t = { ...e }, n = /* @__PURE__ */ new Map();
|
|
4496
4529
|
for (let { column: e, alias: r } of f) n.set(e, t[r]), delete t[r];
|
|
4497
|
-
let
|
|
4498
|
-
return p.set(
|
|
4530
|
+
let a = u([t], i, r)[0];
|
|
4531
|
+
return p.set(a, n), a;
|
|
4499
4532
|
});
|
|
4500
|
-
} },
|
|
4533
|
+
} }, g = {
|
|
4501
4534
|
passes: 0,
|
|
4502
4535
|
scanned: 0,
|
|
4503
4536
|
rewritten: 0,
|
|
4504
4537
|
contended: 0
|
|
4505
|
-
},
|
|
4506
|
-
for (let e = 1; e <=
|
|
4507
|
-
let n = 0, r = 0,
|
|
4538
|
+
}, _ = g;
|
|
4539
|
+
for (let e = 1; e <= l; e++) {
|
|
4540
|
+
let n = 0, r = 0, a = 0, l = sc(h, i, c);
|
|
4508
4541
|
for (;;) {
|
|
4509
4542
|
let e = yield* k.tryPromise({
|
|
4510
|
-
try: () =>
|
|
4543
|
+
try: () => l.next(),
|
|
4511
4544
|
catch: (e) => e
|
|
4512
4545
|
});
|
|
4513
4546
|
if (e.done) break;
|
|
@@ -4520,36 +4553,36 @@ BEGIN
|
|
|
4520
4553
|
if (e === void 0) continue;
|
|
4521
4554
|
let c = Object.entries(e).filter(([e, t]) => !Object.is(s[e], t));
|
|
4522
4555
|
if (c.length === 0) continue;
|
|
4523
|
-
let l = [
|
|
4524
|
-
for (let [e] of c)
|
|
4525
|
-
for (let e of d) l.push(
|
|
4556
|
+
let l = [me("id", s.id)], u = (e) => p.get(s)?.has(e) ? p.get(s).get(e) : s[e];
|
|
4557
|
+
for (let [e] of c) dc(s[e]) && l.push(uc(e, u(e)));
|
|
4558
|
+
for (let e of d) l.push(uc(e, u(e)));
|
|
4526
4559
|
(yield* k.tryPromise({
|
|
4527
|
-
try: () => t.updateMany(
|
|
4560
|
+
try: () => t.updateMany(i, Object.fromEntries(c), { where: ie(...l) }),
|
|
4528
4561
|
catch: (e) => e
|
|
4529
|
-
})) === 1 ? r++ :
|
|
4562
|
+
})) === 1 ? r++ : a++;
|
|
4530
4563
|
}
|
|
4531
|
-
yield*
|
|
4564
|
+
yield* cc(s.sleepMs ?? 0);
|
|
4532
4565
|
}
|
|
4533
|
-
if (
|
|
4566
|
+
if (_ = {
|
|
4534
4567
|
passes: e,
|
|
4535
4568
|
scanned: n,
|
|
4536
4569
|
rewritten: r,
|
|
4537
|
-
contended:
|
|
4538
|
-
},
|
|
4570
|
+
contended: a
|
|
4571
|
+
}, g = {
|
|
4539
4572
|
passes: e,
|
|
4540
|
-
scanned:
|
|
4541
|
-
rewritten:
|
|
4542
|
-
contended:
|
|
4543
|
-
}, r === 0 &&
|
|
4573
|
+
scanned: g.scanned + n,
|
|
4574
|
+
rewritten: g.rewritten + r,
|
|
4575
|
+
contended: g.contended + a
|
|
4576
|
+
}, r === 0 && a === 0) return g;
|
|
4544
4577
|
}
|
|
4545
|
-
return yield* k.fail(new
|
|
4546
|
-
}),
|
|
4578
|
+
return yield* k.fail(new m(i, _));
|
|
4579
|
+
}), mc = (e) => {
|
|
4547
4580
|
let { migrationId: t } = e, n = `migrations:file:${t}`;
|
|
4548
|
-
if (e.sql !== void 0 &&
|
|
4549
|
-
if (e.sql === void 0 && e.store.run !== void 0) throw new
|
|
4581
|
+
if (e.sql !== void 0 && !nc(e.sql)) throw new s(t, "makeFileMigrationContext()", `\`sql\` is not an @effect/sql client (got ${typeof e.sql}). Pass the client the store executes on, or omit \`sql\` to drive the body over an in-memory store.`);
|
|
4582
|
+
if (e.sql === void 0 && e.store.run !== void 0) throw new s(t, "makeFileMigrationContext()", "a SQL-backed store was given without `sql`. Its migration context runs `raw()`, `schema` and the guarded rewrite on the client the store executes on; pass that client, or use an in-memory store for a database-free test.");
|
|
4550
4583
|
let r = e.sql, i = [], a = (e) => {
|
|
4551
4584
|
if (typeof e != "string" || e.trim().length < 12) throw Error(`raw(reason): say why this migration needs raw SQL — the reason is what a reviewer and \`voltro doctor\` read (got ${JSON.stringify(e)})`);
|
|
4552
|
-
if (r === void 0) throw new
|
|
4585
|
+
if (r === void 0) throw new s(t, `raw(${JSON.stringify(e)})`, $);
|
|
4553
4586
|
return r;
|
|
4554
4587
|
};
|
|
4555
4588
|
return {
|
|
@@ -4569,9 +4602,9 @@ BEGIN
|
|
|
4569
4602
|
...t ?? {}
|
|
4570
4603
|
}))
|
|
4571
4604
|
},
|
|
4572
|
-
schema: r === void 0 ?
|
|
4573
|
-
each:
|
|
4574
|
-
rewrite:
|
|
4605
|
+
schema: r === void 0 ? tc(t, o) : ac(o, oc(r, e.dialect, o)),
|
|
4606
|
+
each: lc(o),
|
|
4607
|
+
rewrite: pc(t, o, r, e.dialect),
|
|
4575
4608
|
expect: (e, t) => {
|
|
4576
4609
|
i.push({
|
|
4577
4610
|
description: e,
|
|
@@ -4579,7 +4612,7 @@ BEGIN
|
|
|
4579
4612
|
});
|
|
4580
4613
|
},
|
|
4581
4614
|
skipUnless: (e, t) => k.gen(function* () {
|
|
4582
|
-
if (!(typeof e == "boolean" ? e : yield*
|
|
4615
|
+
if (!(typeof e == "boolean" ? e : yield* rc(e))) return yield* k.fail(new d(t));
|
|
4583
4616
|
})
|
|
4584
4617
|
}))(e.store),
|
|
4585
4618
|
transactional: (n) => k.tryPromise({
|
|
@@ -4588,19 +4621,19 @@ BEGIN
|
|
|
4588
4621
|
store: e,
|
|
4589
4622
|
raw: a
|
|
4590
4623
|
});
|
|
4591
|
-
return k.isEffect(r) ?
|
|
4624
|
+
return k.isEffect(r) ? ic(t, e, r) : r;
|
|
4592
4625
|
}),
|
|
4593
4626
|
catch: (e) => e
|
|
4594
4627
|
})
|
|
4595
4628
|
},
|
|
4596
4629
|
expectations: i
|
|
4597
4630
|
};
|
|
4598
|
-
},
|
|
4631
|
+
}, hc = (e) => k.gen(function* () {
|
|
4599
4632
|
let t = [];
|
|
4600
|
-
for (let { description: n, check: r } of e) (yield*
|
|
4633
|
+
for (let { description: n, check: r } of e) (yield* rc(r())) || t.push(n);
|
|
4601
4634
|
return t;
|
|
4602
|
-
}),
|
|
4603
|
-
let t = [], n = (e) => (n) => (!n && !t.some((t) =>
|
|
4635
|
+
}), gc = (e) => e.kind === "table" ? e.table : `${e.table}.${e.name}`, _c = (e, t) => e.kind === t.kind && e.table === t.table && gc(e) === gc(t), vc = (e) => {
|
|
4636
|
+
let t = [], n = (e) => (n) => (!n && !t.some((t) => _c(t, e)) && t.push(e), n), r = (e, t) => (...r) => e(...r).pipe(k.map(n(t(...r)))), i = {
|
|
4604
4637
|
tableExists: r(e.schema.tableExists, (e) => ({
|
|
4605
4638
|
kind: "table",
|
|
4606
4639
|
table: e
|
|
@@ -4631,9 +4664,9 @@ BEGIN
|
|
|
4631
4664
|
},
|
|
4632
4665
|
absent: () => t.slice()
|
|
4633
4666
|
};
|
|
4634
|
-
},
|
|
4667
|
+
}, yc = (e) => {
|
|
4635
4668
|
let t = [], n = (e) => {
|
|
4636
|
-
t.some((t) =>
|
|
4669
|
+
t.some((t) => _c(t, e)) || t.push(e);
|
|
4637
4670
|
};
|
|
4638
4671
|
for (let t of e.operations) {
|
|
4639
4672
|
let e = t.op;
|
|
@@ -4676,17 +4709,17 @@ BEGIN
|
|
|
4676
4709
|
}
|
|
4677
4710
|
}
|
|
4678
4711
|
return t;
|
|
4679
|
-
},
|
|
4680
|
-
let n =
|
|
4712
|
+
}, bc = (e, t) => {
|
|
4713
|
+
let n = yc(t);
|
|
4681
4714
|
return n.length === 0 ? [] : e.flatMap((e) => {
|
|
4682
|
-
let t = e.absent.filter((e) => n.some((t) =>
|
|
4715
|
+
let t = e.absent.filter((e) => n.some((t) => _c(t, e)));
|
|
4683
4716
|
return t.length === 0 ? [] : [{
|
|
4684
4717
|
id: e.id,
|
|
4685
4718
|
reason: e.reason,
|
|
4686
4719
|
created: t
|
|
4687
4720
|
}];
|
|
4688
4721
|
});
|
|
4689
|
-
},
|
|
4722
|
+
}, xc = Ae({ scope: "voltro:migrate" }), Sc = (e) => Oe("sha256").update(e).digest("hex").slice(0, 16), Cc = [{
|
|
4690
4723
|
codemod: "0.78.0/01_file-migration-phase",
|
|
4691
4724
|
inverse: (e) => {
|
|
4692
4725
|
let t = /\n {2}phase: 'before-schema',\n {2}/g, n = /\n {2}phase: 'before-schema'(?=\r?\n[ \t]*\})/g, r = e.includes("\r\n") ? "\r\n" : "\n", i = (t) => {
|
|
@@ -4695,7 +4728,7 @@ BEGIN
|
|
|
4695
4728
|
};
|
|
4696
4729
|
return [e.replace(t, (e, t) => r + i(t)).replace(n, ""), e.replace(t, " ").replace(n, "")];
|
|
4697
4730
|
}
|
|
4698
|
-
}],
|
|
4731
|
+
}], wc = (e) => new Set([e, ...Cc.flatMap((t) => t.inverse(e))].map(Sc)), Tc = /* @__PURE__ */ new Set([
|
|
4699
4732
|
"node_modules",
|
|
4700
4733
|
"dist",
|
|
4701
4734
|
"build",
|
|
@@ -4704,11 +4737,11 @@ BEGIN
|
|
|
4704
4737
|
".next",
|
|
4705
4738
|
".git",
|
|
4706
4739
|
".framework"
|
|
4707
|
-
]),
|
|
4740
|
+
]), Ec = async (e) => {
|
|
4708
4741
|
let t = [], n = async (e) => {
|
|
4709
4742
|
let r = await Me.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
4710
4743
|
for (let i of r) {
|
|
4711
|
-
if (
|
|
4744
|
+
if (Tc.has(i.name)) continue;
|
|
4712
4745
|
let r = Ne(e, i.name);
|
|
4713
4746
|
i.isDirectory() ? await n(r) : i.isFile() && le.test(i.name) && t.push(r);
|
|
4714
4747
|
}
|
|
@@ -4717,42 +4750,42 @@ BEGIN
|
|
|
4717
4750
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
4718
4751
|
return n.localeCompare(r);
|
|
4719
4752
|
});
|
|
4720
|
-
},
|
|
4753
|
+
}, Dc = async (e) => await import(Pe(e).href), Oc = async (e, t = Dc) => {
|
|
4721
4754
|
let n = [];
|
|
4722
4755
|
for (let r of e) {
|
|
4723
4756
|
let e = (await t(r)).default;
|
|
4724
|
-
if (!
|
|
4725
|
-
|
|
4757
|
+
if (!T(e)) {
|
|
4758
|
+
xc.warn("migration file has no default-exported `migration(...)` — skipped", { file: r });
|
|
4726
4759
|
continue;
|
|
4727
4760
|
}
|
|
4728
4761
|
let i = await Me.readFile(r, "utf8").catch(() => "");
|
|
4729
4762
|
n.push({
|
|
4730
4763
|
file: r,
|
|
4731
4764
|
migration: e,
|
|
4732
|
-
hash:
|
|
4733
|
-
accepted:
|
|
4765
|
+
hash: Sc(i),
|
|
4766
|
+
accepted: wc(i)
|
|
4734
4767
|
});
|
|
4735
4768
|
}
|
|
4736
4769
|
return n;
|
|
4737
|
-
},
|
|
4770
|
+
}, kc = "_voltro_migration_plans", Ac = (e) => jc(e).pipe(k.map((e) => e.map((e) => e.id))), jc = (e) => Xi(e, kc).pipe(k.flatMap((t) => t ? e`
|
|
4738
4771
|
SELECT ${e("id")}, ${e("fingerprint")}
|
|
4739
|
-
FROM ${e(
|
|
4740
|
-
WHERE ${e
|
|
4772
|
+
FROM ${e(kc)}
|
|
4773
|
+
WHERE ${ys(e)}
|
|
4741
4774
|
`.pipe(k.map((e) => e.map((e) => ({
|
|
4742
4775
|
id: e.id,
|
|
4743
4776
|
hash: e.fingerprint ?? ""
|
|
4744
|
-
})))) : k.succeed([]))),
|
|
4777
|
+
})))) : k.succeed([]))), Mc = (e, t) => t.filter((t) => {
|
|
4745
4778
|
let n = e.get(t.migration.id);
|
|
4746
4779
|
return n !== void 0 && n !== "" && !t.accepted.has(n);
|
|
4747
|
-
}).map((e) => e.migration.id),
|
|
4780
|
+
}).map((e) => e.migration.id), Nc = /* @__PURE__ */ new Set(), Pc = (e) => C(pe(e))?.kind === "unique", Fc = class extends Error {
|
|
4748
4781
|
migrationId;
|
|
4749
4782
|
file;
|
|
4750
4783
|
cause;
|
|
4751
4784
|
_tag = "FileMigrationLedgerError";
|
|
4752
4785
|
constructor(e, t, n) {
|
|
4753
|
-
super(
|
|
4786
|
+
super(Pc(n) ? `migration ${e}: up() SUCCEEDED here, and ANOTHER process had already recorded the same migration.\n The body has run TWICE. The ledger row is correct — do not delete it; the next run will not apply ${t} again.\n Two processes applied it without being serialised by the migration lock: check that both reach the same database and lock schema.\n Cause: ${n instanceof Error ? n.message : String(n)}` : `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";
|
|
4754
4787
|
}
|
|
4755
|
-
},
|
|
4788
|
+
}, Ic = (e, t, n) => k.gen(function* () {
|
|
4756
4789
|
let r = yield* U(e, n.appliedAtIso);
|
|
4757
4790
|
yield* e`
|
|
4758
4791
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -4767,27 +4800,27 @@ BEGIN
|
|
|
4767
4800
|
}])},
|
|
4768
4801
|
${n.appliedBy}, ${n.env}, ${"file"},
|
|
4769
4802
|
${n.durationMs}, ${r}, ${n.notes})
|
|
4770
|
-
`.pipe(k.mapError((e) => new
|
|
4771
|
-
}),
|
|
4772
|
-
for (let t of
|
|
4773
|
-
},
|
|
4774
|
-
let r =
|
|
4803
|
+
`.pipe(k.mapError((e) => new Fc(t.migration.id, t.file, e)));
|
|
4804
|
+
}), Lc = (e) => {
|
|
4805
|
+
for (let t of ae(e)) if (t instanceof d) return t.reason;
|
|
4806
|
+
}, Rc = (e, t, n) => k.gen(function* () {
|
|
4807
|
+
let r = vc(t), i = r.ctx, a = e.migration.up(i), o = !k.isEffect(a), s = yield* (k.isEffect(a) ? a : k.tryPromise({
|
|
4775
4808
|
try: () => a,
|
|
4776
4809
|
catch: (e) => e
|
|
4777
4810
|
})).pipe(k.as(void 0), k.catchAll((e) => {
|
|
4778
|
-
let t =
|
|
4811
|
+
let t = Lc(e);
|
|
4779
4812
|
return t === void 0 ? k.fail(e) : k.succeed(t);
|
|
4780
4813
|
}));
|
|
4781
4814
|
if (s === void 0) {
|
|
4782
|
-
let t = yield*
|
|
4783
|
-
if (t.length > 0) return yield* k.fail(new
|
|
4815
|
+
let t = yield* hc(n);
|
|
4816
|
+
if (t.length > 0) return yield* k.fail(new S(e.migration.id, t));
|
|
4784
4817
|
}
|
|
4785
4818
|
return {
|
|
4786
4819
|
skipped: s,
|
|
4787
4820
|
promiseForm: o,
|
|
4788
4821
|
absent: r.absent()
|
|
4789
4822
|
};
|
|
4790
|
-
}),
|
|
4823
|
+
}), zc = (e, t, n, r, i, a, o) => k.gen(function* () {
|
|
4791
4824
|
let s = Date.now(), c = (/* @__PURE__ */ new Date()).toISOString(), l = M(e), u = `migrations:file:${n.migration.id}`, d = (e) => ({
|
|
4792
4825
|
durationMs: Date.now() - s,
|
|
4793
4826
|
notes: e.skipped === void 0 ? n.migration.description : `skipped: ${e.skipped}`
|
|
@@ -4795,19 +4828,19 @@ BEGIN
|
|
|
4795
4828
|
if (n.migration.transactional !== !1 && !a) {
|
|
4796
4829
|
if (t.run === void 0) return yield* k.fail(/* @__PURE__ */ Error(`migration ${n.migration.id}: transactional: true needs a SQL-backed store`));
|
|
4797
4830
|
let a = l === "mysql" || l === "mariadb", s = `probe_${n.migration.id}_${Date.now().toString(36)}`;
|
|
4798
|
-
a && (yield*
|
|
4831
|
+
a && (yield* Yo(e, l, o));
|
|
4799
4832
|
let f = () => e`SELECT COUNT(*) AS n FROM ${e(N)} WHERE ${e("runId")} = ${s}`.pipe(k.map((e) => Number(e[0]?.n ?? 0) > 0)), p = yield* k.tryPromise({
|
|
4800
4833
|
try: () => t.transactional(async (t) => {
|
|
4801
4834
|
a && await t.run(e`INSERT INTO ${e(N)} (${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")}, ${e("status")}, ${e("opKind")}, ${e("opTarget")}, ${e("payload")})
|
|
4802
4835
|
VALUES (${`mop_${s}`}, ${s}, ${""}, ${0}, ${"pending"}, ${"probe"}, ${""}, ${"{}"})`);
|
|
4803
|
-
let { ctx: o, expectations: u } =
|
|
4836
|
+
let { ctx: o, expectations: u } = mc({
|
|
4804
4837
|
sql: e,
|
|
4805
4838
|
store: t,
|
|
4806
4839
|
dialect: l,
|
|
4807
4840
|
migrationId: n.migration.id,
|
|
4808
4841
|
appliedAt: c
|
|
4809
|
-
}), p = await t.run(
|
|
4810
|
-
return await t.run(
|
|
4842
|
+
}), p = await t.run(Rc(n, o, u)), m = a && await k.runPromise(f().pipe(k.provideService(A.SqlClient, e))), { durationMs: h, notes: g } = d(p);
|
|
4843
|
+
return await t.run(Ic(e, n, {
|
|
4811
4844
|
env: r,
|
|
4812
4845
|
appliedBy: i,
|
|
4813
4846
|
durationMs: h,
|
|
@@ -4830,14 +4863,14 @@ BEGIN
|
|
|
4830
4863
|
}
|
|
4831
4864
|
});
|
|
4832
4865
|
}
|
|
4833
|
-
let { ctx: f, expectations: p } =
|
|
4866
|
+
let { ctx: f, expectations: p } = mc({
|
|
4834
4867
|
sql: e,
|
|
4835
4868
|
store: t,
|
|
4836
4869
|
dialect: l,
|
|
4837
4870
|
migrationId: n.migration.id,
|
|
4838
4871
|
appliedAt: c
|
|
4839
|
-
}), m = yield*
|
|
4840
|
-
return m.promiseForm && m.skipped === void 0 && h < 2 && (yield* k.logWarning(`migration ${n.migration.id}: up() resolved in ${h}ms — did the body \`await\` an \`@effect/sql\` Effect by accident? \`sql.unsafe(...)\` returns an Effect, not a Promise; \`await\` on it is a silent no-op. Switch the body to \`Effect.gen(function* () { yield* sql.unsafe(...) })\` form.`).pipe(k.annotateLogs({ scope: u }))), m.skipped !== void 0 && (yield* k.logInfo(`migration ${n.migration.id} skipped: ${m.skipped}`).pipe(k.annotateLogs({ scope: u }))), yield*
|
|
4872
|
+
}), m = yield* Rc(n, f, p), { durationMs: h, notes: g } = d(m);
|
|
4873
|
+
return m.promiseForm && m.skipped === void 0 && h < 2 && (yield* k.logWarning(`migration ${n.migration.id}: up() resolved in ${h}ms — did the body \`await\` an \`@effect/sql\` Effect by accident? \`sql.unsafe(...)\` returns an Effect, not a Promise; \`await\` on it is a silent no-op. Switch the body to \`Effect.gen(function* () { yield* sql.unsafe(...) })\` form.`).pipe(k.annotateLogs({ scope: u }))), m.skipped !== void 0 && (yield* k.logInfo(`migration ${n.migration.id} skipped: ${m.skipped}`).pipe(k.annotateLogs({ scope: u }))), yield* Ic(e, n, {
|
|
4841
4874
|
env: r,
|
|
4842
4875
|
appliedBy: i,
|
|
4843
4876
|
durationMs: h,
|
|
@@ -4851,9 +4884,9 @@ BEGIN
|
|
|
4851
4884
|
absent: m.absent
|
|
4852
4885
|
}
|
|
4853
4886
|
};
|
|
4854
|
-
}),
|
|
4887
|
+
}), Bc = (e, t, n, r) => k.gen(function* () {
|
|
4855
4888
|
let i = yield* k.tryPromise({
|
|
4856
|
-
try: () =>
|
|
4889
|
+
try: () => Ec(Ne(t, "migrations")),
|
|
4857
4890
|
catch: (e) => e
|
|
4858
4891
|
});
|
|
4859
4892
|
if (i.length === 0) return {
|
|
@@ -4862,7 +4895,7 @@ BEGIN
|
|
|
4862
4895
|
drifted: []
|
|
4863
4896
|
};
|
|
4864
4897
|
let a = yield* k.tryPromise({
|
|
4865
|
-
try: () =>
|
|
4898
|
+
try: () => Oc(i, r),
|
|
4866
4899
|
catch: (e) => e
|
|
4867
4900
|
});
|
|
4868
4901
|
if (a.length === 0) return {
|
|
@@ -4870,10 +4903,10 @@ BEGIN
|
|
|
4870
4903
|
alreadyApplied: [],
|
|
4871
4904
|
drifted: []
|
|
4872
4905
|
};
|
|
4873
|
-
let o = new Map((yield*
|
|
4906
|
+
let o = new Map((yield* jc(e)).map((e) => [e.id, e.hash])), s = Mc(o, a);
|
|
4874
4907
|
for (let e of s) {
|
|
4875
4908
|
let t = a.find((t) => t.migration.id === e), n = `${t?.file ?? e}:${t?.hash ?? ""}`;
|
|
4876
|
-
|
|
4909
|
+
Nc.has(n) || (Nc.add(n), xc.warn("file migration: the body on disk is not the one that was applied — the file no longer describes this database", {
|
|
4877
4910
|
id: e,
|
|
4878
4911
|
file: t?.file
|
|
4879
4912
|
}));
|
|
@@ -4884,11 +4917,11 @@ BEGIN
|
|
|
4884
4917
|
alreadyApplied: c.filter((e) => o.has(e.migration.id)),
|
|
4885
4918
|
drifted: s
|
|
4886
4919
|
};
|
|
4887
|
-
}),
|
|
4920
|
+
}), Vc = (e, t, n, r) => Bc(e, t, n, r).pipe(k.map((e) => e.pending.map((e) => e.migration.id))), Hc = (e, n, r) => Bc(e, n, r).pipe(k.map((e) => e.pending.map((e) => ({
|
|
4888
4921
|
id: e.migration.id,
|
|
4889
4922
|
phase: e.migration.phase,
|
|
4890
|
-
irreversible:
|
|
4891
|
-
})))),
|
|
4923
|
+
irreversible: t(e.migration.down)
|
|
4924
|
+
})))), Uc = (e, t) => Bc(e, t).pipe(k.map((e) => {
|
|
4892
4925
|
let t = new Set(e.drifted);
|
|
4893
4926
|
return [...e.alreadyApplied.map((e) => ({
|
|
4894
4927
|
id: e.migration.id,
|
|
@@ -4901,16 +4934,16 @@ BEGIN
|
|
|
4901
4934
|
applied: !1,
|
|
4902
4935
|
bodyChanged: !1
|
|
4903
4936
|
}))].sort((e, t) => e.id < t.id ? -1 : 1);
|
|
4904
|
-
})),
|
|
4905
|
-
let { pending: n, alreadyApplied: r } = yield*
|
|
4937
|
+
})), Wc = (e, t) => k.gen(function* () {
|
|
4938
|
+
let { pending: n, alreadyApplied: r } = yield* Bc(e, t.projectRoot, t.phase), i = r.map((e) => e.migration.id);
|
|
4906
4939
|
if (n.length === 0) return {
|
|
4907
4940
|
applied: [],
|
|
4908
4941
|
skipped: i,
|
|
4909
4942
|
skips: []
|
|
4910
4943
|
};
|
|
4911
|
-
yield*
|
|
4944
|
+
yield* Xo(e, M(e), t.charset);
|
|
4912
4945
|
let a = yield* k.acquireUseRelease(_t(e, { schema: t.lockSchema }), () => k.gen(function* () {
|
|
4913
|
-
let r = new Set((yield*
|
|
4946
|
+
let r = new Set((yield* jc(e)).map((e) => e.id)), i = n.filter((e) => !r.has(e.migration.id));
|
|
4914
4947
|
i.length < n.length && (yield* k.logInfo("file-based migrations applied by another process while this one waited for the migration lock").pipe(k.annotateLogs({
|
|
4915
4948
|
scope: "voltro:migrate",
|
|
4916
4949
|
ids: n.filter((e) => r.has(e.migration.id)).map((e) => e.migration.id).join(",")
|
|
@@ -4925,7 +4958,7 @@ BEGIN
|
|
|
4925
4958
|
file: n.file,
|
|
4926
4959
|
phase: n.migration.phase
|
|
4927
4960
|
}));
|
|
4928
|
-
let { durationMs: r, skip: i } = yield*
|
|
4961
|
+
let { durationMs: r, skip: i } = yield* zc(e, t.store, n, t.env, t.appliedBy, t.enclosed === !0, t.charset);
|
|
4929
4962
|
a.push({
|
|
4930
4963
|
id: n.migration.id,
|
|
4931
4964
|
durationMs: r
|
|
@@ -4946,43 +4979,43 @@ BEGIN
|
|
|
4946
4979
|
skipped: i,
|
|
4947
4980
|
skips: a.skips
|
|
4948
4981
|
};
|
|
4949
|
-
}),
|
|
4982
|
+
}), Gc = (e, t) => e`
|
|
4950
4983
|
SELECT ${e("id")}
|
|
4951
4984
|
FROM ${e("_voltro_migration_plans")}
|
|
4952
4985
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
4953
|
-
`,
|
|
4954
|
-
if (!(yield*
|
|
4955
|
-
let
|
|
4956
|
-
try: () =>
|
|
4986
|
+
`, Kc = (e, n) => k.gen(function* () {
|
|
4987
|
+
if (!(yield* Gc(e, n.id))[0]) return yield* k.fail(/* @__PURE__ */ Error(`rollback: ${n.id} not found in _voltro_migration_plans (file source)`));
|
|
4988
|
+
let r = yield* k.tryPromise({
|
|
4989
|
+
try: () => Ec(Ne(n.projectRoot, "migrations")),
|
|
4957
4990
|
catch: (e) => e
|
|
4958
4991
|
}), i = (yield* k.tryPromise({
|
|
4959
|
-
try: () =>
|
|
4992
|
+
try: () => Oc(r),
|
|
4960
4993
|
catch: (e) => e
|
|
4961
|
-
})).find((e) => e.migration.id ===
|
|
4962
|
-
if (!i) return yield* k.fail(/* @__PURE__ */ Error(`rollback: file for migration ${
|
|
4963
|
-
let a =
|
|
4964
|
-
return a === void 0 ? yield* k.acquireUseRelease(_t(e, { schema:
|
|
4965
|
-
if ((yield*
|
|
4966
|
-
let
|
|
4994
|
+
})).find((e) => e.migration.id === n.id);
|
|
4995
|
+
if (!i) return yield* k.fail(/* @__PURE__ */ Error(`rollback: file for migration ${n.id} not found on disk under ${n.projectRoot}/migrations/`));
|
|
4996
|
+
let a = t(i.migration.down);
|
|
4997
|
+
return a === void 0 ? yield* k.acquireUseRelease(_t(e, { schema: n.lockSchema }), () => k.gen(function* () {
|
|
4998
|
+
if ((yield* Gc(e, n.id))[0] === void 0) return yield* k.fail(/* @__PURE__ */ Error(`rollback: ${n.id} was rolled back by another process while this one waited for the migration lock — nothing to do`));
|
|
4999
|
+
let t = Date.now(), { ctx: r } = mc({
|
|
4967
5000
|
sql: e,
|
|
4968
|
-
store:
|
|
5001
|
+
store: n.store,
|
|
4969
5002
|
dialect: M(e),
|
|
4970
|
-
migrationId:
|
|
5003
|
+
migrationId: n.id,
|
|
4971
5004
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4972
5005
|
});
|
|
4973
|
-
|
|
5006
|
+
n.beforeExecute !== void 0 && (yield* n.beforeExecute);
|
|
4974
5007
|
let a = i.migration.down(r);
|
|
4975
5008
|
k.isEffect(a) ? yield* a : yield* k.tryPromise({
|
|
4976
5009
|
try: () => a,
|
|
4977
5010
|
catch: (e) => e
|
|
4978
5011
|
});
|
|
4979
|
-
let o = Date.now() -
|
|
4980
|
-
return yield* e`DELETE FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${
|
|
4981
|
-
id:
|
|
5012
|
+
let o = Date.now() - t;
|
|
5013
|
+
return yield* e`DELETE FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${n.id} AND ${e("source")} = 'file'`, {
|
|
5014
|
+
id: n.id,
|
|
4982
5015
|
durationMs: o
|
|
4983
5016
|
};
|
|
4984
|
-
}), (e) => e.release.pipe(k.orDie)) : yield* k.fail(new
|
|
4985
|
-
}),
|
|
5017
|
+
}), (e) => e.release.pipe(k.orDie)) : yield* k.fail(new h(n.id, a));
|
|
5018
|
+
}), qc = (e) => k.gen(function* () {
|
|
4986
5019
|
let t = yield* A.SqlClient;
|
|
4987
5020
|
if (!Number.isFinite(Date.parse(e.before))) return yield* k.fail(/* @__PURE__ */ Error("squash: cut-off must be a valid date"));
|
|
4988
5021
|
let n = yield* t`
|
|
@@ -5014,10 +5047,10 @@ BEGIN
|
|
|
5014
5047
|
token: i
|
|
5015
5048
|
}
|
|
5016
5049
|
};
|
|
5017
|
-
}),
|
|
5050
|
+
}), Jc = (e) => qc(e).pipe(k.map((e) => e.preview)), Yc = (e) => k.gen(function* () {
|
|
5018
5051
|
let t = yield* A.SqlClient;
|
|
5019
|
-
return yield* bt(t,
|
|
5020
|
-
let { eligible: n, preview: r } = yield*
|
|
5052
|
+
return yield* bt(t, ua(t, k.gen(function* () {
|
|
5053
|
+
let { eligible: n, preview: r } = yield* qc(e);
|
|
5021
5054
|
if (e.expectedPreview !== void 0 && e.expectedPreview !== r.token) return yield* k.fail(/* @__PURE__ */ Error("squash: selected history changed after preview; review a new preview before confirming"));
|
|
5022
5055
|
yield* t`
|
|
5023
5056
|
UPDATE _voltro_migration_plans
|
|
@@ -5054,8 +5087,8 @@ BEGIN
|
|
|
5054
5087
|
snapshotId: i
|
|
5055
5088
|
};
|
|
5056
5089
|
})));
|
|
5057
|
-
}),
|
|
5058
|
-
if (
|
|
5090
|
+
}), Xc = (e) => new Set(e.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), Zc = (e, t) => t !== void 0 && "table" in e && t.createdTables.has(e.table), Qc = { safe: !0 }, $c = (e, t) => {
|
|
5091
|
+
if (Zc(e, t)) return Qc;
|
|
5059
5092
|
switch (e.kind) {
|
|
5060
5093
|
case "add-enum-value": return { safe: !0 };
|
|
5061
5094
|
case "drop-column": return {
|
|
@@ -5087,7 +5120,7 @@ BEGIN
|
|
|
5087
5120
|
reason: `instances on the previous release read/write "${e.table}"."${e.column}" as ${e.from}; the new ${e.to} type can reject their writes or fail to decode their reads`,
|
|
5088
5121
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
5089
5122
|
};
|
|
5090
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
5123
|
+
case "alter-column-nullability": return e.toNullable ? Qc : {
|
|
5091
5124
|
safe: !1,
|
|
5092
5125
|
reason: `instances on the previous release may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
5093
5126
|
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)`
|
|
@@ -5098,12 +5131,12 @@ BEGIN
|
|
|
5098
5131
|
reason: `instances on the previous release still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
|
|
5099
5132
|
remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
|
|
5100
5133
|
};
|
|
5101
|
-
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ?
|
|
5134
|
+
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ? Qc : {
|
|
5102
5135
|
safe: !1,
|
|
5103
5136
|
reason: `instances on the previous release write "${e.table}"."${e.column}" without the new JSON validation, which now rejects them`,
|
|
5104
5137
|
remedy: "ensure all writers supply valid JSON in the required domain before enabling this check"
|
|
5105
5138
|
};
|
|
5106
|
-
case "add-check": return e.table.startsWith("_voltro_") ?
|
|
5139
|
+
case "add-check": return e.table.startsWith("_voltro_") ? Qc : {
|
|
5107
5140
|
safe: !1,
|
|
5108
5141
|
reason: `instances on the previous release may write values to "${e.table}" the new CHECK rejects`,
|
|
5109
5142
|
remedy: "make code satisfy the constraint first and deploy that; add the CHECK in a LATER deploy"
|
|
@@ -5113,7 +5146,7 @@ BEGIN
|
|
|
5113
5146
|
reason: `instances on the previous release may write "${e.table}"."${e.column}" values with no matching parent row, which the new FK rejects`,
|
|
5114
5147
|
remedy: "make code guarantee the referent first and deploy that; add the FK in a LATER deploy"
|
|
5115
5148
|
};
|
|
5116
|
-
case "convert-charset": return e.charset === "utf8mb4" ?
|
|
5149
|
+
case "convert-charset": return e.charset === "utf8mb4" ? Qc : {
|
|
5117
5150
|
safe: !1,
|
|
5118
5151
|
reason: `instances on the previous release may write 4-byte characters into "${e.table}", which utf8mb3 rejects with errno 1366`,
|
|
5119
5152
|
remedy: "keep utf8mb4 while any writer on the previous release remains; narrow in a LATER deploy, after every writer refuses such input itself"
|
|
@@ -5127,12 +5160,12 @@ BEGIN
|
|
|
5127
5160
|
case "drop-unique":
|
|
5128
5161
|
case "drop-unique-composite":
|
|
5129
5162
|
case "drop-foreign-key":
|
|
5130
|
-
case "drop-check": return
|
|
5163
|
+
case "drop-check": return Qc;
|
|
5131
5164
|
}
|
|
5132
|
-
},
|
|
5133
|
-
let t = [], n = { createdTables:
|
|
5165
|
+
}, el = (e) => {
|
|
5166
|
+
let t = [], n = { createdTables: Xc(e) };
|
|
5134
5167
|
for (let r of e) {
|
|
5135
|
-
let e =
|
|
5168
|
+
let e = $c(r.op, n);
|
|
5136
5169
|
e.safe || t.push({
|
|
5137
5170
|
op: r,
|
|
5138
5171
|
reason: e.reason,
|
|
@@ -5140,7 +5173,7 @@ BEGIN
|
|
|
5140
5173
|
});
|
|
5141
5174
|
}
|
|
5142
5175
|
return t;
|
|
5143
|
-
},
|
|
5176
|
+
}, tl = (e) => {
|
|
5144
5177
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
5145
5178
|
refuse: !1,
|
|
5146
5179
|
warnForced: !1,
|
|
@@ -5156,18 +5189,18 @@ BEGIN
|
|
|
5156
5189
|
warnForced: !1,
|
|
5157
5190
|
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.`
|
|
5158
5191
|
};
|
|
5159
|
-
},
|
|
5192
|
+
}, nl = (e) => {
|
|
5160
5193
|
let t = e.table;
|
|
5161
5194
|
if (typeof t == "string") return t;
|
|
5162
5195
|
let n = e.from;
|
|
5163
5196
|
return typeof n == "string" ? n : void 0;
|
|
5164
|
-
},
|
|
5197
|
+
}, rl = (e) => ({
|
|
5165
5198
|
kind: e.op.kind,
|
|
5166
|
-
table:
|
|
5199
|
+
table: nl(e.op),
|
|
5167
5200
|
classification: e.classification,
|
|
5168
5201
|
reason: e.reason,
|
|
5169
5202
|
blockedFix: e.blocked?.fix
|
|
5170
|
-
}),
|
|
5203
|
+
}), il = (e) => e.operations.map(rl), al = async (e) => {
|
|
5171
5204
|
let t = e.log ?? (() => {}), n = {
|
|
5172
5205
|
branchId: e.branchId,
|
|
5173
5206
|
mechanism: e.mechanism,
|
|
@@ -5186,10 +5219,10 @@ BEGIN
|
|
|
5186
5219
|
applied: !1,
|
|
5187
5220
|
converged: !1,
|
|
5188
5221
|
residual: r,
|
|
5189
|
-
infidelity:
|
|
5222
|
+
infidelity: il(o)
|
|
5190
5223
|
};
|
|
5191
5224
|
else {
|
|
5192
|
-
let i = await e.plan(), o =
|
|
5225
|
+
let i = await e.plan(), o = il(i), s = o.filter((e) => e.classification === "lossy"), c = Us(i), l = c.operations.filter((e) => e.blocked !== void 0).map(rl);
|
|
5193
5226
|
if (l.length > 0) a = {
|
|
5194
5227
|
...n,
|
|
5195
5228
|
outcome: "blocked",
|
|
@@ -5214,7 +5247,7 @@ BEGIN
|
|
|
5214
5247
|
};
|
|
5215
5248
|
else {
|
|
5216
5249
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
5217
|
-
let i =
|
|
5250
|
+
let i = il(await e.replan());
|
|
5218
5251
|
a = {
|
|
5219
5252
|
...n,
|
|
5220
5253
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -5252,7 +5285,7 @@ BEGIN
|
|
|
5252
5285
|
...a,
|
|
5253
5286
|
tornDown: o
|
|
5254
5287
|
};
|
|
5255
|
-
},
|
|
5288
|
+
}, ol = (e) => {
|
|
5256
5289
|
switch (e.outcome) {
|
|
5257
5290
|
case "clean": return 0;
|
|
5258
5291
|
case "lossy": return 2;
|
|
@@ -5261,28 +5294,28 @@ BEGIN
|
|
|
5261
5294
|
case "infidelity": return 1;
|
|
5262
5295
|
case "failed": return 1;
|
|
5263
5296
|
}
|
|
5264
|
-
},
|
|
5297
|
+
}, sl = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, cl = (e) => {
|
|
5265
5298
|
let t = [];
|
|
5266
5299
|
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"}`);
|
|
5267
5300
|
else if (e.outcome === "infidelity") {
|
|
5268
5301
|
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:");
|
|
5269
|
-
for (let n of e.infidelity) t.push(
|
|
5302
|
+
for (let n of e.infidelity) t.push(sl(n));
|
|
5270
5303
|
} else {
|
|
5271
5304
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
5272
|
-
for (let n of e.operations) t.push(
|
|
5273
|
-
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(
|
|
5305
|
+
for (let n of e.operations) t.push(sl(n));
|
|
5306
|
+
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(sl(n));
|
|
5274
5307
|
}
|
|
5275
5308
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
5276
|
-
},
|
|
5277
|
-
let e = yield* A.SqlClient, n =
|
|
5309
|
+
}, ll = "tenant_", ul = (e) => e.map((e) => Object.fromEntries(Object.entries(e).map(([e, t]) => [e.toLowerCase(), t]))), dl = async (e, t) => e(k.gen(function* () {
|
|
5310
|
+
let e = yield* A.SqlClient, n = ul(yield* e`
|
|
5278
5311
|
SELECT schema_name FROM information_schema.schemata
|
|
5279
|
-
WHERE schema_name LIKE ${`${
|
|
5312
|
+
WHERE schema_name LIKE ${`${ll}%`} ORDER BY schema_name`), r = [];
|
|
5280
5313
|
for (let { schema_name: i } of n) {
|
|
5281
|
-
let n =
|
|
5314
|
+
let n = ul(yield* e`
|
|
5282
5315
|
SELECT table_name, column_name, data_type, character_set_name
|
|
5283
5316
|
FROM information_schema.columns
|
|
5284
5317
|
WHERE table_schema = ${i}
|
|
5285
|
-
ORDER BY table_name, ordinal_position`), a =
|
|
5318
|
+
ORDER BY table_name, ordinal_position`), a = ul(yield* e`
|
|
5286
5319
|
SELECT cc.table_name AS table_name, cc.check_clause AS check_clause
|
|
5287
5320
|
FROM information_schema.check_constraints cc
|
|
5288
5321
|
WHERE cc.constraint_schema = ${i}`.pipe(k.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set();
|
|
@@ -5317,33 +5350,33 @@ BEGIN
|
|
|
5317
5350
|
});
|
|
5318
5351
|
}
|
|
5319
5352
|
return r;
|
|
5320
|
-
})),
|
|
5353
|
+
})), fl = "owner", pl = (e) => k.map(e`SELECT ${e("appName")}, ${e("claimedAt")} FROM ${e(Si)} WHERE ${e("id")} = ${fl}`, (e) => e[0]), ml = (e, t) => e.appName === t ? { kind: "owned" } : {
|
|
5321
5354
|
kind: "foreign",
|
|
5322
5355
|
owner: e.appName,
|
|
5323
5356
|
claimedAt: e.claimedAt === void 0 || e.claimedAt === null ? void 0 : String(e.claimedAt)
|
|
5324
|
-
},
|
|
5357
|
+
}, hl = (e, t) => Zo(e, M(e), t).pipe(k.catchAll(() => Zo(e, M(e), t))), gl = (e, t, n) => k.gen(function* () {
|
|
5325
5358
|
if (!n.mayWrite) {
|
|
5326
|
-
let n = yield*
|
|
5327
|
-
return n === void 0 ? { kind: "unclaimed" } :
|
|
5359
|
+
let n = yield* pl(e).pipe(k.catchAll(() => k.succeed(void 0)));
|
|
5360
|
+
return n === void 0 ? { kind: "unclaimed" } : ml(n, t.appName);
|
|
5328
5361
|
}
|
|
5329
|
-
yield*
|
|
5330
|
-
let r = yield*
|
|
5331
|
-
if (r !== void 0) return
|
|
5362
|
+
yield* hl(e, n.charset);
|
|
5363
|
+
let r = yield* pl(e);
|
|
5364
|
+
if (r !== void 0) return ml(r, t.appName);
|
|
5332
5365
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
5333
5366
|
if (yield* e`INSERT INTO ${e("_voltro_schema_owner")} ${e.insert({
|
|
5334
|
-
id:
|
|
5367
|
+
id: fl,
|
|
5335
5368
|
appName: t.appName,
|
|
5336
5369
|
projectName: t.projectName ?? null,
|
|
5337
5370
|
frameworkVersion: t.frameworkVersion ?? null,
|
|
5338
5371
|
claimedAt: i
|
|
5339
5372
|
})}`.pipe(k.as(!0), k.catchAll(() => k.succeed(!1)))) return { kind: "claimed" };
|
|
5340
|
-
let a = yield*
|
|
5341
|
-
return a === void 0 ? { kind: "unclaimed" } :
|
|
5342
|
-
}),
|
|
5343
|
-
yield*
|
|
5344
|
-
let r = yield*
|
|
5373
|
+
let a = yield* pl(e);
|
|
5374
|
+
return a === void 0 ? { kind: "unclaimed" } : ml(a, t.appName);
|
|
5375
|
+
}), _l = (e, t, n) => k.gen(function* () {
|
|
5376
|
+
yield* hl(e, n);
|
|
5377
|
+
let r = yield* pl(e), i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
5345
5378
|
return r === void 0 ? yield* e`INSERT INTO ${e(Si)} ${e.insert({
|
|
5346
|
-
id:
|
|
5379
|
+
id: fl,
|
|
5347
5380
|
appName: t.appName,
|
|
5348
5381
|
projectName: t.projectName ?? null,
|
|
5349
5382
|
frameworkVersion: t.frameworkVersion ?? null,
|
|
@@ -5353,27 +5386,36 @@ BEGIN
|
|
|
5353
5386
|
projectName: t.projectName ?? null,
|
|
5354
5387
|
frameworkVersion: t.frameworkVersion ?? null,
|
|
5355
5388
|
claimedAt: i
|
|
5356
|
-
})} WHERE ${e("id")} = ${
|
|
5357
|
-
}),
|
|
5389
|
+
})} WHERE ${e("id")} = ${fl}`, { previous: r?.appName };
|
|
5390
|
+
}), vl = (e, t, n) => `this database belongs to the app '${t}'${n === void 0 ? "" : ` (claimed ${n})`}, and '${e}' is a different app. Two apps on one schema each plan to drop the other's tables, and their data is shared with no contract between them. Give this app its own database (DB_URL) or its own schema (DB_SCHEMA); if it needs the other app's data, call it — \`apis:\` on this app, \`service:\` procedures on the other. If this app was RENAMED from '${t}', run \`voltro db claim\` once to hand the schema over.`, yl = (e, ...t) => ({
|
|
5358
5391
|
_tag: "RawSqlFragment",
|
|
5359
5392
|
strings: [...e],
|
|
5360
5393
|
values: [...t]
|
|
5361
|
-
}),
|
|
5362
|
-
let t =
|
|
5394
|
+
}), bl = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment", xl = (e) => k.gen(function* () {
|
|
5395
|
+
let t = e.onDialectOrElse({
|
|
5396
|
+
mysql: () => e`CAST(${e("operations")} AS CHAR)`,
|
|
5397
|
+
mssql: () => e`CAST(${e("operations")} AS NVARCHAR(MAX))`,
|
|
5398
|
+
orElse: () => e`CAST(${e("operations")} AS TEXT)`
|
|
5399
|
+
}), n = e`(${t} LIKE ${"%softDropSnapshot%"} OR ${t} LIKE ${"%\\%"} ESCAPE '!')`, r = e.onDialectOrElse({
|
|
5400
|
+
pg: () => e`CASE WHEN pg_typeof(${e("operations")})::text IN ('json', 'jsonb')
|
|
5401
|
+
THEN jsonb_path_exists(${e("operations")}::jsonb, '$[*].softDropSnapshot')
|
|
5402
|
+
ELSE ${n} END`,
|
|
5403
|
+
orElse: () => n
|
|
5404
|
+
}), i = [], a;
|
|
5363
5405
|
for (;;) {
|
|
5364
|
-
let
|
|
5406
|
+
let t = yield* e`
|
|
5365
5407
|
SELECT ${e("id")}, ${e("operations")} FROM ${e("_voltro_migration_plans")}
|
|
5366
|
-
${
|
|
5408
|
+
WHERE ${r} ${a === void 0 ? e`` : e`AND ${e("id")} > ${a}`}
|
|
5367
5409
|
ORDER BY ${e("id")}
|
|
5368
5410
|
${e.onDialectOrElse({
|
|
5369
5411
|
mssql: () => e`OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY`,
|
|
5370
5412
|
orElse: () => e`LIMIT 100`
|
|
5371
5413
|
})}
|
|
5372
5414
|
`;
|
|
5373
|
-
if (
|
|
5374
|
-
|
|
5415
|
+
if (i.push(...t), t.length < 100) return i;
|
|
5416
|
+
a = t[t.length - 1].id;
|
|
5375
5417
|
}
|
|
5376
|
-
}),
|
|
5418
|
+
}), Sl = (e, t) => {
|
|
5377
5419
|
let n = [], r = /* @__PURE__ */ new Map(), i = (e, t) => JSON.stringify(e.kind === "table" ? ["table", e.snapshotName] : [
|
|
5378
5420
|
"column",
|
|
5379
5421
|
t.find((t) => t.kind === "table" && t.originalName === e.table)?.snapshotName ?? e.table,
|
|
@@ -5388,7 +5430,7 @@ BEGIN
|
|
|
5388
5430
|
}
|
|
5389
5431
|
if (!Array.isArray(e)) continue;
|
|
5390
5432
|
let o = [];
|
|
5391
|
-
for (let t of e)
|
|
5433
|
+
for (let t of e) wl(t) && wl(t.op) && typeof t.softDropSnapshot == "string" && typeof t.op.table == "string" && (t.op.kind === "drop-table" && o.push({
|
|
5392
5434
|
kind: "table",
|
|
5393
5435
|
table: t.op.table,
|
|
5394
5436
|
originalName: t.op.table,
|
|
@@ -5404,7 +5446,7 @@ BEGIN
|
|
|
5404
5446
|
n.add(a.id), r.set(t, n);
|
|
5405
5447
|
}
|
|
5406
5448
|
try {
|
|
5407
|
-
let r =
|
|
5449
|
+
let r = El(e, t);
|
|
5408
5450
|
r.length > 0 && n.push({
|
|
5409
5451
|
planId: a.id,
|
|
5410
5452
|
objects: r
|
|
@@ -5412,18 +5454,18 @@ BEGIN
|
|
|
5412
5454
|
} catch {}
|
|
5413
5455
|
}
|
|
5414
5456
|
return n.filter((e) => e.objects.every((t) => r.get(i(t, e.objects))?.size === 1));
|
|
5415
|
-
},
|
|
5457
|
+
}, Cl = (e, t) => xl(e).pipe(k.map((e) => Sl(e, t))), wl = (e) => typeof e == "object" && !!e && !Array.isArray(e), Tl = {
|
|
5416
5458
|
postgres: !0,
|
|
5417
5459
|
mysql: !1,
|
|
5418
5460
|
mariadb: !1,
|
|
5419
5461
|
mssql: !0,
|
|
5420
5462
|
sqlite: !0
|
|
5421
|
-
},
|
|
5463
|
+
}, El = (e, t) => {
|
|
5422
5464
|
let n = typeof e == "string" ? JSON.parse(e) : e;
|
|
5423
5465
|
if (!Array.isArray(n)) throw Error("Snapshot restoration requires an operation array");
|
|
5424
5466
|
let r = [], i = /* @__PURE__ */ new Set();
|
|
5425
5467
|
for (let e of n) {
|
|
5426
|
-
if (!
|
|
5468
|
+
if (!wl(e) || !wl(e.op) || typeof e.op.kind != "string") throw Error("Invalid migration operation history");
|
|
5427
5469
|
let t = e.op;
|
|
5428
5470
|
if (t.kind !== "drop-column" && t.kind !== "drop-table") {
|
|
5429
5471
|
if (e.softDropSnapshot !== void 0) throw Error("Snapshot metadata belongs to a non-drop operation");
|
|
@@ -5431,7 +5473,7 @@ BEGIN
|
|
|
5431
5473
|
}
|
|
5432
5474
|
if (typeof t.table != "string" || !t.table || t.kind === "drop-column" && (typeof t.column != "string" || !t.column)) throw Error("Invalid drop operation identity");
|
|
5433
5475
|
if (typeof e.softDropSnapshot != "string") throw Error("Snapshot ownership is unavailable for this plan. Its history has no exact soft-drop identity; automatic restoration is refused.");
|
|
5434
|
-
let n =
|
|
5476
|
+
let n = Qi({
|
|
5435
5477
|
op: t.kind === "drop-table" ? {
|
|
5436
5478
|
kind: "drop-table",
|
|
5437
5479
|
table: t.table
|
|
@@ -5441,7 +5483,7 @@ BEGIN
|
|
|
5441
5483
|
column: String(t.column)
|
|
5442
5484
|
},
|
|
5443
5485
|
classification: "lossy",
|
|
5444
|
-
atomicByDialect:
|
|
5486
|
+
atomicByDialect: Tl,
|
|
5445
5487
|
softDropSnapshot: e.softDropSnapshot
|
|
5446
5488
|
}), a = {
|
|
5447
5489
|
kind: t.kind === "drop-table" ? "table" : "column",
|
|
@@ -5467,17 +5509,17 @@ BEGIN
|
|
|
5467
5509
|
if (!i.columns.some((t) => t.name === e.snapshotName)) throw Error(`Recorded snapshot is missing: ${e.table}.${e.snapshotName}`);
|
|
5468
5510
|
}
|
|
5469
5511
|
return r;
|
|
5470
|
-
},
|
|
5512
|
+
}, Dl = (e, t, n = {}) => k.acquireUseRelease(_t(e), () => {
|
|
5471
5513
|
let r = k.gen(function* () {
|
|
5472
5514
|
let e = yield* A.SqlClient, r = yield* e`SELECT ${e("operations")} FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t}`;
|
|
5473
5515
|
if (r.length !== 1) return yield* k.fail(/* @__PURE__ */ Error(`Snapshot plan not found: ${t}`));
|
|
5474
5516
|
let i = yield* B(e), a = yield* k.try({
|
|
5475
|
-
try: () =>
|
|
5517
|
+
try: () => El(r[0].operations, i),
|
|
5476
5518
|
catch: (e) => e instanceof Error ? e : Error(String(e))
|
|
5477
5519
|
});
|
|
5478
|
-
if (a.length > 0 && !(yield*
|
|
5520
|
+
if (a.length > 0 && !(yield* Cl(e, i)).some((e) => e.planId === t)) return yield* k.fail(/* @__PURE__ */ Error("Snapshot ownership is ambiguous across migration history; automatic restoration is refused."));
|
|
5479
5521
|
a.length > 0 && n.beforeExecute && (yield* n.beforeExecute(e));
|
|
5480
|
-
for (let t of a) yield*
|
|
5522
|
+
for (let t of a) yield* vs(e, {
|
|
5481
5523
|
op: t.kind === "table" ? {
|
|
5482
5524
|
kind: "rename-table",
|
|
5483
5525
|
from: t.snapshotName,
|
|
@@ -5489,7 +5531,7 @@ BEGIN
|
|
|
5489
5531
|
to: t.originalName
|
|
5490
5532
|
},
|
|
5491
5533
|
classification: "safe",
|
|
5492
|
-
atomicByDialect:
|
|
5534
|
+
atomicByDialect: Tl
|
|
5493
5535
|
}, []);
|
|
5494
5536
|
return {
|
|
5495
5537
|
restoredColumns: a.filter((e) => e.kind === "column").length,
|
|
@@ -5497,7 +5539,7 @@ BEGIN
|
|
|
5497
5539
|
objects: a
|
|
5498
5540
|
};
|
|
5499
5541
|
});
|
|
5500
|
-
return St(M(e)) === "plan-transactional" ?
|
|
5542
|
+
return St(M(e)) === "plan-transactional" ? ua(e, r) : r;
|
|
5501
5543
|
}, (e) => e.release.pipe(k.orDie));
|
|
5502
5544
|
//#endregion
|
|
5503
|
-
export { Rt as DEFAULT_CDC_CHANNEL, R as DEPLOY_LEDGER_TABLE, le as FILE_MIGRATION_PATTERN,
|
|
5545
|
+
export { Rt as DEFAULT_CDC_CHANNEL, R as DEPLOY_LEDGER_TABLE, le as FILE_MIGRATION_PATTERN, Cc as FRAMEWORK_MIGRATION_EDITS, Fc as FileMigrationLedgerError, h as IrreversibleMigrationError, xt as MIGRATION_ATOMICITY, vt as MIGRATION_NEEDS_TWO_CONNECTIONS, v as MIGRATION_PHASES, yr as MYSQL_CHARSETS, S as MigrationExpectationFailed, s as MigrationNeedsSqlClient, d as MigrationSkipped, zt as REACTIVE_TRIGGER_PREFIX, m as RewriteUnstableError, Si as SCHEMA_OWNER_TABLE, Or as STORE_CHARSET_REMEDY, w as TransactionBrokenByBodyError, Ze as VOLTRO_MIGRATION_LOCK_KEY, _i as _voltroDeploysTable, wc as acceptedBodyHashes, _t as acquireMigrationLock, Ho as addColumnDdl, U as appliedAtValue, Ac as appliedFileMigrationIds, jc as appliedFileMigrations, cs as appliedLedgerOperations, Vn as applyNamespacedSchema, hs as applyPlan, An as applySchema, js as applyUndeclaredCharsetWork, tl as assessRollingDeployGate, ol as branchRehearsalExitCode, Cr as charsetColumnsOf, gl as checkSchemaOwner, Pi as chunkTables, $c as classifyRollingDeploySafety, ls as clearResumeLedger, yi as closeDeploy, ka as columnLevelChecksMysql, xr as columnTakesCharset, Ms as convergeUndeclaredCharset, Xc as createdTablesOf, Nr as declaredSnapshot, Yt as defaultArrayClause, Jt as defaultClause, Xt as defaultJsonClause, qs as describeOutcome, gc as describeProbe, Dr as describeStoreCharsetFinding, Es as describeUndeclaredCharsetWork, bs as describesSchema, Vs as destructiveScope, Fr as detectReactiveTriggerDrift, M as dialectOf, po as emitAddIndexMysql, Wa as emitConvertCharsetMysql, io as emitCreateTableMssql, Ga as emitCreateTableMysql, Ra as emitCreateTablePg, Za as emitCreateTableSqlite, ya as emitDropColumnDdl, ba as emitDropColumnDdlMysql, kn as emitFrameworkBootstrapSql, Dn as emitNamespaceProvisionDdl, On as emitNamespacedSchemaSql, En as emitSchemaSql, $i as engineFromVersion, $o as ensureDeployLedgerTable, Mn as ensureFullTextIndexes, Yo as ensureLedgerTable, Xo as ensurePlanLedgerTable, Qo as ensurePluginMigrationsLedgerTable, es as ensureReplaceMarkerTable, Zo as ensureSchemaOwnerTable, wn as enumRenameBlocks, Cn as enumTypeBlocks, _n as extensionBlocks, bi as failDeploy, hc as failedExpectations, Ps as fetchLastFingerprint, Uc as fileMigrationStatus, I as fingerprintSchema, rt as fnv1a64, vl as foreignOwnerMessage, cl as formatBranchRehearsal, Ir as formatReactiveTriggerDrift, un as fullTextIndexSql, rs as hasInterruptedMigration, Bs as ignoreTablesFromEnv, B as introspectSchema, Se as irreversible, t as irreversibleReason, ia as isAlreadySatisfied, T as isFileMigration, ys as isFileMigrationRow, br as isMysqlCharset, bl as isRawSqlFragment, Nn as isReRunSafeDdl, Ss as isUndeclaredCharsetTable, Ts as isUndeclaredCharsetWorkEmpty, V as limitClause, mc as makeFileMigrationContext, Ti as mapPgType, Xs as materialiseSnapshot, l as migration, St as migrationAtomicityFor, Sc as migrationBodyHash, it as migrationLockKeyForSchema, at as migrationLockNameForSchema, so as mysqlIndexPrefixFor, Wt as notifyFunctionName, Zt as numericIdSql, vi as openDeploy, wi as parseEnumCheck, Vc as pendingFileMigrationIds, Hc as pendingFileMigrationSummary, bc as permanentSkips, gi as planMigrations, ue as plannableLiveTables, yc as plannedCreations, Jc as previewMigrationSquash, Hn as provisionTenantNamespace, Bt as reactiveTriggerName, gn as reactiveTriggerRepairSql, Cl as readMigrationSnapshotCandidates, Os as readUndeclaredCharsetColumns, Fs as recordUpToDate, Je as registerSqlPoolCapacity, al as rehearseMigrationOnBranch, rl as rehearsedOperation, Va as renderColumnMysql, Fa as renderColumnPg, $e as resolveMigrationLockSchema, H as resolveMysqlEngine, Dl as restoreMigrationSnapshots, Kc as rollbackFileBasedMigration, el as rollingDeployUnsafeOps, Wc as runFileBasedMigrations, Un as runFrameworkBootstrap, Bn as runMigrate, vs as runMigrationOp, Ks as runPlannedMigrations, Z as runSchemaOp, vr as shortFingerprint, kr as snapshotColumn, yl as sql, Ye as sqlPoolCapacity, F as sqlType, Yc as squashMigrationPlans, Sr as stampDeclaredCharset, Er as storeCharsetFindings, dl as tenantNamespaceCharsetFindings, _l as transferSchemaOwner, Us as unblockLossy, As as undeclaredCharsetStatements, ws as undeclaredCharsetWork, xi as unfinishedDeploys, Ec as walkMigrationFiles, bt as withMigrationLock, vc as withSchemaProbeRecorder };
|