@voltro/database 0.73.0 → 0.74.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 +130 -0
- package/dist/index.d.ts +11 -2
- package/dist/sql.d.ts +104 -2
- package/dist/sql.js +842 -803
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Cause as
|
|
3
|
-
import { createHash as
|
|
4
|
-
import { createLogger as
|
|
1
|
+
import { D as e, Gn as t, Gt as n, I as r, Jt as i, Kn as a, Ln as o, N as s, Nn as c, Pn as l, S as u, Ut as d, V as f, Wt as p, Yt as m, _ as h, a as g, c as _, cn as v, d as y, f as b, g as x, h as S, i as C, lt as ee, m as w, mn as te, o as T, ot as ne, p as E, rt as re, s as ie, tt as ae, u as oe, v as se, x as ce, y as le } from "./frameworkLiveTables-C1WjQ_uI.js";
|
|
2
|
+
import { Cause as ue, Effect as D, Equal as de, Exit as fe, Schedule as pe, Scope as me } from "effect";
|
|
3
|
+
import { createHash as he } from "node:crypto";
|
|
4
|
+
import { createLogger as ge } from "@voltro/logger";
|
|
5
5
|
import { SqlClient as O } from "@effect/sql";
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
6
|
+
import { promises as _e } from "node:fs";
|
|
7
|
+
import { join as ve } from "node:path";
|
|
8
|
+
import { pathToFileURL as ye } from "node:url";
|
|
9
9
|
//#region src/indexStorage.ts
|
|
10
|
-
var
|
|
10
|
+
var be = (e, t = "float32") => {
|
|
11
11
|
let n = e?.hnsw, r = n?.m ?? 16, i = n?.efConstruction ?? 64;
|
|
12
12
|
for (let [e, t] of Object.entries({
|
|
13
13
|
m: r,
|
|
14
14
|
efConstruction: i
|
|
15
15
|
})) if (!Number.isSafeInteger(t) || t <= 0) throw Error(`HNSW ${e} must be a positive safe integer`);
|
|
16
|
-
let a = n?.opclass ??
|
|
16
|
+
let a = n?.opclass ?? m(n?.distance, t);
|
|
17
17
|
if (!/^[a-z_][a-z0-9_$]*(?:\.[a-z_][a-z0-9_$]*)?$/i.test(a)) throw Error("HNSW opclass must be an unquoted, optionally schema-qualified identifier");
|
|
18
18
|
return {
|
|
19
19
|
m: r,
|
|
20
20
|
efConstruction: i,
|
|
21
21
|
opclass: a.toLowerCase().replace(/^public\./, "")
|
|
22
22
|
};
|
|
23
|
-
},
|
|
23
|
+
}, xe = (e, t) => t === void 0 || t === "postgres" ? e ?? "btree" : e === "hnsw" || e === "gin" && (t === "mysql" || t === "mariadb") ? null : "btree", Se = (e, t) => ({
|
|
24
24
|
...e !== void 0 && e !== "btree" ? { kind: e } : {},
|
|
25
|
-
...e === "hnsw" ? { kindOptions: { hnsw:
|
|
26
|
-
}),
|
|
25
|
+
...e === "hnsw" ? { kindOptions: { hnsw: be(t) } } : {}
|
|
26
|
+
}), Ce = (e, t, n = "float32") => {
|
|
27
27
|
if (e === void 0 || e === "btree") return {
|
|
28
28
|
using: "",
|
|
29
29
|
withSuffix: "",
|
|
@@ -35,14 +35,14 @@ var xe = (e, t = "float32") => {
|
|
|
35
35
|
withSuffix: "",
|
|
36
36
|
skip: !1
|
|
37
37
|
};
|
|
38
|
-
let r =
|
|
38
|
+
let r = be(t, n);
|
|
39
39
|
return {
|
|
40
40
|
using: " USING hnsw",
|
|
41
41
|
withSuffix: ` WITH (m = ${r.m}, ef_construction = ${r.efConstruction})`,
|
|
42
42
|
opclass: r.opclass,
|
|
43
43
|
skip: !1
|
|
44
44
|
};
|
|
45
|
-
},
|
|
45
|
+
}, we = (e, t, n, r = 400) => {
|
|
46
46
|
let i = n, a = i.cause ?? {}, o = (e) => {
|
|
47
47
|
let t = a[e];
|
|
48
48
|
return t == null || t === "" ? void 0 : String(t);
|
|
@@ -73,21 +73,21 @@ var xe = (e, t = "float32") => {
|
|
|
73
73
|
let t = o(e);
|
|
74
74
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
75
75
|
}
|
|
76
|
-
let c =
|
|
76
|
+
let c = Te(o("code"));
|
|
77
77
|
return c !== void 0 && s.push("", c), s.push(""), s.join("\n");
|
|
78
|
-
},
|
|
79
|
-
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(
|
|
78
|
+
}, Te = (e) => e === "3F000" ? "remedy: the connection's search_path names a schema that does not exist. Voltro sets it from DB_SCHEMA — create the schema (`CREATE SCHEMA \"<name>\"`) or unset DB_SCHEMA to use the connection default. Voltro creates TABLES, never the schema itself: that is a namespace decision, and inventing one from a typo is how a migration lands somewhere nobody is looking." : void 0, Ee = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, De = (e) => e.replace(/"/g, "`"), Oe = (e) => typeof e == "string" ? e : e.name ?? String(e), ke = (e, t) => `_ua_${t}_${e}`.slice(0, 64), Ae = (e, t) => {
|
|
79
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(Ee)) return e;
|
|
80
80
|
let n = { ...e.fields }, r = [], i = [];
|
|
81
81
|
for (let t of e.appliedIndexes) {
|
|
82
|
-
if (!
|
|
82
|
+
if (!Ee(t)) {
|
|
83
83
|
r.push(t);
|
|
84
84
|
continue;
|
|
85
85
|
}
|
|
86
|
-
let a =
|
|
86
|
+
let a = De(t.where), o = [];
|
|
87
87
|
for (let r of t.fields) {
|
|
88
|
-
let i =
|
|
88
|
+
let i = Oe(r);
|
|
89
89
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
90
|
-
let s =
|
|
90
|
+
let s = ke(t.name, i);
|
|
91
91
|
o.push(s), n[s] = {
|
|
92
92
|
type: "text",
|
|
93
93
|
nullable: !0,
|
|
@@ -110,7 +110,7 @@ var xe = (e, t = "float32") => {
|
|
|
110
110
|
appliedIndexes: r,
|
|
111
111
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
112
112
|
};
|
|
113
|
-
}, k = (e, t) => `${e}::${t}`,
|
|
113
|
+
}, k = (e, t) => `${e}::${t}`, je = (e, t) => {
|
|
114
114
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
115
115
|
n.add(e);
|
|
116
116
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
@@ -119,7 +119,7 @@ var xe = (e, t = "float32") => {
|
|
|
119
119
|
};
|
|
120
120
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
121
121
|
return i;
|
|
122
|
-
},
|
|
122
|
+
}, Me = (e, t) => e.executeUnprepared(t, [], void 0), Ne = 6322741009312437n, Pe = (e) => {
|
|
123
123
|
let t = e?.trim();
|
|
124
124
|
return t === void 0 || t === "" || t === "public" ? void 0 : t;
|
|
125
125
|
}, Fe = (e) => e?.schema === void 0 ? Pe(process.env.DB_SCHEMA) : Pe(e.schema), Ie = 14695981039346656037n, Le = 1099511628211n, Re = 18446744073709551615n, ze = (e) => {
|
|
@@ -140,19 +140,19 @@ var xe = (e, t = "float32") => {
|
|
|
140
140
|
}, We = (e, t) => D.gen(function* () {
|
|
141
141
|
let n = Ue(), r = Date.now();
|
|
142
142
|
for (;;) {
|
|
143
|
-
if ((yield*
|
|
143
|
+
if ((yield* Me(e, `SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`))[0]?.got) return;
|
|
144
144
|
Date.now() - r >= n && (yield* D.die(/* @__PURE__ */ Error(`could not acquire the postgres migration advisory lock within ${Math.round(n / 1e3)}s. Another migration is in progress, or a prior boot crashed while holding it. (A crashed process's session-level advisory lock is released once its DB connection closes; if this persists, find + terminate the holder via pg_stat_activity, or raise VOLTRO_MIGRATION_LOCK_TIMEOUT_MS.)`))), yield* D.sleep(`${He} millis`);
|
|
145
145
|
}
|
|
146
|
-
}), Ge = (e, t) => D.asVoid(
|
|
147
|
-
(yield*
|
|
148
|
-
}), Je = (e, t) => D.asVoid(
|
|
149
|
-
let n = yield*
|
|
146
|
+
}), Ge = (e, t) => D.asVoid(Me(e, `SELECT pg_advisory_unlock(${t.toString()}::bigint)`)), Ke = 30, qe = (e, t) => D.gen(function* () {
|
|
147
|
+
(yield* Me(e, `SELECT GET_LOCK('${t}', ${String(Ke)}) AS got`))[0]?.got !== 1 && (yield* D.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${Ke}s (another migration is in progress, or a prior one left it held).`)));
|
|
148
|
+
}), Je = (e, t) => D.asVoid(Me(e, `SELECT RELEASE_LOCK('${t}')`)), Ye = 3e4, Xe = (e, t) => D.gen(function* () {
|
|
149
|
+
let n = yield* Me(e, `
|
|
150
150
|
DECLARE @res int;
|
|
151
151
|
EXEC @res = sp_getapplock @Resource = '${t}', @LockMode = 'Exclusive',
|
|
152
152
|
@LockOwner = 'Session', @LockTimeout = ${String(Ye)};
|
|
153
153
|
SELECT @res AS res`);
|
|
154
154
|
(n[0]?.res ?? -999) < 0 && (yield* D.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
155
|
-
}), Ze = (e, t) => D.asVoid(
|
|
155
|
+
}), Ze = (e, t) => D.asVoid(Me(e, `EXEC sp_releaseapplock @Resource = '${t}', @LockOwner = 'Session'`)), Qe = D.void, $e = (e, t) => D.gen(function* () {
|
|
156
156
|
let n = Fe(t), r = Ve(n), i = Be(n);
|
|
157
157
|
if (!e.onDialectOrElse({
|
|
158
158
|
mysql: () => !0,
|
|
@@ -160,19 +160,19 @@ var xe = (e, t = "float32") => {
|
|
|
160
160
|
sqlite: () => !1,
|
|
161
161
|
orElse: () => !0
|
|
162
162
|
})) return { release: Qe };
|
|
163
|
-
let a = yield*
|
|
163
|
+
let a = yield* me.make(), o = yield* D.provideService(e.reserve, me.Scope, a), s = me.close(a, fe.void);
|
|
164
164
|
return yield* e.onDialectOrElse({
|
|
165
165
|
mysql: () => qe(o, r),
|
|
166
166
|
mssql: () => Xe(o, r),
|
|
167
167
|
sqlite: () => Qe,
|
|
168
168
|
orElse: () => We(o, i)
|
|
169
|
-
}).pipe(D.onExit((e) =>
|
|
169
|
+
}).pipe(D.onExit((e) => fe.isSuccess(e) ? D.void : s)), { release: e.onDialectOrElse({
|
|
170
170
|
mysql: () => Je(o, r),
|
|
171
171
|
mssql: () => Ze(o, r),
|
|
172
172
|
sqlite: () => Qe,
|
|
173
173
|
orElse: () => Ge(o, i)
|
|
174
174
|
}).pipe(D.ensuring(s)) };
|
|
175
|
-
}), et = "a migration needs 2 connections: one holds the migration lock for the whole apply, the other runs the statements. The pool could not hand out the second one — raise its size (DB_POOL_MAX / maxConnections) to at least 2 for the migrating process; behind a pooler (PgBouncer, Supavisor) point the migration at the database directly (DB_DIRECT_URL / DB_MIGRATE_URL).", tt = (e) => /acquire connection/i.test(String(e?.message ?? e)), nt = (e, t, n) => D.acquireUseRelease($e(e, n), () => t.pipe(D.tapError((e) => tt(e) ? D.logError(`migrate: ${et}`).pipe(D.annotateLogs({ scope: "voltro:migrate" })) : D.void)), (e) => e.release.pipe(D.orDie)),
|
|
175
|
+
}), et = "a migration needs 2 connections: one holds the migration lock for the whole apply, the other runs the statements. The pool could not hand out the second one — raise its size (DB_POOL_MAX / maxConnections) to at least 2 for the migrating process; behind a pooler (PgBouncer, Supavisor) point the migration at the database directly (DB_DIRECT_URL / DB_MIGRATE_URL).", tt = (e) => /acquire connection/i.test(String(e?.message ?? e)), nt = (e, t, n) => D.acquireUseRelease($e(e, n), () => t.pipe(D.tapError((e) => tt(e) ? D.logError(`migrate: ${et}`).pipe(D.annotateLogs({ scope: "voltro:migrate" })) : D.void)), (e) => e.release.pipe(D.orDie)), A = (e) => e.onDialectOrElse({
|
|
176
176
|
pg: () => "postgres",
|
|
177
177
|
mysql: () => "mysql",
|
|
178
178
|
mssql: () => "mssql",
|
|
@@ -185,19 +185,19 @@ var xe = (e, t = "float32") => {
|
|
|
185
185
|
mariadb: "per-operation",
|
|
186
186
|
sqlite: "per-operation",
|
|
187
187
|
turso: "per-operation"
|
|
188
|
-
}, it = (e) => rt[e],
|
|
189
|
-
id:
|
|
190
|
-
runId:
|
|
191
|
-
planFingerprint:
|
|
192
|
-
opIndex:
|
|
193
|
-
opKind:
|
|
194
|
-
opTarget:
|
|
195
|
-
status:
|
|
196
|
-
payload:
|
|
197
|
-
startedAt:
|
|
198
|
-
appliedAt:
|
|
199
|
-
durationMs:
|
|
200
|
-
createdAt:
|
|
188
|
+
}, it = (e) => rt[e], j = "_voltro_migration_ops", at = i(j, {
|
|
189
|
+
id: c({ prefix: "mop" }),
|
|
190
|
+
runId: t(),
|
|
191
|
+
planFingerprint: t(),
|
|
192
|
+
opIndex: l(),
|
|
193
|
+
opKind: t(),
|
|
194
|
+
opTarget: t(),
|
|
195
|
+
status: t(),
|
|
196
|
+
payload: t(),
|
|
197
|
+
startedAt: a().nullable(),
|
|
198
|
+
appliedAt: a().nullable(),
|
|
199
|
+
durationMs: l().nullable(),
|
|
200
|
+
createdAt: a().default("now")
|
|
201
201
|
}), ot = (e) => {
|
|
202
202
|
switch (e.kind) {
|
|
203
203
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
@@ -288,14 +288,17 @@ var gt = (e) => {
|
|
|
288
288
|
if (e.length === 0) return;
|
|
289
289
|
let t = e.filter((e) => e.enabled);
|
|
290
290
|
return t.some((e) => e.validation === "container") ? t.some((e) => e.validation === "container" && e.trusted) ? "container" : "unverified" : t.some((e) => e.validation === "value" && e.trusted) ? "value" : "unverified";
|
|
291
|
-
}, bt = "framework_changes", xt = "framework_changes_", St = (e, t) => t === "framework_changes" ? `${xt}${e}` : `${xt}${t}_${e}`, Ct = (e) => e
|
|
291
|
+
}, bt = "framework_changes", xt = "framework_changes_", St = (e, t) => t === "framework_changes" ? `${xt}${e}` : `${xt}${t}_${e}`, Ct = (e, t) => Tt(St(e, t).replace(/[A-Z]/g, (e) => e.toLowerCase())), wt = 63, Tt = (e) => {
|
|
292
|
+
let t = new TextEncoder().encode(e);
|
|
293
|
+
return t.length <= wt ? e : new TextDecoder().decode(t.subarray(0, wt)).replace(/�+$/u, "");
|
|
294
|
+
}, Et = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, Dt = "voltro:notify:v2", Ot = (e, t) => {
|
|
292
295
|
if (e.type === "text" && e.generatedAs === void 0) {
|
|
293
296
|
if (e.maxLength !== void 0) return e.maxLength;
|
|
294
297
|
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
295
298
|
}
|
|
296
|
-
},
|
|
297
|
-
|
|
298
|
-
},
|
|
299
|
+
}, kt = ge({ scope: "voltro:migrate" }), M = (e) => {
|
|
300
|
+
kt.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
301
|
+
}, N = (e, t) => {
|
|
299
302
|
let n = e.type;
|
|
300
303
|
if (e.spatial) {
|
|
301
304
|
if (t === "postgres") return `${e.spatial.kind}(${e.spatial.geomKind},${e.spatial.srid})`;
|
|
@@ -306,14 +309,14 @@ var gt = (e) => {
|
|
|
306
309
|
return e.rawDdl;
|
|
307
310
|
}
|
|
308
311
|
if (n === "array" && e.arrayElement) {
|
|
309
|
-
if (t === "postgres") return `${
|
|
312
|
+
if (t === "postgres") return `${N({
|
|
310
313
|
...e,
|
|
311
314
|
type: e.arrayElement,
|
|
312
315
|
arrayElement: void 0
|
|
313
316
|
}, t)}[]`;
|
|
314
317
|
if (t === "mysql" || t === "mariadb") return "JSON";
|
|
315
318
|
if (t === "mssql") return "NVARCHAR(MAX)";
|
|
316
|
-
if (
|
|
319
|
+
if (p(t)) return "TEXT";
|
|
317
320
|
}
|
|
318
321
|
if (n === "vector") {
|
|
319
322
|
let n = e.vectorDim;
|
|
@@ -322,27 +325,27 @@ var gt = (e) => {
|
|
|
322
325
|
if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
|
|
323
326
|
if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
|
|
324
327
|
if (t === "mssql") return "VARBINARY(MAX)";
|
|
325
|
-
if (
|
|
328
|
+
if (p(t)) return "BLOB";
|
|
326
329
|
}
|
|
327
330
|
if (n === "interval") {
|
|
328
331
|
if (t === "postgres") return "INTERVAL";
|
|
329
332
|
if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
|
|
330
|
-
if (
|
|
333
|
+
if (p(t)) return "INTEGER";
|
|
331
334
|
}
|
|
332
335
|
if (n === "decimal") {
|
|
333
336
|
let n = e.precision, r = e.scale ?? 0;
|
|
334
337
|
if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
|
|
335
|
-
return
|
|
338
|
+
return p(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
|
|
336
339
|
}
|
|
337
|
-
if (n === "bigint") return
|
|
340
|
+
if (n === "bigint") return p(t) ? "INTEGER" : "BIGINT";
|
|
338
341
|
if (n === "enum") {
|
|
339
342
|
if (t === "postgres") return e.enumName ?? "TEXT";
|
|
340
343
|
if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
|
|
341
344
|
if (t === "mssql") return "NVARCHAR(255)";
|
|
342
|
-
if (
|
|
345
|
+
if (p(t)) return "TEXT";
|
|
343
346
|
}
|
|
344
|
-
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` :
|
|
345
|
-
if (
|
|
347
|
+
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` : p(t) ? "TEXT" : `VARCHAR(${e.maxLength})`;
|
|
348
|
+
if (p(t)) switch (n) {
|
|
346
349
|
case "id": return "TEXT";
|
|
347
350
|
case "text": return "TEXT";
|
|
348
351
|
case "integer": return "INTEGER";
|
|
@@ -377,7 +380,7 @@ var gt = (e) => {
|
|
|
377
380
|
if (t === "mssql") switch (n) {
|
|
378
381
|
case "id": return "NVARCHAR(64)";
|
|
379
382
|
case "text": {
|
|
380
|
-
let t =
|
|
383
|
+
let t = Ot(e, !1);
|
|
381
384
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
382
385
|
}
|
|
383
386
|
case "integer": return "INT";
|
|
@@ -409,22 +412,22 @@ var gt = (e) => {
|
|
|
409
412
|
case "array": return "TEXT[]";
|
|
410
413
|
case "interval": return "INTERVAL";
|
|
411
414
|
}
|
|
412
|
-
},
|
|
415
|
+
}, At = (e, t) => {
|
|
413
416
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
414
417
|
let n = e.defaultValue;
|
|
415
|
-
return n === "now" ?
|
|
416
|
-
},
|
|
417
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
418
|
-
let r =
|
|
418
|
+
return n === "now" ? p(t) ? "DEFAULT CURRENT_TIMESTAMP" : t === "mssql" ? "DEFAULT SYSUTCDATETIME()" : t === "mysql" || t === "mariadb" ? "DEFAULT CURRENT_TIMESTAMP(6)" : "DEFAULT now()" : typeof n == "boolean" ? t === "postgres" ? `DEFAULT ${n}` : `DEFAULT ${+!!n}` : typeof n == "number" ? `DEFAULT ${n}` : typeof n == "string" ? `DEFAULT '${n.replace(/'/g, "''")}'` : Array.isArray(n) ? jt(n, e, t) : typeof n == "object" && n ? P(n, t) : null;
|
|
419
|
+
}, jt = (e, t, n) => {
|
|
420
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return P(e, n);
|
|
421
|
+
let r = N({
|
|
419
422
|
...t,
|
|
420
423
|
type: t.arrayElement,
|
|
421
424
|
arrayElement: void 0
|
|
422
425
|
}, n);
|
|
423
426
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
424
|
-
},
|
|
427
|
+
}, P = (e, t) => {
|
|
425
428
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
426
429
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
427
|
-
},
|
|
430
|
+
}, F = (e, t) => {
|
|
428
431
|
switch (t) {
|
|
429
432
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
430
433
|
case "mysql":
|
|
@@ -433,7 +436,7 @@ var gt = (e) => {
|
|
|
433
436
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
434
437
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
435
438
|
}
|
|
436
|
-
},
|
|
439
|
+
}, I = (e, t) => {
|
|
437
440
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
438
441
|
switch (e) {
|
|
439
442
|
case "cascade": return "CASCADE";
|
|
@@ -441,103 +444,103 @@ var gt = (e) => {
|
|
|
441
444
|
case "setNull": return "SET NULL";
|
|
442
445
|
case "noAction": return "NO ACTION";
|
|
443
446
|
}
|
|
444
|
-
}, Mt = (e, t,
|
|
447
|
+
}, Mt = (e, t, r) => r === null ? n(e, t) : `${n(r, t)}.${n(e, t)}`, Nt = 191, Pt = (e, t) => {
|
|
445
448
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
446
|
-
let n =
|
|
449
|
+
let n = N(e, t).toUpperCase();
|
|
447
450
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
448
|
-
}, Ft = (e, t,
|
|
449
|
-
let i =
|
|
450
|
-
if (
|
|
451
|
+
}, Ft = (e, t, r) => {
|
|
452
|
+
let i = n(e, r);
|
|
453
|
+
if (r !== "mysql" && r !== "mariadb") return i;
|
|
451
454
|
let a = t[e];
|
|
452
455
|
if (!a) return i;
|
|
453
|
-
let o =
|
|
456
|
+
let o = N(a, r).toUpperCase();
|
|
454
457
|
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${Nt})` : i;
|
|
455
458
|
}, It = (e, t) => {
|
|
456
459
|
if (!e.generatedAs) return null;
|
|
457
460
|
let { expr: n, stored: r } = e.generatedAs;
|
|
458
|
-
if (t === "postgres") return r ||
|
|
461
|
+
if (t === "postgres") return r || M("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
459
462
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
460
463
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
461
464
|
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.");
|
|
462
465
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
463
|
-
}, Lt = (e, t,
|
|
464
|
-
if (t.type === "id" && t.idScheme?.kind === "numeric") return
|
|
465
|
-
let s =
|
|
466
|
+
}, Lt = (e, t, r, i, a = !1, o = !1) => {
|
|
467
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return F(e, r);
|
|
468
|
+
let s = r === "mssql" ? Ot(t, i?.has(e) ?? !1) : void 0, c = s === void 0 ? N(t, r) : `NVARCHAR(${s})`, l = [n(e, r), c];
|
|
466
469
|
t.type === "id" && !o && l.push("PRIMARY KEY");
|
|
467
|
-
let u = It(t,
|
|
470
|
+
let u = It(t, r);
|
|
468
471
|
if (u) l.push(u);
|
|
469
472
|
else {
|
|
470
|
-
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !Pt(t,
|
|
471
|
-
let e =
|
|
473
|
+
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !Pt(t, r) && l.push("UNIQUE");
|
|
474
|
+
let e = At(t, r);
|
|
472
475
|
e && l.push(e);
|
|
473
476
|
}
|
|
474
|
-
if (t.type === "reference" && t.references && !a && !
|
|
477
|
+
if (t.type === "reference" && t.references && !a && !d(r)) {
|
|
475
478
|
let e = t.references();
|
|
476
|
-
l.push(`REFERENCES ${
|
|
477
|
-
let i =
|
|
479
|
+
l.push(`REFERENCES ${n(e.tableName, r)} (${n(t.referenceColumn ?? "id", r)})`);
|
|
480
|
+
let i = I(t.onDelete ?? "restrict", r);
|
|
478
481
|
l.push(`ON DELETE ${i}`);
|
|
479
|
-
let a =
|
|
482
|
+
let a = I(t.refOnUpdate ?? "noAction", r);
|
|
480
483
|
a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
|
|
481
484
|
}
|
|
482
485
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
483
486
|
let i = t.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
484
|
-
l.push(`CHECK (${
|
|
487
|
+
l.push(`CHECK (${n(e, r)} IN (${i}))`);
|
|
485
488
|
}
|
|
486
489
|
if (t.checks && t.checks.length > 0) for (let e of t.checks) l.push(`CHECK (${e})`);
|
|
487
|
-
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (
|
|
490
|
+
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (r === "mssql" || p(r))) {
|
|
488
491
|
let i = t.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
489
|
-
l.push(`CHECK (${
|
|
492
|
+
l.push(`CHECK (${n(e, r)} IN (${i}))`);
|
|
490
493
|
}
|
|
491
494
|
if (t.type === "json" || t.type === "array") {
|
|
492
|
-
let i =
|
|
493
|
-
|
|
495
|
+
let i = n(e, r);
|
|
496
|
+
p(r) ? l.push(`CHECK (${i} IS NULL OR json_valid(${i}))`) : r === "mssql" && l.push(t.type === "json" ? `CHECK ${gt(i)}` : `CHECK (${i} IS NULL OR ISJSON(${i}) = 1)`);
|
|
494
497
|
}
|
|
495
498
|
return l.join(" ");
|
|
496
|
-
}, Rt = (e, t,
|
|
499
|
+
}, Rt = (e, t, r = null, i) => {
|
|
497
500
|
let a = /* @__PURE__ */ new Set();
|
|
498
501
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
499
502
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
|
|
500
503
|
for (let [t, n] of Object.entries(e.fields)) n.unique && a.add(t);
|
|
501
504
|
let o = e.appliedPrimaryKey ?? [];
|
|
502
505
|
for (let e of o) a.add(e);
|
|
503
|
-
let s = o.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${Lt(e, n, t, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((
|
|
504
|
-
let i =
|
|
505
|
-
return ` CONSTRAINT ${r
|
|
506
|
-
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${
|
|
506
|
+
let s = o.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${Lt(e, n, t, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((r) => {
|
|
507
|
+
let i = r.fields.map((n) => Ft(n, e.fields, t)).join(", ");
|
|
508
|
+
return ` CONSTRAINT ${n(r.name, t)} UNIQUE (${i})`;
|
|
509
|
+
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${n(e.name, t)} CHECK (${e.expr})`), f = s ? [` PRIMARY KEY (${o.map((n) => Ft(n, e.fields, t)).join(", ")})`] : [], p = d(t) ? Object.entries(e.fields).flatMap(([a, o]) => {
|
|
507
510
|
if (o.type !== "reference" || !o.references || (i?.has(a) ?? !1)) return [];
|
|
508
|
-
let s = o.references(), c =
|
|
509
|
-
return [` CONSTRAINT ${
|
|
511
|
+
let s = o.references(), c = I(o.onDelete ?? "restrict", t), l = I(o.refOnUpdate ?? "noAction", t);
|
|
512
|
+
return [` CONSTRAINT ${n(`${e.tableName}_${a}_fkey`, t)} FOREIGN KEY (${n(a, t)}) REFERENCES ${Mt(s.tableName, t, r)} (${n(o.referenceColumn ?? "id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
510
513
|
}) : [], m = [
|
|
511
|
-
...
|
|
514
|
+
...f,
|
|
512
515
|
...l,
|
|
513
516
|
...u,
|
|
514
517
|
...p
|
|
515
|
-
], h = m.length > 0 ? `${c},\n${m.join(",\n")}` : c, g = Mt(e.tableName, t,
|
|
518
|
+
], h = m.length > 0 ? `${c},\n${m.join(",\n")}` : c, g = Mt(e.tableName, t, r);
|
|
516
519
|
if (t === "mssql") {
|
|
517
|
-
let t =
|
|
518
|
-
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${
|
|
520
|
+
let t = r === null ? e.tableName : `${r}.${e.tableName}`, n = `CREATE TABLE ${g} (\n${h}\n)`;
|
|
521
|
+
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${n.replace(/'/g, "''")}');`;
|
|
519
522
|
}
|
|
520
523
|
return [
|
|
521
524
|
`CREATE TABLE IF NOT EXISTS ${g} (`,
|
|
522
525
|
h,
|
|
523
526
|
");"
|
|
524
527
|
].join("\n");
|
|
525
|
-
}, zt = (e, t,
|
|
526
|
-
let i = `${e}_${t.name}_fts`, a = (e) =>
|
|
528
|
+
}, zt = (e, t, r) => {
|
|
529
|
+
let i = `${e}_${t.name}_fts`, a = (e) => n(e, r), o = t.columns.map(a).join(", "), s = t.columns.map((e) => `new.${a(e)}`).join(", "), c = [];
|
|
527
530
|
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;
|
|
528
|
-
}, Bt = (e, t,
|
|
531
|
+
}, Bt = (e, t, r = null) => {
|
|
529
532
|
let i = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, n, r, i, a) => {
|
|
530
|
-
if (t === "postgres") return
|
|
533
|
+
if (t === "postgres") return Ce(r, i, a);
|
|
531
534
|
let o = {
|
|
532
535
|
using: "",
|
|
533
536
|
withSuffix: "",
|
|
534
537
|
skip: !1
|
|
535
538
|
};
|
|
536
|
-
return r === void 0 || r === "btree" ? o : r === "gist" ? (
|
|
539
|
+
return r === void 0 || r === "btree" ? o : r === "gist" ? (M(`[voltro:migrate] index '${e}' on '${n}': ${t} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), o) : r === "gin" ? t === "mysql" || t === "mariadb" ? (M(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
537
540
|
using: "",
|
|
538
541
|
withSuffix: "",
|
|
539
542
|
skip: !0
|
|
540
|
-
}) : (
|
|
543
|
+
}) : (M(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), o) : r === "brin" ? (M(`[voltro:migrate] brin index '${e}' on '${n}': ${t} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), o) : r === "hnsw" ? (M(`[voltro:migrate] hnsw index '${e}' on '${n}': ${t} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
541
544
|
using: "",
|
|
542
545
|
withSuffix: "",
|
|
543
546
|
skip: !0
|
|
@@ -547,7 +550,7 @@ var gt = (e) => {
|
|
|
547
550
|
if (typeof n == "string") return Ft(n, e.fields, t);
|
|
548
551
|
if ("jsonPath" in n) {
|
|
549
552
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
550
|
-
return `(${
|
|
553
|
+
return `(${ae(e, r, t, { numeric: i })})`;
|
|
551
554
|
}
|
|
552
555
|
return `(${n.expr})`;
|
|
553
556
|
});
|
|
@@ -555,33 +558,33 @@ var gt = (e) => {
|
|
|
555
558
|
}, l = (i, a, o, l, u, d = "", f = !1) => {
|
|
556
559
|
let p = o[0], m = typeof p == "string" ? e.fields[p]?.vectorPrecision : void 0, h = s(i, a, l, u, m);
|
|
557
560
|
if (h.skip) return "";
|
|
558
|
-
let g = c(o, h.opclass), _ = `${h.withSuffix}${d}`, v = Mt(a, t,
|
|
559
|
-
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${i}') CREATE ${y}INDEX ${
|
|
561
|
+
let g = c(o, h.opclass), _ = `${h.withSuffix}${d}`, v = Mt(a, t, r), y = f ? "UNIQUE " : "";
|
|
562
|
+
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${i}') CREATE ${y}INDEX ${n(i, t)} ON ${v}${h.using} (${g})${_};` : t === "mysql" ? `CREATE ${y}INDEX ${n(i, t)} ON ${v}${h.using} (${g})${_};` : `CREATE ${y}INDEX IF NOT EXISTS ${n(i, t)} ON ${v}${h.using} (${g})${_};`;
|
|
560
563
|
};
|
|
561
564
|
if (t === "mysql" || t === "mariadb") for (let [n, r] of Object.entries(e.fields)) {
|
|
562
565
|
if (!r.unique || r.type === "id" || !Pt(r, t)) continue;
|
|
563
566
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
564
567
|
a && i.push(a);
|
|
565
568
|
}
|
|
566
|
-
for (let
|
|
567
|
-
let a =
|
|
568
|
-
let i =
|
|
569
|
-
return `setweight(to_tsvector('${a}', coalesce(${
|
|
569
|
+
for (let r of e.appliedFullText ?? []) if (t === "postgres") {
|
|
570
|
+
let a = r.config ?? "english", o = `${r.name}_tsv`, s = r.columns.map((e) => {
|
|
571
|
+
let i = r.weights?.[e] ?? "A";
|
|
572
|
+
return `setweight(to_tsvector('${a}', coalesce(${n(e, t)}, '')), '${i}')`;
|
|
570
573
|
}).join(" || ");
|
|
571
|
-
i.push(`ALTER TABLE ${
|
|
574
|
+
i.push(`ALTER TABLE ${n(e.tableName, t)} ADD COLUMN IF NOT EXISTS ${n(o, t)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), i.push(`CREATE INDEX IF NOT EXISTS ${n(r.name, t)} ON ${n(e.tableName, t)} USING GIN (${n(o, t)});`);
|
|
572
575
|
} else if (t === "mysql" || t === "mariadb") {
|
|
573
|
-
let a =
|
|
574
|
-
i.push(`CREATE FULLTEXT INDEX ${r
|
|
575
|
-
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${
|
|
576
|
-
else t === "sqlite" ? i.push(...zt(e.tableName,
|
|
576
|
+
let a = r.columns.map((e) => n(e, t)).join(", ");
|
|
577
|
+
i.push(`CREATE FULLTEXT INDEX ${n(r.name, t)} ON ${n(e.tableName, t)} (${a});`);
|
|
578
|
+
} else if (t === "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.`);
|
|
579
|
+
else t === "sqlite" ? i.push(...zt(e.tableName, r, t)) : M(`[voltro:migrate] full-text index '${r.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
577
580
|
for (let n of e.appliedIndexes) {
|
|
578
581
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
579
|
-
|
|
582
|
+
M(`[voltro:migrate] json-path index '${n.name}' on '${e.tableName}': ${t} cannot index a JSON expression directly — skipping. For an indexed JSON path on ${t}, add a generated column for the path (text().generatedAs(...) / .stored()) and .index([...]) it, then filter on that column instead of jsonField(...).`);
|
|
580
583
|
continue;
|
|
581
584
|
}
|
|
582
585
|
if (n.unique && n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb")) throw Error(`@voltro/migrate: uniqueActive index '${n.name}' on '${e.tableName}' cannot be expressed on ${t} — it has no partial (WHERE) index support, and a full UNIQUE index would forbid re-creating a soft-deleted row. Use a generated STORED column (text().generatedAs("CASE WHEN \`deletedAt\` IS NULL THEN <key> ELSE NULL END", { stored: true })) + .unique([...]) on ${t}, or move this table to postgres/sqlite/mssql.`);
|
|
583
586
|
let r = "";
|
|
584
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ?
|
|
587
|
+
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? M(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) : r = ` WHERE ${n.where}`);
|
|
585
588
|
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions, r, n.unique === !0);
|
|
586
589
|
s !== "" && i.push(s), n.fields.every((e) => typeof e == "string") && a.add(o(n.fields));
|
|
587
590
|
}
|
|
@@ -596,12 +599,12 @@ var gt = (e) => {
|
|
|
596
599
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
597
600
|
return r.length === 0 ? [] : [Ht(n), ...r.map((e) => Wt(e, n))];
|
|
598
601
|
}, Ht = (e) => `
|
|
599
|
-
CREATE OR REPLACE FUNCTION ${
|
|
602
|
+
CREATE OR REPLACE FUNCTION ${Et(e)}() RETURNS trigger AS $$
|
|
600
603
|
DECLARE
|
|
601
604
|
payload TEXT;
|
|
602
605
|
pk JSONB;
|
|
603
606
|
BEGIN
|
|
604
|
-
-- ${
|
|
607
|
+
-- ${Dt}
|
|
605
608
|
payload := json_build_object(
|
|
606
609
|
'table', TG_TABLE_NAME,
|
|
607
610
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -660,7 +663,7 @@ $$ LANGUAGE plpgsql;
|
|
|
660
663
|
return [
|
|
661
664
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
662
665
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
663
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
666
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${Et(t)}()`
|
|
664
667
|
];
|
|
665
668
|
}, Wt = (e, t) => Ut(e, t).map((e) => `${e};`).join("\n"), Gt = (e) => {
|
|
666
669
|
if (e.dialect !== "postgres") return [];
|
|
@@ -674,7 +677,7 @@ $$ LANGUAGE plpgsql;
|
|
|
674
677
|
let n = [];
|
|
675
678
|
return qt(e) && n.push("CREATE EXTENSION IF NOT EXISTS vector;"), Jt(e) && n.push("CREATE EXTENSION IF NOT EXISTS postgis;"), n.length === 0 ? void 0 : n.join("\n");
|
|
676
679
|
}, qt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), Jt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), Yt = (e) => {
|
|
677
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
680
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = je(e.map((e) => e.tableName), (e) => {
|
|
678
681
|
let n = t.get(e);
|
|
679
682
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
680
683
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -711,13 +714,13 @@ $$ LANGUAGE plpgsql;
|
|
|
711
714
|
sorted: o,
|
|
712
715
|
cyclic: r
|
|
713
716
|
};
|
|
714
|
-
}, Xt = (e, t,
|
|
715
|
-
let i = (e) =>
|
|
717
|
+
}, Xt = (e, t, r = null) => {
|
|
718
|
+
let i = (e) => r ? `${n(r, t)}.${n(e, t)}` : n(e, t), a = `${e.table}_${e.column}_fkey`, o = I(e.onDelete, t), s = I(e.onUpdate, t), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (r) => `ADD CONSTRAINT ${n(a, t)} FOREIGN KEY ${r ? "IF NOT EXISTS " : ""}(${n(e.column, t)}) REFERENCES ${i(e.targetTable)} (${n(e.targetColumn, t)})${c}`;
|
|
716
719
|
switch (t) {
|
|
717
720
|
case "postgres": return [
|
|
718
721
|
"DO $$ BEGIN",
|
|
719
722
|
" IF NOT EXISTS (SELECT 1 FROM pg_constraint",
|
|
720
|
-
` WHERE conname = '${a}' AND conrelid = '${
|
|
723
|
+
` WHERE conname = '${a}' AND conrelid = '${r ? `${r}.` : ""}${e.table}'::regclass) THEN`,
|
|
721
724
|
` ALTER TABLE ${i(e.table)} ${l(!1)};`,
|
|
722
725
|
" END IF;",
|
|
723
726
|
"END $$;"
|
|
@@ -728,7 +731,7 @@ $$ LANGUAGE plpgsql;
|
|
|
728
731
|
}
|
|
729
732
|
}, Zt = (e, t) => {
|
|
730
733
|
let n = /* @__PURE__ */ new Map();
|
|
731
|
-
if (
|
|
734
|
+
if (p(t)) return n;
|
|
732
735
|
for (let t of e) {
|
|
733
736
|
let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
|
|
734
737
|
e.add(t.column), n.set(t.table, e);
|
|
@@ -766,47 +769,47 @@ BEGIN
|
|
|
766
769
|
return r.join("\n\n");
|
|
767
770
|
}, en = (e) => {
|
|
768
771
|
let t = [], n = [];
|
|
769
|
-
for (let r of e)
|
|
772
|
+
for (let r of e) ne(r) ? n.push(r) : t.push(r);
|
|
770
773
|
return {
|
|
771
774
|
tables: t,
|
|
772
775
|
views: n
|
|
773
776
|
};
|
|
774
777
|
}, tn = (e, t, n = bt) => {
|
|
775
|
-
let { tables: r, views: i } = en(e), { sorted: a, cyclic: o } = Yt(r.map((e) =>
|
|
778
|
+
let { tables: r, views: i } = en(e), { sorted: a, cyclic: o } = Yt(r.map((e) => Ae(e, t))), s = Zt(o, t), c = [], l = Kt(a, t);
|
|
776
779
|
l && c.push(l);
|
|
777
780
|
let u = $t(a, t);
|
|
778
781
|
u && c.push(u);
|
|
779
782
|
let d = Qt(a, t);
|
|
780
783
|
d && c.push(d);
|
|
781
784
|
for (let e of a) c.push(Rt(e, t, null, s.get(e.tableName)));
|
|
782
|
-
if (!
|
|
785
|
+
if (!p(t)) for (let e of o) c.push(Xt(e, t));
|
|
783
786
|
for (let e of a) {
|
|
784
787
|
let n = Bt(e, t);
|
|
785
788
|
n && c.push(n);
|
|
786
789
|
}
|
|
787
790
|
c.push(...Vt(a, t, n));
|
|
788
|
-
for (let e of i) c.push(
|
|
791
|
+
for (let e of i) c.push(ee(e, t));
|
|
789
792
|
return c.join("\n\n") + "\n";
|
|
790
|
-
}, nn = (e, t,
|
|
791
|
-
let i =
|
|
793
|
+
}, nn = (e, t, r) => {
|
|
794
|
+
let i = n(e, t);
|
|
792
795
|
switch (t) {
|
|
793
796
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
|
|
794
797
|
case "mysql":
|
|
795
798
|
case "mariadb": return `CREATE DATABASE IF NOT EXISTS ${i};`;
|
|
796
799
|
case "mssql": return `IF SCHEMA_ID('${e.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${i.replace(/'/g, "''")}');`;
|
|
797
800
|
case "turso":
|
|
798
|
-
case "sqlite": return `ATTACH DATABASE '${(
|
|
801
|
+
case "sqlite": return `ATTACH DATABASE '${(r ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
|
|
799
802
|
}
|
|
800
|
-
}, rn = (e, t,
|
|
801
|
-
let a = nn(
|
|
803
|
+
}, rn = (e, t, r, i) => {
|
|
804
|
+
let a = nn(r, t, i), o = n(r, t);
|
|
802
805
|
if (t === "postgres") return `${a}\n\nSET search_path TO ${o};\n\n${tn(e, t)}`;
|
|
803
806
|
if (t === "mysql" || t === "mariadb") return `${a}\n\nUSE ${o};\n\n${tn(e, t)}`;
|
|
804
807
|
let { sorted: s, cyclic: c } = Yt(e), l = Zt(c, t), u = [a];
|
|
805
|
-
for (let e of s) u.push(Rt(e, t,
|
|
806
|
-
if (!
|
|
808
|
+
for (let e of s) u.push(Rt(e, t, r, l.get(e.tableName)));
|
|
809
|
+
if (!p(t)) for (let e of c) u.push(Xt(e, t, r));
|
|
807
810
|
for (let e of s) {
|
|
808
|
-
let
|
|
809
|
-
|
|
811
|
+
let n = Bt(e, t, r);
|
|
812
|
+
n && u.push(n);
|
|
810
813
|
}
|
|
811
814
|
return u.join("\n\n") + "\n";
|
|
812
815
|
}, an = (e, t, n = bt) => {
|
|
@@ -832,7 +835,7 @@ BEGIN
|
|
|
832
835
|
}, un = (e) => ({
|
|
833
836
|
while: e,
|
|
834
837
|
times: ln(),
|
|
835
|
-
schedule:
|
|
838
|
+
schedule: pe.jittered(pe.exponential("50 millis"))
|
|
836
839
|
}), dn = class {
|
|
837
840
|
statement;
|
|
838
841
|
error;
|
|
@@ -843,15 +846,15 @@ BEGIN
|
|
|
843
846
|
}, fn = (e, t, n) => D.gen(function* () {
|
|
844
847
|
let r = yield* O.SqlClient, i = n !== void 0 && it(t) === "per-operation";
|
|
845
848
|
for (let a of mn(e)) {
|
|
846
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
849
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && kt.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
847
850
|
let e = r.unsafe(a).pipe(D.catchIf((e) => sn(a, e), () => D.succeed([])), D.tapError((e) => D.sync(() => {
|
|
848
|
-
|
|
851
|
+
kt.error(we("migrate: statement failed", a, e, 200));
|
|
849
852
|
})));
|
|
850
853
|
yield* (i && n !== void 0 && cn(a, t) ? e.pipe(D.retry(un((e) => n(e) === "retry"))) : e).pipe(D.mapError((e) => new dn(a, e)));
|
|
851
854
|
}
|
|
852
855
|
}), pn = (e, t, n, r) => {
|
|
853
856
|
let i = n === "turso" ? fn(t, n, r) : e.withTransaction(fn(t, n, r)), a = (e) => e instanceof dn ? e.error : e;
|
|
854
|
-
return (r !== void 0 && it(n) === "plan-transactional" ? i.pipe(D.retry(un((e) => r(a(e)) === "retry"))) : i).pipe(D.orDieWith((e) => e instanceof dn ? Error(
|
|
857
|
+
return (r !== void 0 && it(n) === "plan-transactional" ? i.pipe(D.retry(un((e) => r(a(e)) === "retry"))) : i).pipe(D.orDieWith((e) => e instanceof dn ? Error(we("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
855
858
|
}, mn = (e) => {
|
|
856
859
|
let t = [], n = "", r = !1;
|
|
857
860
|
for (let i = 0; i < e.length; i++) {
|
|
@@ -873,7 +876,7 @@ BEGIN
|
|
|
873
876
|
let i = rn(e, n, t), a = yield* O.SqlClient;
|
|
874
877
|
yield* nt(a, pn(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(D.orDie);
|
|
875
878
|
}), _n = async (e, t, n, r = "postgres", i = {}) => {
|
|
876
|
-
await D.runPromise(gn(e, t, r, i).pipe(D.provide(n))), await
|
|
879
|
+
await D.runPromise(gn(e, t, r, i).pipe(D.provide(n))), await u({
|
|
877
880
|
namespace: t,
|
|
878
881
|
dialect: r
|
|
879
882
|
});
|
|
@@ -950,36 +953,36 @@ BEGIN
|
|
|
950
953
|
}, Pn = (e) => {
|
|
951
954
|
let { kind: t, kindOptions: n, ...r } = e, i = {
|
|
952
955
|
...r,
|
|
953
|
-
...
|
|
956
|
+
...Se(t, n),
|
|
954
957
|
...e.where === void 0 ? {} : { where: xn(e.where) }
|
|
955
958
|
};
|
|
956
959
|
return e.expression ? {
|
|
957
960
|
...i,
|
|
958
961
|
columns: []
|
|
959
962
|
} : i;
|
|
960
|
-
},
|
|
963
|
+
}, L = (e) => {
|
|
961
964
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
962
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
965
|
+
if (Array.isArray(e)) return `[${e.map(L).join(",")}]`;
|
|
963
966
|
let t = e;
|
|
964
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
967
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${L(t[e])}`).join(",")}}`;
|
|
965
968
|
}, Fn = (e) => {
|
|
966
969
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
967
970
|
let t = e.defaultValue;
|
|
968
971
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
969
972
|
if (typeof t == "number") return String(t);
|
|
970
|
-
if (typeof t != "string") return
|
|
973
|
+
if (typeof t != "string") return L(t);
|
|
971
974
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
972
975
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
973
976
|
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);
|
|
974
977
|
if (o) try {
|
|
975
|
-
return
|
|
978
|
+
return L(JSON.parse(o[1]));
|
|
976
979
|
} catch {}
|
|
977
980
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
978
981
|
if (s) try {
|
|
979
|
-
return
|
|
982
|
+
return L(JSON.parse(s[1]));
|
|
980
983
|
} catch {}
|
|
981
984
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
982
|
-
return
|
|
985
|
+
return L(JSON.parse(a));
|
|
983
986
|
} catch {}
|
|
984
987
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
985
988
|
}, In = (e) => {
|
|
@@ -996,11 +999,11 @@ BEGIN
|
|
|
996
999
|
};
|
|
997
1000
|
}, zn = (e, t, n) => {
|
|
998
1001
|
if (t === "mssql") {
|
|
999
|
-
let t =
|
|
1002
|
+
let t = Ot(e, n);
|
|
1000
1003
|
if (t !== void 0) return t;
|
|
1001
1004
|
}
|
|
1002
1005
|
try {
|
|
1003
|
-
let n = /^N?VARCHAR\((\d+)\)$/i.exec(
|
|
1006
|
+
let n = /^N?VARCHAR\((\d+)\)$/i.exec(N(e, t).trim());
|
|
1004
1007
|
return n ? Number(n[1]) : void 0;
|
|
1005
1008
|
} catch {
|
|
1006
1009
|
return;
|
|
@@ -1037,13 +1040,13 @@ BEGIN
|
|
|
1037
1040
|
...t.spatial === void 0 ? {} : { spatial: Mn(t.spatial) },
|
|
1038
1041
|
...t.enumValues === void 0 ? {} : { enumValues: [...t.enumValues].sort() }
|
|
1039
1042
|
};
|
|
1040
|
-
}, Un = (e) => e.columns.filter((e) => !
|
|
1043
|
+
}, Un = (e) => e.columns.filter((e) => !ie(e.name)).map((t) => Hn(kn(t, Sn(e, t)))).sort((e, t) => e.name.localeCompare(t.name)), Wn = (e) => [...e].map(Pn).sort((e, t) => e.name.localeCompare(t.name)), Gn = (e) => [...e].filter((e) => !ie(e.name)).map((e) => ({
|
|
1041
1044
|
name: e.name,
|
|
1042
1045
|
columns: Un(e),
|
|
1043
1046
|
indexes: Wn(e.indexes)
|
|
1044
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
1047
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), R = (e) => {
|
|
1045
1048
|
let t = { tables: Gn(e.tables) }, n = JSON.stringify(Bn(t));
|
|
1046
|
-
return
|
|
1049
|
+
return he("sha256").update(n).digest("hex");
|
|
1047
1050
|
}, Kn = (e) => e.slice(0, 16), qn = (e, t, n) => {
|
|
1048
1051
|
let r = t.references ? {
|
|
1049
1052
|
table: t.references().tableName,
|
|
@@ -1104,15 +1107,15 @@ BEGIN
|
|
|
1104
1107
|
});
|
|
1105
1108
|
let o = e.appliedIndexes ?? [];
|
|
1106
1109
|
for (let n of o) {
|
|
1107
|
-
let r =
|
|
1110
|
+
let r = xe(n.kind, t);
|
|
1108
1111
|
if (r === null) continue;
|
|
1109
|
-
let a = n.fields[0], o = typeof a == "string" ? e.fields[a]?.vectorPrecision : void 0, s = r === "hnsw" ? { hnsw:
|
|
1112
|
+
let a = n.fields[0], o = typeof a == "string" ? e.fields[a]?.vectorPrecision : void 0, s = r === "hnsw" ? { hnsw: be(n.kindOptions, o) } : void 0, c = n.fields.map((e) => typeof e == "string" ? e : "jsonPath" in e ? `(json:${e.jsonPath.column}->${e.jsonPath.path.join(".")}${e.jsonPath.numeric ? "::num" : ""})` : `(${e.expr})`), l = n.fields.some((e) => typeof e != "string");
|
|
1110
1113
|
i({
|
|
1111
1114
|
name: n.name,
|
|
1112
1115
|
table: e.tableName,
|
|
1113
1116
|
columns: c,
|
|
1114
1117
|
unique: n.unique ?? !1,
|
|
1115
|
-
...
|
|
1118
|
+
...Se(r, s),
|
|
1116
1119
|
...n.where === void 0 ? {} : { where: n.where },
|
|
1117
1120
|
...l ? { expression: !0 } : {}
|
|
1118
1121
|
});
|
|
@@ -1130,7 +1133,7 @@ BEGIN
|
|
|
1130
1133
|
let r = n;
|
|
1131
1134
|
if (r.dropped || !r.references || r.fkAutoIndex === !1 || c.has(t)) continue;
|
|
1132
1135
|
let a = `${e.tableName}_${t}_idx`;
|
|
1133
|
-
|
|
1136
|
+
v(e.tableName, a, !0, [t]), i({
|
|
1134
1137
|
name: a,
|
|
1135
1138
|
table: e.tableName,
|
|
1136
1139
|
columns: [t],
|
|
@@ -1163,8 +1166,8 @@ BEGIN
|
|
|
1163
1166
|
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}').`);
|
|
1164
1167
|
t.set(e.name, n.name);
|
|
1165
1168
|
}
|
|
1166
|
-
},
|
|
1167
|
-
let n = e.filter((e) => !
|
|
1169
|
+
}, z = (e, t) => {
|
|
1170
|
+
let n = e.filter((e) => !_(e.tableName)).map((e) => Yn(Ae(e, t), t));
|
|
1168
1171
|
if (t === "mysql" || t === "mariadb") {
|
|
1169
1172
|
for (let e of n) for (let n of e.indexes) if (n.where !== void 0) throw Error(`Partial index '${n.name}' on '${e.name}' is not supported by ${t}. Use uniqueActive for portable conditional uniqueness.`);
|
|
1170
1173
|
}
|
|
@@ -1177,7 +1180,7 @@ BEGIN
|
|
|
1177
1180
|
if (t === "mssql" && !e.generatedAs && (e.type === "json" || e.type === "array") && (e = {
|
|
1178
1181
|
...e,
|
|
1179
1182
|
jsonValidation: e.type === "json" ? "value" : "container"
|
|
1180
|
-
}),
|
|
1183
|
+
}), p(t)) {
|
|
1181
1184
|
if (e.maxLength === void 0) return e;
|
|
1182
1185
|
let { maxLength: t, ...n } = e;
|
|
1183
1186
|
return n;
|
|
@@ -1196,7 +1199,7 @@ BEGIN
|
|
|
1196
1199
|
FROM pg_proc p
|
|
1197
1200
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
1198
1201
|
WHERE n.nspname = current_schema()
|
|
1199
|
-
AND p.proname = ${
|
|
1202
|
+
AND p.proname = ${Et(n)}
|
|
1200
1203
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = (yield* e`SELECT current_schema() AS schema`)[0]?.schema ?? "", o = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
1201
1204
|
if (o.length === 0) return {
|
|
1202
1205
|
missing: [],
|
|
@@ -1209,26 +1212,26 @@ BEGIN
|
|
|
1209
1212
|
}
|
|
1210
1213
|
};
|
|
1211
1214
|
let s = yield* e`
|
|
1212
|
-
SELECT t.tgname
|
|
1215
|
+
SELECT t.tgname, c.relname
|
|
1213
1216
|
FROM pg_trigger t
|
|
1214
1217
|
JOIN pg_class c ON c.oid = t.tgrelid
|
|
1215
1218
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1216
1219
|
WHERE NOT t.tgisinternal
|
|
1217
1220
|
AND n.nspname = current_schema()
|
|
1218
1221
|
AND t.tgname LIKE ${`${xt}%`}
|
|
1219
|
-
`, c = new Set(s.map((e) => e.tgname)),
|
|
1222
|
+
`, c = (e, t) => `${e}\u0000${t}`, l = new Set(s.map((e) => c(e.relname, e.tgname))), u = [], d = [];
|
|
1220
1223
|
for (let e of o) {
|
|
1221
|
-
let t =
|
|
1222
|
-
r && !t &&
|
|
1224
|
+
let t = l.has(c(e.tableName, Ct(e.tableName, n))), r = e.isReactive !== !1;
|
|
1225
|
+
r && !t && u.push(e.tableName), !r && t && d.push(e.tableName);
|
|
1223
1226
|
}
|
|
1224
1227
|
return {
|
|
1225
|
-
missing:
|
|
1226
|
-
stale:
|
|
1228
|
+
missing: u.sort(),
|
|
1229
|
+
stale: d.sort(),
|
|
1227
1230
|
functionOutdated: i,
|
|
1228
1231
|
compared: {
|
|
1229
1232
|
schema: a,
|
|
1230
1233
|
channel: n,
|
|
1231
|
-
present:
|
|
1234
|
+
present: l.size
|
|
1232
1235
|
}
|
|
1233
1236
|
};
|
|
1234
1237
|
}), $n = (e) => {
|
|
@@ -1285,12 +1288,12 @@ BEGIN
|
|
|
1285
1288
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1286
1289
|
let i = [...n].sort(), a = [...r].sort();
|
|
1287
1290
|
return i.every((e, t) => e === a[t]);
|
|
1288
|
-
}, or = (e, t, n, r) => n === void 0 ||
|
|
1291
|
+
}, or = (e, t, n, r) => n === void 0 || p(n) ? !0 : e.type !== "text" || !On(t) || zn(e, n, r) === t.maxLength, sr = (e, t, n, r, i = !1) => (!jn(e) || e.type === t.type || An(e, t, i)) && kn(e, i).idStorage === kn(t, !1).idStorage && e.nullable === t.nullable && (e.unique === t.unique || An(e, t, i)) && e.jsonValidation === t.jsonValidation && (t.enumValues === void 0 || e.enumValues === void 0 || e.enumValues.length === t.enumValues.length && e.enumValues.every((e) => t.enumValues.includes(e))) && (t.precision === void 0 || e.precision === t.precision && (e.scale ?? 0) === (t.scale ?? 0)) && Nn(e.spatial, t.spatial) && (e.storageType !== void 0 || t.storageType !== void 0 || t.arrayElement === void 0 || e.arrayElement === void 0 || e.arrayElement === t.arrayElement) && (t.vectorDim === void 0 || e.vectorDim === t.vectorDim) && (e.vectorPrecision ?? "float32") === (t.vectorPrecision ?? "float32") && ir(e, t) && or(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(Rn(e.references)) === JSON.stringify(Rn(t.references)) && ar(e.oneOf, t.oneOf), cr = (e, t) => t.oneOf && t.oneOf.length > 0 ? B({
|
|
1289
1292
|
kind: "add-check",
|
|
1290
1293
|
table: e,
|
|
1291
1294
|
column: t.name,
|
|
1292
1295
|
values: t.oneOf
|
|
1293
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, lr = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && xn(e.where) === xn(t.where) && JSON.stringify(
|
|
1296
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, lr = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && xn(e.where) === xn(t.where) && JSON.stringify(Se(e.kind, e.kindOptions)) === JSON.stringify(Se(t.kind, t.kindOptions)) && (e.expression ?? !1) === (t.expression ?? !1) && (e.expression === !0 && t.expression === !0 || e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), ur = (e, t, n) => {
|
|
1294
1297
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [], c = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1295
1298
|
for (let t of e.columns) {
|
|
1296
1299
|
let i = r.get(t.name);
|
|
@@ -1323,7 +1326,7 @@ BEGIN
|
|
|
1323
1326
|
added: o,
|
|
1324
1327
|
removed: s
|
|
1325
1328
|
};
|
|
1326
|
-
},
|
|
1329
|
+
}, B = (e, t, n, r) => ({
|
|
1327
1330
|
op: e,
|
|
1328
1331
|
classification: t,
|
|
1329
1332
|
atomicByDialect: nr(e.kind),
|
|
@@ -1335,21 +1338,21 @@ BEGIN
|
|
|
1335
1338
|
table: e,
|
|
1336
1339
|
column: t
|
|
1337
1340
|
};
|
|
1338
|
-
return t.nullable ?
|
|
1341
|
+
return t.nullable ? B(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? B(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? B(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : B(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` });
|
|
1339
1342
|
}, pr = (e, t, n) => {
|
|
1340
1343
|
let r = {
|
|
1341
1344
|
kind: "drop-column",
|
|
1342
1345
|
table: e,
|
|
1343
1346
|
column: t.name
|
|
1344
1347
|
};
|
|
1345
|
-
return n?.dropped ?
|
|
1346
|
-
}, mr = (e, t, n, r, i) =>
|
|
1348
|
+
return n?.dropped ? B(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : B(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1349
|
+
}, mr = (e, t, n, r, i) => B({
|
|
1347
1350
|
kind: "create-table",
|
|
1348
1351
|
table: e,
|
|
1349
1352
|
columns: t,
|
|
1350
1353
|
indexes: n,
|
|
1351
1354
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1352
|
-
}, "safe", i ?? "new table — no data to preserve"), hr = (e) =>
|
|
1355
|
+
}, "safe", i ?? "new table — no data to preserve"), hr = (e) => B({
|
|
1353
1356
|
kind: "drop-table",
|
|
1354
1357
|
table: e
|
|
1355
1358
|
}, "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" }), gr = 5e4, _r = (e, t, n, r) => {
|
|
@@ -1367,12 +1370,12 @@ BEGIN
|
|
|
1367
1370
|
table: e,
|
|
1368
1371
|
name: t.name,
|
|
1369
1372
|
fields: t.columns
|
|
1370
|
-
}, i ?
|
|
1371
|
-
}, vr = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ?
|
|
1373
|
+
}, i ? B(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : B(a, "safe", t.where === void 0 ? t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : `add ${t.kind === void 0 || t.kind === "btree" ? "B-tree" : t.kind.toUpperCase()} index` : `add ${t.unique ? "unique " : ""}partial index`);
|
|
1374
|
+
}, vr = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ? B({
|
|
1372
1375
|
kind: "drop-unique-composite",
|
|
1373
1376
|
table: e,
|
|
1374
1377
|
name: t.name
|
|
1375
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1378
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : B({
|
|
1376
1379
|
kind: "drop-index",
|
|
1377
1380
|
table: e,
|
|
1378
1381
|
index: t.name
|
|
@@ -1380,7 +1383,7 @@ BEGIN
|
|
|
1380
1383
|
let n = e.type;
|
|
1381
1384
|
if (n === "id") return Dn(e) === "numeric" ? "bigint" : "text";
|
|
1382
1385
|
if (n === "array") return t === void 0 || t === "postgres" ? "array" : t === "mysql" || t === "mariadb" ? "json" : "text";
|
|
1383
|
-
if (n === "enum") return t === "mssql" ||
|
|
1386
|
+
if (n === "enum") return t === "mssql" || p(t ?? "postgres") ? "text" : "enum";
|
|
1384
1387
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
1385
1388
|
switch (t) {
|
|
1386
1389
|
case "sqlite":
|
|
@@ -1400,7 +1403,7 @@ BEGIN
|
|
|
1400
1403
|
column: t.name,
|
|
1401
1404
|
toNullable: t.nullable
|
|
1402
1405
|
};
|
|
1403
|
-
o.push(t.nullable ?
|
|
1406
|
+
o.push(t.nullable ? B(n, "safe", `loosen ${e}.${t.name} to nullable`) : B(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1404
1407
|
}
|
|
1405
1408
|
if (t.unique !== n.unique) {
|
|
1406
1409
|
if (t.unique) {
|
|
@@ -1409,8 +1412,8 @@ BEGIN
|
|
|
1409
1412
|
table: e,
|
|
1410
1413
|
column: t.name
|
|
1411
1414
|
}, r = (i ?? 0) >= a;
|
|
1412
|
-
o.push(r ?
|
|
1413
|
-
} else o.push(
|
|
1415
|
+
o.push(r ? B(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : B(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1416
|
+
} else o.push(B({
|
|
1414
1417
|
kind: "drop-unique",
|
|
1415
1418
|
table: e,
|
|
1416
1419
|
column: t.name
|
|
@@ -1427,7 +1430,7 @@ BEGIN
|
|
|
1427
1430
|
to: t.type,
|
|
1428
1431
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1429
1432
|
};
|
|
1430
|
-
o.push(
|
|
1433
|
+
o.push(B(r, "needs-backfill", `type change ${n.type} → ${t.type} on ${e}.${t.name} — narrowedFrom('${i.from}') declared` + (i.using ? ` with USING ${i.using}` : " (implicit cast)")));
|
|
1431
1434
|
} else {
|
|
1432
1435
|
let i = {
|
|
1433
1436
|
kind: "alter-column-type",
|
|
@@ -1436,12 +1439,12 @@ BEGIN
|
|
|
1436
1439
|
from: n.type,
|
|
1437
1440
|
to: t.type
|
|
1438
1441
|
};
|
|
1439
|
-
o.push(
|
|
1442
|
+
o.push(B(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: br(n.type, t, r) }));
|
|
1440
1443
|
}
|
|
1441
1444
|
}
|
|
1442
|
-
if (t.type === "text" && On(n) && !
|
|
1445
|
+
if (t.type === "text" && On(n) && !p(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1443
1446
|
let r = t.maxLength === void 0 || n.maxLength !== void 0 && t.maxLength > n.maxLength, i = n.maxLength === void 0 ? "unbounded" : `varchar(${n.maxLength})`, a = t.maxLength === void 0 ? "unbounded" : `varchar(${t.maxLength})`;
|
|
1444
|
-
o.push(
|
|
1447
|
+
o.push(B({
|
|
1445
1448
|
kind: "alter-column-type",
|
|
1446
1449
|
table: e,
|
|
1447
1450
|
column: t.name,
|
|
@@ -1452,7 +1455,7 @@ BEGIN
|
|
|
1452
1455
|
if (t.type === "enum" && n.type === "enum" && n.enumValues !== void 0 && t.enumValues !== void 0) {
|
|
1453
1456
|
let r = new Set(n.enumValues);
|
|
1454
1457
|
new Set(t.enumValues);
|
|
1455
|
-
for (let n of t.enumValues) r.has(n) || o.push(
|
|
1458
|
+
for (let n of t.enumValues) r.has(n) || o.push(B({
|
|
1456
1459
|
kind: "add-enum-value",
|
|
1457
1460
|
table: e,
|
|
1458
1461
|
column: t.name,
|
|
@@ -1462,7 +1465,7 @@ BEGIN
|
|
|
1462
1465
|
}
|
|
1463
1466
|
if (!Nn(t.spatial, n.spatial)) {
|
|
1464
1467
|
let r = t.spatial, i = n.spatial, a = (e) => e === void 0 ? "plain text" : `${e.kind}(${e.geomKind},${String(e.srid)})`, s = r !== void 0 && i !== void 0 && r.kind === i.kind && r.geomKind.toUpperCase() === i.geomKind.toUpperCase() && r.srid !== i.srid, c = r === void 0 ? void 0 : r.kind === "geography" ? `ST_Transform("${t.name}"::geometry, ${String(r.srid)})::geography` : `ST_Transform("${t.name}", ${String(r.srid)})`, l = t.narrowedFrom, u = l !== void 0 && l.from === n.type, d = s ? c : u ? l.using : void 0;
|
|
1465
|
-
o.push(
|
|
1468
|
+
o.push(B({
|
|
1466
1469
|
kind: "alter-column-type",
|
|
1467
1470
|
table: e,
|
|
1468
1471
|
column: t.name,
|
|
@@ -1473,7 +1476,7 @@ BEGIN
|
|
|
1473
1476
|
}
|
|
1474
1477
|
if (t.type === "array" && n.type === "array" && n.arrayElement !== void 0 && t.arrayElement !== void 0 && t.arrayElement !== n.arrayElement) {
|
|
1475
1478
|
let r = t.narrowedFrom, i = r !== void 0 && r.from === n.type;
|
|
1476
|
-
o.push(
|
|
1479
|
+
o.push(B({
|
|
1477
1480
|
kind: "alter-column-type",
|
|
1478
1481
|
table: e,
|
|
1479
1482
|
column: t.name,
|
|
@@ -1484,7 +1487,7 @@ BEGIN
|
|
|
1484
1487
|
}
|
|
1485
1488
|
if (t.type === "vector" && n.type === "vector" && (n.vectorDim !== void 0 && t.vectorDim !== n.vectorDim || (t.vectorPrecision ?? "float32") !== (n.vectorPrecision ?? "float32"))) {
|
|
1486
1489
|
let r = (e) => `${e.vectorPrecision === "half" ? "halfvec" : "vector"}(${String(e.vectorDim ?? "?")})`, i = t.narrowedFrom, a = i !== void 0 && i.from === n.type;
|
|
1487
|
-
o.push(
|
|
1490
|
+
o.push(B({
|
|
1488
1491
|
kind: "alter-column-type",
|
|
1489
1492
|
table: e,
|
|
1490
1493
|
column: t.name,
|
|
@@ -1495,7 +1498,7 @@ BEGIN
|
|
|
1495
1498
|
}
|
|
1496
1499
|
if (t.type === "decimal" && n.type === "decimal" && n.precision !== void 0 && (t.precision !== n.precision || (t.scale ?? 0) !== (n.scale ?? 0))) {
|
|
1497
1500
|
let r = (e) => `${String(e.precision)},${String(e.scale ?? 0)}`, i = t.precision !== void 0 && n.precision !== void 0 && t.precision - (t.scale ?? 0) >= n.precision - (n.scale ?? 0) && (t.scale ?? 0) >= (n.scale ?? 0);
|
|
1498
|
-
o.push(
|
|
1501
|
+
o.push(B({
|
|
1499
1502
|
kind: "alter-column-type",
|
|
1500
1503
|
table: e,
|
|
1501
1504
|
column: t.name,
|
|
@@ -1511,11 +1514,11 @@ BEGIN
|
|
|
1511
1514
|
hasDefault: t.hasDefault,
|
|
1512
1515
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1513
1516
|
};
|
|
1514
|
-
o.push(
|
|
1517
|
+
o.push(B(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1515
1518
|
}
|
|
1516
1519
|
if (r === "mssql" && t.jsonValidation !== void 0 && t.jsonValidation !== "unverified" && t.jsonValidation !== n.jsonValidation) {
|
|
1517
1520
|
let r = t.jsonValidation === "value" && n.jsonValidation === "container";
|
|
1518
|
-
o.push(
|
|
1521
|
+
o.push(B({
|
|
1519
1522
|
kind: "reconcile-json-check",
|
|
1520
1523
|
table: e,
|
|
1521
1524
|
column: t.name,
|
|
@@ -1525,7 +1528,7 @@ BEGIN
|
|
|
1525
1528
|
}, r ? "safe" : "needs-backfill", r ? `allow every JSON value on ${e}.${t.name}; preserve existing rows` : `validate existing JSON on ${e}.${t.name}; invalid rows refuse the migration without being rewritten`));
|
|
1526
1529
|
}
|
|
1527
1530
|
if (!ar(t.oneOf, n.oneOf)) {
|
|
1528
|
-
n.oneOf && n.oneOf.length > 0 && o.push(
|
|
1531
|
+
n.oneOf && n.oneOf.length > 0 && o.push(B({
|
|
1529
1532
|
kind: "drop-check",
|
|
1530
1533
|
table: e,
|
|
1531
1534
|
column: t.name
|
|
@@ -1533,7 +1536,7 @@ BEGIN
|
|
|
1533
1536
|
let r = cr(e, t);
|
|
1534
1537
|
r && o.push(r);
|
|
1535
1538
|
}
|
|
1536
|
-
return JSON.stringify(Rn(t.references)) !== JSON.stringify(Rn(n.references)) && (n.references && o.push(
|
|
1539
|
+
return JSON.stringify(Rn(t.references)) !== JSON.stringify(Rn(n.references)) && (n.references && o.push(B({
|
|
1537
1540
|
kind: "drop-foreign-key",
|
|
1538
1541
|
table: e,
|
|
1539
1542
|
column: t.name
|
|
@@ -1550,15 +1553,15 @@ BEGIN
|
|
|
1550
1553
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1551
1554
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1552
1555
|
};
|
|
1553
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1556
|
+
return i === "null" && !t.nullable ? n.push(B(a, "lossy", `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' needs a nullable column (the NULL-out would violate NOT NULL)`, { fix: `make ${t.name} \`.nullable()\`, OR use \`orphanPolicy: 'delete'\`, OR clean the orphans and drop the policy` })) : i === "null" || i === "delete" ? n.push(B({
|
|
1554
1557
|
...a,
|
|
1555
1558
|
orphanPolicy: i
|
|
1556
|
-
}, "lossy", i === "delete" ? `add FK ${e}.${t.name} → ${r}: orphanPolicy 'delete' first DELETES rows whose ${t.name} points at a missing ${r}` : `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' first NULLs ${t.name} where it points at a missing ${r}`)) : n.push(
|
|
1559
|
+
}, "lossy", i === "delete" ? `add FK ${e}.${t.name} → ${r}: orphanPolicy 'delete' first DELETES rows whose ${t.name} points at a missing ${r}` : `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' first NULLs ${t.name} where it points at a missing ${r}`)) : n.push(B(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1557
1560
|
}, Cr = (e, t, n) => {
|
|
1558
1561
|
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));
|
|
1559
1562
|
for (let [n, c] of Object.entries(t)) {
|
|
1560
1563
|
let t = c.renamedFrom;
|
|
1561
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1564
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(B({
|
|
1562
1565
|
kind: "rename-column",
|
|
1563
1566
|
table: e.tableName,
|
|
1564
1567
|
from: t,
|
|
@@ -1589,7 +1592,7 @@ BEGIN
|
|
|
1589
1592
|
let r = o(n), i = a.filter((e) => !l.has(e.name) && s(e) === r);
|
|
1590
1593
|
if (i.length !== 1) continue;
|
|
1591
1594
|
let d = i[0];
|
|
1592
|
-
d.name !== n.name && (l.add(d.name), u.add(n.name), c.push(
|
|
1595
|
+
d.name !== n.name && (l.add(d.name), u.add(n.name), c.push(B({
|
|
1593
1596
|
kind: "rename-index",
|
|
1594
1597
|
table: e,
|
|
1595
1598
|
from: n.name,
|
|
@@ -1612,7 +1615,7 @@ BEGIN
|
|
|
1612
1615
|
continue;
|
|
1613
1616
|
}
|
|
1614
1617
|
if (t.has(c.name)) {
|
|
1615
|
-
r.push(
|
|
1618
|
+
r.push(B({
|
|
1616
1619
|
kind: "rename-table",
|
|
1617
1620
|
from: e,
|
|
1618
1621
|
to: c.name
|
|
@@ -1620,14 +1623,14 @@ BEGIN
|
|
|
1620
1623
|
continue;
|
|
1621
1624
|
}
|
|
1622
1625
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1623
|
-
r.push(
|
|
1626
|
+
r.push(B({
|
|
1624
1627
|
kind: "rename-table",
|
|
1625
1628
|
from: e,
|
|
1626
1629
|
to: c.name
|
|
1627
1630
|
}, "needs-rename-annotation", `.renamedFrom('${e}') is claimed by ${s.get(e)} tables — nothing says which receives its rows`, { fix: `remove the \`.renamedFrom('${e}')\` marker from all but one of them.` }));
|
|
1628
1631
|
continue;
|
|
1629
1632
|
}
|
|
1630
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1633
|
+
i.set(c.name, e), a.add(e), r.push(B({
|
|
1631
1634
|
kind: "rename-table",
|
|
1632
1635
|
from: e,
|
|
1633
1636
|
to: c.name
|
|
@@ -1653,7 +1656,7 @@ BEGIN
|
|
|
1653
1656
|
...e,
|
|
1654
1657
|
name: r,
|
|
1655
1658
|
table: n
|
|
1656
|
-
} : i ? (a.push(
|
|
1659
|
+
} : i ? (a.push(B({
|
|
1657
1660
|
kind: "rename-index",
|
|
1658
1661
|
table: n,
|
|
1659
1662
|
from: e.name,
|
|
@@ -1706,7 +1709,7 @@ BEGIN
|
|
|
1706
1709
|
}
|
|
1707
1710
|
return t;
|
|
1708
1711
|
}, jr = (e) => {
|
|
1709
|
-
let t =
|
|
1712
|
+
let t = z(e.declared, e.dialect), n = rr(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? gr, a = [], o = Or(t, r, n);
|
|
1710
1713
|
a.push(...o.ops);
|
|
1711
1714
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1712
1715
|
a.push(mr(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
@@ -1721,11 +1724,11 @@ BEGIN
|
|
|
1721
1724
|
c.push(t.name);
|
|
1722
1725
|
continue;
|
|
1723
1726
|
}
|
|
1724
|
-
if (
|
|
1727
|
+
if (T(t.name)) {
|
|
1725
1728
|
c.push(t.name);
|
|
1726
1729
|
continue;
|
|
1727
1730
|
}
|
|
1728
|
-
if (
|
|
1731
|
+
if (ie(t.name)) {
|
|
1729
1732
|
c.push(t.name);
|
|
1730
1733
|
continue;
|
|
1731
1734
|
}
|
|
@@ -1751,10 +1754,10 @@ BEGIN
|
|
|
1751
1754
|
}, e.dialect, u.rowCount, i));
|
|
1752
1755
|
}
|
|
1753
1756
|
for (let e of f.removed) {
|
|
1754
|
-
if (m.consumedRemovedNames.has(e.name) ||
|
|
1757
|
+
if (m.consumedRemovedNames.has(e.name) || ie(e.name)) continue;
|
|
1755
1758
|
let t = d.columnDefs[e.name], n = pr(s.name, e, t);
|
|
1756
1759
|
e.references !== void 0 && a.push({
|
|
1757
|
-
...
|
|
1760
|
+
...B({
|
|
1758
1761
|
kind: "drop-foreign-key",
|
|
1759
1762
|
table: s.name,
|
|
1760
1763
|
column: e.name,
|
|
@@ -1782,8 +1785,8 @@ BEGIN
|
|
|
1782
1785
|
column: e.name,
|
|
1783
1786
|
target: e.references.table
|
|
1784
1787
|
}] : []) : [];
|
|
1785
|
-
}, f =
|
|
1786
|
-
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) t.references && f.has(k(e.name, t.name)) && p.push(
|
|
1788
|
+
}, f = je([...l], d), p = [];
|
|
1789
|
+
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) t.references && f.has(k(e.name, t.name)) && p.push(B({
|
|
1787
1790
|
kind: "add-foreign-key",
|
|
1788
1791
|
table: e.name,
|
|
1789
1792
|
column: t.name,
|
|
@@ -1859,12 +1862,12 @@ BEGIN
|
|
|
1859
1862
|
for (let e of t.tables) {
|
|
1860
1863
|
if (S.has(e.name) || o.renamedInto.has(e.name)) continue;
|
|
1861
1864
|
let t = r.get(e.name);
|
|
1862
|
-
t !== void 0 &&
|
|
1865
|
+
t !== void 0 && R({ tables: [t] }) !== R({ tables: [e] }) && C.push(e.name);
|
|
1863
1866
|
}
|
|
1864
1867
|
return {
|
|
1865
1868
|
operations: x,
|
|
1866
|
-
fromFingerprint:
|
|
1867
|
-
toFingerprint:
|
|
1869
|
+
fromFingerprint: R(e.live),
|
|
1870
|
+
toFingerprint: R(t),
|
|
1868
1871
|
summary: Ar(x),
|
|
1869
1872
|
fingerprintDivergence: {
|
|
1870
1873
|
outsideDiff: c,
|
|
@@ -1941,7 +1944,7 @@ BEGIN
|
|
|
1941
1944
|
}, Ir = (e) => e === void 0 ? void 0 : Fr[e], Lr = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1942
1945
|
expr: e,
|
|
1943
1946
|
stored: t
|
|
1944
|
-
} },
|
|
1947
|
+
} }, V = (e) => {
|
|
1945
1948
|
switch (e.toUpperCase()) {
|
|
1946
1949
|
case "CASCADE": return "cascade";
|
|
1947
1950
|
case "RESTRICT": return "restrict";
|
|
@@ -2110,7 +2113,7 @@ BEGIN
|
|
|
2110
2113
|
AND c.relname IN ${t}
|
|
2111
2114
|
)
|
|
2112
2115
|
SELECT * FROM ix ORDER BY table_name, index_name, position
|
|
2113
|
-
`), S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), ee = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(),
|
|
2116
|
+
`), S = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), ee = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), te = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Map();
|
|
2114
2117
|
for (let e of u) {
|
|
2115
2118
|
let t = S.get(e.table_name);
|
|
2116
2119
|
t || (t = [], S.set(e.table_name, t)), t.push(e);
|
|
@@ -2146,23 +2149,23 @@ BEGIN
|
|
|
2146
2149
|
}
|
|
2147
2150
|
}
|
|
2148
2151
|
for (let e of b) {
|
|
2149
|
-
let t =
|
|
2150
|
-
t || (t = [],
|
|
2152
|
+
let t = te.get(e.source_table);
|
|
2153
|
+
t || (t = [], te.set(e.source_table, t)), t.push(e);
|
|
2151
2154
|
}
|
|
2152
2155
|
for (let e of x) {
|
|
2153
|
-
let t =
|
|
2154
|
-
t || (t = /* @__PURE__ */ new Map(),
|
|
2156
|
+
let t = T.get(e.table_name);
|
|
2157
|
+
t || (t = /* @__PURE__ */ new Map(), T.set(e.table_name, t));
|
|
2155
2158
|
let n = t.get(e.index_name);
|
|
2156
2159
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
2157
2160
|
}
|
|
2158
2161
|
let E = [];
|
|
2159
2162
|
for (let e of c) {
|
|
2160
|
-
let t = /* @__PURE__ */ new Set(), n = (S.get(e.table_name) ?? []).filter((e) => !t.has(e.column_name) && (t.add(e.column_name), !0)), r = C.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = ee.get(e.table_name) ?? /* @__PURE__ */ new Set(), a =
|
|
2163
|
+
let t = /* @__PURE__ */ new Set(), n = (S.get(e.table_name) ?? []).filter((e) => !t.has(e.column_name) && (t.add(e.column_name), !0)), r = C.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = ee.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = te.get(e.table_name) ?? [], o = new Map(a.map((e) => [e.source_column, e])), s = new Set(n.filter((e) => e.udt_name === "tsvector").map((e) => e.column_name)), c = n.filter((e) => !s.has(e.column_name)).map((t) => {
|
|
2161
2164
|
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = t.data_type === "USER-DEFINED" && t.udt_name !== void 0 && g.has(t.udt_name), c = s ? "enum" : Pr(t.data_type, t.udt_name), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : c, d = a ? {
|
|
2162
2165
|
table: a.target_table,
|
|
2163
2166
|
column: a.target_column,
|
|
2164
|
-
onDelete:
|
|
2165
|
-
onUpdate:
|
|
2167
|
+
onDelete: V(a.delete_rule),
|
|
2168
|
+
onUpdate: V(a.update_rule),
|
|
2166
2169
|
constraintName: a.constraint_name
|
|
2167
2170
|
} : void 0, f = y.get(`${e.table_name}.${t.column_name}`);
|
|
2168
2171
|
return {
|
|
@@ -2179,7 +2182,7 @@ BEGIN
|
|
|
2179
2182
|
vectorPrecision: t.udt_name === "halfvec" ? "half" : "float32",
|
|
2180
2183
|
...t.type_modifier !== void 0 && t.type_modifier > 0 ? { vectorDim: t.type_modifier } : {}
|
|
2181
2184
|
} : {},
|
|
2182
|
-
...
|
|
2185
|
+
...ti(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: ti(t.data_type, t.character_maximum_length) },
|
|
2183
2186
|
...c === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2184
2187
|
precision: t.numeric_precision,
|
|
2185
2188
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2193,7 +2196,7 @@ BEGIN
|
|
|
2193
2196
|
...f ? { oneOf: f } : {},
|
|
2194
2197
|
...Lr(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
2195
2198
|
};
|
|
2196
|
-
}), l = [], u =
|
|
2199
|
+
}), l = [], u = T.get(e.table_name);
|
|
2197
2200
|
if (u) for (let [t, n] of u) {
|
|
2198
2201
|
let r = /* @__PURE__ */ new Set(), i = [...n].filter((e) => e.column_name !== null && e.position !== null).sort((e, t) => (e.position ?? 0) - (t.position ?? 0)).filter((e) => {
|
|
2199
2202
|
let t = e.position;
|
|
@@ -2210,7 +2213,7 @@ BEGIN
|
|
|
2210
2213
|
table: e.table_name,
|
|
2211
2214
|
columns: i.map((e) => e.column_name),
|
|
2212
2215
|
unique: n[0]?.is_unique ?? !1,
|
|
2213
|
-
...
|
|
2216
|
+
...Se(o?.access_method, o?.access_method === "hnsw" ? { hnsw: {
|
|
2214
2217
|
opclass: o.operator_class,
|
|
2215
2218
|
m: c.get("m") ?? 16,
|
|
2216
2219
|
efConstruction: c.get("ef_construction") ?? 64
|
|
@@ -2345,8 +2348,8 @@ BEGIN
|
|
|
2345
2348
|
let n = i.includes(t.column_name) && i.length === 1, o = r.get(t.column_name), s = c.has(`${e.table_name}.${t.column_name}`) ? "json" : Wr(t.data_type, t.column_type), u = !o && n && t.column_name === "id", d = o ? "reference" : u ? "id" : s, f = o ? {
|
|
2346
2349
|
table: o.target_table,
|
|
2347
2350
|
column: o.target_column,
|
|
2348
|
-
onDelete:
|
|
2349
|
-
onUpdate:
|
|
2351
|
+
onDelete: V(o.delete_rule),
|
|
2352
|
+
onUpdate: V(o.update_rule),
|
|
2350
2353
|
constraintName: o.constraint_name
|
|
2351
2354
|
} : void 0, p = a.has(t.column_name) || n && t.column_name === "id", m = t.column_default === "NULL" ? null : t.column_default, h = l.get(`${e.table_name}.${t.column_name}`), g = t.data_type.toLowerCase() === "enum" ? [...t.column_type.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")) : void 0;
|
|
2352
2355
|
return {
|
|
@@ -2355,7 +2358,7 @@ BEGIN
|
|
|
2355
2358
|
...u ? { idStorage: wn(s) } : {},
|
|
2356
2359
|
...d === "enum" && g !== void 0 ? { enumValues: g } : {},
|
|
2357
2360
|
nullable: t.is_nullable === "YES",
|
|
2358
|
-
...
|
|
2361
|
+
...ti(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: ti(t.data_type, t.character_maximum_length) },
|
|
2359
2362
|
...s === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2360
2363
|
precision: t.numeric_precision,
|
|
2361
2364
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2420,8 +2423,8 @@ BEGIN
|
|
|
2420
2423
|
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = qr(e.type), a = !r && n && e.name === "id", o = r ? "reference" : a ? "id" : i, s = r ? {
|
|
2421
2424
|
table: r.table,
|
|
2422
2425
|
column: r.to,
|
|
2423
|
-
onDelete:
|
|
2424
|
-
onUpdate:
|
|
2426
|
+
onDelete: V(r.on_delete),
|
|
2427
|
+
onUpdate: V(r.on_update)
|
|
2425
2428
|
} : void 0, c = t.get(e.name);
|
|
2426
2429
|
return {
|
|
2427
2430
|
name: e.name,
|
|
@@ -2482,7 +2485,7 @@ BEGIN
|
|
|
2482
2485
|
case "image": return "bytes";
|
|
2483
2486
|
default: return "text";
|
|
2484
2487
|
}
|
|
2485
|
-
},
|
|
2488
|
+
}, H = (e) => e === !0 || e === 1, Zr = (e) => D.gen(function* () {
|
|
2486
2489
|
let t = yield* e`
|
|
2487
2490
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2488
2491
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -2547,8 +2550,8 @@ BEGIN
|
|
|
2547
2550
|
let t = l.get(e) ?? [], n = u.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), a = new Set(n.map((e) => e.source_column)), o = d.get(e), p = [], m = /* @__PURE__ */ new Set();
|
|
2548
2551
|
if (o) for (let [, e] of o) {
|
|
2549
2552
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2550
|
-
if (
|
|
2551
|
-
else t[0].predicate == null &&
|
|
2553
|
+
if (H(t[0].is_primary)) for (let e of t) p.push(e.column_name);
|
|
2554
|
+
else t[0].predicate == null && H(t[0].is_unique) && t.length === 1 && m.add(t[0].column_name);
|
|
2552
2555
|
}
|
|
2553
2556
|
let h = t.map((t) => {
|
|
2554
2557
|
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o = Xr(t.data_type), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : o, d = a ? {
|
|
@@ -2563,8 +2566,8 @@ BEGIN
|
|
|
2563
2566
|
return r ? [{
|
|
2564
2567
|
name: n.constraint_name,
|
|
2565
2568
|
validation: r,
|
|
2566
|
-
enabled: !
|
|
2567
|
-
trusted: !
|
|
2569
|
+
enabled: !H(n.is_disabled),
|
|
2570
|
+
trusted: !H(n.is_not_trusted)
|
|
2568
2571
|
}] : [];
|
|
2569
2572
|
}).sort((e, t) => e.name.localeCompare(t.name)), _ = yt(g);
|
|
2570
2573
|
return {
|
|
@@ -2572,7 +2575,7 @@ BEGIN
|
|
|
2572
2575
|
type: u,
|
|
2573
2576
|
...l ? { idStorage: wn(o) } : {},
|
|
2574
2577
|
nullable: t.is_nullable === "YES",
|
|
2575
|
-
...
|
|
2578
|
+
...ti(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: ti(t.data_type, t.character_maximum_length) },
|
|
2576
2579
|
...o === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2577
2580
|
precision: t.numeric_precision,
|
|
2578
2581
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2585,18 +2588,18 @@ BEGIN
|
|
|
2585
2588
|
...h ? { oneOf: h } : {},
|
|
2586
2589
|
...g.length > 0 ? { jsonChecks: g } : {},
|
|
2587
2590
|
..._ ? { jsonValidation: _ } : {},
|
|
2588
|
-
...Lr(i.get(`${e}.${t.column_name}`)?.definition ?? null,
|
|
2591
|
+
...Lr(i.get(`${e}.${t.column_name}`)?.definition ?? null, H(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2589
2592
|
};
|
|
2590
2593
|
}), g = [];
|
|
2591
2594
|
if (o) for (let [t, n] of o) {
|
|
2592
2595
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2593
|
-
if (
|
|
2596
|
+
if (H(r[0].is_primary)) continue;
|
|
2594
2597
|
let i = r[0].predicate ?? void 0;
|
|
2595
|
-
i === void 0 && r.length === 1 &&
|
|
2598
|
+
i === void 0 && r.length === 1 && H(r[0].is_unique) || (i !== void 0 || r.length !== 1 || H(r[0].is_unique) || !a.has(r[0].column_name) || t === `${e}_${r[0].column_name}_idx`) && g.push({
|
|
2596
2599
|
name: t,
|
|
2597
2600
|
table: e,
|
|
2598
2601
|
columns: r.map((e) => e.column_name),
|
|
2599
|
-
unique:
|
|
2602
|
+
unique: H(r[0].is_unique),
|
|
2600
2603
|
...i === void 0 ? {} : { where: i }
|
|
2601
2604
|
});
|
|
2602
2605
|
}
|
|
@@ -2630,72 +2633,72 @@ BEGIN
|
|
|
2630
2633
|
"char",
|
|
2631
2634
|
"character",
|
|
2632
2635
|
"nchar"
|
|
2633
|
-
]),
|
|
2636
|
+
]), ti = (e, t) => {
|
|
2634
2637
|
if (!ei.has(e.toLowerCase())) return;
|
|
2635
2638
|
let n = Number(t);
|
|
2636
2639
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2637
|
-
},
|
|
2640
|
+
}, ni = /* @__PURE__ */ new Set([j]), ri = (e) => e.onDialectOrElse({
|
|
2638
2641
|
mysql: () => Kr(e),
|
|
2639
2642
|
mssql: () => Zr(e),
|
|
2640
2643
|
sqlite: () => Yr(e),
|
|
2641
2644
|
orElse: () => Ur(e)
|
|
2642
2645
|
}).pipe(D.map((e) => ({
|
|
2643
2646
|
...e,
|
|
2644
|
-
tables: e.tables.filter((e) => !
|
|
2645
|
-
}))),
|
|
2646
|
-
let t =
|
|
2647
|
-
return t === void 0 ?
|
|
2648
|
-
}),
|
|
2647
|
+
tables: e.tables.filter((e) => !ni.has(e.name))
|
|
2648
|
+
}))), ii = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", ai = /* @__PURE__ */ new WeakMap(), oi = (e) => D.suspend(() => {
|
|
2649
|
+
let t = ai.get(e);
|
|
2650
|
+
return t === void 0 ? si(e).pipe(D.tap((t) => D.sync(() => ai.set(e, t)))) : D.succeed(t);
|
|
2651
|
+
}), si = (e) => e.unsafe("SELECT VERSION() AS v").pipe(D.map((e) => {
|
|
2649
2652
|
let t = e[0]?.v;
|
|
2650
|
-
return typeof t == "string" ?
|
|
2651
|
-
}), D.catchAll(() => D.succeed("mysql"))), U = "_voltro_deploys",
|
|
2652
|
-
id:
|
|
2653
|
-
status:
|
|
2654
|
-
dialect:
|
|
2655
|
-
appliedBy:
|
|
2656
|
-
startedAt:
|
|
2657
|
-
baseline:
|
|
2658
|
-
report:
|
|
2659
|
-
}),
|
|
2660
|
-
VALUES (${t.id}, ${"running"}, ${t.dialect}, ${t.appliedBy}, ${(/* @__PURE__ */ new Date()).toISOString()}, ${t.baseline}, ${null})`.pipe(D.asVoid),
|
|
2653
|
+
return typeof t == "string" ? ii(t) : "mysql";
|
|
2654
|
+
}), D.catchAll(() => D.succeed("mysql"))), U = "_voltro_deploys", ci = i(U, {
|
|
2655
|
+
id: c({ prefix: "dpl" }),
|
|
2656
|
+
status: t(),
|
|
2657
|
+
dialect: t(),
|
|
2658
|
+
appliedBy: t(),
|
|
2659
|
+
startedAt: t(),
|
|
2660
|
+
baseline: t(),
|
|
2661
|
+
report: t().nullable()
|
|
2662
|
+
}), li = (e, t) => e`INSERT INTO ${e(U)} (${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")})
|
|
2663
|
+
VALUES (${t.id}, ${"running"}, ${t.dialect}, ${t.appliedBy}, ${(/* @__PURE__ */ new Date()).toISOString()}, ${t.baseline}, ${null})`.pipe(D.asVoid), ui = (e, t) => e`DELETE FROM ${e(U)} WHERE ${e("id")} = ${t}`.pipe(D.asVoid), di = (e, t, n) => e`UPDATE ${e(U)} SET ${e("status")} = ${"failed"}, ${e("report")} = ${n} WHERE ${e("id")} = ${t}`.pipe(D.asVoid), fi = (e) => e`SELECT ${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")} FROM ${e(U)}`.pipe(D.map((e) => e.map((e) => ({
|
|
2661
2664
|
...e,
|
|
2662
2665
|
startedAt: String(e.startedAt)
|
|
2663
|
-
}))), D.catchAll(() => D.succeed([]))),
|
|
2666
|
+
}))), D.catchAll(() => D.succeed([]))), pi = (e) => {
|
|
2664
2667
|
let t = e;
|
|
2665
2668
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2666
2669
|
let e = t;
|
|
2667
2670
|
if (typeof e.errno == "number") return e.errno;
|
|
2668
2671
|
t = e.cause;
|
|
2669
2672
|
}
|
|
2670
|
-
},
|
|
2673
|
+
}, mi = (e) => {
|
|
2671
2674
|
let t = [], n = e;
|
|
2672
2675
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2673
2676
|
let e = n;
|
|
2674
2677
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2675
2678
|
}
|
|
2676
2679
|
return t.join(" | ");
|
|
2677
|
-
},
|
|
2680
|
+
}, hi = (e, t) => {
|
|
2678
2681
|
if (t.length === 0) return !1;
|
|
2679
|
-
let n =
|
|
2682
|
+
let n = pi(e), r = mi(e);
|
|
2680
2683
|
return t.some((e) => e.errno !== void 0 && n !== void 0 && e.errno.includes(n) || e.messageIncludes !== void 0 && e.messageIncludes.some((e) => r.includes(e)));
|
|
2681
|
-
},
|
|
2684
|
+
}, gi = {
|
|
2682
2685
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2683
2686
|
errno: [1061]
|
|
2684
|
-
},
|
|
2687
|
+
}, _i = {
|
|
2685
2688
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2686
2689
|
errno: [1091]
|
|
2687
|
-
},
|
|
2690
|
+
}, vi = {
|
|
2688
2691
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2689
2692
|
messageIncludes: ["no such column"]
|
|
2690
|
-
},
|
|
2693
|
+
}, yi = {
|
|
2691
2694
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2692
2695
|
errno: [1091, 3940]
|
|
2693
|
-
},
|
|
2696
|
+
}, bi = (e, t) => D.suspend(() => {
|
|
2694
2697
|
let n;
|
|
2695
2698
|
return e.withTransaction(t.pipe(D.tapErrorCause((e) => D.sync(() => {
|
|
2696
2699
|
n = e;
|
|
2697
|
-
})))).pipe(D.catchAllCause((e) => D.failCause(n !== void 0 && !
|
|
2698
|
-
}),
|
|
2700
|
+
})))).pipe(D.catchAllCause((e) => D.failCause(n !== void 0 && !de.equals(n, e) ? ue.sequential(n, e) : e)));
|
|
2701
|
+
}), xi = (e, t, r) => {
|
|
2699
2702
|
let i = e.match(/'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|\s+|[^'\[\s]+/g) ?? [];
|
|
2700
2703
|
if (i.join("") !== e || i.some((e) => !e.startsWith("'") && !e.startsWith("[") && /"|\/\*|--/.test(e))) throw Error("Cannot safely rename CHECK: unsupported catalog SQL; use an explicit migration");
|
|
2701
2704
|
let a = i.map((e, t) => ({
|
|
@@ -2704,31 +2707,31 @@ BEGIN
|
|
|
2704
2707
|
})).filter((e) => e.value.trim() !== ""), o = 0;
|
|
2705
2708
|
for (let e = 0; e < a.length; e++) {
|
|
2706
2709
|
let s = a[e];
|
|
2707
|
-
if (s.value !==
|
|
2710
|
+
if (s.value !== n(t, "mssql")) continue;
|
|
2708
2711
|
let c = a[e - 1]?.value ?? "", l = a[e + 1]?.value ?? "";
|
|
2709
2712
|
if (c.endsWith(".") || l.startsWith(".") || l.startsWith("(")) throw Error(`Cannot safely rename CHECK reference '${t}': qualified or callable identifier; use an explicit migration`);
|
|
2710
|
-
i[s.index] = r
|
|
2713
|
+
i[s.index] = n(r, "mssql"), o++;
|
|
2711
2714
|
}
|
|
2712
2715
|
if (o === 0 || i.join("").length === 0) throw Error(`Cannot safely rename CHECK reference '${t}': no exact catalog column token; use an explicit migration`);
|
|
2713
2716
|
return i.join("");
|
|
2714
2717
|
}, W = (e, t) => e.onDialectOrElse({
|
|
2715
2718
|
mysql: () => D.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2716
2719
|
orElse: () => D.succeed(t)
|
|
2717
|
-
}),
|
|
2718
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2720
|
+
}), Si = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, Ci = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), wi = (e, t) => {
|
|
2721
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !Ci(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2719
2722
|
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;
|
|
2720
2723
|
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.`);
|
|
2721
|
-
return
|
|
2722
|
-
},
|
|
2723
|
-
let t =
|
|
2724
|
-
return t === void 0 ?
|
|
2725
|
-
},
|
|
2724
|
+
return N(e, t);
|
|
2725
|
+
}, Ti = (e) => {
|
|
2726
|
+
let t = wi(e, "postgres");
|
|
2727
|
+
return t === void 0 ? Ei(e) : t;
|
|
2728
|
+
}, Ei = (e) => {
|
|
2726
2729
|
switch (e.type) {
|
|
2727
2730
|
case "id": return "text";
|
|
2728
2731
|
case "text": return "text";
|
|
2729
2732
|
case "integer": return "integer";
|
|
2730
2733
|
case "real": return "double precision";
|
|
2731
|
-
case "decimal": return
|
|
2734
|
+
case "decimal": return Si(e, "NUMERIC");
|
|
2732
2735
|
case "bigint": return "bigint";
|
|
2733
2736
|
case "boolean": return "boolean";
|
|
2734
2737
|
case "timestamp": return "timestamptz";
|
|
@@ -2742,15 +2745,15 @@ BEGIN
|
|
|
2742
2745
|
case "interval": return "interval";
|
|
2743
2746
|
case "raw": return e.rawDdl ?? "text";
|
|
2744
2747
|
}
|
|
2745
|
-
},
|
|
2746
|
-
let t =
|
|
2748
|
+
}, Di = (e) => {
|
|
2749
|
+
let t = wi(e, "mariadb");
|
|
2747
2750
|
if (t !== void 0) return t;
|
|
2748
2751
|
switch (e.type) {
|
|
2749
2752
|
case "id": return "VARCHAR(64)";
|
|
2750
2753
|
case "text": return "LONGTEXT";
|
|
2751
2754
|
case "integer": return "INT";
|
|
2752
2755
|
case "real": return "DOUBLE";
|
|
2753
|
-
case "decimal": return
|
|
2756
|
+
case "decimal": return Si(e, "DECIMAL");
|
|
2754
2757
|
case "bigint": return "BIGINT";
|
|
2755
2758
|
case "boolean": return "TINYINT(1)";
|
|
2756
2759
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2764,38 +2767,38 @@ BEGIN
|
|
|
2764
2767
|
case "interval": return "BIGINT";
|
|
2765
2768
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2766
2769
|
}
|
|
2767
|
-
}, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2770
|
+
}, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``, Oi = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", ki = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, Ai = (e, t = "mariadb") => `ALTER TABLE ${K(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${K(e.column)}, ALGORITHM=COPY;`, ji = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Mi = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${ua(t)}`)};`, Ni = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Fi(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, Pi = (e, t) => {
|
|
2768
2771
|
let { defaultFactory: n, ...r } = e;
|
|
2769
|
-
return
|
|
2772
|
+
return N(e, t) !== N({
|
|
2770
2773
|
...r,
|
|
2771
2774
|
hasDefault: !1
|
|
2772
2775
|
}, t);
|
|
2773
|
-
},
|
|
2776
|
+
}, Fi = (e, t) => {
|
|
2774
2777
|
let n = t(e.defaultValue);
|
|
2775
2778
|
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.`);
|
|
2776
2779
|
return n;
|
|
2777
|
-
}, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2780
|
+
}, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Ii = (e, t, n) => {
|
|
2778
2781
|
let r = q(e, t, n);
|
|
2779
2782
|
return r ? qn(n, r) : void 0;
|
|
2780
|
-
},
|
|
2781
|
-
let r = n ?? e.nullable, i =
|
|
2783
|
+
}, Li = (e, t, n) => {
|
|
2784
|
+
let r = n ?? e.nullable, i = At(e, "mariadb");
|
|
2782
2785
|
return [
|
|
2783
2786
|
K(t),
|
|
2784
|
-
|
|
2787
|
+
N(e, "mariadb"),
|
|
2785
2788
|
r ? null : "NOT NULL",
|
|
2786
2789
|
i
|
|
2787
2790
|
].filter(Boolean).join(" ");
|
|
2788
|
-
},
|
|
2791
|
+
}, Ri = (e, t) => e == null ? null : Array.isArray(e) ? zi(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" ? P(e, "mariadb") : null, zi = (e, t, n) => jt(e, t ?? { type: "json" }, n), Bi = (e, t) => e == null ? null : Array.isArray(e) ? zi(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" ? P(e, "postgres") : null, Vi = (e, t) => {
|
|
2789
2792
|
if (!e.generatedAs) return null;
|
|
2790
2793
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2791
2794
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2792
|
-
},
|
|
2793
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2794
|
-
let n =
|
|
2795
|
-
if (n) return `${G(e.name)} ${
|
|
2796
|
-
let r = [G(e.name),
|
|
2795
|
+
}, Hi = (e, t = !1) => {
|
|
2796
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return F(e.name, "postgres");
|
|
2797
|
+
let n = Vi(e, "postgres");
|
|
2798
|
+
if (n) return `${G(e.name)} ${Ti(e)} ${n}`;
|
|
2799
|
+
let r = [G(e.name), Ti(e)];
|
|
2797
2800
|
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
2798
|
-
let t =
|
|
2801
|
+
let t = Bi(e.defaultValue, e);
|
|
2799
2802
|
t && r.push(t);
|
|
2800
2803
|
}
|
|
2801
2804
|
return e.references && (r.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${{
|
|
@@ -2804,28 +2807,28 @@ BEGIN
|
|
|
2804
2807
|
setNull: "SET NULL",
|
|
2805
2808
|
noAction: "NO ACTION"
|
|
2806
2809
|
}[e.references.onDelete]}`)), r.join(" ");
|
|
2807
|
-
},
|
|
2808
|
-
let t = e.columns.map((t) => ` ${
|
|
2809
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(
|
|
2810
|
+
}, Ui = (e) => (e.primaryKey?.length ?? 0) > 0, Wi = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Gi = (e) => {
|
|
2811
|
+
let t = e.columns.map((t) => ` ${Hi(t, Ui(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${Wi(e, G)}\n)`];
|
|
2812
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(_a({
|
|
2810
2813
|
kind: "add-index",
|
|
2811
2814
|
table: e.table,
|
|
2812
2815
|
index: t
|
|
2813
2816
|
}, !1));
|
|
2814
2817
|
return n;
|
|
2815
|
-
},
|
|
2816
|
-
let t =
|
|
2818
|
+
}, Ki = 191, qi = (e) => {
|
|
2819
|
+
let t = Di(e).toUpperCase();
|
|
2817
2820
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2818
|
-
},
|
|
2819
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2820
|
-
let n =
|
|
2821
|
-
if (n) return `${K(e.name)} ${
|
|
2822
|
-
let r = [K(e.name),
|
|
2823
|
-
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2824
|
-
let t =
|
|
2821
|
+
}, Ji = (e, t = !1) => {
|
|
2822
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return F(e.name, "mariadb");
|
|
2823
|
+
let n = Vi(e, "mariadb");
|
|
2824
|
+
if (n) return `${K(e.name)} ${Di(e)} ${n}`;
|
|
2825
|
+
let r = [K(e.name), Di(e)];
|
|
2826
|
+
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && !qi(e) && r.push("UNIQUE"), e.hasDefault) {
|
|
2827
|
+
let t = Ri(e.defaultValue, e);
|
|
2825
2828
|
t && r.push(t);
|
|
2826
2829
|
}
|
|
2827
2830
|
return r.join(" ");
|
|
2828
|
-
},
|
|
2831
|
+
}, Yi = (e) => e.columns.flatMap((t) => {
|
|
2829
2832
|
if (!t.references) return [];
|
|
2830
2833
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2831
2834
|
cascade: "CASCADE",
|
|
@@ -2834,27 +2837,27 @@ BEGIN
|
|
|
2834
2837
|
noAction: "NO ACTION"
|
|
2835
2838
|
}[t.references.onDelete]}` : "";
|
|
2836
2839
|
return [` CONSTRAINT ${K(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${K(t.name)}) REFERENCES ${K(t.references.table)} (${K(t.references.column)})${n}`];
|
|
2837
|
-
}),
|
|
2838
|
-
for (let n of e.indexes)
|
|
2840
|
+
}), Xi = (e, t = "mariadb") => {
|
|
2841
|
+
for (let n of e.indexes) ya(n, t);
|
|
2839
2842
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2840
|
-
let t =
|
|
2843
|
+
let t = pa(n.get(e));
|
|
2841
2844
|
return t === void 0 ? K(e) : `${K(e)}(${t})`;
|
|
2842
|
-
}, i = e.columns.map((t) => ` ${
|
|
2843
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
2844
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2845
|
+
}, i = e.columns.map((t) => ` ${Ji(t, Ui(e))}`).join(",\n"), a = Yi(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${o}${Wi(e, r)}\n)`];
|
|
2846
|
+
for (let n of e.columns) n.unique && n.type !== "id" && qi(n) && s.push(`CREATE UNIQUE INDEX ${Oi(t)}${K(`${e.table}_${n.name}_key`)} ON ${K(e.table)} (${r(n.name)})`);
|
|
2847
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Oi(t)}${K(n.name)} ON ${K(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2845
2848
|
return s;
|
|
2846
|
-
},
|
|
2849
|
+
}, Zi = {
|
|
2847
2850
|
cascade: "CASCADE",
|
|
2848
2851
|
restrict: "RESTRICT",
|
|
2849
2852
|
setNull: "SET NULL",
|
|
2850
2853
|
noAction: "NO ACTION"
|
|
2851
|
-
},
|
|
2854
|
+
}, Qi = {
|
|
2852
2855
|
cascade: "CASCADE",
|
|
2853
2856
|
restrict: "NO ACTION",
|
|
2854
2857
|
setNull: "SET NULL",
|
|
2855
2858
|
noAction: "NO ACTION"
|
|
2856
|
-
},
|
|
2857
|
-
let t =
|
|
2859
|
+
}, $i = (e) => {
|
|
2860
|
+
let t = wi(e, "sqlite");
|
|
2858
2861
|
if (t !== void 0) return t;
|
|
2859
2862
|
switch (e.type) {
|
|
2860
2863
|
case "integer":
|
|
@@ -2866,30 +2869,30 @@ BEGIN
|
|
|
2866
2869
|
case "bytes": return "BLOB";
|
|
2867
2870
|
default: return "TEXT";
|
|
2868
2871
|
}
|
|
2869
|
-
},
|
|
2870
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2871
|
-
let n =
|
|
2872
|
-
if (n) return `${G(e.name)} ${
|
|
2873
|
-
let r = [G(e.name),
|
|
2872
|
+
}, ea = (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" ? P(e, "sqlite") : null, ta = (e, t = !1) => {
|
|
2873
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return F(e.name, "sqlite");
|
|
2874
|
+
let n = Vi(e, "sqlite");
|
|
2875
|
+
if (n) return `${G(e.name)} ${$i(e)} ${n}`;
|
|
2876
|
+
let r = [G(e.name), $i(e)];
|
|
2874
2877
|
if (e.type === "id" && !t && r.push("PRIMARY KEY"), e.nullable || r.push("NOT NULL"), e.unique && e.type !== "id" && r.push("UNIQUE"), e.hasDefault) {
|
|
2875
|
-
let t =
|
|
2878
|
+
let t = ea(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2876
2879
|
t && r.push(t);
|
|
2877
2880
|
}
|
|
2878
|
-
if (e.references && (r.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${
|
|
2881
|
+
if (e.references && (r.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${Zi[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2879
2882
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2880
2883
|
r.push(`CHECK (${G(e.name)} IN (${t}))`);
|
|
2881
2884
|
}
|
|
2882
2885
|
return r.join(" ");
|
|
2883
|
-
},
|
|
2884
|
-
let t = e.columns.map((t) => ` ${
|
|
2885
|
-
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(", ")})${
|
|
2886
|
+
}, na = (e) => {
|
|
2887
|
+
let t = e.columns.map((t) => ` ${ta(t, Ui(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${Wi(e, G)}\n)`];
|
|
2888
|
+
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(", ")})${ga(t)}`);
|
|
2886
2889
|
return n;
|
|
2887
|
-
},
|
|
2890
|
+
}, ra = (e, t) => {
|
|
2888
2891
|
let n = t.find((t) => t.tableName === e);
|
|
2889
|
-
return n ?
|
|
2890
|
-
},
|
|
2892
|
+
return n ? ia(z([n], "sqlite").tables[0]) : [];
|
|
2893
|
+
}, ia = (e) => {
|
|
2891
2894
|
let t = e.name, n = `${t}__voltro_rebuild`, r = e.columns.map((e) => G(e.name)).join(", "), i = [
|
|
2892
|
-
...
|
|
2895
|
+
...na({
|
|
2893
2896
|
kind: "create-table",
|
|
2894
2897
|
table: n,
|
|
2895
2898
|
columns: e.columns,
|
|
@@ -2900,27 +2903,27 @@ BEGIN
|
|
|
2900
2903
|
`DROP TABLE ${G(t)}`,
|
|
2901
2904
|
`ALTER TABLE ${G(n)} RENAME TO ${G(t)}`
|
|
2902
2905
|
];
|
|
2903
|
-
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(n.name)} ON ${G(t)} (${n.columns.map(G).join(", ")})${
|
|
2906
|
+
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(n.name)} ON ${G(t)} (${n.columns.map(G).join(", ")})${ga(n)}`);
|
|
2904
2907
|
return i;
|
|
2905
|
-
},
|
|
2908
|
+
}, aa = (e, t, n, r) => {
|
|
2906
2909
|
let i = r ?? e.nullable;
|
|
2907
|
-
return `ALTER TABLE ${J(n)} ALTER COLUMN ${J(t)} ${
|
|
2908
|
-
},
|
|
2910
|
+
return `ALTER TABLE ${J(n)} ALTER COLUMN ${J(t)} ${N(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2911
|
+
}, oa = (e, t) => {
|
|
2909
2912
|
let n = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${J(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
2910
2913
|
if (!e.hasDefault) return n;
|
|
2911
|
-
let r =
|
|
2914
|
+
let r = ea(e.defaultValue, "SYSUTCDATETIME()");
|
|
2912
2915
|
if (!r) return n;
|
|
2913
2916
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2914
2917
|
return `${n} ALTER TABLE ${J(e.table)} ADD DEFAULT ${i} FOR ${J(e.column)};`;
|
|
2915
|
-
}, J = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2916
|
-
let t =
|
|
2918
|
+
}, J = (e) => `[${e.replace(/]/g, "]]")}]`, sa = (e) => {
|
|
2919
|
+
let t = wi(e, "mssql");
|
|
2917
2920
|
if (t !== void 0) return t;
|
|
2918
2921
|
switch (e.type) {
|
|
2919
2922
|
case "id": return "NVARCHAR(64)";
|
|
2920
2923
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
2921
2924
|
case "integer": return "INT";
|
|
2922
2925
|
case "real": return "FLOAT";
|
|
2923
|
-
case "decimal": return
|
|
2926
|
+
case "decimal": return Si(e, "DECIMAL");
|
|
2924
2927
|
case "bigint": return "BIGINT";
|
|
2925
2928
|
case "boolean": return "BIT";
|
|
2926
2929
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2928,53 +2931,53 @@ BEGIN
|
|
|
2928
2931
|
case "bytes": return "VARBINARY(MAX)";
|
|
2929
2932
|
default: return "NVARCHAR(MAX)";
|
|
2930
2933
|
}
|
|
2931
|
-
},
|
|
2932
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2933
|
-
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` :
|
|
2934
|
+
}, ca = (e, t, n = !1) => {
|
|
2935
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return F(e.name, "mssql");
|
|
2936
|
+
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` : sa(e), i = Vi(e, "mssql");
|
|
2934
2937
|
if (i) return `${J(e.name)} ${i}`;
|
|
2935
2938
|
let a = [J(e.name), r];
|
|
2936
2939
|
if (e.type === "json" && a.push(`CHECK ${gt(J(e.name))}`), e.type === "array" && a.push(`CHECK (${J(e.name)} IS NULL OR ISJSON(${J(e.name)}) = 1)`), e.type === "id" && !n && a.push("PRIMARY KEY"), e.nullable || a.push("NOT NULL"), e.unique && e.type !== "id" && a.push("UNIQUE"), e.hasDefault) {
|
|
2937
|
-
let t =
|
|
2940
|
+
let t = ea(e.defaultValue, "SYSUTCDATETIME()");
|
|
2938
2941
|
t && a.push(t);
|
|
2939
2942
|
}
|
|
2940
|
-
return e.references && (a.push(`REFERENCES ${J(e.references.table)} (${J(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${
|
|
2941
|
-
},
|
|
2942
|
-
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((t) => ` ${
|
|
2943
|
+
return e.references && (a.push(`REFERENCES ${J(e.references.table)} (${J(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${Qi[e.references.onDelete]}`)), a.join(" ");
|
|
2944
|
+
}, la = (e) => {
|
|
2945
|
+
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((t) => ` ${ca(t, n, Ui(e))}`).join(",\n"), i = `CREATE TABLE ${J(e.table)} (\n${r}${Wi(e, J)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2943
2946
|
for (let n of e.indexes) {
|
|
2944
2947
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2945
|
-
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${J(n.name)} ON ${J(e.table)} (${n.columns.map(J).join(", ")})${
|
|
2948
|
+
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${J(n.name)} ON ${J(e.table)} (${n.columns.map(J).join(", ")})${ga(n)}`;
|
|
2946
2949
|
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)}')`);
|
|
2947
2950
|
}
|
|
2948
2951
|
return a;
|
|
2949
|
-
},
|
|
2950
|
-
let r = `${e.table}${
|
|
2952
|
+
}, ua = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, da = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, fa = (e, t, n) => {
|
|
2953
|
+
let r = `${e.table}${ua(t)}`;
|
|
2951
2954
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2952
|
-
},
|
|
2953
|
-
if (e === void 0 || !
|
|
2955
|
+
}, pa = (e) => {
|
|
2956
|
+
if (e === void 0 || !qi(e)) return;
|
|
2954
2957
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2955
|
-
return t === void 0 ?
|
|
2956
|
-
},
|
|
2957
|
-
let r =
|
|
2958
|
+
return t === void 0 ? Ki : Math.min(Ki, t);
|
|
2959
|
+
}, ma = (e, t, n) => {
|
|
2960
|
+
let r = pa(Ii(e, t, n));
|
|
2958
2961
|
return r === void 0 ? K(n) : `${K(n)}(${r})`;
|
|
2959
|
-
},
|
|
2960
|
-
let n =
|
|
2962
|
+
}, ha = (e) => e.startsWith("(") ? e : G(e), ga = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, _a = (e, t) => {
|
|
2963
|
+
let n = Ce(e.index.kind, e.index.kindOptions), r = e.index.columns.map(ha);
|
|
2961
2964
|
if (n.opclass !== void 0) {
|
|
2962
2965
|
if (r.length !== 1) throw Error("HNSW index requires exactly one column");
|
|
2963
2966
|
r[0] = `${r[0]} ${n.opclass}`;
|
|
2964
2967
|
}
|
|
2965
|
-
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${G(e.index.name)} ON ${G(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${
|
|
2966
|
-
},
|
|
2968
|
+
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${G(e.index.name)} ON ${G(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${ga(e.index)};`;
|
|
2969
|
+
}, va = (e, t, n = "mariadb") => (ya(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Oi(n)}${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map((n) => ma(t, e.table, n)).join(", ")});`), ya = (e, t) => {
|
|
2967
2970
|
if (e.where !== void 0) throw Error(`Partial index '${e.name}' is not supported by ${t}; uniqueActive must be lowered before applying the plan.`);
|
|
2968
|
-
},
|
|
2971
|
+
}, ba = (e) => `DROP INDEX IF EXISTS ${G(e.index)};`, xa = (e) => `DROP INDEX ${K(e.index)} ON ${K(e.table)};`, Sa = (e) => `DROP INDEX IF EXISTS ${J(e.index)} ON ${J(e.table)};`, Ca = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, wa = (e) => {
|
|
2969
2972
|
let t = (e) => e.replace(/'/g, "''");
|
|
2970
2973
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2971
|
-
},
|
|
2974
|
+
}, Ta = (e) => `ALTER INDEX ${G(e.from)} RENAME TO ${G(e.to)};`, Ea = (e) => `ALTER TABLE ${K(e.table)} RENAME INDEX ${K(e.from)} TO ${K(e.to)};`, Da = (e) => {
|
|
2972
2975
|
let t = (e) => e.replace(/'/g, "''");
|
|
2973
2976
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2974
|
-
},
|
|
2975
|
-
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${J(e.index.name)} ON ${J(e.table)} (${e.index.columns.map(J).join(", ")})${
|
|
2977
|
+
}, Oa = (e) => {
|
|
2978
|
+
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${J(e.index.name)} ON ${J(e.table)} (${e.index.columns.map(J).join(", ")})${ga(e.index)}`;
|
|
2976
2979
|
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)}');`;
|
|
2977
|
-
},
|
|
2980
|
+
}, ka = (e, t, n) => {
|
|
2978
2981
|
let r = n.find((t) => t.tableName === e);
|
|
2979
2982
|
if (!r) return [];
|
|
2980
2983
|
let i = [];
|
|
@@ -2986,13 +2989,13 @@ BEGIN
|
|
|
2986
2989
|
}
|
|
2987
2990
|
}
|
|
2988
2991
|
return i;
|
|
2989
|
-
},
|
|
2992
|
+
}, Aa = (e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${G(e.column)});`, ja = (e, t) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${ma(t, e.table, e.column)});`, Ma = (e) => {
|
|
2990
2993
|
let t = e.fields.map((e) => G(e)).join(", ");
|
|
2991
2994
|
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${t});`;
|
|
2992
|
-
},
|
|
2993
|
-
let n = e.fields.map((n) =>
|
|
2995
|
+
}, Na = (e, t) => {
|
|
2996
|
+
let n = e.fields.map((n) => ma(t, e.table, n)).join(", ");
|
|
2994
2997
|
return `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(e.name)} UNIQUE (${n});`;
|
|
2995
|
-
},
|
|
2998
|
+
}, Pa = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(e.name)};`, Fa = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(e.name)};`, Ia = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_key`)};`, La = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(`${e.table}_${e.column}_key`)};`, Ra = (e, t, n = Zi) => {
|
|
2996
2999
|
let r = [], i = t(e.table), a = t(e.column), o = t(e.targetTable), s = t(e.targetColumn);
|
|
2997
3000
|
if (e.orphanPolicy) {
|
|
2998
3001
|
let t = `${a} IS NOT NULL AND ${a} NOT IN (SELECT ${s} FROM ${o})`;
|
|
@@ -3005,10 +3008,10 @@ BEGIN
|
|
|
3005
3008
|
`REFERENCES ${o} (${s})`
|
|
3006
3009
|
];
|
|
3007
3010
|
return e.onDelete && c.push(`ON DELETE ${n[e.onDelete]}`), r.push(c.join(" ") + ";"), r;
|
|
3008
|
-
},
|
|
3011
|
+
}, za = (e) => e.name ?? `${e.table}_${e.column}_fkey`, Ba = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(za(e))};`, Va = (e) => `ALTER TABLE ${K(e.table)} DROP FOREIGN KEY ${K(za(e))};`, Ha = (e, t) => {
|
|
3009
3012
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
3010
3013
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
3011
|
-
},
|
|
3014
|
+
}, Ua = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_check`)};`, Wa = (e, t) => D.gen(function* () {
|
|
3012
3015
|
let n = yield* e`
|
|
3013
3016
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
3014
3017
|
FROM information_schema.check_constraints cc
|
|
@@ -3023,16 +3026,16 @@ BEGIN
|
|
|
3023
3026
|
let n = String(e.n ?? "");
|
|
3024
3027
|
if (n !== "" && Nr(String(e.c ?? ""))?.column === t.column) return n;
|
|
3025
3028
|
}
|
|
3026
|
-
}),
|
|
3027
|
-
let r = yield*
|
|
3028
|
-
r !== void 0 && (yield* Y(e, `ALTER TABLE ${K(t.table)} DROP CONSTRAINT ${K(r)};`, t.kind, [
|
|
3029
|
-
let i = yield*
|
|
3029
|
+
}), Ga = (e, t, n) => D.gen(function* () {
|
|
3030
|
+
let r = yield* Wa(e, t);
|
|
3031
|
+
r !== void 0 && (yield* Y(e, `ALTER TABLE ${K(t.table)} DROP CONSTRAINT ${K(r)};`, t.kind, [yi]));
|
|
3032
|
+
let i = yield* Wa(e, t);
|
|
3030
3033
|
if (i === void 0) return;
|
|
3031
3034
|
let a = q(n, t.table, t.column);
|
|
3032
3035
|
if (!a) return yield* D.die(/* @__PURE__ */ Error(`applier: cannot drop the CHECK on '${t.table}.${t.column}' — it is column-level (catalog name '${i}'), which this family removes only by redefining the column, and the declared column is not available to redefine it from.`));
|
|
3033
|
-
yield* Y(e, `ALTER TABLE ${K(t.table)} MODIFY COLUMN ${
|
|
3034
|
-
}),
|
|
3035
|
-
let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? J : G, s = a ?
|
|
3036
|
+
yield* Y(e, `ALTER TABLE ${K(t.table)} MODIFY COLUMN ${Li(a, t.column)};`, t.kind);
|
|
3037
|
+
}), Ka = (e, t, n, r) => {
|
|
3038
|
+
let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? J : G, s = a ? Di(i) : r === "mssql" ? sa(i) : r === "sqlite" ? $i(i) : Ti(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = r === "mssql" ? i.type === "json" ? ` CHECK ${gt(o(i.name))}` : i.type === "array" ? ` CHECK (${o(i.name)} IS NULL OR ISJSON(${o(i.name)}) = 1)` : "" : "", u = (e) => a ? Ri(e, i) : r === "mssql" ? ea(e, "SYSUTCDATETIME()") : r === "sqlite" ? ea(e, "CURRENT_TIMESTAMP") : Bi(e, i), d = Vi(i, r);
|
|
3036
3039
|
if (d) {
|
|
3037
3040
|
let t = r === "mssql" ? `${o(i.name)} ${d}` : `${o(i.name)} ${s} ${d}`;
|
|
3038
3041
|
return {
|
|
@@ -3052,15 +3055,16 @@ BEGIN
|
|
|
3052
3055
|
if (t === null) throw Error(`migration applier: cannot render the declared default for '${e.table}.${i.name}' (${JSON.stringify(i.defaultValue)}) while adding it NOT NULL to a populated table. This is a framework bug — report the column type + default.`);
|
|
3053
3056
|
return {
|
|
3054
3057
|
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s} NOT NULL ${t}${l};`],
|
|
3055
|
-
post: []
|
|
3058
|
+
post: [],
|
|
3059
|
+
...i.unique && i.type !== "id" ? { uniquePending: !0 } : {}
|
|
3056
3060
|
};
|
|
3057
3061
|
}
|
|
3058
3062
|
let f = n(e.table, i.name), p = a ? `ALTER TABLE ${o(e.table)} MODIFY COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "mssql" ? `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "sqlite" ? null : `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} SET NOT NULL;`, m = {
|
|
3059
3063
|
pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s}${l};`],
|
|
3060
3064
|
post: p ? [p] : []
|
|
3061
3065
|
};
|
|
3062
|
-
return f?.sql && (m.backfillKind = "sql", m.backfillSql = f.sql), f?.js && (m.backfillKind = "js", m.backfillJs = f.js), f?.batchSize !== void 0 && (m.batchSize = f.batchSize), f?.sleepMs !== void 0 && (m.sleepMs = f.sleepMs), m;
|
|
3063
|
-
},
|
|
3066
|
+
return i.unique && i.type !== "id" && (m.uniquePending = !0), f?.sql && (m.backfillKind = "sql", m.backfillSql = f.sql), f?.js && (m.backfillKind = "js", m.backfillJs = f.js), f?.batchSize !== void 0 && (m.batchSize = f.batchSize), f?.sleepMs !== void 0 && (m.sleepMs = f.sleepMs), m;
|
|
3067
|
+
}, qa = /* @__PURE__ */ new Set([
|
|
3064
3068
|
"drop-index",
|
|
3065
3069
|
"drop-check",
|
|
3066
3070
|
"drop-unique",
|
|
@@ -3068,7 +3072,7 @@ BEGIN
|
|
|
3068
3072
|
"drop-foreign-key",
|
|
3069
3073
|
"drop-column",
|
|
3070
3074
|
"drop-table"
|
|
3071
|
-
]),
|
|
3075
|
+
]), Ja = (e) => {
|
|
3072
3076
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
3073
3077
|
return (e, n) => {
|
|
3074
3078
|
let r = t.get(e);
|
|
@@ -3088,15 +3092,15 @@ BEGIN
|
|
|
3088
3092
|
...o
|
|
3089
3093
|
};
|
|
3090
3094
|
};
|
|
3091
|
-
}, Y = (e, t, n, r = []) => e.unsafe(t).pipe(D.catchIf((e) =>
|
|
3092
|
-
process.stderr.write(
|
|
3095
|
+
}, Y = (e, t, n, r = []) => e.unsafe(t).pipe(D.catchIf((e) => hi(e, r), () => D.void), D.tapError((e) => D.sync(() => {
|
|
3096
|
+
process.stderr.write(we(`applier: statement failed (op=${n})`, t, e, 400));
|
|
3093
3097
|
})), D.mapError((e) => {
|
|
3094
|
-
let r =
|
|
3098
|
+
let r = we(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
3095
3099
|
return Object.assign(e, { message: r });
|
|
3096
|
-
}), D.map(() => void 0)), X = (e, t, n, r) =>
|
|
3100
|
+
}), D.map(() => void 0)), X = (e, t, n, r) => Ya(e, t, ra(t, n), r), Ya = (e, t, n, r) => {
|
|
3097
3101
|
if (n.length === 0) return D.void;
|
|
3098
3102
|
let i = (e) => (n) => {
|
|
3099
|
-
let i =
|
|
3103
|
+
let i = we(`applier: statement failed (op=${r}, sqlite rebuild of ${t})`, e, n, 400).trim();
|
|
3100
3104
|
return process.stderr.write(`${i}\n`), Object.assign(n, { message: i });
|
|
3101
3105
|
};
|
|
3102
3106
|
return D.scoped(D.gen(function* () {
|
|
@@ -3110,8 +3114,8 @@ BEGIN
|
|
|
3110
3114
|
}
|
|
3111
3115
|
}), D.ignore(a("PRAGMA foreign_keys = ON")));
|
|
3112
3116
|
}));
|
|
3113
|
-
},
|
|
3114
|
-
let
|
|
3117
|
+
}, Xa = (e, t) => D.gen(function* () {
|
|
3118
|
+
let r = (yield* e`
|
|
3115
3119
|
SELECT ck.name, ck.definition, ck.is_disabled AS disabled,
|
|
3116
3120
|
ck.is_not_trusted AS untrusted, ck.is_not_for_replication AS notForReplication
|
|
3117
3121
|
FROM sys.check_constraints ck
|
|
@@ -3122,18 +3126,18 @@ BEGIN
|
|
|
3122
3126
|
) ORDER BY ck.name
|
|
3123
3127
|
`).map((e) => ({
|
|
3124
3128
|
...e,
|
|
3125
|
-
definition:
|
|
3126
|
-
})), i = (e) =>
|
|
3129
|
+
definition: xi(e.definition, t.from, t.to)
|
|
3130
|
+
})), i = (e) => n(e, "mssql"), a = (e) => e.replace(/'/g, "''");
|
|
3127
3131
|
return yield* Z(e, [
|
|
3128
|
-
...
|
|
3132
|
+
...r.map((e) => `ALTER TABLE ${i(t.table)} DROP CONSTRAINT ${i(e.name)}`),
|
|
3129
3133
|
`EXEC sp_rename N'${a(`${i(t.table)}.${i(t.from)}`)}', N'${a(t.to)}', 'COLUMN';`,
|
|
3130
|
-
...
|
|
3134
|
+
...r.flatMap((e) => [`ALTER TABLE ${i(t.table)} WITH ${e.untrusted ? "NOCHECK" : "CHECK"} ADD CONSTRAINT ${i(e.name)} CHECK ${e.notForReplication ? "NOT FOR REPLICATION " : ""}${e.definition}`, ...e.disabled ? [`ALTER TABLE ${i(t.table)} NOCHECK CONSTRAINT ${i(e.name)}`] : []])
|
|
3131
3135
|
], t.kind);
|
|
3132
|
-
}),
|
|
3136
|
+
}), Za = (e, t, n) => e == null ? e : t.type === "json" ? JSON.stringify(e) : (t.type === "array" || t.type === "vector") && n !== "postgres" ? typeof e == "string" ? e : JSON.stringify(e) : e, Z = (e, t, n) => D.forEach(t, (t) => Y(e, t, n), { discard: !0 }), Qa = (e, t) => {
|
|
3133
3137
|
let n = Math.max(1, Math.floor(Number.isFinite(t) ? t : 1));
|
|
3134
|
-
return e.literal(
|
|
3135
|
-
},
|
|
3136
|
-
let i =
|
|
3138
|
+
return e.literal(A(e) === "mssql" ? `OFFSET 0 ROWS FETCH NEXT ${n} ROWS ONLY` : `LIMIT ${n}`);
|
|
3139
|
+
}, $a = (e, t, r, i) => e.unsafe(`SELECT ${i === void 0 ? "*" : n(i, t)} FROM ${n(r, t)} WHERE 1=0`).pipe(D.as(!0), D.catchAll(() => D.succeed(!1))), eo = (e, t) => no(e, t, at, j), to = (e, t) => no(e, t, ci, U), no = (e, t, n, r) => D.gen(function* () {
|
|
3140
|
+
let i = z([n], t).tables[0];
|
|
3137
3141
|
if (!i) return yield* D.die(/* @__PURE__ */ Error(`migration applier: the ${r} table descriptor produced no snapshot. This is a framework bug.`));
|
|
3138
3142
|
let a = {
|
|
3139
3143
|
kind: "create-table",
|
|
@@ -3141,20 +3145,20 @@ BEGIN
|
|
|
3141
3145
|
columns: i.columns,
|
|
3142
3146
|
indexes: []
|
|
3143
3147
|
}, o = yield* e.onDialectOrElse({
|
|
3144
|
-
mysql: () =>
|
|
3145
|
-
mssql: () => D.succeed(
|
|
3146
|
-
sqlite: () => D.succeed(
|
|
3147
|
-
orElse: () => D.succeed(
|
|
3148
|
+
mysql: () => oi(e).pipe(D.map((e) => Xi(a, e))),
|
|
3149
|
+
mssql: () => D.succeed(la(a)),
|
|
3150
|
+
sqlite: () => D.succeed(na(a)),
|
|
3151
|
+
orElse: () => D.succeed(Gi(a))
|
|
3148
3152
|
});
|
|
3149
3153
|
yield* D.forEach(o, (t) => Y(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
3150
|
-
}),
|
|
3154
|
+
}), ro = (e) => e`
|
|
3151
3155
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
3152
3156
|
${e("status")}, ${e("payload")}
|
|
3153
|
-
FROM ${e(
|
|
3154
|
-
`,
|
|
3157
|
+
FROM ${e(j)}
|
|
3158
|
+
`, io = (e, t, n, r) => D.gen(function* () {
|
|
3155
3159
|
let i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3156
3160
|
yield* D.forEach(r, ({ index: r, planned: a }) => e`
|
|
3157
|
-
INSERT INTO ${e(
|
|
3161
|
+
INSERT INTO ${e(j)}
|
|
3158
3162
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
3159
3163
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
3160
3164
|
${e("createdAt")})
|
|
@@ -3163,11 +3167,11 @@ BEGIN
|
|
|
3163
3167
|
${a.op.kind}, ${st(a.op)}, ${"pending"},
|
|
3164
3168
|
${JSON.stringify(a)}, ${i})
|
|
3165
3169
|
`, { discard: !0 });
|
|
3166
|
-
}),
|
|
3170
|
+
}), ao = (e, t, n, r, i) => D.gen(function* () {
|
|
3167
3171
|
let a = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3168
3172
|
if (r === "applied") {
|
|
3169
3173
|
yield* e`
|
|
3170
|
-
UPDATE ${e(
|
|
3174
|
+
UPDATE ${e(j)}
|
|
3171
3175
|
SET ${e("status")} = ${r}, ${e("appliedAt")} = ${a},
|
|
3172
3176
|
${e("durationMs")} = ${i ?? null}
|
|
3173
3177
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
@@ -3175,50 +3179,50 @@ BEGIN
|
|
|
3175
3179
|
return;
|
|
3176
3180
|
}
|
|
3177
3181
|
yield* e`
|
|
3178
|
-
UPDATE ${e(
|
|
3182
|
+
UPDATE ${e(j)}
|
|
3179
3183
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
3180
3184
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
3181
3185
|
`;
|
|
3182
|
-
}),
|
|
3186
|
+
}), oo = (e, t, n, r) => D.gen(function* () {
|
|
3183
3187
|
let i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3184
3188
|
r.length > 0 && (yield* e`
|
|
3185
|
-
UPDATE ${e(
|
|
3189
|
+
UPDATE ${e(j)}
|
|
3186
3190
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
3187
3191
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(r)}
|
|
3188
3192
|
`), n.length > 0 && (yield* e`
|
|
3189
|
-
UPDATE ${e(
|
|
3193
|
+
UPDATE ${e(j)}
|
|
3190
3194
|
SET ${e("status")} = ${"pending"}
|
|
3191
3195
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
3192
3196
|
`);
|
|
3193
|
-
}),
|
|
3194
|
-
if (ht(
|
|
3195
|
-
let i =
|
|
3197
|
+
}), so = (e, t) => t === void 0 ? e`DELETE FROM ${e(j)}`.pipe(D.asVoid) : e`DELETE FROM ${e(j)} WHERE ${e("runId")} = ${t}`.pipe(D.asVoid), co = (e) => ro(e).pipe(D.map((e) => e.filter((e) => e.status === "started" || e.status === "added" || e.status === "applied").map((e) => JSON.parse(e.payload))), D.catchAll(() => D.succeed([]))), lo = (e) => so(e).pipe(D.catchAll(() => D.void)), uo = (e, t, r) => D.gen(function* () {
|
|
3198
|
+
if (ht(r.op, r.classification, t) !== "artefact-repair") return "clean";
|
|
3199
|
+
let i = r.op, a = (e) => n(e, t);
|
|
3196
3200
|
if (t === "sqlite" || t === "turso") {
|
|
3197
3201
|
if (!("table" in i)) return "clean";
|
|
3198
3202
|
let n = `${i.table}${ut}`;
|
|
3199
|
-
return (yield*
|
|
3203
|
+
return (yield* $a(e, t, n)) ? ((yield* $a(e, t, i.table)) ? yield* Y(e, `DROP TABLE ${a(n)}`, "resume-repair") : yield* Y(e, `ALTER TABLE ${a(n)} RENAME TO ${a(i.table)}`, "resume-repair"), yield* D.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${i.table}' — replaying the operation`).pipe(D.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
3200
3204
|
}
|
|
3201
3205
|
if (i.kind !== "alter-column-type") return "clean";
|
|
3202
|
-
let o = `${i.column}${dt}`, s = `${i.column}${ft}`, c = yield*
|
|
3206
|
+
let o = `${i.column}${dt}`, s = `${i.column}${ft}`, c = yield* $a(e, t, i.table, i.column), l = yield* $a(e, t, i.table, o), u = yield* $a(e, t, i.table, s), d = (e) => D.logWarning(`migration resume: ${e}`).pipe(D.annotateLogs({ scope: "voltro:migrate" }));
|
|
3203
3207
|
return !l && !u ? "clean" : c && l && !u ? (yield* Y(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(o)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${i.table}.${o}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* Y(e, `ALTER TABLE ${a(i.table)} RENAME COLUMN ${a(o)} TO ${a(i.column)}`, "resume-repair"), yield* Y(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${i.table}.${i.column}'`), "applied") : c && !l && u ? (yield* Y(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${i.table}.${s}'`), "applied") : yield* D.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${i.table}.${i.column}' left a shadow-swap state this resume cannot classify (column=${c}, ${o}=${l}, ${s}=${u}).\nNothing was changed. Inspect those three columns and reconcile them by hand — the data is in whichever of them is populated — then re-run the migration.`));
|
|
3204
|
-
}),
|
|
3205
|
-
let o = process.hrtime.bigint(), s =
|
|
3208
|
+
}), fo = (e, t, r, i = "fresh", a) => D.gen(function* () {
|
|
3209
|
+
let o = process.hrtime.bigint(), s = Ja(r.declared), c = t.op, l = A(e);
|
|
3206
3210
|
switch (c.kind) {
|
|
3207
3211
|
case "create-table": {
|
|
3208
3212
|
let t = yield* e.onDialectOrElse({
|
|
3209
|
-
mysql: () =>
|
|
3210
|
-
mssql: () => D.succeed(
|
|
3211
|
-
sqlite: () => D.succeed(
|
|
3212
|
-
orElse: () => D.succeed(
|
|
3213
|
+
mysql: () => oi(e).pipe(D.map((e) => Xi(c, e))),
|
|
3214
|
+
mssql: () => D.succeed(la(c)),
|
|
3215
|
+
sqlite: () => D.succeed(na(c)),
|
|
3216
|
+
orElse: () => D.succeed(Gi(c))
|
|
3213
3217
|
}), n = yield* e.onDialectOrElse({
|
|
3214
|
-
mysql: () => D.succeed([
|
|
3218
|
+
mysql: () => D.succeed([gi]),
|
|
3215
3219
|
orElse: () => D.succeed([])
|
|
3216
3220
|
});
|
|
3217
3221
|
for (let r of t) yield* Y(e, r, c.kind, n);
|
|
3218
3222
|
break;
|
|
3219
3223
|
}
|
|
3220
3224
|
case "drop-table": {
|
|
3221
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
3225
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? fa(c, n, e) : da(c, e);
|
|
3222
3226
|
yield* e.onDialectOrElse({
|
|
3223
3227
|
mysql: () => Y(e, r(K), c.kind),
|
|
3224
3228
|
orElse: () => Y(e, r(G), c.kind)
|
|
@@ -3228,131 +3232,131 @@ BEGIN
|
|
|
3228
3232
|
case "drop-column": {
|
|
3229
3233
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
3230
3234
|
yield* e.onDialectOrElse({
|
|
3231
|
-
mysql: () =>
|
|
3232
|
-
sqlite: () => Y(e, t ?
|
|
3233
|
-
orElse: () => Y(e, t ?
|
|
3235
|
+
mysql: () => oi(e).pipe(D.flatMap((r) => Y(e, t ? Mi(c, n, K) : Ai(c, r), c.kind, t ? [] : [_i]))),
|
|
3236
|
+
sqlite: () => Y(e, t ? Mi(c, n, G) : ki(c, G, !1), c.kind, t ? [] : [vi]),
|
|
3237
|
+
orElse: () => Y(e, t ? Mi(c, n, G) : ki(c, G), c.kind)
|
|
3234
3238
|
});
|
|
3235
3239
|
break;
|
|
3236
3240
|
}
|
|
3237
3241
|
case "rename-column":
|
|
3238
3242
|
yield* e.onDialectOrElse({
|
|
3239
|
-
mysql: () => Y(e,
|
|
3240
|
-
mssql: () =>
|
|
3241
|
-
orElse: () => Y(e,
|
|
3243
|
+
mysql: () => Y(e, ji(c, K), c.kind),
|
|
3244
|
+
mssql: () => Xa(e, c),
|
|
3245
|
+
orElse: () => Y(e, ji(c, G), c.kind)
|
|
3242
3246
|
});
|
|
3243
3247
|
break;
|
|
3244
3248
|
case "add-index":
|
|
3245
3249
|
yield* e.onDialectOrElse({
|
|
3246
|
-
sqlite: () => Y(e,
|
|
3247
|
-
mysql: () =>
|
|
3248
|
-
mssql: () => Z(e, [...
|
|
3249
|
-
orElse: () => Y(e,
|
|
3250
|
+
sqlite: () => Y(e, _a(c, !1), c.kind),
|
|
3251
|
+
mysql: () => oi(e).pipe(D.flatMap((t) => Y(e, va(c, r.declared, t), c.kind, [gi]))),
|
|
3252
|
+
mssql: () => Z(e, [...ka(c.table, c.index.columns, r.declared), Oa(c)], c.kind),
|
|
3253
|
+
orElse: () => Y(e, _a(c, t.classification === "online-required"), c.kind)
|
|
3250
3254
|
});
|
|
3251
3255
|
break;
|
|
3252
3256
|
case "drop-index":
|
|
3253
3257
|
yield* e.onDialectOrElse({
|
|
3254
|
-
mysql: () => Y(e,
|
|
3255
|
-
mssql: () => Y(e,
|
|
3256
|
-
orElse: () => Y(e,
|
|
3258
|
+
mysql: () => Y(e, xa(c), c.kind),
|
|
3259
|
+
mssql: () => Y(e, Sa(c), c.kind),
|
|
3260
|
+
orElse: () => Y(e, ba(c), c.kind)
|
|
3257
3261
|
});
|
|
3258
3262
|
break;
|
|
3259
3263
|
case "rename-table":
|
|
3260
3264
|
yield* e.onDialectOrElse({
|
|
3261
|
-
mysql: () => Y(e,
|
|
3262
|
-
mssql: () => Y(e,
|
|
3263
|
-
orElse: () => Y(e,
|
|
3265
|
+
mysql: () => Y(e, Ca(c, K), c.kind),
|
|
3266
|
+
mssql: () => Y(e, wa(c), c.kind),
|
|
3267
|
+
orElse: () => Y(e, Ca(c, G), c.kind)
|
|
3264
3268
|
});
|
|
3265
3269
|
break;
|
|
3266
3270
|
case "rename-index":
|
|
3267
3271
|
yield* e.onDialectOrElse({
|
|
3268
|
-
mysql: () => Y(e,
|
|
3269
|
-
mssql: () => Y(e,
|
|
3270
|
-
orElse: () => Y(e,
|
|
3272
|
+
mysql: () => Y(e, Ea(c), c.kind),
|
|
3273
|
+
mssql: () => Y(e, Da(c), c.kind),
|
|
3274
|
+
orElse: () => Y(e, Ta(c), c.kind)
|
|
3271
3275
|
});
|
|
3272
3276
|
break;
|
|
3273
3277
|
case "add-unique":
|
|
3274
3278
|
yield* e.onDialectOrElse({
|
|
3275
|
-
mysql: () => Y(e,
|
|
3276
|
-
sqlite: () => X(e, c.table,
|
|
3277
|
-
mssql: () => Z(e, [...
|
|
3278
|
-
orElse: () => Y(e,
|
|
3279
|
+
mysql: () => Y(e, ja(c, r.declared), c.kind),
|
|
3280
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3281
|
+
mssql: () => Z(e, [...ka(c.table, [c.column], r.declared), Aa(c)], c.kind),
|
|
3282
|
+
orElse: () => Y(e, Aa(c), c.kind)
|
|
3279
3283
|
});
|
|
3280
3284
|
break;
|
|
3281
3285
|
case "drop-unique":
|
|
3282
3286
|
yield* e.onDialectOrElse({
|
|
3283
|
-
mysql: () => Y(e,
|
|
3284
|
-
sqlite: () => X(e, c.table,
|
|
3285
|
-
orElse: () => Y(e,
|
|
3287
|
+
mysql: () => Y(e, La(c), c.kind),
|
|
3288
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3289
|
+
orElse: () => Y(e, Ia(c), c.kind)
|
|
3286
3290
|
});
|
|
3287
3291
|
break;
|
|
3288
3292
|
case "add-enum-value":
|
|
3289
3293
|
yield* e.onDialectOrElse({
|
|
3290
|
-
pg: () => c.enumName === void 0 ? D.die(/* @__PURE__ */ Error(`add-enum-value on postgres needs the type name for ${c.table}.${c.column}; the plan carries none.`)) : Y(e, `ALTER TYPE ${
|
|
3294
|
+
pg: () => c.enumName === void 0 ? D.die(/* @__PURE__ */ Error(`add-enum-value on postgres needs the type name for ${c.table}.${c.column}; the plan carries none.`)) : Y(e, `ALTER TYPE ${n(c.enumName, "postgres")} ADD VALUE IF NOT EXISTS '${c.value.replace(/'/g, "''")}'`, c.kind),
|
|
3291
3295
|
mysql: () => {
|
|
3292
|
-
let t = q(
|
|
3293
|
-
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? D.die(/* @__PURE__ */ Error(`add-enum-value on the mysql family needs the declared column ${c.table}.${c.column} and its labels; the declaration carries none.`)) : Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${
|
|
3296
|
+
let t = q(r.declared, c.table, c.column);
|
|
3297
|
+
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? D.die(/* @__PURE__ */ Error(`add-enum-value on the mysql family needs the declared column ${c.table}.${c.column} and its labels; the declaration carries none.`)) : Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${Li(t, c.column)}`, c.kind);
|
|
3294
3298
|
},
|
|
3295
3299
|
orElse: () => D.void
|
|
3296
3300
|
});
|
|
3297
3301
|
break;
|
|
3298
3302
|
case "add-unique-composite":
|
|
3299
3303
|
yield* e.onDialectOrElse({
|
|
3300
|
-
mysql: () => Y(e,
|
|
3301
|
-
sqlite: () => X(e, c.table,
|
|
3302
|
-
mssql: () => Z(e, [...
|
|
3303
|
-
orElse: () => Y(e,
|
|
3304
|
+
mysql: () => Y(e, Na(c, r.declared), c.kind),
|
|
3305
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3306
|
+
mssql: () => Z(e, [...ka(c.table, c.fields, r.declared), Ma(c)], c.kind),
|
|
3307
|
+
orElse: () => Y(e, Ma(c), c.kind)
|
|
3304
3308
|
});
|
|
3305
3309
|
break;
|
|
3306
3310
|
case "drop-unique-composite":
|
|
3307
3311
|
yield* e.onDialectOrElse({
|
|
3308
|
-
mysql: () => Y(e,
|
|
3309
|
-
sqlite: () => X(e, c.table,
|
|
3310
|
-
orElse: () => Y(e,
|
|
3312
|
+
mysql: () => Y(e, Fa(c), c.kind),
|
|
3313
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3314
|
+
orElse: () => Y(e, Pa(c), c.kind)
|
|
3311
3315
|
});
|
|
3312
3316
|
break;
|
|
3313
3317
|
case "add-foreign-key":
|
|
3314
3318
|
yield* e.onDialectOrElse({
|
|
3315
|
-
mysql: () => Z(e,
|
|
3316
|
-
sqlite: () => X(e, c.table,
|
|
3317
|
-
mssql: () => Z(e,
|
|
3318
|
-
orElse: () => Z(e,
|
|
3319
|
+
mysql: () => Z(e, Ra(c, K), c.kind),
|
|
3320
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3321
|
+
mssql: () => Z(e, Ra(c, J, Qi), c.kind),
|
|
3322
|
+
orElse: () => Z(e, Ra(c, G), c.kind)
|
|
3319
3323
|
});
|
|
3320
3324
|
break;
|
|
3321
3325
|
case "add-column": {
|
|
3322
|
-
let
|
|
3326
|
+
let n = Ka(c, t, s, yield* e.onDialectOrElse({
|
|
3323
3327
|
mysql: () => D.succeed("mariadb"),
|
|
3324
3328
|
mssql: () => D.succeed("mssql"),
|
|
3325
3329
|
sqlite: () => D.succeed("sqlite"),
|
|
3326
3330
|
orElse: () => D.succeed("postgres")
|
|
3327
3331
|
}));
|
|
3328
|
-
if (!(i === "resume" && (yield*
|
|
3329
|
-
let u = t.classification === "online-required" ||
|
|
3330
|
-
if (
|
|
3331
|
-
if (t.classification !== "online-required" &&
|
|
3332
|
+
if (!(i === "resume" && (yield* $a(e, A(e), c.table, c.column.name)))) for (let t of n.pre) yield* Y(e, t, c.kind);
|
|
3333
|
+
let u = t.classification === "online-required" || n.batchSize !== void 0 || n.sleepMs !== void 0, d = D.gen(function* () {
|
|
3334
|
+
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
3335
|
+
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${n.backfillSql}`;
|
|
3332
3336
|
else {
|
|
3333
|
-
let t =
|
|
3337
|
+
let t = n.batchSize ?? 5e3, r = n.sleepMs ?? 0, i, a = 0;
|
|
3334
3338
|
for (;;) {
|
|
3335
|
-
let o = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${
|
|
3339
|
+
let o = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${Qa(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Qa(e, t)}`;
|
|
3336
3340
|
if (o.length === 0) break;
|
|
3337
3341
|
let s = o.map((e) => e.id);
|
|
3338
|
-
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${
|
|
3342
|
+
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(s)}`, a += o.length, yield* D.logInfo(`backfill ${c.table}.${c.column.name}: ${a} rows`).pipe(D.annotateLogs({
|
|
3339
3343
|
scope: "voltro:migrate",
|
|
3340
3344
|
mode: "sql-batched"
|
|
3341
|
-
})), i = o[o.length - 1].id,
|
|
3345
|
+
})), i = o[o.length - 1].id, r > 0 && (yield* D.sleep(`${r} millis`));
|
|
3342
3346
|
}
|
|
3343
3347
|
}
|
|
3344
|
-
} else if (
|
|
3345
|
-
let t =
|
|
3348
|
+
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
3349
|
+
let t = n.batchSize ?? 1e3, i = n.sleepMs ?? 0, a = r.declared.find((e) => e.tableName === c.table), o, s = 0;
|
|
3346
3350
|
for (;;) {
|
|
3347
|
-
let
|
|
3348
|
-
if (
|
|
3349
|
-
let u = a === void 0 ?
|
|
3351
|
+
let r = o === void 0 ? yield* e`SELECT * FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${Qa(e, t)}` : yield* e`SELECT * FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL AND ${e("id")} > ${o} ORDER BY ${e("id")} ${Qa(e, t)}`;
|
|
3352
|
+
if (r.length === 0) break;
|
|
3353
|
+
let u = a === void 0 ? r : re(r, a, l);
|
|
3350
3354
|
for (let t of u) {
|
|
3351
|
-
let
|
|
3352
|
-
try: () => Promise.resolve(
|
|
3355
|
+
let r = yield* D.tryPromise({
|
|
3356
|
+
try: () => Promise.resolve(n.backfillJs(t)),
|
|
3353
3357
|
catch: (e) => e
|
|
3354
3358
|
}).pipe(D.orDie);
|
|
3355
|
-
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${
|
|
3359
|
+
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${Za(r, c.column, l)} WHERE ${e("id")} = ${t.id}`;
|
|
3356
3360
|
}
|
|
3357
3361
|
s += u.length, yield* D.logInfo(`backfill ${c.table}.${c.column.name}: ${s} rows processed`).pipe(D.annotateLogs({
|
|
3358
3362
|
scope: "voltro:migrate",
|
|
@@ -3362,10 +3366,22 @@ BEGIN
|
|
|
3362
3366
|
}
|
|
3363
3367
|
}
|
|
3364
3368
|
}), f = D.gen(function* () {
|
|
3365
|
-
for (let t of
|
|
3366
|
-
|
|
3369
|
+
for (let t of n.post) yield* Y(e, t, c.kind);
|
|
3370
|
+
if (p(l) && (n.uniquePending === !0 || n.backfillKind !== void 0 && !c.column.nullable)) yield* X(e, c.table, r.declared, c.kind);
|
|
3371
|
+
else if (n.uniquePending === !0) {
|
|
3372
|
+
let t = {
|
|
3373
|
+
kind: "add-unique",
|
|
3374
|
+
table: c.table,
|
|
3375
|
+
column: c.column.name
|
|
3376
|
+
};
|
|
3377
|
+
yield* e.onDialectOrElse({
|
|
3378
|
+
mysql: () => Y(e, ja(t, r.declared), c.kind),
|
|
3379
|
+
mssql: () => Z(e, [...ka(c.table, [c.column.name], r.declared), Aa(t)], c.kind),
|
|
3380
|
+
orElse: () => Y(e, Aa(t), c.kind)
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
3367
3383
|
});
|
|
3368
|
-
if (a !== void 0 &&
|
|
3384
|
+
if (a !== void 0 && n.backfillKind !== void 0 && !u) return a({
|
|
3369
3385
|
table: c.table,
|
|
3370
3386
|
op: c,
|
|
3371
3387
|
data: d,
|
|
@@ -3382,47 +3398,47 @@ BEGIN
|
|
|
3382
3398
|
case "alter-column-nullability":
|
|
3383
3399
|
yield* e.onDialectOrElse({
|
|
3384
3400
|
mysql: () => {
|
|
3385
|
-
let t = q(
|
|
3386
|
-
return t ? Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${
|
|
3401
|
+
let t = q(r.declared, c.table, c.column);
|
|
3402
|
+
return t ? Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${Li(t, c.column, c.toNullable)};`, c.kind) : D.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${c.table}.${c.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
3387
3403
|
},
|
|
3388
3404
|
mssql: () => {
|
|
3389
|
-
let t = q(
|
|
3390
|
-
return t ? Y(e,
|
|
3405
|
+
let t = q(r.declared, c.table, c.column);
|
|
3406
|
+
return t ? Y(e, aa(t, c.column, c.table, c.toNullable), c.kind) : D.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${c.table}.${c.column}'.`));
|
|
3391
3407
|
},
|
|
3392
|
-
sqlite: () => X(e, c.table,
|
|
3408
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3393
3409
|
orElse: () => Y(e, `ALTER TABLE ${G(c.table)} ALTER COLUMN ${G(c.column)} ${c.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, c.kind)
|
|
3394
3410
|
});
|
|
3395
3411
|
break;
|
|
3396
3412
|
case "alter-column-default": {
|
|
3397
|
-
let t =
|
|
3413
|
+
let t = Ii(r.declared, c.table, c.column), n = q(r.declared, c.table, c.column), i = (e) => c.hasDefault && n !== void 0 && Pi(n, e) ? n : void 0;
|
|
3398
3414
|
yield* e.onDialectOrElse({
|
|
3399
3415
|
mysql: () => {
|
|
3400
3416
|
let n = i("mariadb");
|
|
3401
|
-
return Y(e, n ? `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${
|
|
3417
|
+
return Y(e, n ? `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${Li(n, c.column)};` : Ni(c, K, (e) => Ri(e, t)), c.kind);
|
|
3402
3418
|
},
|
|
3403
3419
|
mssql: () => {
|
|
3404
3420
|
let t = i("mssql");
|
|
3405
|
-
return Y(e,
|
|
3421
|
+
return Y(e, oa(c, t ? aa(t, c.column, c.table) : void 0), c.kind);
|
|
3406
3422
|
},
|
|
3407
|
-
sqlite: () => X(e, c.table,
|
|
3408
|
-
orElse: () => Y(e,
|
|
3423
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3424
|
+
orElse: () => Y(e, Ni(c, G, (e) => Bi(e, t)), c.kind)
|
|
3409
3425
|
});
|
|
3410
3426
|
break;
|
|
3411
3427
|
}
|
|
3412
3428
|
case "alter-column-type": {
|
|
3413
|
-
let
|
|
3429
|
+
let n = Ti(Ii(r.declared, c.table, c.column) ?? { type: c.to }), i = c.using ? ` USING ${c.using}` : "";
|
|
3414
3430
|
if (t.classification !== "online-required") {
|
|
3415
3431
|
yield* e.onDialectOrElse({
|
|
3416
3432
|
mysql: () => {
|
|
3417
|
-
let t = q(
|
|
3418
|
-
return t ? Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${
|
|
3433
|
+
let t = q(r.declared, c.table, c.column);
|
|
3434
|
+
return t ? Y(e, `ALTER TABLE ${K(c.table)} MODIFY COLUMN ${Li(t, c.column)};`, c.kind) : D.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${c.table}.${c.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
3419
3435
|
},
|
|
3420
3436
|
mssql: () => {
|
|
3421
|
-
let t = q(
|
|
3422
|
-
return t ? Y(e,
|
|
3437
|
+
let t = q(r.declared, c.table, c.column);
|
|
3438
|
+
return t ? Y(e, aa(t, c.column, c.table), c.kind) : D.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${c.table}.${c.column}'.`));
|
|
3423
3439
|
},
|
|
3424
|
-
sqlite: () => X(e, c.table,
|
|
3425
|
-
orElse: () => Y(e, `ALTER TABLE ${G(c.table)} ALTER COLUMN ${G(c.column)} TYPE ${
|
|
3440
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3441
|
+
orElse: () => Y(e, `ALTER TABLE ${G(c.table)} ALTER COLUMN ${G(c.column)} TYPE ${n}${i};`, c.kind)
|
|
3426
3442
|
});
|
|
3427
3443
|
break;
|
|
3428
3444
|
}
|
|
@@ -3431,10 +3447,10 @@ BEGIN
|
|
|
3431
3447
|
orElse: () => D.void
|
|
3432
3448
|
});
|
|
3433
3449
|
let a = `${c.column}__shadow`, o = `${c.column}__old`;
|
|
3434
|
-
yield* e.unsafe(`ALTER TABLE ${G(c.table)} ADD COLUMN ${G(a)} ${
|
|
3450
|
+
yield* e.unsafe(`ALTER TABLE ${G(c.table)} ADD COLUMN ${G(a)} ${n}`);
|
|
3435
3451
|
let s = c.using ?? G(c.column), l;
|
|
3436
3452
|
for (;;) {
|
|
3437
|
-
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${
|
|
3453
|
+
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${Qa(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${Qa(e, 5e3)}`;
|
|
3438
3454
|
if (t.length === 0) break;
|
|
3439
3455
|
yield* e.unsafe(`UPDATE ${G(c.table)} SET ${G(a)} = ${s} WHERE ${G(c.column)} IS NOT NULL AND ${G(a)} IS NULL AND ${G("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
3440
3456
|
}
|
|
@@ -3443,16 +3459,16 @@ BEGIN
|
|
|
3443
3459
|
}
|
|
3444
3460
|
case "drop-foreign-key":
|
|
3445
3461
|
yield* e.onDialectOrElse({
|
|
3446
|
-
mysql: () => Y(e,
|
|
3447
|
-
sqlite: () => X(e, c.table,
|
|
3448
|
-
orElse: () => Y(e,
|
|
3462
|
+
mysql: () => Y(e, Va(c), c.kind),
|
|
3463
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3464
|
+
orElse: () => Y(e, Ba(c), c.kind)
|
|
3449
3465
|
});
|
|
3450
3466
|
break;
|
|
3451
3467
|
case "add-check":
|
|
3452
3468
|
yield* e.onDialectOrElse({
|
|
3453
|
-
mysql: () => Y(e,
|
|
3454
|
-
sqlite: () => X(e, c.table,
|
|
3455
|
-
orElse: () => Y(e,
|
|
3469
|
+
mysql: () => Y(e, Ha(c, K), c.kind),
|
|
3470
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3471
|
+
orElse: () => Y(e, Ha(c, G), c.kind)
|
|
3456
3472
|
});
|
|
3457
3473
|
break;
|
|
3458
3474
|
case "reconcile-json-check": {
|
|
@@ -3464,9 +3480,9 @@ BEGIN
|
|
|
3464
3480
|
break;
|
|
3465
3481
|
}
|
|
3466
3482
|
case "drop-check": yield* e.onDialectOrElse({
|
|
3467
|
-
mysql: () =>
|
|
3468
|
-
sqlite: () => X(e, c.table,
|
|
3469
|
-
orElse: () => Y(e,
|
|
3483
|
+
mysql: () => Ga(e, c, r.declared),
|
|
3484
|
+
sqlite: () => X(e, c.table, r.declared, c.kind),
|
|
3485
|
+
orElse: () => Y(e, Ua(c), c.kind)
|
|
3470
3486
|
});
|
|
3471
3487
|
}
|
|
3472
3488
|
return {
|
|
@@ -3474,22 +3490,22 @@ BEGIN
|
|
|
3474
3490
|
status: "applied",
|
|
3475
3491
|
durationMs: Number((process.hrtime.bigint() - o) / 1000000n)
|
|
3476
3492
|
};
|
|
3477
|
-
}),
|
|
3493
|
+
}), po = (e, t, n, r) => D.gen(function* () {
|
|
3478
3494
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
3479
|
-
if (i.length > 1) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger holds ${i.length} unfinished runs (${i.join(", ")}). Only one migration may be in flight at a time — the advisory lock enforces it — so this means a run was interrupted and a LATER one wrote over it without clearing.\nNothing was changed. Inspect \`${
|
|
3495
|
+
if (i.length > 1) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger holds ${i.length} unfinished runs (${i.join(", ")}). Only one migration may be in flight at a time — the advisory lock enforces it — so this means a run was interrupted and a LATER one wrote over it without clearing.\nNothing was changed. Inspect \`${j}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
3480
3496
|
let a = i[0], o = [...r].map((e) => ({
|
|
3481
3497
|
index: Number(e.opIndex),
|
|
3482
3498
|
status: e.status,
|
|
3483
3499
|
planned: JSON.parse(e.payload)
|
|
3484
3500
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
3485
|
-
if (c > 1) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger records ${c} operations as in-flight for run ${a}. It is written strictly sequentially, so at most one can be — this ledger is corrupt and the schema state it describes cannot be trusted.\nNothing was changed. Reconcile \`${
|
|
3501
|
+
if (c > 1) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the resume ledger records ${c} operations as in-flight for run ${a}. It is written strictly sequentially, so at most one can be — this ledger is corrupt and the schema state it describes cannot be trusted.\nNothing was changed. Reconcile \`${j}\` by hand before re-running.`));
|
|
3486
3502
|
let l = o.filter((e) => e.status === "added");
|
|
3487
3503
|
if (yield* D.logWarning(`migration resume: found an interrupted run (${a}) — ${o.filter((e) => e.status === "applied").length} of ${o.length} operation(s) completed${s ? `, in flight: ${s.planned.op.kind} ${st(s.planned.op)}` : ""}${l.length > 0 ? `, ${l.length} column(s) added with the backfill still owed` : ""}`).pipe(D.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
3488
3504
|
kind: "discard",
|
|
3489
3505
|
runId: a,
|
|
3490
3506
|
why: "no operation had started — no DDL ran"
|
|
3491
3507
|
};
|
|
3492
|
-
let u = s ? yield*
|
|
3508
|
+
let u = s ? yield* uo(e, t, s.planned) : "clean", d = r[0].planFingerprint;
|
|
3493
3509
|
if (d !== n.toFingerprint) return {
|
|
3494
3510
|
kind: "discard",
|
|
3495
3511
|
runId: a,
|
|
@@ -3500,7 +3516,7 @@ BEGIN
|
|
|
3500
3516
|
kind: "discard",
|
|
3501
3517
|
runId: a,
|
|
3502
3518
|
why: "every recorded operation had already taken effect"
|
|
3503
|
-
} : (yield*
|
|
3519
|
+
} : (yield* oo(e, a, p.map((e) => e.index), m.map((e) => e.index)), yield* D.logWarning(`migration resume: continuing run ${a} — replaying ${p.length} operation(s), ${o.length - p.length} already applied`).pipe(D.annotateLogs({ scope: "voltro:migrate" })), {
|
|
3504
3520
|
kind: "resume",
|
|
3505
3521
|
runId: a,
|
|
3506
3522
|
ops: p.map((e) => ({
|
|
@@ -3508,7 +3524,7 @@ BEGIN
|
|
|
3508
3524
|
planned: e.planned
|
|
3509
3525
|
}))
|
|
3510
3526
|
});
|
|
3511
|
-
}),
|
|
3527
|
+
}), mo = (e, t, r) => D.gen(function* () {
|
|
3512
3528
|
for (let i of t.operations) {
|
|
3513
3529
|
let a = i.op;
|
|
3514
3530
|
if (a.kind !== "add-index" || !a.index.unique || a.index.where === void 0 || t.operations.some((e) => e.op.kind === "rename-table" ? e.op.to === a.table : e.op.table === a.table && [
|
|
@@ -3516,10 +3532,10 @@ BEGIN
|
|
|
3516
3532
|
"add-column",
|
|
3517
3533
|
"rename-column"
|
|
3518
3534
|
].includes(e.op.kind))) continue;
|
|
3519
|
-
let o = a.index.columns.map((e) => e.startsWith("(") ? e :
|
|
3520
|
-
if ((yield* e.unsafe(`${c} FROM ${
|
|
3535
|
+
let o = a.index.columns.map((e) => e.startsWith("(") ? e : n(e, r)), s = r === "mssql" ? "" : o.map((e) => ` AND ${e} IS NOT NULL`).join(""), c = r === "mssql" ? "SELECT TOP (1) 1" : "SELECT 1", l = r === "mssql" ? "" : " LIMIT 1";
|
|
3536
|
+
if ((yield* e.unsafe(`${c} FROM ${n(a.table, r)} WHERE (${a.index.where})${s} GROUP BY ${o.join(", ")} HAVING COUNT(*) > 1${l}`)).length > 0) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: partial unique index '${a.index.name}' on '${a.table}' conflicts with existing qualifying rows. No schema or row changes were applied. Resolve the conflicting data explicitly before retrying.`));
|
|
3521
3537
|
}
|
|
3522
|
-
}),
|
|
3538
|
+
}), ho = (e) => {
|
|
3523
3539
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3524
3540
|
return [
|
|
3525
3541
|
t.kind,
|
|
@@ -3528,13 +3544,13 @@ BEGIN
|
|
|
3528
3544
|
n("name"),
|
|
3529
3545
|
n("to")
|
|
3530
3546
|
].join("\0");
|
|
3531
|
-
},
|
|
3547
|
+
}, go = (e, t, n) => D.acquireUseRelease($e(e, { schema: n.lockSchema }), () => _o(e, t, n), (e) => e.release.pipe(D.orDie)), _o = (e, t, n) => D.gen(function* () {
|
|
3532
3548
|
let r = t.operations.filter((e) => e.blocked);
|
|
3533
3549
|
if (r.length > 0) return yield* D.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
3534
|
-
let i = Date.now(), a = [], o =
|
|
3550
|
+
let i = Date.now(), a = [], o = A(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => ho(e))), l = {
|
|
3535
3551
|
...s,
|
|
3536
3552
|
operations: s.operations.map((e) => {
|
|
3537
|
-
if (!e.blocked || !c.has(
|
|
3553
|
+
if (!e.blocked || !c.has(ho(e))) return e;
|
|
3538
3554
|
let { blocked: t, ...n } = e;
|
|
3539
3555
|
return n;
|
|
3540
3556
|
})
|
|
@@ -3552,66 +3568,66 @@ BEGIN
|
|
|
3552
3568
|
index: t,
|
|
3553
3569
|
planned: e
|
|
3554
3570
|
})), y = "fresh";
|
|
3555
|
-
yield*
|
|
3556
|
-
let b = yield*
|
|
3571
|
+
yield* mo(e, l, o), yield* eo(e, o);
|
|
3572
|
+
let b = yield* ro(e);
|
|
3557
3573
|
if (b.length > 0) {
|
|
3558
|
-
let t = yield*
|
|
3559
|
-
t.kind === "resume" ? (_ = t.runId, v = t.ops, y = "resume") : (yield* D.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(D.annotateLogs({ scope: "voltro:migrate" })), yield*
|
|
3574
|
+
let t = yield* po(e, o, l, b);
|
|
3575
|
+
t.kind === "resume" ? (_ = t.runId, v = t.ops, y = "resume") : (yield* D.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(D.annotateLogs({ scope: "voltro:migrate" })), yield* so(e, t.runId));
|
|
3560
3576
|
}
|
|
3561
|
-
y === "fresh" && v.length > 0 && (yield*
|
|
3577
|
+
y === "fresh" && v.length > 0 && (yield* io(e, _, l.toFingerprint, v)), h.length > 0 && (yield* bi(e, D.gen(function* () {
|
|
3562
3578
|
let e = yield* O.SqlClient, t = [], r = () => D.gen(function* () {
|
|
3563
3579
|
for (let e of t.splice(0)) yield* e.data, yield* e.after;
|
|
3564
3580
|
});
|
|
3565
|
-
for (let i of h)
|
|
3581
|
+
for (let i of h) qa.has(i.op.kind) && t.length > 0 && (yield* r()), a.push(yield* fo(e, i, n, "fresh", (e) => t.push(e)));
|
|
3566
3582
|
yield* r();
|
|
3567
3583
|
})));
|
|
3568
3584
|
let x = [], S = () => D.gen(function* () {
|
|
3569
3585
|
let t = x.splice(0);
|
|
3570
3586
|
if (t.length !== 0) {
|
|
3571
|
-
yield*
|
|
3587
|
+
yield* bi(e, D.gen(function* () {
|
|
3572
3588
|
for (let e of t) yield* e.data;
|
|
3573
3589
|
}));
|
|
3574
3590
|
for (let n of t) yield* n.after, a.push({
|
|
3575
3591
|
op: n.op,
|
|
3576
3592
|
status: "applied",
|
|
3577
3593
|
durationMs: Number(process.hrtime.bigint() - n.startedAt) / 1e6
|
|
3578
|
-
}), yield*
|
|
3594
|
+
}), yield* ao(e, _, n.index, "applied", Number(process.hrtime.bigint() - n.startedAt) / 1e6);
|
|
3579
3595
|
}
|
|
3580
3596
|
});
|
|
3581
3597
|
for (let { index: t, planned: r } of v) {
|
|
3582
|
-
|
|
3583
|
-
let i = a.length, o = process.hrtime.bigint(), s = yield*
|
|
3598
|
+
qa.has(r.op.kind) && x.length > 0 && (yield* S()), yield* ao(e, _, t, "started");
|
|
3599
|
+
let i = a.length, o = process.hrtime.bigint(), s = yield* fo(e, r, n, y, (e) => x.push({
|
|
3584
3600
|
...e,
|
|
3585
3601
|
index: t,
|
|
3586
3602
|
startedAt: o
|
|
3587
3603
|
})).pipe(D.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${v.length + h.length} operation(s) applied before this one${h.length > 0 ? ` (${h.length} of them in a transaction)` : ""}.\n` + (m ? " This dialect applies a plan atomically, so the run is rolled back.\n" : ` This dialect does NOT apply a plan atomically: those ${i} are COMMITTED and there is no rollback.\n The ledger records how far it got (operation ${t} was in flight).\n`) })));
|
|
3588
3604
|
if (s.deferred === !0) {
|
|
3589
|
-
yield*
|
|
3605
|
+
yield* ao(e, _, t, "added");
|
|
3590
3606
|
continue;
|
|
3591
3607
|
}
|
|
3592
|
-
a.push(s), yield*
|
|
3608
|
+
a.push(s), yield* ao(e, _, t, "applied", s.durationMs);
|
|
3593
3609
|
}
|
|
3594
3610
|
yield* S();
|
|
3595
3611
|
let C = yield* n.replan(e);
|
|
3596
3612
|
if (C.operations.length > 0) {
|
|
3597
|
-
let e = C.operations.slice(0, 10).map((
|
|
3598
|
-
return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${C.operations.length}:\n${
|
|
3613
|
+
let e = (e) => "column" in e ? typeof e.column == "string" ? `.${e.column}` : `.${String(e.column.name ?? "")}` : "", t = C.operations.slice(0, 10).map((t) => ` - ${t.op.kind} ${"table" in t.op ? t.op.table : ""}${e(t.op)}`).join("\n"), n = a.filter((e) => e.status === "applied"), r = n.slice(0, 10).map((t) => ` - ${t.op.kind} ${"table" in t.op ? t.op.table : ""}${e(t.op)}`).join("\n") + (n.length > 10 ? `\n … and ${n.length - 10} more` : "");
|
|
3614
|
+
return yield* D.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${C.operations.length}:\n${t}${C.operations.length > 10 ? `\n … and ${C.operations.length - 10} more` : ""}\nNo fingerprint was recorded — recording one would make the next boot report "schema up to date" for a schema that was never applied. This is a framework bug.\n` + (m ? " This dialect applies a plan atomically, so the run is rolled back and the schema IS unchanged.\n" : ` This dialect does NOT apply a plan atomically. The ${n.length} operation(s) below are COMMITTED\n and there is no rollback — the schema is PART-APPLIED, not unchanged:\n${r}\n Re-running plans from where the database now is, which is a different plan from the one that failed.\n`) + "Two causes look identical from here, so read the list before assuming either:\n - the DDL for those operations is a no-op (it succeeded and changed nothing), or\n - the planner cannot see what the DDL did, so it proposes the same work again — which is what an\n operation naming an object a PREVIOUS operation created or renamed usually means.\nReport the operation kinds above with the column types involved."));
|
|
3599
3615
|
}
|
|
3600
|
-
let ee = a.filter((e) => e.status === "applied").length, w = Date.now() - i,
|
|
3616
|
+
let ee = a.filter((e) => e.status === "applied").length, w = Date.now() - i, te = _, T = (/* @__PURE__ */ new Date()).toISOString(), ne = yield* W(e, T), E = [...h, ...v.map((e) => e.planned)];
|
|
3601
3617
|
yield* e`
|
|
3602
3618
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3603
3619
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
3604
3620
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
3605
3621
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
3606
3622
|
VALUES
|
|
3607
|
-
(${
|
|
3623
|
+
(${te}, ${l.toFingerprint}, ${C.fromFingerprint}, ${JSON.stringify(E)},
|
|
3608
3624
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3609
3625
|
${w}, ${ne}, ${n.notes ?? null})
|
|
3610
|
-
`, yield*
|
|
3626
|
+
`, yield* so(e, _);
|
|
3611
3627
|
let re = [...new Set(E.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3612
|
-
return yield* D.promise(() =>
|
|
3613
|
-
id:
|
|
3614
|
-
appliedAt:
|
|
3628
|
+
return yield* D.promise(() => ce({ changedTables: re }).catch(() => {})), {
|
|
3629
|
+
id: te,
|
|
3630
|
+
appliedAt: T,
|
|
3615
3631
|
fingerprint: l.toFingerprint,
|
|
3616
3632
|
operations: E,
|
|
3617
3633
|
appliedBy: n.appliedBy,
|
|
@@ -3621,7 +3637,7 @@ BEGIN
|
|
|
3621
3637
|
source: n.source,
|
|
3622
3638
|
...n.notes ? { notes: n.notes } : {}
|
|
3623
3639
|
};
|
|
3624
|
-
}),
|
|
3640
|
+
}), vo = (e, t) => {
|
|
3625
3641
|
switch (t.kind) {
|
|
3626
3642
|
case "drop-foreign-key": return {
|
|
3627
3643
|
...e,
|
|
@@ -3654,36 +3670,36 @@ BEGIN
|
|
|
3654
3670
|
};
|
|
3655
3671
|
}
|
|
3656
3672
|
}, Q = (e, t, n) => {
|
|
3657
|
-
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? D.void :
|
|
3673
|
+
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? D.void : Ya(e, t.table, ia(vo(r, t)), t.kind);
|
|
3658
3674
|
switch (t.kind) {
|
|
3659
3675
|
case "drop-foreign-key": return e.onDialectOrElse({
|
|
3660
|
-
mysql: () => Y(e,
|
|
3676
|
+
mysql: () => Y(e, Va(t), t.kind),
|
|
3661
3677
|
sqlite: i,
|
|
3662
|
-
orElse: () => Y(e,
|
|
3678
|
+
orElse: () => Y(e, Ba(t), t.kind)
|
|
3663
3679
|
});
|
|
3664
3680
|
case "drop-index": return e.onDialectOrElse({
|
|
3665
|
-
mysql: () => Y(e,
|
|
3666
|
-
mssql: () => Y(e,
|
|
3667
|
-
orElse: () => Y(e,
|
|
3681
|
+
mysql: () => Y(e, xa(t), t.kind),
|
|
3682
|
+
mssql: () => Y(e, Sa(t), t.kind),
|
|
3683
|
+
orElse: () => Y(e, ba(t), t.kind)
|
|
3668
3684
|
});
|
|
3669
3685
|
case "drop-column": return e.onDialectOrElse({
|
|
3670
|
-
mysql: () =>
|
|
3686
|
+
mysql: () => oi(e).pipe(D.flatMap((n) => Y(e, Ai(t, n), t.kind, [_i]))),
|
|
3671
3687
|
sqlite: i,
|
|
3672
|
-
orElse: () => Y(e,
|
|
3688
|
+
orElse: () => Y(e, ki(t, G), t.kind)
|
|
3673
3689
|
});
|
|
3674
3690
|
case "rename-column": return e.onDialectOrElse({
|
|
3675
|
-
mysql: () => Y(e,
|
|
3676
|
-
mssql: () =>
|
|
3677
|
-
orElse: () => Y(e,
|
|
3691
|
+
mysql: () => Y(e, ji(t, K), t.kind),
|
|
3692
|
+
mssql: () => Xa(e, t),
|
|
3693
|
+
orElse: () => Y(e, ji(t, G), t.kind)
|
|
3678
3694
|
});
|
|
3679
3695
|
}
|
|
3680
|
-
},
|
|
3696
|
+
}, yo = (e, t, n) => fo(e, t, { declared: n }), bo = (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"), xo = (e) => e`
|
|
3681
3697
|
SELECT fingerprint
|
|
3682
3698
|
FROM _voltro_migration_plans
|
|
3683
3699
|
ORDER BY ${e("appliedAt")} DESC
|
|
3684
3700
|
LIMIT 1
|
|
3685
|
-
`.pipe(D.map((e) => e.length > 0 ? e[0].fingerprint : void 0), D.catchAll(() => D.succeed(void 0))),
|
|
3686
|
-
if ((yield*
|
|
3701
|
+
`.pipe(D.map((e) => e.length > 0 ? e[0].fingerprint : void 0), D.catchAll(() => D.succeed(void 0))), So = (e, t, n) => D.gen(function* () {
|
|
3702
|
+
if ((yield* xo(e)) === t.toFingerprint) return "already-current";
|
|
3687
3703
|
let r = `plan_${Date.now().toString(36)}`, i = yield* W(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3688
3704
|
return yield* e`
|
|
3689
3705
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3695,8 +3711,8 @@ BEGIN
|
|
|
3695
3711
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3696
3712
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3697
3713
|
`, "recorded";
|
|
3698
|
-
}).pipe(D.catchAll(() => D.succeed("already-current"))),
|
|
3699
|
-
let n =
|
|
3714
|
+
}).pipe(D.catchAll(() => D.succeed("already-current"))), Co = (e, t) => D.gen(function* () {
|
|
3715
|
+
let n = R(z(t, A(e))), r = yield* xo(e);
|
|
3700
3716
|
return r === n ? {
|
|
3701
3717
|
kind: "up-to-date",
|
|
3702
3718
|
fingerprint: n
|
|
@@ -3705,23 +3721,23 @@ BEGIN
|
|
|
3705
3721
|
expected: n,
|
|
3706
3722
|
...r === void 0 ? {} : { actual: r }
|
|
3707
3723
|
};
|
|
3708
|
-
}),
|
|
3724
|
+
}), wo = [
|
|
3709
3725
|
"pgeagertest_",
|
|
3710
3726
|
"mig_e2e_",
|
|
3711
3727
|
"mig_test_",
|
|
3712
3728
|
"mysqleagertest_",
|
|
3713
3729
|
"mssqleagertest_",
|
|
3714
3730
|
"sqliteeagertest_"
|
|
3715
|
-
],
|
|
3731
|
+
], To = (e) => wo.some((t) => e.startsWith(t)), Eo = (e, t) => D.gen(function* () {
|
|
3716
3732
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3717
|
-
let n = t.filter((e) =>
|
|
3733
|
+
let n = t.filter((e) => To(e.name)).map((e) => e.name);
|
|
3718
3734
|
if (n.length === 0) return [];
|
|
3719
3735
|
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(D.catchAll(() => D.void));
|
|
3720
3736
|
return n;
|
|
3721
|
-
}),
|
|
3737
|
+
}), Do = () => {
|
|
3722
3738
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3723
3739
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3724
|
-
},
|
|
3740
|
+
}, Oo = (e) => {
|
|
3725
3741
|
if (e === void 0) return;
|
|
3726
3742
|
let t = e.trim();
|
|
3727
3743
|
if (t === "") return;
|
|
@@ -3731,55 +3747,55 @@ BEGIN
|
|
|
3731
3747
|
kind: "tables",
|
|
3732
3748
|
tables: new Set(n)
|
|
3733
3749
|
} : void 0;
|
|
3734
|
-
},
|
|
3750
|
+
}, ko = (e) => typeof e.table == "string" ? e.table : void 0, Ao = (e, t = { kind: "all" }) => ({
|
|
3735
3751
|
...e,
|
|
3736
3752
|
operations: e.operations.map((e) => {
|
|
3737
3753
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3738
3754
|
if (t?.kind === "tables") {
|
|
3739
|
-
let n =
|
|
3755
|
+
let n = ko(e.op);
|
|
3740
3756
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3741
3757
|
}
|
|
3742
3758
|
let { blocked: n, ...r } = e;
|
|
3743
3759
|
return r;
|
|
3744
3760
|
})
|
|
3745
|
-
}),
|
|
3761
|
+
}), jo = (e, t, n) => t === "postgres" ? Qn(e, n).pipe(D.flatMap((e) => {
|
|
3746
3762
|
let t = $n(e);
|
|
3747
3763
|
return t === void 0 ? D.void : D.logWarning(`auto-migrate: ${t}`).pipe(D.annotateLogs({ scope: "voltro:migrate" }));
|
|
3748
|
-
}), D.catchAll(() => D.void)) : D.void,
|
|
3749
|
-
let r =
|
|
3764
|
+
}), D.catchAll(() => D.void)) : D.void, Mo = (e, t, n) => D.gen(function* () {
|
|
3765
|
+
let r = A(e), i = t;
|
|
3750
3766
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3751
|
-
let t =
|
|
3752
|
-
if ((yield*
|
|
3767
|
+
let t = R(z(i, r));
|
|
3768
|
+
if ((yield* xo(e)) === t) return yield* jo(e, r, i), {
|
|
3753
3769
|
kind: "up-to-date",
|
|
3754
3770
|
fingerprint: t
|
|
3755
3771
|
};
|
|
3756
3772
|
}
|
|
3757
|
-
let a = yield*
|
|
3773
|
+
let a = yield* ri(e), o = yield* Eo(e, a.tables);
|
|
3758
3774
|
o.length > 0 && (yield* D.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(D.annotateLogs({
|
|
3759
3775
|
scope: "voltro:migrate",
|
|
3760
3776
|
count: o.length
|
|
3761
|
-
})), a = yield*
|
|
3777
|
+
})), a = yield* ri(e));
|
|
3762
3778
|
{
|
|
3763
|
-
let e = n.softDropRetentionDays ?? 7, t =
|
|
3764
|
-
t.length > 0 && (yield* D.logWarning(`auto-migrate: ${
|
|
3779
|
+
let e = n.softDropRetentionDays ?? 7, t = C(a, { retentionDays: e });
|
|
3780
|
+
t.length > 0 && (yield* D.logWarning(`auto-migrate: ${g(t, e)}`).pipe(D.annotateLogs({
|
|
3765
3781
|
scope: "voltro:migrate",
|
|
3766
3782
|
snapshots: t.map((e) => e.name)
|
|
3767
3783
|
})));
|
|
3768
3784
|
}
|
|
3769
|
-
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !
|
|
3785
|
+
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !T(e.name) || s.has(e.name)), l = jr({
|
|
3770
3786
|
declared: i,
|
|
3771
3787
|
live: { tables: c(a.tables) },
|
|
3772
3788
|
dialect: r,
|
|
3773
|
-
...
|
|
3789
|
+
...Do()
|
|
3774
3790
|
});
|
|
3775
3791
|
if (l.summary.blocked > 0) {
|
|
3776
|
-
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
3777
|
-
if (t === void 0 || !e || (l =
|
|
3792
|
+
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Oo(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3793
|
+
if (t === void 0 || !e || (l = Ao(l, t), l.operations.some((e) => e.blocked))) return {
|
|
3778
3794
|
kind: "refused-blocked",
|
|
3779
3795
|
plan: l
|
|
3780
3796
|
};
|
|
3781
3797
|
}
|
|
3782
|
-
return l.operations.length === 0 ? (yield*
|
|
3798
|
+
return l.operations.length === 0 ? (yield* So(e, l, {
|
|
3783
3799
|
appliedBy: n.appliedBy,
|
|
3784
3800
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3785
3801
|
source: "auto-diff"
|
|
@@ -3788,27 +3804,27 @@ BEGIN
|
|
|
3788
3804
|
fingerprint: l.toFingerprint
|
|
3789
3805
|
}) : {
|
|
3790
3806
|
kind: "applied",
|
|
3791
|
-
applied: yield*
|
|
3807
|
+
applied: yield* go(e, l, {
|
|
3792
3808
|
declared: t,
|
|
3793
3809
|
appliedBy: n.appliedBy,
|
|
3794
3810
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3795
3811
|
source: "auto-diff",
|
|
3796
3812
|
replan: (e) => D.gen(function* () {
|
|
3797
|
-
let t = yield*
|
|
3813
|
+
let t = yield* ri(e);
|
|
3798
3814
|
return jr({
|
|
3799
3815
|
declared: i,
|
|
3800
3816
|
live: { tables: c(t.tables) },
|
|
3801
3817
|
dialect: r,
|
|
3802
|
-
...
|
|
3818
|
+
...Do()
|
|
3803
3819
|
});
|
|
3804
3820
|
})
|
|
3805
3821
|
}),
|
|
3806
3822
|
plan: l
|
|
3807
3823
|
};
|
|
3808
|
-
}),
|
|
3824
|
+
}), No = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? D.succeed({
|
|
3809
3825
|
kind: "skipped",
|
|
3810
3826
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3811
|
-
}) : n.environment === "prod" ?
|
|
3827
|
+
}) : n.environment === "prod" ? Co(e, t) : Mo(e, t, n), Po = (e, t) => {
|
|
3812
3828
|
switch (e.kind) {
|
|
3813
3829
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3814
3830
|
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${Kn(e.fingerprint)})`;
|
|
@@ -3818,7 +3834,7 @@ BEGIN
|
|
|
3818
3834
|
}
|
|
3819
3835
|
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${Kn(e.expected)}` + (e.actual ? ` live=${Kn(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
3820
3836
|
case "refused-blocked": {
|
|
3821
|
-
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` +
|
|
3837
|
+
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` + bo(e.plan), c = [""];
|
|
3822
3838
|
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) {
|
|
3823
3839
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3824
3840
|
for (let r of e.plan.operations) {
|
|
@@ -3835,7 +3851,7 @@ BEGIN
|
|
|
3835
3851
|
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");
|
|
3836
3852
|
}
|
|
3837
3853
|
}
|
|
3838
|
-
},
|
|
3854
|
+
}, Fo = (e) => typeof e.__definition == "function" ? o({ c: e }).c : e, $ = (e, t = /* @__PURE__ */ new Map()) => {
|
|
3839
3855
|
let n = {};
|
|
3840
3856
|
for (let r of e.columns) {
|
|
3841
3857
|
let e = r.references, i = e === void 0 ? void 0 : t.get(e.table);
|
|
@@ -3886,66 +3902,66 @@ BEGIN
|
|
|
3886
3902
|
})),
|
|
3887
3903
|
...e.primaryKey === void 0 ? {} : { appliedPrimaryKey: e.primaryKey }
|
|
3888
3904
|
};
|
|
3889
|
-
},
|
|
3905
|
+
}, Io = (e) => {
|
|
3890
3906
|
let t = new Map(e.tables.map((e) => [e.name, e]));
|
|
3891
3907
|
return e.tables.map((e) => $(e, t));
|
|
3892
|
-
},
|
|
3908
|
+
}, Lo = (e, t = "safe") => ({
|
|
3893
3909
|
op: e,
|
|
3894
3910
|
classification: t,
|
|
3895
3911
|
reason: "file migration schema operation"
|
|
3896
|
-
}),
|
|
3912
|
+
}), Ro = (e) => D.isEffect(e) ? e : D.tryPromise({
|
|
3897
3913
|
try: () => e,
|
|
3898
3914
|
catch: (e) => e
|
|
3899
|
-
}),
|
|
3900
|
-
let
|
|
3901
|
-
let n =
|
|
3915
|
+
}), zo = (e, t) => e.run === void 0 ? Promise.reject(/* @__PURE__ */ Error("this data store cannot execute raw SQL inside its transaction — use the store for data, or a non-transactional scope for sql")) : e.run(t), Bo = (e, t, n) => {
|
|
3916
|
+
let r = () => ri(e), i = (e, t) => e.tables.find((e) => e.name === t), a = (e, t, n) => i(e, t)?.columns.find((e) => e.name === n), o = (e) => D.succeed(e), s = (e) => new Map(e.tables.map((e) => [e.name, e])), c = (e, t) => {
|
|
3917
|
+
let n = i(e, t);
|
|
3902
3918
|
if (n === void 0) throw Error(`schema: table ${t} does not exist`);
|
|
3903
3919
|
return n;
|
|
3904
|
-
},
|
|
3905
|
-
let
|
|
3906
|
-
declared: [
|
|
3907
|
-
live: yield*
|
|
3908
|
-
dialect:
|
|
3920
|
+
}, l = (n) => D.gen(function* () {
|
|
3921
|
+
let i = () => r().pipe(D.map((e) => ({ tables: e.tables.filter((e) => e.name === n.tableName) }))), a = Ao(jr({
|
|
3922
|
+
declared: [n],
|
|
3923
|
+
live: yield* i(),
|
|
3924
|
+
dialect: t
|
|
3909
3925
|
})), o = a.operations.filter((e) => e.blocked !== void 0);
|
|
3910
|
-
if (o.length > 0) return yield* D.fail(/* @__PURE__ */ Error(`evolve(${
|
|
3911
|
-
for (let
|
|
3926
|
+
if (o.length > 0) return yield* D.fail(/* @__PURE__ */ Error(`evolve(${n.tableName}): ${o.length} operation(s) cannot be planned:\n` + o.map((e) => ` - ${e.op.kind}: ${e.blocked?.fix ?? e.reason}`).join("\n")));
|
|
3927
|
+
for (let t of a.operations) yield* yo(e, t, [n]);
|
|
3912
3928
|
let s = jr({
|
|
3913
|
-
declared: [
|
|
3914
|
-
live: yield*
|
|
3915
|
-
dialect:
|
|
3929
|
+
declared: [n],
|
|
3930
|
+
live: yield* i(),
|
|
3931
|
+
dialect: t
|
|
3916
3932
|
});
|
|
3917
|
-
return s.operations.length > 0 ? yield* D.fail(/* @__PURE__ */ Error(`evolve(${
|
|
3933
|
+
return s.operations.length > 0 ? yield* D.fail(/* @__PURE__ */ Error(`evolve(${n.tableName}): applied ${a.operations.length} operation(s) and the re-plan still finds ${s.operations.length}: ${s.operations.map((e) => e.op.kind).join(", ")} — the migration did not converge`)) : { applied: a.operations.length };
|
|
3918
3934
|
});
|
|
3919
3935
|
return {
|
|
3920
|
-
snapshot:
|
|
3921
|
-
evolve:
|
|
3936
|
+
snapshot: r,
|
|
3937
|
+
evolve: l,
|
|
3922
3938
|
createTable: (e) => D.gen(function* () {
|
|
3923
|
-
return (yield*
|
|
3939
|
+
return (yield* r()).tables.some((t) => t.name === e.tableName) ? yield* o("already-present") : (yield* l(e), "applied");
|
|
3924
3940
|
}),
|
|
3925
|
-
dropTable: (
|
|
3926
|
-
return (yield*
|
|
3941
|
+
dropTable: (t) => D.gen(function* () {
|
|
3942
|
+
return (yield* r()).tables.some((e) => e.name === t) ? (yield* yo(e, Lo({
|
|
3927
3943
|
kind: "drop-table",
|
|
3928
|
-
table:
|
|
3929
|
-
}, "lossy"), []), "applied") : yield*
|
|
3944
|
+
table: t
|
|
3945
|
+
}, "lossy"), []), "applied") : yield* o("already-absent");
|
|
3930
3946
|
}),
|
|
3931
|
-
renameTable: (
|
|
3932
|
-
let
|
|
3933
|
-
return !
|
|
3947
|
+
renameTable: (t, n) => D.gen(function* () {
|
|
3948
|
+
let a = yield* r(), s = i(a, t) !== void 0, l = i(a, n) !== void 0;
|
|
3949
|
+
return !s && l ? yield* o("already-present") : s ? l ? yield* D.fail(/* @__PURE__ */ Error(`renameTable: ${n} already exists beside ${t}`)) : (yield* yo(e, Lo({
|
|
3934
3950
|
kind: "rename-table",
|
|
3935
|
-
from:
|
|
3951
|
+
from: t,
|
|
3936
3952
|
to: n
|
|
3937
|
-
}), [$(
|
|
3953
|
+
}), [$(c(a, t))]), "applied") : yield* D.fail(/* @__PURE__ */ Error(`renameTable: ${t} does not exist`));
|
|
3938
3954
|
}),
|
|
3939
|
-
addColumn: (
|
|
3940
|
-
let a = yield*
|
|
3941
|
-
if (
|
|
3942
|
-
let d =
|
|
3955
|
+
addColumn: (t, n, i) => D.gen(function* () {
|
|
3956
|
+
let a = yield* r(), u = c(a, t);
|
|
3957
|
+
if (u.columns.some((e) => e.name === n)) return yield* o("already-present");
|
|
3958
|
+
let d = Fo(i);
|
|
3943
3959
|
if (!d.nullable && !d.hasDefault && d.backfill === void 0) {
|
|
3944
|
-
let r = yield*
|
|
3945
|
-
if (Number(r[0]?.n ?? 0) > 0) return yield* D.fail(/* @__PURE__ */ Error(`addColumn(${
|
|
3960
|
+
let r = yield* e`SELECT COUNT(*) AS n FROM ${e(t)}`;
|
|
3961
|
+
if (Number(r[0]?.n ?? 0) > 0) return yield* D.fail(/* @__PURE__ */ Error(`addColumn(${t}.${n}): a NOT NULL column without a default cannot be added to a table with rows on any dialect. Add it nullable or with a default, fill it (rewrite), then alterColumn(${JSON.stringify(t)}, ${JSON.stringify(n)}, { nullable: false }).`));
|
|
3946
3962
|
}
|
|
3947
|
-
let f = $(
|
|
3948
|
-
return yield*
|
|
3963
|
+
let f = $(u, s(a));
|
|
3964
|
+
return yield* l({
|
|
3949
3965
|
...f,
|
|
3950
3966
|
fields: {
|
|
3951
3967
|
...f.fields,
|
|
@@ -3954,12 +3970,12 @@ BEGIN
|
|
|
3954
3970
|
}), "applied";
|
|
3955
3971
|
}),
|
|
3956
3972
|
alterColumn: (e, t, n) => D.gen(function* () {
|
|
3957
|
-
let
|
|
3958
|
-
if (
|
|
3959
|
-
let d = n.default === void 0 || (n.default === null ? !
|
|
3960
|
-
if ((n.nullable === void 0 || n.nullable ===
|
|
3973
|
+
let i = yield* r(), a = c(i, e), u = a.columns.find((e) => e.name === t);
|
|
3974
|
+
if (u === void 0) return yield* D.fail(/* @__PURE__ */ Error(`alterColumn: ${e}.${t} does not exist`));
|
|
3975
|
+
let d = n.default === void 0 || (n.default === null ? !u.hasDefault : u.hasDefault && String(u.defaultValue) === String(n.default));
|
|
3976
|
+
if ((n.nullable === void 0 || n.nullable === u.nullable) && d) return yield* o("already-present");
|
|
3961
3977
|
let f = {
|
|
3962
|
-
...
|
|
3978
|
+
...u,
|
|
3963
3979
|
...n.nullable === void 0 ? {} : { nullable: n.nullable },
|
|
3964
3980
|
...n.default === void 0 ? {} : n.default === null ? {
|
|
3965
3981
|
hasDefault: !1,
|
|
@@ -3969,127 +3985,124 @@ BEGIN
|
|
|
3969
3985
|
defaultValue: n.default
|
|
3970
3986
|
}
|
|
3971
3987
|
};
|
|
3972
|
-
return yield*
|
|
3988
|
+
return yield* l($({
|
|
3973
3989
|
...a,
|
|
3974
3990
|
columns: a.columns.map((e) => e.name === t ? f : e)
|
|
3975
|
-
},
|
|
3991
|
+
}, s(i))), "applied";
|
|
3976
3992
|
}),
|
|
3977
3993
|
addIndex: (e, t, n = {}) => D.gen(function* () {
|
|
3978
|
-
let
|
|
3979
|
-
if (
|
|
3994
|
+
let i = yield* r(), a = c(i, e), u = n.unique === !0;
|
|
3995
|
+
if (u && t.length === 1) {
|
|
3980
3996
|
let n = a.columns.find((e) => e.name === t[0]);
|
|
3981
|
-
return n === void 0 ? yield* D.fail(/* @__PURE__ */ Error(`addIndex: ${e}.${t[0]} does not exist`)) : n.unique ? yield*
|
|
3997
|
+
return n === void 0 ? yield* D.fail(/* @__PURE__ */ Error(`addIndex: ${e}.${t[0]} does not exist`)) : n.unique ? yield* o("already-present") : (yield* l($({
|
|
3982
3998
|
...a,
|
|
3983
3999
|
columns: a.columns.map((e) => e.name === n.name ? {
|
|
3984
4000
|
...e,
|
|
3985
4001
|
unique: !0
|
|
3986
4002
|
} : e)
|
|
3987
|
-
},
|
|
4003
|
+
}, s(i))), "applied");
|
|
3988
4004
|
}
|
|
3989
4005
|
let d = n.name ?? `${e}_${t.join("_")}_idx`;
|
|
3990
|
-
if (a.indexes.some((e) => e.name === d)) return yield*
|
|
4006
|
+
if (a.indexes.some((e) => e.name === d)) return yield* o("already-present");
|
|
3991
4007
|
let f = {
|
|
3992
4008
|
name: d,
|
|
3993
4009
|
table: e,
|
|
3994
4010
|
columns: t,
|
|
3995
|
-
unique:
|
|
4011
|
+
unique: u
|
|
3996
4012
|
};
|
|
3997
|
-
return yield*
|
|
4013
|
+
return yield* l($({
|
|
3998
4014
|
...a,
|
|
3999
4015
|
indexes: [...a.indexes, f]
|
|
4000
|
-
},
|
|
4016
|
+
}, s(i))), "applied";
|
|
4001
4017
|
}),
|
|
4002
|
-
addForeignKey: (e,
|
|
4003
|
-
let d = yield*
|
|
4004
|
-
if (p === void 0) return yield* D.fail(/* @__PURE__ */ Error(`addForeignKey: ${e}.${
|
|
4005
|
-
if (p.references !== void 0) return yield*
|
|
4006
|
-
if (
|
|
4007
|
-
let m =
|
|
4008
|
-
if ((
|
|
4018
|
+
addForeignKey: (e, n, a, u = {}) => D.gen(function* () {
|
|
4019
|
+
let d = yield* r(), f = c(d, e), p = f.columns.find((e) => e.name === n);
|
|
4020
|
+
if (p === void 0) return yield* D.fail(/* @__PURE__ */ Error(`addForeignKey: ${e}.${n} does not exist`));
|
|
4021
|
+
if (p.references !== void 0) return yield* o("already-present");
|
|
4022
|
+
if (i(d, a.table) === void 0) return yield* D.fail(/* @__PURE__ */ Error(`addForeignKey: target table ${a.table} does not exist`));
|
|
4023
|
+
let m = a.column ?? "id";
|
|
4024
|
+
if ((t === "mysql" || t === "mariadb" || t === "mssql") && p.type === "text" && p.maxLength === void 0) return yield* D.fail(/* @__PURE__ */ Error(`addForeignKey(${e}.${n}): an unbounded text column cannot carry a FOREIGN KEY on ${t} — the referencing column must match the key's width. Add the column as \`reference(() => target)\` (addColumn), or give it \`text().maxLength(n)\` matching the key first.`));
|
|
4009
4025
|
let h = {
|
|
4010
4026
|
...p,
|
|
4011
4027
|
type: "reference",
|
|
4012
4028
|
references: {
|
|
4013
|
-
table:
|
|
4029
|
+
table: a.table,
|
|
4014
4030
|
column: m,
|
|
4015
|
-
onDelete:
|
|
4016
|
-
onUpdate:
|
|
4031
|
+
onDelete: u.onDelete ?? "noAction",
|
|
4032
|
+
onUpdate: u.onUpdate ?? "noAction"
|
|
4017
4033
|
}
|
|
4018
4034
|
};
|
|
4019
|
-
return yield*
|
|
4035
|
+
return yield* l($({
|
|
4020
4036
|
...f,
|
|
4021
|
-
columns: f.columns.map((e) => e.name ===
|
|
4022
|
-
},
|
|
4037
|
+
columns: f.columns.map((e) => e.name === n ? h : e)
|
|
4038
|
+
}, s(d))), "applied";
|
|
4023
4039
|
}),
|
|
4024
4040
|
truncate: (t) => D.gen(function* () {
|
|
4025
|
-
yield*
|
|
4026
|
-
try: () => r.deleteMany(t, { where: e("id") }),
|
|
4027
|
-
catch: (e) => e
|
|
4028
|
-
});
|
|
4041
|
+
return (yield* r()).tables.some((e) => e.name === t) ? (yield* e`DELETE FROM ${e(t)}`, "applied") : yield* o("already-absent");
|
|
4029
4042
|
}),
|
|
4030
|
-
tableExists: (e) =>
|
|
4031
|
-
columnExists: (e, t) =>
|
|
4032
|
-
indexExists: (e, t) =>
|
|
4033
|
-
foreignKeyExists: (e, t) =>
|
|
4034
|
-
dropForeignKey: (
|
|
4035
|
-
let
|
|
4036
|
-
return
|
|
4043
|
+
tableExists: (e) => r().pipe(D.map((t) => i(t, e) !== void 0)),
|
|
4044
|
+
columnExists: (e, t) => r().pipe(D.map((n) => a(n, e, t) !== void 0)),
|
|
4045
|
+
indexExists: (e, t) => r().pipe(D.map((n) => i(n, e)?.indexes.some((e) => e.name === t) ?? !1)),
|
|
4046
|
+
foreignKeyExists: (e, t) => r().pipe(D.map((n) => a(n, e, t)?.references !== void 0)),
|
|
4047
|
+
dropForeignKey: (t, n) => D.gen(function* () {
|
|
4048
|
+
let i = yield* r(), s = a(i, t, n);
|
|
4049
|
+
return s?.references === void 0 ? yield* o("already-absent") : (yield* Q(e, {
|
|
4037
4050
|
kind: "drop-foreign-key",
|
|
4038
|
-
table:
|
|
4051
|
+
table: t,
|
|
4039
4052
|
column: n,
|
|
4040
|
-
...
|
|
4041
|
-
},
|
|
4053
|
+
...s.references.constraintName === void 0 ? {} : { name: s.references.constraintName }
|
|
4054
|
+
}, i), "applied");
|
|
4042
4055
|
}),
|
|
4043
|
-
dropIndex: (
|
|
4044
|
-
let
|
|
4045
|
-
return a
|
|
4056
|
+
dropIndex: (t, n) => D.gen(function* () {
|
|
4057
|
+
let a = yield* r();
|
|
4058
|
+
return i(a, t)?.indexes.some((e) => e.name === n) ?? !1 ? (yield* Q(e, {
|
|
4046
4059
|
kind: "drop-index",
|
|
4047
|
-
table:
|
|
4060
|
+
table: t,
|
|
4048
4061
|
index: n
|
|
4049
|
-
},
|
|
4062
|
+
}, a), "applied") : yield* o("already-absent");
|
|
4050
4063
|
}),
|
|
4051
|
-
dropColumn: (
|
|
4052
|
-
let
|
|
4053
|
-
if (c === void 0) return yield*
|
|
4054
|
-
c.references !== void 0 && (yield* Q(
|
|
4064
|
+
dropColumn: (t, n) => D.gen(function* () {
|
|
4065
|
+
let s = yield* r(), c = a(s, t, n);
|
|
4066
|
+
if (c === void 0) return yield* o("already-absent");
|
|
4067
|
+
c.references !== void 0 && (yield* Q(e, {
|
|
4055
4068
|
kind: "drop-foreign-key",
|
|
4056
|
-
table:
|
|
4069
|
+
table: t,
|
|
4057
4070
|
column: n,
|
|
4058
4071
|
...c.references.constraintName === void 0 ? {} : { name: c.references.constraintName }
|
|
4059
|
-
},
|
|
4060
|
-
for (let
|
|
4072
|
+
}, s), s = yield* r());
|
|
4073
|
+
for (let r of i(s, t)?.indexes ?? []) r.columns.includes(n) && r.name !== `${t}_pkey` && (yield* Q(e, {
|
|
4061
4074
|
kind: "drop-index",
|
|
4062
|
-
table:
|
|
4063
|
-
index:
|
|
4064
|
-
},
|
|
4065
|
-
return
|
|
4075
|
+
table: t,
|
|
4076
|
+
index: r.name
|
|
4077
|
+
}, s));
|
|
4078
|
+
return i(s, t)?.indexes.some((e) => e.columns.includes(n) && e.name !== `${t}_pkey`) && (s = yield* r()), yield* Q(e, {
|
|
4066
4079
|
kind: "drop-column",
|
|
4067
|
-
table:
|
|
4080
|
+
table: t,
|
|
4068
4081
|
column: n
|
|
4069
|
-
},
|
|
4082
|
+
}, s), "applied";
|
|
4070
4083
|
}),
|
|
4071
|
-
renameColumn: (
|
|
4072
|
-
let
|
|
4073
|
-
return !c && l ? yield*
|
|
4084
|
+
renameColumn: (t, n, i) => D.gen(function* () {
|
|
4085
|
+
let s = yield* r(), c = a(s, t, n) !== void 0, l = a(s, t, i) !== void 0;
|
|
4086
|
+
return !c && l ? yield* o("already-present") : c ? l ? yield* D.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${i} already exists beside ${n} — a rename cannot merge two columns`)) : (yield* Q(e, {
|
|
4074
4087
|
kind: "rename-column",
|
|
4075
|
-
table:
|
|
4088
|
+
table: t,
|
|
4076
4089
|
from: n,
|
|
4077
|
-
to:
|
|
4078
|
-
},
|
|
4090
|
+
to: i
|
|
4091
|
+
}, s), "applied") : yield* D.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${n} does not exist`));
|
|
4079
4092
|
})
|
|
4080
4093
|
};
|
|
4081
|
-
},
|
|
4094
|
+
}, Vo = (t, n, i, a) => {
|
|
4082
4095
|
let o;
|
|
4083
4096
|
return (async function* () {
|
|
4084
4097
|
for (;;) {
|
|
4085
|
-
let s = [o === void 0 ? void 0 :
|
|
4098
|
+
let s = [o === void 0 ? void 0 : r("id", o), a].filter((e) => e !== void 0), c = await t.query({
|
|
4086
4099
|
table: n,
|
|
4087
|
-
predicate: s.length === 0 ? void 0 : s.length === 1 ? s[0] :
|
|
4100
|
+
predicate: s.length === 0 ? void 0 : s.length === 1 ? s[0] : e(...s),
|
|
4088
4101
|
order: [{
|
|
4089
4102
|
column: "id",
|
|
4090
4103
|
direction: "asc"
|
|
4091
4104
|
}],
|
|
4092
|
-
take:
|
|
4105
|
+
take: i,
|
|
4093
4106
|
skip: void 0,
|
|
4094
4107
|
projection: void 0
|
|
4095
4108
|
});
|
|
@@ -4097,11 +4110,11 @@ BEGIN
|
|
|
4097
4110
|
let l = c[c.length - 1].id;
|
|
4098
4111
|
if (l == null) throw Error(`each/rewrite: ${n} rows carry no \`id\` — paging needs one`);
|
|
4099
4112
|
if (o !== void 0 && !(String(l) > String(o))) throw Error(`each/rewrite: paging ${n} did not advance past ${String(o)}`);
|
|
4100
|
-
if (o = l, yield c, c.length <
|
|
4113
|
+
if (o = l, yield c, c.length < i) return;
|
|
4101
4114
|
}
|
|
4102
4115
|
})();
|
|
4103
|
-
},
|
|
4104
|
-
let i = r.batchSize ?? 1e3, a = 0, o = 0, s =
|
|
4116
|
+
}, Ho = (e) => e > 0 ? D.sleep(`${e} millis`) : D.void, Uo = (e) => (t, n, r = {}) => D.gen(function* () {
|
|
4117
|
+
let i = r.batchSize ?? 1e3, a = 0, o = 0, s = Vo(e, t, i);
|
|
4105
4118
|
for (;;) {
|
|
4106
4119
|
let e = yield* D.tryPromise({
|
|
4107
4120
|
try: () => s.next(),
|
|
@@ -4109,22 +4122,22 @@ BEGIN
|
|
|
4109
4122
|
});
|
|
4110
4123
|
if (e.done) break;
|
|
4111
4124
|
o++;
|
|
4112
|
-
for (let t of e.value) yield*
|
|
4113
|
-
yield*
|
|
4125
|
+
for (let t of e.value) yield* Ro(n(t)), a++;
|
|
4126
|
+
yield* Ho(r.sleepMs ?? 0);
|
|
4114
4127
|
}
|
|
4115
4128
|
return {
|
|
4116
4129
|
scanned: a,
|
|
4117
4130
|
pages: o
|
|
4118
4131
|
};
|
|
4119
|
-
}),
|
|
4120
|
-
let a = i.batchSize ?? 1e3, o = i.maxPasses ?? 10,
|
|
4132
|
+
}), Wo = (e, t) => t == null ? f(e) : s(e, t), Go = (e) => typeof e != "object" || !e || e instanceof Date, Ko = (t) => (n, r, i = {}) => D.gen(function* () {
|
|
4133
|
+
let a = i.batchSize ?? 1e3, o = i.maxPasses ?? 10, c = i.guard ?? [], l = {
|
|
4121
4134
|
passes: 0,
|
|
4122
4135
|
scanned: 0,
|
|
4123
4136
|
rewritten: 0,
|
|
4124
4137
|
contended: 0
|
|
4125
4138
|
}, u = l;
|
|
4126
4139
|
for (let d = 1; d <= o; d++) {
|
|
4127
|
-
let o = 0, f = 0, p = 0, m =
|
|
4140
|
+
let o = 0, f = 0, p = 0, m = Vo(t, n, a);
|
|
4128
4141
|
for (;;) {
|
|
4129
4142
|
let a = yield* D.tryPromise({
|
|
4130
4143
|
try: () => m.next(),
|
|
@@ -4140,15 +4153,15 @@ BEGIN
|
|
|
4140
4153
|
if (a === void 0) continue;
|
|
4141
4154
|
let l = Object.entries(a).filter(([e, t]) => !Object.is(i[e], t));
|
|
4142
4155
|
if (l.length === 0) continue;
|
|
4143
|
-
let u = [
|
|
4144
|
-
for (let [e] of l)
|
|
4145
|
-
for (let e of
|
|
4156
|
+
let u = [s("id", i.id)];
|
|
4157
|
+
for (let [e] of l) Go(i[e]) && u.push(Wo(e, i[e]));
|
|
4158
|
+
for (let e of c) u.push(Wo(e, i[e]));
|
|
4146
4159
|
(yield* D.tryPromise({
|
|
4147
|
-
try: () =>
|
|
4160
|
+
try: () => t.updateMany(n, Object.fromEntries(l), { where: e(...u) }),
|
|
4148
4161
|
catch: (e) => e
|
|
4149
4162
|
})) === 1 ? f++ : p++;
|
|
4150
4163
|
}
|
|
4151
|
-
yield*
|
|
4164
|
+
yield* Ho(i.sleepMs ?? 0);
|
|
4152
4165
|
}
|
|
4153
4166
|
if (u = {
|
|
4154
4167
|
passes: d,
|
|
@@ -4162,8 +4175,8 @@ BEGIN
|
|
|
4162
4175
|
contended: l.contended + p
|
|
4163
4176
|
}, f === 0 && p === 0) return l;
|
|
4164
4177
|
}
|
|
4165
|
-
return yield* D.fail(new
|
|
4166
|
-
}),
|
|
4178
|
+
return yield* D.fail(new w(n, u));
|
|
4179
|
+
}), qo = (e) => {
|
|
4167
4180
|
let t = `migrations:file:${e.migrationId}`, n = [], r = (t) => {
|
|
4168
4181
|
if (typeof t != "string" || t.trim().length < 12) throw Error(`raw(reason): say why this migration needs raw SQL — the reason is what a reviewer and \`voltro doctor\` read (got ${JSON.stringify(t)})`);
|
|
4169
4182
|
return e.sql;
|
|
@@ -4185,9 +4198,9 @@ BEGIN
|
|
|
4185
4198
|
...n ?? {}
|
|
4186
4199
|
}))
|
|
4187
4200
|
},
|
|
4188
|
-
schema:
|
|
4189
|
-
each:
|
|
4190
|
-
rewrite:
|
|
4201
|
+
schema: Bo(a, e.dialect, i),
|
|
4202
|
+
each: Uo(i),
|
|
4203
|
+
rewrite: Ko(i),
|
|
4191
4204
|
expect: (e, t) => {
|
|
4192
4205
|
n.push({
|
|
4193
4206
|
description: e,
|
|
@@ -4195,7 +4208,7 @@ BEGIN
|
|
|
4195
4208
|
});
|
|
4196
4209
|
},
|
|
4197
4210
|
skipUnless: (e, t) => D.gen(function* () {
|
|
4198
|
-
if (!(typeof e == "boolean" ? e : yield*
|
|
4211
|
+
if (!(typeof e == "boolean" ? e : yield* Ro(e))) return yield* D.fail(new E(t));
|
|
4199
4212
|
})
|
|
4200
4213
|
}))(e.store, e.sql),
|
|
4201
4214
|
transactional: (t) => D.tryPromise({
|
|
@@ -4204,18 +4217,18 @@ BEGIN
|
|
|
4204
4217
|
store: e,
|
|
4205
4218
|
raw: r
|
|
4206
4219
|
});
|
|
4207
|
-
return D.isEffect(n) ?
|
|
4220
|
+
return D.isEffect(n) ? zo(e, n) : n;
|
|
4208
4221
|
}),
|
|
4209
4222
|
catch: (e) => e
|
|
4210
4223
|
})
|
|
4211
4224
|
},
|
|
4212
4225
|
expectations: n
|
|
4213
4226
|
};
|
|
4214
|
-
},
|
|
4227
|
+
}, Jo = (e) => D.gen(function* () {
|
|
4215
4228
|
let t = [];
|
|
4216
|
-
for (let { description: n, check: r } of e) (yield*
|
|
4229
|
+
for (let { description: n, check: r } of e) (yield* Ro(r())) || t.push(n);
|
|
4217
4230
|
return t;
|
|
4218
|
-
}),
|
|
4231
|
+
}), Yo = ge({ scope: "voltro:migrate" }), Xo = (e) => he("sha256").update(e).digest("hex").slice(0, 16), Zo = /* @__PURE__ */ new Set([
|
|
4219
4232
|
"node_modules",
|
|
4220
4233
|
"dist",
|
|
4221
4234
|
"build",
|
|
@@ -4224,38 +4237,46 @@ BEGIN
|
|
|
4224
4237
|
".next",
|
|
4225
4238
|
".git",
|
|
4226
4239
|
".framework"
|
|
4227
|
-
]),
|
|
4240
|
+
]), Qo = async (e) => {
|
|
4228
4241
|
let t = [], n = async (e) => {
|
|
4229
|
-
let r = await
|
|
4242
|
+
let r = await _e.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
4230
4243
|
for (let i of r) {
|
|
4231
|
-
if (
|
|
4232
|
-
let r =
|
|
4233
|
-
i.isDirectory() ? await n(r) : i.isFile() &&
|
|
4244
|
+
if (Zo.has(i.name)) continue;
|
|
4245
|
+
let r = ve(e, i.name);
|
|
4246
|
+
i.isDirectory() ? await n(r) : i.isFile() && oe.test(i.name) && t.push(r);
|
|
4234
4247
|
}
|
|
4235
4248
|
};
|
|
4236
4249
|
return await n(e), t.sort((e, t) => {
|
|
4237
4250
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
4238
4251
|
return n.localeCompare(r);
|
|
4239
4252
|
});
|
|
4240
|
-
},
|
|
4253
|
+
}, $o = async (e) => {
|
|
4241
4254
|
let t = [];
|
|
4242
4255
|
for (let n of e) {
|
|
4243
|
-
let e = (await import(
|
|
4244
|
-
if (!
|
|
4245
|
-
|
|
4256
|
+
let e = (await import(ye(n).href)).default;
|
|
4257
|
+
if (!se(e)) {
|
|
4258
|
+
Yo.warn("migration file has no default-exported `migration(...)` — skipped", { file: n });
|
|
4246
4259
|
continue;
|
|
4247
4260
|
}
|
|
4261
|
+
let r = await _e.readFile(n, "utf8").catch(() => "");
|
|
4248
4262
|
t.push({
|
|
4249
4263
|
file: n,
|
|
4250
|
-
migration: e
|
|
4264
|
+
migration: e,
|
|
4265
|
+
hash: Xo(r)
|
|
4251
4266
|
});
|
|
4252
4267
|
}
|
|
4253
4268
|
return t;
|
|
4254
|
-
},
|
|
4255
|
-
SELECT ${e("id")}
|
|
4269
|
+
}, es = (e) => ts(e).pipe(D.map((e) => e.map((e) => e.id))), ts = (e) => e`
|
|
4270
|
+
SELECT ${e("id")}, ${e("fingerprint")}
|
|
4256
4271
|
FROM ${e("_voltro_migration_plans")}
|
|
4257
4272
|
WHERE ${e("source")} = 'file'
|
|
4258
|
-
`.pipe(D.map((e) => e.map((e) =>
|
|
4273
|
+
`.pipe(D.map((e) => e.map((e) => ({
|
|
4274
|
+
id: e.id,
|
|
4275
|
+
hash: e.fingerprint ?? ""
|
|
4276
|
+
}))), D.catchAll(() => D.succeed([]))), ns = (e, t) => t.filter((t) => {
|
|
4277
|
+
let n = e.get(t.migration.id);
|
|
4278
|
+
return n !== void 0 && n !== "" && n !== t.hash;
|
|
4279
|
+
}).map((e) => e.migration.id), rs = class extends Error {
|
|
4259
4280
|
migrationId;
|
|
4260
4281
|
file;
|
|
4261
4282
|
cause;
|
|
@@ -4263,7 +4284,7 @@ BEGIN
|
|
|
4263
4284
|
constructor(e, t, n) {
|
|
4264
4285
|
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";
|
|
4265
4286
|
}
|
|
4266
|
-
},
|
|
4287
|
+
}, is = (e, t, n) => D.gen(function* () {
|
|
4267
4288
|
let r = yield* W(e, n.appliedAtIso);
|
|
4268
4289
|
yield* e`
|
|
4269
4290
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -4271,53 +4292,53 @@ BEGIN
|
|
|
4271
4292
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
4272
4293
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
4273
4294
|
VALUES
|
|
4274
|
-
(${t.migration.id}, ${
|
|
4295
|
+
(${t.migration.id}, ${t.hash}, ${JSON.stringify([{
|
|
4275
4296
|
kind: "file",
|
|
4276
4297
|
file: t.file
|
|
4277
4298
|
}])},
|
|
4278
4299
|
${n.appliedBy}, ${n.env}, ${"file"},
|
|
4279
4300
|
${n.durationMs}, ${r}, ${n.notes})
|
|
4280
|
-
`.pipe(D.mapError((e) => new
|
|
4281
|
-
}),
|
|
4301
|
+
`.pipe(D.mapError((e) => new rs(t.migration.id, t.file, e)));
|
|
4302
|
+
}), as = (e, t, n) => D.gen(function* () {
|
|
4282
4303
|
let r = e.migration.up(t), i = !D.isEffect(r), a = yield* (D.isEffect(r) ? r : D.tryPromise({
|
|
4283
4304
|
try: () => r,
|
|
4284
4305
|
catch: (e) => e
|
|
4285
|
-
})).pipe(D.as(void 0), D.catchIf((e) => e instanceof
|
|
4306
|
+
})).pipe(D.as(void 0), D.catchIf((e) => e instanceof E, (e) => D.succeed(e.reason)));
|
|
4286
4307
|
if (a === void 0) {
|
|
4287
|
-
let t = yield*
|
|
4288
|
-
if (t.length > 0) return yield* D.fail(new
|
|
4308
|
+
let t = yield* Jo(n);
|
|
4309
|
+
if (t.length > 0) return yield* D.fail(new b(e.migration.id, t));
|
|
4289
4310
|
}
|
|
4290
4311
|
return {
|
|
4291
4312
|
skipped: a,
|
|
4292
4313
|
promiseForm: i
|
|
4293
4314
|
};
|
|
4294
|
-
}),
|
|
4295
|
-
let o = Date.now(), s = (/* @__PURE__ */ new Date()).toISOString(), c =
|
|
4315
|
+
}), os = (e, t, n, r, i, a) => D.gen(function* () {
|
|
4316
|
+
let o = Date.now(), s = (/* @__PURE__ */ new Date()).toISOString(), c = A(e), l = `migrations:file:${n.migration.id}`, u = (e) => ({
|
|
4296
4317
|
durationMs: Date.now() - o,
|
|
4297
4318
|
notes: e.skipped === void 0 ? n.migration.description : `skipped: ${e.skipped}`
|
|
4298
4319
|
});
|
|
4299
4320
|
if (n.migration.transactional !== !1 && !a) {
|
|
4300
4321
|
if (t.run === void 0) return yield* D.fail(/* @__PURE__ */ Error(`migration ${n.migration.id}: transactional: true needs a SQL-backed store`));
|
|
4301
4322
|
let a = c === "mysql" || c === "mariadb", o = `probe_${n.migration.id}_${Date.now().toString(36)}`;
|
|
4302
|
-
a && (yield*
|
|
4303
|
-
let d = () => e`SELECT COUNT(*) AS n FROM ${e(
|
|
4323
|
+
a && (yield* eo(e, c));
|
|
4324
|
+
let d = () => e`SELECT COUNT(*) AS n FROM ${e(j)} WHERE ${e("runId")} = ${o}`.pipe(D.map((e) => Number(e[0]?.n ?? 0) > 0)), f = yield* D.tryPromise({
|
|
4304
4325
|
try: () => t.transactional(async (t) => {
|
|
4305
|
-
a && await t.run(e`INSERT INTO ${e(
|
|
4326
|
+
a && await t.run(e`INSERT INTO ${e(j)} (${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")}, ${e("status")}, ${e("opKind")}, ${e("opTarget")}, ${e("payload")})
|
|
4306
4327
|
VALUES (${`mop_${o}`}, ${o}, ${""}, ${0}, ${"pending"}, ${"probe"}, ${""}, ${"{}"})`);
|
|
4307
|
-
let { ctx: l, expectations: f } =
|
|
4328
|
+
let { ctx: l, expectations: f } = qo({
|
|
4308
4329
|
sql: e,
|
|
4309
4330
|
store: t,
|
|
4310
4331
|
dialect: c,
|
|
4311
4332
|
migrationId: n.migration.id,
|
|
4312
4333
|
appliedAt: s
|
|
4313
|
-
}), p = await t.run(
|
|
4314
|
-
return await t.run(
|
|
4334
|
+
}), p = await t.run(as(n, l, f)), m = a && await D.runPromise(d().pipe(D.provideService(O.SqlClient, e))), { durationMs: h, notes: g } = u(p);
|
|
4335
|
+
return await t.run(is(e, n, {
|
|
4315
4336
|
env: r,
|
|
4316
4337
|
appliedBy: i,
|
|
4317
4338
|
durationMs: h,
|
|
4318
4339
|
appliedAtIso: s,
|
|
4319
4340
|
notes: m ? `${g} — transactional guarantee broken by the body (DDL on ${c})` : g
|
|
4320
|
-
})), a && await t.run(e`DELETE FROM ${e(
|
|
4341
|
+
})), a && await t.run(e`DELETE FROM ${e(j)} WHERE ${e("runId")} = ${o}`), {
|
|
4321
4342
|
...p,
|
|
4322
4343
|
durationMs: h,
|
|
4323
4344
|
broken: m
|
|
@@ -4325,49 +4346,67 @@ BEGIN
|
|
|
4325
4346
|
}),
|
|
4326
4347
|
catch: (e) => e
|
|
4327
4348
|
});
|
|
4328
|
-
return f.broken ? yield* D.fail(new
|
|
4349
|
+
return f.broken ? yield* D.fail(new S(n.migration.id, c)) : (f.skipped !== void 0 && (yield* D.logInfo(`migration ${n.migration.id} skipped: ${f.skipped}`).pipe(D.annotateLogs({ scope: l }))), { durationMs: f.durationMs });
|
|
4329
4350
|
}
|
|
4330
|
-
let { ctx: d, expectations: f } =
|
|
4351
|
+
let { ctx: d, expectations: f } = qo({
|
|
4331
4352
|
sql: e,
|
|
4332
4353
|
store: t,
|
|
4333
4354
|
dialect: c,
|
|
4334
4355
|
migrationId: n.migration.id,
|
|
4335
4356
|
appliedAt: s
|
|
4336
|
-
}), p = yield*
|
|
4337
|
-
return p.promiseForm && p.skipped === void 0 && m < 2 && (yield* D.logWarning(`migration ${n.migration.id}: up() resolved in ${m}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(D.annotateLogs({ scope: l }))), p.skipped !== void 0 && (yield* D.logInfo(`migration ${n.migration.id} skipped: ${p.skipped}`).pipe(D.annotateLogs({ scope: l }))), yield*
|
|
4357
|
+
}), p = yield* as(n, d, f), { durationMs: m, notes: h } = u(p);
|
|
4358
|
+
return p.promiseForm && p.skipped === void 0 && m < 2 && (yield* D.logWarning(`migration ${n.migration.id}: up() resolved in ${m}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(D.annotateLogs({ scope: l }))), p.skipped !== void 0 && (yield* D.logInfo(`migration ${n.migration.id} skipped: ${p.skipped}`).pipe(D.annotateLogs({ scope: l }))), yield* is(e, n, {
|
|
4338
4359
|
env: r,
|
|
4339
4360
|
appliedBy: i,
|
|
4340
4361
|
durationMs: m,
|
|
4341
4362
|
appliedAtIso: s,
|
|
4342
4363
|
notes: h
|
|
4343
4364
|
}), { durationMs: m };
|
|
4344
|
-
}),
|
|
4365
|
+
}), ss = (e, t) => D.gen(function* () {
|
|
4345
4366
|
let n = yield* D.tryPromise({
|
|
4346
|
-
try: () =>
|
|
4367
|
+
try: () => Qo(ve(t, "migrations")),
|
|
4347
4368
|
catch: (e) => e
|
|
4348
4369
|
});
|
|
4349
4370
|
if (n.length === 0) return {
|
|
4350
4371
|
pending: [],
|
|
4351
|
-
skipped: []
|
|
4372
|
+
skipped: [],
|
|
4373
|
+
drifted: []
|
|
4352
4374
|
};
|
|
4353
4375
|
let r = yield* D.tryPromise({
|
|
4354
|
-
try: () =>
|
|
4376
|
+
try: () => $o(n),
|
|
4355
4377
|
catch: (e) => e
|
|
4356
4378
|
});
|
|
4357
4379
|
if (r.length === 0) return {
|
|
4358
4380
|
pending: [],
|
|
4359
|
-
skipped: []
|
|
4381
|
+
skipped: [],
|
|
4382
|
+
drifted: []
|
|
4360
4383
|
};
|
|
4361
|
-
let i = new
|
|
4384
|
+
let i = new Map((yield* ts(e)).map((e) => [e.id, e.hash])), a = ns(i, r);
|
|
4385
|
+
for (let e of a) Yo.warn("file migration: the body on disk is not the one that was applied — the file no longer describes this database", {
|
|
4386
|
+
id: e,
|
|
4387
|
+
file: r.find((t) => t.migration.id === e)?.file
|
|
4388
|
+
});
|
|
4362
4389
|
return {
|
|
4363
4390
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
4364
|
-
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
4391
|
+
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id),
|
|
4392
|
+
drifted: a
|
|
4365
4393
|
};
|
|
4366
|
-
}),
|
|
4394
|
+
}), cs = (e, t) => ss(e, t).pipe(D.map((e) => e.pending.map((e) => e.migration.id))), ls = (e, t) => ss(e, t).pipe(D.map((e) => e.pending.map((e) => ({
|
|
4367
4395
|
id: e.migration.id,
|
|
4368
|
-
irreversible:
|
|
4369
|
-
})))),
|
|
4370
|
-
let
|
|
4396
|
+
irreversible: h(e.migration.down)
|
|
4397
|
+
})))), us = (e, t) => ss(e, t).pipe(D.map((e) => {
|
|
4398
|
+
let t = new Set(e.drifted);
|
|
4399
|
+
return [...e.skipped.map((e) => ({
|
|
4400
|
+
id: e,
|
|
4401
|
+
applied: !0,
|
|
4402
|
+
bodyChanged: t.has(e)
|
|
4403
|
+
})), ...e.pending.map((e) => ({
|
|
4404
|
+
id: e.migration.id,
|
|
4405
|
+
applied: !1,
|
|
4406
|
+
bodyChanged: !1
|
|
4407
|
+
}))].sort((e, t) => e.id < t.id ? -1 : 1);
|
|
4408
|
+
})), ds = (e, t) => D.gen(function* () {
|
|
4409
|
+
let { pending: n, skipped: r } = yield* ss(e, t.projectRoot);
|
|
4371
4410
|
return n.length === 0 ? {
|
|
4372
4411
|
applied: [],
|
|
4373
4412
|
skipped: r
|
|
@@ -4380,7 +4419,7 @@ BEGIN
|
|
|
4380
4419
|
id: i.migration.id,
|
|
4381
4420
|
file: i.file
|
|
4382
4421
|
}));
|
|
4383
|
-
let { durationMs: n } = yield*
|
|
4422
|
+
let { durationMs: n } = yield* os(e, t.store, i, t.env, t.appliedBy, t.enclosed === !0);
|
|
4384
4423
|
r.push({
|
|
4385
4424
|
id: i.migration.id,
|
|
4386
4425
|
durationMs: n
|
|
@@ -4394,26 +4433,26 @@ BEGIN
|
|
|
4394
4433
|
}), (e) => e.release.pipe(D.orDie)),
|
|
4395
4434
|
skipped: r
|
|
4396
4435
|
};
|
|
4397
|
-
}),
|
|
4436
|
+
}), fs = (e, t) => e`
|
|
4398
4437
|
SELECT ${e("id")}
|
|
4399
4438
|
FROM ${e("_voltro_migration_plans")}
|
|
4400
4439
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
4401
|
-
`,
|
|
4402
|
-
if (!(yield*
|
|
4440
|
+
`, ps = (e, t) => D.gen(function* () {
|
|
4441
|
+
if (!(yield* fs(e, t.id))[0]) return yield* D.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
4403
4442
|
let n = yield* D.tryPromise({
|
|
4404
|
-
try: () =>
|
|
4443
|
+
try: () => Qo(ve(t.projectRoot, "migrations")),
|
|
4405
4444
|
catch: (e) => e
|
|
4406
4445
|
}), r = (yield* D.tryPromise({
|
|
4407
|
-
try: () =>
|
|
4446
|
+
try: () => $o(n),
|
|
4408
4447
|
catch: (e) => e
|
|
4409
4448
|
})).find((e) => e.migration.id === t.id);
|
|
4410
4449
|
if (!r) return yield* D.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
4411
|
-
let i =
|
|
4450
|
+
let i = h(r.migration.down);
|
|
4412
4451
|
return i === void 0 ? yield* D.acquireUseRelease($e(e, { schema: t.lockSchema }), () => D.gen(function* () {
|
|
4413
|
-
let n = Date.now(), { ctx: i } =
|
|
4452
|
+
let n = Date.now(), { ctx: i } = qo({
|
|
4414
4453
|
sql: e,
|
|
4415
4454
|
store: t.store,
|
|
4416
|
-
dialect:
|
|
4455
|
+
dialect: A(e),
|
|
4417
4456
|
migrationId: t.id,
|
|
4418
4457
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4419
4458
|
}), a = r.migration.down(i);
|
|
@@ -4426,8 +4465,8 @@ BEGIN
|
|
|
4426
4465
|
id: t.id,
|
|
4427
4466
|
durationMs: o
|
|
4428
4467
|
};
|
|
4429
|
-
}), (e) => e.release.pipe(D.orDie)) : yield* D.fail(new
|
|
4430
|
-
}),
|
|
4468
|
+
}), (e) => e.release.pipe(D.orDie)) : yield* D.fail(new y(t.id, i));
|
|
4469
|
+
}), ms = (e) => D.gen(function* () {
|
|
4431
4470
|
let t = yield* O.SqlClient, n = yield* t`
|
|
4432
4471
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
4433
4472
|
WHERE source = 'auto-diff'
|
|
@@ -4472,7 +4511,7 @@ BEGIN
|
|
|
4472
4511
|
snapshotFingerprint: e.fingerprint,
|
|
4473
4512
|
snapshotId: i
|
|
4474
4513
|
};
|
|
4475
|
-
}),
|
|
4514
|
+
}), hs = { safe: !0 }, gs = (e) => {
|
|
4476
4515
|
switch (e.kind) {
|
|
4477
4516
|
case "add-enum-value": return { safe: !0 };
|
|
4478
4517
|
case "drop-column": return {
|
|
@@ -4500,7 +4539,7 @@ BEGIN
|
|
|
4500
4539
|
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`,
|
|
4501
4540
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
4502
4541
|
};
|
|
4503
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
4542
|
+
case "alter-column-nullability": return e.toNullable ? hs : {
|
|
4504
4543
|
safe: !1,
|
|
4505
4544
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
4506
4545
|
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)`
|
|
@@ -4511,12 +4550,12 @@ BEGIN
|
|
|
4511
4550
|
reason: `old instances still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
|
|
4512
4551
|
remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
|
|
4513
4552
|
};
|
|
4514
|
-
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ?
|
|
4553
|
+
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ? hs : {
|
|
4515
4554
|
safe: !1,
|
|
4516
4555
|
reason: `writes to "${e.table}"."${e.column}" must satisfy the new JSON validation`,
|
|
4517
4556
|
remedy: "ensure all writers supply valid JSON in the required domain before enabling this check"
|
|
4518
4557
|
};
|
|
4519
|
-
case "add-check": return e.table.startsWith("_voltro_") ?
|
|
4558
|
+
case "add-check": return e.table.startsWith("_voltro_") ? hs : {
|
|
4520
4559
|
safe: !1,
|
|
4521
4560
|
reason: `old instances may write values to "${e.table}" the new CHECK rejects`,
|
|
4522
4561
|
remedy: "make code satisfy the constraint first and deploy that; add the CHECK in a LATER deploy"
|
|
@@ -4535,12 +4574,12 @@ BEGIN
|
|
|
4535
4574
|
case "drop-unique":
|
|
4536
4575
|
case "drop-unique-composite":
|
|
4537
4576
|
case "drop-foreign-key":
|
|
4538
|
-
case "drop-check": return
|
|
4577
|
+
case "drop-check": return hs;
|
|
4539
4578
|
}
|
|
4540
|
-
},
|
|
4579
|
+
}, _s = (e) => {
|
|
4541
4580
|
let t = [];
|
|
4542
4581
|
for (let n of e) {
|
|
4543
|
-
let e =
|
|
4582
|
+
let e = gs(n.op);
|
|
4544
4583
|
e.safe || t.push({
|
|
4545
4584
|
op: n,
|
|
4546
4585
|
reason: e.reason,
|
|
@@ -4548,7 +4587,7 @@ BEGIN
|
|
|
4548
4587
|
});
|
|
4549
4588
|
}
|
|
4550
4589
|
return t;
|
|
4551
|
-
},
|
|
4590
|
+
}, vs = (e) => {
|
|
4552
4591
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
4553
4592
|
refuse: !1,
|
|
4554
4593
|
warnForced: !1,
|
|
@@ -4564,18 +4603,18 @@ BEGIN
|
|
|
4564
4603
|
warnForced: !1,
|
|
4565
4604
|
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.`
|
|
4566
4605
|
};
|
|
4567
|
-
},
|
|
4606
|
+
}, ys = (e) => {
|
|
4568
4607
|
let t = e.table;
|
|
4569
4608
|
if (typeof t == "string") return t;
|
|
4570
4609
|
let n = e.from;
|
|
4571
4610
|
return typeof n == "string" ? n : void 0;
|
|
4572
|
-
},
|
|
4611
|
+
}, bs = (e) => ({
|
|
4573
4612
|
kind: e.op.kind,
|
|
4574
|
-
table:
|
|
4613
|
+
table: ys(e.op),
|
|
4575
4614
|
classification: e.classification,
|
|
4576
4615
|
reason: e.reason,
|
|
4577
4616
|
blockedFix: e.blocked?.fix
|
|
4578
|
-
}),
|
|
4617
|
+
}), xs = (e) => e.operations.map(bs), Ss = async (e) => {
|
|
4579
4618
|
let t = e.log ?? (() => {}), n = {
|
|
4580
4619
|
branchId: e.branchId,
|
|
4581
4620
|
mechanism: e.mechanism,
|
|
@@ -4594,10 +4633,10 @@ BEGIN
|
|
|
4594
4633
|
applied: !1,
|
|
4595
4634
|
converged: !1,
|
|
4596
4635
|
residual: r,
|
|
4597
|
-
infidelity:
|
|
4636
|
+
infidelity: xs(o)
|
|
4598
4637
|
};
|
|
4599
4638
|
else {
|
|
4600
|
-
let i = await e.plan(), o =
|
|
4639
|
+
let i = await e.plan(), o = xs(i), s = o.filter((e) => e.classification === "lossy"), c = Ao(i), l = c.operations.filter((e) => e.blocked !== void 0).map(bs);
|
|
4601
4640
|
if (l.length > 0) a = {
|
|
4602
4641
|
...n,
|
|
4603
4642
|
outcome: "blocked",
|
|
@@ -4622,7 +4661,7 @@ BEGIN
|
|
|
4622
4661
|
};
|
|
4623
4662
|
else {
|
|
4624
4663
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
4625
|
-
let i =
|
|
4664
|
+
let i = xs(await e.replan());
|
|
4626
4665
|
a = {
|
|
4627
4666
|
...n,
|
|
4628
4667
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -4660,7 +4699,7 @@ BEGIN
|
|
|
4660
4699
|
...a,
|
|
4661
4700
|
tornDown: o
|
|
4662
4701
|
};
|
|
4663
|
-
},
|
|
4702
|
+
}, Cs = (e) => {
|
|
4664
4703
|
switch (e.outcome) {
|
|
4665
4704
|
case "clean": return 0;
|
|
4666
4705
|
case "lossy": return 2;
|
|
@@ -4669,22 +4708,22 @@ BEGIN
|
|
|
4669
4708
|
case "infidelity": return 1;
|
|
4670
4709
|
case "failed": return 1;
|
|
4671
4710
|
}
|
|
4672
|
-
},
|
|
4711
|
+
}, ws = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, Ts = (e) => {
|
|
4673
4712
|
let t = [];
|
|
4674
4713
|
if (t.push(`branch rehearsal · ${e.branchId} · mechanism ${e.mechanism}`), t.push(` branched ${e.branchedTables} table(s), replayed ${e.replayedForeignKeys} foreign key(s)`), e.outcome === "failed") t.push(` FAILED: ${e.error ?? "unknown error"}`);
|
|
4675
4714
|
else if (e.outcome === "infidelity") {
|
|
4676
4715
|
t.push(" BRANCH IS NOT A FAITHFUL COPY of the parent — the rehearsal proves nothing about your migration."), t.push(" The parent's own schema still differs from the branch by:");
|
|
4677
|
-
for (let n of e.infidelity) t.push(
|
|
4716
|
+
for (let n of e.infidelity) t.push(ws(n));
|
|
4678
4717
|
} else {
|
|
4679
4718
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
4680
|
-
for (let n of e.operations) t.push(
|
|
4681
|
-
if (e.lossy.length > 0 && (t.push(""), t.push(` ⚠ ${e.lossy.length} operation(s) DESTROY DATA. They were executed on the branch (it is`), t.push(" disposable) so they are rehearsed, but production refuses them until you set"), t.push(" VOLTRO_DESTRUCTIVE_OK — naming the tables, not `1`.")), e.blocked.length > 0 && (t.push(""), t.push(` ${e.blocked.length} operation(s) the planner will not auto-apply anywhere — the plan was NOT executed.`)), e.applied && (t.push(""), t.push(e.converged ? " ✓ applied on the branch, and the re-plan is EMPTY (the migration converges)." : ` ✗ applied, but the re-plan STILL proposes ${e.residual.length} operation(s) — this migration does not converge:`), !e.converged)) for (let n of e.residual) t.push(
|
|
4719
|
+
for (let n of e.operations) t.push(ws(n));
|
|
4720
|
+
if (e.lossy.length > 0 && (t.push(""), t.push(` ⚠ ${e.lossy.length} operation(s) DESTROY DATA. They were executed on the branch (it is`), t.push(" disposable) so they are rehearsed, but production refuses them until you set"), t.push(" VOLTRO_DESTRUCTIVE_OK — naming the tables, not `1`.")), e.blocked.length > 0 && (t.push(""), t.push(` ${e.blocked.length} operation(s) the planner will not auto-apply anywhere — the plan was NOT executed.`)), e.applied && (t.push(""), t.push(e.converged ? " ✓ applied on the branch, and the re-plan is EMPTY (the migration converges)." : ` ✗ applied, but the re-plan STILL proposes ${e.residual.length} operation(s) — this migration does not converge:`), !e.converged)) for (let n of e.residual) t.push(ws(n));
|
|
4682
4721
|
}
|
|
4683
4722
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
4684
|
-
},
|
|
4723
|
+
}, Es = (e, ...t) => ({
|
|
4685
4724
|
_tag: "RawSqlFragment",
|
|
4686
4725
|
strings: [...e],
|
|
4687
4726
|
values: [...t]
|
|
4688
|
-
}),
|
|
4727
|
+
}), Ds = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
4689
4728
|
//#endregion
|
|
4690
|
-
export { bt as DEFAULT_CDC_CHANNEL, U as DEPLOY_LEDGER_TABLE,
|
|
4729
|
+
export { bt as DEFAULT_CDC_CHANNEL, U as DEPLOY_LEDGER_TABLE, oe as FILE_MIGRATION_PATTERN, rs as FileMigrationLedgerError, y as IrreversibleMigrationError, rt as MIGRATION_ATOMICITY, et as MIGRATION_NEEDS_TWO_CONNECTIONS, b as MigrationExpectationFailed, E as MigrationSkipped, xt as REACTIVE_TRIGGER_PREFIX, w as RewriteUnstableError, S as TransactionBrokenByBodyError, Ne as VOLTRO_MIGRATION_LOCK_KEY, ci as _voltroDeploysTable, $e as acquireMigrationLock, Ka as addColumnDdl, W as appliedAtValue, es as appliedFileMigrationIds, ts as appliedFileMigrations, co as appliedLedgerOperations, gn as applyNamespacedSchema, go as applyPlan, on as applySchema, vs as assessRollingDeployGate, Cs as branchRehearsalExitCode, Hr as chunkTables, gs as classifyRollingDeploySafety, lo as clearResumeLedger, ui as closeDeploy, z as declaredSnapshot, jt as defaultArrayClause, At as defaultClause, P as defaultJsonClause, Po as describeOutcome, Oo as destructiveScope, Qn as detectReactiveTriggerDrift, va as emitAddIndexMysql, la as emitCreateTableMssql, Xi as emitCreateTableMysql, Gi as emitCreateTablePg, na as emitCreateTableSqlite, ki as emitDropColumnDdl, Ai as emitDropColumnDdlMysql, an as emitFrameworkBootstrapSql, nn as emitNamespaceProvisionDdl, rn as emitNamespacedSchemaSql, tn as emitSchemaSql, ii as engineFromVersion, to as ensureDeployLedgerTable, eo as ensureLedgerTable, $t as enumRenameBlocks, Qt as enumTypeBlocks, Kt as extensionBlocks, di as failDeploy, Jo as failedExpectations, us as fileMigrationStatus, R as fingerprintSchema, ze as fnv1a64, Ts as formatBranchRehearsal, $n as formatReactiveTriggerDrift, Do as ignoreTablesFromEnv, ri as introspectSchema, x as irreversible, h as irreversibleReason, hi as isAlreadySatisfied, se as isFileMigration, Ds as isRawSqlFragment, cn as isReRunSafeDdl, qo as makeFileMigrationContext, Pr as mapPgType, Io as materialiseSnapshot, le as migration, it as migrationAtomicityFor, Xo as migrationBodyHash, Be as migrationLockKeyForSchema, Ve as migrationLockNameForSchema, pa as mysqlIndexPrefixFor, Et as notifyFunctionName, F as numericIdSql, li as openDeploy, Nr as parseEnumCheck, cs as pendingFileMigrationIds, ls as pendingFileMigrationSummary, jr as planMigrations, _n as provisionTenantNamespace, St as reactiveTriggerName, Gt as reactiveTriggerRepairSql, So as recordUpToDate, Ss as rehearseMigrationOnBranch, bs as rehearsedOperation, Ji as renderColumnMysql, Hi as renderColumnPg, Fe as resolveMigrationLockSchema, oi as resolveMysqlEngine, ps as rollbackFileBasedMigration, _s as rollingDeployUnsafeOps, ds as runFileBasedMigrations, vn as runFrameworkBootstrap, hn as runMigrate, yo as runMigrationOp, No as runPlannedMigrations, Q as runSchemaOp, Kn as shortFingerprint, qn as snapshotColumn, Es as sql, N as sqlType, ms as squashMigrationPlans, Ao as unblockLossy, fi as unfinishedDeploys, nt as withMigrationLock };
|