@voltro/database 0.23.0 → 0.25.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 +537 -0
- package/dist/{frameworkLiveTables-BvPIm2cD.js → frameworkLiveTables-BQwB8K6R.js} +9 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.js +457 -426
- package/dist/sql.d.ts +143 -6
- package/dist/sql.js +600 -497
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as e, U as t, a as n, c as r, d as i, ft as a, i as o, n as s, o as c, ot as l, q as u, r as d, s as f } from "./frameworkLiveTables-
|
|
1
|
+
import { H as e, U as t, a as n, c as r, d as i, ft as a, i as o, n as s, o as c, ot as l, q as u, r as d, s as f } from "./frameworkLiveTables-BQwB8K6R.js";
|
|
2
2
|
import { Effect as p } from "effect";
|
|
3
3
|
import { createLogger as m } from "@voltro/logger";
|
|
4
4
|
import { SqlClient as h } from "@effect/sql";
|
|
@@ -39,7 +39,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
39
39
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
40
40
|
}
|
|
41
41
|
return s.push(""), s.join("\n");
|
|
42
|
-
}, x = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, S = (e) => e.replace(/"/g, "`"), ee = (e) => typeof e == "string" ? e : e.name ?? String(e),
|
|
42
|
+
}, x = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, S = (e) => e.replace(/"/g, "`"), ee = (e) => typeof e == "string" ? e : e.name ?? String(e), C = (e, t) => `_ua_${t}_${e}`.slice(0, 64), te = (e, t) => {
|
|
43
43
|
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(x)) return e;
|
|
44
44
|
let n = { ...e.fields }, r = [], i = [];
|
|
45
45
|
for (let t of e.appliedIndexes) {
|
|
@@ -51,7 +51,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
51
51
|
for (let r of t.fields) {
|
|
52
52
|
let i = ee(r);
|
|
53
53
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
54
|
-
let s =
|
|
54
|
+
let s = C(t.name, i);
|
|
55
55
|
o.push(s), n[s] = {
|
|
56
56
|
type: "text",
|
|
57
57
|
nullable: !0,
|
|
@@ -74,54 +74,54 @@ var b = (e, t, n, r = 400) => {
|
|
|
74
74
|
appliedIndexes: r,
|
|
75
75
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
76
76
|
};
|
|
77
|
-
},
|
|
77
|
+
}, w = (e, t) => `${e}::${t}`, ne = (e, t) => {
|
|
78
78
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
79
79
|
n.add(e);
|
|
80
80
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
81
|
-
for (let t of o) n.has(t.target) ? i.add(
|
|
81
|
+
for (let t of o) n.has(t.target) ? i.add(w(e, t.column)) : r.has(t.target) || a(t.target);
|
|
82
82
|
n.delete(e), r.add(e);
|
|
83
83
|
};
|
|
84
84
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
85
85
|
return i;
|
|
86
|
-
},
|
|
86
|
+
}, re = 6322741009312437n, ie = 250, ae = () => {
|
|
87
87
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
88
88
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
89
|
-
},
|
|
90
|
-
let t =
|
|
89
|
+
}, oe = (e) => p.gen(function* () {
|
|
90
|
+
let t = ae(), n = Date.now();
|
|
91
91
|
for (;;) {
|
|
92
92
|
if ((yield* e`
|
|
93
93
|
SELECT pg_try_advisory_lock(${"6322741009312437"}::bigint) AS got`)[0]?.got) return;
|
|
94
|
-
Date.now() - n >= t && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the postgres migration advisory lock within ${Math.round(t / 1e3)}s. Another migration is in progress, or a prior boot crashed while holding it. (A crashed process's session-level advisory lock is released once its DB connection closes; if this persists, find + terminate the holder via pg_stat_activity, or raise VOLTRO_MIGRATION_LOCK_TIMEOUT_MS.)`))), yield* p.sleep(`${
|
|
94
|
+
Date.now() - n >= t && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the postgres migration advisory lock within ${Math.round(t / 1e3)}s. Another migration is in progress, or a prior boot crashed while holding it. (A crashed process's session-level advisory lock is released once its DB connection closes; if this persists, find + terminate the holder via pg_stat_activity, or raise VOLTRO_MIGRATION_LOCK_TIMEOUT_MS.)`))), yield* p.sleep(`${ie} millis`);
|
|
95
95
|
}
|
|
96
|
-
}),
|
|
97
|
-
yield* e`SELECT pg_advisory_unlock(${
|
|
98
|
-
}),
|
|
96
|
+
}), se = (e) => p.gen(function* () {
|
|
97
|
+
yield* e`SELECT pg_advisory_unlock(${re.toString()}::bigint)`;
|
|
98
|
+
}), ce = `voltro_migration_${re.toString(36)}`, le = 30, ue = (e) => p.gen(function* () {
|
|
99
99
|
(yield* e`
|
|
100
|
-
SELECT GET_LOCK(${
|
|
101
|
-
}),
|
|
102
|
-
yield* e`SELECT RELEASE_LOCK(${
|
|
103
|
-
}),
|
|
100
|
+
SELECT GET_LOCK(${ce}, ${le}) AS got`)[0]?.got !== 1 && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${ce}' within ${le}s (another migration is in progress, or a prior one left it held).`)));
|
|
101
|
+
}), de = (e) => p.gen(function* () {
|
|
102
|
+
yield* e`SELECT RELEASE_LOCK(${ce})`;
|
|
103
|
+
}), fe = `voltro_migration_${re.toString(36)}`, pe = 3e4, me = (e) => p.gen(function* () {
|
|
104
104
|
let t = yield* e`
|
|
105
105
|
DECLARE @res int;
|
|
106
|
-
EXEC @res = sp_getapplock @Resource = ${
|
|
107
|
-
@LockOwner = 'Session', @LockTimeout = ${
|
|
106
|
+
EXEC @res = sp_getapplock @Resource = ${fe}, @LockMode = 'Exclusive',
|
|
107
|
+
@LockOwner = 'Session', @LockTimeout = ${pe};
|
|
108
108
|
SELECT @res AS res`;
|
|
109
|
-
(t[0]?.res ?? -999) < 0 && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${
|
|
110
|
-
}),
|
|
111
|
-
yield* e`EXEC sp_releaseapplock @Resource = ${
|
|
112
|
-
}),
|
|
109
|
+
(t[0]?.res ?? -999) < 0 && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${fe}' (sp_getapplock returned ${t[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
110
|
+
}), he = (e) => p.gen(function* () {
|
|
111
|
+
yield* e`EXEC sp_releaseapplock @Resource = ${fe}, @LockOwner = 'Session'`;
|
|
112
|
+
}), ge = p.void, T = (e) => e.onDialectOrElse({
|
|
113
|
+
mysql: () => ue(e),
|
|
114
|
+
mssql: () => me(e),
|
|
115
|
+
sqlite: () => ge,
|
|
116
|
+
orElse: () => oe(e)
|
|
117
|
+
}), E = (e) => e.onDialectOrElse({
|
|
113
118
|
mysql: () => de(e),
|
|
114
119
|
mssql: () => he(e),
|
|
115
|
-
sqlite: () =>
|
|
120
|
+
sqlite: () => ge,
|
|
116
121
|
orElse: () => se(e)
|
|
117
|
-
}),
|
|
118
|
-
mysql: () => fe(e),
|
|
119
|
-
mssql: () => ge(e),
|
|
120
|
-
sqlite: () => _e,
|
|
121
|
-
orElse: () => ce(e)
|
|
122
|
-
}), ve = (e, t) => p.acquireUseRelease(w(e), () => t, () => T(e).pipe(p.orDie)), ye = m({ scope: "voltro:migrate" }), E = (e) => {
|
|
122
|
+
}), D = (e, t) => p.acquireUseRelease(T(e), () => t, () => E(e).pipe(p.orDie)), O = "framework_changes", k = "framework_changes_", _e = (e, t) => t === "framework_changes" ? `${k}${e}` : `${k}${t}_${e}`, ve = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, ye = m({ scope: "voltro:migrate" }), A = (e) => {
|
|
123
123
|
ye.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
124
|
-
},
|
|
124
|
+
}, j = (t, n) => {
|
|
125
125
|
let r = t.type;
|
|
126
126
|
if (t.spatial) {
|
|
127
127
|
if (n === "postgres") return `${t.spatial.kind}(${t.spatial.geomKind},${t.spatial.srid})`;
|
|
@@ -132,7 +132,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
132
132
|
return t.rawDdl;
|
|
133
133
|
}
|
|
134
134
|
if (r === "array" && t.arrayElement) {
|
|
135
|
-
if (n === "postgres") return `${
|
|
135
|
+
if (n === "postgres") return `${j({
|
|
136
136
|
...t,
|
|
137
137
|
type: t.arrayElement,
|
|
138
138
|
arrayElement: void 0
|
|
@@ -235,19 +235,19 @@ var b = (e, t, n, r = 400) => {
|
|
|
235
235
|
}, be = (t, n) => {
|
|
236
236
|
if (!t.hasDefault || t.defaultFactory !== void 0) return null;
|
|
237
237
|
let r = t.defaultValue;
|
|
238
|
-
return r === "now" ? e(n) ? "DEFAULT CURRENT_TIMESTAMP" : n === "mssql" ? "DEFAULT SYSUTCDATETIME()" : n === "mysql" || n === "mariadb" ? "DEFAULT CURRENT_TIMESTAMP(6)" : "DEFAULT now()" : typeof r == "boolean" ? n === "postgres" ? `DEFAULT ${r}` : `DEFAULT ${+!!r}` : typeof r == "number" ? `DEFAULT ${r}` : typeof r == "string" ? `DEFAULT '${r.replace(/'/g, "''")}'` : Array.isArray(r) ? xe(r, t, n) : typeof r == "object" && r ?
|
|
238
|
+
return r === "now" ? e(n) ? "DEFAULT CURRENT_TIMESTAMP" : n === "mssql" ? "DEFAULT SYSUTCDATETIME()" : n === "mysql" || n === "mariadb" ? "DEFAULT CURRENT_TIMESTAMP(6)" : "DEFAULT now()" : typeof r == "boolean" ? n === "postgres" ? `DEFAULT ${r}` : `DEFAULT ${+!!r}` : typeof r == "number" ? `DEFAULT ${r}` : typeof r == "string" ? `DEFAULT '${r.replace(/'/g, "''")}'` : Array.isArray(r) ? xe(r, t, n) : typeof r == "object" && r ? M(r, n) : null;
|
|
239
239
|
}, xe = (e, t, n) => {
|
|
240
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
241
|
-
let r =
|
|
240
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return M(e, n);
|
|
241
|
+
let r = j({
|
|
242
242
|
...t,
|
|
243
243
|
type: t.arrayElement,
|
|
244
244
|
arrayElement: void 0
|
|
245
245
|
}, n);
|
|
246
246
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
247
|
-
},
|
|
247
|
+
}, M = (e, t) => {
|
|
248
248
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
249
249
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CAST('${n}' AS JSON))` : `DEFAULT '${n}'`;
|
|
250
|
-
},
|
|
250
|
+
}, N = (e, t) => {
|
|
251
251
|
switch (t) {
|
|
252
252
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
253
253
|
case "mysql":
|
|
@@ -256,7 +256,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
256
256
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
257
257
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
258
258
|
}
|
|
259
|
-
},
|
|
259
|
+
}, Se = (e, t) => {
|
|
260
260
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
261
261
|
switch (e) {
|
|
262
262
|
case "cascade": return "CASCADE";
|
|
@@ -264,26 +264,26 @@ var b = (e, t, n, r = 400) => {
|
|
|
264
264
|
case "setNull": return "SET NULL";
|
|
265
265
|
case "noAction": return "NO ACTION";
|
|
266
266
|
}
|
|
267
|
-
},
|
|
267
|
+
}, Ce = (e, n, r) => r === null ? t(e, n) : `${t(r, n)}.${t(e, n)}`, we = 191, Te = (e, n, r) => {
|
|
268
268
|
let i = t(e, r);
|
|
269
269
|
if (r !== "mysql" && r !== "mariadb") return i;
|
|
270
270
|
let a = n[e];
|
|
271
271
|
if (!a) return i;
|
|
272
|
-
let o =
|
|
273
|
-
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${
|
|
274
|
-
},
|
|
272
|
+
let o = j(a, r).toUpperCase();
|
|
273
|
+
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${we})` : i;
|
|
274
|
+
}, Ee = (e, t) => {
|
|
275
275
|
if (!e.generatedAs) return null;
|
|
276
276
|
let { expr: n, stored: r } = e.generatedAs;
|
|
277
|
-
if (t === "postgres") return r ||
|
|
277
|
+
if (t === "postgres") return r || A("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
278
278
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
279
279
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
280
280
|
if (t === "turso") throw Error("@voltro/sql-turso: generated columns (.generatedAs(...)) are not supported — Turso's MVCC mode (journal_mode=experimental_mvcc) rejects them. Drop the generated column, or use the 'sqlite' / 'postgres' dialect for this table.");
|
|
281
281
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
282
|
-
},
|
|
283
|
-
if (r.type === "id" && r.idScheme?.kind === "numeric") return
|
|
284
|
-
let c = i === "mssql" && r.type === "text" && !r.generatedAs && r.maxLength === void 0 && a?.has(n) ? "NVARCHAR(450)" :
|
|
282
|
+
}, De = (n, r, i, a, o = !1, s = !1) => {
|
|
283
|
+
if (r.type === "id" && r.idScheme?.kind === "numeric") return N(n, i);
|
|
284
|
+
let c = i === "mssql" && r.type === "text" && !r.generatedAs && r.maxLength === void 0 && a?.has(n) ? "NVARCHAR(450)" : j(r, i), l = [t(n, i), c];
|
|
285
285
|
r.type === "id" && !s && l.push("PRIMARY KEY");
|
|
286
|
-
let u =
|
|
286
|
+
let u = Ee(r, i);
|
|
287
287
|
if (u) l.push(u);
|
|
288
288
|
else {
|
|
289
289
|
r.nullable || l.push("NOT NULL"), r.unique && r.type !== "id" && l.push("UNIQUE");
|
|
@@ -293,9 +293,9 @@ var b = (e, t, n, r = 400) => {
|
|
|
293
293
|
if (r.type === "reference" && r.references && !o) {
|
|
294
294
|
let e = r.references();
|
|
295
295
|
l.push(`REFERENCES ${t(e.tableName, i)} (${t("id", i)})`);
|
|
296
|
-
let n =
|
|
296
|
+
let n = Se(r.onDelete ?? "restrict", i);
|
|
297
297
|
l.push(`ON DELETE ${n}`);
|
|
298
|
-
let a =
|
|
298
|
+
let a = Se(r.refOnUpdate ?? "noAction", i);
|
|
299
299
|
a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
|
|
300
300
|
}
|
|
301
301
|
if (r.oneOf && r.oneOf.length > 0) {
|
|
@@ -312,18 +312,18 @@ var b = (e, t, n, r = 400) => {
|
|
|
312
312
|
e(i) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : i === "mssql" && l.push(`CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
|
|
313
313
|
}
|
|
314
314
|
return l.join(" ");
|
|
315
|
-
},
|
|
315
|
+
}, Oe = (e, n, r = null, i) => {
|
|
316
316
|
let a = /* @__PURE__ */ new Set();
|
|
317
317
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
318
318
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
319
|
-
let o = e.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(e.fields).map(([e, t]) => ` ${
|
|
320
|
-
let i = r.fields.map((t) =>
|
|
319
|
+
let o = e.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(e.fields).map(([e, t]) => ` ${De(e, t, n, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((r) => {
|
|
320
|
+
let i = r.fields.map((t) => Te(t, e.fields, n)).join(", ");
|
|
321
321
|
return ` CONSTRAINT ${t(r.name, n)} UNIQUE (${i})`;
|
|
322
322
|
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${t(e.name, n)} CHECK (${e.expr})`), d = [
|
|
323
|
-
...s ? [` PRIMARY KEY (${o.map((t) =>
|
|
323
|
+
...s ? [` PRIMARY KEY (${o.map((t) => Te(t, e.fields, n)).join(", ")})`] : [],
|
|
324
324
|
...l,
|
|
325
325
|
...u
|
|
326
|
-
], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p =
|
|
326
|
+
], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p = Ce(e.tableName, n, r);
|
|
327
327
|
if (n === "mssql") {
|
|
328
328
|
let t = r === null ? e.tableName : `${r}.${e.tableName}`, n = `CREATE TABLE ${p} (\n${f}\n)`;
|
|
329
329
|
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${n.replace(/'/g, "''")}');`;
|
|
@@ -333,10 +333,10 @@ var b = (e, t, n, r = 400) => {
|
|
|
333
333
|
f,
|
|
334
334
|
");"
|
|
335
335
|
].join("\n");
|
|
336
|
-
},
|
|
336
|
+
}, ke = (e, n, r) => {
|
|
337
337
|
let i = `${e}_${n.name}_fts`, a = (e) => t(e, r), o = n.columns.map(a).join(", "), s = n.columns.map((e) => `new.${a(e)}`).join(", "), c = [];
|
|
338
338
|
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${a(i)} USING fts5(${o}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_ai`)} AFTER INSERT ON ${a(e)} BEGIN\n INSERT INTO ${a(i)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_ad`)} AFTER DELETE ON ${a(e)} BEGIN\n DELETE FROM ${a(i)} WHERE row_id = old.${a("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_au`)} AFTER UPDATE ON ${a(e)} BEGIN\n DELETE FROM ${a(i)} WHERE row_id = old.${a("id")};\n INSERT INTO ${a(i)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c;
|
|
339
|
-
},
|
|
339
|
+
}, Ae = (e, n, r = null) => {
|
|
340
340
|
let i = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, t, r, i) => {
|
|
341
341
|
let a = {
|
|
342
342
|
using: "",
|
|
@@ -348,21 +348,21 @@ var b = (e, t, n, r = 400) => {
|
|
|
348
348
|
using: " USING GIST",
|
|
349
349
|
withSuffix: "",
|
|
350
350
|
skip: !1
|
|
351
|
-
} : (
|
|
351
|
+
} : (A(`[voltro:migrate] index '${e}' on '${t}': ${n} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), a);
|
|
352
352
|
if (r === "gin") return n === "postgres" ? {
|
|
353
353
|
using: " USING GIN",
|
|
354
354
|
withSuffix: "",
|
|
355
355
|
skip: !1
|
|
356
|
-
} : n === "mysql" || n === "mariadb" ? (
|
|
356
|
+
} : n === "mysql" || n === "mariadb" ? (A(`[voltro:migrate] gin index '${e}' on '${t}': ${n} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
357
357
|
using: "",
|
|
358
358
|
withSuffix: "",
|
|
359
359
|
skip: !0
|
|
360
|
-
}) : (
|
|
360
|
+
}) : (A(`[voltro:migrate] gin index '${e}' on '${t}': ${n} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), a);
|
|
361
361
|
if (r === "brin") return n === "postgres" ? {
|
|
362
362
|
using: " USING BRIN",
|
|
363
363
|
withSuffix: "",
|
|
364
364
|
skip: !1
|
|
365
|
-
} : (
|
|
365
|
+
} : (A(`[voltro:migrate] brin index '${e}' on '${t}': ${n} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), a);
|
|
366
366
|
if (r === "hnsw") {
|
|
367
367
|
if (n === "postgres") {
|
|
368
368
|
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? u(i?.hnsw?.distance);
|
|
@@ -373,7 +373,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
373
373
|
skip: !1
|
|
374
374
|
};
|
|
375
375
|
}
|
|
376
|
-
return
|
|
376
|
+
return A(`[voltro:migrate] hnsw index '${e}' on '${t}': ${n} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
377
377
|
using: "",
|
|
378
378
|
withSuffix: "",
|
|
379
379
|
skip: !0
|
|
@@ -382,7 +382,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
382
382
|
return a;
|
|
383
383
|
}, c = (t, r) => {
|
|
384
384
|
let i = t.map((t) => {
|
|
385
|
-
if (typeof t == "string") return
|
|
385
|
+
if (typeof t == "string") return Te(t, e.fields, n);
|
|
386
386
|
if ("jsonPath" in t) {
|
|
387
387
|
let { column: e, path: r, numeric: i } = t.jsonPath;
|
|
388
388
|
return `(${f(e, r, n, { numeric: i })})`;
|
|
@@ -393,7 +393,7 @@ var b = (e, t, n, r = 400) => {
|
|
|
393
393
|
}, l = (e, i, a, o, l, u = "", d = !1) => {
|
|
394
394
|
let f = s(e, i, o, l);
|
|
395
395
|
if (f.skip) return "";
|
|
396
|
-
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h =
|
|
396
|
+
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h = Ce(i, n, r), g = d ? "UNIQUE " : "";
|
|
397
397
|
return n === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${t(e, n)} ON ${h}${f.using} (${p})${m};` : n === "mysql" ? `CREATE ${g}INDEX ${t(e, n)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${t(e, n)} ON ${h}${f.using} (${p})${m};`;
|
|
398
398
|
};
|
|
399
399
|
for (let r of e.appliedFullText ?? []) if (n === "postgres") {
|
|
@@ -406,15 +406,15 @@ var b = (e, t, n, r = 400) => {
|
|
|
406
406
|
let a = r.columns.map((e) => t(e, n)).join(", ");
|
|
407
407
|
i.push(`CREATE FULLTEXT INDEX ${t(r.name, n)} ON ${t(e.tableName, n)} (${a});`);
|
|
408
408
|
} else if (n === "turso") throw Error(`@voltro/sql-turso: full-text index '${r.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
|
|
409
|
-
else n === "sqlite" ? i.push(...
|
|
409
|
+
else n === "sqlite" ? i.push(...ke(e.tableName, r, n)) : A(`[voltro:migrate] full-text index '${r.name}' on '${e.tableName}': ${n} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
410
410
|
for (let t of e.appliedIndexes) {
|
|
411
411
|
if ((n === "mariadb" || n === "mssql") && t.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
412
|
-
|
|
412
|
+
A(`[voltro:migrate] json-path index '${t.name}' on '${e.tableName}': ${n} cannot index a JSON expression directly — skipping. For an indexed JSON path on ${n}, add a generated column for the path (text().generatedAs(...) / .stored()) and .index([...]) it, then filter on that column instead of jsonField(...).`);
|
|
413
413
|
continue;
|
|
414
414
|
}
|
|
415
415
|
if (t.unique && t.where !== void 0 && t.where.length > 0 && (n === "mysql" || n === "mariadb")) throw Error(`@voltro/migrate: uniqueActive index '${t.name}' on '${e.tableName}' cannot be expressed on ${n} — 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 ${n}, or move this table to postgres/sqlite/mssql.`);
|
|
416
416
|
let r = "";
|
|
417
|
-
t.where !== void 0 && t.where.length > 0 && (n === "mysql" || n === "mariadb" ?
|
|
417
|
+
t.where !== void 0 && t.where.length > 0 && (n === "mysql" || n === "mariadb" ? A(`[voltro:migrate] partial index '${t.name}' on '${e.tableName}': ${n} does not support WHERE clauses on indexes — emitting a full index`) : r = ` WHERE ${t.where}`);
|
|
418
418
|
let s = l(t.name, e.tableName, t.fields, t.kind, t.kindOptions, r, t.unique === !0);
|
|
419
419
|
s !== "" && i.push(s), t.fields.every((e) => typeof e == "string") && a.add(o(t.fields));
|
|
420
420
|
}
|
|
@@ -424,12 +424,12 @@ var b = (e, t, n, r = 400) => {
|
|
|
424
424
|
i.push(l(r, e.tableName, [t])), a.add(o([t]));
|
|
425
425
|
}
|
|
426
426
|
return i.join("\n");
|
|
427
|
-
},
|
|
427
|
+
}, je = (e, t, n = O) => {
|
|
428
428
|
if (t !== "postgres") return [];
|
|
429
429
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
430
|
-
return r.length === 0 ? [] : [Me(n), ...r.map((e) =>
|
|
431
|
-
},
|
|
432
|
-
CREATE OR REPLACE FUNCTION ${
|
|
430
|
+
return r.length === 0 ? [] : [Me(n), ...r.map((e) => Pe(e, n))];
|
|
431
|
+
}, Me = (e) => `
|
|
432
|
+
CREATE OR REPLACE FUNCTION ${ve(e)}() RETURNS trigger AS $$
|
|
433
433
|
DECLARE
|
|
434
434
|
payload TEXT;
|
|
435
435
|
BEGIN
|
|
@@ -464,16 +464,23 @@ BEGIN
|
|
|
464
464
|
END;
|
|
465
465
|
$$ LANGUAGE plpgsql;
|
|
466
466
|
`.trim(), Ne = (e, t) => {
|
|
467
|
-
let n =
|
|
468
|
-
return
|
|
469
|
-
ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL
|
|
470
|
-
DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"
|
|
471
|
-
CREATE TRIGGER ${n}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
467
|
+
let n = _e(e.tableName, t);
|
|
468
|
+
return [
|
|
469
|
+
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
470
|
+
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
471
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${ve(t)}()`
|
|
472
|
+
];
|
|
473
|
+
}, Pe = (e, t) => Ne(e, t).map((e) => `${e};`).join("\n"), Fe = (e) => {
|
|
474
|
+
if (e.dialect !== "postgres") return [];
|
|
475
|
+
let t = e.channel ?? "framework_changes", n = new Map(e.tables.map((e) => [e.tableName, e])), r = [], i = e.missing.filter((e) => n.has(e));
|
|
476
|
+
if (i.length > 0) {
|
|
477
|
+
r.push(Me(t));
|
|
478
|
+
for (let e of i) r.push(...Ne(n.get(e), t));
|
|
479
|
+
}
|
|
480
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${_e(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
481
|
+
return r;
|
|
482
|
+
}, Ie = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), Le = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), Re = (e) => {
|
|
483
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = ne(e.map((e) => e.tableName), (e) => {
|
|
477
484
|
let n = t.get(e);
|
|
478
485
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
479
486
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -484,7 +491,7 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
484
491
|
}] : [];
|
|
485
492
|
}) : [];
|
|
486
493
|
}), r = [];
|
|
487
|
-
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(
|
|
494
|
+
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(w(t.tableName, e)) && r.push({
|
|
488
495
|
table: t.tableName,
|
|
489
496
|
column: e,
|
|
490
497
|
targetTable: i.references().tableName,
|
|
@@ -495,7 +502,7 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
495
502
|
if (!(i.has(e.tableName) || a.has(e.tableName))) {
|
|
496
503
|
a.add(e.tableName);
|
|
497
504
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
498
|
-
if (i.type !== "reference" || !i.references || n.has(
|
|
505
|
+
if (i.type !== "reference" || !i.references || n.has(w(e.tableName, r))) continue;
|
|
499
506
|
let a = i.references();
|
|
500
507
|
if (a.tableName === e.tableName) continue;
|
|
501
508
|
let o = t.get(a.tableName);
|
|
@@ -509,8 +516,8 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
509
516
|
sorted: o,
|
|
510
517
|
cyclic: r
|
|
511
518
|
};
|
|
512
|
-
},
|
|
513
|
-
let i = (e) => r ? `${t(r, n)}.${t(e, n)}` : t(e, n), a = `${e.table}_${e.column}_fkey`, o =
|
|
519
|
+
}, ze = (e, n, r = null) => {
|
|
520
|
+
let i = (e) => r ? `${t(r, n)}.${t(e, n)}` : t(e, n), a = `${e.table}_${e.column}_fkey`, o = Se(e.onDelete, n), s = Se(e.onUpdate, n), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (r) => `ADD CONSTRAINT ${t(a, n)} FOREIGN KEY ${r ? "IF NOT EXISTS " : ""}(${t(e.column, n)}) REFERENCES ${i(e.targetTable)} (${t("id", n)})${c}`;
|
|
514
521
|
switch (n) {
|
|
515
522
|
case "postgres": return [
|
|
516
523
|
"DO $$ BEGIN",
|
|
@@ -524,7 +531,7 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
524
531
|
case "mariadb": return `ALTER TABLE ${i(e.table)} ${l(!0)};`;
|
|
525
532
|
default: return `ALTER TABLE ${i(e.table)} ${l(!1)};`;
|
|
526
533
|
}
|
|
527
|
-
},
|
|
534
|
+
}, Be = (t, n) => {
|
|
528
535
|
let r = /* @__PURE__ */ new Map();
|
|
529
536
|
if (e(n)) return r;
|
|
530
537
|
for (let e of t) {
|
|
@@ -532,7 +539,7 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
532
539
|
t.add(e.column), r.set(e.table, t);
|
|
533
540
|
}
|
|
534
541
|
return r;
|
|
535
|
-
},
|
|
542
|
+
}, Ve = (e, t) => {
|
|
536
543
|
if (t !== "postgres") return "";
|
|
537
544
|
let n = /* @__PURE__ */ new Map();
|
|
538
545
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -548,7 +555,7 @@ FOR EACH ROW EXECUTE FUNCTION ${je(t)}();
|
|
|
548
555
|
r.push(`DO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${e.replace(/'/g, "''")}') THEN\n CREATE TYPE "${e}" AS ENUM (${n});\n END IF;\nEND $$;`);
|
|
549
556
|
}
|
|
550
557
|
return r.join("\n\n");
|
|
551
|
-
},
|
|
558
|
+
}, He = (e, t) => {
|
|
552
559
|
if (t !== "postgres") return "";
|
|
553
560
|
let n = /* @__PURE__ */ new Set();
|
|
554
561
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
|
|
@@ -562,30 +569,30 @@ BEGIN
|
|
|
562
569
|
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${i}';\n IF type_oid IS NOT NULL\n AND EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${a}')\n AND NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${o}') THEN\n IF current_setting('server_version_num')::int >= 140000 THEN\n EXECUTE format('ALTER TYPE %I RENAME VALUE %L TO %L', '${i}', '${a}', '${o}');\n ELSE\n UPDATE pg_enum SET enumlabel = '${o}' WHERE enumtypid = type_oid AND enumlabel = '${a}';\n END IF;\n END IF;\nEND $$;`);
|
|
563
570
|
}
|
|
564
571
|
return r.join("\n\n");
|
|
565
|
-
},
|
|
572
|
+
}, Ue = (e) => {
|
|
566
573
|
let t = [], n = [];
|
|
567
574
|
for (let i of e) r(i) ? n.push(i) : t.push(i);
|
|
568
575
|
return {
|
|
569
576
|
tables: t,
|
|
570
577
|
views: n
|
|
571
578
|
};
|
|
572
|
-
},
|
|
573
|
-
let { tables: a, views: o } =
|
|
574
|
-
n === "postgres" &&
|
|
575
|
-
let d =
|
|
579
|
+
}, We = (t, n, r = O) => {
|
|
580
|
+
let { tables: a, views: o } = Ue(t), { sorted: s, cyclic: c } = Re(a.map((e) => te(e, n))), l = Be(c, n), u = [];
|
|
581
|
+
n === "postgres" && Ie(s) && u.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && Le(s) && u.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
582
|
+
let d = He(s, n);
|
|
576
583
|
d && u.push(d);
|
|
577
|
-
let f =
|
|
584
|
+
let f = Ve(s, n);
|
|
578
585
|
f && u.push(f);
|
|
579
|
-
for (let e of s) u.push(
|
|
580
|
-
if (!e(n)) for (let e of c) u.push(
|
|
586
|
+
for (let e of s) u.push(Oe(e, n, null, l.get(e.tableName)));
|
|
587
|
+
if (!e(n)) for (let e of c) u.push(ze(e, n));
|
|
581
588
|
for (let e of s) {
|
|
582
|
-
let t =
|
|
589
|
+
let t = Ae(e, n);
|
|
583
590
|
t && u.push(t);
|
|
584
591
|
}
|
|
585
|
-
u.push(...
|
|
592
|
+
u.push(...je(s, n, r));
|
|
586
593
|
for (let e of o) u.push(i(e, n));
|
|
587
594
|
return u.join("\n\n") + "\n";
|
|
588
|
-
},
|
|
595
|
+
}, Ge = (e, n, r) => {
|
|
589
596
|
let i = t(e, n);
|
|
590
597
|
switch (n) {
|
|
591
598
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
|
|
@@ -595,38 +602,38 @@ BEGIN
|
|
|
595
602
|
case "turso":
|
|
596
603
|
case "sqlite": return `ATTACH DATABASE '${(r ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
|
|
597
604
|
}
|
|
598
|
-
},
|
|
599
|
-
let o =
|
|
600
|
-
if (r === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${
|
|
601
|
-
if (r === "mysql" || r === "mariadb") return `${o}\n\nUSE ${s};\n\n${
|
|
602
|
-
let { sorted: c, cyclic: l } =
|
|
603
|
-
for (let e of c) d.push(
|
|
604
|
-
if (!e(r)) for (let e of l) d.push(
|
|
605
|
+
}, Ke = (n, r, i, a) => {
|
|
606
|
+
let o = Ge(i, r, a), s = t(i, r);
|
|
607
|
+
if (r === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${We(n, r)}`;
|
|
608
|
+
if (r === "mysql" || r === "mariadb") return `${o}\n\nUSE ${s};\n\n${We(n, r)}`;
|
|
609
|
+
let { sorted: c, cyclic: l } = Re(n), u = Be(l, r), d = [o];
|
|
610
|
+
for (let e of c) d.push(Oe(e, r, i, u.get(e.tableName)));
|
|
611
|
+
if (!e(r)) for (let e of l) d.push(ze(e, r, i));
|
|
605
612
|
for (let e of c) {
|
|
606
|
-
let t =
|
|
613
|
+
let t = Ae(e, r, i);
|
|
607
614
|
t && d.push(t);
|
|
608
615
|
}
|
|
609
616
|
return d.join("\n\n") + "\n";
|
|
610
|
-
},
|
|
611
|
-
let { sorted: r, cyclic: i } =
|
|
617
|
+
}, qe = (e, t, n = O) => {
|
|
618
|
+
let { sorted: r, cyclic: i } = Re(e), a = Be(i, t), o = [], s = He(r, t);
|
|
612
619
|
s && o.push(s);
|
|
613
|
-
let c =
|
|
620
|
+
let c = Ve(r, t);
|
|
614
621
|
c && o.push(c);
|
|
615
|
-
for (let e of r) o.push(
|
|
616
|
-
for (let e of i) o.push(
|
|
617
|
-
return o.push(...
|
|
618
|
-
},
|
|
622
|
+
for (let e of r) o.push(Oe(e, t, null, a.get(e.tableName)));
|
|
623
|
+
for (let e of i) o.push(ze(e, t));
|
|
624
|
+
return o.push(...je(r, t, n)), o.join("\n\n") + "\n";
|
|
625
|
+
}, Je = (e, t = "postgres", n = O) => p.gen(function* () {
|
|
619
626
|
let r = yield* h.SqlClient;
|
|
620
|
-
yield*
|
|
621
|
-
}),
|
|
627
|
+
yield* D(r, Ze(r, We(e, t, n), t)).pipe(p.orDie);
|
|
628
|
+
}), Ye = (e, t) => {
|
|
622
629
|
let n = t.cause ?? {};
|
|
623
630
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
624
|
-
},
|
|
631
|
+
}, Xe = (e) => p.gen(function* () {
|
|
625
632
|
let t = yield* h.SqlClient;
|
|
626
|
-
for (let n of
|
|
633
|
+
for (let n of Qe(e)) process.env.VOLTRO_MIGRATE_DEBUG === "1" && ye.debug(`EXEC: ${n.replace(/\s+/g, " ").slice(0, 180)}`), yield* t.unsafe(n).pipe(p.catchIf((e) => Ye(n, e), () => p.void), p.tapError((e) => p.sync(() => {
|
|
627
634
|
ye.error(b("migrate: statement failed", n, e, 200));
|
|
628
635
|
})), p.orDieWith((e) => Error(b("migrate: statement failed", n, e, 400).trim())));
|
|
629
|
-
}),
|
|
636
|
+
}), Ze = (e, t, n) => (n === "turso" ? Xe(t) : e.withTransaction(Xe(t))).pipe(p.orDie), Qe = (e) => {
|
|
630
637
|
let t = [], n = "", r = !1;
|
|
631
638
|
for (let i = 0; i < e.length; i++) {
|
|
632
639
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -641,40 +648,40 @@ BEGIN
|
|
|
641
648
|
}
|
|
642
649
|
let i = n.trim();
|
|
643
650
|
return i.length > 0 && t.push(i), t;
|
|
644
|
-
}, Xe = async (e, t, n = "postgres") => {
|
|
645
|
-
await p.runPromise(Ge(e, n).pipe(p.provide(t)));
|
|
646
|
-
}, Ze = (e, t, n = "postgres") => p.gen(function* () {
|
|
647
|
-
let r = Ue(e, n, t), i = yield* h.SqlClient;
|
|
648
|
-
yield* ve(i, Je(i, r, n)).pipe(p.orDie);
|
|
649
|
-
}), Qe = async (e, t, n, r = "postgres") => {
|
|
650
|
-
await p.runPromise(Ze(e, t, r).pipe(p.provide(n)));
|
|
651
651
|
}, $e = async (e, t, n = "postgres") => {
|
|
652
|
+
await p.runPromise(Je(e, n).pipe(p.provide(t)));
|
|
653
|
+
}, et = (e, t, n = "postgres") => p.gen(function* () {
|
|
654
|
+
let r = Ke(e, n, t), i = yield* h.SqlClient;
|
|
655
|
+
yield* D(i, Ze(i, r, n)).pipe(p.orDie);
|
|
656
|
+
}), tt = async (e, t, n, r = "postgres") => {
|
|
657
|
+
await p.runPromise(et(e, t, r).pipe(p.provide(n)));
|
|
658
|
+
}, nt = async (e, t, n = "postgres") => {
|
|
652
659
|
await p.runPromise(p.gen(function* () {
|
|
653
|
-
let t =
|
|
654
|
-
yield*
|
|
660
|
+
let t = qe(e, n), r = yield* h.SqlClient;
|
|
661
|
+
yield* D(r, Ze(r, t, n)).pipe(p.orDie);
|
|
655
662
|
}).pipe(p.provide(t)));
|
|
656
|
-
},
|
|
663
|
+
}, rt = (e) => {
|
|
657
664
|
if (e == null) return e;
|
|
658
|
-
if (Array.isArray(e)) return e.map(
|
|
665
|
+
if (Array.isArray(e)) return e.map(rt);
|
|
659
666
|
if (typeof e != "object") return e;
|
|
660
667
|
let t = {};
|
|
661
668
|
for (let n of Object.keys(e).sort()) {
|
|
662
669
|
let r = e[n];
|
|
663
|
-
r !== void 0 && (t[n] =
|
|
670
|
+
r !== void 0 && (t[n] = rt(r));
|
|
664
671
|
}
|
|
665
672
|
return t;
|
|
666
|
-
},
|
|
673
|
+
}, it = (e) => {
|
|
667
674
|
if (!e.idScheme && !e.sensitive && !e.safe) return e;
|
|
668
675
|
let { idScheme: t, sensitive: n, safe: r, ...i } = e;
|
|
669
676
|
return i;
|
|
670
|
-
},
|
|
677
|
+
}, at = (e) => [...e].map(it).sort((e, t) => e.name.localeCompare(t.name)), ot = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), st = (e) => [...e].map((e) => ({
|
|
671
678
|
name: e.name,
|
|
672
|
-
columns:
|
|
673
|
-
indexes:
|
|
674
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
675
|
-
let t = { tables:
|
|
679
|
+
columns: at(e.columns),
|
|
680
|
+
indexes: ot(e.indexes)
|
|
681
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), P = (e) => {
|
|
682
|
+
let t = { tables: st(e.tables) }, n = JSON.stringify(rt(t));
|
|
676
683
|
return g("sha256").update(n).digest("hex");
|
|
677
|
-
},
|
|
684
|
+
}, F = (e) => e.slice(0, 16), ct = (e, t) => {
|
|
678
685
|
let n = t.references ? {
|
|
679
686
|
table: t.references().tableName,
|
|
680
687
|
column: "id",
|
|
@@ -713,7 +720,7 @@ BEGIN
|
|
|
713
720
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
714
721
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
715
722
|
};
|
|
716
|
-
},
|
|
723
|
+
}, lt = (e) => {
|
|
717
724
|
let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
718
725
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
719
726
|
}, i = e.appliedPrimaryKey ?? [];
|
|
@@ -761,11 +768,11 @@ BEGIN
|
|
|
761
768
|
});
|
|
762
769
|
}
|
|
763
770
|
return t;
|
|
764
|
-
},
|
|
771
|
+
}, ut = (e) => {
|
|
765
772
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
766
773
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
767
774
|
if (i.dropped) continue;
|
|
768
|
-
let e =
|
|
775
|
+
let e = ct(r, i);
|
|
769
776
|
n.push(t.has(r) ? {
|
|
770
777
|
...e,
|
|
771
778
|
unique: !0
|
|
@@ -775,44 +782,44 @@ BEGIN
|
|
|
775
782
|
return {
|
|
776
783
|
name: e.tableName,
|
|
777
784
|
columns: n,
|
|
778
|
-
indexes:
|
|
785
|
+
indexes: lt(e),
|
|
779
786
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
780
787
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
781
788
|
};
|
|
782
|
-
},
|
|
789
|
+
}, dt = (e) => {
|
|
783
790
|
let t = /* @__PURE__ */ new Map();
|
|
784
791
|
for (let n of e) for (let e of n.indexes) {
|
|
785
792
|
let r = t.get(e.name);
|
|
786
793
|
if (r !== void 0 && r !== n.name) throw Error(`duplicate index name '${e.name}' across tables '${r}' and '${n.name}'. Index names must be unique per SCHEMA, not just per table — the DB creates only one, so the other never applies and 'db plan' re-emits it forever. Give each an explicit, table-prefixed name (e.g. '${n.name}_${e.name}').`);
|
|
787
794
|
t.set(e.name, n.name);
|
|
788
795
|
}
|
|
789
|
-
},
|
|
790
|
-
let n = e.map((e) =>
|
|
791
|
-
return
|
|
792
|
-
},
|
|
793
|
-
let
|
|
794
|
-
if (
|
|
796
|
+
}, I = (e, t) => {
|
|
797
|
+
let n = e.map((e) => ut(te(e, t)));
|
|
798
|
+
return dt(n), { tables: n };
|
|
799
|
+
}, ft = (e, t, n = O) => p.gen(function* () {
|
|
800
|
+
let r = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
801
|
+
if (r.length === 0) return {
|
|
795
802
|
missing: [],
|
|
796
803
|
stale: []
|
|
797
804
|
};
|
|
798
|
-
let
|
|
805
|
+
let i = yield* e`
|
|
799
806
|
SELECT t.tgname
|
|
800
807
|
FROM pg_trigger t
|
|
801
808
|
JOIN pg_class c ON c.oid = t.tgrelid
|
|
802
809
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
803
810
|
WHERE NOT t.tgisinternal
|
|
804
811
|
AND n.nspname = current_schema()
|
|
805
|
-
AND t.tgname LIKE ${`${
|
|
806
|
-
`,
|
|
807
|
-
for (let e of
|
|
808
|
-
let t =
|
|
809
|
-
|
|
812
|
+
AND t.tgname LIKE ${`${k}%`}
|
|
813
|
+
`, a = new Set(i.map((e) => e.tgname)), o = [], s = [];
|
|
814
|
+
for (let e of r) {
|
|
815
|
+
let t = a.has(_e(e.tableName, n)), r = e.isReactive !== !1;
|
|
816
|
+
r && !t && o.push(e.tableName), !r && t && s.push(e.tableName);
|
|
810
817
|
}
|
|
811
818
|
return {
|
|
812
|
-
missing:
|
|
813
|
-
stale:
|
|
819
|
+
missing: o.sort(),
|
|
820
|
+
stale: s.sort()
|
|
814
821
|
};
|
|
815
|
-
}),
|
|
822
|
+
}), pt = (e) => {
|
|
816
823
|
let t = [];
|
|
817
824
|
if (e.missing.length > 0) {
|
|
818
825
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -823,19 +830,19 @@ BEGIN
|
|
|
823
830
|
t.push(`${e.stale.length} .nonReactive() table(s) still carry a change trigger — ${n}. They keep paying REPLICA IDENTITY FULL and a NOTIFY on every write for a subscription nobody receives. \`voltro db apply\` removes them.`);
|
|
824
831
|
}
|
|
825
832
|
return t.length > 0 ? t.join("\n") : void 0;
|
|
826
|
-
},
|
|
833
|
+
}, mt = {
|
|
827
834
|
postgres: !0,
|
|
828
835
|
mysql: !0,
|
|
829
836
|
mariadb: !0,
|
|
830
837
|
mssql: !0,
|
|
831
838
|
sqlite: !0
|
|
832
|
-
},
|
|
839
|
+
}, ht = {
|
|
833
840
|
postgres: !0,
|
|
834
841
|
mysql: !1,
|
|
835
842
|
mariadb: !1,
|
|
836
843
|
mssql: !0,
|
|
837
844
|
sqlite: !0
|
|
838
|
-
},
|
|
845
|
+
}, gt = (e) => {
|
|
839
846
|
switch (e) {
|
|
840
847
|
case "add-column":
|
|
841
848
|
case "drop-column":
|
|
@@ -845,43 +852,43 @@ BEGIN
|
|
|
845
852
|
case "add-foreign-key":
|
|
846
853
|
case "add-unique":
|
|
847
854
|
case "add-unique-composite":
|
|
848
|
-
case "add-check": return
|
|
849
|
-
default: return
|
|
855
|
+
case "add-check": return ht;
|
|
856
|
+
default: return mt;
|
|
850
857
|
}
|
|
851
|
-
},
|
|
858
|
+
}, _t = (e, t) => {
|
|
852
859
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
853
860
|
return new Map(e.map((e) => [e.tableName, {
|
|
854
861
|
table: e,
|
|
855
862
|
snapshot: n.get(e.tableName),
|
|
856
863
|
columnDefs: e.fields
|
|
857
864
|
}]));
|
|
858
|
-
},
|
|
865
|
+
}, L = (e) => {
|
|
859
866
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
860
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
867
|
+
if (Array.isArray(e)) return `[${e.map(L).join(",")}]`;
|
|
861
868
|
let t = e;
|
|
862
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
863
|
-
},
|
|
869
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${L(t[e])}`).join(",")}}`;
|
|
870
|
+
}, vt = (e) => {
|
|
864
871
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
865
872
|
let t = e.defaultValue;
|
|
866
873
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
867
874
|
if (typeof t == "number") return String(t);
|
|
868
|
-
if (typeof t != "string") return
|
|
875
|
+
if (typeof t != "string") return L(t);
|
|
869
876
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
870
877
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
871
878
|
let i = n.replace(/::[a-zA-Z0-9_ "]+$/, "").trim(), a = /^'(.*)'$/.test(i) ? i.slice(1, -1).replace(/''/g, "'") : i, o = /^cast\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+as\s+json\s*\)$/i.exec(a);
|
|
872
879
|
if (o) try {
|
|
873
|
-
return
|
|
880
|
+
return L(JSON.parse(o[1]));
|
|
874
881
|
} catch {}
|
|
875
882
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
876
|
-
return
|
|
883
|
+
return L(JSON.parse(a));
|
|
877
884
|
} catch {}
|
|
878
885
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
879
|
-
},
|
|
880
|
-
let n =
|
|
886
|
+
}, yt = (e, t) => {
|
|
887
|
+
let n = vt(e), r = vt(t);
|
|
881
888
|
if (n === r) return !0;
|
|
882
889
|
let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
883
890
|
return i(n) === i(r);
|
|
884
|
-
},
|
|
891
|
+
}, bt = (e) => {
|
|
885
892
|
if (!e) return null;
|
|
886
893
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
887
894
|
return {
|
|
@@ -890,25 +897,25 @@ BEGIN
|
|
|
890
897
|
onDelete: t(e.onDelete),
|
|
891
898
|
onUpdate: t(e.onUpdate)
|
|
892
899
|
};
|
|
893
|
-
},
|
|
900
|
+
}, xt = (e, t) => {
|
|
894
901
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
895
902
|
if (!n && !r) return !0;
|
|
896
903
|
if (!n || !r || n.length !== r.length) return !1;
|
|
897
904
|
let i = [...n].sort(), a = [...r].sort();
|
|
898
905
|
return i.every((e, t) => e === a[t]);
|
|
899
|
-
},
|
|
906
|
+
}, St = (e, t) => {
|
|
900
907
|
try {
|
|
901
|
-
let n = /\((\d+)\)/.exec(
|
|
908
|
+
let n = /\((\d+)\)/.exec(j(e, t));
|
|
902
909
|
return n ? Number(n[1]) : void 0;
|
|
903
910
|
} catch {
|
|
904
911
|
return;
|
|
905
912
|
}
|
|
906
|
-
},
|
|
913
|
+
}, Ct = (t, n, r) => r === void 0 || e(r) ? !0 : t.type !== "text" || n.type !== "text" || St(t, r) === n.maxLength, wt = (e, t, n) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && yt(e, t) && Ct(e, t, n) && JSON.stringify(bt(e.references)) === JSON.stringify(bt(t.references)) && xt(e.oneOf, t.oneOf), Tt = (e, t) => t.oneOf && t.oneOf.length > 0 ? R({
|
|
907
914
|
kind: "add-check",
|
|
908
915
|
table: e,
|
|
909
916
|
column: t.name,
|
|
910
917
|
values: t.oneOf
|
|
911
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
918
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, Et = (e, t) => e.unique === t.unique && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), Dt = (e, t, n) => {
|
|
912
919
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [];
|
|
913
920
|
for (let t of e.columns) {
|
|
914
921
|
let e = r.get(t.name);
|
|
@@ -916,7 +923,7 @@ BEGIN
|
|
|
916
923
|
a.push(t);
|
|
917
924
|
continue;
|
|
918
925
|
}
|
|
919
|
-
|
|
926
|
+
wt(t, e, n) || s.push({
|
|
920
927
|
declared: t,
|
|
921
928
|
live: e
|
|
922
929
|
});
|
|
@@ -927,11 +934,11 @@ BEGIN
|
|
|
927
934
|
removed: o,
|
|
928
935
|
changed: s
|
|
929
936
|
};
|
|
930
|
-
},
|
|
937
|
+
}, Ot = (e, t) => {
|
|
931
938
|
let n = new Map(t.indexes.map((e) => [e.name, e])), r = new Map(e.indexes.map((e) => [e.name, e])), i = [], a = [];
|
|
932
939
|
for (let t of e.indexes) {
|
|
933
940
|
let e = n.get(t.name);
|
|
934
|
-
(!e || !
|
|
941
|
+
(!e || !Et(t, e)) && i.push(t);
|
|
935
942
|
}
|
|
936
943
|
for (let e of t.indexes) r.has(e.name) || a.push(e);
|
|
937
944
|
return {
|
|
@@ -941,33 +948,33 @@ BEGIN
|
|
|
941
948
|
}, R = (e, t, n, r) => ({
|
|
942
949
|
op: e,
|
|
943
950
|
classification: t,
|
|
944
|
-
atomicByDialect:
|
|
951
|
+
atomicByDialect: gt(e.kind),
|
|
945
952
|
...n ? { reason: n } : {},
|
|
946
953
|
...r ? { blocked: r } : {}
|
|
947
|
-
}),
|
|
954
|
+
}), kt = (e, t, n) => {
|
|
948
955
|
let r = {
|
|
949
956
|
kind: "add-column",
|
|
950
957
|
table: e,
|
|
951
958
|
column: t
|
|
952
959
|
};
|
|
953
960
|
return t.nullable ? R(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? R(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? R(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : R(r, "needs-backfill", "NOT NULL column on a table whose row count is unknown", { fix: `declare \`${t.name}: <type>().backfill(sql\`...\`)\` OR \`.default(value)\` so existing rows survive the migration` });
|
|
954
|
-
},
|
|
961
|
+
}, At = (e, t, n) => {
|
|
955
962
|
let r = {
|
|
956
963
|
kind: "drop-column",
|
|
957
964
|
table: e,
|
|
958
965
|
column: t.name
|
|
959
966
|
};
|
|
960
967
|
return n?.dropped ? R(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : R(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
961
|
-
},
|
|
968
|
+
}, jt = (e, t, n, r, i) => R({
|
|
962
969
|
kind: "create-table",
|
|
963
970
|
table: e,
|
|
964
971
|
columns: t,
|
|
965
972
|
indexes: n,
|
|
966
973
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
967
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
974
|
+
}, "safe", i ?? "new table — no data to preserve"), Mt = (e) => R({
|
|
968
975
|
kind: "drop-table",
|
|
969
976
|
table: e
|
|
970
|
-
}, "lossy", "table missing from declared schema", { fix: "if intentional, set VOLTRO_DESTRUCTIVE_OK=1 OR add a file-based migration. If a typo, restore the table declaration" }),
|
|
977
|
+
}, "lossy", "table missing from declared schema", { fix: "if intentional, set VOLTRO_DESTRUCTIVE_OK=1 OR add a file-based migration. If a typo, restore the table declaration" }), Nt = 5e4, Pt = (e, t, n, r) => {
|
|
971
978
|
let i = (n ?? 0) >= r, a;
|
|
972
979
|
return a = t.unique ? t.columns.length === 1 ? {
|
|
973
980
|
kind: "add-unique",
|
|
@@ -983,7 +990,7 @@ BEGIN
|
|
|
983
990
|
table: e,
|
|
984
991
|
index: t
|
|
985
992
|
}, i ? R(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : R(a, "safe", t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index");
|
|
986
|
-
},
|
|
993
|
+
}, Ft = (e, t) => t.unique && t.columns.length > 1 ? R({
|
|
987
994
|
kind: "drop-unique-composite",
|
|
988
995
|
table: e,
|
|
989
996
|
name: t.name
|
|
@@ -991,7 +998,7 @@ BEGIN
|
|
|
991
998
|
kind: "drop-index",
|
|
992
999
|
table: e,
|
|
993
1000
|
index: t.name
|
|
994
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1001
|
+
}, "safe", "drop index (no data loss — index is derived data)"), It = (e, t) => {
|
|
995
1002
|
if (e === "reference") return "text";
|
|
996
1003
|
switch (t) {
|
|
997
1004
|
case "sqlite":
|
|
@@ -999,7 +1006,7 @@ BEGIN
|
|
|
999
1006
|
case "mssql": return e === "json" ? "text" : e;
|
|
1000
1007
|
default: return e;
|
|
1001
1008
|
}
|
|
1002
|
-
},
|
|
1009
|
+
}, Lt = (t, n, r, i, a, o) => {
|
|
1003
1010
|
let s = [];
|
|
1004
1011
|
if (n.nullable !== r.nullable) {
|
|
1005
1012
|
let e = {
|
|
@@ -1022,7 +1029,7 @@ BEGIN
|
|
|
1022
1029
|
table: t,
|
|
1023
1030
|
column: n.name
|
|
1024
1031
|
}, "safe", `drop unique constraint on ${t}.${n.name} — constraint is derived metadata, no data loss`));
|
|
1025
|
-
if (
|
|
1032
|
+
if (It(n.type, i) !== It(r.type, i)) {
|
|
1026
1033
|
let e = n.narrowedFrom;
|
|
1027
1034
|
if (e && e.from === r.type) {
|
|
1028
1035
|
let i = {
|
|
@@ -1055,7 +1062,7 @@ BEGIN
|
|
|
1055
1062
|
to: "text"
|
|
1056
1063
|
}, e ? "safe" : "needs-backfill", e ? `text length ${i} → ${a} on ${t}.${n.name} — widening, no data can be lost` : `text length ${i} → ${a} on ${t}.${n.name} — NARROWING; the ALTER fails if any existing value is longer than ${String(n.maxLength)}. Check first: SELECT COUNT(*) FROM ${t} WHERE LENGTH(${n.name}) > ${String(n.maxLength)}`));
|
|
1057
1064
|
}
|
|
1058
|
-
if (!
|
|
1065
|
+
if (!yt(n, r)) {
|
|
1059
1066
|
let e = {
|
|
1060
1067
|
kind: "alter-column-default",
|
|
1061
1068
|
table: t,
|
|
@@ -1065,16 +1072,16 @@ BEGIN
|
|
|
1065
1072
|
};
|
|
1066
1073
|
s.push(R(e, "safe", `default change on ${t}.${n.name} affects only future inserts`));
|
|
1067
1074
|
}
|
|
1068
|
-
if (!
|
|
1075
|
+
if (!xt(n.oneOf, r.oneOf)) {
|
|
1069
1076
|
r.oneOf && r.oneOf.length > 0 && s.push(R({
|
|
1070
1077
|
kind: "drop-check",
|
|
1071
1078
|
table: t,
|
|
1072
1079
|
column: n.name
|
|
1073
1080
|
}, "safe", `drop stale enum CHECK on ${t}.${n.name}`));
|
|
1074
|
-
let e =
|
|
1081
|
+
let e = Tt(t, n);
|
|
1075
1082
|
e && s.push(e);
|
|
1076
1083
|
}
|
|
1077
|
-
if (JSON.stringify(
|
|
1084
|
+
if (JSON.stringify(bt(n.references)) !== JSON.stringify(bt(r.references)) && (r.references && s.push(R({
|
|
1078
1085
|
kind: "drop-foreign-key",
|
|
1079
1086
|
table: t,
|
|
1080
1087
|
column: n.name
|
|
@@ -1094,7 +1101,7 @@ BEGIN
|
|
|
1094
1101
|
}, "lossy", r === "delete" ? `add FK ${t}.${n.name} → ${e}: orphanPolicy 'delete' first DELETES rows whose ${n.name} points at a missing ${e}` : `add FK ${t}.${n.name} → ${e}: orphanPolicy 'null' first NULLs ${n.name} where it points at a missing ${e}`)) : s.push(R(i, "needs-backfill", `add FK ${t}.${n.name} → ${e} — existing rows must already reference a valid ${e} (else set orphanPolicy:'null'/'delete')`));
|
|
1095
1102
|
}
|
|
1096
1103
|
return s;
|
|
1097
|
-
},
|
|
1104
|
+
}, Rt = (e, t, n) => {
|
|
1098
1105
|
let r = [], i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), o = new Set(n.removed.map((e) => e.name)), s = new Set(n.added.map((e) => e.name));
|
|
1099
1106
|
for (let [n, c] of Object.entries(t)) {
|
|
1100
1107
|
let t = c.renamedFrom;
|
|
@@ -1110,22 +1117,22 @@ BEGIN
|
|
|
1110
1117
|
consumedAddedNames: i,
|
|
1111
1118
|
consumedRemovedNames: a
|
|
1112
1119
|
};
|
|
1113
|
-
},
|
|
1120
|
+
}, zt = /* @__PURE__ */ new Set([
|
|
1114
1121
|
"postgres",
|
|
1115
1122
|
"mysql",
|
|
1116
1123
|
"mariadb",
|
|
1117
1124
|
"mssql"
|
|
1118
|
-
]),
|
|
1125
|
+
]), Bt = {
|
|
1119
1126
|
ops: [],
|
|
1120
1127
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1121
1128
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1122
|
-
},
|
|
1123
|
-
if (i === void 0 || !
|
|
1124
|
-
let a = t.added.filter((e) =>
|
|
1125
|
-
if (a.length === 0) return
|
|
1129
|
+
}, Vt = (e) => !e.unique && !e.expression, Ht = (e, t, n, r, i) => {
|
|
1130
|
+
if (i === void 0 || !zt.has(i)) return Bt;
|
|
1131
|
+
let a = t.added.filter((e) => Vt(e) && !r.has(e.name));
|
|
1132
|
+
if (a.length === 0) return Bt;
|
|
1126
1133
|
let o = (e) => e.columns.map((e) => n.get(e) ?? e).join("\0"), s = (e) => e.columns.join("\0"), c = [], l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set();
|
|
1127
1134
|
for (let n of t.removed) {
|
|
1128
|
-
if (!
|
|
1135
|
+
if (!Vt(n)) continue;
|
|
1129
1136
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1130
1137
|
if (r.length !== 1) continue;
|
|
1131
1138
|
let i = r[0];
|
|
@@ -1141,7 +1148,7 @@ BEGIN
|
|
|
1141
1148
|
consumedAddedNames: l,
|
|
1142
1149
|
consumedRemovedNames: u
|
|
1143
1150
|
};
|
|
1144
|
-
},
|
|
1151
|
+
}, Ut = (e, t, n) => {
|
|
1145
1152
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1146
1153
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1147
1154
|
for (let c of e.tables) {
|
|
@@ -1181,12 +1188,12 @@ BEGIN
|
|
|
1181
1188
|
claimedOldNames: c,
|
|
1182
1189
|
refusals: o
|
|
1183
1190
|
};
|
|
1184
|
-
},
|
|
1191
|
+
}, Wt = (e, t, n, r) => {
|
|
1185
1192
|
if (t === void 0) return {
|
|
1186
1193
|
live: e,
|
|
1187
1194
|
ops: []
|
|
1188
1195
|
};
|
|
1189
|
-
let i = r !== void 0 &&
|
|
1196
|
+
let i = r !== void 0 && zt.has(r), a = [], o = e.indexes.map((e) => {
|
|
1190
1197
|
if (!e.name.startsWith(t)) return e;
|
|
1191
1198
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1192
1199
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
@@ -1212,7 +1219,7 @@ BEGIN
|
|
|
1212
1219
|
},
|
|
1213
1220
|
ops: a
|
|
1214
1221
|
};
|
|
1215
|
-
},
|
|
1222
|
+
}, Gt = (e) => {
|
|
1216
1223
|
let t = {
|
|
1217
1224
|
safe: 0,
|
|
1218
1225
|
needsDefault: 0,
|
|
@@ -1247,42 +1254,42 @@ BEGIN
|
|
|
1247
1254
|
break;
|
|
1248
1255
|
}
|
|
1249
1256
|
return t;
|
|
1250
|
-
},
|
|
1251
|
-
let t =
|
|
1257
|
+
}, Kt = (e) => {
|
|
1258
|
+
let t = I(e.declared, e.dialect), n = _t(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? Nt, a = [], o = Ut(t, r, n);
|
|
1252
1259
|
a.push(...o.ops);
|
|
1253
1260
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1254
|
-
a.push(
|
|
1261
|
+
a.push(jt(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1255
1262
|
for (let t of e.columns) {
|
|
1256
|
-
let n =
|
|
1263
|
+
let n = Tt(e.name, t);
|
|
1257
1264
|
n && a.push(n);
|
|
1258
1265
|
}
|
|
1259
1266
|
}
|
|
1260
1267
|
let c = new Set(e.ignoreTables ?? []);
|
|
1261
|
-
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || s(t.name) || d(t.name) || c.has(t.name) || a.push(
|
|
1268
|
+
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || s(t.name) || d(t.name) || c.has(t.name) || a.push(Mt(t.name));
|
|
1262
1269
|
for (let s of t.tables) {
|
|
1263
1270
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1264
1271
|
if (!c) continue;
|
|
1265
|
-
let l =
|
|
1272
|
+
let l = Wt(c, t, s.name, e.dialect);
|
|
1266
1273
|
a.push(...l.ops);
|
|
1267
|
-
let u = l.live, f = n.get(s.name), p =
|
|
1274
|
+
let u = l.live, f = n.get(s.name), p = Dt(s, u, e.dialect), m = Ot(s, u), h = Rt(f.table, f.columnDefs, p);
|
|
1268
1275
|
a.push(...h.ops);
|
|
1269
1276
|
for (let e of p.removed) {
|
|
1270
1277
|
if (h.consumedRemovedNames.has(e.name) || d(e.name)) continue;
|
|
1271
1278
|
let t = f.columnDefs[e.name];
|
|
1272
|
-
a.push(
|
|
1279
|
+
a.push(At(s.name, e, t));
|
|
1273
1280
|
}
|
|
1274
1281
|
for (let e of p.added) {
|
|
1275
1282
|
if (h.consumedAddedNames.has(e.name)) continue;
|
|
1276
1283
|
let t = f.columnDefs[e.name];
|
|
1277
|
-
a.push(
|
|
1278
|
-
let n =
|
|
1284
|
+
a.push(kt(s.name, e, t));
|
|
1285
|
+
let n = Tt(s.name, e);
|
|
1279
1286
|
n && a.push(n);
|
|
1280
1287
|
}
|
|
1281
|
-
let g = new Map(h.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), _ =
|
|
1288
|
+
let g = new Map(h.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), _ = Ht(s.name, m, g, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1282
1289
|
a.push(..._.ops);
|
|
1283
|
-
for (let e of m.added) _.consumedAddedNames.has(e.name) || a.push(
|
|
1284
|
-
for (let e of m.removed) _.consumedRemovedNames.has(e.name) || a.push(
|
|
1285
|
-
for (let { declared: t, live: n } of p.changed) a.push(...
|
|
1290
|
+
for (let e of m.added) _.consumedAddedNames.has(e.name) || a.push(Pt(s.name, e, u.rowCount, i));
|
|
1291
|
+
for (let e of m.removed) _.consumedRemovedNames.has(e.name) || a.push(Ft(s.name, e));
|
|
1292
|
+
for (let { declared: t, live: n } of p.changed) a.push(...Lt(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1286
1293
|
}
|
|
1287
1294
|
let l = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), u = new Map(t.tables.map((e) => [e.name, e])), f = (e) => {
|
|
1288
1295
|
let t = u.get(e);
|
|
@@ -1290,8 +1297,8 @@ BEGIN
|
|
|
1290
1297
|
column: e.name,
|
|
1291
1298
|
target: e.references.table
|
|
1292
1299
|
}] : []) : [];
|
|
1293
|
-
}, p =
|
|
1294
|
-
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) !t.references || !p.has(
|
|
1300
|
+
}, p = ne([...l], f), m = [];
|
|
1301
|
+
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) !t.references || !p.has(w(e.name, t.name)) || m.push(R({
|
|
1295
1302
|
kind: "add-foreign-key",
|
|
1296
1303
|
table: e.name,
|
|
1297
1304
|
column: t.name,
|
|
@@ -1306,8 +1313,8 @@ BEGIN
|
|
|
1306
1313
|
let n = a[t];
|
|
1307
1314
|
if (n.op.kind !== "create-table") continue;
|
|
1308
1315
|
let r = n.op;
|
|
1309
|
-
if (!r.columns.some((e) => p.has(
|
|
1310
|
-
let i = r.columns.map((t) => p.has(
|
|
1316
|
+
if (!r.columns.some((e) => p.has(w(r.table, e.name)))) continue;
|
|
1317
|
+
let i = r.columns.map((t) => p.has(w(r.table, t.name)) ? e(t) : t);
|
|
1311
1318
|
a[t] = {
|
|
1312
1319
|
...n,
|
|
1313
1320
|
op: {
|
|
@@ -1327,7 +1334,7 @@ BEGIN
|
|
|
1327
1334
|
let i = new Set(t).add(e), a = 0;
|
|
1328
1335
|
for (let t of r.columns) {
|
|
1329
1336
|
let n = t.references?.table;
|
|
1330
|
-
n && n !== e && !p.has(
|
|
1337
|
+
n && n !== e && !p.has(w(e, t.name)) && (a = Math.max(a, _(n, i) + 1));
|
|
1331
1338
|
}
|
|
1332
1339
|
return g.set(e, a), a;
|
|
1333
1340
|
}, v = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, y = (e) => {
|
|
@@ -1363,11 +1370,11 @@ BEGIN
|
|
|
1363
1370
|
});
|
|
1364
1371
|
return {
|
|
1365
1372
|
operations: S,
|
|
1366
|
-
fromFingerprint:
|
|
1367
|
-
toFingerprint:
|
|
1368
|
-
summary:
|
|
1373
|
+
fromFingerprint: P(e.live),
|
|
1374
|
+
toFingerprint: P(t),
|
|
1375
|
+
summary: Gt(S)
|
|
1369
1376
|
};
|
|
1370
|
-
},
|
|
1377
|
+
}, qt = (e) => {
|
|
1371
1378
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1372
1379
|
if (!t) return null;
|
|
1373
1380
|
let n = [...e.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
|
|
@@ -1375,7 +1382,7 @@ BEGIN
|
|
|
1375
1382
|
column: t[1],
|
|
1376
1383
|
values: n
|
|
1377
1384
|
};
|
|
1378
|
-
},
|
|
1385
|
+
}, Jt = (e, t) => {
|
|
1379
1386
|
if (t === "vector") return "vector";
|
|
1380
1387
|
switch (e) {
|
|
1381
1388
|
case "text":
|
|
@@ -1410,25 +1417,25 @@ BEGIN
|
|
|
1410
1417
|
case "SET DEFAULT": return "noAction";
|
|
1411
1418
|
default: return "noAction";
|
|
1412
1419
|
}
|
|
1413
|
-
},
|
|
1420
|
+
}, Yt = (e, t) => {
|
|
1414
1421
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1415
1422
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1416
|
-
},
|
|
1423
|
+
}, Xt = () => Yt(process.env.VOLTRO_INTROSPECT_BATCH, 20), Zt = 300, Qt = () => {
|
|
1417
1424
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1418
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1419
|
-
},
|
|
1425
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Yt(e, 3e4);
|
|
1426
|
+
}, $t = (e, t) => {
|
|
1420
1427
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1421
1428
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1422
1429
|
return r;
|
|
1423
|
-
},
|
|
1424
|
-
let t =
|
|
1430
|
+
}, en = (e) => {
|
|
1431
|
+
let t = Qt(), n = p.gen(function* () {
|
|
1425
1432
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1426
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
1433
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Xt(), a = (e, t) => p.gen(function* () {
|
|
1427
1434
|
let r = [];
|
|
1428
|
-
for (let a of
|
|
1435
|
+
for (let a of $t(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1429
1436
|
return r;
|
|
1430
1437
|
}), o = [];
|
|
1431
|
-
for (let t = 0;; t +=
|
|
1438
|
+
for (let t = 0;; t += Zt) {
|
|
1432
1439
|
let n = yield* e`
|
|
1433
1440
|
SELECT c.relname AS table_name,
|
|
1434
1441
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1436,9 +1443,9 @@ BEGIN
|
|
|
1436
1443
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1437
1444
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1438
1445
|
ORDER BY c.relname
|
|
1439
|
-
LIMIT ${r(
|
|
1446
|
+
LIMIT ${r(Zt)} OFFSET ${r(t)}
|
|
1440
1447
|
`;
|
|
1441
|
-
if (o.push(...n), n.length <
|
|
1448
|
+
if (o.push(...n), n.length < Zt) break;
|
|
1442
1449
|
}
|
|
1443
1450
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1444
1451
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1533,18 +1540,18 @@ BEGIN
|
|
|
1533
1540
|
let t = y.get(e.table_name);
|
|
1534
1541
|
t || (t = /* @__PURE__ */ new Set(), y.set(e.table_name, t)), t.add(e.column_name);
|
|
1535
1542
|
}
|
|
1536
|
-
let
|
|
1543
|
+
let C = /* @__PURE__ */ new Map();
|
|
1537
1544
|
for (let e of f) {
|
|
1538
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
1545
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = C.get(t);
|
|
1539
1546
|
n || (n = {
|
|
1540
1547
|
table: e.table_name,
|
|
1541
1548
|
columns: []
|
|
1542
|
-
},
|
|
1549
|
+
}, C.set(t, n)), n.columns.push({
|
|
1543
1550
|
name: e.column_name,
|
|
1544
1551
|
position: e.position
|
|
1545
1552
|
});
|
|
1546
1553
|
}
|
|
1547
|
-
for (let [e, t] of
|
|
1554
|
+
for (let [e, t] of C) {
|
|
1548
1555
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
1549
1556
|
if (n.length === 1) {
|
|
1550
1557
|
let e = b.get(t.table);
|
|
@@ -1569,10 +1576,10 @@ BEGIN
|
|
|
1569
1576
|
let n = t.get(e.index_name);
|
|
1570
1577
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1571
1578
|
}
|
|
1572
|
-
let
|
|
1579
|
+
let te = [];
|
|
1573
1580
|
for (let e of c) {
|
|
1574
1581
|
let t = /* @__PURE__ */ new Set(), n = (v.get(e.table_name) ?? []).filter((e) => t.has(e.column_name) ? !1 : (t.add(e.column_name), !0)), r = y.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = b.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = S.get(e.table_name) ?? [], o = new Map(a.map((e) => [e.source_column, e])), s = new Set(n.filter((e) => e.udt_name === "tsvector").map((e) => e.column_name)), c = n.filter((e) => !s.has(e.column_name)).map((t) => {
|
|
1575
|
-
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" :
|
|
1582
|
+
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" : Jt(t.data_type, t.udt_name), c = a ? {
|
|
1576
1583
|
table: a.target_table,
|
|
1577
1584
|
column: a.target_column,
|
|
1578
1585
|
onDelete: z(a.delete_rule),
|
|
@@ -1613,20 +1620,20 @@ BEGIN
|
|
|
1613
1620
|
unique: !0
|
|
1614
1621
|
});
|
|
1615
1622
|
let d = Number(e.row_count ?? 0);
|
|
1616
|
-
|
|
1623
|
+
te.push({
|
|
1617
1624
|
name: e.table_name,
|
|
1618
1625
|
columns: c,
|
|
1619
1626
|
indexes: l,
|
|
1620
1627
|
...d > 0 ? { rowCount: d } : {}
|
|
1621
1628
|
});
|
|
1622
1629
|
}
|
|
1623
|
-
return { tables:
|
|
1630
|
+
return { tables: te };
|
|
1624
1631
|
});
|
|
1625
1632
|
return (t > 0 ? e.withTransaction(n) : n).pipe(p.catchAll((e) => {
|
|
1626
1633
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1627
1634
|
return n.includes("statement timeout") || n.includes("57014") ? p.die(/* @__PURE__ */ Error(`schema introspection exceeded VOLTRO_INTROSPECT_TIMEOUT_MS (${t}ms) — the schema is very large / FK-dense or the database is slow. Raise VOLTRO_INTROSPECT_TIMEOUT_MS, set it to 0 to disable the ceiling, or use DB_DIRECT_URL for a non-pooler connection.`)) : p.fail(e);
|
|
1628
1635
|
}));
|
|
1629
|
-
},
|
|
1636
|
+
}, tn = (e, t) => {
|
|
1630
1637
|
switch (e.toLowerCase()) {
|
|
1631
1638
|
case "varchar":
|
|
1632
1639
|
case "char":
|
|
@@ -1662,7 +1669,7 @@ BEGIN
|
|
|
1662
1669
|
let t = e, n = {};
|
|
1663
1670
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1664
1671
|
return n;
|
|
1665
|
-
}),
|
|
1672
|
+
}), nn = (e) => p.gen(function* () {
|
|
1666
1673
|
let t = B(yield* e`
|
|
1667
1674
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1668
1675
|
FROM information_schema.tables
|
|
@@ -1696,7 +1703,7 @@ BEGIN
|
|
|
1696
1703
|
o.add(`${e.table_name}.${t[1]}`);
|
|
1697
1704
|
continue;
|
|
1698
1705
|
}
|
|
1699
|
-
let n =
|
|
1706
|
+
let n = qt(e.check_clause);
|
|
1700
1707
|
n && s.set(`${e.table_name}.${n.column}`, n.values);
|
|
1701
1708
|
}
|
|
1702
1709
|
let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
|
|
@@ -1719,7 +1726,7 @@ BEGIN
|
|
|
1719
1726
|
let t = c.get(e.table_name) ?? [], n = l.get(e.table_name) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = t.filter((e) => e.column_key === "PRI").map((e) => e.column_name), a = /* @__PURE__ */ new Set(), f = u.get(e.table_name);
|
|
1720
1727
|
if (f) for (let e of f.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1721
1728
|
let p = t.map((t) => {
|
|
1722
|
-
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" :
|
|
1729
|
+
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" : tn(t.data_type, t.column_type), u = c ? {
|
|
1723
1730
|
table: c.target_table,
|
|
1724
1731
|
column: c.target_column,
|
|
1725
1732
|
onDelete: z(c.delete_rule),
|
|
@@ -1761,10 +1768,10 @@ BEGIN
|
|
|
1761
1768
|
});
|
|
1762
1769
|
}
|
|
1763
1770
|
return { tables: d };
|
|
1764
|
-
}),
|
|
1771
|
+
}), rn = (e) => {
|
|
1765
1772
|
let t = e.toUpperCase();
|
|
1766
1773
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
1767
|
-
},
|
|
1774
|
+
}, an = (e) => p.gen(function* () {
|
|
1768
1775
|
let t = yield* e`
|
|
1769
1776
|
SELECT name, sql FROM sqlite_master
|
|
1770
1777
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -1781,7 +1788,7 @@ BEGIN
|
|
|
1781
1788
|
d.set(t.name, r), t.unique === 1 && r.length === 1 && f.add(r[0]);
|
|
1782
1789
|
}
|
|
1783
1790
|
let p = o.map((e) => {
|
|
1784
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
1791
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : rn(e.type), a = r ? {
|
|
1785
1792
|
table: r.table,
|
|
1786
1793
|
column: r.to,
|
|
1787
1794
|
onDelete: z(r.on_delete),
|
|
@@ -1820,7 +1827,7 @@ BEGIN
|
|
|
1820
1827
|
});
|
|
1821
1828
|
}
|
|
1822
1829
|
return { tables: r };
|
|
1823
|
-
}),
|
|
1830
|
+
}), on = (e) => {
|
|
1824
1831
|
switch (e.toLowerCase()) {
|
|
1825
1832
|
case "int":
|
|
1826
1833
|
case "smallint":
|
|
@@ -1842,7 +1849,7 @@ BEGIN
|
|
|
1842
1849
|
case "image": return "bytes";
|
|
1843
1850
|
default: return "text";
|
|
1844
1851
|
}
|
|
1845
|
-
}, V = (e) => e === !0 || e === 1,
|
|
1852
|
+
}, V = (e) => e === !0 || e === 1, sn = (e) => p.gen(function* () {
|
|
1846
1853
|
let t = yield* e`
|
|
1847
1854
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
1848
1855
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -1903,12 +1910,12 @@ BEGIN
|
|
|
1903
1910
|
else V(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
|
|
1904
1911
|
}
|
|
1905
1912
|
let p = t.map((t) => {
|
|
1906
|
-
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" :
|
|
1913
|
+
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" : on(t.data_type), s = i ? {
|
|
1907
1914
|
table: i.target_table,
|
|
1908
1915
|
column: i.target_column,
|
|
1909
|
-
onDelete:
|
|
1910
|
-
onUpdate:
|
|
1911
|
-
} : void 0, c = t.column_default === null ? null :
|
|
1916
|
+
onDelete: cn(i.delete_rule),
|
|
1917
|
+
onUpdate: cn(i.update_rule)
|
|
1918
|
+
} : void 0, c = t.column_default === null ? null : ln(t.column_default), l = o.get(`${e}.${t.column_name}`);
|
|
1912
1919
|
return {
|
|
1913
1920
|
name: t.column_name,
|
|
1914
1921
|
type: a,
|
|
@@ -1942,18 +1949,18 @@ BEGIN
|
|
|
1942
1949
|
});
|
|
1943
1950
|
}
|
|
1944
1951
|
return { tables: u };
|
|
1945
|
-
}),
|
|
1952
|
+
}), cn = (e) => {
|
|
1946
1953
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
1947
1954
|
case "CASCADE": return "cascade";
|
|
1948
1955
|
case "SET NULL": return "setNull";
|
|
1949
1956
|
case "SET DEFAULT": return "noAction";
|
|
1950
1957
|
default: return "noAction";
|
|
1951
1958
|
}
|
|
1952
|
-
},
|
|
1959
|
+
}, ln = (e) => {
|
|
1953
1960
|
let t = e.trim();
|
|
1954
1961
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
1955
1962
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
1956
|
-
},
|
|
1963
|
+
}, un = /* @__PURE__ */ new Set([
|
|
1957
1964
|
"character varying",
|
|
1958
1965
|
"varchar",
|
|
1959
1966
|
"nvarchar",
|
|
@@ -1961,29 +1968,32 @@ BEGIN
|
|
|
1961
1968
|
"character",
|
|
1962
1969
|
"nchar"
|
|
1963
1970
|
]), H = (e, t) => {
|
|
1964
|
-
if (!
|
|
1971
|
+
if (!un.has(e.toLowerCase())) return;
|
|
1965
1972
|
let n = Number(t);
|
|
1966
1973
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
1967
1974
|
}, U = (e) => e.onDialectOrElse({
|
|
1968
|
-
mysql: () =>
|
|
1969
|
-
mssql: () =>
|
|
1970
|
-
sqlite: () =>
|
|
1971
|
-
orElse: () =>
|
|
1972
|
-
}),
|
|
1975
|
+
mysql: () => nn(e),
|
|
1976
|
+
mssql: () => sn(e),
|
|
1977
|
+
sqlite: () => an(e),
|
|
1978
|
+
orElse: () => en(e)
|
|
1979
|
+
}), dn = (e, t) => e.onDialectOrElse({
|
|
1980
|
+
mysql: () => p.succeed(t.replace("T", " ").replace("Z", "")),
|
|
1981
|
+
orElse: () => p.succeed(t)
|
|
1982
|
+
}), fn = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, W = (e, t) => {
|
|
1973
1983
|
if (!(e.type === "text" && e.maxLength !== void 0) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
1974
1984
|
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;
|
|
1975
1985
|
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.`);
|
|
1976
|
-
return
|
|
1977
|
-
},
|
|
1978
|
-
let t =
|
|
1979
|
-
return t === void 0 ?
|
|
1980
|
-
},
|
|
1986
|
+
return j(e, t);
|
|
1987
|
+
}, pn = (e) => {
|
|
1988
|
+
let t = W(e, "postgres");
|
|
1989
|
+
return t === void 0 ? mn(e) : t;
|
|
1990
|
+
}, mn = (e) => {
|
|
1981
1991
|
switch (e.type) {
|
|
1982
1992
|
case "id": return "text";
|
|
1983
1993
|
case "text": return "text";
|
|
1984
1994
|
case "integer": return "integer";
|
|
1985
1995
|
case "real": return "double precision";
|
|
1986
|
-
case "decimal": return
|
|
1996
|
+
case "decimal": return fn(e, "NUMERIC");
|
|
1987
1997
|
case "bigint": return "bigint";
|
|
1988
1998
|
case "boolean": return "boolean";
|
|
1989
1999
|
case "timestamp": return "timestamptz";
|
|
@@ -1997,15 +2007,15 @@ BEGIN
|
|
|
1997
2007
|
case "interval": return "interval";
|
|
1998
2008
|
case "raw": return e.rawDdl ?? "text";
|
|
1999
2009
|
}
|
|
2000
|
-
},
|
|
2001
|
-
let t =
|
|
2010
|
+
}, hn = (e) => {
|
|
2011
|
+
let t = W(e, "mariadb");
|
|
2002
2012
|
if (t !== void 0) return t;
|
|
2003
2013
|
switch (e.type) {
|
|
2004
2014
|
case "id": return "VARCHAR(64)";
|
|
2005
2015
|
case "text": return e.hasDefault && e.defaultValue !== void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : "LONGTEXT";
|
|
2006
2016
|
case "integer": return "INT";
|
|
2007
2017
|
case "real": return "DOUBLE";
|
|
2008
|
-
case "decimal": return
|
|
2018
|
+
case "decimal": return fn(e, "DECIMAL");
|
|
2009
2019
|
case "bigint": return "BIGINT";
|
|
2010
2020
|
case "boolean": return "TINYINT(1)";
|
|
2011
2021
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2019,82 +2029,82 @@ BEGIN
|
|
|
2019
2029
|
case "interval": return "BIGINT";
|
|
2020
2030
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2021
2031
|
}
|
|
2022
|
-
},
|
|
2032
|
+
}, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``, gn = (e, t) => `ALTER TABLE ${t(e.table)} DROP COLUMN IF EXISTS ${t(e.column)};`, _n = (e) => `ALTER TABLE ${K(e.table)} DROP COLUMN IF EXISTS ${K(e.column)}, ALGORITHM=COPY;`, vn = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, yn = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${Wn(t)}`)};`, bn = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${xn(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, xn = (e, t) => {
|
|
2023
2033
|
let n = t(e.defaultValue);
|
|
2024
2034
|
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.`);
|
|
2025
2035
|
return n;
|
|
2026
|
-
},
|
|
2027
|
-
let r =
|
|
2028
|
-
return r ?
|
|
2029
|
-
},
|
|
2036
|
+
}, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Sn = (e, t, n) => {
|
|
2037
|
+
let r = q(e, t, n);
|
|
2038
|
+
return r ? ct(n, r) : void 0;
|
|
2039
|
+
}, Cn = (e, t, n) => {
|
|
2030
2040
|
let r = n ?? e.nullable, i = be(e, "mariadb");
|
|
2031
2041
|
return [
|
|
2032
|
-
|
|
2033
|
-
|
|
2042
|
+
K(t),
|
|
2043
|
+
j(e, "mariadb"),
|
|
2034
2044
|
r ? null : "NOT NULL",
|
|
2035
2045
|
i
|
|
2036
2046
|
].filter(Boolean).join(" ");
|
|
2037
|
-
},
|
|
2047
|
+
}, wn = (e, t) => e == null ? null : Array.isArray(e) ? Tn(e, t, "mariadb") : e === "now" ? "DEFAULT CURRENT_TIMESTAMP(6)" : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "mysql") : null, Tn = (e, t, n) => xe(e, t ?? { type: "json" }, n), En = (e, t) => e == null ? null : Array.isArray(e) ? Tn(e, t, "postgres") : e === "now" ? "DEFAULT now()" : typeof e == "boolean" || typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|::|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "postgres") : null, J = (e, t) => {
|
|
2038
2048
|
if (!e.generatedAs) return null;
|
|
2039
2049
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2040
2050
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2041
|
-
},
|
|
2042
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2043
|
-
let t =
|
|
2044
|
-
if (t) return `${
|
|
2045
|
-
let n = [
|
|
2051
|
+
}, Dn = (e) => {
|
|
2052
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "postgres");
|
|
2053
|
+
let t = J(e, "postgres");
|
|
2054
|
+
if (t) return `${G(e.name)} ${pn(e)} ${t}`;
|
|
2055
|
+
let n = [G(e.name), pn(e)];
|
|
2046
2056
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2047
|
-
let t =
|
|
2057
|
+
let t = En(e.defaultValue, e);
|
|
2048
2058
|
t && n.push(t);
|
|
2049
2059
|
}
|
|
2050
|
-
return e.references && (n.push(`REFERENCES ${
|
|
2060
|
+
return e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
2051
2061
|
cascade: "CASCADE",
|
|
2052
2062
|
restrict: "RESTRICT",
|
|
2053
2063
|
setNull: "SET NULL",
|
|
2054
2064
|
noAction: "NO ACTION"
|
|
2055
2065
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2056
|
-
},
|
|
2057
|
-
let t = e.columns.map((e) => ` ${
|
|
2058
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2066
|
+
}, On = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", kn = (e) => {
|
|
2067
|
+
let t = e.columns.map((e) => ` ${Dn(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${On(e, G)}\n)`];
|
|
2068
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e.table)} (${t.columns.map(Yn).join(", ")})`);
|
|
2059
2069
|
return n;
|
|
2060
|
-
},
|
|
2061
|
-
let t =
|
|
2070
|
+
}, An = 191, jn = (e) => {
|
|
2071
|
+
let t = hn(e).toUpperCase();
|
|
2062
2072
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2063
|
-
},
|
|
2064
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2065
|
-
let t =
|
|
2066
|
-
if (t) return `${
|
|
2067
|
-
let n = [
|
|
2068
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2069
|
-
let t =
|
|
2073
|
+
}, Mn = (e) => {
|
|
2074
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mariadb");
|
|
2075
|
+
let t = J(e, "mariadb");
|
|
2076
|
+
if (t) return `${K(e.name)} ${hn(e)} ${t}`;
|
|
2077
|
+
let n = [K(e.name), hn(e)];
|
|
2078
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !jn(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2079
|
+
let t = wn(e.defaultValue, e);
|
|
2070
2080
|
t && n.push(t);
|
|
2071
2081
|
}
|
|
2072
|
-
return e.references && (n.push(`REFERENCES ${
|
|
2082
|
+
return e.references && (n.push(`REFERENCES ${K(e.references.table)} (${K(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
2073
2083
|
cascade: "CASCADE",
|
|
2074
2084
|
restrict: "RESTRICT",
|
|
2075
2085
|
setNull: "SET NULL",
|
|
2076
2086
|
noAction: "NO ACTION"
|
|
2077
2087
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2078
|
-
},
|
|
2088
|
+
}, Nn = (e) => {
|
|
2079
2089
|
let t = new Map(e.columns.map((e) => [e.name, e])), n = (e) => {
|
|
2080
2090
|
let n = t.get(e);
|
|
2081
|
-
return n &&
|
|
2082
|
-
}, r = e.columns.map((e) => ` ${
|
|
2083
|
-
for (let t of e.columns) t.unique && t.type !== "id" &&
|
|
2084
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && i.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2091
|
+
return n && jn(n) ? `${K(e)}(${An})` : K(e);
|
|
2092
|
+
}, r = e.columns.map((e) => ` ${Mn(e)}`).join(",\n"), i = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${r}${On(e, n)}\n)`];
|
|
2093
|
+
for (let t of e.columns) t.unique && t.type !== "id" && jn(t) && i.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${K(`${e.table}_${t.name}_key`)} ON ${K(e.table)} (${n(t.name)})`);
|
|
2094
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && i.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(t.name)} ON ${K(e.table)} (${t.columns.map(n).join(", ")})`);
|
|
2085
2095
|
return i;
|
|
2086
|
-
},
|
|
2096
|
+
}, Pn = {
|
|
2087
2097
|
cascade: "CASCADE",
|
|
2088
2098
|
restrict: "RESTRICT",
|
|
2089
2099
|
setNull: "SET NULL",
|
|
2090
2100
|
noAction: "NO ACTION"
|
|
2091
|
-
},
|
|
2101
|
+
}, Fn = {
|
|
2092
2102
|
cascade: "CASCADE",
|
|
2093
2103
|
restrict: "NO ACTION",
|
|
2094
2104
|
setNull: "SET NULL",
|
|
2095
2105
|
noAction: "NO ACTION"
|
|
2096
|
-
},
|
|
2097
|
-
let t =
|
|
2106
|
+
}, In = (e) => {
|
|
2107
|
+
let t = W(e, "sqlite");
|
|
2098
2108
|
if (t !== void 0) return t;
|
|
2099
2109
|
switch (e.type) {
|
|
2100
2110
|
case "integer":
|
|
@@ -2105,60 +2115,60 @@ BEGIN
|
|
|
2105
2115
|
case "bytes": return "BLOB";
|
|
2106
2116
|
default: return "TEXT";
|
|
2107
2117
|
}
|
|
2108
|
-
}, Y = (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" ?
|
|
2109
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2110
|
-
let t =
|
|
2111
|
-
if (t) return `${
|
|
2112
|
-
let n = [
|
|
2118
|
+
}, Y = (e, t) => e == null ? null : e === "now" ? `DEFAULT ${t}` : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "sqlite") : null, Ln = (e) => {
|
|
2119
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "sqlite");
|
|
2120
|
+
let t = J(e, "sqlite");
|
|
2121
|
+
if (t) return `${G(e.name)} ${In(e)} ${t}`;
|
|
2122
|
+
let n = [G(e.name), In(e)];
|
|
2113
2123
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2114
2124
|
let t = Y(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2115
2125
|
t && n.push(t);
|
|
2116
2126
|
}
|
|
2117
|
-
if (e.references && (n.push(`REFERENCES ${
|
|
2127
|
+
if (e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Pn[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2118
2128
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2119
|
-
n.push(`CHECK (${
|
|
2129
|
+
n.push(`CHECK (${G(e.name)} IN (${t}))`);
|
|
2120
2130
|
}
|
|
2121
2131
|
return n.join(" ");
|
|
2122
|
-
},
|
|
2123
|
-
let t = e.columns.map((e) => ` ${
|
|
2124
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2132
|
+
}, Rn = (e) => {
|
|
2133
|
+
let t = e.columns.map((e) => ` ${Ln(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${On(e, G)}\n)`];
|
|
2134
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e.table)} (${t.columns.map(G).join(", ")})`);
|
|
2125
2135
|
return n;
|
|
2126
2136
|
}, X = (e, t) => {
|
|
2127
2137
|
let n = t.find((t) => t.tableName === e);
|
|
2128
2138
|
if (!n) return [];
|
|
2129
|
-
let r =
|
|
2130
|
-
...
|
|
2139
|
+
let r = I([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => G(e.name)).join(", "), o = [
|
|
2140
|
+
...Rn({
|
|
2131
2141
|
kind: "create-table",
|
|
2132
2142
|
table: i,
|
|
2133
2143
|
columns: r.columns,
|
|
2134
2144
|
indexes: [],
|
|
2135
2145
|
...r.primaryKey ? { primaryKey: r.primaryKey } : {}
|
|
2136
2146
|
}),
|
|
2137
|
-
`INSERT INTO ${
|
|
2138
|
-
`DROP TABLE ${
|
|
2139
|
-
`ALTER TABLE ${
|
|
2147
|
+
`INSERT INTO ${G(i)} (${a}) SELECT ${a} FROM ${G(e)}`,
|
|
2148
|
+
`DROP TABLE ${G(e)}`,
|
|
2149
|
+
`ALTER TABLE ${G(i)} RENAME TO ${G(e)}`
|
|
2140
2150
|
];
|
|
2141
|
-
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2151
|
+
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e)} (${t.columns.map(G).join(", ")})`);
|
|
2142
2152
|
return o;
|
|
2143
|
-
},
|
|
2153
|
+
}, zn = (e, t, n, r) => {
|
|
2144
2154
|
let i = r ?? e.nullable;
|
|
2145
|
-
return `ALTER TABLE ${Z(n)} ALTER COLUMN ${Z(t)} ${
|
|
2146
|
-
},
|
|
2155
|
+
return `ALTER TABLE ${Z(n)} ALTER COLUMN ${Z(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2156
|
+
}, Bn = (e) => {
|
|
2147
2157
|
let t = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${Z(e.table)} DROP CONSTRAINT [' + @dc + ']');`;
|
|
2148
2158
|
if (!e.hasDefault) return t;
|
|
2149
2159
|
let n = Y(e.defaultValue, "SYSUTCDATETIME()");
|
|
2150
2160
|
if (!n) return t;
|
|
2151
2161
|
let r = n.replace(/^DEFAULT\s+/i, "");
|
|
2152
2162
|
return `${t} ALTER TABLE ${Z(e.table)} ADD DEFAULT ${r} FOR ${Z(e.column)};`;
|
|
2153
|
-
}, Z = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2154
|
-
let t =
|
|
2163
|
+
}, Z = (e) => `[${e.replace(/]/g, "]]")}]`, Vn = (e) => {
|
|
2164
|
+
let t = W(e, "mssql");
|
|
2155
2165
|
if (t !== void 0) return t;
|
|
2156
2166
|
switch (e.type) {
|
|
2157
2167
|
case "id":
|
|
2158
2168
|
case "reference": return "NVARCHAR(64)";
|
|
2159
2169
|
case "integer": return "INT";
|
|
2160
2170
|
case "real": return "FLOAT";
|
|
2161
|
-
case "decimal": return
|
|
2171
|
+
case "decimal": return fn(e, "DECIMAL");
|
|
2162
2172
|
case "bigint": return "BIGINT";
|
|
2163
2173
|
case "boolean": return "BIT";
|
|
2164
2174
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2166,40 +2176,40 @@ BEGIN
|
|
|
2166
2176
|
case "bytes": return "VARBINARY(MAX)";
|
|
2167
2177
|
default: return "NVARCHAR(MAX)";
|
|
2168
2178
|
}
|
|
2169
|
-
},
|
|
2170
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2171
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2179
|
+
}, Hn = (e, t) => {
|
|
2180
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mssql");
|
|
2181
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Vn(e), r = J(e, "mssql");
|
|
2172
2182
|
if (r) return `${Z(e.name)} ${r}`;
|
|
2173
2183
|
let i = [Z(e.name), n];
|
|
2174
2184
|
if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
|
|
2175
2185
|
let t = Y(e.defaultValue, "SYSUTCDATETIME()");
|
|
2176
2186
|
t && i.push(t);
|
|
2177
2187
|
}
|
|
2178
|
-
return e.references && (i.push(`REFERENCES ${Z(e.references.table)} (${Z(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2179
|
-
},
|
|
2180
|
-
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${
|
|
2188
|
+
return e.references && (i.push(`REFERENCES ${Z(e.references.table)} (${Z(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${Fn[e.references.onDelete]}`)), i.join(" ");
|
|
2189
|
+
}, Un = (e) => {
|
|
2190
|
+
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${Hn(e, n)}`).join(",\n"), i = `CREATE TABLE ${Z(e.table)} (\n${r}${On(e, Z)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2181
2191
|
for (let n of e.indexes) {
|
|
2182
2192
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2183
2193
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Z(n.name)} ON ${Z(e.table)} (${n.columns.map(Z).join(", ")})`;
|
|
2184
2194
|
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)}')`);
|
|
2185
2195
|
}
|
|
2186
2196
|
return a;
|
|
2187
|
-
},
|
|
2188
|
-
let r = `${e.table}${
|
|
2197
|
+
}, Wn = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Gn = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Kn = (e, t, n) => {
|
|
2198
|
+
let r = `${e.table}${Wn(t)}`;
|
|
2189
2199
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2190
|
-
},
|
|
2191
|
-
let r =
|
|
2192
|
-
return r ?
|
|
2193
|
-
},
|
|
2200
|
+
}, qn = (e, t, n) => {
|
|
2201
|
+
let r = q(e, t, n);
|
|
2202
|
+
return r ? jn({ type: r.type }) : !1;
|
|
2203
|
+
}, Jn = (e, t, n) => qn(e, t, n) ? `${K(n)}(${An})` : K(n), Yn = (e) => e.startsWith("(") ? e : G(e), Xn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map(Yn).join(", ")});`, Zn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map((n) => Jn(t, e.table, n)).join(", ")});`, Qn = (e) => `DROP INDEX IF EXISTS ${G(e.index)};`, $n = (e) => `DROP INDEX ${K(e.index)} ON ${K(e.table)};`, er = (e) => `DROP INDEX IF EXISTS ${Z(e.index)} ON ${Z(e.table)};`, tr = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, nr = (e) => {
|
|
2194
2204
|
let t = (e) => e.replace(/'/g, "''");
|
|
2195
2205
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2196
|
-
},
|
|
2206
|
+
}, rr = (e) => `ALTER INDEX ${G(e.from)} RENAME TO ${G(e.to)};`, ir = (e) => `ALTER TABLE ${K(e.table)} RENAME INDEX ${K(e.from)} TO ${K(e.to)};`, ar = (e) => {
|
|
2197
2207
|
let t = (e) => e.replace(/'/g, "''");
|
|
2198
2208
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2199
|
-
},
|
|
2209
|
+
}, or = (e) => {
|
|
2200
2210
|
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Z(e.index.name)} ON ${Z(e.table)} (${e.index.columns.map(Z).join(", ")})`;
|
|
2201
2211
|
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)}');`;
|
|
2202
|
-
},
|
|
2212
|
+
}, sr = (e, t, n) => {
|
|
2203
2213
|
let r = n.find((t) => t.tableName === e);
|
|
2204
2214
|
if (!r) return [];
|
|
2205
2215
|
let i = [];
|
|
@@ -2208,13 +2218,13 @@ BEGIN
|
|
|
2208
2218
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Z(e)} ALTER COLUMN ${Z(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2209
2219
|
}
|
|
2210
2220
|
return i;
|
|
2211
|
-
},
|
|
2212
|
-
let t = e.fields.map((e) =>
|
|
2213
|
-
return `ALTER TABLE ${
|
|
2214
|
-
},
|
|
2215
|
-
let n = e.fields.map((n) =>
|
|
2216
|
-
return `ALTER TABLE ${
|
|
2217
|
-
},
|
|
2221
|
+
}, cr = (e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${G(e.column)});`, lr = (e, t) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${Jn(t, e.table, e.column)});`, ur = (e) => {
|
|
2222
|
+
let t = e.fields.map((e) => G(e)).join(", ");
|
|
2223
|
+
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${t});`;
|
|
2224
|
+
}, dr = (e, t) => {
|
|
2225
|
+
let n = e.fields.map((n) => Jn(t, e.table, n)).join(", ");
|
|
2226
|
+
return `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(e.name)} UNIQUE (${n});`;
|
|
2227
|
+
}, fr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(e.name)};`, pr = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(e.name)};`, mr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_key`)};`, hr = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(`${e.table}_${e.column}_key`)};`, gr = (e, t) => {
|
|
2218
2228
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2219
2229
|
if (e.orphanPolicy) {
|
|
2220
2230
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2232,11 +2242,11 @@ BEGIN
|
|
|
2232
2242
|
setNull: "SET NULL",
|
|
2233
2243
|
noAction: "NO ACTION"
|
|
2234
2244
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2235
|
-
},
|
|
2245
|
+
}, _r = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_fkey`)};`, vr = (e) => `ALTER TABLE ${K(e.table)} DROP FOREIGN KEY ${K(`${e.table}_${e.column}_fkey`)};`, yr = (e, t) => {
|
|
2236
2246
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2237
2247
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2238
|
-
},
|
|
2239
|
-
let i = e.column, a = r === "mariadb", o = a ?
|
|
2248
|
+
}, br = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_check`)};`, xr = (e) => `ALTER TABLE ${K(e.table)} DROP CHECK ${K(`${e.table}_${e.column}_check`)};`, Sr = (e, t, n, r) => {
|
|
2249
|
+
let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? Z : G, s = a ? hn(i) : r === "mssql" ? Vn(i) : r === "sqlite" ? In(i) : pn(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? wn(e, i) : r === "mssql" ? Y(e, "SYSUTCDATETIME()") : r === "sqlite" ? Y(e, "CURRENT_TIMESTAMP") : En(e, i), u = J(i, r);
|
|
2240
2250
|
if (u) {
|
|
2241
2251
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2242
2252
|
return {
|
|
@@ -2264,7 +2274,7 @@ BEGIN
|
|
|
2264
2274
|
post: f ? [f] : []
|
|
2265
2275
|
};
|
|
2266
2276
|
return d?.sql && (p.backfillKind = "sql", p.backfillSql = d.sql), d?.js && (p.backfillKind = "js", p.backfillJs = d.js), d?.batchSize !== void 0 && (p.batchSize = d.batchSize), d?.sleepMs !== void 0 && (p.sleepMs = d.sleepMs), p;
|
|
2267
|
-
},
|
|
2277
|
+
}, Cr = (e) => {
|
|
2268
2278
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2269
2279
|
return (e, n) => {
|
|
2270
2280
|
let r = t.get(e);
|
|
@@ -2289,109 +2299,109 @@ BEGIN
|
|
|
2289
2299
|
})), p.mapError((e) => {
|
|
2290
2300
|
let r = b(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2291
2301
|
return Object.assign(e, { message: r });
|
|
2292
|
-
}), p.map(() => void 0)), $ = (e, t, n) => p.forEach(t, (t) => Q(e, t, n), { discard: !0 }),
|
|
2293
|
-
let r = process.hrtime.bigint(), i =
|
|
2302
|
+
}), p.map(() => void 0)), $ = (e, t, n) => p.forEach(t, (t) => Q(e, t, n), { discard: !0 }), wr = (e, t, n) => p.gen(function* () {
|
|
2303
|
+
let r = process.hrtime.bigint(), i = Cr(n.declared), a = t.op;
|
|
2294
2304
|
switch (a.kind) {
|
|
2295
2305
|
case "create-table": {
|
|
2296
2306
|
let t = yield* e.onDialectOrElse({
|
|
2297
|
-
mysql: () => p.succeed(
|
|
2298
|
-
mssql: () => p.succeed(
|
|
2299
|
-
sqlite: () => p.succeed(
|
|
2300
|
-
orElse: () => p.succeed(
|
|
2307
|
+
mysql: () => p.succeed(Nn(a)),
|
|
2308
|
+
mssql: () => p.succeed(Un(a)),
|
|
2309
|
+
sqlite: () => p.succeed(Rn(a)),
|
|
2310
|
+
orElse: () => p.succeed(kn(a))
|
|
2301
2311
|
});
|
|
2302
2312
|
for (let n of t) yield* Q(e, n, a.kind);
|
|
2303
2313
|
break;
|
|
2304
2314
|
}
|
|
2305
2315
|
case "drop-table": {
|
|
2306
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2316
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Kn(a, n, e) : Gn(a, e);
|
|
2307
2317
|
yield* e.onDialectOrElse({
|
|
2308
|
-
mysql: () => Q(e, r(
|
|
2309
|
-
orElse: () => Q(e, r(
|
|
2318
|
+
mysql: () => Q(e, r(K), a.kind),
|
|
2319
|
+
orElse: () => Q(e, r(G), a.kind)
|
|
2310
2320
|
});
|
|
2311
2321
|
break;
|
|
2312
2322
|
}
|
|
2313
2323
|
case "drop-column": {
|
|
2314
2324
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2315
2325
|
yield* e.onDialectOrElse({
|
|
2316
|
-
mysql: () => Q(e, t ?
|
|
2317
|
-
orElse: () => Q(e, t ?
|
|
2326
|
+
mysql: () => Q(e, t ? yn(a, n, K) : _n(a), a.kind),
|
|
2327
|
+
orElse: () => Q(e, t ? yn(a, n, G) : gn(a, G), a.kind)
|
|
2318
2328
|
});
|
|
2319
2329
|
break;
|
|
2320
2330
|
}
|
|
2321
2331
|
case "rename-column":
|
|
2322
2332
|
yield* e.onDialectOrElse({
|
|
2323
|
-
mysql: () => Q(e,
|
|
2333
|
+
mysql: () => Q(e, vn(a, K), a.kind),
|
|
2324
2334
|
mssql: () => Q(e, `EXEC sp_rename N'${a.table.replace(/'/g, "''")}.${a.from.replace(/'/g, "''")}', N'${a.to.replace(/'/g, "''")}', 'COLUMN';`, a.kind),
|
|
2325
|
-
orElse: () => Q(e,
|
|
2335
|
+
orElse: () => Q(e, vn(a, G), a.kind)
|
|
2326
2336
|
});
|
|
2327
2337
|
break;
|
|
2328
2338
|
case "add-index":
|
|
2329
2339
|
yield* e.onDialectOrElse({
|
|
2330
|
-
mysql: () => Q(e,
|
|
2331
|
-
mssql: () => $(e, [...
|
|
2332
|
-
orElse: () => Q(e,
|
|
2340
|
+
mysql: () => Q(e, Zn(a, n.declared), a.kind),
|
|
2341
|
+
mssql: () => $(e, [...sr(a.table, a.index.columns, n.declared), or(a)], a.kind),
|
|
2342
|
+
orElse: () => Q(e, Xn(a, t.classification === "online-required"), a.kind)
|
|
2333
2343
|
});
|
|
2334
2344
|
break;
|
|
2335
2345
|
case "drop-index":
|
|
2336
2346
|
yield* e.onDialectOrElse({
|
|
2337
|
-
mysql: () => Q(e,
|
|
2338
|
-
mssql: () => Q(e,
|
|
2339
|
-
orElse: () => Q(e,
|
|
2347
|
+
mysql: () => Q(e, $n(a), a.kind),
|
|
2348
|
+
mssql: () => Q(e, er(a), a.kind),
|
|
2349
|
+
orElse: () => Q(e, Qn(a), a.kind)
|
|
2340
2350
|
});
|
|
2341
2351
|
break;
|
|
2342
2352
|
case "rename-table":
|
|
2343
2353
|
yield* e.onDialectOrElse({
|
|
2344
|
-
mysql: () => Q(e,
|
|
2345
|
-
mssql: () => Q(e,
|
|
2346
|
-
orElse: () => Q(e,
|
|
2354
|
+
mysql: () => Q(e, tr(a, K), a.kind),
|
|
2355
|
+
mssql: () => Q(e, nr(a), a.kind),
|
|
2356
|
+
orElse: () => Q(e, tr(a, G), a.kind)
|
|
2347
2357
|
});
|
|
2348
2358
|
break;
|
|
2349
2359
|
case "rename-index":
|
|
2350
2360
|
yield* e.onDialectOrElse({
|
|
2351
|
-
mysql: () => Q(e,
|
|
2352
|
-
mssql: () => Q(e,
|
|
2353
|
-
orElse: () => Q(e,
|
|
2361
|
+
mysql: () => Q(e, ir(a), a.kind),
|
|
2362
|
+
mssql: () => Q(e, ar(a), a.kind),
|
|
2363
|
+
orElse: () => Q(e, rr(a), a.kind)
|
|
2354
2364
|
});
|
|
2355
2365
|
break;
|
|
2356
2366
|
case "add-unique":
|
|
2357
2367
|
yield* e.onDialectOrElse({
|
|
2358
|
-
mysql: () => Q(e,
|
|
2368
|
+
mysql: () => Q(e, lr(a, n.declared), a.kind),
|
|
2359
2369
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2360
|
-
mssql: () => $(e, [...
|
|
2361
|
-
orElse: () => Q(e,
|
|
2370
|
+
mssql: () => $(e, [...sr(a.table, [a.column], n.declared), cr(a)], a.kind),
|
|
2371
|
+
orElse: () => Q(e, cr(a), a.kind)
|
|
2362
2372
|
});
|
|
2363
2373
|
break;
|
|
2364
2374
|
case "drop-unique":
|
|
2365
2375
|
yield* e.onDialectOrElse({
|
|
2366
|
-
mysql: () => Q(e,
|
|
2376
|
+
mysql: () => Q(e, hr(a), a.kind),
|
|
2367
2377
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2368
|
-
orElse: () => Q(e,
|
|
2378
|
+
orElse: () => Q(e, mr(a), a.kind)
|
|
2369
2379
|
});
|
|
2370
2380
|
break;
|
|
2371
2381
|
case "add-unique-composite":
|
|
2372
2382
|
yield* e.onDialectOrElse({
|
|
2373
|
-
mysql: () => Q(e,
|
|
2383
|
+
mysql: () => Q(e, dr(a, n.declared), a.kind),
|
|
2374
2384
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2375
|
-
mssql: () => $(e, [...
|
|
2376
|
-
orElse: () => Q(e,
|
|
2385
|
+
mssql: () => $(e, [...sr(a.table, a.fields, n.declared), ur(a)], a.kind),
|
|
2386
|
+
orElse: () => Q(e, ur(a), a.kind)
|
|
2377
2387
|
});
|
|
2378
2388
|
break;
|
|
2379
2389
|
case "drop-unique-composite":
|
|
2380
2390
|
yield* e.onDialectOrElse({
|
|
2381
|
-
mysql: () => Q(e,
|
|
2391
|
+
mysql: () => Q(e, pr(a), a.kind),
|
|
2382
2392
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2383
|
-
orElse: () => Q(e,
|
|
2393
|
+
orElse: () => Q(e, fr(a), a.kind)
|
|
2384
2394
|
});
|
|
2385
2395
|
break;
|
|
2386
2396
|
case "add-foreign-key":
|
|
2387
2397
|
yield* e.onDialectOrElse({
|
|
2388
|
-
mysql: () => $(e,
|
|
2398
|
+
mysql: () => $(e, gr(a, K), a.kind),
|
|
2389
2399
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2390
|
-
orElse: () => $(e,
|
|
2400
|
+
orElse: () => $(e, gr(a, G), a.kind)
|
|
2391
2401
|
});
|
|
2392
2402
|
break;
|
|
2393
2403
|
case "add-column": {
|
|
2394
|
-
let n =
|
|
2404
|
+
let n = Sr(a, t, i, yield* e.onDialectOrElse({
|
|
2395
2405
|
mysql: () => p.succeed("mariadb"),
|
|
2396
2406
|
mssql: () => p.succeed("mssql"),
|
|
2397
2407
|
sqlite: () => p.succeed("sqlite"),
|
|
@@ -2436,41 +2446,41 @@ BEGIN
|
|
|
2436
2446
|
case "alter-column-nullability":
|
|
2437
2447
|
yield* e.onDialectOrElse({
|
|
2438
2448
|
mysql: () => {
|
|
2439
|
-
let t =
|
|
2440
|
-
return t ? Q(e, `ALTER TABLE ${
|
|
2449
|
+
let t = q(n.declared, a.table, a.column);
|
|
2450
|
+
return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${Cn(t, a.column, a.toNullable)};`, a.kind) : p.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${a.table}.${a.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2441
2451
|
},
|
|
2442
2452
|
mssql: () => {
|
|
2443
|
-
let t =
|
|
2444
|
-
return t ? Q(e,
|
|
2453
|
+
let t = q(n.declared, a.table, a.column);
|
|
2454
|
+
return t ? Q(e, zn(t, a.column, a.table, a.toNullable), a.kind) : p.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${a.table}.${a.column}'.`));
|
|
2445
2455
|
},
|
|
2446
2456
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2447
|
-
orElse: () => Q(e, `ALTER TABLE ${
|
|
2457
|
+
orElse: () => Q(e, `ALTER TABLE ${G(a.table)} ALTER COLUMN ${G(a.column)} ${a.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, a.kind)
|
|
2448
2458
|
});
|
|
2449
2459
|
break;
|
|
2450
2460
|
case "alter-column-default": {
|
|
2451
|
-
let t =
|
|
2461
|
+
let t = Sn(n.declared, a.table, a.column);
|
|
2452
2462
|
yield* e.onDialectOrElse({
|
|
2453
|
-
mysql: () => Q(e,
|
|
2454
|
-
mssql: () => Q(e,
|
|
2463
|
+
mysql: () => Q(e, bn(a, K, (e) => wn(e, t)), a.kind),
|
|
2464
|
+
mssql: () => Q(e, Bn(a), a.kind),
|
|
2455
2465
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2456
|
-
orElse: () => Q(e,
|
|
2466
|
+
orElse: () => Q(e, bn(a, G, (e) => En(e, t)), a.kind)
|
|
2457
2467
|
});
|
|
2458
2468
|
break;
|
|
2459
2469
|
}
|
|
2460
2470
|
case "alter-column-type": {
|
|
2461
|
-
let r =
|
|
2471
|
+
let r = pn(Sn(n.declared, a.table, a.column) ?? { type: a.to }), i = a.using ? ` USING ${a.using}` : "";
|
|
2462
2472
|
if (t.classification !== "online-required") {
|
|
2463
2473
|
yield* e.onDialectOrElse({
|
|
2464
2474
|
mysql: () => {
|
|
2465
|
-
let t =
|
|
2466
|
-
return t ? Q(e, `ALTER TABLE ${
|
|
2475
|
+
let t = q(n.declared, a.table, a.column);
|
|
2476
|
+
return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${Cn(t, a.column)};`, a.kind) : p.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${a.table}.${a.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2467
2477
|
},
|
|
2468
2478
|
mssql: () => {
|
|
2469
|
-
let t =
|
|
2470
|
-
return t ? Q(e,
|
|
2479
|
+
let t = q(n.declared, a.table, a.column);
|
|
2480
|
+
return t ? Q(e, zn(t, a.column, a.table), a.kind) : p.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${a.table}.${a.column}'.`));
|
|
2471
2481
|
},
|
|
2472
2482
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2473
|
-
orElse: () => Q(e, `ALTER TABLE ${
|
|
2483
|
+
orElse: () => Q(e, `ALTER TABLE ${G(a.table)} ALTER COLUMN ${G(a.column)} TYPE ${r}${i};`, a.kind)
|
|
2474
2484
|
});
|
|
2475
2485
|
break;
|
|
2476
2486
|
}
|
|
@@ -2479,35 +2489,35 @@ BEGIN
|
|
|
2479
2489
|
orElse: () => p.void
|
|
2480
2490
|
});
|
|
2481
2491
|
let o = `${a.column}__shadow`, s = `${a.column}__old`;
|
|
2482
|
-
yield* e.unsafe(`ALTER TABLE ${
|
|
2483
|
-
let c = a.using ??
|
|
2492
|
+
yield* e.unsafe(`ALTER TABLE ${G(a.table)} ADD COLUMN ${G(o)} ${r}`);
|
|
2493
|
+
let c = a.using ?? G(a.column), l;
|
|
2484
2494
|
for (;;) {
|
|
2485
2495
|
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(a.table)} WHERE ${e(o)} IS NULL ORDER BY ${e("id")} LIMIT 5000` : yield* e`SELECT ${e("id")} FROM ${e(a.table)} WHERE ${e(o)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} LIMIT 5000`;
|
|
2486
2496
|
if (t.length === 0) break;
|
|
2487
|
-
yield* e.unsafe(`UPDATE ${
|
|
2497
|
+
yield* e.unsafe(`UPDATE ${G(a.table)} SET ${G(o)} = ${c} WHERE ${G(a.column)} IS NOT NULL AND ${G(o)} IS NULL AND ${G("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
2488
2498
|
}
|
|
2489
|
-
yield* p.logInfo(`alter-column-type shadow ${a.table}.${a.column}: shadow populated`).pipe(p.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${
|
|
2499
|
+
yield* p.logInfo(`alter-column-type shadow ${a.table}.${a.column}: shadow populated`).pipe(p.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${G(a.table)} RENAME COLUMN ${G(a.column)} TO ${G(s)}`), yield* e.unsafe(`ALTER TABLE ${G(a.table)} RENAME COLUMN ${G(o)} TO ${G(a.column)}`), yield* e.unsafe(`ALTER TABLE ${G(a.table)} DROP COLUMN ${G(s)}`);
|
|
2490
2500
|
break;
|
|
2491
2501
|
}
|
|
2492
2502
|
case "drop-foreign-key":
|
|
2493
2503
|
yield* e.onDialectOrElse({
|
|
2494
|
-
mysql: () => Q(e,
|
|
2504
|
+
mysql: () => Q(e, vr(a), a.kind),
|
|
2495
2505
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2496
|
-
orElse: () => Q(e,
|
|
2506
|
+
orElse: () => Q(e, _r(a), a.kind)
|
|
2497
2507
|
});
|
|
2498
2508
|
break;
|
|
2499
2509
|
case "add-check":
|
|
2500
2510
|
yield* e.onDialectOrElse({
|
|
2501
|
-
mysql: () => Q(e,
|
|
2511
|
+
mysql: () => Q(e, yr(a, K), a.kind),
|
|
2502
2512
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2503
|
-
orElse: () => Q(e,
|
|
2513
|
+
orElse: () => Q(e, yr(a, G), a.kind)
|
|
2504
2514
|
});
|
|
2505
2515
|
break;
|
|
2506
2516
|
case "drop-check":
|
|
2507
2517
|
yield* e.onDialectOrElse({
|
|
2508
|
-
mysql: () => Q(e,
|
|
2518
|
+
mysql: () => Q(e, xr(a), a.kind),
|
|
2509
2519
|
sqlite: () => $(e, X(a.table, n.declared), a.kind),
|
|
2510
|
-
orElse: () => Q(e,
|
|
2520
|
+
orElse: () => Q(e, br(a), a.kind)
|
|
2511
2521
|
});
|
|
2512
2522
|
break;
|
|
2513
2523
|
}
|
|
@@ -2516,10 +2526,10 @@ BEGIN
|
|
|
2516
2526
|
status: "applied",
|
|
2517
2527
|
durationMs: Number((process.hrtime.bigint() - r) / 1000000n)
|
|
2518
2528
|
};
|
|
2519
|
-
}),
|
|
2529
|
+
}), Tr = (e, t, n) => p.gen(function* () {
|
|
2520
2530
|
let r = t.operations.filter((e) => e.blocked);
|
|
2521
2531
|
if (r.length > 0) return yield* p.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
2522
|
-
yield*
|
|
2532
|
+
yield* T(e);
|
|
2523
2533
|
let i = Date.now(), a = [];
|
|
2524
2534
|
try {
|
|
2525
2535
|
let r = yield* e.onDialectOrElse({
|
|
@@ -2529,21 +2539,18 @@ BEGIN
|
|
|
2529
2539
|
}), i = r ? t.operations.filter((e) => e.classification !== "online-required") : [], o = r ? t.operations.filter((e) => e.classification === "online-required") : t.operations;
|
|
2530
2540
|
i.length > 0 && (yield* e.withTransaction(p.gen(function* () {
|
|
2531
2541
|
let e = yield* h.SqlClient;
|
|
2532
|
-
for (let t of i) a.push(yield*
|
|
2542
|
+
for (let t of i) a.push(yield* wr(e, t, n));
|
|
2533
2543
|
})));
|
|
2534
|
-
for (let t of o) a.push(yield*
|
|
2544
|
+
for (let t of o) a.push(yield* wr(e, t, n));
|
|
2535
2545
|
} finally {
|
|
2536
|
-
yield*
|
|
2546
|
+
yield* E(e).pipe(p.orDie);
|
|
2537
2547
|
}
|
|
2538
2548
|
let o = yield* n.replan(e);
|
|
2539
2549
|
if (o.operations.length > 0) {
|
|
2540
2550
|
let e = o.operations.slice(0, 10).map((e) => ` - ${e.op.kind} ${"table" in e.op ? e.op.table : ""}${"column" in e.op ? `.${String(e.op.column)}` : ""}`).join("\n");
|
|
2541
2551
|
return yield* p.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${t.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${o.operations.length}:\n${e}${o.operations.length > 10 ? `\n … and ${o.operations.length - 10} more` : ""}\nNo fingerprint was recorded — recording one would make the next boot report "schema up to date" for a schema that was never applied. This is a framework bug; the schema is unchanged and safe.\nTwo causes look identical from here, so read the list before assuming either:\n - the DDL for those operations is a no-op (it succeeded and changed nothing), or\n - the planner cannot see what the DDL did, so it proposes the same work again — which is what an\n operation naming an object a PREVIOUS operation created or renamed usually means.\nReport the operation kinds above with the column types involved.`));
|
|
2542
2552
|
}
|
|
2543
|
-
let s = a.filter((e) => e.status === "applied").length, c = Date.now() - i, l = `plan_${Date.now().toString(36)}`, u = (/* @__PURE__ */ new Date()).toISOString(), d = yield* e
|
|
2544
|
-
mysql: () => p.succeed(u.replace("T", " ").replace("Z", "")),
|
|
2545
|
-
orElse: () => p.succeed(u)
|
|
2546
|
-
});
|
|
2553
|
+
let s = a.filter((e) => e.status === "applied").length, c = Date.now() - i, l = `plan_${Date.now().toString(36)}`, u = (/* @__PURE__ */ new Date()).toISOString(), d = yield* dn(e, u);
|
|
2547
2554
|
return yield* e`
|
|
2548
2555
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2549
2556
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -2565,19 +2572,19 @@ BEGIN
|
|
|
2565
2572
|
source: n.source,
|
|
2566
2573
|
...n.notes ? { notes: n.notes } : {}
|
|
2567
2574
|
};
|
|
2568
|
-
}),
|
|
2575
|
+
}), Er = (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"), Dr = (e) => e`
|
|
2569
2576
|
SELECT fingerprint
|
|
2570
2577
|
FROM _voltro_migration_plans
|
|
2571
2578
|
ORDER BY ${e("appliedAt")} DESC
|
|
2572
2579
|
LIMIT 1
|
|
2573
|
-
`.pipe(p.map((e) => e.length > 0 ? e[0].fingerprint : void 0), p.catchAll(() => p.succeed(void 0))),
|
|
2580
|
+
`.pipe(p.map((e) => e.length > 0 ? e[0].fingerprint : void 0), p.catchAll(() => p.succeed(void 0))), Or = (e) => e.onDialectOrElse({
|
|
2574
2581
|
pg: () => "postgres",
|
|
2575
2582
|
mysql: () => "mysql",
|
|
2576
2583
|
mssql: () => "mssql",
|
|
2577
2584
|
sqlite: () => "sqlite",
|
|
2578
2585
|
orElse: () => "sqlite"
|
|
2579
|
-
}),
|
|
2580
|
-
let n =
|
|
2586
|
+
}), kr = (e, t) => p.gen(function* () {
|
|
2587
|
+
let n = P(I(t, Or(e))), r = yield* Dr(e);
|
|
2581
2588
|
return r === n ? {
|
|
2582
2589
|
kind: "up-to-date",
|
|
2583
2590
|
fingerprint: n
|
|
@@ -2586,23 +2593,23 @@ BEGIN
|
|
|
2586
2593
|
expected: n,
|
|
2587
2594
|
...r === void 0 ? {} : { actual: r }
|
|
2588
2595
|
};
|
|
2589
|
-
}),
|
|
2596
|
+
}), Ar = [
|
|
2590
2597
|
"pgeagertest_",
|
|
2591
2598
|
"mig_e2e_",
|
|
2592
2599
|
"mig_test_",
|
|
2593
2600
|
"mysqleagertest_",
|
|
2594
2601
|
"mssqleagertest_",
|
|
2595
2602
|
"sqliteeagertest_"
|
|
2596
|
-
],
|
|
2603
|
+
], jr = (e) => Ar.some((t) => e.startsWith(t)), Mr = (e, t) => p.gen(function* () {
|
|
2597
2604
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
2598
|
-
let n = t.filter((e) =>
|
|
2605
|
+
let n = t.filter((e) => jr(e.name)).map((e) => e.name);
|
|
2599
2606
|
if (n.length === 0) return [];
|
|
2600
2607
|
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(p.catchAll(() => p.void));
|
|
2601
2608
|
return n;
|
|
2602
|
-
}),
|
|
2609
|
+
}), Nr = () => {
|
|
2603
2610
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
2604
2611
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
2605
|
-
},
|
|
2612
|
+
}, Pr = (e) => {
|
|
2606
2613
|
if (e === void 0) return;
|
|
2607
2614
|
let t = e.trim();
|
|
2608
2615
|
if (t === "") return;
|
|
@@ -2612,43 +2619,43 @@ BEGIN
|
|
|
2612
2619
|
kind: "tables",
|
|
2613
2620
|
tables: new Set(n)
|
|
2614
2621
|
} : void 0;
|
|
2615
|
-
},
|
|
2622
|
+
}, Fr = (e) => typeof e.table == "string" ? e.table : void 0, Ir = (e, t = { kind: "all" }) => ({
|
|
2616
2623
|
...e,
|
|
2617
2624
|
operations: e.operations.map((e) => {
|
|
2618
2625
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
2619
2626
|
if (t?.kind === "tables") {
|
|
2620
|
-
let n =
|
|
2627
|
+
let n = Fr(e.op);
|
|
2621
2628
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
2622
2629
|
}
|
|
2623
2630
|
let { blocked: n, ...r } = e;
|
|
2624
2631
|
return r;
|
|
2625
2632
|
})
|
|
2626
|
-
}),
|
|
2627
|
-
let t =
|
|
2633
|
+
}), Lr = (e, t, n) => t === "postgres" ? ft(e, n).pipe(p.flatMap((e) => {
|
|
2634
|
+
let t = pt(e);
|
|
2628
2635
|
return t === void 0 ? p.void : p.logWarning(`auto-migrate: ${t}`).pipe(p.annotateLogs({ scope: "voltro:migrate" }));
|
|
2629
|
-
}), p.catchAll(() => p.void)) : p.void,
|
|
2630
|
-
let r =
|
|
2636
|
+
}), p.catchAll(() => p.void)) : p.void, Rr = (e, t, n) => p.gen(function* () {
|
|
2637
|
+
let r = Or(e), i = t;
|
|
2631
2638
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
2632
|
-
let t =
|
|
2633
|
-
if ((yield*
|
|
2639
|
+
let t = P(I(i, r));
|
|
2640
|
+
if ((yield* Dr(e)) === t) return yield* Lr(e, r, i), {
|
|
2634
2641
|
kind: "up-to-date",
|
|
2635
2642
|
fingerprint: t
|
|
2636
2643
|
};
|
|
2637
2644
|
}
|
|
2638
|
-
let a = yield* U(e), o = yield*
|
|
2645
|
+
let a = yield* U(e), o = yield* Mr(e, a.tables);
|
|
2639
2646
|
o.length > 0 && (yield* p.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(p.annotateLogs({
|
|
2640
2647
|
scope: "voltro:migrate",
|
|
2641
2648
|
count: o.length
|
|
2642
2649
|
})), a = yield* U(e));
|
|
2643
|
-
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !s(e.name) || c.has(e.name)), u =
|
|
2650
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !s(e.name) || c.has(e.name)), u = Kt({
|
|
2644
2651
|
declared: i,
|
|
2645
2652
|
live: { tables: l(a.tables) },
|
|
2646
2653
|
dialect: r,
|
|
2647
|
-
...
|
|
2654
|
+
...Nr()
|
|
2648
2655
|
});
|
|
2649
2656
|
if (u.summary.blocked > 0) {
|
|
2650
|
-
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
2651
|
-
if (t === void 0 || !e || (u =
|
|
2657
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Pr(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
2658
|
+
if (t === void 0 || !e || (u = Ir(u, t), u.operations.some((e) => e.blocked))) return {
|
|
2652
2659
|
kind: "refused-blocked",
|
|
2653
2660
|
plan: u
|
|
2654
2661
|
};
|
|
@@ -2658,37 +2665,37 @@ BEGIN
|
|
|
2658
2665
|
fingerprint: u.toFingerprint
|
|
2659
2666
|
} : {
|
|
2660
2667
|
kind: "applied",
|
|
2661
|
-
applied: yield*
|
|
2668
|
+
applied: yield* Tr(e, u, {
|
|
2662
2669
|
declared: t,
|
|
2663
2670
|
appliedBy: n.appliedBy,
|
|
2664
2671
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
2665
2672
|
source: "auto-diff",
|
|
2666
2673
|
replan: (e) => p.gen(function* () {
|
|
2667
2674
|
let t = yield* U(e);
|
|
2668
|
-
return
|
|
2675
|
+
return Kt({
|
|
2669
2676
|
declared: i,
|
|
2670
2677
|
live: { tables: l(t.tables) },
|
|
2671
2678
|
dialect: r,
|
|
2672
|
-
...
|
|
2679
|
+
...Nr()
|
|
2673
2680
|
});
|
|
2674
2681
|
})
|
|
2675
2682
|
}),
|
|
2676
2683
|
plan: u
|
|
2677
2684
|
};
|
|
2678
|
-
}),
|
|
2685
|
+
}), zr = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? p.succeed({
|
|
2679
2686
|
kind: "skipped",
|
|
2680
2687
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
2681
|
-
}) : n.environment === "prod" ?
|
|
2688
|
+
}) : n.environment === "prod" ? kr(e, t) : Rr(e, t, n), Br = (e, t) => {
|
|
2682
2689
|
switch (e.kind) {
|
|
2683
2690
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
2684
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
2691
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${F(e.fingerprint)})`;
|
|
2685
2692
|
case "applied": {
|
|
2686
2693
|
let t = e.plan.summary;
|
|
2687
|
-
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${
|
|
2694
|
+
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${F(e.applied.fingerprint)}`;
|
|
2688
2695
|
}
|
|
2689
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
2696
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${F(e.expected)}` + (e.actual ? ` live=${F(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
2690
2697
|
case "refused-blocked": {
|
|
2691
|
-
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` +
|
|
2698
|
+
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` + Er(e.plan), c = [""];
|
|
2692
2699
|
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) {
|
|
2693
2700
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2694
2701
|
for (let r of e.plan.operations) {
|
|
@@ -2705,7 +2712,7 @@ BEGIN
|
|
|
2705
2712
|
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");
|
|
2706
2713
|
}
|
|
2707
2714
|
}
|
|
2708
|
-
},
|
|
2715
|
+
}, Vr = /* @__PURE__ */ new Set([
|
|
2709
2716
|
"node_modules",
|
|
2710
2717
|
"dist",
|
|
2711
2718
|
"build",
|
|
@@ -2714,11 +2721,11 @@ BEGIN
|
|
|
2714
2721
|
".next",
|
|
2715
2722
|
".git",
|
|
2716
2723
|
".framework"
|
|
2717
|
-
]),
|
|
2724
|
+
]), Hr = async (e) => {
|
|
2718
2725
|
let t = [], n = async (e) => {
|
|
2719
2726
|
let r = await _.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
2720
2727
|
for (let i of r) {
|
|
2721
|
-
if (
|
|
2728
|
+
if (Vr.has(i.name)) continue;
|
|
2722
2729
|
let r = v(e, i.name);
|
|
2723
2730
|
i.isDirectory() ? await n(r) : i.isFile() && o.test(i.name) && t.push(r);
|
|
2724
2731
|
}
|
|
@@ -2727,7 +2734,7 @@ BEGIN
|
|
|
2727
2734
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
2728
2735
|
return n.localeCompare(r);
|
|
2729
2736
|
});
|
|
2730
|
-
},
|
|
2737
|
+
}, Ur = async (e) => {
|
|
2731
2738
|
let t = [];
|
|
2732
2739
|
for (let r of e) {
|
|
2733
2740
|
let e = (await import(y(r).href)).default;
|
|
@@ -2741,11 +2748,19 @@ BEGIN
|
|
|
2741
2748
|
});
|
|
2742
2749
|
}
|
|
2743
2750
|
return t;
|
|
2744
|
-
},
|
|
2751
|
+
}, Wr = (e) => e`
|
|
2745
2752
|
SELECT ${e("id")}
|
|
2746
2753
|
FROM ${e("_voltro_migration_plans")}
|
|
2747
2754
|
WHERE ${e("source")} = 'file'
|
|
2748
|
-
`.pipe(p.map((e) => e.map((e) => e.id)), p.catchAll(() => p.succeed([]))),
|
|
2755
|
+
`.pipe(p.map((e) => e.map((e) => e.id)), p.catchAll(() => p.succeed([]))), Gr = class extends Error {
|
|
2756
|
+
migrationId;
|
|
2757
|
+
file;
|
|
2758
|
+
cause;
|
|
2759
|
+
_tag = "FileMigrationLedgerError";
|
|
2760
|
+
constructor(e, t, n) {
|
|
2761
|
+
super(`migration ${e}: up() SUCCEEDED but the ledger row could not be written.\n The change IS in the database. It is NOT recorded, so the next run would apply it AGAIN.\n Do not re-run ${t} until this is resolved.\n Cause: ${n instanceof Error ? n.message : String(n)}`), this.migrationId = e, this.file = t, this.cause = n, this.name = "FileMigrationLedgerError";
|
|
2762
|
+
}
|
|
2763
|
+
}, Kr = (e, t, n, r) => p.gen(function* () {
|
|
2749
2764
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
2750
2765
|
sql: e,
|
|
2751
2766
|
log: {
|
|
@@ -2765,7 +2780,9 @@ BEGIN
|
|
|
2765
2780
|
catch: (e) => e
|
|
2766
2781
|
});
|
|
2767
2782
|
let c = Date.now() - i;
|
|
2768
|
-
|
|
2783
|
+
!p.isEffect(s) && c < 2 && (yield* p.logWarning(`migration ${t.migration.id}: up() resolved in ${c}ms — did the body \`await\` an \`@effect/sql\` Effect by accident? \`sql.unsafe(...)\` returns an Effect, not a Promise; \`await\` on it is a silent no-op. Switch the body to \`Effect.gen(function* () { yield* sql.unsafe(...) })\` form.`).pipe(p.annotateLogs({ scope: `migrations:file:${t.migration.id}` })));
|
|
2784
|
+
let l = yield* dn(e, a);
|
|
2785
|
+
return yield* e`
|
|
2769
2786
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2770
2787
|
(${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
2771
2788
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
@@ -2776,11 +2793,11 @@ BEGIN
|
|
|
2776
2793
|
file: t.file
|
|
2777
2794
|
}])},
|
|
2778
2795
|
${r}, ${n}, ${"file"},
|
|
2779
|
-
${c}, ${
|
|
2780
|
-
|
|
2781
|
-
}),
|
|
2796
|
+
${c}, ${l}, ${t.migration.description})
|
|
2797
|
+
`.pipe(p.mapError((e) => new Gr(t.migration.id, t.file, e))), { durationMs: c };
|
|
2798
|
+
}), qr = (e, t) => p.gen(function* () {
|
|
2782
2799
|
let n = yield* p.tryPromise({
|
|
2783
|
-
try: () =>
|
|
2800
|
+
try: () => Hr(v(t, "migrations")),
|
|
2784
2801
|
catch: (e) => e
|
|
2785
2802
|
});
|
|
2786
2803
|
if (n.length === 0) return {
|
|
@@ -2788,25 +2805,25 @@ BEGIN
|
|
|
2788
2805
|
skipped: []
|
|
2789
2806
|
};
|
|
2790
2807
|
let r = yield* p.tryPromise({
|
|
2791
|
-
try: () =>
|
|
2808
|
+
try: () => Ur(n),
|
|
2792
2809
|
catch: (e) => e
|
|
2793
2810
|
});
|
|
2794
2811
|
if (r.length === 0) return {
|
|
2795
2812
|
pending: [],
|
|
2796
2813
|
skipped: []
|
|
2797
2814
|
};
|
|
2798
|
-
let i = new Set(yield*
|
|
2815
|
+
let i = new Set(yield* Wr(e));
|
|
2799
2816
|
return {
|
|
2800
2817
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
2801
2818
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
2802
2819
|
};
|
|
2803
|
-
}),
|
|
2804
|
-
let { pending: n, skipped: r } = yield*
|
|
2820
|
+
}), Jr = (e, t) => qr(e, t).pipe(p.map((e) => e.pending.map((e) => e.migration.id))), Yr = (e, t) => p.gen(function* () {
|
|
2821
|
+
let { pending: n, skipped: r } = yield* qr(e, t.projectRoot);
|
|
2805
2822
|
if (n.length === 0) return {
|
|
2806
2823
|
applied: [],
|
|
2807
2824
|
skipped: r
|
|
2808
2825
|
};
|
|
2809
|
-
yield*
|
|
2826
|
+
yield* T(e);
|
|
2810
2827
|
let i = [];
|
|
2811
2828
|
try {
|
|
2812
2829
|
for (let r of n) {
|
|
@@ -2815,7 +2832,7 @@ BEGIN
|
|
|
2815
2832
|
id: r.migration.id,
|
|
2816
2833
|
file: r.file
|
|
2817
2834
|
}));
|
|
2818
|
-
let { durationMs: n } = yield*
|
|
2835
|
+
let { durationMs: n } = yield* Kr(e, r, t.env, t.appliedBy);
|
|
2819
2836
|
i.push({
|
|
2820
2837
|
id: r.migration.id,
|
|
2821
2838
|
durationMs: n
|
|
@@ -2826,28 +2843,28 @@ BEGIN
|
|
|
2826
2843
|
}));
|
|
2827
2844
|
}
|
|
2828
2845
|
} finally {
|
|
2829
|
-
yield*
|
|
2846
|
+
yield* E(e).pipe(p.orDie);
|
|
2830
2847
|
}
|
|
2831
2848
|
return {
|
|
2832
2849
|
applied: i,
|
|
2833
2850
|
skipped: r
|
|
2834
2851
|
};
|
|
2835
|
-
}),
|
|
2852
|
+
}), Xr = (e, t) => e`
|
|
2836
2853
|
SELECT ${e("id")}
|
|
2837
2854
|
FROM ${e("_voltro_migration_plans")}
|
|
2838
2855
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
2839
2856
|
LIMIT 1
|
|
2840
|
-
`,
|
|
2841
|
-
if (!(yield*
|
|
2857
|
+
`, Zr = (e, t) => p.gen(function* () {
|
|
2858
|
+
if (!(yield* Xr(e, t.id))[0]) return yield* p.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
2842
2859
|
let n = yield* p.tryPromise({
|
|
2843
|
-
try: () =>
|
|
2860
|
+
try: () => Hr(v(t.projectRoot, "migrations")),
|
|
2844
2861
|
catch: (e) => e
|
|
2845
2862
|
}), r = (yield* p.tryPromise({
|
|
2846
|
-
try: () =>
|
|
2863
|
+
try: () => Ur(n),
|
|
2847
2864
|
catch: (e) => e
|
|
2848
2865
|
})).find((e) => e.migration.id === t.id);
|
|
2849
2866
|
if (!r) return yield* p.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
2850
|
-
yield*
|
|
2867
|
+
yield* T(e);
|
|
2851
2868
|
let i = Date.now();
|
|
2852
2869
|
try {
|
|
2853
2870
|
let n = {
|
|
@@ -2874,9 +2891,9 @@ BEGIN
|
|
|
2874
2891
|
durationMs: o
|
|
2875
2892
|
};
|
|
2876
2893
|
} finally {
|
|
2877
|
-
yield*
|
|
2894
|
+
yield* E(e).pipe(p.orDie);
|
|
2878
2895
|
}
|
|
2879
|
-
}),
|
|
2896
|
+
}), Qr = (e) => p.gen(function* () {
|
|
2880
2897
|
let t = yield* h.SqlClient, n = yield* t`
|
|
2881
2898
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
2882
2899
|
WHERE source = 'auto-diff'
|
|
@@ -2921,10 +2938,96 @@ BEGIN
|
|
|
2921
2938
|
snapshotFingerprint: e.fingerprint,
|
|
2922
2939
|
snapshotId: i
|
|
2923
2940
|
};
|
|
2924
|
-
}),
|
|
2941
|
+
}), $r = { safe: !0 }, ei = (e) => {
|
|
2942
|
+
switch (e.kind) {
|
|
2943
|
+
case "drop-column": return {
|
|
2944
|
+
safe: !1,
|
|
2945
|
+
reason: `old instances still SELECT/INSERT "${e.table}"."${e.column}"; after the drop those queries error mid-rollout`,
|
|
2946
|
+
remedy: "stop reading the column in code and deploy that first; drop it in a LATER deploy (expand/contract)"
|
|
2947
|
+
};
|
|
2948
|
+
case "drop-table": return {
|
|
2949
|
+
safe: !1,
|
|
2950
|
+
reason: `old instances still query table "${e.table}"; after the drop every such query errors mid-rollout`,
|
|
2951
|
+
remedy: `remove all code that touches "${e.table}" and deploy that first; drop the table in a LATER deploy`
|
|
2952
|
+
};
|
|
2953
|
+
case "rename-column": return {
|
|
2954
|
+
safe: !1,
|
|
2955
|
+
reason: `old instances reference "${e.table}"."${e.from}", which no longer exists after the rename`,
|
|
2956
|
+
remedy: `add "${e.to}" alongside "${e.from}" + backfill + dual-write, cut code over, then drop "${e.from}" in a LATER deploy`
|
|
2957
|
+
};
|
|
2958
|
+
case "rename-table": return {
|
|
2959
|
+
safe: !1,
|
|
2960
|
+
reason: `old instances query table "${e.from}", which no longer exists after the rename`,
|
|
2961
|
+
remedy: `create "${e.to}" as a copy + dual-write, cut code over, then drop "${e.from}" in a LATER deploy`
|
|
2962
|
+
};
|
|
2963
|
+
case "alter-column-type": return {
|
|
2964
|
+
safe: !1,
|
|
2965
|
+
reason: `old instances read/write "${e.table}"."${e.column}" as ${e.from}; the new ${e.to} type can reject their writes or fail to decode their reads`,
|
|
2966
|
+
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
2967
|
+
};
|
|
2968
|
+
case "alter-column-nullability": return e.toNullable ? $r : {
|
|
2969
|
+
safe: !1,
|
|
2970
|
+
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
2971
|
+
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)`
|
|
2972
|
+
};
|
|
2973
|
+
case "add-unique":
|
|
2974
|
+
case "add-unique-composite": return {
|
|
2975
|
+
safe: !1,
|
|
2976
|
+
reason: `old instances still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
|
|
2977
|
+
remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
|
|
2978
|
+
};
|
|
2979
|
+
case "add-check": return {
|
|
2980
|
+
safe: !1,
|
|
2981
|
+
reason: `old instances may write values to "${e.table}" the new CHECK rejects`,
|
|
2982
|
+
remedy: "make code satisfy the constraint first and deploy that; add the CHECK in a LATER deploy"
|
|
2983
|
+
};
|
|
2984
|
+
case "add-foreign-key": return {
|
|
2985
|
+
safe: !1,
|
|
2986
|
+
reason: `old instances may write "${e.table}"."${e.column}" values with no matching parent row, which the new FK rejects`,
|
|
2987
|
+
remedy: "make code guarantee the referent first and deploy that; add the FK in a LATER deploy"
|
|
2988
|
+
};
|
|
2989
|
+
case "create-table":
|
|
2990
|
+
case "add-column":
|
|
2991
|
+
case "add-index":
|
|
2992
|
+
case "drop-index":
|
|
2993
|
+
case "rename-index":
|
|
2994
|
+
case "alter-column-default":
|
|
2995
|
+
case "drop-unique":
|
|
2996
|
+
case "drop-unique-composite":
|
|
2997
|
+
case "drop-foreign-key":
|
|
2998
|
+
case "drop-check": return $r;
|
|
2999
|
+
}
|
|
3000
|
+
}, ti = (e) => {
|
|
3001
|
+
let t = [];
|
|
3002
|
+
for (let n of e) {
|
|
3003
|
+
let e = ei(n.op);
|
|
3004
|
+
e.safe || t.push({
|
|
3005
|
+
op: n,
|
|
3006
|
+
reason: e.reason,
|
|
3007
|
+
remedy: e.remedy
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
return t;
|
|
3011
|
+
}, ni = (e) => {
|
|
3012
|
+
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3013
|
+
refuse: !1,
|
|
3014
|
+
warnForced: !1,
|
|
3015
|
+
message: ""
|
|
3016
|
+
};
|
|
3017
|
+
let t = `${e.unsafeCount} operation(s) are UNSAFE under a rolling deploy (VOLTRO_ROLLING_DEPLOY=1)`;
|
|
3018
|
+
return e.forced ? {
|
|
3019
|
+
refuse: !1,
|
|
3020
|
+
warnForced: !0,
|
|
3021
|
+
message: `${t} — proceeding anyway (--force). Old instances may error mid-rollout.`
|
|
3022
|
+
} : {
|
|
3023
|
+
refuse: !0,
|
|
3024
|
+
warnForced: !1,
|
|
3025
|
+
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.`
|
|
3026
|
+
};
|
|
3027
|
+
}, ri = (e, ...t) => ({
|
|
2925
3028
|
_tag: "RawSqlFragment",
|
|
2926
3029
|
strings: [...e],
|
|
2927
3030
|
values: [...t]
|
|
2928
|
-
}),
|
|
3031
|
+
}), ii = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
2929
3032
|
//#endregion
|
|
2930
|
-
export {
|
|
3033
|
+
export { O as DEFAULT_CDC_CHANNEL, o as FILE_MIGRATION_PATTERN, Gr as FileMigrationLedgerError, k as REACTIVE_TRIGGER_PREFIX, re as VOLTRO_MIGRATION_LOCK_KEY, T as acquireMigrationLock, et as applyNamespacedSchema, Tr as applyPlan, Je as applySchema, ni as assessRollingDeployGate, $t as chunkTables, ei as classifyRollingDeploySafety, I as declaredSnapshot, xe as defaultArrayClause, be as defaultClause, M as defaultJsonClause, Br as describeOutcome, Pr as destructiveScope, ft as detectReactiveTriggerDrift, gn as emitDropColumnDdl, _n as emitDropColumnDdlMysql, qe as emitFrameworkBootstrapSql, Ge as emitNamespaceProvisionDdl, Ke as emitNamespacedSchemaSql, We as emitSchemaSql, P as fingerprintSchema, pt as formatReactiveTriggerDrift, Nr as ignoreTablesFromEnv, U as introspectSchema, n as isFileMigration, ii as isRawSqlFragment, Jt as mapPgType, c as migration, N as numericIdSql, qt as parseEnumCheck, Jr as pendingFileMigrationIds, Kt as planMigrations, tt as provisionTenantNamespace, Fe as reactiveTriggerRepairSql, E as releaseMigrationLock, Mn as renderColumnMysql, Dn as renderColumnPg, Zr as rollbackFileBasedMigration, ti as rollingDeployUnsafeOps, Yr as runFileBasedMigrations, nt as runFrameworkBootstrap, $e as runMigrate, zr as runPlannedMigrations, F as shortFingerprint, ct as snapshotColumn, ri as sql, j as sqlType, Qr as squashMigrationPlans, Ir as unblockLossy, D as withMigrationLock };
|