@voltro/database 0.79.0 → 0.80.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 +134 -0
- package/dist/index.d.ts +6 -4
- package/dist/sql.d.ts +29 -3
- package/dist/sql.js +1047 -1022
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as e, B as t, Bn as n, C as r, Cn as i, Cr as a, D as o, Dn as s, E as c, En as l, Er as u, F as d, Fr as f, Ft as p, Gn as m, H as h, I as g, It as _, J as v, Kn as y, L as b, M as x, N as S, Nt as C,
|
|
2
|
-
import { Cause as
|
|
3
|
-
import { createHash as
|
|
4
|
-
import { createLogger as
|
|
1
|
+
import { A as e, B as t, Bn as n, C as r, Cn as i, Cr as a, D as o, Dn as s, E as c, En as l, Er as u, F as d, Fr as f, Ft as p, Gn as m, H as h, I as g, It as _, J as v, Kn as y, L as b, M as x, N as S, Nt as C, O as w, P as T, Pr as E, R as D, Rt as ee, S as te, Sn as O, Sr as ne, T as k, U as re, Vt as ie, Xn as ae, ct as oe, et as se, hn as ce, j as le, k as ue, p as de, r as fe, rr as pe, rt as me, t as he, w as ge, wt as _e, xn as ve, z as ye } from "./replaceInProgress-BmSjNTp0.js";
|
|
2
|
+
import { Cause as be, Effect as A, Equal as xe, Exit as Se, Schedule as Ce, Scope as we } from "effect";
|
|
3
|
+
import { createHash as Te } from "node:crypto";
|
|
4
|
+
import { createLogger as Ee } from "@voltro/logger";
|
|
5
5
|
import { SqlClient as j } from "@effect/sql";
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
6
|
+
import { promises as De } from "node:fs";
|
|
7
|
+
import { join as Oe } from "node:path";
|
|
8
|
+
import { pathToFileURL as ke } from "node:url";
|
|
9
9
|
//#region src/indexStorage.ts
|
|
10
|
-
var
|
|
10
|
+
var Ae = (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,
|
|
@@ -20,10 +20,10 @@ var ke = (e, t = "float32") => {
|
|
|
20
20
|
efConstruction: i,
|
|
21
21
|
opclass: a.toLowerCase().replace(/^public\./, "")
|
|
22
22
|
};
|
|
23
|
-
},
|
|
23
|
+
}, je = (e, t) => t === void 0 || t === "postgres" ? e ?? "btree" : e === "hnsw" || e === "gin" && (t === "mysql" || t === "mariadb") ? null : "btree", Me = (e, t) => ({
|
|
24
24
|
...e !== void 0 && e !== "btree" ? { kind: e } : {},
|
|
25
|
-
...e === "hnsw" ? { kindOptions: { hnsw:
|
|
26
|
-
}),
|
|
25
|
+
...e === "hnsw" ? { kindOptions: { hnsw: Ae(t) } } : {}
|
|
26
|
+
}), Ne = (e, t, n = "float32") => {
|
|
27
27
|
if (e === void 0 || e === "btree") return {
|
|
28
28
|
using: "",
|
|
29
29
|
withSuffix: "",
|
|
@@ -35,14 +35,14 @@ var ke = (e, t = "float32") => {
|
|
|
35
35
|
withSuffix: "",
|
|
36
36
|
skip: !1
|
|
37
37
|
};
|
|
38
|
-
let r =
|
|
38
|
+
let r = Ae(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
|
+
}, Pe = (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 ke = (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 = Fe(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
|
+
}, Fe = (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, Ie = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, Le = (e) => e.replace(/"/g, "`"), Re = (e) => typeof e == "string" ? e : e.name ?? String(e), ze = (e, t) => `_ua_${t}_${e}`.slice(0, 64), Be = (e, t) => {
|
|
79
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(Ie)) return e;
|
|
80
80
|
let n = { ...e.fields }, r = [], i = [];
|
|
81
81
|
for (let t of e.appliedIndexes) {
|
|
82
|
-
if (!
|
|
82
|
+
if (!Ie(t)) {
|
|
83
83
|
r.push(t);
|
|
84
84
|
continue;
|
|
85
85
|
}
|
|
86
|
-
let a =
|
|
86
|
+
let a = Le(t.where), o = [];
|
|
87
87
|
for (let r of t.fields) {
|
|
88
|
-
let i =
|
|
88
|
+
let i = Re(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 = ze(t.name, i);
|
|
91
91
|
o.push(s), n[s] = {
|
|
92
92
|
type: "text",
|
|
93
93
|
nullable: !0,
|
|
@@ -110,7 +110,7 @@ var ke = (e, t = "float32") => {
|
|
|
110
110
|
appliedIndexes: r,
|
|
111
111
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
112
112
|
};
|
|
113
|
-
}, M = (e, t) => `${e}::${t}`,
|
|
113
|
+
}, M = (e, t) => `${e}::${t}`, Ve = (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,96 +119,96 @@ var ke = (e, t = "float32") => {
|
|
|
119
119
|
};
|
|
120
120
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
121
121
|
return i;
|
|
122
|
-
},
|
|
123
|
-
t !== void 0 && Number.isInteger(t) && t > 0 &&
|
|
124
|
-
},
|
|
125
|
-
let t =
|
|
122
|
+
}, He = /* @__PURE__ */ new WeakMap(), Ue = (e, t) => {
|
|
123
|
+
t !== void 0 && Number.isInteger(t) && t > 0 && He.set(e, t);
|
|
124
|
+
}, We = (e) => {
|
|
125
|
+
let t = He.get(e);
|
|
126
126
|
if (t !== void 0) return t;
|
|
127
127
|
if (!("config" in e) || typeof e.config != "object" || e.config === null || !("maxConnections" in e.config)) return;
|
|
128
128
|
let n = e.config.maxConnections;
|
|
129
129
|
return typeof n == "number" && Number.isInteger(n) && n > 0 ? n : void 0;
|
|
130
|
-
},
|
|
130
|
+
}, Ge = (e, t) => e.executeUnprepared(t, [], void 0), Ke = 6322741009312437n, qe = (e) => {
|
|
131
131
|
let t = e?.trim();
|
|
132
132
|
return t === void 0 || t === "" || t === "public" ? void 0 : t;
|
|
133
|
-
},
|
|
134
|
-
let t =
|
|
135
|
-
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t *
|
|
133
|
+
}, Je = (e) => e?.schema === void 0 ? qe(process.env.DB_SCHEMA) : qe(e.schema), Ye = 14695981039346656037n, Xe = 1099511628211n, Ze = 18446744073709551615n, Qe = (e) => {
|
|
134
|
+
let t = Ye;
|
|
135
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * Xe & Ze;
|
|
136
136
|
return t;
|
|
137
|
-
}, Qe = (e) => {
|
|
138
|
-
let t = Ke(e);
|
|
139
|
-
return t === void 0 ? Ge : Ze(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
140
137
|
}, $e = (e) => {
|
|
141
|
-
let t =
|
|
138
|
+
let t = qe(e);
|
|
139
|
+
return t === void 0 ? Ke : Qe(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
140
|
+
}, et = (e) => {
|
|
141
|
+
let t = `voltro_migration_${Ke.toString(36)}`, n = qe(e);
|
|
142
142
|
if (n === void 0) return t;
|
|
143
143
|
let r = `${t}_${n}`;
|
|
144
|
-
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(
|
|
145
|
-
},
|
|
144
|
+
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(Qe(`voltro_migration_lock:${n}`) & Ze).toString(16)}`;
|
|
145
|
+
}, tt = 250, nt = () => {
|
|
146
146
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
147
147
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
148
|
-
},
|
|
149
|
-
let n =
|
|
148
|
+
}, rt = (e, t) => A.gen(function* () {
|
|
149
|
+
let n = nt(), r = Date.now();
|
|
150
150
|
for (;;) {
|
|
151
|
-
if ((yield*
|
|
152
|
-
Date.now() - r >= n && (yield* A.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* A.sleep(`${
|
|
151
|
+
if ((yield* Ge(e, `SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`))[0]?.got) return;
|
|
152
|
+
Date.now() - r >= n && (yield* A.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* A.sleep(`${tt} millis`);
|
|
153
153
|
}
|
|
154
|
-
}),
|
|
155
|
-
(yield*
|
|
156
|
-
}),
|
|
157
|
-
let n = yield*
|
|
154
|
+
}), it = (e, t) => A.asVoid(Ge(e, `SELECT pg_advisory_unlock(${t.toString()}::bigint)`)), at = 30, ot = (e, t) => A.gen(function* () {
|
|
155
|
+
(yield* Ge(e, `SELECT GET_LOCK('${t}', ${String(at)}) AS got`))[0]?.got !== 1 && (yield* A.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${at}s (another migration is in progress, or a prior one left it held).`)));
|
|
156
|
+
}), st = (e, t) => A.asVoid(Ge(e, `SELECT RELEASE_LOCK('${t}')`)), ct = 3e4, lt = (e, t) => A.gen(function* () {
|
|
157
|
+
let n = yield* Ge(e, `
|
|
158
158
|
DECLARE @res int;
|
|
159
159
|
EXEC @res = sp_getapplock @Resource = '${t}', @LockMode = 'Exclusive',
|
|
160
|
-
@LockOwner = 'Session', @LockTimeout = ${String(
|
|
160
|
+
@LockOwner = 'Session', @LockTimeout = ${String(ct)};
|
|
161
161
|
SELECT @res AS res`);
|
|
162
162
|
(n[0]?.res ?? -999) < 0 && (yield* A.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
163
|
-
}),
|
|
164
|
-
let n =
|
|
163
|
+
}), ut = (e, t) => A.asVoid(Ge(e, `EXEC sp_releaseapplock @Resource = '${t}', @LockOwner = 'Session'`)), dt = A.void, ft = (e, t) => A.gen(function* () {
|
|
164
|
+
let n = Je(t), r = et(n), i = $e(n);
|
|
165
165
|
if (!e.onDialectOrElse({
|
|
166
166
|
mysql: () => !0,
|
|
167
167
|
mssql: () => !0,
|
|
168
168
|
sqlite: () => !1,
|
|
169
169
|
orElse: () => !0
|
|
170
|
-
})) return { release:
|
|
171
|
-
let a =
|
|
170
|
+
})) return { release: dt };
|
|
171
|
+
let a = We(e);
|
|
172
172
|
if (a !== void 0 && a < 2) return yield* A.dieMessage(`migrate needs at least 2 connections, pool has ${a}: one holds the migration lock and another runs the statements. Configure maxConnections >= 2 for the migrating process.`);
|
|
173
|
-
let o = yield*
|
|
173
|
+
let o = yield* we.make(), s = yield* A.provideService(e.reserve, we.Scope, o), c = we.close(o, Se.void);
|
|
174
174
|
return yield* e.onDialectOrElse({
|
|
175
|
-
mysql: () => at(s, r),
|
|
176
|
-
mssql: () => ct(s, r),
|
|
177
|
-
sqlite: () => ut,
|
|
178
|
-
orElse: () => nt(s, i)
|
|
179
|
-
}).pipe(A.onExit((e) => xe.isSuccess(e) ? A.void : c)), { release: e.onDialectOrElse({
|
|
180
175
|
mysql: () => ot(s, r),
|
|
181
176
|
mssql: () => lt(s, r),
|
|
182
|
-
sqlite: () =>
|
|
177
|
+
sqlite: () => dt,
|
|
183
178
|
orElse: () => rt(s, i)
|
|
179
|
+
}).pipe(A.onExit((e) => Se.isSuccess(e) ? A.void : c)), { release: e.onDialectOrElse({
|
|
180
|
+
mysql: () => st(s, r),
|
|
181
|
+
mssql: () => ut(s, r),
|
|
182
|
+
sqlite: () => dt,
|
|
183
|
+
orElse: () => it(s, i)
|
|
184
184
|
}).pipe(A.ensuring(c)) };
|
|
185
|
-
}),
|
|
185
|
+
}), pt = "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_MAX_CONNECTIONS / PG_MAX_CONNECTIONS, or the driver's own `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).", mt = (e) => /acquire connection/i.test(String(e?.message ?? e)), ht = (e, t, n) => A.acquireUseRelease(ft(e, n), () => t.pipe(A.tapError((e) => mt(e) ? A.logError(`migrate: ${pt}`).pipe(A.annotateLogs({ scope: "voltro:migrate" })) : A.void)), (e) => e.release.pipe(A.orDie)), N = (e) => e.onDialectOrElse({
|
|
186
186
|
pg: () => "postgres",
|
|
187
187
|
mysql: () => "mysql",
|
|
188
188
|
mssql: () => "mssql",
|
|
189
189
|
sqlite: () => "sqlite",
|
|
190
190
|
orElse: () => "sqlite"
|
|
191
|
-
}),
|
|
191
|
+
}), gt = {
|
|
192
192
|
postgres: "plan-transactional",
|
|
193
193
|
mssql: "plan-transactional",
|
|
194
194
|
mysql: "per-operation",
|
|
195
195
|
mariadb: "per-operation",
|
|
196
196
|
sqlite: "per-operation",
|
|
197
197
|
turso: "per-operation"
|
|
198
|
-
},
|
|
199
|
-
id:
|
|
200
|
-
runId:
|
|
201
|
-
planFingerprint:
|
|
198
|
+
}, _t = (e) => gt[e], P = "_voltro_migration_ops", vt = l(P, {
|
|
199
|
+
id: ne({ prefix: "mop" }),
|
|
200
|
+
runId: E(),
|
|
201
|
+
planFingerprint: E(),
|
|
202
202
|
opIndex: a(),
|
|
203
|
-
opKind:
|
|
204
|
-
opTarget:
|
|
205
|
-
status:
|
|
206
|
-
payload:
|
|
203
|
+
opKind: E(),
|
|
204
|
+
opTarget: E(),
|
|
205
|
+
status: E(),
|
|
206
|
+
payload: E(),
|
|
207
207
|
startedAt: f().nullable(),
|
|
208
208
|
appliedAt: f().nullable(),
|
|
209
209
|
durationMs: a().nullable(),
|
|
210
210
|
createdAt: f().default("now")
|
|
211
|
-
}),
|
|
211
|
+
}), yt = (e) => {
|
|
212
212
|
switch (e.kind) {
|
|
213
213
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
214
214
|
`table:${e.table}`,
|
|
@@ -242,11 +242,11 @@ var ke = (e, t = "float32") => {
|
|
|
242
242
|
...e.foreignKeys.map((e) => `column:${e.table}.${e.column}`)
|
|
243
243
|
]);
|
|
244
244
|
}
|
|
245
|
-
},
|
|
246
|
-
let n =
|
|
247
|
-
for (let t of
|
|
245
|
+
}, bt = (e) => [...yt(e)].join(" "), xt = (e, t) => {
|
|
246
|
+
let n = yt(t);
|
|
247
|
+
for (let t of yt(e)) if (n.has(t)) return !0;
|
|
248
248
|
return !1;
|
|
249
|
-
},
|
|
249
|
+
}, St = (e, t) => e.operations.some((e) => xt(e.op, t)), Ct = "__voltro_rebuild", wt = "__shadow", Tt = "__old", Et = /* @__PURE__ */ new Set([
|
|
250
250
|
"add-unique",
|
|
251
251
|
"drop-unique",
|
|
252
252
|
"add-unique-composite",
|
|
@@ -258,14 +258,14 @@ var ke = (e, t = "float32") => {
|
|
|
258
258
|
"alter-column-nullability",
|
|
259
259
|
"alter-column-type",
|
|
260
260
|
"alter-column-default"
|
|
261
|
-
]),
|
|
261
|
+
]), Dt = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Ot = (e, t, n) => {
|
|
262
262
|
let r = n === "sqlite" || n === "turso";
|
|
263
|
-
return e.kind === "alter-column-type" && t === "online-required" || r &&
|
|
263
|
+
return e.kind === "alter-column-type" && t === "online-required" || r && Et.has(e.kind) ? "artefact-repair" : Dt.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
264
264
|
};
|
|
265
|
-
Object.keys(
|
|
265
|
+
Object.keys(gt);
|
|
266
266
|
//#endregion
|
|
267
267
|
//#region src/mssqlJsonValueCheck.ts
|
|
268
|
-
var
|
|
268
|
+
var kt = (e) => {
|
|
269
269
|
let t = `(N'{"v":' + ${e} + N'}')`, n = `ISJSON(${t}) = 1`, r = `JSON_MODIFY(CASE WHEN ${n} THEN ${t} ELSE N'{}' END, '$.v', NULL)`;
|
|
270
270
|
return `(${e} IS NULL OR (${n} AND ${[
|
|
271
271
|
32,
|
|
@@ -273,7 +273,7 @@ var Ot = (e) => {
|
|
|
273
273
|
10,
|
|
274
274
|
13
|
|
275
275
|
].reduce((e, t) => `REPLACE(${e}, NCHAR(${t}), N'')`, r)} = N'{}'))`;
|
|
276
|
-
},
|
|
276
|
+
}, At = (e) => {
|
|
277
277
|
let t = [], n = /\s+|N?'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|[A-Za-z_][A-Za-z_0-9]*|[0-9]+|[()+,=]/giy, r = 0;
|
|
278
278
|
for (; r < e.length;) {
|
|
279
279
|
n.lastIndex = r;
|
|
@@ -283,36 +283,36 @@ var Ot = (e) => {
|
|
|
283
283
|
/^\s+$/.test(a) || t.push(/^(?:N?')|^\[/i.test(a) ? a.replace(/^n'/, "N'") : a.toLowerCase()), r = n.lastIndex;
|
|
284
284
|
}
|
|
285
285
|
return t;
|
|
286
|
-
},
|
|
286
|
+
}, jt = (e, t) => {
|
|
287
287
|
let n = `[${e.replaceAll("]", "]]")}]`, r = `(N'{"v":'+${n})+N'}'`, i = `isjson(${r})=(1)`, a = `json_modify(case when ${i} then ${r} else N'{}' end,'$.v',NULL)`, o = [
|
|
288
288
|
32,
|
|
289
289
|
9,
|
|
290
290
|
10,
|
|
291
291
|
13
|
|
292
292
|
].reduce((e, t) => `replace(${e},nchar((${t})),N'')`, a), s = [
|
|
293
|
-
["value",
|
|
293
|
+
["value", kt(n)],
|
|
294
294
|
["value", `(${n} IS NULL OR ${i} AND ${o}=N'{}')`],
|
|
295
295
|
["container", `(${n} IS NULL OR ISJSON(${n}) = 1)`],
|
|
296
296
|
["container", `(${n} IS NULL OR isjson(${n})=(1))`]
|
|
297
|
-
], c =
|
|
297
|
+
], c = At(t);
|
|
298
298
|
if (c) return s.find(([, e]) => {
|
|
299
|
-
let t =
|
|
299
|
+
let t = At(e);
|
|
300
300
|
return t?.length === c.length && t.every((e, t) => e === c[t]);
|
|
301
301
|
})?.[0];
|
|
302
|
-
},
|
|
302
|
+
}, Mt = (e) => {
|
|
303
303
|
if (e.length === 0) return;
|
|
304
304
|
let t = e.filter((e) => e.enabled);
|
|
305
305
|
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";
|
|
306
|
-
},
|
|
306
|
+
}, Nt = "framework_changes", Pt = "framework_changes_", Ft = (e, t) => t === "framework_changes" ? `${Pt}${e}` : `${Pt}${t}_${e}`, It = (e, t) => Rt(Ft(e, t).replace(/[A-Z]/g, (e) => e.toLowerCase())), Lt = 63, Rt = (e) => {
|
|
307
307
|
let t = new TextEncoder().encode(e);
|
|
308
|
-
return t.length <=
|
|
309
|
-
},
|
|
308
|
+
return t.length <= Lt ? e : new TextDecoder().decode(t.subarray(0, Lt)).replace(/�+$/u, "");
|
|
309
|
+
}, zt = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, Bt = "voltro:notify:v2", Vt = (e, t) => {
|
|
310
310
|
if (e.type === "text" && e.generatedAs === void 0) {
|
|
311
311
|
if (e.maxLength !== void 0) return e.maxLength;
|
|
312
312
|
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
313
313
|
}
|
|
314
|
-
},
|
|
315
|
-
|
|
314
|
+
}, Ht = Ee({ scope: "voltro:migrate" }), F = (e) => {
|
|
315
|
+
Ht.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
316
316
|
}, I = (e, t) => {
|
|
317
317
|
let n = e.type;
|
|
318
318
|
if (e.spatial) {
|
|
@@ -395,7 +395,7 @@ var Ot = (e) => {
|
|
|
395
395
|
if (t === "mssql") switch (n) {
|
|
396
396
|
case "id": return "NVARCHAR(64)";
|
|
397
397
|
case "text": {
|
|
398
|
-
let t =
|
|
398
|
+
let t = Vt(e, !1);
|
|
399
399
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
400
400
|
}
|
|
401
401
|
case "integer": return "INT";
|
|
@@ -427,22 +427,22 @@ var Ot = (e) => {
|
|
|
427
427
|
case "array": return "TEXT[]";
|
|
428
428
|
case "interval": return "INTERVAL";
|
|
429
429
|
}
|
|
430
|
-
},
|
|
430
|
+
}, Ut = (e, t) => {
|
|
431
431
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
432
432
|
let n = e.defaultValue;
|
|
433
|
-
return n === "now" ? O(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) ?
|
|
434
|
-
},
|
|
435
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
433
|
+
return n === "now" ? O(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) ? Wt(n, e, t) : typeof n == "object" && n ? Gt(n, t) : null;
|
|
434
|
+
}, Wt = (e, t, n) => {
|
|
435
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return Gt(e, n);
|
|
436
436
|
let r = I({
|
|
437
437
|
...t,
|
|
438
438
|
type: t.arrayElement,
|
|
439
439
|
arrayElement: void 0
|
|
440
440
|
}, n);
|
|
441
441
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
442
|
-
},
|
|
442
|
+
}, Gt = (e, t) => {
|
|
443
443
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
444
444
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
445
|
-
},
|
|
445
|
+
}, Kt = (e, t) => {
|
|
446
446
|
switch (t) {
|
|
447
447
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
448
448
|
case "mysql":
|
|
@@ -451,7 +451,7 @@ var Ot = (e) => {
|
|
|
451
451
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
452
452
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
453
453
|
}
|
|
454
|
-
},
|
|
454
|
+
}, qt = (e, t) => {
|
|
455
455
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
456
456
|
switch (e) {
|
|
457
457
|
case "cascade": return "CASCADE";
|
|
@@ -459,18 +459,18 @@ var Ot = (e) => {
|
|
|
459
459
|
case "setNull": return "SET NULL";
|
|
460
460
|
case "noAction": return "NO ACTION";
|
|
461
461
|
}
|
|
462
|
-
},
|
|
462
|
+
}, Jt = (e, t, n) => n === null ? i(e, t) : `${i(n, t)}.${i(e, t)}`, Yt = 191, Xt = (e, t) => {
|
|
463
463
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
464
464
|
let n = I(e, t).toUpperCase();
|
|
465
465
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
466
|
-
},
|
|
466
|
+
}, Zt = (e, t, n) => {
|
|
467
467
|
let r = i(e, n);
|
|
468
468
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
469
469
|
let a = t[e];
|
|
470
470
|
if (!a) return r;
|
|
471
471
|
let o = I(a, n).toUpperCase();
|
|
472
|
-
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${r}(${
|
|
473
|
-
},
|
|
472
|
+
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${r}(${Yt})` : r;
|
|
473
|
+
}, Qt = (e, t) => {
|
|
474
474
|
if (!e.generatedAs) return null;
|
|
475
475
|
let { expr: n, stored: r } = e.generatedAs;
|
|
476
476
|
if (t === "postgres") return r || F("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
@@ -478,23 +478,23 @@ var Ot = (e) => {
|
|
|
478
478
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
479
479
|
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.");
|
|
480
480
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
481
|
-
},
|
|
482
|
-
if (t.type === "id" && t.idScheme?.kind === "numeric") return
|
|
483
|
-
let s = n === "mssql" ?
|
|
481
|
+
}, $t = (e, t, n, r, a = !1, o = !1) => {
|
|
482
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return Kt(e, n);
|
|
483
|
+
let s = n === "mssql" ? Vt(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? I(t, n) : `NVARCHAR(${s})`, l = [i(e, n), c];
|
|
484
484
|
t.type === "id" && !o && l.push("PRIMARY KEY");
|
|
485
|
-
let u =
|
|
485
|
+
let u = Qt(t, n);
|
|
486
486
|
if (u) l.push(u);
|
|
487
487
|
else {
|
|
488
|
-
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !
|
|
489
|
-
let e =
|
|
488
|
+
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !Xt(t, n) && l.push("UNIQUE");
|
|
489
|
+
let e = Ut(t, n);
|
|
490
490
|
e && l.push(e);
|
|
491
491
|
}
|
|
492
|
-
if (t.type === "reference" && t.references && !a && !
|
|
492
|
+
if (t.type === "reference" && t.references && !a && !ve(n)) {
|
|
493
493
|
let e = t.references();
|
|
494
494
|
l.push(`REFERENCES ${i(e.tableName, n)} (${i(t.referenceColumn ?? "id", n)})`);
|
|
495
|
-
let r =
|
|
495
|
+
let r = qt(t.onDelete ?? "restrict", n);
|
|
496
496
|
l.push(`ON DELETE ${r}`);
|
|
497
|
-
let a =
|
|
497
|
+
let a = qt(t.refOnUpdate ?? "noAction", n);
|
|
498
498
|
a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
|
|
499
499
|
}
|
|
500
500
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
@@ -508,34 +508,34 @@ var Ot = (e) => {
|
|
|
508
508
|
}
|
|
509
509
|
if (t.type === "json" || t.type === "array") {
|
|
510
510
|
let r = i(e, n);
|
|
511
|
-
O(n) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : n === "mssql" && l.push(t.type === "json" ? `CHECK ${
|
|
511
|
+
O(n) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : n === "mssql" && l.push(t.type === "json" ? `CHECK ${kt(r)}` : `CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
|
|
512
512
|
}
|
|
513
513
|
return l.join(" ");
|
|
514
|
-
},
|
|
514
|
+
}, en = (e, t) => {
|
|
515
515
|
if (t.charset !== void 0) {
|
|
516
|
-
if (!
|
|
516
|
+
if (!ve(e)) throw Error(`store charset '${t.charset}' is declared for a ${e} store — a character set is a MySQL / MariaDB setting. Remove \`charset\` from \`store\` in app.config.ts, or declare \`store: { dialect: 'mysql' | 'mariadb', charset }\`.`);
|
|
517
517
|
return t.charset;
|
|
518
518
|
}
|
|
519
|
-
},
|
|
519
|
+
}, tn = (e, t, n = null, r, a) => {
|
|
520
520
|
let o = /* @__PURE__ */ new Set();
|
|
521
521
|
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
522
522
|
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
523
523
|
for (let [t, n] of Object.entries(e.fields)) n.unique && o.add(t);
|
|
524
524
|
let s = e.appliedPrimaryKey ?? [];
|
|
525
525
|
for (let e of s) o.add(e);
|
|
526
|
-
let c = s.length > 0, l = Object.entries(e.fields).map(([e, n]) => ` ${
|
|
527
|
-
let r = n.fields.map((n) =>
|
|
526
|
+
let c = s.length > 0, l = Object.entries(e.fields).map(([e, n]) => ` ${$t(e, n, t, o, r?.has(e) ?? !1, c)}`).join(",\n"), u = (e.appliedUniques ?? []).map((n) => {
|
|
527
|
+
let r = n.fields.map((n) => Zt(n, e.fields, t)).join(", ");
|
|
528
528
|
return ` CONSTRAINT ${i(n.name, t)} UNIQUE (${r})`;
|
|
529
|
-
}), d = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${i(e.name, t)} CHECK (${e.expr})`), f = c ? [` PRIMARY KEY (${s.map((n) =>
|
|
529
|
+
}), d = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${i(e.name, t)} CHECK (${e.expr})`), f = c ? [` PRIMARY KEY (${s.map((n) => Zt(n, e.fields, t)).join(", ")})`] : [], p = ve(t) ? Object.entries(e.fields).flatMap(([a, o]) => {
|
|
530
530
|
if (o.type !== "reference" || !o.references || (r?.has(a) ?? !1)) return [];
|
|
531
|
-
let s = o.references(), c =
|
|
532
|
-
return [` CONSTRAINT ${i(`${e.tableName}_${a}_fkey`, t)} FOREIGN KEY (${i(a, t)}) REFERENCES ${
|
|
531
|
+
let s = o.references(), c = qt(o.onDelete ?? "restrict", t), l = qt(o.refOnUpdate ?? "noAction", t);
|
|
532
|
+
return [` CONSTRAINT ${i(`${e.tableName}_${a}_fkey`, t)} FOREIGN KEY (${i(a, t)}) REFERENCES ${Jt(s.tableName, t, n)} (${i(o.referenceColumn ?? "id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
533
533
|
}) : [], m = [
|
|
534
534
|
...f,
|
|
535
535
|
...u,
|
|
536
536
|
...d,
|
|
537
537
|
...p
|
|
538
|
-
], h = m.length > 0 ? `${l},\n${m.join(",\n")}` : l, g =
|
|
538
|
+
], h = m.length > 0 ? `${l},\n${m.join(",\n")}` : l, g = Jt(e.tableName, t, n);
|
|
539
539
|
if (t === "mssql") {
|
|
540
540
|
let t = n === null ? e.tableName : `${n}.${e.tableName}`, r = `CREATE TABLE ${g} (\n${h}\n)`;
|
|
541
541
|
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${r.replace(/'/g, "''")}');`;
|
|
@@ -543,14 +543,14 @@ var Ot = (e) => {
|
|
|
543
543
|
return [
|
|
544
544
|
`CREATE TABLE IF NOT EXISTS ${g} (`,
|
|
545
545
|
h,
|
|
546
|
-
`)${a !== void 0 &&
|
|
546
|
+
`)${a !== void 0 && ve(t) ? ` DEFAULT CHARACTER SET ${a}` : ""};`
|
|
547
547
|
].join("\n");
|
|
548
|
-
},
|
|
548
|
+
}, nn = (e, t, n) => {
|
|
549
549
|
let r = `${e}_${t.name}_fts`, a = (e) => i(e, n), o = t.columns.map(a).join(", "), s = t.columns.map((e) => `new.${a(e)}`).join(", "), c = [];
|
|
550
550
|
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${a(r)} USING fts5(${o}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_ai`)} AFTER INSERT ON ${a(e)} BEGIN\n INSERT INTO ${a(r)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_ad`)} AFTER DELETE ON ${a(e)} BEGIN\n DELETE FROM ${a(r)} WHERE row_id = old.${a("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${r}_au`)} AFTER UPDATE ON ${a(e)} BEGIN\n DELETE FROM ${a(r)} WHERE row_id = old.${a("id")};\n INSERT INTO ${a(r)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c;
|
|
551
|
-
},
|
|
551
|
+
}, rn = (e, t, n = null) => {
|
|
552
552
|
let r = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, n, r, i, a) => {
|
|
553
|
-
if (t === "postgres") return
|
|
553
|
+
if (t === "postgres") return Ne(r, i, a);
|
|
554
554
|
let o = {
|
|
555
555
|
using: "",
|
|
556
556
|
withSuffix: "",
|
|
@@ -567,7 +567,7 @@ var Ot = (e) => {
|
|
|
567
567
|
}) : o;
|
|
568
568
|
}, c = (n, r) => {
|
|
569
569
|
let i = n.map((n) => {
|
|
570
|
-
if (typeof n == "string") return
|
|
570
|
+
if (typeof n == "string") return Zt(n, e.fields, t);
|
|
571
571
|
if ("jsonPath" in n) {
|
|
572
572
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
573
573
|
return `(${C(e, r, t, { numeric: i })})`;
|
|
@@ -578,11 +578,11 @@ var Ot = (e) => {
|
|
|
578
578
|
}, l = (r, a, o, l, u, d = "", f = !1) => {
|
|
579
579
|
let p = o[0], m = typeof p == "string" ? e.fields[p]?.vectorPrecision : void 0, h = s(r, a, l, u, m);
|
|
580
580
|
if (h.skip) return "";
|
|
581
|
-
let g = c(o, h.opclass), _ = `${h.withSuffix}${d}`, v =
|
|
581
|
+
let g = c(o, h.opclass), _ = `${h.withSuffix}${d}`, v = Jt(a, t, n), y = f ? "UNIQUE " : "";
|
|
582
582
|
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${r}') CREATE ${y}INDEX ${i(r, t)} ON ${v}${h.using} (${g})${_};` : t === "mysql" ? `CREATE ${y}INDEX ${i(r, t)} ON ${v}${h.using} (${g})${_};` : `CREATE ${y}INDEX IF NOT EXISTS ${i(r, t)} ON ${v}${h.using} (${g})${_};`;
|
|
583
583
|
};
|
|
584
584
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
585
|
-
if (!i.unique || i.type === "id" || !
|
|
585
|
+
if (!i.unique || i.type === "id" || !Xt(i, t)) continue;
|
|
586
586
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
587
587
|
a && r.push(a);
|
|
588
588
|
}
|
|
@@ -596,7 +596,7 @@ var Ot = (e) => {
|
|
|
596
596
|
let a = n.columns.map((e) => i(e, t)).join(", ");
|
|
597
597
|
r.push(`CREATE FULLTEXT INDEX ${i(n.name, t)} ON ${i(e.tableName, t)} (${a});`);
|
|
598
598
|
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${n.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
|
|
599
|
-
else t === "sqlite" ? r.push(...
|
|
599
|
+
else t === "sqlite" ? r.push(...nn(e.tableName, n, t)) : F(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
600
600
|
for (let n of e.appliedIndexes) {
|
|
601
601
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
602
602
|
F(`[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(...).`);
|
|
@@ -614,17 +614,17 @@ var Ot = (e) => {
|
|
|
614
614
|
r.push(l(i, e.tableName, [t])), a.add(o([t]));
|
|
615
615
|
}
|
|
616
616
|
return r.join("\n");
|
|
617
|
-
},
|
|
617
|
+
}, an = (e, t, n = Nt) => {
|
|
618
618
|
if (t !== "postgres") return [];
|
|
619
619
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
620
|
-
return r.length === 0 ? [] : [
|
|
621
|
-
},
|
|
622
|
-
CREATE OR REPLACE FUNCTION ${
|
|
620
|
+
return r.length === 0 ? [] : [on(n), ...r.map((e) => cn(e, n))];
|
|
621
|
+
}, on = (e) => `
|
|
622
|
+
CREATE OR REPLACE FUNCTION ${zt(e)}() RETURNS trigger AS $$
|
|
623
623
|
DECLARE
|
|
624
624
|
payload TEXT;
|
|
625
625
|
pk JSONB;
|
|
626
626
|
BEGIN
|
|
627
|
-
-- ${
|
|
627
|
+
-- ${Bt}
|
|
628
628
|
payload := json_build_object(
|
|
629
629
|
'table', TG_TABLE_NAME,
|
|
630
630
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -678,26 +678,26 @@ BEGIN
|
|
|
678
678
|
RETURN COALESCE(NEW, OLD);
|
|
679
679
|
END;
|
|
680
680
|
$$ LANGUAGE plpgsql;
|
|
681
|
-
`.trim(),
|
|
682
|
-
let n =
|
|
681
|
+
`.trim(), sn = (e, t) => {
|
|
682
|
+
let n = Ft(e.tableName, t);
|
|
683
683
|
return [
|
|
684
684
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
685
685
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
686
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
686
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${zt(t)}()`
|
|
687
687
|
];
|
|
688
|
-
},
|
|
688
|
+
}, cn = (e, t) => sn(e, t).map((e) => `${e};`).join("\n"), ln = (e) => {
|
|
689
689
|
if (e.dialect !== "postgres") return [];
|
|
690
690
|
let t = e.channel ?? "framework_changes", n = new Map(e.tables.map((e) => [e.tableName, e])), r = [], i = e.missing.filter((e) => n.has(e));
|
|
691
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
692
|
-
for (let e of i) r.push(...
|
|
693
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
691
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(on(t));
|
|
692
|
+
for (let e of i) r.push(...sn(n.get(e), t));
|
|
693
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${Ft(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
694
694
|
return r;
|
|
695
|
-
},
|
|
695
|
+
}, un = (e, t) => {
|
|
696
696
|
if (t !== "postgres") return;
|
|
697
697
|
let n = [];
|
|
698
|
-
return
|
|
699
|
-
},
|
|
700
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
698
|
+
return dn(e) && n.push("CREATE EXTENSION IF NOT EXISTS vector;"), fn(e) && n.push("CREATE EXTENSION IF NOT EXISTS postgis;"), n.length === 0 ? void 0 : n.join("\n");
|
|
699
|
+
}, dn = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), fn = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), pn = (e) => {
|
|
700
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = Ve(e.map((e) => e.tableName), (e) => {
|
|
701
701
|
let n = t.get(e);
|
|
702
702
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
703
703
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -734,8 +734,8 @@ $$ LANGUAGE plpgsql;
|
|
|
734
734
|
sorted: o,
|
|
735
735
|
cyclic: r
|
|
736
736
|
};
|
|
737
|
-
},
|
|
738
|
-
let r = (e) => n ? `${i(n, t)}.${i(e, t)}` : i(e, t), a = `${e.table}_${e.column}_fkey`, o =
|
|
737
|
+
}, mn = (e, t, n = null) => {
|
|
738
|
+
let r = (e) => n ? `${i(n, t)}.${i(e, t)}` : i(e, t), a = `${e.table}_${e.column}_fkey`, o = qt(e.onDelete, t), s = qt(e.onUpdate, t), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (n) => `ADD CONSTRAINT ${i(a, t)} FOREIGN KEY ${n ? "IF NOT EXISTS " : ""}(${i(e.column, t)}) REFERENCES ${r(e.targetTable)} (${i(e.targetColumn, t)})${c}`;
|
|
739
739
|
switch (t) {
|
|
740
740
|
case "postgres": return [
|
|
741
741
|
"DO $$ BEGIN",
|
|
@@ -749,7 +749,7 @@ $$ LANGUAGE plpgsql;
|
|
|
749
749
|
case "mariadb": return `ALTER TABLE ${r(e.table)} ${l(!0)};`;
|
|
750
750
|
default: return `ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
751
751
|
}
|
|
752
|
-
},
|
|
752
|
+
}, hn = (e, t) => {
|
|
753
753
|
let n = /* @__PURE__ */ new Map();
|
|
754
754
|
if (O(t)) return n;
|
|
755
755
|
for (let t of e) {
|
|
@@ -757,7 +757,7 @@ $$ LANGUAGE plpgsql;
|
|
|
757
757
|
e.add(t.column), n.set(t.table, e);
|
|
758
758
|
}
|
|
759
759
|
return n;
|
|
760
|
-
},
|
|
760
|
+
}, gn = (e, t) => {
|
|
761
761
|
if (t !== "postgres") return "";
|
|
762
762
|
let n = /* @__PURE__ */ new Map();
|
|
763
763
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -773,12 +773,12 @@ $$ LANGUAGE plpgsql;
|
|
|
773
773
|
r.push(`DO $$ BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${e.replace(/'/g, "''")}') THEN\n CREATE TYPE "${e}" AS ENUM (${n});\n END IF;\nEND $$;`);
|
|
774
774
|
}
|
|
775
775
|
return r.join("\n\n");
|
|
776
|
-
},
|
|
776
|
+
}, _n = (e, t) => {
|
|
777
777
|
if (t !== "postgres") return "";
|
|
778
778
|
let n = /* @__PURE__ */ new Set();
|
|
779
779
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
|
|
780
780
|
let r = [];
|
|
781
|
-
for (let e of n) for (let { from: t, to: n } of
|
|
781
|
+
for (let e of n) for (let { from: t, to: n } of pe(e)) {
|
|
782
782
|
let i = e.replace(/'/g, "''"), a = t.replace(/'/g, "''"), o = n.replace(/'/g, "''");
|
|
783
783
|
r.push(`DO \$\$
|
|
784
784
|
DECLARE
|
|
@@ -787,30 +787,30 @@ BEGIN
|
|
|
787
787
|
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${i}';\n IF type_oid IS NOT NULL\n AND EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${a}')\n AND NOT EXISTS (SELECT 1 FROM pg_enum WHERE enumtypid = type_oid AND enumlabel = '${o}') THEN\n IF current_setting('server_version_num')::int >= 140000 THEN\n EXECUTE format('ALTER TYPE %I RENAME VALUE %L TO %L', '${i}', '${a}', '${o}');\n ELSE\n UPDATE pg_enum SET enumlabel = '${o}' WHERE enumtypid = type_oid AND enumlabel = '${a}';\n END IF;\n END IF;\nEND $$;`);
|
|
788
788
|
}
|
|
789
789
|
return r.join("\n\n");
|
|
790
|
-
},
|
|
790
|
+
}, vn = (e) => {
|
|
791
791
|
let t = [], n = [];
|
|
792
|
-
for (let r of e)
|
|
792
|
+
for (let r of e) ee(r) ? n.push(r) : t.push(r);
|
|
793
793
|
return {
|
|
794
794
|
tables: t,
|
|
795
795
|
views: n
|
|
796
796
|
};
|
|
797
|
-
},
|
|
798
|
-
let i =
|
|
797
|
+
}, yn = (e, t, n = Nt, r = {}) => {
|
|
798
|
+
let i = en(t, r), { tables: a, views: o } = vn(e), { sorted: s, cyclic: c } = pn(a.map((e) => Be(e, t))), l = hn(c, t), u = [], d = un(s, t);
|
|
799
799
|
d && u.push(d);
|
|
800
|
-
let f =
|
|
800
|
+
let f = _n(s, t);
|
|
801
801
|
f && u.push(f);
|
|
802
|
-
let p =
|
|
802
|
+
let p = gn(s, t);
|
|
803
803
|
p && u.push(p);
|
|
804
|
-
for (let e of s) u.push(
|
|
805
|
-
if (!O(t)) for (let e of c) u.push(
|
|
804
|
+
for (let e of s) u.push(tn(e, t, null, l.get(e.tableName), i));
|
|
805
|
+
if (!O(t)) for (let e of c) u.push(mn(e, t));
|
|
806
806
|
for (let e of s) {
|
|
807
|
-
let n =
|
|
807
|
+
let n = rn(e, t);
|
|
808
808
|
n && u.push(n);
|
|
809
809
|
}
|
|
810
|
-
u.push(...
|
|
811
|
-
for (let e of o) u.push(
|
|
810
|
+
u.push(...an(s, t, n));
|
|
811
|
+
for (let e of o) u.push(ie(e, t));
|
|
812
812
|
return u.join("\n\n") + "\n";
|
|
813
|
-
},
|
|
813
|
+
}, bn = (e, t, n, r) => {
|
|
814
814
|
let a = i(e, t);
|
|
815
815
|
switch (t) {
|
|
816
816
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${a};`;
|
|
@@ -820,61 +820,61 @@ BEGIN
|
|
|
820
820
|
case "turso":
|
|
821
821
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${a};`;
|
|
822
822
|
}
|
|
823
|
-
},
|
|
824
|
-
let o =
|
|
825
|
-
if (t === "postgres") return `${s}\n\nSET search_path TO ${c};\n\n${
|
|
826
|
-
let { sorted: l, cyclic: u } =
|
|
827
|
-
for (let e of l) f.push(
|
|
828
|
-
if (!O(t)) for (let e of u) f.push(
|
|
823
|
+
}, xn = (e, t, n, r, a = {}) => {
|
|
824
|
+
let o = en(t, a), s = bn(n, t, r, o), c = i(n, t);
|
|
825
|
+
if (t === "postgres") return `${s}\n\nSET search_path TO ${c};\n\n${yn(e, t)}`;
|
|
826
|
+
let { sorted: l, cyclic: u } = pn(e), d = hn(u, t), f = [s];
|
|
827
|
+
for (let e of l) f.push(tn(e, t, n, d.get(e.tableName), o));
|
|
828
|
+
if (!O(t)) for (let e of u) f.push(mn(e, t, n));
|
|
829
829
|
for (let e of l) {
|
|
830
|
-
let r =
|
|
830
|
+
let r = rn(e, t, n);
|
|
831
831
|
r && f.push(r);
|
|
832
832
|
}
|
|
833
833
|
return f.join("\n\n") + "\n";
|
|
834
|
-
},
|
|
835
|
-
let { sorted: r, cyclic: i } =
|
|
834
|
+
}, Sn = (e, t, n = Nt) => {
|
|
835
|
+
let { sorted: r, cyclic: i } = pn(e), a = hn(i, t), o = [], s = _n(r, t);
|
|
836
836
|
s && o.push(s);
|
|
837
|
-
let c =
|
|
837
|
+
let c = gn(r, t);
|
|
838
838
|
c && o.push(c);
|
|
839
|
-
for (let e of r) o.push(
|
|
840
|
-
for (let e of i) o.push(
|
|
841
|
-
return o.push(...
|
|
842
|
-
},
|
|
839
|
+
for (let e of r) o.push(tn(e, t, null, a.get(e.tableName)));
|
|
840
|
+
for (let e of i) o.push(mn(e, t));
|
|
841
|
+
return o.push(...an(r, t, n)), o.join("\n\n") + "\n";
|
|
842
|
+
}, Cn = (e, t = "postgres", n = Nt, r = {}) => A.gen(function* () {
|
|
843
843
|
let i = yield* j.SqlClient;
|
|
844
|
-
yield*
|
|
845
|
-
}),
|
|
844
|
+
yield* ht(i, An(i, yn(e, t, n, { charset: r.charset }), t, r.retryFilter), { schema: r.lockSchema }).pipe(A.orDie);
|
|
845
|
+
}), wn = (e, t) => {
|
|
846
846
|
let n = t.cause ?? {};
|
|
847
847
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
848
|
-
},
|
|
848
|
+
}, Tn = (e, t) => {
|
|
849
849
|
let n = e.trimStart();
|
|
850
850
|
return !!(/\bIF NOT EXISTS\b/i.test(n) || /^CREATE OR REPLACE\b/i.test(n) || /^DROP\s[\s\S]*?\bIF EXISTS\b/i.test(n) || /^SET search_path\b/i.test(n) || /^USE[\s`"[]/i.test(n) || /^IF\s/i.test(n) || (t === "mysql" || t === "mariadb") && /^CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(n));
|
|
851
|
-
},
|
|
851
|
+
}, En = () => {
|
|
852
852
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
853
853
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
854
|
-
},
|
|
854
|
+
}, Dn = (e) => ({
|
|
855
855
|
while: e,
|
|
856
|
-
times:
|
|
857
|
-
schedule:
|
|
858
|
-
}),
|
|
856
|
+
times: En(),
|
|
857
|
+
schedule: Ce.jittered(Ce.exponential("50 millis"))
|
|
858
|
+
}), On = class {
|
|
859
859
|
statement;
|
|
860
860
|
error;
|
|
861
861
|
_tag = "DdlStatementFailed";
|
|
862
862
|
constructor(e, t) {
|
|
863
863
|
this.statement = e, this.error = t;
|
|
864
864
|
}
|
|
865
|
-
},
|
|
866
|
-
let r = yield* j.SqlClient, i = n !== void 0 &&
|
|
867
|
-
for (let a of
|
|
868
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
869
|
-
let e = r.unsafe(a).pipe(A.catchIf((e) =>
|
|
870
|
-
|
|
865
|
+
}, kn = (e, t, n) => A.gen(function* () {
|
|
866
|
+
let r = yield* j.SqlClient, i = n !== void 0 && _t(t) === "per-operation";
|
|
867
|
+
for (let a of jn(e)) {
|
|
868
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && Ht.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
869
|
+
let e = r.unsafe(a).pipe(A.catchIf((e) => wn(a, e), () => A.succeed([])), A.tapError((e) => A.sync(() => {
|
|
870
|
+
Ht.error(Pe("migrate: statement failed", a, e, 200));
|
|
871
871
|
})));
|
|
872
|
-
yield* (i && n !== void 0 &&
|
|
872
|
+
yield* (i && n !== void 0 && Tn(a, t) ? e.pipe(A.retry(Dn((e) => n(e) === "retry"))) : e).pipe(A.mapError((e) => new On(a, e)));
|
|
873
873
|
}
|
|
874
|
-
}),
|
|
875
|
-
let i = n === "turso" ?
|
|
876
|
-
return (r !== void 0 &&
|
|
877
|
-
},
|
|
874
|
+
}), An = (e, t, n, r) => {
|
|
875
|
+
let i = n === "turso" ? kn(t, n, r) : e.withTransaction(kn(t, n, r)), a = (e) => e instanceof On ? e.error : e;
|
|
876
|
+
return (r !== void 0 && _t(n) === "plan-transactional" ? i.pipe(A.retry(Dn((e) => r(a(e)) === "retry"))) : i).pipe(A.orDieWith((e) => e instanceof On ? Error(Pe("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
877
|
+
}, jn = (e) => {
|
|
878
878
|
let t = [], n = "", r = !1;
|
|
879
879
|
for (let i = 0; i < e.length; i++) {
|
|
880
880
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -889,30 +889,30 @@ BEGIN
|
|
|
889
889
|
}
|
|
890
890
|
let i = n.trim();
|
|
891
891
|
return i.length > 0 && t.push(i), t;
|
|
892
|
-
},
|
|
893
|
-
await A.runPromise(
|
|
894
|
-
},
|
|
895
|
-
let i =
|
|
896
|
-
yield*
|
|
897
|
-
}),
|
|
898
|
-
await A.runPromise(
|
|
892
|
+
}, Mn = async (e, t, n = "postgres", r = {}) => {
|
|
893
|
+
await A.runPromise(Cn(e, n, void 0, r).pipe(A.provide(t)));
|
|
894
|
+
}, Nn = (e, t, n = "postgres", r = {}) => A.gen(function* () {
|
|
895
|
+
let i = xn(e, n, t, void 0, { charset: r.charset }), a = yield* j.SqlClient;
|
|
896
|
+
yield* ht(a, An(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(A.orDie);
|
|
897
|
+
}), Pn = async (e, t, n, r = "postgres", i = {}) => {
|
|
898
|
+
await A.runPromise(Nn(e, t, r, i).pipe(A.provide(n))), await re({
|
|
899
899
|
namespace: t,
|
|
900
900
|
dialect: r
|
|
901
901
|
});
|
|
902
|
-
},
|
|
902
|
+
}, Fn = async (e, t, n = "postgres", r = {}) => {
|
|
903
903
|
await A.runPromise(A.gen(function* () {
|
|
904
|
-
let t =
|
|
905
|
-
yield*
|
|
904
|
+
let t = Sn(e, n), i = yield* j.SqlClient;
|
|
905
|
+
yield* ht(i, An(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(A.orDie);
|
|
906
906
|
}).pipe(A.provide(t)));
|
|
907
|
-
},
|
|
907
|
+
}, In = /'(?:''|[^'])*'|"(?:""|[^"])*"|\[(?:\]\]|[^\]])*\]|`(?:``|[^`])*`|[A-Za-z_][A-Za-z_0-9$]*|\d+(?:\.\d+)?|::|<>|!=|<=|>=|\|\||[^\s]/g, Ln = (e) => {
|
|
908
908
|
let t = 0;
|
|
909
|
-
for (let n of e.matchAll(
|
|
910
|
-
},
|
|
909
|
+
for (let n of e.matchAll(In)) if (n[0] === "(" && t++, n[0] === ")" && t--, t === 0 && n[0].toLowerCase() === "where") return e.slice(n.index + n[0].length).trim().replace(/;$/, "").trim();
|
|
910
|
+
}, Rn = (e) => {
|
|
911
911
|
if (e === void 0) return;
|
|
912
|
-
let t = e.match(
|
|
912
|
+
let t = e.match(In) ?? [], n = "(?:'(?:''|[^'])*'(?:\\s*::\\s*text)?|[0-9]+)", r = RegExp(`^\\s*${n}(?:\\s*,\\s*${n})*\\s*$`, "i");
|
|
913
913
|
for (let e = 0; e < t.length - 5; e++) {
|
|
914
914
|
let n = t[e + 4];
|
|
915
|
-
t[e] === "=" && t[e + 1]?.toLowerCase() === "any" && t[e + 2] === "(" && t[e + 3]?.toLowerCase() === "array" && n.startsWith("[") && n.endsWith("]") && t[e + 5] === ")" && r.test(n.slice(1, -1)) && t.splice(e, 6, "in", "(", ...n.slice(1, -1).match(
|
|
915
|
+
t[e] === "=" && t[e + 1]?.toLowerCase() === "any" && t[e + 2] === "(" && t[e + 3]?.toLowerCase() === "array" && n.startsWith("[") && n.endsWith("]") && t[e + 5] === ")" && r.test(n.slice(1, -1)) && t.splice(e, 6, "in", "(", ...n.slice(1, -1).match(In) ?? [], ")");
|
|
916
916
|
}
|
|
917
917
|
let i = t.filter((e, n) => !(e === "::" && t[n - 1]?.startsWith("'") && t[n + 1]?.toLowerCase() === "text" || e.toLowerCase() === "text" && t[n - 1] === "::" && t[n - 2]?.startsWith("'"))).map((e) => {
|
|
918
918
|
if (e.startsWith("'")) return e;
|
|
@@ -950,64 +950,64 @@ BEGIN
|
|
|
950
950
|
return r;
|
|
951
951
|
};
|
|
952
952
|
return JSON.stringify(a(i));
|
|
953
|
-
},
|
|
953
|
+
}, zn = (e, t) => t.name === "id" && e.primaryKey?.length === 1 && e.primaryKey[0] === "id", Bn = /* @__PURE__ */ new Set(["integer", "bigint"]), Vn = (e) => Bn.has(e) ? "numeric" : "text", Hn = (e) => e.idScheme?.kind === "numeric" ? "numeric" : "text", Un = (e) => e.idStorage ?? (tr(e) ? "numeric" : "text"), Wn = (e) => e.idScheme ? Hn(e) : Un(e), Gn = (e) => e.type === "text" || e.type === "id" && Wn(e) === "text", Kn = (e, t) => t && (e.type === "text" || e.type === "id") ? {
|
|
954
954
|
...e,
|
|
955
955
|
type: "id",
|
|
956
956
|
unique: !0,
|
|
957
|
-
idStorage:
|
|
957
|
+
idStorage: Wn(e)
|
|
958
958
|
} : e.type === "id" ? {
|
|
959
959
|
...e,
|
|
960
|
-
idStorage:
|
|
961
|
-
} : e,
|
|
962
|
-
let r =
|
|
960
|
+
idStorage: Wn(e)
|
|
961
|
+
} : e, qn = (e, t, n) => {
|
|
962
|
+
let r = Kn(e, n), i = Kn(t, !1);
|
|
963
963
|
return n && r.type === "id" && i.type === "id" && r.idStorage === i.idStorage;
|
|
964
|
-
},
|
|
964
|
+
}, Jn = (e) => e.type !== "raw", Yn = (e) => ({
|
|
965
965
|
kind: e.kind,
|
|
966
966
|
geomKind: e.geomKind.toUpperCase(),
|
|
967
967
|
srid: e.srid
|
|
968
|
-
}),
|
|
968
|
+
}), Xn = (e, t) => {
|
|
969
969
|
if (e === void 0 || t === void 0) return e === t;
|
|
970
|
-
let n =
|
|
970
|
+
let n = Yn(e), r = Yn(t);
|
|
971
971
|
return n.kind === r.kind && n.geomKind === r.geomKind && n.srid === r.srid;
|
|
972
|
-
},
|
|
972
|
+
}, Zn = (e) => {
|
|
973
973
|
let { kind: t, kindOptions: n, ...r } = e, i = {
|
|
974
974
|
...r,
|
|
975
|
-
...
|
|
976
|
-
...e.where === void 0 ? {} : { where:
|
|
975
|
+
...Me(t, n),
|
|
976
|
+
...e.where === void 0 ? {} : { where: Rn(e.where) }
|
|
977
977
|
};
|
|
978
978
|
return e.expression ? {
|
|
979
979
|
...i,
|
|
980
980
|
columns: []
|
|
981
981
|
} : i;
|
|
982
|
-
},
|
|
982
|
+
}, Qn = (e) => {
|
|
983
983
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
984
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
984
|
+
if (Array.isArray(e)) return `[${e.map(Qn).join(",")}]`;
|
|
985
985
|
let t = e;
|
|
986
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
987
|
-
},
|
|
986
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${Qn(t[e])}`).join(",")}}`;
|
|
987
|
+
}, $n = (e) => {
|
|
988
988
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
989
989
|
let t = e.defaultValue;
|
|
990
990
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
991
991
|
if (typeof t == "number") return String(t);
|
|
992
|
-
if (typeof t != "string") return
|
|
992
|
+
if (typeof t != "string") return Qn(t);
|
|
993
993
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
994
994
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
995
995
|
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);
|
|
996
996
|
if (o) try {
|
|
997
|
-
return
|
|
997
|
+
return Qn(JSON.parse(o[1]));
|
|
998
998
|
} catch {}
|
|
999
999
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1000
1000
|
if (s) try {
|
|
1001
|
-
return
|
|
1001
|
+
return Qn(JSON.parse(s[1]));
|
|
1002
1002
|
} catch {}
|
|
1003
1003
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1004
|
-
return
|
|
1004
|
+
return Qn(JSON.parse(a));
|
|
1005
1005
|
} catch {}
|
|
1006
1006
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1007
|
-
},
|
|
1008
|
-
let t =
|
|
1007
|
+
}, er = (e) => {
|
|
1008
|
+
let t = $n(e);
|
|
1009
1009
|
return t === "1" || t === "true" ? "__BOOL_TRUE__" : t === "0" || t === "false" ? "__BOOL_FALSE__" : t;
|
|
1010
|
-
},
|
|
1010
|
+
}, tr = (e) => typeof e.defaultValue == "string" && /^nextval\(.+::regclass\)$/i.test(e.defaultValue.trim()), nr = (e) => {
|
|
1011
1011
|
if (!e) return null;
|
|
1012
1012
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1013
1013
|
return {
|
|
@@ -1016,9 +1016,9 @@ BEGIN
|
|
|
1016
1016
|
onDelete: t(e.onDelete),
|
|
1017
1017
|
onUpdate: t(e.onUpdate)
|
|
1018
1018
|
};
|
|
1019
|
-
},
|
|
1019
|
+
}, rr = (e, t, n) => {
|
|
1020
1020
|
if (t === "mssql") {
|
|
1021
|
-
let t =
|
|
1021
|
+
let t = Vt(e, n);
|
|
1022
1022
|
if (t !== void 0) return t;
|
|
1023
1023
|
}
|
|
1024
1024
|
try {
|
|
@@ -1027,46 +1027,46 @@ BEGIN
|
|
|
1027
1027
|
} catch {
|
|
1028
1028
|
return;
|
|
1029
1029
|
}
|
|
1030
|
-
},
|
|
1030
|
+
}, ir = (e) => {
|
|
1031
1031
|
if (e == null) return e;
|
|
1032
|
-
if (Array.isArray(e)) return e.map(
|
|
1032
|
+
if (Array.isArray(e)) return e.map(ir);
|
|
1033
1033
|
if (typeof e != "object") return e;
|
|
1034
1034
|
let t = {};
|
|
1035
1035
|
for (let n of Object.keys(e).sort()) {
|
|
1036
1036
|
let r = e[n];
|
|
1037
|
-
r !== void 0 && (t[n] =
|
|
1037
|
+
r !== void 0 && (t[n] = ir(r));
|
|
1038
1038
|
}
|
|
1039
1039
|
return t;
|
|
1040
|
-
},
|
|
1040
|
+
}, ar = (e) => {
|
|
1041
1041
|
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs && !e.jsonChecks && !e.narrowedFrom && !e.rawDdl && !e.charset) return e;
|
|
1042
1042
|
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, jsonChecks: a, narrowedFrom: o, rawDdl: s, charset: c, ...l } = e;
|
|
1043
1043
|
return l;
|
|
1044
|
-
},
|
|
1045
|
-
let t =
|
|
1044
|
+
}, or = (e) => {
|
|
1045
|
+
let t = ar((() => {
|
|
1046
1046
|
if (e.storageType === void 0) return e;
|
|
1047
1047
|
let { storageType: t, enumValues: n, enumName: r, arrayElement: i, ...a } = e;
|
|
1048
1048
|
return {
|
|
1049
1049
|
...a,
|
|
1050
1050
|
type: t
|
|
1051
1051
|
};
|
|
1052
|
-
})()), { references: n, defaultValue: r, hasDefault: i, oneOf: a, spatial: o, enumValues: s, ...c } = t, l = t.type === "id" &&
|
|
1052
|
+
})()), { references: n, defaultValue: r, hasDefault: i, oneOf: a, spatial: o, enumValues: s, ...c } = t, l = t.type === "id" && tr(t) ? null : er(t), u = nr(t.references);
|
|
1053
1053
|
return {
|
|
1054
1054
|
...c,
|
|
1055
1055
|
hasDefault: l !== null,
|
|
1056
1056
|
...l === null ? {} : { defaultValue: l },
|
|
1057
1057
|
...u === null ? {} : { references: u },
|
|
1058
1058
|
...t.oneOf !== void 0 && t.oneOf.length > 0 ? { oneOf: [...t.oneOf].sort() } : {},
|
|
1059
|
-
...t.spatial === void 0 ? {} : { spatial:
|
|
1059
|
+
...t.spatial === void 0 ? {} : { spatial: Yn(t.spatial) },
|
|
1060
1060
|
...t.enumValues === void 0 ? {} : { enumValues: [...t.enumValues].sort() }
|
|
1061
1061
|
};
|
|
1062
|
-
},
|
|
1062
|
+
}, sr = (e) => e.columns.filter((e) => !k(e.name)).map((t) => or(Kn(t, zn(e, t)))).sort((e, t) => e.name.localeCompare(t.name)), cr = (e) => [...e].map(Zn).sort((e, t) => e.name.localeCompare(t.name)), lr = (e) => [...e].filter((e) => !k(e.name)).map((e) => ({
|
|
1063
1063
|
name: e.name,
|
|
1064
|
-
columns:
|
|
1065
|
-
indexes:
|
|
1064
|
+
columns: sr(e),
|
|
1065
|
+
indexes: cr(e.indexes)
|
|
1066
1066
|
})).sort((e, t) => e.name.localeCompare(t.name)), L = (e) => {
|
|
1067
|
-
let t = { tables:
|
|
1068
|
-
return
|
|
1069
|
-
},
|
|
1067
|
+
let t = { tables: lr(e.tables) }, n = JSON.stringify(ir(t));
|
|
1068
|
+
return Te("sha256").update(n).digest("hex");
|
|
1069
|
+
}, ur = (e) => e.slice(0, 16), dr = ["utf8mb3", "utf8mb4"], fr = (e) => e === "utf8mb3" || e === "utf8mb4", pr = (e) => {
|
|
1070
1070
|
switch (e.type) {
|
|
1071
1071
|
case "text":
|
|
1072
1072
|
case "enum": return !0;
|
|
@@ -1074,21 +1074,21 @@ BEGIN
|
|
|
1074
1074
|
case "reference": return e.referenceStorage !== "numeric";
|
|
1075
1075
|
default: return !1;
|
|
1076
1076
|
}
|
|
1077
|
-
},
|
|
1077
|
+
}, mr = (e, t) => e.map((e) => ({
|
|
1078
1078
|
...e,
|
|
1079
|
-
columns: e.columns.map((e) =>
|
|
1079
|
+
columns: e.columns.map((e) => pr(e) && e.charset === void 0 ? {
|
|
1080
1080
|
...e,
|
|
1081
1081
|
charset: t
|
|
1082
1082
|
} : e)
|
|
1083
|
-
})),
|
|
1083
|
+
})), hr = (e) => e.columns.flatMap((e) => e.charset === void 0 ? [] : [{
|
|
1084
1084
|
column: e.name,
|
|
1085
1085
|
charset: e.charset
|
|
1086
|
-
}]),
|
|
1087
|
-
if (!
|
|
1086
|
+
}]), gr = "utf8mb4", _r = (e) => e.columns.some((e) => e.type === "json" || e.type === "array" || e.storageType === "json"), vr = (e) => {
|
|
1087
|
+
if (!ve(e.dialect)) return [];
|
|
1088
1088
|
let t = [];
|
|
1089
1089
|
for (let n of [...e.live.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1090
1090
|
if (k(n.name)) continue;
|
|
1091
|
-
let r =
|
|
1091
|
+
let r = hr(n);
|
|
1092
1092
|
if (r.length === 0) continue;
|
|
1093
1093
|
if (e.charset !== void 0) {
|
|
1094
1094
|
let i = r.filter((t) => t.charset !== e.charset);
|
|
@@ -1100,13 +1100,13 @@ BEGIN
|
|
|
1100
1100
|
});
|
|
1101
1101
|
continue;
|
|
1102
1102
|
}
|
|
1103
|
-
if (
|
|
1104
|
-
let e = r.filter((e) => e.charset !==
|
|
1103
|
+
if (_r(n)) {
|
|
1104
|
+
let e = r.filter((e) => e.charset !== gr);
|
|
1105
1105
|
e.length > 0 && t.push({
|
|
1106
1106
|
table: n.name,
|
|
1107
1107
|
kind: "json-outruns-text",
|
|
1108
1108
|
columns: e,
|
|
1109
|
-
expected:
|
|
1109
|
+
expected: gr
|
|
1110
1110
|
});
|
|
1111
1111
|
continue;
|
|
1112
1112
|
}
|
|
@@ -1119,14 +1119,14 @@ BEGIN
|
|
|
1119
1119
|
});
|
|
1120
1120
|
}
|
|
1121
1121
|
return t;
|
|
1122
|
-
},
|
|
1122
|
+
}, yr = (e) => {
|
|
1123
1123
|
let t = e.columns.map((e) => `${e.column} (${e.charset})`).join(", ");
|
|
1124
1124
|
switch (e.kind) {
|
|
1125
1125
|
case "disagrees-with-declaration": return `${e.table}: declared ${e.expected}, stored otherwise — ${t}`;
|
|
1126
1126
|
case "json-outruns-text": return `${e.table}: its json column holds every character (utf8mb4); these text columns do not — ${t}`;
|
|
1127
1127
|
case "mixed": return `${e.table}: its string columns are not in one character set — ${t}`;
|
|
1128
1128
|
}
|
|
1129
|
-
},
|
|
1129
|
+
}, br = "declare the store's character set in app.config.ts — store: { dialect: 'mariadb' | 'mysql', charset: 'utf8mb4' } — and run `voltro db plan`: every table the app declares is created with it and converted to it (a table rewrite; foreign keys are re-created around it). `utf8mb3` is accepted too, for a database that must stay there.", xr = (e, t, n) => {
|
|
1130
1130
|
let r = t.references ? {
|
|
1131
1131
|
table: t.references().tableName,
|
|
1132
1132
|
column: t.referenceColumn ?? "id",
|
|
@@ -1169,7 +1169,7 @@ BEGIN
|
|
|
1169
1169
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
1170
1170
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
1171
1171
|
};
|
|
1172
|
-
},
|
|
1172
|
+
}, Sr = (e, t) => {
|
|
1173
1173
|
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
1174
1174
|
i.has(e.name) || (i.add(e.name), r.push(e));
|
|
1175
1175
|
}, o = e.appliedPrimaryKey ?? [];
|
|
@@ -1186,15 +1186,15 @@ BEGIN
|
|
|
1186
1186
|
});
|
|
1187
1187
|
let s = e.appliedIndexes ?? [];
|
|
1188
1188
|
for (let n of s) {
|
|
1189
|
-
let r =
|
|
1189
|
+
let r = je(n.kind, t);
|
|
1190
1190
|
if (r === null) continue;
|
|
1191
|
-
let i = n.fields[0], o = typeof i == "string" ? e.fields[i]?.vectorPrecision : void 0, s = r === "hnsw" ? { hnsw:
|
|
1191
|
+
let i = n.fields[0], o = typeof i == "string" ? e.fields[i]?.vectorPrecision : void 0, s = r === "hnsw" ? { hnsw: Ae(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");
|
|
1192
1192
|
a({
|
|
1193
1193
|
name: n.name,
|
|
1194
1194
|
table: e.tableName,
|
|
1195
1195
|
columns: c,
|
|
1196
1196
|
unique: n.unique ?? !1,
|
|
1197
|
-
...
|
|
1197
|
+
...Me(r, s),
|
|
1198
1198
|
...n.where === void 0 ? {} : { where: n.where },
|
|
1199
1199
|
...l ? { expression: !0 } : {}
|
|
1200
1200
|
});
|
|
@@ -1220,11 +1220,11 @@ BEGIN
|
|
|
1220
1220
|
});
|
|
1221
1221
|
}
|
|
1222
1222
|
return r;
|
|
1223
|
-
},
|
|
1223
|
+
}, Cr = (e, t) => {
|
|
1224
1224
|
let n = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), r = [];
|
|
1225
1225
|
for (let [i, a] of Object.entries(e.fields)) {
|
|
1226
1226
|
if (a.dropped) continue;
|
|
1227
|
-
let e =
|
|
1227
|
+
let e = xr(i, a, t);
|
|
1228
1228
|
r.push(n.has(i) ? {
|
|
1229
1229
|
...e,
|
|
1230
1230
|
unique: !0
|
|
@@ -1234,27 +1234,27 @@ BEGIN
|
|
|
1234
1234
|
return {
|
|
1235
1235
|
name: e.tableName,
|
|
1236
1236
|
columns: r,
|
|
1237
|
-
indexes:
|
|
1237
|
+
indexes: Sr(e, t),
|
|
1238
1238
|
...i.length > 0 ? { primaryKey: [...i] } : {},
|
|
1239
1239
|
...a === void 0 ? {} : { renamedFrom: a }
|
|
1240
1240
|
};
|
|
1241
|
-
},
|
|
1241
|
+
}, wr = (e) => {
|
|
1242
1242
|
let t = /* @__PURE__ */ new Map();
|
|
1243
1243
|
for (let n of e) for (let e of n.indexes) {
|
|
1244
1244
|
let r = t.get(e.name);
|
|
1245
1245
|
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}').`);
|
|
1246
1246
|
t.set(e.name, n.name);
|
|
1247
1247
|
}
|
|
1248
|
-
},
|
|
1248
|
+
}, Tr = (e, t, n = {}) => {
|
|
1249
1249
|
if (n.charset !== void 0 && t !== "mysql" && t !== "mariadb") throw Error(`store charset '${n.charset}' is declared for a ${t ?? "dialect-less"} store — a character set is a MySQL / MariaDB setting. Remove \`charset\` from \`store\` in app.config.ts, or declare \`store: { dialect: 'mysql' | 'mariadb', charset }\`.`);
|
|
1250
|
-
let r = e.filter((e) => !c(e.tableName)).map((e) =>
|
|
1250
|
+
let r = e.filter((e) => !c(e.tableName)).map((e) => Cr(Be(e, t), t));
|
|
1251
1251
|
if (t === "mysql" || t === "mariadb") {
|
|
1252
1252
|
for (let e of r) for (let n of e.indexes) if (n.where !== void 0) throw Error(`Partial index '${n.name}' on '${e.name}' is not supported by ${t}. Use uniqueActive for portable conditional uniqueness.`);
|
|
1253
1253
|
}
|
|
1254
|
-
|
|
1255
|
-
let i = t === void 0 ? r : r.map((e) =>
|
|
1256
|
-
return { tables: n.charset === void 0 ? i :
|
|
1257
|
-
},
|
|
1254
|
+
wr(r);
|
|
1255
|
+
let i = t === void 0 ? r : r.map((e) => Er(e, t));
|
|
1256
|
+
return { tables: n.charset === void 0 ? i : mr(i, n.charset) };
|
|
1257
|
+
}, Er = (e, t) => {
|
|
1258
1258
|
let n = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1259
1259
|
return {
|
|
1260
1260
|
...e,
|
|
@@ -1268,20 +1268,20 @@ BEGIN
|
|
|
1268
1268
|
return n;
|
|
1269
1269
|
}
|
|
1270
1270
|
if (e.maxLength !== void 0) return e;
|
|
1271
|
-
let r =
|
|
1271
|
+
let r = rr(e, t, n.has(e.name) || e.unique);
|
|
1272
1272
|
return r === void 0 ? e : {
|
|
1273
1273
|
...e,
|
|
1274
1274
|
maxLength: r
|
|
1275
1275
|
};
|
|
1276
1276
|
})
|
|
1277
1277
|
};
|
|
1278
|
-
},
|
|
1278
|
+
}, Dr = (e, t, n = Nt) => A.gen(function* () {
|
|
1279
1279
|
let r = (yield* e`
|
|
1280
1280
|
SELECT p.prosrc
|
|
1281
1281
|
FROM pg_proc p
|
|
1282
1282
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
1283
1283
|
WHERE n.nspname = current_schema()
|
|
1284
|
-
AND p.proname = ${
|
|
1284
|
+
AND p.proname = ${zt(n)}
|
|
1285
1285
|
`)[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_"));
|
|
1286
1286
|
if (o.length === 0) return {
|
|
1287
1287
|
missing: [],
|
|
@@ -1300,10 +1300,10 @@ BEGIN
|
|
|
1300
1300
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1301
1301
|
WHERE NOT t.tgisinternal
|
|
1302
1302
|
AND n.nspname = current_schema()
|
|
1303
|
-
AND t.tgname LIKE ${`${
|
|
1303
|
+
AND t.tgname LIKE ${`${Pt}%`}
|
|
1304
1304
|
`, c = (e, t) => `${e}\u0000${t}`, l = new Set(s.map((e) => c(e.relname, e.tgname))), u = [], d = [];
|
|
1305
1305
|
for (let e of o) {
|
|
1306
|
-
let t = l.has(c(e.tableName,
|
|
1306
|
+
let t = l.has(c(e.tableName, It(e.tableName, n))), r = e.isReactive !== !1;
|
|
1307
1307
|
r && !t && u.push(e.tableName), !r && t && d.push(e.tableName);
|
|
1308
1308
|
}
|
|
1309
1309
|
return {
|
|
@@ -1316,30 +1316,30 @@ BEGIN
|
|
|
1316
1316
|
present: l.size
|
|
1317
1317
|
}
|
|
1318
1318
|
};
|
|
1319
|
-
}),
|
|
1319
|
+
}), Or = (e) => {
|
|
1320
1320
|
let t = [];
|
|
1321
1321
|
if (e.missing.length > 0) {
|
|
1322
1322
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
1323
|
-
t.push(`${e.missing.length} reactive table(s) have NO change trigger in the database — ${n}${r}. Writes to them will not reach another instance's subscribers; a single instance is unaffected, which is why this stays invisible until you scale out. Run \`voltro db apply\` to install them.` + (e.compared === void 0 ? "" : ` (compared against ${e.compared.present} \`${
|
|
1323
|
+
t.push(`${e.missing.length} reactive table(s) have NO change trigger in the database — ${n}${r}. Writes to them will not reach another instance's subscribers; a single instance is unaffected, which is why this stays invisible until you scale out. Run \`voltro db apply\` to install them.` + (e.compared === void 0 ? "" : ` (compared against ${e.compared.present} \`${Pt}*\` trigger(s) present in schema "${e.compared.schema}", channel "${e.compared.channel}")`));
|
|
1324
1324
|
}
|
|
1325
1325
|
if (e.stale.length > 0) {
|
|
1326
1326
|
let n = e.stale.slice(0, 8).join(", ");
|
|
1327
1327
|
t.push(`${e.stale.length} .nonReactive() table(s) still carry a change trigger — ${n}. They keep paying REPLICA IDENTITY FULL and a NOTIFY on every write for a subscription nobody receives. \`voltro db apply\` removes them.`);
|
|
1328
1328
|
}
|
|
1329
1329
|
return e.functionOutdated && t.push("The change-notify function in this database is OLDER than the framework installed here. Its triggers fire, so nothing looks wrong — but a row too large for a NOTIFY payload (postgres caps it at 8000 bytes) is emitted without its primary key, and a change that carries no key cannot be re-read: it reaches subscriptions as a re-query and reaches every TAP — search index, analytics mirror, cdc-out, row history — as nothing at all. Run `voltro db apply` to replace it."), t.length > 0 ? t.join("\n") : void 0;
|
|
1330
|
-
},
|
|
1330
|
+
}, kr = {
|
|
1331
1331
|
postgres: !0,
|
|
1332
1332
|
mysql: !0,
|
|
1333
1333
|
mariadb: !0,
|
|
1334
1334
|
mssql: !0,
|
|
1335
1335
|
sqlite: !0
|
|
1336
|
-
},
|
|
1336
|
+
}, Ar = {
|
|
1337
1337
|
postgres: !0,
|
|
1338
1338
|
mysql: !1,
|
|
1339
1339
|
mariadb: !1,
|
|
1340
1340
|
mssql: !0,
|
|
1341
1341
|
sqlite: !0
|
|
1342
|
-
},
|
|
1342
|
+
}, jr = (e) => {
|
|
1343
1343
|
switch (e) {
|
|
1344
1344
|
case "add-column":
|
|
1345
1345
|
case "drop-column":
|
|
@@ -1350,33 +1350,33 @@ BEGIN
|
|
|
1350
1350
|
case "add-unique":
|
|
1351
1351
|
case "add-unique-composite":
|
|
1352
1352
|
case "add-check":
|
|
1353
|
-
case "convert-charset": return
|
|
1354
|
-
default: return
|
|
1353
|
+
case "convert-charset": return Ar;
|
|
1354
|
+
default: return kr;
|
|
1355
1355
|
}
|
|
1356
|
-
},
|
|
1356
|
+
}, Mr = (e, t) => {
|
|
1357
1357
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1358
1358
|
return new Map(e.map((e) => [e.tableName, {
|
|
1359
1359
|
table: e,
|
|
1360
1360
|
snapshot: n.get(e.tableName),
|
|
1361
1361
|
columnDefs: e.fields
|
|
1362
1362
|
}]));
|
|
1363
|
-
}, Mr = (e, t) => {
|
|
1364
|
-
let n = Qn(e), r = Qn(t);
|
|
1365
|
-
if (n === r) return !0;
|
|
1366
|
-
let i = er, a = (e) => e.type === "id" && e.idScheme?.kind === "numeric";
|
|
1367
|
-
return e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e)) ? !0 : $n(e) === $n(t);
|
|
1368
1363
|
}, Nr = (e, t) => {
|
|
1364
|
+
let n = $n(e), r = $n(t);
|
|
1365
|
+
if (n === r) return !0;
|
|
1366
|
+
let i = tr, a = (e) => e.type === "id" && e.idScheme?.kind === "numeric";
|
|
1367
|
+
return e.type === "id" && t.type === "id" && (a(e) && n === null && i(t) || a(t) && r === null && i(e)) ? !0 : er(e) === er(t);
|
|
1368
|
+
}, Pr = (e, t) => {
|
|
1369
1369
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1370
1370
|
if (!n && !r) return !0;
|
|
1371
1371
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1372
1372
|
let i = [...n].sort(), a = [...r].sort();
|
|
1373
1373
|
return i.every((e, t) => e === a[t]);
|
|
1374
|
-
},
|
|
1374
|
+
}, Fr = (e, t, n, r) => n === void 0 || O(n) ? !0 : e.type !== "text" || !Gn(t) || rr(e, n, r) === t.maxLength, Ir = (e, t, n, r, i = !1) => (!Jn(e) || e.type === t.type || qn(e, t, i)) && Kn(e, i).idStorage === Kn(t, !1).idStorage && e.nullable === t.nullable && (e.unique === t.unique || qn(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)) && Xn(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") && Nr(e, t) && Fr(e, t, n, r) && (e.type !== "reference" || (e.referenceStorage ?? "text") === (t.referenceStorage ?? "text")) && JSON.stringify(nr(e.references)) === JSON.stringify(nr(t.references)) && Pr(e.oneOf, t.oneOf), Lr = (e, t) => t.oneOf && t.oneOf.length > 0 ? R({
|
|
1375
1375
|
kind: "add-check",
|
|
1376
1376
|
table: e,
|
|
1377
1377
|
column: t.name,
|
|
1378
1378
|
values: t.oneOf
|
|
1379
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1379
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, Rr = (e, t) => e.unique === t.unique && e.valid !== !1 && t.valid !== !1 && Rn(e.where) === Rn(t.where) && JSON.stringify(Me(e.kind, e.kindOptions)) === JSON.stringify(Me(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])), zr = (e, t, n) => {
|
|
1380
1380
|
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));
|
|
1381
1381
|
for (let t of e.columns) {
|
|
1382
1382
|
let i = r.get(t.name);
|
|
@@ -1384,7 +1384,7 @@ BEGIN
|
|
|
1384
1384
|
a.push(t);
|
|
1385
1385
|
continue;
|
|
1386
1386
|
}
|
|
1387
|
-
|
|
1387
|
+
Ir(t, i, n, c.has(t.name) || t.unique, zn(e, t)) || s.push({
|
|
1388
1388
|
declared: t,
|
|
1389
1389
|
live: i
|
|
1390
1390
|
});
|
|
@@ -1395,15 +1395,15 @@ BEGIN
|
|
|
1395
1395
|
removed: o,
|
|
1396
1396
|
changed: s
|
|
1397
1397
|
};
|
|
1398
|
-
},
|
|
1398
|
+
}, Br = (e, t, n) => {
|
|
1399
1399
|
let r = (e) => n === "turso" || n === "sqlite" ? e.toLowerCase() : e, i = new Map(t.indexes.map((e) => [r(e.name), e])), a = new Map(e.indexes.map((e) => [r(e.name), e])), o = [], s = [];
|
|
1400
1400
|
for (let t of e.indexes) {
|
|
1401
1401
|
let e = i.get(r(t.name));
|
|
1402
|
-
(!e || !
|
|
1402
|
+
(!e || !Rr(t, e)) && o.push(t);
|
|
1403
1403
|
}
|
|
1404
1404
|
for (let e of t.indexes) {
|
|
1405
1405
|
let t = a.get(r(e.name));
|
|
1406
|
-
(!t || !
|
|
1406
|
+
(!t || !Rr(t, e)) && s.push(e);
|
|
1407
1407
|
}
|
|
1408
1408
|
return {
|
|
1409
1409
|
added: o,
|
|
@@ -1412,33 +1412,33 @@ BEGIN
|
|
|
1412
1412
|
}, R = (e, t, n, r) => ({
|
|
1413
1413
|
op: e,
|
|
1414
1414
|
classification: t,
|
|
1415
|
-
atomicByDialect:
|
|
1415
|
+
atomicByDialect: jr(e.kind),
|
|
1416
1416
|
...n ? { reason: n } : {},
|
|
1417
1417
|
...r ? { blocked: r } : {}
|
|
1418
|
-
}),
|
|
1418
|
+
}), Vr = (e, t, n) => {
|
|
1419
1419
|
let r = {
|
|
1420
1420
|
kind: "add-column",
|
|
1421
1421
|
table: e,
|
|
1422
1422
|
column: t
|
|
1423
1423
|
};
|
|
1424
1424
|
return t.nullable ? R(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? R(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? R(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : R(r, "needs-backfill", "NOT NULL column on a table whose row count is unknown", { fix: `declare \`${t.name}: <type>().backfill(sql\`...\`)\` OR \`.default(value)\` so existing rows survive the migration` });
|
|
1425
|
-
},
|
|
1425
|
+
}, Hr = (e, t, n) => {
|
|
1426
1426
|
let r = {
|
|
1427
1427
|
kind: "drop-column",
|
|
1428
1428
|
table: e,
|
|
1429
1429
|
column: t.name
|
|
1430
1430
|
};
|
|
1431
1431
|
return n?.dropped ? R(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : R(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1432
|
-
},
|
|
1432
|
+
}, Ur = (e, t, n, r, i) => R({
|
|
1433
1433
|
kind: "create-table",
|
|
1434
1434
|
table: e,
|
|
1435
1435
|
columns: t,
|
|
1436
1436
|
indexes: n,
|
|
1437
1437
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1438
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1438
|
+
}, "safe", i ?? "new table — no data to preserve"), Wr = (e) => R({
|
|
1439
1439
|
kind: "drop-table",
|
|
1440
1440
|
table: e
|
|
1441
|
-
}, "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" }),
|
|
1441
|
+
}, "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, Kr = (e, t, n, r) => {
|
|
1442
1442
|
let i = (n ?? 0) >= r, a;
|
|
1443
1443
|
return a = !t.unique || t.where !== void 0 ? {
|
|
1444
1444
|
kind: "add-index",
|
|
@@ -1454,7 +1454,7 @@ BEGIN
|
|
|
1454
1454
|
name: t.name,
|
|
1455
1455
|
fields: t.columns
|
|
1456
1456
|
}, i ? R(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : R(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`);
|
|
1457
|
-
},
|
|
1457
|
+
}, qr = (e, t) => t.unique && t.where === void 0 && t.columns.length > 1 ? R({
|
|
1458
1458
|
kind: "drop-unique-composite",
|
|
1459
1459
|
table: e,
|
|
1460
1460
|
name: t.name
|
|
@@ -1462,9 +1462,9 @@ BEGIN
|
|
|
1462
1462
|
kind: "drop-index",
|
|
1463
1463
|
table: e,
|
|
1464
1464
|
index: t.name
|
|
1465
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1465
|
+
}, "safe", "drop index (no data loss — index is derived data)"), Jr = (e, t) => {
|
|
1466
1466
|
let n = e.type;
|
|
1467
|
-
if (n === "id") return
|
|
1467
|
+
if (n === "id") return Wn(e) === "numeric" ? "bigint" : "text";
|
|
1468
1468
|
if (n === "array") return t === void 0 || t === "postgres" ? "array" : t === "mysql" || t === "mariadb" ? "json" : "text";
|
|
1469
1469
|
if (n === "enum") return t === "mssql" || O(t ?? "postgres") ? "text" : "enum";
|
|
1470
1470
|
if (n === "reference") return e.referenceStorage === "numeric" ? "bigint" : "text";
|
|
@@ -1474,10 +1474,10 @@ BEGIN
|
|
|
1474
1474
|
case "mssql": return n === "json" ? "text" : n;
|
|
1475
1475
|
default: return n;
|
|
1476
1476
|
}
|
|
1477
|
-
},
|
|
1477
|
+
}, Yr = (e, t, n) => {
|
|
1478
1478
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1479
1479
|
return n === "postgres" ? `${r} — add \`{ using: '${t.name}::${t.type}' }\` when the cast is not implicit, or use a file-based migration` : `${r} — ${n === void 0 ? "this dialect" : n} converts in place (\`using\` is postgres-only and is ignored here), so verify the conversion is value-preserving for your data, or use a file-based migration`;
|
|
1480
|
-
},
|
|
1480
|
+
}, Xr = (e, t, n, r, i, a) => {
|
|
1481
1481
|
let o = [];
|
|
1482
1482
|
if (t.nullable !== n.nullable) {
|
|
1483
1483
|
let n = {
|
|
@@ -1502,7 +1502,7 @@ BEGIN
|
|
|
1502
1502
|
column: t.name
|
|
1503
1503
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1504
1504
|
}
|
|
1505
|
-
if (
|
|
1505
|
+
if (Jn(t) && Jr(t, r) !== Jr(n, r)) {
|
|
1506
1506
|
let i = t.narrowedFrom;
|
|
1507
1507
|
if (i && i.from === n.type) {
|
|
1508
1508
|
let r = {
|
|
@@ -1522,10 +1522,10 @@ BEGIN
|
|
|
1522
1522
|
from: n.type,
|
|
1523
1523
|
to: t.type
|
|
1524
1524
|
};
|
|
1525
|
-
o.push(R(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix:
|
|
1525
|
+
o.push(R(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: Yr(n.type, t, r) }));
|
|
1526
1526
|
}
|
|
1527
1527
|
}
|
|
1528
|
-
if (t.type === "text" &&
|
|
1528
|
+
if (t.type === "text" && Gn(n) && !O(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1529
1529
|
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})`;
|
|
1530
1530
|
o.push(R({
|
|
1531
1531
|
kind: "alter-column-type",
|
|
@@ -1546,7 +1546,7 @@ BEGIN
|
|
|
1546
1546
|
...t.enumName === void 0 ? {} : { enumName: t.enumName }
|
|
1547
1547
|
}, "safe", `add '${n}' to the enum on ${e}.${t.name} — existing rows are untouched, and the label is what the declaration already promises`));
|
|
1548
1548
|
}
|
|
1549
|
-
if (!
|
|
1549
|
+
if (!Xn(t.spatial, n.spatial)) {
|
|
1550
1550
|
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;
|
|
1551
1551
|
o.push(R({
|
|
1552
1552
|
kind: "alter-column-type",
|
|
@@ -1589,7 +1589,7 @@ BEGIN
|
|
|
1589
1589
|
to: "decimal"
|
|
1590
1590
|
}, i ? "safe" : "needs-backfill", i ? `decimal(${r(n)}) → decimal(${r(t)}) on ${e}.${t.name} — widening, every value survives` : `decimal(${r(n)}) → decimal(${r(t)}) on ${e}.${t.name} — NARROWING; the engine ROUNDS to the new scale and rejects a value that no longer fits. Check first: SELECT COUNT(*) FROM ${e} WHERE ${t.name} <> ROUND(${t.name}, ${String(t.scale ?? 0)})`));
|
|
1591
1591
|
}
|
|
1592
|
-
if (!
|
|
1592
|
+
if (!Nr(t, n)) {
|
|
1593
1593
|
let n = {
|
|
1594
1594
|
kind: "alter-column-default",
|
|
1595
1595
|
table: e,
|
|
@@ -1610,21 +1610,21 @@ BEGIN
|
|
|
1610
1610
|
dropConstraints: (n.jsonChecks ?? []).map((e) => e.name).sort()
|
|
1611
1611
|
}, 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`));
|
|
1612
1612
|
}
|
|
1613
|
-
if (!
|
|
1613
|
+
if (!Pr(t.oneOf, n.oneOf)) {
|
|
1614
1614
|
n.oneOf && n.oneOf.length > 0 && o.push(R({
|
|
1615
1615
|
kind: "drop-check",
|
|
1616
1616
|
table: e,
|
|
1617
1617
|
column: t.name
|
|
1618
1618
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1619
|
-
let r =
|
|
1619
|
+
let r = Lr(e, t);
|
|
1620
1620
|
r && o.push(r);
|
|
1621
1621
|
}
|
|
1622
|
-
return JSON.stringify(
|
|
1622
|
+
return JSON.stringify(nr(t.references)) !== JSON.stringify(nr(n.references)) && (n.references && o.push(R({
|
|
1623
1623
|
kind: "drop-foreign-key",
|
|
1624
1624
|
table: e,
|
|
1625
1625
|
column: t.name
|
|
1626
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1627
|
-
},
|
|
1626
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...Zr(e, t))), o;
|
|
1627
|
+
}, Zr = (e, t) => {
|
|
1628
1628
|
let n = [];
|
|
1629
1629
|
if (!t.references) return n;
|
|
1630
1630
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1640,7 +1640,7 @@ BEGIN
|
|
|
1640
1640
|
...a,
|
|
1641
1641
|
orphanPolicy: i
|
|
1642
1642
|
}, "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(R(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1643
|
-
},
|
|
1643
|
+
}, Qr = (e, t, n) => {
|
|
1644
1644
|
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));
|
|
1645
1645
|
for (let [n, c] of Object.entries(t)) {
|
|
1646
1646
|
let t = c.renamedFrom;
|
|
@@ -1656,22 +1656,22 @@ BEGIN
|
|
|
1656
1656
|
consumedAddedNames: i,
|
|
1657
1657
|
consumedRemovedNames: a
|
|
1658
1658
|
};
|
|
1659
|
-
},
|
|
1659
|
+
}, $r = /* @__PURE__ */ new Set([
|
|
1660
1660
|
"postgres",
|
|
1661
1661
|
"mysql",
|
|
1662
1662
|
"mariadb",
|
|
1663
1663
|
"mssql"
|
|
1664
|
-
]),
|
|
1664
|
+
]), ei = {
|
|
1665
1665
|
ops: [],
|
|
1666
1666
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1667
1667
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1668
|
-
},
|
|
1669
|
-
if (i === void 0 ||
|
|
1670
|
-
let a = t.added.filter((e) =>
|
|
1671
|
-
if (a.length === 0) return
|
|
1668
|
+
}, ti = (e) => !e.unique && !e.expression && e.where === void 0 && (e.kind === void 0 || e.kind === "btree"), ni = (e, t, n, r, i) => {
|
|
1669
|
+
if (i === void 0 || !$r.has(i)) return ei;
|
|
1670
|
+
let a = t.added.filter((e) => ti(e) && !r.has(e.name));
|
|
1671
|
+
if (a.length === 0) return ei;
|
|
1672
1672
|
let o = (e) => e.columns.map((e) => n.get(e) ?? e).join("\0"), s = (e) => e.columns.join("\0"), c = [], l = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set();
|
|
1673
1673
|
for (let n of t.removed) {
|
|
1674
|
-
if (!
|
|
1674
|
+
if (!ti(n) || t.added.some((e) => e.name === n.name)) continue;
|
|
1675
1675
|
let r = o(n), i = a.filter((e) => !l.has(e.name) && s(e) === r);
|
|
1676
1676
|
if (i.length !== 1) continue;
|
|
1677
1677
|
let d = i[0];
|
|
@@ -1687,7 +1687,7 @@ BEGIN
|
|
|
1687
1687
|
consumedAddedNames: l,
|
|
1688
1688
|
consumedRemovedNames: u
|
|
1689
1689
|
};
|
|
1690
|
-
},
|
|
1690
|
+
}, ri = (e, t, n) => {
|
|
1691
1691
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1692
1692
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1693
1693
|
for (let c of e.tables) {
|
|
@@ -1727,12 +1727,12 @@ BEGIN
|
|
|
1727
1727
|
claimedOldNames: c,
|
|
1728
1728
|
refusals: o
|
|
1729
1729
|
};
|
|
1730
|
-
},
|
|
1730
|
+
}, ii = (e, t, n, r) => {
|
|
1731
1731
|
if (t === void 0) return {
|
|
1732
1732
|
live: e,
|
|
1733
1733
|
ops: []
|
|
1734
1734
|
};
|
|
1735
|
-
let i = r !== void 0 &&
|
|
1735
|
+
let i = r !== void 0 && $r.has(r), a = [], o = e.indexes.map((e) => {
|
|
1736
1736
|
if (!e.name.startsWith(t)) return e;
|
|
1737
1737
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1738
1738
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
@@ -1758,7 +1758,7 @@ BEGIN
|
|
|
1758
1758
|
},
|
|
1759
1759
|
ops: a
|
|
1760
1760
|
};
|
|
1761
|
-
},
|
|
1761
|
+
}, ai = (e) => {
|
|
1762
1762
|
let t = {
|
|
1763
1763
|
safe: 0,
|
|
1764
1764
|
needsDefault: 0,
|
|
@@ -1791,13 +1791,19 @@ BEGIN
|
|
|
1791
1791
|
case "multi-step": t.multiStep++;
|
|
1792
1792
|
}
|
|
1793
1793
|
return t;
|
|
1794
|
-
},
|
|
1794
|
+
}, oi = (e, t) => {
|
|
1795
|
+
let n = t.flatMap((e) => [e.table, e.targetTable]).flatMap((e) => {
|
|
1796
|
+
let t = w(e);
|
|
1797
|
+
return t === void 0 ? [] : [t.getTime()];
|
|
1798
|
+
}), r = new Date(Math.max(...n)), i = new Date(Date.UTC(r.getUTCFullYear(), r.getUTCMonth(), r.getUTCDate() + 1)).toISOString().slice(0, 10);
|
|
1799
|
+
return `${e.join("; ")}. Reclaim the snapshots first — \`voltro db gc-snapshots --before ${i}\` drops every snapshot older than that date, so run it with --dry-run to see the list — or, if a snapshot's data is still wanted, bring it back with \`voltro db restore-snapshot <plan-id>\` and declare it, so it converts in the same plan.`;
|
|
1800
|
+
}, si = (e, t, n, r) => {
|
|
1795
1801
|
let i = /* @__PURE__ */ new Map();
|
|
1796
1802
|
for (let a of e.tables) {
|
|
1797
1803
|
let e = t.get(a.name) ?? (n.has(a.name) ? t.get(n.get(a.name)) : void 0);
|
|
1798
1804
|
if (e === void 0) continue;
|
|
1799
|
-
let o = new Set(a.columns.filter(
|
|
1800
|
-
|
|
1805
|
+
let o = new Set(a.columns.filter(pr).map((e) => e.name));
|
|
1806
|
+
hr(e).filter((e) => o.has(e.column) && e.charset !== r).length > 0 && i.set(a.name, {
|
|
1801
1807
|
declared: a,
|
|
1802
1808
|
live: e
|
|
1803
1809
|
});
|
|
@@ -1822,39 +1828,43 @@ BEGIN
|
|
|
1822
1828
|
}
|
|
1823
1829
|
let o = [];
|
|
1824
1830
|
for (let [e, { declared: t, live: n }] of i) {
|
|
1825
|
-
let s = t.columns.filter(
|
|
1831
|
+
let s = t.columns.filter(pr).map((e) => e.name), c = new Map(n.columns.map((e) => [e.name, e])), l = [...new Set(s.flatMap((e) => {
|
|
1826
1832
|
let t = c.get(e);
|
|
1827
1833
|
return t?.charset === void 0 ? [] : [t.charset];
|
|
1828
|
-
}))].sort(), u = s.filter((e) => c.has(e)), d = a.filter((t) => t.table === e || t.targetTable === e), f = [], p = d.map((t) => {
|
|
1834
|
+
}))].sort(), u = s.filter((e) => c.has(e)), d = a.filter((t) => t.table === e || t.targetTable === e), f = [], p = [], m = d.map((t) => {
|
|
1829
1835
|
let n = t.table === e ? t.targetTable : t.table, a = n === e || i.has(n), o = t.table === e ? t.targetCharset : t.sourceCharset;
|
|
1830
|
-
!a && o !== void 0 && o !== r
|
|
1836
|
+
if (!a && o !== void 0 && o !== r) {
|
|
1837
|
+
let e = `${t.name} (${t.table}.${t.column} → ${t.targetTable}.${t.targetColumn})`;
|
|
1838
|
+
k(n) ? p.push(`${e}: "${n}" is a soft-drop snapshot, stored ${o}`) : f.push(`${e}: "${n}" stays ${o} — it is not a declared table, so the plan does not convert it`);
|
|
1839
|
+
}
|
|
1831
1840
|
let { sourceCharset: s, targetCharset: c, ...l } = t, u = a && n !== e && n.localeCompare(e) > 0 ? "peer" : "here";
|
|
1832
1841
|
return {
|
|
1833
1842
|
...l,
|
|
1834
1843
|
restore: u
|
|
1835
1844
|
};
|
|
1836
|
-
}),
|
|
1845
|
+
}), h = r === "utf8mb4", g = `table rewrite: ${u.length} string column${u.length === 1 ? "" : "s"} ${l.join("/")} → ${r}` + (m.length > 0 ? `; ${m.length} foreign key${m.length === 1 ? "" : "s"} dropped and re-created around it` : ""), _ = {
|
|
1837
1846
|
kind: "convert-charset",
|
|
1838
1847
|
table: e,
|
|
1839
1848
|
charset: r,
|
|
1840
1849
|
columns: u,
|
|
1841
1850
|
from: l,
|
|
1842
|
-
foreignKeys:
|
|
1851
|
+
foreignKeys: m
|
|
1843
1852
|
};
|
|
1844
|
-
if (f.length > 0) {
|
|
1845
|
-
|
|
1853
|
+
if (f.length > 0 || p.length > 0) {
|
|
1854
|
+
let t = [...f.length > 0 ? [`${f.join("; ")}. Declare that table so it converts in the same plan, convert it by hand first, or leave the store charset undeclared.`] : [], ...p.length > 0 ? [oi(p, d)] : []];
|
|
1855
|
+
o.push(R(_, "lossy", g, { fix: `converting "${e}" to ${r} would break a foreign key the plan cannot carry: ${t.join(" ")}` }));
|
|
1846
1856
|
continue;
|
|
1847
1857
|
}
|
|
1848
|
-
o.push(
|
|
1858
|
+
o.push(h ? R(_, "safe", g) : R(_, "lossy", g, { fix: `${e}: narrowing to ${r} can refuse or truncate 4-byte characters the columns already hold. Declare charset: 'utf8mb4' instead, or — after checking the data — allow it with the destructive opt-in (VOLTRO_DESTRUCTIVE_OK=1).` }));
|
|
1849
1859
|
}
|
|
1850
1860
|
return o;
|
|
1851
|
-
},
|
|
1852
|
-
let t =
|
|
1861
|
+
}, ci = (e) => {
|
|
1862
|
+
let t = Tr(e.declared, e.dialect, { charset: e.charset }), n = Mr(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? Gr, a = [], o = ri(t, r, n);
|
|
1853
1863
|
a.push(...o.ops);
|
|
1854
1864
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1855
|
-
a.push(
|
|
1865
|
+
a.push(Ur(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1856
1866
|
for (let t of e.columns) {
|
|
1857
|
-
let n =
|
|
1867
|
+
let n = Lr(e.name, t);
|
|
1858
1868
|
n && a.push(n);
|
|
1859
1869
|
}
|
|
1860
1870
|
}
|
|
@@ -1864,7 +1874,7 @@ BEGIN
|
|
|
1864
1874
|
c.push(t.name);
|
|
1865
1875
|
continue;
|
|
1866
1876
|
}
|
|
1867
|
-
if (
|
|
1877
|
+
if (ge(t.name)) {
|
|
1868
1878
|
c.push(t.name);
|
|
1869
1879
|
continue;
|
|
1870
1880
|
}
|
|
@@ -1876,26 +1886,26 @@ BEGIN
|
|
|
1876
1886
|
c.push(t.name);
|
|
1877
1887
|
continue;
|
|
1878
1888
|
}
|
|
1879
|
-
a.push(
|
|
1889
|
+
a.push(Wr(t.name));
|
|
1880
1890
|
}
|
|
1881
1891
|
for (let s of t.tables) {
|
|
1882
1892
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1883
1893
|
if (!c) continue;
|
|
1884
|
-
let l =
|
|
1894
|
+
let l = ii(c, t, s.name, e.dialect);
|
|
1885
1895
|
a.push(...l.ops);
|
|
1886
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1896
|
+
let u = l.live, d = n.get(s.name), f = zr(s, u, e.dialect), p = Br(s, u, e.dialect), m = Qr(d.table, d.columnDefs, f);
|
|
1887
1897
|
a.push(...m.ops);
|
|
1888
1898
|
for (let { op: t } of m.ops) {
|
|
1889
1899
|
if (t.kind !== "rename-column") continue;
|
|
1890
1900
|
let n = s.columns.find((e) => e.name === t.to), r = u.columns.find((e) => e.name === t.from);
|
|
1891
|
-
n && r && a.push(...
|
|
1901
|
+
n && r && a.push(...Xr(s.name, n, {
|
|
1892
1902
|
...r,
|
|
1893
1903
|
name: t.to
|
|
1894
1904
|
}, e.dialect, u.rowCount, i));
|
|
1895
1905
|
}
|
|
1896
1906
|
for (let e of f.removed) {
|
|
1897
1907
|
if (m.consumedRemovedNames.has(e.name) || k(e.name)) continue;
|
|
1898
|
-
let t = d.columnDefs[e.name], n =
|
|
1908
|
+
let t = d.columnDefs[e.name], n = Hr(s.name, e, t);
|
|
1899
1909
|
e.references !== void 0 && a.push({
|
|
1900
1910
|
...R({
|
|
1901
1911
|
kind: "drop-foreign-key",
|
|
@@ -1909,24 +1919,24 @@ BEGIN
|
|
|
1909
1919
|
for (let e of f.added) {
|
|
1910
1920
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1911
1921
|
let t = d.columnDefs[e.name];
|
|
1912
|
-
a.push(
|
|
1913
|
-
let n =
|
|
1914
|
-
n && a.push(n), a.push(...
|
|
1922
|
+
a.push(Vr(s.name, e, t));
|
|
1923
|
+
let n = Lr(s.name, e);
|
|
1924
|
+
n && a.push(n), a.push(...Zr(s.name, e));
|
|
1915
1925
|
}
|
|
1916
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1926
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = ni(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1917
1927
|
a.push(...g.ops);
|
|
1918
|
-
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(
|
|
1919
|
-
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(
|
|
1920
|
-
for (let { declared: t, live: n } of f.changed) a.push(...
|
|
1928
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(Kr(s.name, e, u.rowCount, i));
|
|
1929
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(qr(s.name, e));
|
|
1930
|
+
for (let { declared: t, live: n } of f.changed) a.push(...Xr(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1921
1931
|
}
|
|
1922
|
-
e.charset !== void 0 && a.push(...
|
|
1932
|
+
e.charset !== void 0 && a.push(...si(t, r, o.renamedInto, e.charset));
|
|
1923
1933
|
let l = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), u = new Map(t.tables.map((e) => [e.name, e])), d = (e) => {
|
|
1924
1934
|
let t = u.get(e);
|
|
1925
1935
|
return t ? t.columns.flatMap((e) => e.references && l.has(e.references.table) ? [{
|
|
1926
1936
|
column: e.name,
|
|
1927
1937
|
target: e.references.table
|
|
1928
1938
|
}] : []) : [];
|
|
1929
|
-
}, f =
|
|
1939
|
+
}, f = Ve([...l], d), p = [];
|
|
1930
1940
|
for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) t.references && f.has(M(e.name, t.name)) && p.push(R({
|
|
1931
1941
|
kind: "add-foreign-key",
|
|
1932
1942
|
table: e.name,
|
|
@@ -2010,25 +2020,25 @@ BEGIN
|
|
|
2010
2020
|
operations: x,
|
|
2011
2021
|
fromFingerprint: L(e.live),
|
|
2012
2022
|
toFingerprint: L(t),
|
|
2013
|
-
summary:
|
|
2023
|
+
summary: ai(x),
|
|
2014
2024
|
fingerprintDivergence: {
|
|
2015
2025
|
outsideDiff: c,
|
|
2016
2026
|
diffEquivalent: C
|
|
2017
2027
|
}
|
|
2018
2028
|
};
|
|
2019
|
-
}, z = "_voltro_deploys",
|
|
2020
|
-
id:
|
|
2021
|
-
status:
|
|
2022
|
-
dialect:
|
|
2023
|
-
appliedBy:
|
|
2024
|
-
startedAt:
|
|
2025
|
-
baseline:
|
|
2026
|
-
report:
|
|
2027
|
-
}),
|
|
2028
|
-
VALUES (${t.id}, ${"running"}, ${t.dialect}, ${t.appliedBy}, ${(/* @__PURE__ */ new Date()).toISOString()}, ${t.baseline}, ${null})`.pipe(A.asVoid),
|
|
2029
|
+
}, z = "_voltro_deploys", li = l(z, {
|
|
2030
|
+
id: ne({ prefix: "dpl" }),
|
|
2031
|
+
status: E(),
|
|
2032
|
+
dialect: E(),
|
|
2033
|
+
appliedBy: E(),
|
|
2034
|
+
startedAt: E(),
|
|
2035
|
+
baseline: E(),
|
|
2036
|
+
report: E().nullable()
|
|
2037
|
+
}), ui = (e, t) => e`INSERT INTO ${e(z)} (${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")})
|
|
2038
|
+
VALUES (${t.id}, ${"running"}, ${t.dialect}, ${t.appliedBy}, ${(/* @__PURE__ */ new Date()).toISOString()}, ${t.baseline}, ${null})`.pipe(A.asVoid), di = (e, t) => e`DELETE FROM ${e(z)} WHERE ${e("id")} = ${t}`.pipe(A.asVoid), fi = (e, t, n) => e`UPDATE ${e(z)} SET ${e("status")} = ${"failed"}, ${e("report")} = ${n} WHERE ${e("id")} = ${t}`.pipe(A.asVoid), pi = (e) => e`SELECT ${e("id")}, ${e("status")}, ${e("dialect")}, ${e("appliedBy")}, ${e("startedAt")}, ${e("baseline")}, ${e("report")} FROM ${e(z)}`.pipe(A.map((e) => e.map((e) => ({
|
|
2029
2039
|
...e,
|
|
2030
2040
|
startedAt: String(e.startedAt)
|
|
2031
|
-
}))), A.catchAll(() => A.succeed([]))),
|
|
2041
|
+
}))), A.catchAll(() => A.succeed([]))), mi = (e, t) => {
|
|
2032
2042
|
let n = (e.match(/'(?:''|[^'])*'|"(?:""|[^"])*"|::|[A-Za-z_][A-Za-z_0-9$]*|[^\s]/g) ?? []).filter((e) => e !== "(" && e !== ")"), r = 0, i = (e) => n[r]?.toLowerCase() === e && (r++, !0);
|
|
2033
2043
|
if (!i("check")) return null;
|
|
2034
2044
|
let a = n[r++];
|
|
@@ -2043,7 +2053,7 @@ BEGIN
|
|
|
2043
2053
|
if (e === void 0 || !/^'(?:''|[^'])*'$/.test(e) || (c.push(e.slice(1, -1).replace(/''/g, "'")), !o())) return null;
|
|
2044
2054
|
} while (s && i(","));
|
|
2045
2055
|
return s && (!i("]") || i("::") && (!i("text") || !i("[") || !i("]"))) ? null : r === n.length ? c : null;
|
|
2046
|
-
},
|
|
2056
|
+
}, hi = (e) => {
|
|
2047
2057
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
2048
2058
|
if (!t) return null;
|
|
2049
2059
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -2051,7 +2061,7 @@ BEGIN
|
|
|
2051
2061
|
column: t[1],
|
|
2052
2062
|
values: n
|
|
2053
2063
|
};
|
|
2054
|
-
},
|
|
2064
|
+
}, gi = (e, t) => {
|
|
2055
2065
|
if (t === "vector" || t === "halfvec") return "vector";
|
|
2056
2066
|
switch (e) {
|
|
2057
2067
|
case "text":
|
|
@@ -2079,7 +2089,7 @@ BEGIN
|
|
|
2079
2089
|
case "USER-DEFINED": return "text";
|
|
2080
2090
|
default: return "text";
|
|
2081
2091
|
}
|
|
2082
|
-
},
|
|
2092
|
+
}, _i = {
|
|
2083
2093
|
_text: "text",
|
|
2084
2094
|
_varchar: "text",
|
|
2085
2095
|
_uuid: "text",
|
|
@@ -2095,10 +2105,10 @@ BEGIN
|
|
|
2095
2105
|
_date: "date",
|
|
2096
2106
|
_jsonb: "json",
|
|
2097
2107
|
_json: "json"
|
|
2098
|
-
},
|
|
2108
|
+
}, vi = (e) => e === void 0 ? void 0 : _i[e], yi = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
2099
2109
|
expr: e,
|
|
2100
2110
|
stored: t
|
|
2101
|
-
} },
|
|
2111
|
+
} }, bi = (e) => {
|
|
2102
2112
|
switch (e.toUpperCase()) {
|
|
2103
2113
|
case "CASCADE": return "cascade";
|
|
2104
2114
|
case "RESTRICT": return "restrict";
|
|
@@ -2106,25 +2116,25 @@ BEGIN
|
|
|
2106
2116
|
case "SET DEFAULT": return "noAction";
|
|
2107
2117
|
default: return "noAction";
|
|
2108
2118
|
}
|
|
2109
|
-
},
|
|
2119
|
+
}, xi = (e, t) => {
|
|
2110
2120
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
2111
2121
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
2112
|
-
},
|
|
2122
|
+
}, Si = () => xi(process.env.VOLTRO_INTROSPECT_BATCH, 20), Ci = 300, wi = () => {
|
|
2113
2123
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
2114
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
2115
|
-
},
|
|
2124
|
+
return e !== void 0 && e.trim() === "0" ? 0 : xi(e, 3e4);
|
|
2125
|
+
}, Ti = (e, t) => {
|
|
2116
2126
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
2117
2127
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
2118
2128
|
return r;
|
|
2119
|
-
},
|
|
2120
|
-
let t =
|
|
2129
|
+
}, Ei = (e) => {
|
|
2130
|
+
let t = wi(), n = A.gen(function* () {
|
|
2121
2131
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
2122
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
2132
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Si(), a = (e, t) => A.gen(function* () {
|
|
2123
2133
|
let r = [];
|
|
2124
|
-
for (let a of
|
|
2134
|
+
for (let a of Ti(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
2125
2135
|
return r;
|
|
2126
2136
|
}), o = [];
|
|
2127
|
-
for (let t = 0;; t +=
|
|
2137
|
+
for (let t = 0;; t += Ci) {
|
|
2128
2138
|
let n = yield* e`
|
|
2129
2139
|
SELECT c.relname AS table_name,
|
|
2130
2140
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -2132,9 +2142,9 @@ BEGIN
|
|
|
2132
2142
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
2133
2143
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
2134
2144
|
ORDER BY c.relname
|
|
2135
|
-
LIMIT ${r(
|
|
2145
|
+
LIMIT ${r(Ci)} OFFSET ${r(t)}
|
|
2136
2146
|
`;
|
|
2137
|
-
if (o.push(...n), n.length <
|
|
2147
|
+
if (o.push(...n), n.length < Ci) break;
|
|
2138
2148
|
}
|
|
2139
2149
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
2140
2150
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -2197,7 +2207,7 @@ BEGIN
|
|
|
2197
2207
|
srid: e.srid
|
|
2198
2208
|
}])), y = /* @__PURE__ */ new Map();
|
|
2199
2209
|
for (let e of p) {
|
|
2200
|
-
let t =
|
|
2210
|
+
let t = mi(e.def, e.column_name);
|
|
2201
2211
|
t !== null && y.set(`${e.table_name}.${e.column_name}`, t);
|
|
2202
2212
|
}
|
|
2203
2213
|
let b = yield* a(l, (t) => e`
|
|
@@ -2312,14 +2322,14 @@ BEGIN
|
|
|
2312
2322
|
let n = t.get(e.index_name);
|
|
2313
2323
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
2314
2324
|
}
|
|
2315
|
-
let
|
|
2325
|
+
let te = [];
|
|
2316
2326
|
for (let e of c) {
|
|
2317
2327
|
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 = w.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = E.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) => {
|
|
2318
|
-
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" :
|
|
2328
|
+
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" : gi(t.data_type, t.udt_name), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : c, d = a ? {
|
|
2319
2329
|
table: a.target_table,
|
|
2320
2330
|
column: a.target_column,
|
|
2321
|
-
onDelete:
|
|
2322
|
-
onUpdate:
|
|
2331
|
+
onDelete: bi(a.delete_rule),
|
|
2332
|
+
onUpdate: bi(a.update_rule),
|
|
2323
2333
|
constraintName: a.constraint_name
|
|
2324
2334
|
} : void 0, f = y.get(`${e.table_name}.${t.column_name}`);
|
|
2325
2335
|
return {
|
|
@@ -2329,14 +2339,14 @@ BEGIN
|
|
|
2329
2339
|
enumName: t.udt_name,
|
|
2330
2340
|
enumValues: h.get(t.udt_name) ?? []
|
|
2331
2341
|
} : {},
|
|
2332
|
-
...u === "array" &&
|
|
2342
|
+
...u === "array" && vi(t.udt_name) !== void 0 ? { arrayElement: vi(t.udt_name) } : {},
|
|
2333
2343
|
...v.has(`${e.table_name}.${t.column_name}`) ? { spatial: v.get(`${e.table_name}.${t.column_name}`) } : {},
|
|
2334
|
-
...l ? { idStorage:
|
|
2344
|
+
...l ? { idStorage: Vn(c) } : {},
|
|
2335
2345
|
...u === "vector" ? {
|
|
2336
2346
|
vectorPrecision: t.udt_name === "halfvec" ? "half" : "float32",
|
|
2337
2347
|
...t.type_modifier !== void 0 && t.type_modifier > 0 ? { vectorDim: t.type_modifier } : {}
|
|
2338
2348
|
} : {},
|
|
2339
|
-
...
|
|
2349
|
+
...Ri(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ri(t.data_type, t.character_maximum_length) },
|
|
2340
2350
|
...c === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2341
2351
|
precision: t.numeric_precision,
|
|
2342
2352
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2346,9 +2356,9 @@ BEGIN
|
|
|
2346
2356
|
hasDefault: t.column_default !== null,
|
|
2347
2357
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
2348
2358
|
...d ? { references: d } : {},
|
|
2349
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2359
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(gi(t.data_type, t.udt_name)) ? "numeric" : "text" } : {},
|
|
2350
2360
|
...f ? { oneOf: f } : {},
|
|
2351
|
-
...
|
|
2361
|
+
...yi(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
2352
2362
|
};
|
|
2353
2363
|
}), l = [], u = D.get(e.table_name);
|
|
2354
2364
|
if (u) for (let [t, n] of u) {
|
|
@@ -2367,7 +2377,7 @@ BEGIN
|
|
|
2367
2377
|
table: e.table_name,
|
|
2368
2378
|
columns: i.map((e) => e.column_name),
|
|
2369
2379
|
unique: n[0]?.is_unique ?? !1,
|
|
2370
|
-
...
|
|
2380
|
+
...Me(o?.access_method, o?.access_method === "hnsw" ? { hnsw: {
|
|
2371
2381
|
opclass: o.operator_class,
|
|
2372
2382
|
m: c.get("m") ?? 16,
|
|
2373
2383
|
efConstruction: c.get("ef_construction") ?? 64
|
|
@@ -2385,20 +2395,20 @@ BEGIN
|
|
|
2385
2395
|
unique: !0
|
|
2386
2396
|
});
|
|
2387
2397
|
let d = Number(e.row_count ?? 0);
|
|
2388
|
-
|
|
2398
|
+
te.push({
|
|
2389
2399
|
name: e.table_name,
|
|
2390
2400
|
columns: c,
|
|
2391
2401
|
indexes: l,
|
|
2392
2402
|
...d > 0 ? { rowCount: d } : {}
|
|
2393
2403
|
});
|
|
2394
2404
|
}
|
|
2395
|
-
return { tables:
|
|
2405
|
+
return { tables: te };
|
|
2396
2406
|
});
|
|
2397
2407
|
return (t > 0 ? e.withTransaction(n) : n).pipe(A.catchAll((e) => {
|
|
2398
2408
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
2399
2409
|
return n.includes("statement timeout") || n.includes("57014") ? A.die(/* @__PURE__ */ Error(`schema introspection exceeded VOLTRO_INTROSPECT_TIMEOUT_MS (${t}ms) — the schema is very large / FK-dense or the database is slow. Raise VOLTRO_INTROSPECT_TIMEOUT_MS, set it to 0 to disable the ceiling, or use DB_DIRECT_URL for a non-pooler connection.`)) : A.fail(e);
|
|
2400
2410
|
}));
|
|
2401
|
-
},
|
|
2411
|
+
}, Di = (e, t) => {
|
|
2402
2412
|
switch (e.toLowerCase()) {
|
|
2403
2413
|
case "varchar":
|
|
2404
2414
|
case "char":
|
|
@@ -2430,22 +2440,22 @@ BEGIN
|
|
|
2430
2440
|
case "json": return "json";
|
|
2431
2441
|
default: return "text";
|
|
2432
2442
|
}
|
|
2433
|
-
},
|
|
2443
|
+
}, Oi = (e) => e.map((e) => {
|
|
2434
2444
|
let t = e, n = {};
|
|
2435
2445
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
2436
2446
|
return n;
|
|
2437
|
-
}),
|
|
2438
|
-
let t =
|
|
2447
|
+
}), ki = (e) => A.gen(function* () {
|
|
2448
|
+
let t = Oi(yield* e`
|
|
2439
2449
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
2440
2450
|
FROM information_schema.tables
|
|
2441
2451
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
2442
|
-
ORDER BY table_name`), n =
|
|
2452
|
+
ORDER BY table_name`), n = Oi(yield* e`
|
|
2443
2453
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
2444
2454
|
character_maximum_length, numeric_precision, numeric_scale,
|
|
2445
2455
|
generation_expression, extra, character_set_name
|
|
2446
2456
|
FROM information_schema.columns
|
|
2447
2457
|
WHERE table_schema = DATABASE()
|
|
2448
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
2458
|
+
ORDER BY table_name, ordinal_position`), r = Oi(yield* e`
|
|
2449
2459
|
SELECT k.table_name AS source_table,
|
|
2450
2460
|
k.column_name AS source_column,
|
|
2451
2461
|
k.referenced_table_name AS target_table,
|
|
@@ -2456,7 +2466,7 @@ BEGIN
|
|
|
2456
2466
|
JOIN information_schema.referential_constraints r
|
|
2457
2467
|
ON k.constraint_name = r.constraint_name
|
|
2458
2468
|
AND k.table_schema = r.constraint_schema
|
|
2459
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
2469
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = Oi(yield* e`
|
|
2460
2470
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
2461
2471
|
FROM information_schema.statistics
|
|
2462
2472
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -2469,14 +2479,14 @@ BEGIN
|
|
|
2469
2479
|
JOIN information_schema.table_constraints tc
|
|
2470
2480
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2471
2481
|
AND tc.constraint_name = cc.constraint_name
|
|
2472
|
-
WHERE cc.constraint_schema = DATABASE()`.unprepared, s =
|
|
2482
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared, s = Oi(yield* a.pipe(A.orElse(() => o), A.orElseSucceed(() => []))), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map();
|
|
2473
2483
|
for (let e of s) {
|
|
2474
2484
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
2475
2485
|
if (t) {
|
|
2476
2486
|
c.add(`${e.table_name}.${t[1]}`);
|
|
2477
2487
|
continue;
|
|
2478
2488
|
}
|
|
2479
|
-
let n =
|
|
2489
|
+
let n = hi(e.check_clause);
|
|
2480
2490
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
2481
2491
|
}
|
|
2482
2492
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -2499,20 +2509,20 @@ BEGIN
|
|
|
2499
2509
|
let t = u.get(e.table_name) ?? [], n = d.get(e.table_name) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = t.filter((e) => e.column_key === "PRI").map((e) => e.column_name), a = /* @__PURE__ */ new Set(), o = f.get(e.table_name);
|
|
2500
2510
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
2501
2511
|
let s = t.map((t) => {
|
|
2502
|
-
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" :
|
|
2512
|
+
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" : Di(t.data_type, t.column_type), u = !o && n && t.column_name === "id", d = o ? "reference" : u ? "id" : s, f = o ? {
|
|
2503
2513
|
table: o.target_table,
|
|
2504
2514
|
column: o.target_column,
|
|
2505
|
-
onDelete:
|
|
2506
|
-
onUpdate:
|
|
2515
|
+
onDelete: bi(o.delete_rule),
|
|
2516
|
+
onUpdate: bi(o.update_rule),
|
|
2507
2517
|
constraintName: o.constraint_name
|
|
2508
2518
|
} : 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;
|
|
2509
2519
|
return {
|
|
2510
2520
|
name: t.column_name,
|
|
2511
2521
|
type: d,
|
|
2512
|
-
...u ? { idStorage:
|
|
2522
|
+
...u ? { idStorage: Vn(s) } : {},
|
|
2513
2523
|
...d === "enum" && g !== void 0 ? { enumValues: g } : {},
|
|
2514
2524
|
nullable: t.is_nullable === "YES",
|
|
2515
|
-
...
|
|
2525
|
+
...Ri(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ri(t.data_type, t.character_maximum_length) },
|
|
2516
2526
|
...s === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2517
2527
|
precision: t.numeric_precision,
|
|
2518
2528
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2521,9 +2531,9 @@ BEGIN
|
|
|
2521
2531
|
hasDefault: m !== null,
|
|
2522
2532
|
...m === null ? {} : { defaultValue: m },
|
|
2523
2533
|
...f ? { references: f } : {},
|
|
2524
|
-
...o ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2534
|
+
...o ? { referenceStorage: ["integer", "bigint"].includes(Di(t.data_type, t.column_type)) ? "numeric" : "text" } : {},
|
|
2525
2535
|
...h ? { oneOf: h } : {},
|
|
2526
|
-
...
|
|
2536
|
+
...yi(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {},
|
|
2527
2537
|
...t.character_set_name !== null && t.character_set_name !== void 0 && d !== "json" ? { charset: t.character_set_name } : {}
|
|
2528
2538
|
};
|
|
2529
2539
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
@@ -2551,10 +2561,10 @@ BEGIN
|
|
|
2551
2561
|
});
|
|
2552
2562
|
}
|
|
2553
2563
|
return { tables: p };
|
|
2554
|
-
}),
|
|
2564
|
+
}), Ai = (e) => {
|
|
2555
2565
|
let t = e.toUpperCase();
|
|
2556
2566
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
2557
|
-
},
|
|
2567
|
+
}, ji = (e) => e === 1 || e === !0, Mi = (e) => A.gen(function* () {
|
|
2558
2568
|
let t = yield* e`
|
|
2559
2569
|
SELECT name, sql FROM sqlite_master
|
|
2560
2570
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -2568,41 +2578,41 @@ BEGIN
|
|
|
2568
2578
|
let o = yield* e.unsafe(`PRAGMA table_xinfo(${n(i)})`), s = yield* e.unsafe(`PRAGMA foreign_key_list(${n(i)})`), c = yield* e.unsafe(`PRAGMA index_list(${n(i)})`), l = new Map(s.map((e) => [e.from, e])), u = o.filter((e) => e.pk > 0).sort((e, t) => e.pk - t.pk).map((e) => e.name), d = new Map(o.map((e) => [e.name.toLowerCase(), e.name])), f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set();
|
|
2569
2579
|
for (let t of c) {
|
|
2570
2580
|
let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null).map((e) => d.get(e.toLowerCase()) ?? e);
|
|
2571
|
-
if (f.set(t.name, r), t.partial !== void 0 &&
|
|
2572
|
-
let n =
|
|
2581
|
+
if (f.set(t.name, r), t.partial !== void 0 && ji(t.partial)) {
|
|
2582
|
+
let n = Ln((yield* e`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${t.name}`)[0]?.sql ?? "");
|
|
2573
2583
|
n !== void 0 && p.set(t.name, n);
|
|
2574
2584
|
}
|
|
2575
|
-
!p.has(t.name) &&
|
|
2585
|
+
!p.has(t.name) && ji(t.unique) && r.length === 1 && m.add(r[0]);
|
|
2576
2586
|
}
|
|
2577
2587
|
let h = o.map((e) => {
|
|
2578
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i =
|
|
2588
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = Ai(e.type), a = !r && n && e.name === "id", o = r ? "reference" : a ? "id" : i, s = r ? {
|
|
2579
2589
|
table: r.table,
|
|
2580
2590
|
column: r.to,
|
|
2581
|
-
onDelete:
|
|
2582
|
-
onUpdate:
|
|
2591
|
+
onDelete: bi(r.on_delete),
|
|
2592
|
+
onUpdate: bi(r.on_update)
|
|
2583
2593
|
} : void 0, c = t.get(e.name);
|
|
2584
2594
|
return {
|
|
2585
2595
|
name: e.name,
|
|
2586
2596
|
type: o,
|
|
2587
|
-
...a ? { idStorage:
|
|
2597
|
+
...a ? { idStorage: Vn(i) } : {},
|
|
2588
2598
|
nullable: e.notnull === 0,
|
|
2589
2599
|
unique: m.has(e.name) || n && e.name === "id",
|
|
2590
2600
|
hasDefault: e.dflt_value !== null,
|
|
2591
2601
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
2592
2602
|
...s ? { references: s } : {},
|
|
2593
|
-
...r ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2603
|
+
...r ? { referenceStorage: ["integer", "bigint"].includes(Ai(e.type)) ? "numeric" : "text" } : {},
|
|
2594
2604
|
...c ? { oneOf: c } : {},
|
|
2595
|
-
...
|
|
2605
|
+
...yi(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
2596
2606
|
};
|
|
2597
2607
|
}), g = new Set(s.map((e) => e.from)), _ = [];
|
|
2598
2608
|
for (let e of c) {
|
|
2599
2609
|
if (e.origin === "pk") continue;
|
|
2600
2610
|
let t = f.get(e.name) ?? [], n = p.get(e.name);
|
|
2601
|
-
n === void 0 && t.length === 1 &&
|
|
2611
|
+
n === void 0 && t.length === 1 && ji(e.unique) || (n !== void 0 || t.length !== 1 || ji(e.unique) || !g.has(t[0]) || e.name.toLowerCase() === `${i}_${t[0]}_idx`.toLowerCase()) && _.push({
|
|
2602
2612
|
name: e.name,
|
|
2603
2613
|
table: i,
|
|
2604
2614
|
columns: t,
|
|
2605
|
-
unique:
|
|
2615
|
+
unique: ji(e.unique),
|
|
2606
2616
|
...n === void 0 ? {} : { where: n }
|
|
2607
2617
|
});
|
|
2608
2618
|
}
|
|
@@ -2618,7 +2628,7 @@ BEGIN
|
|
|
2618
2628
|
});
|
|
2619
2629
|
}
|
|
2620
2630
|
return { tables: r };
|
|
2621
|
-
}),
|
|
2631
|
+
}), Ni = (e) => {
|
|
2622
2632
|
switch (e.toLowerCase()) {
|
|
2623
2633
|
case "int":
|
|
2624
2634
|
case "smallint":
|
|
@@ -2640,7 +2650,7 @@ BEGIN
|
|
|
2640
2650
|
case "image": return "bytes";
|
|
2641
2651
|
default: return "text";
|
|
2642
2652
|
}
|
|
2643
|
-
},
|
|
2653
|
+
}, B = (e) => e === !0 || e === 1, Pi = (e) => A.gen(function* () {
|
|
2644
2654
|
let t = yield* e`
|
|
2645
2655
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2646
2656
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -2680,7 +2690,7 @@ BEGIN
|
|
|
2680
2690
|
JOIN sys.tables t ON t.object_id = cc.parent_object_id
|
|
2681
2691
|
LEFT JOIN sys.columns c ON c.object_id = cc.parent_object_id AND c.column_id = cc.parent_column_id`, c = /* @__PURE__ */ new Map();
|
|
2682
2692
|
for (let e of s) {
|
|
2683
|
-
let t =
|
|
2693
|
+
let t = hi(e.def);
|
|
2684
2694
|
t?.column === e.column_name && c.set(`${e.table_name}.${e.column_name}`, t.values);
|
|
2685
2695
|
}
|
|
2686
2696
|
let l = /* @__PURE__ */ new Map();
|
|
@@ -2705,32 +2715,32 @@ BEGIN
|
|
|
2705
2715
|
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();
|
|
2706
2716
|
if (o) for (let [, e] of o) {
|
|
2707
2717
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2708
|
-
if (
|
|
2709
|
-
else t[0].predicate == null &&
|
|
2718
|
+
if (B(t[0].is_primary)) for (let e of t) p.push(e.column_name);
|
|
2719
|
+
else t[0].predicate == null && B(t[0].is_unique) && t.length === 1 && m.add(t[0].column_name);
|
|
2710
2720
|
}
|
|
2711
2721
|
let h = t.map((t) => {
|
|
2712
|
-
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o =
|
|
2722
|
+
let n = p.length === 1 && p[0] === t.column_name, a = r.get(t.column_name), o = Ni(t.data_type), l = !a && n && t.column_name === "id", u = a ? "reference" : l ? "id" : o, d = a ? {
|
|
2713
2723
|
table: a.target_table,
|
|
2714
2724
|
column: a.target_column,
|
|
2715
|
-
onDelete:
|
|
2716
|
-
onUpdate:
|
|
2725
|
+
onDelete: Fi(a.delete_rule),
|
|
2726
|
+
onUpdate: Fi(a.update_rule),
|
|
2717
2727
|
constraintName: a.constraint_name
|
|
2718
|
-
} : void 0, f = t.column_default === null ? null :
|
|
2728
|
+
} : void 0, f = t.column_default === null ? null : Ii(t.column_default), h = c.get(`${e}.${t.column_name}`), g = s.flatMap((n) => {
|
|
2719
2729
|
if (n.table_name !== e || n.column_name !== null && n.column_name !== t.column_name) return [];
|
|
2720
|
-
let r =
|
|
2730
|
+
let r = jt(t.column_name, n.def);
|
|
2721
2731
|
return r ? [{
|
|
2722
2732
|
name: n.constraint_name,
|
|
2723
2733
|
validation: r,
|
|
2724
|
-
enabled: !
|
|
2725
|
-
trusted: !
|
|
2734
|
+
enabled: !B(n.is_disabled),
|
|
2735
|
+
trusted: !B(n.is_not_trusted)
|
|
2726
2736
|
}] : [];
|
|
2727
|
-
}).sort((e, t) => e.name.localeCompare(t.name)), _ =
|
|
2737
|
+
}).sort((e, t) => e.name.localeCompare(t.name)), _ = Mt(g);
|
|
2728
2738
|
return {
|
|
2729
2739
|
name: t.column_name,
|
|
2730
2740
|
type: u,
|
|
2731
|
-
...l ? { idStorage:
|
|
2741
|
+
...l ? { idStorage: Vn(o) } : {},
|
|
2732
2742
|
nullable: t.is_nullable === "YES",
|
|
2733
|
-
...
|
|
2743
|
+
...Ri(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: Ri(t.data_type, t.character_maximum_length) },
|
|
2734
2744
|
...o === "decimal" && typeof t.numeric_precision == "number" ? {
|
|
2735
2745
|
precision: t.numeric_precision,
|
|
2736
2746
|
...typeof t.numeric_scale == "number" ? { scale: t.numeric_scale } : {}
|
|
@@ -2739,22 +2749,22 @@ BEGIN
|
|
|
2739
2749
|
hasDefault: f !== null,
|
|
2740
2750
|
...f === null ? {} : { defaultValue: f },
|
|
2741
2751
|
...d ? { references: d } : {},
|
|
2742
|
-
...a ? { referenceStorage: ["integer", "bigint"].includes(
|
|
2752
|
+
...a ? { referenceStorage: ["integer", "bigint"].includes(Ni(t.data_type)) ? "numeric" : "text" } : {},
|
|
2743
2753
|
...h ? { oneOf: h } : {},
|
|
2744
2754
|
...g.length > 0 ? { jsonChecks: g } : {},
|
|
2745
2755
|
..._ ? { jsonValidation: _ } : {},
|
|
2746
|
-
...
|
|
2756
|
+
...yi(i.get(`${e}.${t.column_name}`)?.definition ?? null, B(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2747
2757
|
};
|
|
2748
2758
|
}), g = [];
|
|
2749
2759
|
if (o) for (let [t, n] of o) {
|
|
2750
2760
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2751
|
-
if (
|
|
2761
|
+
if (B(r[0].is_primary)) continue;
|
|
2752
2762
|
let i = r[0].predicate ?? void 0;
|
|
2753
|
-
i === void 0 && r.length === 1 &&
|
|
2763
|
+
i === void 0 && r.length === 1 && B(r[0].is_unique) || (i !== void 0 || r.length !== 1 || B(r[0].is_unique) || !a.has(r[0].column_name) || t === `${e}_${r[0].column_name}_idx`) && g.push({
|
|
2754
2764
|
name: t,
|
|
2755
2765
|
table: e,
|
|
2756
2766
|
columns: r.map((e) => e.column_name),
|
|
2757
|
-
unique:
|
|
2767
|
+
unique: B(r[0].is_unique),
|
|
2758
2768
|
...i === void 0 ? {} : { where: i }
|
|
2759
2769
|
});
|
|
2760
2770
|
}
|
|
@@ -2770,81 +2780,81 @@ BEGIN
|
|
|
2770
2780
|
});
|
|
2771
2781
|
}
|
|
2772
2782
|
return { tables: f };
|
|
2773
|
-
}),
|
|
2783
|
+
}), Fi = (e) => {
|
|
2774
2784
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2775
2785
|
case "CASCADE": return "cascade";
|
|
2776
2786
|
case "SET NULL": return "setNull";
|
|
2777
2787
|
case "SET DEFAULT": return "noAction";
|
|
2778
2788
|
default: return "noAction";
|
|
2779
2789
|
}
|
|
2780
|
-
},
|
|
2790
|
+
}, Ii = (e) => {
|
|
2781
2791
|
let t = e.trim();
|
|
2782
2792
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2783
2793
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2784
|
-
},
|
|
2794
|
+
}, Li = /* @__PURE__ */ new Set([
|
|
2785
2795
|
"character varying",
|
|
2786
2796
|
"varchar",
|
|
2787
2797
|
"nvarchar",
|
|
2788
2798
|
"char",
|
|
2789
2799
|
"character",
|
|
2790
2800
|
"nchar"
|
|
2791
|
-
]),
|
|
2792
|
-
if (!
|
|
2801
|
+
]), Ri = (e, t) => {
|
|
2802
|
+
if (!Li.has(e.toLowerCase())) return;
|
|
2793
2803
|
let n = Number(t);
|
|
2794
2804
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2795
|
-
},
|
|
2796
|
-
mysql: () =>
|
|
2797
|
-
mssql: () =>
|
|
2798
|
-
sqlite: () =>
|
|
2799
|
-
orElse: () =>
|
|
2805
|
+
}, zi = /* @__PURE__ */ new Set([P, z]), Bi = (e) => e.onDialectOrElse({
|
|
2806
|
+
mysql: () => ki(e),
|
|
2807
|
+
mssql: () => Pi(e),
|
|
2808
|
+
sqlite: () => Mi(e),
|
|
2809
|
+
orElse: () => Ei(e)
|
|
2800
2810
|
}).pipe(A.map((e) => ({
|
|
2801
2811
|
...e,
|
|
2802
|
-
tables: e.tables.filter((e) => !
|
|
2803
|
-
}))),
|
|
2804
|
-
let t =
|
|
2805
|
-
return t === void 0 ?
|
|
2806
|
-
}),
|
|
2812
|
+
tables: e.tables.filter((e) => !zi.has(e.name))
|
|
2813
|
+
}))), Vi = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", Hi = /* @__PURE__ */ new WeakMap(), V = (e) => A.suspend(() => {
|
|
2814
|
+
let t = Hi.get(e);
|
|
2815
|
+
return t === void 0 ? Ui(e).pipe(A.tap((t) => A.sync(() => Hi.set(e, t)))) : A.succeed(t);
|
|
2816
|
+
}), Ui = (e) => e.unsafe("SELECT VERSION() AS v").pipe(A.map((e) => {
|
|
2807
2817
|
let t = e[0]?.v;
|
|
2808
|
-
return typeof t == "string" ?
|
|
2809
|
-
}), A.catchAll(() => A.succeed("mysql"))),
|
|
2818
|
+
return typeof t == "string" ? Vi(t) : "mysql";
|
|
2819
|
+
}), A.catchAll(() => A.succeed("mysql"))), Wi = (e) => {
|
|
2810
2820
|
let t = e;
|
|
2811
2821
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2812
2822
|
let e = t;
|
|
2813
2823
|
if (typeof e.errno == "number") return e.errno;
|
|
2814
2824
|
t = e.cause;
|
|
2815
2825
|
}
|
|
2816
|
-
},
|
|
2826
|
+
}, Gi = (e) => {
|
|
2817
2827
|
let t = [], n = e;
|
|
2818
2828
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2819
2829
|
let e = n;
|
|
2820
2830
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2821
2831
|
}
|
|
2822
2832
|
return t.join(" | ");
|
|
2823
|
-
},
|
|
2833
|
+
}, Ki = (e, t) => {
|
|
2824
2834
|
if (t.length === 0) return !1;
|
|
2825
|
-
let n =
|
|
2835
|
+
let n = Wi(e), r = Gi(e);
|
|
2826
2836
|
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)));
|
|
2827
|
-
},
|
|
2837
|
+
}, qi = {
|
|
2828
2838
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2829
2839
|
errno: [1061]
|
|
2830
|
-
},
|
|
2840
|
+
}, Ji = {
|
|
2831
2841
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2832
2842
|
errno: [1091]
|
|
2833
|
-
},
|
|
2843
|
+
}, Yi = {
|
|
2834
2844
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2835
2845
|
messageIncludes: ["no such column"]
|
|
2836
|
-
},
|
|
2846
|
+
}, Xi = {
|
|
2837
2847
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2838
2848
|
errno: [1091, 3940]
|
|
2839
|
-
},
|
|
2849
|
+
}, Zi = {
|
|
2840
2850
|
why: "mysql/mariadb ADD CONSTRAINT has no IF NOT EXISTS; 1826 is exactly \"already there\"",
|
|
2841
2851
|
errno: [1826]
|
|
2842
|
-
},
|
|
2852
|
+
}, Qi = (e, t) => A.suspend(() => {
|
|
2843
2853
|
let n;
|
|
2844
2854
|
return e.withTransaction(t.pipe(A.tapErrorCause((e) => A.sync(() => {
|
|
2845
2855
|
n = e;
|
|
2846
|
-
})))).pipe(A.catchAllCause((e) => A.failCause(n !== void 0 && !
|
|
2847
|
-
}),
|
|
2856
|
+
})))).pipe(A.catchAllCause((e) => A.failCause(n !== void 0 && !xe.equals(n, e) ? be.sequential(n, e) : e)));
|
|
2857
|
+
}), $i = (e, t, n) => {
|
|
2848
2858
|
let r = e.match(/'(?:''|[^'])*'|\[(?:\]\]|[^\]])*\]|\s+|[^'\[\s]+/g) ?? [];
|
|
2849
2859
|
if (r.join("") !== e || r.some((e) => !e.startsWith("'") && !e.startsWith("[") && /"|\/\*|--/.test(e))) throw Error("Cannot safely rename CHECK: unsupported catalog SQL; use an explicit migration");
|
|
2850
2860
|
let a = r.map((e, t) => ({
|
|
@@ -2860,24 +2870,24 @@ BEGIN
|
|
|
2860
2870
|
}
|
|
2861
2871
|
if (o === 0 || r.join("").length === 0) throw Error(`Cannot safely rename CHECK reference '${t}': no exact catalog column token; use an explicit migration`);
|
|
2862
2872
|
return r.join("");
|
|
2863
|
-
},
|
|
2873
|
+
}, H = (e, t) => e.onDialectOrElse({
|
|
2864
2874
|
mysql: () => A.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2865
2875
|
orElse: () => A.succeed(t)
|
|
2866
|
-
}),
|
|
2867
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2876
|
+
}), ea = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, ta = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), na = (e, t) => {
|
|
2877
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !ta(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2868
2878
|
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;
|
|
2869
2879
|
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.`);
|
|
2870
2880
|
return I(e, t);
|
|
2871
|
-
},
|
|
2872
|
-
let t =
|
|
2873
|
-
return t === void 0 ?
|
|
2874
|
-
},
|
|
2881
|
+
}, ra = (e) => {
|
|
2882
|
+
let t = na(e, "postgres");
|
|
2883
|
+
return t === void 0 ? ia(e) : t;
|
|
2884
|
+
}, ia = (e) => {
|
|
2875
2885
|
switch (e.type) {
|
|
2876
2886
|
case "id": return "text";
|
|
2877
2887
|
case "text": return "text";
|
|
2878
2888
|
case "integer": return "integer";
|
|
2879
2889
|
case "real": return "double precision";
|
|
2880
|
-
case "decimal": return
|
|
2890
|
+
case "decimal": return ea(e, "NUMERIC");
|
|
2881
2891
|
case "bigint": return "bigint";
|
|
2882
2892
|
case "boolean": return "boolean";
|
|
2883
2893
|
case "timestamp": return "timestamptz";
|
|
@@ -2891,15 +2901,15 @@ BEGIN
|
|
|
2891
2901
|
case "interval": return "interval";
|
|
2892
2902
|
case "raw": return e.rawDdl ?? "text";
|
|
2893
2903
|
}
|
|
2894
|
-
},
|
|
2895
|
-
let t =
|
|
2904
|
+
}, aa = (e) => {
|
|
2905
|
+
let t = na(e, "mariadb");
|
|
2896
2906
|
if (t !== void 0) return t;
|
|
2897
2907
|
switch (e.type) {
|
|
2898
2908
|
case "id": return "VARCHAR(64)";
|
|
2899
2909
|
case "text": return "LONGTEXT";
|
|
2900
2910
|
case "integer": return "INT";
|
|
2901
2911
|
case "real": return "DOUBLE";
|
|
2902
|
-
case "decimal": return
|
|
2912
|
+
case "decimal": return ea(e, "DECIMAL");
|
|
2903
2913
|
case "bigint": return "BIGINT";
|
|
2904
2914
|
case "boolean": return "TINYINT(1)";
|
|
2905
2915
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2913,68 +2923,72 @@ BEGIN
|
|
|
2913
2923
|
case "interval": return "BIGINT";
|
|
2914
2924
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2915
2925
|
}
|
|
2916
|
-
},
|
|
2926
|
+
}, U = (e) => `"${e}"`, W = (e) => `\`${e.replace(/`/g, "``")}\``, oa = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", sa = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, ca = (e, t = "mariadb") => `ALTER TABLE ${W(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${W(e.column)}, ALGORITHM=COPY;`, la = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, ua = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${qa(t)}`)};`, da = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${pa(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, fa = (e, t) => {
|
|
2917
2927
|
let { defaultFactory: n, ...r } = e;
|
|
2918
2928
|
return I(e, t) !== I({
|
|
2919
2929
|
...r,
|
|
2920
2930
|
hasDefault: !1
|
|
2921
2931
|
}, t);
|
|
2922
|
-
},
|
|
2932
|
+
}, pa = (e, t) => {
|
|
2923
2933
|
let n = t(e.defaultValue);
|
|
2924
2934
|
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.`);
|
|
2925
2935
|
return n;
|
|
2926
|
-
},
|
|
2927
|
-
let r =
|
|
2928
|
-
return r ?
|
|
2929
|
-
},
|
|
2930
|
-
let
|
|
2936
|
+
}, G = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], ma = (e, t, n) => {
|
|
2937
|
+
let r = G(e, t, n);
|
|
2938
|
+
return r ? xr(n, r) : void 0;
|
|
2939
|
+
}, ha = (e, t, n, r) => {
|
|
2940
|
+
let i = n ?? e.nullable, a = Ut(e, "mariadb");
|
|
2931
2941
|
return [
|
|
2932
|
-
|
|
2942
|
+
W(t),
|
|
2933
2943
|
I(e, "mariadb"),
|
|
2934
|
-
|
|
2935
|
-
|
|
2944
|
+
i ? null : "NOT NULL",
|
|
2945
|
+
a,
|
|
2946
|
+
r === void 0 ? null : `CHECK (${r})`
|
|
2936
2947
|
].filter(Boolean).join(" ");
|
|
2937
|
-
},
|
|
2948
|
+
}, ga = /^json_valid\(`[^`]+`\)$/i, _a = (e, t) => V(e).pipe(A.flatMap((n) => n === "mariadb" ? e`
|
|
2949
|
+
SELECT constraint_name AS n, check_clause AS c
|
|
2950
|
+
FROM information_schema.check_constraints
|
|
2951
|
+
WHERE constraint_schema = DATABASE() AND table_name = ${t} AND level = 'Column'`.pipe(A.map((e) => new Map(e.map((e) => [String(e.n ?? ""), String(e.c ?? "")]).filter(([e, t]) => e !== "" && t !== "" && !ga.test(t.trim()))))) : A.succeed(/* @__PURE__ */ new Map()))), va = (e, t, n, r, i) => A.map(_a(e, t), (e) => `ALTER TABLE ${W(t)} MODIFY COLUMN ${ha(n, r, i, e.get(r))};`), ya = (e, t) => e == null ? null : Array.isArray(e) ? ba(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" ? Gt(e, "mariadb") : null, ba = (e, t, n) => Wt(e, t ?? { type: "json" }, n), xa = (e, t) => e == null ? null : Array.isArray(e) ? ba(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" ? Gt(e, "postgres") : null, Sa = (e, t) => {
|
|
2938
2952
|
if (!e.generatedAs) return null;
|
|
2939
2953
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2940
2954
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2941
|
-
},
|
|
2942
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2943
|
-
let n =
|
|
2944
|
-
if (n) return `${
|
|
2945
|
-
let r = [
|
|
2955
|
+
}, Ca = (e, t = !1) => {
|
|
2956
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return Kt(e.name, "postgres");
|
|
2957
|
+
let n = Sa(e, "postgres");
|
|
2958
|
+
if (n) return `${U(e.name)} ${ra(e)} ${n}`;
|
|
2959
|
+
let r = [U(e.name), ra(e)];
|
|
2946
2960
|
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) {
|
|
2947
|
-
let t =
|
|
2961
|
+
let t = xa(e.defaultValue, e);
|
|
2948
2962
|
t && r.push(t);
|
|
2949
2963
|
}
|
|
2950
|
-
return e.references && (r.push(`REFERENCES ${
|
|
2964
|
+
return e.references && (r.push(`REFERENCES ${U(e.references.table)} (${U(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${{
|
|
2951
2965
|
cascade: "CASCADE",
|
|
2952
2966
|
restrict: "RESTRICT",
|
|
2953
2967
|
setNull: "SET NULL",
|
|
2954
2968
|
noAction: "NO ACTION"
|
|
2955
2969
|
}[e.references.onDelete]}`)), r.join(" ");
|
|
2956
|
-
},
|
|
2957
|
-
let t = e.columns.map((t) => ` ${
|
|
2958
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(
|
|
2970
|
+
}, wa = (e) => (e.primaryKey?.length ?? 0) > 0, Ta = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Ea = (e) => {
|
|
2971
|
+
let t = e.columns.map((t) => ` ${Ca(t, wa(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${U(e.table)} (\n${t}${Ta(e, U)}\n)`];
|
|
2972
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(eo({
|
|
2959
2973
|
kind: "add-index",
|
|
2960
2974
|
table: e.table,
|
|
2961
2975
|
index: t
|
|
2962
2976
|
}, !1));
|
|
2963
2977
|
return n;
|
|
2964
|
-
},
|
|
2965
|
-
let t =
|
|
2978
|
+
}, Da = 191, Oa = (e) => {
|
|
2979
|
+
let t = aa(e).toUpperCase();
|
|
2966
2980
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2967
|
-
},
|
|
2968
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2969
|
-
let n = e.charset === void 0 ?
|
|
2970
|
-
if (r) return `${
|
|
2971
|
-
let i = [
|
|
2972
|
-
if (e.type === "id" && !t && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2973
|
-
let t =
|
|
2981
|
+
}, ka = (e, t = !1) => {
|
|
2982
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return Kt(e.name, "mariadb");
|
|
2983
|
+
let n = e.charset === void 0 ? aa(e) : `${aa(e)} CHARACTER SET ${e.charset}`, r = Sa(e, "mariadb");
|
|
2984
|
+
if (r) return `${W(e.name)} ${n} ${r}`;
|
|
2985
|
+
let i = [W(e.name), n];
|
|
2986
|
+
if (e.type === "id" && !t && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && !Oa(e) && i.push("UNIQUE"), e.hasDefault) {
|
|
2987
|
+
let t = ya(e.defaultValue, e);
|
|
2974
2988
|
t && i.push(t);
|
|
2975
2989
|
}
|
|
2976
2990
|
return i.join(" ");
|
|
2977
|
-
},
|
|
2991
|
+
}, Aa = (e) => e.columns.flatMap((t) => {
|
|
2978
2992
|
if (!t.references) return [];
|
|
2979
2993
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2980
2994
|
cascade: "CASCADE",
|
|
@@ -2982,49 +2996,54 @@ BEGIN
|
|
|
2982
2996
|
setNull: "SET NULL",
|
|
2983
2997
|
noAction: "NO ACTION"
|
|
2984
2998
|
}[t.references.onDelete]}` : "";
|
|
2985
|
-
return [` CONSTRAINT ${
|
|
2986
|
-
}),
|
|
2999
|
+
return [` CONSTRAINT ${W(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${W(t.name)}) REFERENCES ${W(t.references.table)} (${W(t.references.column)})${n}`];
|
|
3000
|
+
}), ja = (e) => {
|
|
2987
3001
|
let t = e.find((e) => e.charset !== void 0)?.charset;
|
|
2988
3002
|
return t === void 0 ? "" : ` DEFAULT CHARACTER SET ${t}`;
|
|
2989
|
-
},
|
|
2990
|
-
let
|
|
2991
|
-
let
|
|
2992
|
-
if (
|
|
2993
|
-
let
|
|
2994
|
-
if (
|
|
2995
|
-
|
|
2996
|
-
return `MODIFY COLUMN ${[
|
|
3003
|
+
}, Ma = (e, t, n = /* @__PURE__ */ new Map()) => {
|
|
3004
|
+
let r = e.foreignKeys.map((e) => `ALTER TABLE ${W(e.table)} DROP FOREIGN KEY ${W(e.name)}`), i = e.columns.map((r) => {
|
|
3005
|
+
let i = G(t, e.table, r), a = ma(t, e.table, r);
|
|
3006
|
+
if (i === void 0 || a === void 0) throw Error(`convert-charset: no declared column '${e.table}.${r}' to render MODIFY COLUMN from; it was not in ctx.declared.`);
|
|
3007
|
+
let o = Sa(a, "mariadb"), s = `${W(r)} ${I(i, "mariadb")} CHARACTER SET ${e.charset}`, c = n.get(r), l = c === void 0 ? null : `CHECK (${c})`;
|
|
3008
|
+
if (o) return `MODIFY COLUMN ${[
|
|
3009
|
+
s,
|
|
2997
3010
|
o,
|
|
2998
|
-
|
|
2999
|
-
|
|
3011
|
+
l
|
|
3012
|
+
].filter(Boolean).join(" ")}`;
|
|
3013
|
+
let u = Ut(i, "mariadb");
|
|
3014
|
+
return `MODIFY COLUMN ${[
|
|
3015
|
+
s,
|
|
3016
|
+
i.nullable ? null : "NOT NULL",
|
|
3017
|
+
u,
|
|
3018
|
+
l
|
|
3000
3019
|
].filter(Boolean).join(" ")}`;
|
|
3001
3020
|
});
|
|
3002
3021
|
return {
|
|
3003
|
-
drops:
|
|
3004
|
-
rewrite: `ALTER TABLE ${
|
|
3005
|
-
restores: e.foreignKeys.filter((e) => e.restore === "here").map((e) => `ALTER TABLE ${
|
|
3022
|
+
drops: r,
|
|
3023
|
+
rewrite: `ALTER TABLE ${W(e.table)} ${[...i, `DEFAULT CHARACTER SET ${e.charset}`].join(", ")}`,
|
|
3024
|
+
restores: e.foreignKeys.filter((e) => e.restore === "here").map((e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} FOREIGN KEY (${W(e.column)}) REFERENCES ${W(e.targetTable)} (${W(e.targetColumn)})` + (e.onDelete ? ` ON DELETE ${Pa[e.onDelete]}` : "") + (e.onUpdate && e.onUpdate !== "noAction" ? ` ON UPDATE ${Pa[e.onUpdate]}` : ""))
|
|
3006
3025
|
};
|
|
3007
|
-
},
|
|
3008
|
-
for (let n of e.indexes)
|
|
3026
|
+
}, Na = (e, t = "mariadb") => {
|
|
3027
|
+
for (let n of e.indexes) no(n, t);
|
|
3009
3028
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
3010
|
-
let t =
|
|
3011
|
-
return t === void 0 ?
|
|
3012
|
-
}, i = e.columns.map((t) => ` ${
|
|
3013
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
3014
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
3029
|
+
let t = Xa(n.get(e));
|
|
3030
|
+
return t === void 0 ? W(e) : `${W(e)}(${t})`;
|
|
3031
|
+
}, i = e.columns.map((t) => ` ${ka(t, wa(e))}`).join(",\n"), a = Aa(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${o}${Ta(e, r)}\n)${ja(e.columns)}`];
|
|
3032
|
+
for (let n of e.columns) n.unique && n.type !== "id" && Oa(n) && s.push(`CREATE UNIQUE INDEX ${oa(t)}${W(`${e.table}_${n.name}_key`)} ON ${W(e.table)} (${r(n.name)})`);
|
|
3033
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${oa(t)}${W(n.name)} ON ${W(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
3015
3034
|
return s;
|
|
3016
|
-
},
|
|
3035
|
+
}, Pa = {
|
|
3017
3036
|
cascade: "CASCADE",
|
|
3018
3037
|
restrict: "RESTRICT",
|
|
3019
3038
|
setNull: "SET NULL",
|
|
3020
3039
|
noAction: "NO ACTION"
|
|
3021
|
-
},
|
|
3040
|
+
}, Fa = {
|
|
3022
3041
|
cascade: "CASCADE",
|
|
3023
3042
|
restrict: "NO ACTION",
|
|
3024
3043
|
setNull: "SET NULL",
|
|
3025
3044
|
noAction: "NO ACTION"
|
|
3026
|
-
},
|
|
3027
|
-
let t =
|
|
3045
|
+
}, Ia = (e) => {
|
|
3046
|
+
let t = na(e, "sqlite");
|
|
3028
3047
|
if (t !== void 0) return t;
|
|
3029
3048
|
switch (e.type) {
|
|
3030
3049
|
case "integer":
|
|
@@ -3036,61 +3055,61 @@ BEGIN
|
|
|
3036
3055
|
case "bytes": return "BLOB";
|
|
3037
3056
|
default: return "TEXT";
|
|
3038
3057
|
}
|
|
3039
|
-
},
|
|
3040
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
3041
|
-
let n =
|
|
3042
|
-
if (n) return `${
|
|
3043
|
-
let r = [
|
|
3058
|
+
}, La = (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" ? Gt(e, "sqlite") : null, Ra = (e, t = !1) => {
|
|
3059
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return Kt(e.name, "sqlite");
|
|
3060
|
+
let n = Sa(e, "sqlite");
|
|
3061
|
+
if (n) return `${U(e.name)} ${Ia(e)} ${n}`;
|
|
3062
|
+
let r = [U(e.name), Ia(e)];
|
|
3044
3063
|
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) {
|
|
3045
|
-
let t =
|
|
3064
|
+
let t = La(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
3046
3065
|
t && r.push(t);
|
|
3047
3066
|
}
|
|
3048
|
-
if (e.references && (r.push(`REFERENCES ${
|
|
3067
|
+
if (e.references && (r.push(`REFERENCES ${U(e.references.table)} (${U(e.references.column)})`), e.references.onDelete && r.push(`ON DELETE ${Pa[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
3049
3068
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
3050
|
-
r.push(`CHECK (${
|
|
3069
|
+
r.push(`CHECK (${U(e.name)} IN (${t}))`);
|
|
3051
3070
|
}
|
|
3052
3071
|
return r.join(" ");
|
|
3053
|
-
},
|
|
3054
|
-
let t = e.columns.map((t) => ` ${
|
|
3055
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
3072
|
+
}, za = (e) => {
|
|
3073
|
+
let t = e.columns.map((t) => ` ${Ra(t, wa(e))}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${U(e.table)} (\n${t}${Ta(e, U)}\n)`];
|
|
3074
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(t.name)} ON ${U(e.table)} (${t.columns.map(U).join(", ")})${$a(t)}`);
|
|
3056
3075
|
return n;
|
|
3057
|
-
},
|
|
3076
|
+
}, Ba = (e, t) => {
|
|
3058
3077
|
let n = t.find((t) => t.tableName === e);
|
|
3059
|
-
return n ?
|
|
3060
|
-
},
|
|
3061
|
-
let t = e.name, n = `${t}__voltro_rebuild`, r = e.columns.map((e) =>
|
|
3062
|
-
...
|
|
3078
|
+
return n ? Va(Tr([n], "sqlite").tables[0]) : [];
|
|
3079
|
+
}, Va = (e) => {
|
|
3080
|
+
let t = e.name, n = `${t}__voltro_rebuild`, r = e.columns.map((e) => U(e.name)).join(", "), i = [
|
|
3081
|
+
...za({
|
|
3063
3082
|
kind: "create-table",
|
|
3064
3083
|
table: n,
|
|
3065
3084
|
columns: e.columns,
|
|
3066
3085
|
indexes: [],
|
|
3067
3086
|
...e.primaryKey ? { primaryKey: e.primaryKey } : {}
|
|
3068
3087
|
}),
|
|
3069
|
-
`INSERT INTO ${
|
|
3070
|
-
`DROP TABLE ${
|
|
3071
|
-
`ALTER TABLE ${
|
|
3088
|
+
`INSERT INTO ${U(n)} (${r}) SELECT ${r} FROM ${U(t)}`,
|
|
3089
|
+
`DROP TABLE ${U(t)}`,
|
|
3090
|
+
`ALTER TABLE ${U(n)} RENAME TO ${U(t)}`
|
|
3072
3091
|
];
|
|
3073
|
-
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
3092
|
+
for (let n of e.indexes) n.name !== `${t}_pkey` && i.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${U(n.name)} ON ${U(t)} (${n.columns.map(U).join(", ")})${$a(n)}`);
|
|
3074
3093
|
return i;
|
|
3075
|
-
},
|
|
3094
|
+
}, Ha = (e, t, n, r) => {
|
|
3076
3095
|
let i = r ?? e.nullable;
|
|
3077
|
-
return `ALTER TABLE ${
|
|
3078
|
-
},
|
|
3079
|
-
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 ${
|
|
3096
|
+
return `ALTER TABLE ${K(n)} ALTER COLUMN ${K(t)} ${I(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
3097
|
+
}, Ua = (e, t) => {
|
|
3098
|
+
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 ${K(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
3080
3099
|
if (!e.hasDefault) return n;
|
|
3081
|
-
let r =
|
|
3100
|
+
let r = La(e.defaultValue, "SYSUTCDATETIME()");
|
|
3082
3101
|
if (!r) return n;
|
|
3083
3102
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
3084
|
-
return `${n} ALTER TABLE ${
|
|
3085
|
-
},
|
|
3086
|
-
let t =
|
|
3103
|
+
return `${n} ALTER TABLE ${K(e.table)} ADD DEFAULT ${i} FOR ${K(e.column)};`;
|
|
3104
|
+
}, K = (e) => `[${e.replace(/]/g, "]]")}]`, Wa = (e) => {
|
|
3105
|
+
let t = na(e, "mssql");
|
|
3087
3106
|
if (t !== void 0) return t;
|
|
3088
3107
|
switch (e.type) {
|
|
3089
3108
|
case "id": return "NVARCHAR(64)";
|
|
3090
3109
|
case "reference": return e.referenceStorage === "numeric" ? "BIGINT" : "NVARCHAR(64)";
|
|
3091
3110
|
case "integer": return "INT";
|
|
3092
3111
|
case "real": return "FLOAT";
|
|
3093
|
-
case "decimal": return
|
|
3112
|
+
case "decimal": return ea(e, "DECIMAL");
|
|
3094
3113
|
case "bigint": return "BIGINT";
|
|
3095
3114
|
case "boolean": return "BIT";
|
|
3096
3115
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -3098,53 +3117,53 @@ BEGIN
|
|
|
3098
3117
|
case "bytes": return "VARBINARY(MAX)";
|
|
3099
3118
|
default: return "NVARCHAR(MAX)";
|
|
3100
3119
|
}
|
|
3101
|
-
},
|
|
3102
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
3103
|
-
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` :
|
|
3104
|
-
if (i) return `${
|
|
3105
|
-
let a = [
|
|
3106
|
-
if (e.type === "json" && a.push(`CHECK ${
|
|
3107
|
-
let t =
|
|
3120
|
+
}, Ga = (e, t, n = !1) => {
|
|
3121
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return Kt(e.name, "mssql");
|
|
3122
|
+
let r = e.type === "text" && t?.has(e.name) ? `NVARCHAR(${Math.min(e.maxLength ?? 450, 450)})` : Wa(e), i = Sa(e, "mssql");
|
|
3123
|
+
if (i) return `${K(e.name)} ${i}`;
|
|
3124
|
+
let a = [K(e.name), r];
|
|
3125
|
+
if (e.type === "json" && a.push(`CHECK ${kt(K(e.name))}`), e.type === "array" && a.push(`CHECK (${K(e.name)} IS NULL OR ISJSON(${K(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) {
|
|
3126
|
+
let t = La(e.defaultValue, "SYSUTCDATETIME()");
|
|
3108
3127
|
t && a.push(t);
|
|
3109
3128
|
}
|
|
3110
|
-
return e.references && (a.push(`REFERENCES ${
|
|
3111
|
-
},
|
|
3112
|
-
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) => ` ${
|
|
3129
|
+
return e.references && (a.push(`REFERENCES ${K(e.references.table)} (${K(e.references.column)})`), e.references.onDelete && a.push(`ON DELETE ${Fa[e.references.onDelete]}`)), a.join(" ");
|
|
3130
|
+
}, Ka = (e) => {
|
|
3131
|
+
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) => ` ${Ga(t, n, wa(e))}`).join(",\n"), i = `CREATE TABLE ${K(e.table)} (\n${r}${Ta(e, K)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
3113
3132
|
for (let n of e.indexes) {
|
|
3114
3133
|
if (n.name === `${e.table}_pkey`) continue;
|
|
3115
|
-
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
3134
|
+
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${K(n.name)} ON ${K(e.table)} (${n.columns.map(K).join(", ")})${$a(n)}`;
|
|
3116
3135
|
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)}')`);
|
|
3117
3136
|
}
|
|
3118
3137
|
return a;
|
|
3119
|
-
},
|
|
3120
|
-
let r = `${e.table}${
|
|
3138
|
+
}, qa = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Ja = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Ya = (e, t, n) => {
|
|
3139
|
+
let r = `${e.table}${qa(t)}`;
|
|
3121
3140
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
3122
|
-
},
|
|
3123
|
-
if (e === void 0 || !
|
|
3141
|
+
}, Xa = (e) => {
|
|
3142
|
+
if (e === void 0 || !Oa(e)) return;
|
|
3124
3143
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
3125
|
-
return t === void 0 ?
|
|
3126
|
-
},
|
|
3127
|
-
let r =
|
|
3128
|
-
return r === void 0 ?
|
|
3129
|
-
},
|
|
3130
|
-
let n =
|
|
3144
|
+
return t === void 0 ? Da : Math.min(Da, t);
|
|
3145
|
+
}, Za = (e, t, n) => {
|
|
3146
|
+
let r = Xa(ma(e, t, n));
|
|
3147
|
+
return r === void 0 ? W(n) : `${W(n)}(${r})`;
|
|
3148
|
+
}, Qa = (e) => e.startsWith("(") ? e : U(e), $a = (e) => e.where === void 0 ? "" : ` WHERE ${e.where}`, eo = (e, t) => {
|
|
3149
|
+
let n = Ne(e.index.kind, e.index.kindOptions), r = e.index.columns.map(Qa);
|
|
3131
3150
|
if (n.opclass !== void 0) {
|
|
3132
3151
|
if (r.length !== 1) throw Error("HNSW index requires exactly one column");
|
|
3133
3152
|
r[0] = `${r[0]} ${n.opclass}`;
|
|
3134
3153
|
}
|
|
3135
|
-
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${
|
|
3136
|
-
},
|
|
3154
|
+
return `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${U(e.index.name)} ON ${U(e.table)}${n.using} (${r.join(", ")})${n.withSuffix}${$a(e.index)};`;
|
|
3155
|
+
}, to = (e, t, n = "mariadb") => (no(e.index, n), `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${oa(n)}${W(e.index.name)} ON ${W(e.table)} (${e.index.columns.map((n) => Za(t, e.table, n)).join(", ")});`), no = (e, t) => {
|
|
3137
3156
|
if (e.where !== void 0) throw Error(`Partial index '${e.name}' is not supported by ${t}; uniqueActive must be lowered before applying the plan.`);
|
|
3138
|
-
},
|
|
3157
|
+
}, ro = (e) => `DROP INDEX IF EXISTS ${U(e.index)};`, io = (e) => `DROP INDEX ${W(e.index)} ON ${W(e.table)};`, ao = (e) => `DROP INDEX IF EXISTS ${K(e.index)} ON ${K(e.table)};`, oo = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, so = (e) => {
|
|
3139
3158
|
let t = (e) => e.replace(/'/g, "''");
|
|
3140
3159
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
3141
|
-
},
|
|
3160
|
+
}, co = (e) => `ALTER INDEX ${U(e.from)} RENAME TO ${U(e.to)};`, lo = (e) => `ALTER TABLE ${W(e.table)} RENAME INDEX ${W(e.from)} TO ${W(e.to)};`, uo = (e) => {
|
|
3142
3161
|
let t = (e) => e.replace(/'/g, "''");
|
|
3143
3162
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
3144
|
-
},
|
|
3145
|
-
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${
|
|
3163
|
+
}, fo = (e) => {
|
|
3164
|
+
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map(K).join(", ")})${$a(e.index)}`;
|
|
3146
3165
|
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)}');`;
|
|
3147
|
-
},
|
|
3166
|
+
}, po = (e, t, n) => {
|
|
3148
3167
|
let r = n.find((t) => t.tableName === e);
|
|
3149
3168
|
if (!r) return [];
|
|
3150
3169
|
let i = [];
|
|
@@ -3152,17 +3171,17 @@ BEGIN
|
|
|
3152
3171
|
let t = r.fields[n];
|
|
3153
3172
|
if (t && t.type === "text" && !t.generatedAs) {
|
|
3154
3173
|
let r = Math.min(t.maxLength ?? 450, 450);
|
|
3155
|
-
i.push(`ALTER TABLE ${
|
|
3174
|
+
i.push(`ALTER TABLE ${K(e)} ALTER COLUMN ${K(n)} NVARCHAR(${r}) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
3156
3175
|
}
|
|
3157
3176
|
}
|
|
3158
3177
|
return i;
|
|
3159
|
-
},
|
|
3160
|
-
let t = e.fields.map((e) =>
|
|
3161
|
-
return `ALTER TABLE ${
|
|
3162
|
-
},
|
|
3163
|
-
let n = e.fields.map((n) =>
|
|
3164
|
-
return `ALTER TABLE ${
|
|
3165
|
-
},
|
|
3178
|
+
}, mo = (e) => `ALTER TABLE ${U(e.table)} ADD CONSTRAINT ${U(`${e.table}_${e.column}_key`)} UNIQUE (${U(e.column)});`, ho = (e, t) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${Za(t, e.table, e.column)});`, go = (e) => {
|
|
3179
|
+
let t = e.fields.map((e) => U(e)).join(", ");
|
|
3180
|
+
return `ALTER TABLE ${U(e.table)} ADD CONSTRAINT ${U(e.name)} UNIQUE (${t});`;
|
|
3181
|
+
}, _o = (e, t) => {
|
|
3182
|
+
let n = e.fields.map((n) => Za(t, e.table, n)).join(", ");
|
|
3183
|
+
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${n});`;
|
|
3184
|
+
}, vo = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(e.name)};`, yo = (e) => `ALTER TABLE ${W(e.table)} DROP INDEX ${W(e.name)};`, bo = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(`${e.table}_${e.column}_key`)};`, xo = (e) => `ALTER TABLE ${W(e.table)} DROP INDEX ${W(`${e.table}_${e.column}_key`)};`, So = (e, t, n = Pa) => {
|
|
3166
3185
|
let r = [], i = t(e.table), a = t(e.column), o = t(e.targetTable), s = t(e.targetColumn);
|
|
3167
3186
|
if (e.orphanPolicy) {
|
|
3168
3187
|
let t = `${a} IS NOT NULL AND ${a} NOT IN (SELECT ${s} FROM ${o})`;
|
|
@@ -3175,10 +3194,10 @@ BEGIN
|
|
|
3175
3194
|
`REFERENCES ${o} (${s})`
|
|
3176
3195
|
];
|
|
3177
3196
|
return e.onDelete && c.push(`ON DELETE ${n[e.onDelete]}`), r.push(c.join(" ") + ";"), r;
|
|
3178
|
-
},
|
|
3197
|
+
}, Co = (e) => e.name ?? `${e.table}_${e.column}_fkey`, wo = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(Co(e))};`, To = (e) => `ALTER TABLE ${W(e.table)} DROP FOREIGN KEY ${W(Co(e))};`, Eo = (e, t) => {
|
|
3179
3198
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
3180
3199
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
3181
|
-
},
|
|
3200
|
+
}, Do = (e) => `ALTER TABLE ${U(e.table)} DROP CONSTRAINT IF EXISTS ${U(`${e.table}_${e.column}_check`)};`, Oo = (e, t) => A.gen(function* () {
|
|
3182
3201
|
let n = yield* e`
|
|
3183
3202
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
3184
3203
|
FROM information_schema.check_constraints cc
|
|
@@ -3191,18 +3210,18 @@ BEGIN
|
|
|
3191
3210
|
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`), A.orElseSucceed(() => []));
|
|
3192
3211
|
for (let e of n) {
|
|
3193
3212
|
let n = String(e.n ?? "");
|
|
3194
|
-
if (n !== "" &&
|
|
3213
|
+
if (n !== "" && hi(String(e.c ?? ""))?.column === t.column) return n;
|
|
3195
3214
|
}
|
|
3196
|
-
}),
|
|
3197
|
-
let r = yield*
|
|
3198
|
-
r !== void 0 && (yield*
|
|
3199
|
-
let i = yield*
|
|
3215
|
+
}), ko = (e, t, n) => A.gen(function* () {
|
|
3216
|
+
let r = yield* Oo(e, t);
|
|
3217
|
+
r !== void 0 && (yield* q(e, `ALTER TABLE ${W(t.table)} DROP CONSTRAINT ${W(r)};`, t.kind, [Xi]));
|
|
3218
|
+
let i = yield* Oo(e, t);
|
|
3200
3219
|
if (i === void 0) return;
|
|
3201
|
-
let a =
|
|
3220
|
+
let a = G(n, t.table, t.column);
|
|
3202
3221
|
if (!a) return yield* A.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.`));
|
|
3203
|
-
yield*
|
|
3204
|
-
}),
|
|
3205
|
-
let i = e.column, a = r === "mariadb", o = a ?
|
|
3222
|
+
yield* q(e, `ALTER TABLE ${W(t.table)} MODIFY COLUMN ${ha(a, t.column)};`, t.kind);
|
|
3223
|
+
}), Ao = (e, t, n, r) => {
|
|
3224
|
+
let i = e.column, a = r === "mariadb", o = a ? W : r === "mssql" ? K : U, s = a ? aa(i) : r === "mssql" ? Wa(i) : r === "sqlite" ? Ia(i) : ra(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = r === "mssql" ? i.type === "json" ? ` CHECK ${kt(o(i.name))}` : i.type === "array" ? ` CHECK (${o(i.name)} IS NULL OR ISJSON(${o(i.name)}) = 1)` : "" : "", u = (e) => a ? ya(e, i) : r === "mssql" ? La(e, "SYSUTCDATETIME()") : r === "sqlite" ? La(e, "CURRENT_TIMESTAMP") : xa(e, i), d = Sa(i, r);
|
|
3206
3225
|
if (d) {
|
|
3207
3226
|
let t = r === "mssql" ? `${o(i.name)} ${d}` : `${o(i.name)} ${s} ${d}`;
|
|
3208
3227
|
return {
|
|
@@ -3231,7 +3250,7 @@ BEGIN
|
|
|
3231
3250
|
post: p ? [p] : []
|
|
3232
3251
|
};
|
|
3233
3252
|
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;
|
|
3234
|
-
},
|
|
3253
|
+
}, jo = /* @__PURE__ */ new Set([
|
|
3235
3254
|
"drop-index",
|
|
3236
3255
|
"drop-check",
|
|
3237
3256
|
"drop-unique",
|
|
@@ -3239,7 +3258,7 @@ BEGIN
|
|
|
3239
3258
|
"drop-foreign-key",
|
|
3240
3259
|
"drop-column",
|
|
3241
3260
|
"drop-table"
|
|
3242
|
-
]),
|
|
3261
|
+
]), Mo = (e) => {
|
|
3243
3262
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
3244
3263
|
return (e, n) => {
|
|
3245
3264
|
let r = t.get(e);
|
|
@@ -3259,15 +3278,15 @@ BEGIN
|
|
|
3259
3278
|
...o
|
|
3260
3279
|
};
|
|
3261
3280
|
};
|
|
3262
|
-
},
|
|
3263
|
-
process.stderr.write(
|
|
3281
|
+
}, q = (e, t, n, r = []) => e.unsafe(t).pipe(A.catchIf((e) => Ki(e, r), () => A.void), A.tapError((e) => A.sync(() => {
|
|
3282
|
+
process.stderr.write(Pe(`applier: statement failed (op=${n})`, t, e, 400));
|
|
3264
3283
|
})), A.mapError((e) => {
|
|
3265
|
-
let r =
|
|
3284
|
+
let r = Pe(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
3266
3285
|
return Object.assign(e, { message: r });
|
|
3267
|
-
}), A.map(() => void 0)),
|
|
3286
|
+
}), A.map(() => void 0)), J = (e, t, n, r) => No(e, t, Ba(t, n), r), No = (e, t, n, r) => {
|
|
3268
3287
|
if (n.length === 0) return A.void;
|
|
3269
3288
|
let i = (e) => (n) => {
|
|
3270
|
-
let i =
|
|
3289
|
+
let i = Pe(`applier: statement failed (op=${r}, sqlite rebuild of ${t})`, e, n, 400).trim();
|
|
3271
3290
|
return process.stderr.write(`${i}\n`), Object.assign(n, { message: i });
|
|
3272
3291
|
};
|
|
3273
3292
|
return A.scoped(A.gen(function* () {
|
|
@@ -3281,7 +3300,7 @@ BEGIN
|
|
|
3281
3300
|
}
|
|
3282
3301
|
}), A.ignore(a("PRAGMA foreign_keys = ON")));
|
|
3283
3302
|
}));
|
|
3284
|
-
},
|
|
3303
|
+
}, Po = (e, t) => A.gen(function* () {
|
|
3285
3304
|
let n = (yield* e`
|
|
3286
3305
|
SELECT ck.name, ck.definition, ck.is_disabled AS disabled,
|
|
3287
3306
|
ck.is_not_trusted AS untrusted, ck.is_not_for_replication AS notForReplication
|
|
@@ -3293,18 +3312,18 @@ BEGIN
|
|
|
3293
3312
|
) ORDER BY ck.name
|
|
3294
3313
|
`).map((e) => ({
|
|
3295
3314
|
...e,
|
|
3296
|
-
definition:
|
|
3315
|
+
definition: $i(e.definition, t.from, t.to)
|
|
3297
3316
|
})), r = (e) => i(e, "mssql"), a = (e) => e.replace(/'/g, "''");
|
|
3298
|
-
return yield*
|
|
3317
|
+
return yield* Y(e, [
|
|
3299
3318
|
...n.map((e) => `ALTER TABLE ${r(t.table)} DROP CONSTRAINT ${r(e.name)}`),
|
|
3300
3319
|
`EXEC sp_rename N'${a(`${r(t.table)}.${r(t.from)}`)}', N'${a(t.to)}', 'COLUMN';`,
|
|
3301
3320
|
...n.flatMap((e) => [`ALTER TABLE ${r(t.table)} WITH ${e.untrusted ? "NOCHECK" : "CHECK"} ADD CONSTRAINT ${r(e.name)} CHECK ${e.notForReplication ? "NOT FOR REPLICATION " : ""}${e.definition}`, ...e.disabled ? [`ALTER TABLE ${r(t.table)} NOCHECK CONSTRAINT ${r(e.name)}`] : []])
|
|
3302
3321
|
], t.kind);
|
|
3303
|
-
}),
|
|
3322
|
+
}), Fo = (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, Y = (e, t, n) => A.forEach(t, (t) => q(e, t, n), { discard: !0 }), Io = (e, t) => {
|
|
3304
3323
|
let n = Math.max(1, Math.floor(Number.isFinite(t) ? t : 1));
|
|
3305
3324
|
return e.literal(N(e) === "mssql" ? `OFFSET 0 ROWS FETCH NEXT ${n} ROWS ONLY` : `LIMIT ${n}`);
|
|
3306
|
-
},
|
|
3307
|
-
let i =
|
|
3325
|
+
}, Lo = (e, t, n, r) => e.unsafe(`SELECT ${r === void 0 ? "*" : i(r, t)} FROM ${i(n, t)} WHERE 1=0`).pipe(A.as(!0), A.catchAll(() => A.succeed(!1))), Ro = (e, t) => Ho(e, t, vt, P), zo = (e, t) => Ho(e, t, de, "_voltro_migration_plans"), Bo = (e, t) => Ho(e, t, li, z), Vo = (e, t) => Ho(e, t, fe, he), Ho = (e, t, n, r) => A.gen(function* () {
|
|
3326
|
+
let i = Tr([n], t).tables[0];
|
|
3308
3327
|
if (!i) return yield* A.die(/* @__PURE__ */ Error(`migration applier: the ${r} table descriptor produced no snapshot. This is a framework bug.`));
|
|
3309
3328
|
let a = {
|
|
3310
3329
|
kind: "create-table",
|
|
@@ -3312,18 +3331,18 @@ BEGIN
|
|
|
3312
3331
|
columns: i.columns,
|
|
3313
3332
|
indexes: []
|
|
3314
3333
|
}, o = yield* e.onDialectOrElse({
|
|
3315
|
-
mysql: () =>
|
|
3316
|
-
mssql: () => A.succeed(
|
|
3317
|
-
sqlite: () => A.succeed(
|
|
3318
|
-
orElse: () => A.succeed(
|
|
3334
|
+
mysql: () => V(e).pipe(A.map((e) => Na(a, e))),
|
|
3335
|
+
mssql: () => A.succeed(Ka(a)),
|
|
3336
|
+
sqlite: () => A.succeed(za(a)),
|
|
3337
|
+
orElse: () => A.succeed(Ea(a))
|
|
3319
3338
|
});
|
|
3320
|
-
yield* A.forEach(o, (t) =>
|
|
3321
|
-
}),
|
|
3339
|
+
yield* A.forEach(o, (t) => q(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
3340
|
+
}), Uo = (e) => e`
|
|
3322
3341
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
3323
3342
|
${e("status")}, ${e("payload")}
|
|
3324
3343
|
FROM ${e(P)}
|
|
3325
|
-
`,
|
|
3326
|
-
let i = yield*
|
|
3344
|
+
`, Wo = (e, t, n, r) => A.gen(function* () {
|
|
3345
|
+
let i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3327
3346
|
yield* A.forEach(r, ({ index: r, planned: a }) => e`
|
|
3328
3347
|
INSERT INTO ${e(P)}
|
|
3329
3348
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
@@ -3331,11 +3350,11 @@ BEGIN
|
|
|
3331
3350
|
${e("createdAt")})
|
|
3332
3351
|
VALUES
|
|
3333
3352
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
3334
|
-
${a.op.kind}, ${
|
|
3353
|
+
${a.op.kind}, ${bt(a.op)}, ${"pending"},
|
|
3335
3354
|
${JSON.stringify(a)}, ${i})
|
|
3336
3355
|
`, { discard: !0 });
|
|
3337
|
-
}),
|
|
3338
|
-
let a = yield*
|
|
3356
|
+
}), Go = (e, t, n, r, i) => A.gen(function* () {
|
|
3357
|
+
let a = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3339
3358
|
if (r === "applied") {
|
|
3340
3359
|
yield* e`
|
|
3341
3360
|
UPDATE ${e(P)}
|
|
@@ -3350,8 +3369,8 @@ BEGIN
|
|
|
3350
3369
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
3351
3370
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
3352
3371
|
`;
|
|
3353
|
-
}),
|
|
3354
|
-
let i = yield*
|
|
3372
|
+
}), Ko = (e, t, n, r) => A.gen(function* () {
|
|
3373
|
+
let i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3355
3374
|
r.length > 0 && (yield* e`
|
|
3356
3375
|
UPDATE ${e(P)}
|
|
3357
3376
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
@@ -3361,149 +3380,149 @@ BEGIN
|
|
|
3361
3380
|
SET ${e("status")} = ${"pending"}
|
|
3362
3381
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
3363
3382
|
`);
|
|
3364
|
-
}),
|
|
3365
|
-
if (
|
|
3383
|
+
}), qo = (e, t) => t === void 0 ? e`DELETE FROM ${e(P)}`.pipe(A.asVoid) : e`DELETE FROM ${e(P)} WHERE ${e("runId")} = ${t}`.pipe(A.asVoid), Jo = (e) => Uo(e).pipe(A.map((e) => e.filter((e) => e.status === "started" || e.status === "added" || e.status === "applied").map((e) => JSON.parse(e.payload))), A.catchAll(() => A.succeed([]))), Yo = (e) => qo(e).pipe(A.catchAll(() => A.void)), Xo = (e, t, n) => A.gen(function* () {
|
|
3384
|
+
if (Ot(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
3366
3385
|
let r = n.op, a = (e) => i(e, t);
|
|
3367
3386
|
if (t === "sqlite" || t === "turso") {
|
|
3368
3387
|
if (!("table" in r)) return "clean";
|
|
3369
|
-
let n = `${r.table}${
|
|
3370
|
-
return (yield*
|
|
3388
|
+
let n = `${r.table}${Ct}`;
|
|
3389
|
+
return (yield* Lo(e, t, n)) ? ((yield* Lo(e, t, r.table)) ? yield* q(e, `DROP TABLE ${a(n)}`, "resume-repair") : yield* q(e, `ALTER TABLE ${a(n)} RENAME TO ${a(r.table)}`, "resume-repair"), yield* A.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
3371
3390
|
}
|
|
3372
3391
|
if (r.kind !== "alter-column-type") return "clean";
|
|
3373
|
-
let o = `${r.column}${
|
|
3374
|
-
return !l && !u ? "clean" : c && l && !u ? (yield*
|
|
3375
|
-
}),
|
|
3376
|
-
let o = process.hrtime.bigint(), s =
|
|
3392
|
+
let o = `${r.column}${wt}`, s = `${r.column}${Tt}`, c = yield* Lo(e, t, r.table, r.column), l = yield* Lo(e, t, r.table, o), u = yield* Lo(e, t, r.table, s), d = (e) => A.logWarning(`migration resume: ${e}`).pipe(A.annotateLogs({ scope: "voltro:migrate" }));
|
|
3393
|
+
return !l && !u ? "clean" : c && l && !u ? (yield* q(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(o)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${r.table}.${o}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* q(e, `ALTER TABLE ${a(r.table)} RENAME COLUMN ${a(o)} TO ${a(r.column)}`, "resume-repair"), yield* q(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : c && !l && u ? (yield* q(e, `ALTER TABLE ${a(r.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${r.table}.${s}'`), "applied") : yield* A.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${r.table}.${r.column}' left a shadow-swap state this resume cannot classify (column=${c}, ${o}=${l}, ${s}=${u}).\nNothing was changed. Inspect those three columns and reconcile them by hand — the data is in whichever of them is populated — then re-run the migration.`));
|
|
3394
|
+
}), Zo = (e, t, n, r = "fresh", a) => A.gen(function* () {
|
|
3395
|
+
let o = process.hrtime.bigint(), s = Mo(n.declared), c = t.op, l = N(e);
|
|
3377
3396
|
switch (c.kind) {
|
|
3378
3397
|
case "create-table": {
|
|
3379
3398
|
let t = yield* e.onDialectOrElse({
|
|
3380
|
-
mysql: () =>
|
|
3381
|
-
mssql: () => A.succeed(
|
|
3382
|
-
sqlite: () => A.succeed(
|
|
3383
|
-
orElse: () => A.succeed(
|
|
3399
|
+
mysql: () => V(e).pipe(A.map((e) => Na(c, e))),
|
|
3400
|
+
mssql: () => A.succeed(Ka(c)),
|
|
3401
|
+
sqlite: () => A.succeed(za(c)),
|
|
3402
|
+
orElse: () => A.succeed(Ea(c))
|
|
3384
3403
|
}), n = yield* e.onDialectOrElse({
|
|
3385
|
-
mysql: () => A.succeed([
|
|
3404
|
+
mysql: () => A.succeed([qi]),
|
|
3386
3405
|
orElse: () => A.succeed([])
|
|
3387
3406
|
});
|
|
3388
|
-
for (let r of t) yield*
|
|
3407
|
+
for (let r of t) yield* q(e, r, c.kind, n);
|
|
3389
3408
|
break;
|
|
3390
3409
|
}
|
|
3391
3410
|
case "drop-table": {
|
|
3392
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
3411
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Ya(c, n, e) : Ja(c, e);
|
|
3393
3412
|
yield* e.onDialectOrElse({
|
|
3394
|
-
mysql: () =>
|
|
3395
|
-
orElse: () =>
|
|
3413
|
+
mysql: () => q(e, r(W), c.kind),
|
|
3414
|
+
orElse: () => q(e, r(U), c.kind)
|
|
3396
3415
|
});
|
|
3397
3416
|
break;
|
|
3398
3417
|
}
|
|
3399
3418
|
case "drop-column": {
|
|
3400
3419
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
3401
3420
|
yield* e.onDialectOrElse({
|
|
3402
|
-
mysql: () =>
|
|
3403
|
-
sqlite: () =>
|
|
3404
|
-
orElse: () =>
|
|
3421
|
+
mysql: () => V(e).pipe(A.flatMap((r) => q(e, t ? ua(c, n, W) : ca(c, r), c.kind, t ? [] : [Ji]))),
|
|
3422
|
+
sqlite: () => q(e, t ? ua(c, n, U) : sa(c, U, !1), c.kind, t ? [] : [Yi]),
|
|
3423
|
+
orElse: () => q(e, t ? ua(c, n, U) : sa(c, U), c.kind)
|
|
3405
3424
|
});
|
|
3406
3425
|
break;
|
|
3407
3426
|
}
|
|
3408
3427
|
case "rename-column":
|
|
3409
3428
|
yield* e.onDialectOrElse({
|
|
3410
|
-
mysql: () =>
|
|
3411
|
-
mssql: () =>
|
|
3412
|
-
orElse: () =>
|
|
3429
|
+
mysql: () => q(e, la(c, W), c.kind),
|
|
3430
|
+
mssql: () => Po(e, c),
|
|
3431
|
+
orElse: () => q(e, la(c, U), c.kind)
|
|
3413
3432
|
});
|
|
3414
3433
|
break;
|
|
3415
3434
|
case "add-index":
|
|
3416
3435
|
yield* e.onDialectOrElse({
|
|
3417
|
-
sqlite: () =>
|
|
3418
|
-
mysql: () =>
|
|
3419
|
-
mssql: () =>
|
|
3420
|
-
orElse: () =>
|
|
3436
|
+
sqlite: () => q(e, eo(c, !1), c.kind),
|
|
3437
|
+
mysql: () => V(e).pipe(A.flatMap((t) => q(e, to(c, n.declared, t), c.kind, [qi]))),
|
|
3438
|
+
mssql: () => Y(e, [...po(c.table, c.index.columns, n.declared), fo(c)], c.kind),
|
|
3439
|
+
orElse: () => q(e, eo(c, t.classification === "online-required"), c.kind)
|
|
3421
3440
|
});
|
|
3422
3441
|
break;
|
|
3423
3442
|
case "drop-index":
|
|
3424
3443
|
yield* e.onDialectOrElse({
|
|
3425
|
-
mysql: () =>
|
|
3426
|
-
mssql: () =>
|
|
3427
|
-
orElse: () =>
|
|
3444
|
+
mysql: () => q(e, io(c), c.kind),
|
|
3445
|
+
mssql: () => q(e, ao(c), c.kind),
|
|
3446
|
+
orElse: () => q(e, ro(c), c.kind)
|
|
3428
3447
|
});
|
|
3429
3448
|
break;
|
|
3430
3449
|
case "rename-table":
|
|
3431
3450
|
yield* e.onDialectOrElse({
|
|
3432
|
-
mysql: () =>
|
|
3433
|
-
mssql: () =>
|
|
3434
|
-
orElse: () =>
|
|
3451
|
+
mysql: () => q(e, oo(c, W), c.kind),
|
|
3452
|
+
mssql: () => q(e, so(c), c.kind),
|
|
3453
|
+
orElse: () => q(e, oo(c, U), c.kind)
|
|
3435
3454
|
});
|
|
3436
3455
|
break;
|
|
3437
3456
|
case "rename-index":
|
|
3438
3457
|
yield* e.onDialectOrElse({
|
|
3439
|
-
mysql: () =>
|
|
3440
|
-
mssql: () =>
|
|
3441
|
-
orElse: () =>
|
|
3458
|
+
mysql: () => q(e, lo(c), c.kind),
|
|
3459
|
+
mssql: () => q(e, uo(c), c.kind),
|
|
3460
|
+
orElse: () => q(e, co(c), c.kind)
|
|
3442
3461
|
});
|
|
3443
3462
|
break;
|
|
3444
3463
|
case "add-unique":
|
|
3445
3464
|
yield* e.onDialectOrElse({
|
|
3446
|
-
mysql: () =>
|
|
3447
|
-
sqlite: () =>
|
|
3448
|
-
mssql: () =>
|
|
3449
|
-
orElse: () =>
|
|
3465
|
+
mysql: () => q(e, ho(c, n.declared), c.kind),
|
|
3466
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3467
|
+
mssql: () => Y(e, [...po(c.table, [c.column], n.declared), mo(c)], c.kind),
|
|
3468
|
+
orElse: () => q(e, mo(c), c.kind)
|
|
3450
3469
|
});
|
|
3451
3470
|
break;
|
|
3452
3471
|
case "drop-unique":
|
|
3453
3472
|
yield* e.onDialectOrElse({
|
|
3454
|
-
mysql: () =>
|
|
3455
|
-
sqlite: () =>
|
|
3456
|
-
orElse: () =>
|
|
3473
|
+
mysql: () => q(e, xo(c), c.kind),
|
|
3474
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3475
|
+
orElse: () => q(e, bo(c), c.kind)
|
|
3457
3476
|
});
|
|
3458
3477
|
break;
|
|
3459
3478
|
case "add-enum-value":
|
|
3460
3479
|
yield* e.onDialectOrElse({
|
|
3461
|
-
pg: () => c.enumName === void 0 ? A.die(/* @__PURE__ */ Error(`add-enum-value on postgres needs the type name for ${c.table}.${c.column}; the plan carries none.`)) :
|
|
3480
|
+
pg: () => c.enumName === void 0 ? A.die(/* @__PURE__ */ Error(`add-enum-value on postgres needs the type name for ${c.table}.${c.column}; the plan carries none.`)) : q(e, `ALTER TYPE ${i(c.enumName, "postgres")} ADD VALUE IF NOT EXISTS '${c.value.replace(/'/g, "''")}'`, c.kind),
|
|
3462
3481
|
mysql: () => {
|
|
3463
|
-
let t =
|
|
3464
|
-
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? A.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.`)) :
|
|
3482
|
+
let t = G(n.declared, c.table, c.column);
|
|
3483
|
+
return t === void 0 || t.enumValues === void 0 || t.enumValues.length === 0 ? A.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.`)) : A.flatMap(va(e, c.table, t, c.column), (t) => q(e, t, c.kind));
|
|
3465
3484
|
},
|
|
3466
3485
|
orElse: () => A.void
|
|
3467
3486
|
});
|
|
3468
3487
|
break;
|
|
3469
3488
|
case "add-unique-composite":
|
|
3470
3489
|
yield* e.onDialectOrElse({
|
|
3471
|
-
mysql: () =>
|
|
3472
|
-
sqlite: () =>
|
|
3473
|
-
mssql: () =>
|
|
3474
|
-
orElse: () =>
|
|
3490
|
+
mysql: () => q(e, _o(c, n.declared), c.kind),
|
|
3491
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3492
|
+
mssql: () => Y(e, [...po(c.table, c.fields, n.declared), go(c)], c.kind),
|
|
3493
|
+
orElse: () => q(e, go(c), c.kind)
|
|
3475
3494
|
});
|
|
3476
3495
|
break;
|
|
3477
3496
|
case "drop-unique-composite":
|
|
3478
3497
|
yield* e.onDialectOrElse({
|
|
3479
|
-
mysql: () =>
|
|
3480
|
-
sqlite: () =>
|
|
3481
|
-
orElse: () =>
|
|
3498
|
+
mysql: () => q(e, yo(c), c.kind),
|
|
3499
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3500
|
+
orElse: () => q(e, vo(c), c.kind)
|
|
3482
3501
|
});
|
|
3483
3502
|
break;
|
|
3484
3503
|
case "add-foreign-key":
|
|
3485
3504
|
yield* e.onDialectOrElse({
|
|
3486
|
-
mysql: () =>
|
|
3487
|
-
sqlite: () =>
|
|
3488
|
-
mssql: () =>
|
|
3489
|
-
orElse: () =>
|
|
3505
|
+
mysql: () => Y(e, So(c, W), c.kind),
|
|
3506
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3507
|
+
mssql: () => Y(e, So(c, K, Fa), c.kind),
|
|
3508
|
+
orElse: () => Y(e, So(c, U), c.kind)
|
|
3490
3509
|
});
|
|
3491
3510
|
break;
|
|
3492
3511
|
case "add-column": {
|
|
3493
|
-
let i =
|
|
3512
|
+
let i = Ao(c, t, s, yield* e.onDialectOrElse({
|
|
3494
3513
|
mysql: () => A.succeed("mariadb"),
|
|
3495
3514
|
mssql: () => A.succeed("mssql"),
|
|
3496
3515
|
sqlite: () => A.succeed("sqlite"),
|
|
3497
3516
|
orElse: () => A.succeed("postgres")
|
|
3498
3517
|
}));
|
|
3499
|
-
if (!(r === "resume" && (yield*
|
|
3518
|
+
if (!(r === "resume" && (yield* Lo(e, N(e), c.table, c.column.name)))) for (let t of i.pre) yield* q(e, t, c.kind);
|
|
3500
3519
|
let u = t.classification === "online-required" || i.batchSize !== void 0 || i.sleepMs !== void 0, d = A.gen(function* () {
|
|
3501
3520
|
if (i.backfillKind === "sql" && i.backfillSql) {
|
|
3502
3521
|
if (t.classification !== "online-required" && i.batchSize === void 0) yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${i.backfillSql}`;
|
|
3503
3522
|
else {
|
|
3504
3523
|
let t = i.batchSize ?? 5e3, n = i.sleepMs ?? 0, r, a = 0;
|
|
3505
3524
|
for (;;) {
|
|
3506
|
-
let o = r === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${
|
|
3525
|
+
let o = r === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${Io(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL AND ${e("id")} > ${r} ORDER BY ${e("id")} ${Io(e, t)}`;
|
|
3507
3526
|
if (o.length === 0) break;
|
|
3508
3527
|
let s = o.map((e) => e.id);
|
|
3509
3528
|
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${i.backfillSql} WHERE ${e("id")} IN ${e.in(s)}`, a += o.length, yield* A.logInfo(`backfill ${c.table}.${c.column.name}: ${a} rows`).pipe(A.annotateLogs({
|
|
@@ -3515,7 +3534,7 @@ BEGIN
|
|
|
3515
3534
|
} else if (i.backfillKind === "js" && i.backfillJs) {
|
|
3516
3535
|
let t = i.batchSize ?? 1e3, r = i.sleepMs ?? 0, a = n.declared.find((e) => e.tableName === c.table), o, s = 0;
|
|
3517
3536
|
for (;;) {
|
|
3518
|
-
let n = o === void 0 ? yield* e`SELECT * FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${
|
|
3537
|
+
let n = o === void 0 ? yield* e`SELECT * FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL ORDER BY ${e("id")} ${Io(e, t)}` : yield* e`SELECT * FROM ${e(c.table)} WHERE ${e(c.column.name)} IS NULL AND ${e("id")} > ${o} ORDER BY ${e("id")} ${Io(e, t)}`;
|
|
3519
3538
|
if (n.length === 0) break;
|
|
3520
3539
|
let u = a === void 0 ? n : p(n, a, l);
|
|
3521
3540
|
for (let t of u) {
|
|
@@ -3523,7 +3542,7 @@ BEGIN
|
|
|
3523
3542
|
try: () => Promise.resolve(i.backfillJs(t)),
|
|
3524
3543
|
catch: (e) => e
|
|
3525
3544
|
}).pipe(A.orDie);
|
|
3526
|
-
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${
|
|
3545
|
+
yield* e`UPDATE ${e(c.table)} SET ${e(c.column.name)} = ${Fo(n, c.column, l)} WHERE ${e("id")} = ${t.id}`;
|
|
3527
3546
|
}
|
|
3528
3547
|
s += u.length, yield* A.logInfo(`backfill ${c.table}.${c.column.name}: ${s} rows processed`).pipe(A.annotateLogs({
|
|
3529
3548
|
scope: "voltro:migrate",
|
|
@@ -3533,8 +3552,8 @@ BEGIN
|
|
|
3533
3552
|
}
|
|
3534
3553
|
}
|
|
3535
3554
|
}), f = A.gen(function* () {
|
|
3536
|
-
for (let t of i.post) yield*
|
|
3537
|
-
if (O(l) && (i.uniquePending === !0 || i.backfillKind !== void 0 && !c.column.nullable)) yield*
|
|
3555
|
+
for (let t of i.post) yield* q(e, t, c.kind);
|
|
3556
|
+
if (O(l) && (i.uniquePending === !0 || i.backfillKind !== void 0 && !c.column.nullable)) yield* J(e, c.table, n.declared, c.kind);
|
|
3538
3557
|
else if (i.uniquePending === !0) {
|
|
3539
3558
|
let t = {
|
|
3540
3559
|
kind: "add-unique",
|
|
@@ -3542,9 +3561,9 @@ BEGIN
|
|
|
3542
3561
|
column: c.column.name
|
|
3543
3562
|
};
|
|
3544
3563
|
yield* e.onDialectOrElse({
|
|
3545
|
-
mysql: () =>
|
|
3546
|
-
mssql: () =>
|
|
3547
|
-
orElse: () =>
|
|
3564
|
+
mysql: () => q(e, ho(t, n.declared), c.kind),
|
|
3565
|
+
mssql: () => Y(e, [...po(c.table, [c.column.name], n.declared), mo(t)], c.kind),
|
|
3566
|
+
orElse: () => q(e, mo(t), c.kind)
|
|
3548
3567
|
});
|
|
3549
3568
|
}
|
|
3550
3569
|
});
|
|
@@ -3565,47 +3584,47 @@ BEGIN
|
|
|
3565
3584
|
case "alter-column-nullability":
|
|
3566
3585
|
yield* e.onDialectOrElse({
|
|
3567
3586
|
mysql: () => {
|
|
3568
|
-
let t =
|
|
3569
|
-
return t ?
|
|
3587
|
+
let t = G(n.declared, c.table, c.column);
|
|
3588
|
+
return t ? A.flatMap(va(e, c.table, t, c.column, c.toNullable), (t) => q(e, t, c.kind)) : A.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.`));
|
|
3570
3589
|
},
|
|
3571
3590
|
mssql: () => {
|
|
3572
|
-
let t =
|
|
3573
|
-
return t ?
|
|
3591
|
+
let t = G(n.declared, c.table, c.column);
|
|
3592
|
+
return t ? q(e, Ha(t, c.column, c.table, c.toNullable), c.kind) : A.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${c.table}.${c.column}'.`));
|
|
3574
3593
|
},
|
|
3575
|
-
sqlite: () =>
|
|
3576
|
-
orElse: () =>
|
|
3594
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3595
|
+
orElse: () => q(e, `ALTER TABLE ${U(c.table)} ALTER COLUMN ${U(c.column)} ${c.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, c.kind)
|
|
3577
3596
|
});
|
|
3578
3597
|
break;
|
|
3579
3598
|
case "alter-column-default": {
|
|
3580
|
-
let t =
|
|
3599
|
+
let t = ma(n.declared, c.table, c.column), r = G(n.declared, c.table, c.column), i = (e) => c.hasDefault && r !== void 0 && fa(r, e) ? r : void 0;
|
|
3581
3600
|
yield* e.onDialectOrElse({
|
|
3582
3601
|
mysql: () => {
|
|
3583
3602
|
let n = i("mariadb");
|
|
3584
|
-
return
|
|
3603
|
+
return A.flatMap(n ? va(e, c.table, n, c.column) : A.succeed(da(c, W, (e) => ya(e, t))), (t) => q(e, t, c.kind));
|
|
3585
3604
|
},
|
|
3586
3605
|
mssql: () => {
|
|
3587
3606
|
let t = i("mssql");
|
|
3588
|
-
return
|
|
3607
|
+
return q(e, Ua(c, t ? Ha(t, c.column, c.table) : void 0), c.kind);
|
|
3589
3608
|
},
|
|
3590
|
-
sqlite: () =>
|
|
3591
|
-
orElse: () =>
|
|
3609
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3610
|
+
orElse: () => q(e, da(c, U, (e) => xa(e, t)), c.kind)
|
|
3592
3611
|
});
|
|
3593
3612
|
break;
|
|
3594
3613
|
}
|
|
3595
3614
|
case "alter-column-type": {
|
|
3596
|
-
let r =
|
|
3615
|
+
let r = ra(ma(n.declared, c.table, c.column) ?? { type: c.to }), i = c.using ? ` USING ${c.using}` : "";
|
|
3597
3616
|
if (t.classification !== "online-required") {
|
|
3598
3617
|
yield* e.onDialectOrElse({
|
|
3599
3618
|
mysql: () => {
|
|
3600
|
-
let t =
|
|
3601
|
-
return t ?
|
|
3619
|
+
let t = G(n.declared, c.table, c.column);
|
|
3620
|
+
return t ? A.flatMap(va(e, c.table, t, c.column), (t) => q(e, t, c.kind)) : A.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.`));
|
|
3602
3621
|
},
|
|
3603
3622
|
mssql: () => {
|
|
3604
|
-
let t =
|
|
3605
|
-
return t ?
|
|
3623
|
+
let t = G(n.declared, c.table, c.column);
|
|
3624
|
+
return t ? q(e, Ha(t, c.column, c.table), c.kind) : A.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${c.table}.${c.column}'.`));
|
|
3606
3625
|
},
|
|
3607
|
-
sqlite: () =>
|
|
3608
|
-
orElse: () =>
|
|
3626
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3627
|
+
orElse: () => q(e, `ALTER TABLE ${U(c.table)} ALTER COLUMN ${U(c.column)} TYPE ${r}${i};`, c.kind)
|
|
3609
3628
|
});
|
|
3610
3629
|
break;
|
|
3611
3630
|
}
|
|
@@ -3614,53 +3633,53 @@ BEGIN
|
|
|
3614
3633
|
orElse: () => A.void
|
|
3615
3634
|
});
|
|
3616
3635
|
let a = `${c.column}__shadow`, o = `${c.column}__old`;
|
|
3617
|
-
yield* e.unsafe(`ALTER TABLE ${
|
|
3618
|
-
let s = c.using ??
|
|
3636
|
+
yield* e.unsafe(`ALTER TABLE ${U(c.table)} ADD COLUMN ${U(a)} ${r}`);
|
|
3637
|
+
let s = c.using ?? U(c.column), l;
|
|
3619
3638
|
for (;;) {
|
|
3620
|
-
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${
|
|
3639
|
+
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${Io(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(c.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${Io(e, 5e3)}`;
|
|
3621
3640
|
if (t.length === 0) break;
|
|
3622
|
-
yield* e.unsafe(`UPDATE ${
|
|
3641
|
+
yield* e.unsafe(`UPDATE ${U(c.table)} SET ${U(a)} = ${s} WHERE ${U(c.column)} IS NOT NULL AND ${U(a)} IS NULL AND ${U("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
3623
3642
|
}
|
|
3624
|
-
yield* A.logInfo(`alter-column-type shadow ${c.table}.${c.column}: shadow populated`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${
|
|
3643
|
+
yield* A.logInfo(`alter-column-type shadow ${c.table}.${c.column}: shadow populated`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${U(c.table)} RENAME COLUMN ${U(c.column)} TO ${U(o)}`), yield* e.unsafe(`ALTER TABLE ${U(c.table)} RENAME COLUMN ${U(a)} TO ${U(c.column)}`), yield* e.unsafe(`ALTER TABLE ${U(c.table)} DROP COLUMN ${U(o)}`);
|
|
3625
3644
|
break;
|
|
3626
3645
|
}
|
|
3627
3646
|
case "drop-foreign-key":
|
|
3628
3647
|
yield* e.onDialectOrElse({
|
|
3629
|
-
mysql: () =>
|
|
3630
|
-
sqlite: () =>
|
|
3631
|
-
orElse: () =>
|
|
3648
|
+
mysql: () => q(e, To(c), c.kind),
|
|
3649
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3650
|
+
orElse: () => q(e, wo(c), c.kind)
|
|
3632
3651
|
});
|
|
3633
3652
|
break;
|
|
3634
3653
|
case "add-check":
|
|
3635
3654
|
yield* e.onDialectOrElse({
|
|
3636
|
-
mysql: () =>
|
|
3637
|
-
sqlite: () =>
|
|
3638
|
-
orElse: () =>
|
|
3655
|
+
mysql: () => q(e, Eo(c, W), c.kind),
|
|
3656
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3657
|
+
orElse: () => q(e, Eo(c, U), c.kind)
|
|
3639
3658
|
});
|
|
3640
3659
|
break;
|
|
3641
3660
|
case "convert-charset":
|
|
3642
3661
|
yield* e.onDialectOrElse({
|
|
3643
3662
|
mysql: () => A.gen(function* () {
|
|
3644
|
-
let { drops: t, rewrite: r, restores: i } =
|
|
3645
|
-
for (let n of t) yield*
|
|
3646
|
-
yield*
|
|
3647
|
-
for (let t of i) yield*
|
|
3663
|
+
let { drops: t, rewrite: r, restores: i } = Ma(c, n.declared, yield* _a(e, c.table));
|
|
3664
|
+
for (let n of t) yield* q(e, n, c.kind, [Xi]);
|
|
3665
|
+
yield* q(e, r, c.kind);
|
|
3666
|
+
for (let t of i) yield* q(e, t, c.kind, [Zi]);
|
|
3648
3667
|
}),
|
|
3649
3668
|
orElse: () => A.dieMessage("convert-charset requires MySQL or MariaDB")
|
|
3650
3669
|
});
|
|
3651
3670
|
break;
|
|
3652
3671
|
case "reconcile-json-check": {
|
|
3653
|
-
let t =
|
|
3672
|
+
let t = K(c.column), n = c.validation === "value" ? kt(t) : `(${t} IS NULL OR ISJSON(${t}) = 1)`;
|
|
3654
3673
|
yield* e.onDialectOrElse({
|
|
3655
|
-
mssql: () =>
|
|
3674
|
+
mssql: () => Y(e, [...c.dropConstraints.map((e) => `ALTER TABLE ${K(c.table)} DROP CONSTRAINT ${K(e)}`), `ALTER TABLE ${K(c.table)} WITH CHECK ADD CHECK ${n}`], c.kind),
|
|
3656
3675
|
orElse: () => A.dieMessage("reconcile-json-check requires SQL Server")
|
|
3657
3676
|
});
|
|
3658
3677
|
break;
|
|
3659
3678
|
}
|
|
3660
3679
|
case "drop-check": yield* e.onDialectOrElse({
|
|
3661
|
-
mysql: () =>
|
|
3662
|
-
sqlite: () =>
|
|
3663
|
-
orElse: () =>
|
|
3680
|
+
mysql: () => ko(e, c, n.declared),
|
|
3681
|
+
sqlite: () => J(e, c.table, n.declared, c.kind),
|
|
3682
|
+
orElse: () => q(e, Do(c), c.kind)
|
|
3664
3683
|
});
|
|
3665
3684
|
}
|
|
3666
3685
|
return {
|
|
@@ -3668,7 +3687,7 @@ BEGIN
|
|
|
3668
3687
|
status: "applied",
|
|
3669
3688
|
durationMs: Number((process.hrtime.bigint() - o) / 1000000n)
|
|
3670
3689
|
};
|
|
3671
|
-
}),
|
|
3690
|
+
}), Qo = (e, t, n, r) => A.gen(function* () {
|
|
3672
3691
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
3673
3692
|
if (i.length > 1) return yield* A.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 \`${P}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
3674
3693
|
let a = i[0], o = [...r].map((e) => ({
|
|
@@ -3678,23 +3697,23 @@ BEGIN
|
|
|
3678
3697
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
3679
3698
|
if (c > 1) return yield* A.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 \`${P}\` by hand before re-running.`));
|
|
3680
3699
|
let l = o.filter((e) => e.status === "added");
|
|
3681
|
-
if (yield* A.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} ${
|
|
3700
|
+
if (yield* A.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} ${bt(s.planned.op)}` : ""}${l.length > 0 ? `, ${l.length} column(s) added with the backfill still owed` : ""}`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
3682
3701
|
kind: "discard",
|
|
3683
3702
|
runId: a,
|
|
3684
3703
|
why: "no operation had started — no DDL ran"
|
|
3685
3704
|
};
|
|
3686
|
-
let u = s ? yield*
|
|
3705
|
+
let u = s ? yield* Xo(e, t, s.planned) : "clean", d = r[0].planFingerprint;
|
|
3687
3706
|
if (d !== n.toFingerprint) return {
|
|
3688
3707
|
kind: "discard",
|
|
3689
3708
|
runId: a,
|
|
3690
3709
|
why: `the declared schema changed since the interruption (recorded target ${d.slice(0, 12)}…, current ${n.toFingerprint.slice(0, 12)}…) — applying the freshly-diffed plan instead`
|
|
3691
3710
|
};
|
|
3692
|
-
let f = (e) => e.status === "applied" ? !1 : s && e.index === s.index && u !== "clean" ? u === "outstanding" :
|
|
3711
|
+
let f = (e) => e.status === "applied" ? !1 : s && e.index === s.index && u !== "clean" ? u === "outstanding" : St(n, e.planned.op), p = o.filter(f), m = o.filter((e) => e.status !== "applied" && !f(e));
|
|
3693
3712
|
return p.length === 0 ? {
|
|
3694
3713
|
kind: "discard",
|
|
3695
3714
|
runId: a,
|
|
3696
3715
|
why: "every recorded operation had already taken effect"
|
|
3697
|
-
} : (yield*
|
|
3716
|
+
} : (yield* Ko(e, a, p.map((e) => e.index), m.map((e) => e.index)), yield* A.logWarning(`migration resume: continuing run ${a} — replaying ${p.length} operation(s), ${o.length - p.length} already applied`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), {
|
|
3698
3717
|
kind: "resume",
|
|
3699
3718
|
runId: a,
|
|
3700
3719
|
ops: p.map((e) => ({
|
|
@@ -3702,7 +3721,7 @@ BEGIN
|
|
|
3702
3721
|
planned: e.planned
|
|
3703
3722
|
}))
|
|
3704
3723
|
});
|
|
3705
|
-
}),
|
|
3724
|
+
}), $o = (e, t, n) => A.gen(function* () {
|
|
3706
3725
|
for (let r of t.operations) {
|
|
3707
3726
|
let a = r.op;
|
|
3708
3727
|
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 && [
|
|
@@ -3713,7 +3732,7 @@ BEGIN
|
|
|
3713
3732
|
let o = a.index.columns.map((e) => e.startsWith("(") ? e : i(e, n)), s = n === "mssql" ? "" : o.map((e) => ` AND ${e} IS NOT NULL`).join(""), c = n === "mssql" ? "SELECT TOP (1) 1" : "SELECT 1", l = n === "mssql" ? "" : " LIMIT 1";
|
|
3714
3733
|
if ((yield* e.unsafe(`${c} FROM ${i(a.table, n)} WHERE (${a.index.where})${s} GROUP BY ${o.join(", ")} HAVING COUNT(*) > 1${l}`)).length > 0) return yield* A.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.`));
|
|
3715
3734
|
}
|
|
3716
|
-
}),
|
|
3735
|
+
}), es = (e) => {
|
|
3717
3736
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
3718
3737
|
return [
|
|
3719
3738
|
t.kind,
|
|
@@ -3722,13 +3741,13 @@ BEGIN
|
|
|
3722
3741
|
n("name"),
|
|
3723
3742
|
n("to")
|
|
3724
3743
|
].join("\0");
|
|
3725
|
-
},
|
|
3744
|
+
}, ts = (e, t, n) => A.acquireUseRelease(ft(e, { schema: n.lockSchema }), () => ns(e, t, n), (e) => e.release.pipe(A.orDie)), ns = (e, t, n) => A.gen(function* () {
|
|
3726
3745
|
let r = t.operations.filter((e) => e.blocked);
|
|
3727
3746
|
if (r.length > 0) return yield* A.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
3728
|
-
let i = Date.now(), a = [], o = N(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) =>
|
|
3747
|
+
let i = Date.now(), a = [], o = N(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => es(e))), l = {
|
|
3729
3748
|
...s,
|
|
3730
3749
|
operations: s.operations.map((e) => {
|
|
3731
|
-
if (!e.blocked || !c.has(
|
|
3750
|
+
if (!e.blocked || !c.has(es(e))) return e;
|
|
3732
3751
|
let { blocked: t, ...n } = e;
|
|
3733
3752
|
return n;
|
|
3734
3753
|
})
|
|
@@ -3736,54 +3755,54 @@ BEGIN
|
|
|
3736
3755
|
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield* A.logInfo(`migration: re-planned under the lock — ${t.operations.length} operation(s) became ${l.operations.length}. Another writer changed the schema while this plan waited.`).pipe(A.annotateLogs({ scope: "voltro:migrate" })));
|
|
3737
3756
|
let u = l.operations.filter((e) => e.blocked);
|
|
3738
3757
|
if (u.length > 0) return yield* A.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — re-planning under the migration lock found ${u.length} blocked operation(s). Run \`voltro db plan\` to see the fixes.`));
|
|
3739
|
-
let d =
|
|
3740
|
-
d && (yield*
|
|
3741
|
-
let f =
|
|
3742
|
-
f && (yield*
|
|
3743
|
-
let p =
|
|
3744
|
-
p && (yield*
|
|
3745
|
-
let m =
|
|
3758
|
+
let d = un(n.declared, o);
|
|
3759
|
+
d && (yield* q(e, d, "extensions"));
|
|
3760
|
+
let f = _n(n.declared, o);
|
|
3761
|
+
f && (yield* q(e, f, "enum-types"));
|
|
3762
|
+
let p = gn(n.declared, o);
|
|
3763
|
+
p && (yield* q(e, p, "enum-types"));
|
|
3764
|
+
let m = _t(o) === "plan-transactional", g = m ? l.operations.filter((e) => e.classification !== "online-required") : [], _ = m ? l.operations.filter((e) => e.classification === "online-required") : l.operations, v = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, y = _.map((e, t) => ({
|
|
3746
3765
|
index: t,
|
|
3747
3766
|
planned: e
|
|
3748
3767
|
})), b = "fresh";
|
|
3749
|
-
yield*
|
|
3750
|
-
let x = yield*
|
|
3768
|
+
yield* $o(e, l, o), yield* Ro(e, o);
|
|
3769
|
+
let x = yield* Uo(e);
|
|
3751
3770
|
if (x.length > 0) {
|
|
3752
|
-
let t = yield*
|
|
3753
|
-
t.kind === "resume" ? (v = t.runId, y = t.ops, b = "resume") : (yield* A.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), yield*
|
|
3771
|
+
let t = yield* Qo(e, o, l, x);
|
|
3772
|
+
t.kind === "resume" ? (v = t.runId, y = t.ops, b = "resume") : (yield* A.logWarning(`migration resume: discarding the ledger of run ${t.runId} — ${t.why}`).pipe(A.annotateLogs({ scope: "voltro:migrate" })), yield* qo(e, t.runId));
|
|
3754
3773
|
}
|
|
3755
|
-
b === "fresh" && y.length > 0 && (yield*
|
|
3774
|
+
b === "fresh" && y.length > 0 && (yield* Wo(e, v, l.toFingerprint, y)), g.length > 0 && (yield* Qi(e, A.gen(function* () {
|
|
3756
3775
|
let e = yield* j.SqlClient, t = [], r = () => A.gen(function* () {
|
|
3757
3776
|
for (let e of t.splice(0)) yield* e.data, yield* e.after;
|
|
3758
3777
|
});
|
|
3759
|
-
for (let i of g)
|
|
3778
|
+
for (let i of g) jo.has(i.op.kind) && t.length > 0 && (yield* r()), a.push(yield* Zo(e, i, n, "fresh", (e) => t.push(e)));
|
|
3760
3779
|
yield* r();
|
|
3761
3780
|
})));
|
|
3762
3781
|
let S = [], C = () => A.gen(function* () {
|
|
3763
3782
|
let t = S.splice(0);
|
|
3764
3783
|
if (t.length !== 0) {
|
|
3765
|
-
yield*
|
|
3784
|
+
yield* Qi(e, A.gen(function* () {
|
|
3766
3785
|
for (let e of t) yield* e.data;
|
|
3767
3786
|
}));
|
|
3768
3787
|
for (let n of t) yield* n.after, a.push({
|
|
3769
3788
|
op: n.op,
|
|
3770
3789
|
status: "applied",
|
|
3771
3790
|
durationMs: Number(process.hrtime.bigint() - n.startedAt) / 1e6
|
|
3772
|
-
}), yield*
|
|
3791
|
+
}), yield* Go(e, v, n.index, "applied", Number(process.hrtime.bigint() - n.startedAt) / 1e6);
|
|
3773
3792
|
}
|
|
3774
3793
|
});
|
|
3775
3794
|
for (let { index: t, planned: r } of y) {
|
|
3776
|
-
|
|
3777
|
-
let i = a.length, o = process.hrtime.bigint(), s = yield*
|
|
3795
|
+
jo.has(r.op.kind) && S.length > 0 && (yield* C()), yield* Go(e, v, t, "started");
|
|
3796
|
+
let i = a.length, o = process.hrtime.bigint(), s = yield* Zo(e, r, n, b, (e) => S.push({
|
|
3778
3797
|
...e,
|
|
3779
3798
|
index: t,
|
|
3780
3799
|
startedAt: o
|
|
3781
3800
|
})).pipe(A.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${y.length + g.length} operation(s) applied before this one${g.length > 0 ? ` (${g.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`) })));
|
|
3782
3801
|
if (s.deferred === !0) {
|
|
3783
|
-
yield*
|
|
3802
|
+
yield* Go(e, v, t, "added");
|
|
3784
3803
|
continue;
|
|
3785
3804
|
}
|
|
3786
|
-
a.push(s), yield*
|
|
3805
|
+
a.push(s), yield* Go(e, v, t, "applied", s.durationMs);
|
|
3787
3806
|
}
|
|
3788
3807
|
yield* C();
|
|
3789
3808
|
let w = yield* n.replan(e);
|
|
@@ -3791,23 +3810,23 @@ BEGIN
|
|
|
3791
3810
|
let e = (e) => "column" in e ? typeof e.column == "string" ? `.${e.column}` : `.${String(e.column.name ?? "")}` : "", t = w.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` : "");
|
|
3792
3811
|
return yield* A.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 ${w.operations.length}:\n${t}${w.operations.length > 10 ? `\n … and ${w.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."));
|
|
3793
3812
|
}
|
|
3794
|
-
let T = a.filter((e) => e.status === "applied").length, E = Date.now() - i, D = v, ee = (/* @__PURE__ */ new Date()).toISOString(),
|
|
3813
|
+
let T = a.filter((e) => e.status === "applied").length, E = Date.now() - i, D = v, ee = (/* @__PURE__ */ new Date()).toISOString(), te = yield* H(e, ee), O = [...g, ...y.map((e) => e.planned)];
|
|
3795
3814
|
yield* e`
|
|
3796
3815
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3797
3816
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
3798
3817
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
3799
3818
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
3800
3819
|
VALUES
|
|
3801
|
-
(${D}, ${l.toFingerprint}, ${w.fromFingerprint}, ${JSON.stringify(
|
|
3820
|
+
(${D}, ${l.toFingerprint}, ${w.fromFingerprint}, ${JSON.stringify(O)},
|
|
3802
3821
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3803
|
-
${E}, ${
|
|
3804
|
-
`, yield*
|
|
3805
|
-
let
|
|
3806
|
-
return yield* A.promise(() => h({ changedTables:
|
|
3822
|
+
${E}, ${te}, ${n.notes ?? null})
|
|
3823
|
+
`, yield* qo(e, v);
|
|
3824
|
+
let ne = [...new Set(O.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
3825
|
+
return yield* A.promise(() => h({ changedTables: ne }).catch(() => {})), {
|
|
3807
3826
|
id: D,
|
|
3808
3827
|
appliedAt: ee,
|
|
3809
3828
|
fingerprint: l.toFingerprint,
|
|
3810
|
-
operations:
|
|
3829
|
+
operations: O,
|
|
3811
3830
|
appliedBy: n.appliedBy,
|
|
3812
3831
|
environment: n.environment,
|
|
3813
3832
|
durationMs: E,
|
|
@@ -3815,7 +3834,7 @@ BEGIN
|
|
|
3815
3834
|
source: n.source,
|
|
3816
3835
|
...n.notes ? { notes: n.notes } : {}
|
|
3817
3836
|
};
|
|
3818
|
-
}),
|
|
3837
|
+
}), rs = (e, t) => {
|
|
3819
3838
|
switch (t.kind) {
|
|
3820
3839
|
case "drop-foreign-key": return {
|
|
3821
3840
|
...e,
|
|
@@ -3847,38 +3866,38 @@ BEGIN
|
|
|
3847
3866
|
...e.primaryKey === void 0 ? {} : { primaryKey: e.primaryKey.map((e) => e === t.from ? t.to : e) }
|
|
3848
3867
|
};
|
|
3849
3868
|
}
|
|
3850
|
-
},
|
|
3851
|
-
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? A.void :
|
|
3869
|
+
}, X = (e, t, n) => {
|
|
3870
|
+
let r = n.tables.find((e) => e.name === t.table), i = () => r === void 0 ? A.void : No(e, t.table, Va(rs(r, t)), t.kind);
|
|
3852
3871
|
switch (t.kind) {
|
|
3853
3872
|
case "drop-foreign-key": return e.onDialectOrElse({
|
|
3854
|
-
mysql: () =>
|
|
3873
|
+
mysql: () => q(e, To(t), t.kind),
|
|
3855
3874
|
sqlite: i,
|
|
3856
|
-
orElse: () =>
|
|
3875
|
+
orElse: () => q(e, wo(t), t.kind)
|
|
3857
3876
|
});
|
|
3858
3877
|
case "drop-index": return e.onDialectOrElse({
|
|
3859
|
-
mysql: () =>
|
|
3860
|
-
mssql: () =>
|
|
3861
|
-
orElse: () =>
|
|
3878
|
+
mysql: () => q(e, io(t), t.kind),
|
|
3879
|
+
mssql: () => q(e, ao(t), t.kind),
|
|
3880
|
+
orElse: () => q(e, ro(t), t.kind)
|
|
3862
3881
|
});
|
|
3863
3882
|
case "drop-column": return e.onDialectOrElse({
|
|
3864
|
-
mysql: () =>
|
|
3883
|
+
mysql: () => V(e).pipe(A.flatMap((n) => q(e, ca(t, n), t.kind, [Ji]))),
|
|
3865
3884
|
sqlite: i,
|
|
3866
|
-
orElse: () =>
|
|
3885
|
+
orElse: () => q(e, sa(t, U), t.kind)
|
|
3867
3886
|
});
|
|
3868
3887
|
case "rename-column": return e.onDialectOrElse({
|
|
3869
|
-
mysql: () =>
|
|
3870
|
-
mssql: () =>
|
|
3871
|
-
orElse: () =>
|
|
3888
|
+
mysql: () => q(e, la(t, W), t.kind),
|
|
3889
|
+
mssql: () => Po(e, t),
|
|
3890
|
+
orElse: () => q(e, la(t, U), t.kind)
|
|
3872
3891
|
});
|
|
3873
3892
|
}
|
|
3874
|
-
},
|
|
3893
|
+
}, is = (e, t, n) => Zo(e, t, { declared: n }), as = (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"), os = (e) => e`
|
|
3875
3894
|
SELECT fingerprint
|
|
3876
3895
|
FROM _voltro_migration_plans
|
|
3877
3896
|
ORDER BY ${e("appliedAt")} DESC
|
|
3878
3897
|
LIMIT 1
|
|
3879
|
-
`.pipe(A.map((e) => e.length > 0 ? e[0].fingerprint : void 0), A.catchAll(() => A.succeed(void 0))),
|
|
3880
|
-
if ((yield*
|
|
3881
|
-
let r = `plan_${Date.now().toString(36)}`, i = yield*
|
|
3898
|
+
`.pipe(A.map((e) => e.length > 0 ? e[0].fingerprint : void 0), A.catchAll(() => A.succeed(void 0))), ss = (e, t, n) => A.gen(function* () {
|
|
3899
|
+
if ((yield* os(e)) === t.toFingerprint) return "already-current";
|
|
3900
|
+
let r = `plan_${Date.now().toString(36)}`, i = yield* H(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3882
3901
|
return yield* e`
|
|
3883
3902
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3884
3903
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -3889,8 +3908,8 @@ BEGIN
|
|
|
3889
3908
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3890
3909
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3891
3910
|
`, "recorded";
|
|
3892
|
-
}).pipe(A.catchAll(() => A.succeed("already-current"))),
|
|
3893
|
-
let r = L(
|
|
3911
|
+
}).pipe(A.catchAll(() => A.succeed("already-current"))), cs = (e, t, n) => A.gen(function* () {
|
|
3912
|
+
let r = L(Tr(t, N(e), { charset: n.charset })), i = yield* os(e);
|
|
3894
3913
|
return i === r ? {
|
|
3895
3914
|
kind: "up-to-date",
|
|
3896
3915
|
fingerprint: r
|
|
@@ -3899,23 +3918,23 @@ BEGIN
|
|
|
3899
3918
|
expected: r,
|
|
3900
3919
|
...i === void 0 ? {} : { actual: i }
|
|
3901
3920
|
};
|
|
3902
|
-
}),
|
|
3921
|
+
}), ls = [
|
|
3903
3922
|
"pgeagertest_",
|
|
3904
3923
|
"mig_e2e_",
|
|
3905
3924
|
"mig_test_",
|
|
3906
3925
|
"mysqleagertest_",
|
|
3907
3926
|
"mssqleagertest_",
|
|
3908
3927
|
"sqliteeagertest_"
|
|
3909
|
-
],
|
|
3928
|
+
], us = (e) => ls.some((t) => e.startsWith(t)), ds = (e, t) => A.gen(function* () {
|
|
3910
3929
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3911
|
-
let n = t.filter((e) =>
|
|
3930
|
+
let n = t.filter((e) => us(e.name)).map((e) => e.name);
|
|
3912
3931
|
if (n.length === 0) return [];
|
|
3913
3932
|
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(A.catchAll(() => A.void));
|
|
3914
3933
|
return n;
|
|
3915
|
-
}),
|
|
3934
|
+
}), fs = () => {
|
|
3916
3935
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3917
3936
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3918
|
-
},
|
|
3937
|
+
}, ps = (e) => {
|
|
3919
3938
|
if (e === void 0) return;
|
|
3920
3939
|
let t = e.trim();
|
|
3921
3940
|
if (t === "") return;
|
|
@@ -3925,56 +3944,56 @@ BEGIN
|
|
|
3925
3944
|
kind: "tables",
|
|
3926
3945
|
tables: new Set(n)
|
|
3927
3946
|
} : void 0;
|
|
3928
|
-
},
|
|
3947
|
+
}, ms = (e) => typeof e.table == "string" ? e.table : void 0, hs = (e, t = { kind: "all" }) => ({
|
|
3929
3948
|
...e,
|
|
3930
3949
|
operations: e.operations.map((e) => {
|
|
3931
3950
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3932
3951
|
if (t?.kind === "tables") {
|
|
3933
|
-
let n =
|
|
3952
|
+
let n = ms(e.op);
|
|
3934
3953
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3935
3954
|
}
|
|
3936
3955
|
let { blocked: n, ...r } = e;
|
|
3937
3956
|
return r;
|
|
3938
3957
|
})
|
|
3939
|
-
}),
|
|
3940
|
-
let t =
|
|
3958
|
+
}), gs = (e, t, n) => t === "postgres" ? Dr(e, n).pipe(A.flatMap((e) => {
|
|
3959
|
+
let t = Or(e);
|
|
3941
3960
|
return t === void 0 ? A.void : A.logWarning(`auto-migrate: ${t}`).pipe(A.annotateLogs({ scope: "voltro:migrate" }));
|
|
3942
|
-
}), A.catchAll(() => A.void)) : A.void,
|
|
3961
|
+
}), A.catchAll(() => A.void)) : A.void, _s = (e, t, n) => A.gen(function* () {
|
|
3943
3962
|
let i = N(e), a = t;
|
|
3944
3963
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3945
|
-
let t = L(
|
|
3946
|
-
if ((yield*
|
|
3964
|
+
let t = L(Tr(a, i, { charset: n.charset }));
|
|
3965
|
+
if ((yield* os(e)) === t) return yield* gs(e, i, a), {
|
|
3947
3966
|
kind: "up-to-date",
|
|
3948
3967
|
fingerprint: t
|
|
3949
3968
|
};
|
|
3950
3969
|
}
|
|
3951
|
-
let s = yield*
|
|
3970
|
+
let s = yield* Bi(e), c = yield* ds(e, s.tables);
|
|
3952
3971
|
c.length > 0 && (yield* A.logInfo(`auto-migrate: reaped ${c.length} test-fixture leftover(s)`).pipe(A.annotateLogs({
|
|
3953
3972
|
scope: "voltro:migrate",
|
|
3954
3973
|
count: c.length
|
|
3955
|
-
})), s = yield*
|
|
3974
|
+
})), s = yield* Bi(e));
|
|
3956
3975
|
{
|
|
3957
|
-
let e = n.softDropRetentionDays ?? 7, t =
|
|
3976
|
+
let e = n.softDropRetentionDays ?? 7, t = te(s, { retentionDays: e });
|
|
3958
3977
|
t.length > 0 && (yield* A.logWarning(`auto-migrate: ${r(t, e)}`).pipe(A.annotateLogs({
|
|
3959
3978
|
scope: "voltro:migrate",
|
|
3960
3979
|
snapshots: t.map((e) => e.name)
|
|
3961
3980
|
})));
|
|
3962
3981
|
}
|
|
3963
|
-
let l = new Set(t.map((e) => e.tableName)), u = (e) => o(e, l), d =
|
|
3982
|
+
let l = new Set(t.map((e) => e.tableName)), u = (e) => o(e, l), d = ci({
|
|
3964
3983
|
declared: a,
|
|
3965
3984
|
live: { tables: u(s.tables) },
|
|
3966
3985
|
dialect: i,
|
|
3967
3986
|
charset: n.charset,
|
|
3968
|
-
...
|
|
3987
|
+
...fs()
|
|
3969
3988
|
});
|
|
3970
3989
|
if (d.summary.blocked > 0) {
|
|
3971
|
-
let e = d.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
3972
|
-
if (t === void 0 || !e || (d =
|
|
3990
|
+
let e = d.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = ps(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3991
|
+
if (t === void 0 || !e || (d = hs(d, t), d.operations.some((e) => e.blocked))) return {
|
|
3973
3992
|
kind: "refused-blocked",
|
|
3974
3993
|
plan: d
|
|
3975
3994
|
};
|
|
3976
3995
|
}
|
|
3977
|
-
return d.operations.length === 0 ? (yield*
|
|
3996
|
+
return d.operations.length === 0 ? (yield* ss(e, d, {
|
|
3978
3997
|
appliedBy: n.appliedBy,
|
|
3979
3998
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3980
3999
|
source: "auto-diff"
|
|
@@ -3983,38 +4002,38 @@ BEGIN
|
|
|
3983
4002
|
fingerprint: d.toFingerprint
|
|
3984
4003
|
}) : {
|
|
3985
4004
|
kind: "applied",
|
|
3986
|
-
applied: yield*
|
|
4005
|
+
applied: yield* ts(e, d, {
|
|
3987
4006
|
declared: t,
|
|
3988
4007
|
appliedBy: n.appliedBy,
|
|
3989
4008
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3990
4009
|
source: "auto-diff",
|
|
3991
4010
|
replan: (e) => A.gen(function* () {
|
|
3992
|
-
let t = yield*
|
|
3993
|
-
return
|
|
4011
|
+
let t = yield* Bi(e);
|
|
4012
|
+
return ci({
|
|
3994
4013
|
declared: a,
|
|
3995
4014
|
live: { tables: u(t.tables) },
|
|
3996
4015
|
dialect: i,
|
|
3997
4016
|
charset: n.charset,
|
|
3998
|
-
...
|
|
4017
|
+
...fs()
|
|
3999
4018
|
});
|
|
4000
4019
|
})
|
|
4001
4020
|
}),
|
|
4002
4021
|
plan: d
|
|
4003
4022
|
};
|
|
4004
|
-
}),
|
|
4023
|
+
}), vs = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? A.succeed({
|
|
4005
4024
|
kind: "skipped",
|
|
4006
4025
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
4007
|
-
}) : n.environment === "prod" ?
|
|
4026
|
+
}) : n.environment === "prod" ? cs(e, t, n) : _s(e, t, n), ys = (e, t) => {
|
|
4008
4027
|
switch (e.kind) {
|
|
4009
4028
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
4010
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
4029
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${ur(e.fingerprint)})`;
|
|
4011
4030
|
case "applied": {
|
|
4012
4031
|
let t = e.plan.summary;
|
|
4013
|
-
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${
|
|
4032
|
+
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${ur(e.applied.fingerprint)}`;
|
|
4014
4033
|
}
|
|
4015
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
4034
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${ur(e.expected)}` + (e.actual ? ` live=${ur(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
4016
4035
|
case "refused-blocked": {
|
|
4017
|
-
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` +
|
|
4036
|
+
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` + as(e.plan), c = [""];
|
|
4018
4037
|
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) {
|
|
4019
4038
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
4020
4039
|
for (let r of e.plan.operations) {
|
|
@@ -4031,7 +4050,13 @@ BEGIN
|
|
|
4031
4050
|
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");
|
|
4032
4051
|
}
|
|
4033
4052
|
}
|
|
4034
|
-
},
|
|
4053
|
+
}, bs = (e) => typeof e.__definition == "function" ? u({ c: e }).c : e, xs = (e) => {
|
|
4054
|
+
if (typeof e != "string") return e;
|
|
4055
|
+
let t = e.trim().replace(/::[a-zA-Z0-9_ "]+$/, "").trim();
|
|
4056
|
+
if (/^current_timestamp(\(\d*\))?$/i.test(t) || /^now\(\)$/i.test(t)) return "now";
|
|
4057
|
+
let n = /^'(.*)'$/s.exec(t);
|
|
4058
|
+
return n === null ? e : n[1].replace(/''/g, "'");
|
|
4059
|
+
}, Z = (e, t = /* @__PURE__ */ new Map()) => {
|
|
4035
4060
|
let n = {};
|
|
4036
4061
|
for (let r of e.columns) {
|
|
4037
4062
|
let e = r.references, i = e === void 0 ? void 0 : t.get(e.table);
|
|
@@ -4040,7 +4065,7 @@ BEGIN
|
|
|
4040
4065
|
nullable: r.nullable,
|
|
4041
4066
|
unique: r.unique,
|
|
4042
4067
|
hasDefault: r.hasDefault,
|
|
4043
|
-
...r.hasDefault ? { defaultValue: r.defaultValue } : {},
|
|
4068
|
+
...r.hasDefault ? { defaultValue: xs(r.defaultValue) } : {},
|
|
4044
4069
|
...r.maxLength === void 0 ? {} : { maxLength: r.maxLength },
|
|
4045
4070
|
...r.precision === void 0 ? {} : { precision: r.precision },
|
|
4046
4071
|
...r.scale === void 0 ? {} : { scale: r.scale },
|
|
@@ -4055,7 +4080,7 @@ BEGIN
|
|
|
4055
4080
|
references: () => i === void 0 ? {
|
|
4056
4081
|
tableName: e.table,
|
|
4057
4082
|
fields: {}
|
|
4058
|
-
} :
|
|
4083
|
+
} : Z(i),
|
|
4059
4084
|
referenceColumn: e.column,
|
|
4060
4085
|
...e.onDelete === void 0 ? {} : { onDelete: e.onDelete },
|
|
4061
4086
|
...e.onUpdate === void 0 ? {} : { refOnUpdate: e.onUpdate },
|
|
@@ -4082,31 +4107,31 @@ BEGIN
|
|
|
4082
4107
|
})),
|
|
4083
4108
|
...e.primaryKey === void 0 ? {} : { appliedPrimaryKey: e.primaryKey }
|
|
4084
4109
|
};
|
|
4085
|
-
},
|
|
4110
|
+
}, Ss = (e) => {
|
|
4086
4111
|
let t = new Map(e.tables.map((e) => [e.name, e]));
|
|
4087
|
-
return e.tables.map((e) =>
|
|
4088
|
-
},
|
|
4112
|
+
return e.tables.map((e) => Z(e, t));
|
|
4113
|
+
}, Cs = (e, t = "safe") => ({
|
|
4089
4114
|
op: e,
|
|
4090
4115
|
classification: t,
|
|
4091
4116
|
reason: "file migration schema operation"
|
|
4092
|
-
}),
|
|
4117
|
+
}), Q = "this context was built over an in-memory store without a `sql` client, and this needs a live connection. Run the migration against a database (the runner supplies the client), or keep a database-free test to `each`, `rewrite`, `expect`, `skipUnless`, `store`, `log`, `schema.tableExists`, `schema.columnExists` and a Promise body under `transactional`.", ws = {
|
|
4093
4118
|
snapshot: "the in-memory store holds rows, not a catalog — it has no column types, defaults, indexes or constraints to report. `schema.tableExists` and `schema.columnExists` answer from the rows it holds; a body that needs the whole shape needs a database.",
|
|
4094
4119
|
indexExists: "the in-memory store has no indexes — every read of it is a scan — so there is no honest answer to give, and `false` would claim an index is absent from a store that could never have had one. Run this migration against a database, or guard on `schema.tableExists` / `schema.columnExists`, which the store can answer.",
|
|
4095
4120
|
foreignKeyExists: "the in-memory store has no constraints, so there is no honest answer to give, and `false` would claim a foreign key is absent from a store that could never have had one. Run this migration against a database, or guard on `schema.tableExists` / `schema.columnExists`, which the store can answer.",
|
|
4096
|
-
evolve:
|
|
4097
|
-
createTable:
|
|
4098
|
-
dropTable:
|
|
4099
|
-
renameTable:
|
|
4100
|
-
addColumn:
|
|
4101
|
-
alterColumn:
|
|
4102
|
-
addIndex:
|
|
4103
|
-
addForeignKey:
|
|
4104
|
-
dropForeignKey:
|
|
4105
|
-
dropIndex:
|
|
4106
|
-
dropColumn:
|
|
4107
|
-
renameColumn:
|
|
4108
|
-
truncate:
|
|
4109
|
-
},
|
|
4121
|
+
evolve: Q,
|
|
4122
|
+
createTable: Q,
|
|
4123
|
+
dropTable: Q,
|
|
4124
|
+
renameTable: Q,
|
|
4125
|
+
addColumn: Q,
|
|
4126
|
+
alterColumn: Q,
|
|
4127
|
+
addIndex: Q,
|
|
4128
|
+
addForeignKey: Q,
|
|
4129
|
+
dropForeignKey: Q,
|
|
4130
|
+
dropIndex: Q,
|
|
4131
|
+
dropColumn: Q,
|
|
4132
|
+
renameColumn: Q,
|
|
4133
|
+
truncate: Q
|
|
4134
|
+
}, Ts = "this context was built over a store that cannot report the tables it holds (`DataStore.storedTables` is not implemented), so the question has no honest answer here. Use the in-memory store `@voltro/runtime` ships, or run the migration against a database.", Es = (e, t) => {
|
|
4110
4135
|
let n = () => {
|
|
4111
4136
|
let e = t.storedTables;
|
|
4112
4137
|
if (e !== void 0) return new Map(e.call(t).map((e) => [e.table, e]));
|
|
@@ -4114,23 +4139,23 @@ BEGIN
|
|
|
4114
4139
|
return {
|
|
4115
4140
|
tableExists: (e) => A.suspend(() => {
|
|
4116
4141
|
let t = n();
|
|
4117
|
-
return t === void 0 ? r("schema.tableExists()",
|
|
4142
|
+
return t === void 0 ? r("schema.tableExists()", Ts) : A.succeed(t.has(e));
|
|
4118
4143
|
}),
|
|
4119
4144
|
columnExists: (e, t) => A.suspend(() => {
|
|
4120
4145
|
let i = n();
|
|
4121
|
-
if (i === void 0) return r("schema.columnExists()",
|
|
4146
|
+
if (i === void 0) return r("schema.columnExists()", Ts);
|
|
4122
4147
|
let a = i.get(e);
|
|
4123
4148
|
return a === void 0 ? A.succeed(!1) : a.rowCount === 0 ? r(`schema.columnExists(${JSON.stringify(e)}, ${JSON.stringify(t)})`, `${e} is in this store and holds no rows, and a column exists in a store without a catalog only as a key on a row — so "no such column" and "no row has said yet" are the same observation, and answering either would be a guess. Seed ${e} with a row carrying the columns this migration guards on, or run the migration against a database.`) : A.succeed(a.columns.includes(t));
|
|
4124
4149
|
})
|
|
4125
4150
|
};
|
|
4126
|
-
},
|
|
4127
|
-
let n = { ...
|
|
4128
|
-
for (let [t, r] of Object.entries(
|
|
4151
|
+
}, Ds = (e, t) => {
|
|
4152
|
+
let n = { ...Es(e, t) };
|
|
4153
|
+
for (let [t, r] of Object.entries(ws)) n[t] = () => A.fail(new S(e, `schema.${t}()`, r));
|
|
4129
4154
|
return n;
|
|
4130
|
-
},
|
|
4155
|
+
}, Os = (e) => typeof e == "function" && typeof e.onDialectOrElse == "function", ks = (e) => A.isEffect(e) ? e : A.tryPromise({
|
|
4131
4156
|
try: () => e,
|
|
4132
4157
|
catch: (e) => e
|
|
4133
|
-
}),
|
|
4158
|
+
}), As = (e, t, n) => t.run === void 0 ? Promise.reject(new S(e, "transactional() with an Effect body", "an Effect returned from `transactional` runs ON the transaction's connection, and this store has none. Return a Promise body that uses the transaction's `store`, or run the migration against a database.")) : t.run(n), js = (e, t) => {
|
|
4134
4159
|
let n = e.run;
|
|
4135
4160
|
if (n === void 0) return t;
|
|
4136
4161
|
let r = {};
|
|
@@ -4142,20 +4167,20 @@ BEGIN
|
|
|
4142
4167
|
});
|
|
4143
4168
|
}
|
|
4144
4169
|
return r;
|
|
4145
|
-
},
|
|
4146
|
-
let r = () =>
|
|
4170
|
+
}, Ms = (e, t, n) => {
|
|
4171
|
+
let r = () => Bi(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) => A.succeed(e), s = (e) => new Map(e.tables.map((e) => [e.name, e])), c = (e, t) => {
|
|
4147
4172
|
let n = i(e, t);
|
|
4148
4173
|
if (n === void 0) throw Error(`schema: table ${t} does not exist`);
|
|
4149
4174
|
return n;
|
|
4150
4175
|
}, l = (n) => A.gen(function* () {
|
|
4151
|
-
let i = () => r().pipe(A.map((e) => ({ tables: e.tables.filter((e) => e.name === n.tableName) }))), a =
|
|
4176
|
+
let i = () => r().pipe(A.map((e) => ({ tables: e.tables.filter((e) => e.name === n.tableName) }))), a = hs(ci({
|
|
4152
4177
|
declared: [n],
|
|
4153
4178
|
live: yield* i(),
|
|
4154
4179
|
dialect: t
|
|
4155
4180
|
})), o = a.operations.filter((e) => e.blocked !== void 0);
|
|
4156
4181
|
if (o.length > 0) return yield* A.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")));
|
|
4157
|
-
for (let t of a.operations) yield*
|
|
4158
|
-
let s =
|
|
4182
|
+
for (let t of a.operations) yield* is(e, t, [n]);
|
|
4183
|
+
let s = ci({
|
|
4159
4184
|
declared: [n],
|
|
4160
4185
|
live: yield* i(),
|
|
4161
4186
|
dialect: t
|
|
@@ -4169,28 +4194,28 @@ BEGIN
|
|
|
4169
4194
|
return (yield* r()).tables.some((t) => t.name === e.tableName) ? yield* o("already-present") : (yield* l(e), "applied");
|
|
4170
4195
|
}),
|
|
4171
4196
|
dropTable: (t) => A.gen(function* () {
|
|
4172
|
-
return (yield* r()).tables.some((e) => e.name === t) ? (yield*
|
|
4197
|
+
return (yield* r()).tables.some((e) => e.name === t) ? (yield* is(e, Cs({
|
|
4173
4198
|
kind: "drop-table",
|
|
4174
4199
|
table: t
|
|
4175
4200
|
}, "lossy"), []), "applied") : yield* o("already-absent");
|
|
4176
4201
|
}),
|
|
4177
4202
|
renameTable: (t, n) => A.gen(function* () {
|
|
4178
4203
|
let a = yield* r(), s = i(a, t) !== void 0, l = i(a, n) !== void 0;
|
|
4179
|
-
return !s && l ? yield* o("already-present") : s ? l ? yield* A.fail(/* @__PURE__ */ Error(`renameTable: ${n} already exists beside ${t}`)) : (yield*
|
|
4204
|
+
return !s && l ? yield* o("already-present") : s ? l ? yield* A.fail(/* @__PURE__ */ Error(`renameTable: ${n} already exists beside ${t}`)) : (yield* is(e, Cs({
|
|
4180
4205
|
kind: "rename-table",
|
|
4181
4206
|
from: t,
|
|
4182
4207
|
to: n
|
|
4183
|
-
}), [
|
|
4208
|
+
}), [Z(c(a, t))]), "applied") : yield* A.fail(/* @__PURE__ */ Error(`renameTable: ${t} does not exist`));
|
|
4184
4209
|
}),
|
|
4185
4210
|
addColumn: (t, n, i) => A.gen(function* () {
|
|
4186
4211
|
let a = yield* r(), u = c(a, t);
|
|
4187
4212
|
if (u.columns.some((e) => e.name === n)) return yield* o("already-present");
|
|
4188
|
-
let d =
|
|
4213
|
+
let d = bs(i);
|
|
4189
4214
|
if (!d.nullable && !d.hasDefault && d.backfill === void 0) {
|
|
4190
4215
|
let r = yield* e`SELECT COUNT(*) AS n FROM ${e(t)}`;
|
|
4191
4216
|
if (Number(r[0]?.n ?? 0) > 0) return yield* A.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 }).`));
|
|
4192
4217
|
}
|
|
4193
|
-
let f =
|
|
4218
|
+
let f = Z(u, s(a));
|
|
4194
4219
|
return yield* l({
|
|
4195
4220
|
...f,
|
|
4196
4221
|
fields: {
|
|
@@ -4215,7 +4240,7 @@ BEGIN
|
|
|
4215
4240
|
defaultValue: n.default
|
|
4216
4241
|
}
|
|
4217
4242
|
};
|
|
4218
|
-
return yield* l(
|
|
4243
|
+
return yield* l(Z({
|
|
4219
4244
|
...a,
|
|
4220
4245
|
columns: a.columns.map((e) => e.name === t ? f : e)
|
|
4221
4246
|
}, s(i))), "applied";
|
|
@@ -4224,7 +4249,7 @@ BEGIN
|
|
|
4224
4249
|
let i = yield* r(), a = c(i, e), u = n.unique === !0;
|
|
4225
4250
|
if (u && t.length === 1) {
|
|
4226
4251
|
let n = a.columns.find((e) => e.name === t[0]);
|
|
4227
|
-
return n === void 0 ? yield* A.fail(/* @__PURE__ */ Error(`addIndex: ${e}.${t[0]} does not exist`)) : n.unique ? yield* o("already-present") : (yield* l(
|
|
4252
|
+
return n === void 0 ? yield* A.fail(/* @__PURE__ */ Error(`addIndex: ${e}.${t[0]} does not exist`)) : n.unique ? yield* o("already-present") : (yield* l(Z({
|
|
4228
4253
|
...a,
|
|
4229
4254
|
columns: a.columns.map((e) => e.name === n.name ? {
|
|
4230
4255
|
...e,
|
|
@@ -4240,7 +4265,7 @@ BEGIN
|
|
|
4240
4265
|
columns: t,
|
|
4241
4266
|
unique: u
|
|
4242
4267
|
};
|
|
4243
|
-
return yield* l(
|
|
4268
|
+
return yield* l(Z({
|
|
4244
4269
|
...a,
|
|
4245
4270
|
indexes: [...a.indexes, f]
|
|
4246
4271
|
}, s(i))), "applied";
|
|
@@ -4262,7 +4287,7 @@ BEGIN
|
|
|
4262
4287
|
onUpdate: u.onUpdate ?? "noAction"
|
|
4263
4288
|
}
|
|
4264
4289
|
};
|
|
4265
|
-
return yield* l(
|
|
4290
|
+
return yield* l(Z({
|
|
4266
4291
|
...f,
|
|
4267
4292
|
columns: f.columns.map((e) => e.name === n ? h : e)
|
|
4268
4293
|
}, s(d))), "applied";
|
|
@@ -4276,7 +4301,7 @@ BEGIN
|
|
|
4276
4301
|
foreignKeyExists: (e, t) => r().pipe(A.map((n) => a(n, e, t)?.references !== void 0)),
|
|
4277
4302
|
dropForeignKey: (t, n) => A.gen(function* () {
|
|
4278
4303
|
let i = yield* r(), s = a(i, t, n);
|
|
4279
|
-
return s?.references === void 0 ? yield* o("already-absent") : (yield*
|
|
4304
|
+
return s?.references === void 0 ? yield* o("already-absent") : (yield* X(e, {
|
|
4280
4305
|
kind: "drop-foreign-key",
|
|
4281
4306
|
table: t,
|
|
4282
4307
|
column: n,
|
|
@@ -4285,7 +4310,7 @@ BEGIN
|
|
|
4285
4310
|
}),
|
|
4286
4311
|
dropIndex: (t, n) => A.gen(function* () {
|
|
4287
4312
|
let a = yield* r();
|
|
4288
|
-
return i(a, t)?.indexes.some((e) => e.name === n) ?? !1 ? (yield*
|
|
4313
|
+
return i(a, t)?.indexes.some((e) => e.name === n) ?? !1 ? (yield* X(e, {
|
|
4289
4314
|
kind: "drop-index",
|
|
4290
4315
|
table: t,
|
|
4291
4316
|
index: n
|
|
@@ -4294,18 +4319,18 @@ BEGIN
|
|
|
4294
4319
|
dropColumn: (t, n) => A.gen(function* () {
|
|
4295
4320
|
let s = yield* r(), c = a(s, t, n);
|
|
4296
4321
|
if (c === void 0) return yield* o("already-absent");
|
|
4297
|
-
c.references !== void 0 && (yield*
|
|
4322
|
+
c.references !== void 0 && (yield* X(e, {
|
|
4298
4323
|
kind: "drop-foreign-key",
|
|
4299
4324
|
table: t,
|
|
4300
4325
|
column: n,
|
|
4301
4326
|
...c.references.constraintName === void 0 ? {} : { name: c.references.constraintName }
|
|
4302
4327
|
}, s), s = yield* r());
|
|
4303
|
-
for (let r of i(s, t)?.indexes ?? []) r.columns.includes(n) && r.name !== `${t}_pkey` && (yield*
|
|
4328
|
+
for (let r of i(s, t)?.indexes ?? []) r.columns.includes(n) && r.name !== `${t}_pkey` && (yield* X(e, {
|
|
4304
4329
|
kind: "drop-index",
|
|
4305
4330
|
table: t,
|
|
4306
4331
|
index: r.name
|
|
4307
4332
|
}, s));
|
|
4308
|
-
return i(s, t)?.indexes.some((e) => e.columns.includes(n) && e.name !== `${t}_pkey`) && (s = yield* r()), yield*
|
|
4333
|
+
return i(s, t)?.indexes.some((e) => e.columns.includes(n) && e.name !== `${t}_pkey`) && (s = yield* r()), yield* X(e, {
|
|
4309
4334
|
kind: "drop-column",
|
|
4310
4335
|
table: t,
|
|
4311
4336
|
column: n
|
|
@@ -4313,7 +4338,7 @@ BEGIN
|
|
|
4313
4338
|
}),
|
|
4314
4339
|
renameColumn: (t, n, i) => A.gen(function* () {
|
|
4315
4340
|
let s = yield* r(), c = a(s, t, n) !== void 0, l = a(s, t, i) !== void 0;
|
|
4316
|
-
return !c && l ? yield* o("already-present") : c ? l ? yield* A.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${i} already exists beside ${n} — a rename cannot merge two columns`)) : (yield*
|
|
4341
|
+
return !c && l ? yield* o("already-present") : c ? l ? yield* A.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${i} already exists beside ${n} — a rename cannot merge two columns`)) : (yield* X(e, {
|
|
4317
4342
|
kind: "rename-column",
|
|
4318
4343
|
table: t,
|
|
4319
4344
|
from: n,
|
|
@@ -4321,11 +4346,11 @@ BEGIN
|
|
|
4321
4346
|
}, s), "applied") : yield* A.fail(/* @__PURE__ */ Error(`renameColumn: ${t}.${n} does not exist`));
|
|
4322
4347
|
})
|
|
4323
4348
|
};
|
|
4324
|
-
},
|
|
4349
|
+
}, Ns = (e, t, n, r) => {
|
|
4325
4350
|
let i;
|
|
4326
4351
|
return (async function* () {
|
|
4327
4352
|
for (;;) {
|
|
4328
|
-
let a = [i === void 0 ? void 0 :
|
|
4353
|
+
let a = [i === void 0 ? void 0 : me("id", i), r].filter((e) => e !== void 0), o = await e.query({
|
|
4329
4354
|
table: t,
|
|
4330
4355
|
predicate: a.length === 0 ? void 0 : a.length === 1 ? a[0] : v(...a),
|
|
4331
4356
|
order: [{
|
|
@@ -4343,8 +4368,8 @@ BEGIN
|
|
|
4343
4368
|
if (i = s, yield o, o.length < n) return;
|
|
4344
4369
|
}
|
|
4345
4370
|
})();
|
|
4346
|
-
},
|
|
4347
|
-
let i = r.batchSize ?? 1e3, a = 0, o = 0, s =
|
|
4371
|
+
}, Ps = (e) => e > 0 ? A.sleep(`${e} millis`) : A.void, Fs = (e) => (t, n, r = {}) => A.gen(function* () {
|
|
4372
|
+
let i = r.batchSize ?? 1e3, a = 0, o = 0, s = Ns(e, t, i);
|
|
4348
4373
|
for (;;) {
|
|
4349
4374
|
let e = yield* A.tryPromise({
|
|
4350
4375
|
try: () => s.next(),
|
|
@@ -4352,16 +4377,16 @@ BEGIN
|
|
|
4352
4377
|
});
|
|
4353
4378
|
if (e.done) break;
|
|
4354
4379
|
o++;
|
|
4355
|
-
for (let t of e.value) yield*
|
|
4356
|
-
yield*
|
|
4380
|
+
for (let t of e.value) yield* ks(n(t)), a++;
|
|
4381
|
+
yield* Ps(r.sleepMs ?? 0);
|
|
4357
4382
|
}
|
|
4358
4383
|
return {
|
|
4359
4384
|
scanned: a,
|
|
4360
4385
|
pages: o
|
|
4361
4386
|
};
|
|
4362
|
-
}),
|
|
4387
|
+
}), Is = (e, t) => t == null ? oe(e) : se(e, t), Ls = (e) => typeof e != "object" || !e || e instanceof Date, Rs = (e, t) => A.gen(function* () {
|
|
4363
4388
|
if (e === void 0) return [];
|
|
4364
|
-
let n = (yield*
|
|
4389
|
+
let n = (yield* Bi(e)).tables.find((e) => e.name === t)?.columns ?? [], r = new Set(n.map((e) => e.name)), i = ce(t)?.fields;
|
|
4365
4390
|
return n.filter((e) => e.type === "timestamp" || e.type === "date" || i?.[e.name]?.type === "timestamp" || i?.[e.name]?.type === "date").map((e, t) => {
|
|
4366
4391
|
let n = `__voltro_rewrite_guard_${t}`;
|
|
4367
4392
|
for (; r.has(n);) n += "_";
|
|
@@ -4370,14 +4395,14 @@ BEGIN
|
|
|
4370
4395
|
alias: n
|
|
4371
4396
|
};
|
|
4372
4397
|
});
|
|
4373
|
-
}),
|
|
4374
|
-
let s = o.batchSize ?? 1e3, c = o.maxPasses ?? 10, l = o.guard ?? [], u = yield*
|
|
4375
|
-
let o =
|
|
4398
|
+
}), zs = (e, t, n, r) => (i, a, o = {}) => A.gen(function* () {
|
|
4399
|
+
let s = o.batchSize ?? 1e3, c = o.maxPasses ?? 10, l = o.guard ?? [], u = yield* Rs(n, i), f = /* @__PURE__ */ new WeakMap(), p = u.length === 0 || n === void 0 ? t : { query: async (a) => {
|
|
4400
|
+
let o = _e(a, n), s = u.map(({ column: e, alias: t }) => n`${n.onDialectOrElse({
|
|
4376
4401
|
mysql: () => n`CAST(${n(e)} AS CHAR)`,
|
|
4377
4402
|
mssql: () => n`CONVERT(VARCHAR(40), ${n(e)}, 127)`,
|
|
4378
4403
|
orElse: () => n`CAST(${n(e)} AS TEXT)`
|
|
4379
4404
|
})} AS ${n(t)}`);
|
|
4380
|
-
return (await
|
|
4405
|
+
return (await As(e, t, n`SELECT *, ${n.csv(s)} FROM (${o}) AS ${n("__voltro_rewrite_rows")} ORDER BY ${n("id")} ASC`)).map((e) => {
|
|
4381
4406
|
let t = { ...e }, n = /* @__PURE__ */ new Map();
|
|
4382
4407
|
for (let { column: e, alias: r } of u) n.set(e, t[r]), delete t[r];
|
|
4383
4408
|
let a = _([t], i, r)[0];
|
|
@@ -4390,7 +4415,7 @@ BEGIN
|
|
|
4390
4415
|
contended: 0
|
|
4391
4416
|
}, h = m;
|
|
4392
4417
|
for (let e = 1; e <= c; e++) {
|
|
4393
|
-
let n = 0, r = 0, c = 0, u =
|
|
4418
|
+
let n = 0, r = 0, c = 0, u = Ns(p, i, s);
|
|
4394
4419
|
for (;;) {
|
|
4395
4420
|
let e = yield* A.tryPromise({
|
|
4396
4421
|
try: () => u.next(),
|
|
@@ -4406,15 +4431,15 @@ BEGIN
|
|
|
4406
4431
|
if (e === void 0) continue;
|
|
4407
4432
|
let s = Object.entries(e).filter(([e, t]) => !Object.is(o[e], t));
|
|
4408
4433
|
if (s.length === 0) continue;
|
|
4409
|
-
let u = [
|
|
4410
|
-
for (let [e] of s)
|
|
4411
|
-
for (let e of l) u.push(
|
|
4434
|
+
let u = [se("id", o.id)], d = (e) => f.get(o)?.has(e) ? f.get(o).get(e) : o[e];
|
|
4435
|
+
for (let [e] of s) Ls(o[e]) && u.push(Is(e, d(e)));
|
|
4436
|
+
for (let e of l) u.push(Is(e, d(e)));
|
|
4412
4437
|
(yield* A.tryPromise({
|
|
4413
4438
|
try: () => t.updateMany(i, Object.fromEntries(s), { where: v(...u) }),
|
|
4414
4439
|
catch: (e) => e
|
|
4415
4440
|
})) === 1 ? r++ : c++;
|
|
4416
4441
|
}
|
|
4417
|
-
yield*
|
|
4442
|
+
yield* Ps(o.sleepMs ?? 0);
|
|
4418
4443
|
}
|
|
4419
4444
|
if (h = {
|
|
4420
4445
|
passes: e,
|
|
@@ -4429,13 +4454,13 @@ BEGIN
|
|
|
4429
4454
|
}, r === 0 && c === 0) return m;
|
|
4430
4455
|
}
|
|
4431
4456
|
return yield* A.fail(new d(i, h));
|
|
4432
|
-
}),
|
|
4457
|
+
}), Bs = (e) => {
|
|
4433
4458
|
let { migrationId: t } = e, n = `migrations:file:${t}`;
|
|
4434
|
-
if (e.sql !== void 0 && !
|
|
4459
|
+
if (e.sql !== void 0 && !Os(e.sql)) throw new S(t, "makeFileMigrationContext()", `\`sql\` is not an @effect/sql client (got ${typeof e.sql}). Pass the client the store executes on, or omit \`sql\` to drive the body over an in-memory store.`);
|
|
4435
4460
|
if (e.sql === void 0 && e.store.run !== void 0) throw new S(t, "makeFileMigrationContext()", "a SQL-backed store was given without `sql`. Its migration context runs `raw()`, `schema` and the guarded rewrite on the client the store executes on; pass that client, or use an in-memory store for a database-free test.");
|
|
4436
4461
|
let r = e.sql, i = [], a = (e) => {
|
|
4437
4462
|
if (typeof e != "string" || e.trim().length < 12) throw Error(`raw(reason): say why this migration needs raw SQL — the reason is what a reviewer and \`voltro doctor\` read (got ${JSON.stringify(e)})`);
|
|
4438
|
-
if (r === void 0) throw new S(t, `raw(${JSON.stringify(e)})`,
|
|
4463
|
+
if (r === void 0) throw new S(t, `raw(${JSON.stringify(e)})`, Q);
|
|
4439
4464
|
return r;
|
|
4440
4465
|
};
|
|
4441
4466
|
return {
|
|
@@ -4455,9 +4480,9 @@ BEGIN
|
|
|
4455
4480
|
...t ?? {}
|
|
4456
4481
|
}))
|
|
4457
4482
|
},
|
|
4458
|
-
schema: r === void 0 ?
|
|
4459
|
-
each:
|
|
4460
|
-
rewrite:
|
|
4483
|
+
schema: r === void 0 ? Ds(t, o) : js(o, Ms(r, e.dialect, o)),
|
|
4484
|
+
each: Fs(o),
|
|
4485
|
+
rewrite: zs(t, o, r, e.dialect),
|
|
4461
4486
|
expect: (e, t) => {
|
|
4462
4487
|
i.push({
|
|
4463
4488
|
description: e,
|
|
@@ -4465,7 +4490,7 @@ BEGIN
|
|
|
4465
4490
|
});
|
|
4466
4491
|
},
|
|
4467
4492
|
skipUnless: (e, t) => A.gen(function* () {
|
|
4468
|
-
if (!(typeof e == "boolean" ? e : yield*
|
|
4493
|
+
if (!(typeof e == "boolean" ? e : yield* ks(e))) return yield* A.fail(new T(t));
|
|
4469
4494
|
})
|
|
4470
4495
|
}))(e.store),
|
|
4471
4496
|
transactional: (n) => A.tryPromise({
|
|
@@ -4474,19 +4499,19 @@ BEGIN
|
|
|
4474
4499
|
store: e,
|
|
4475
4500
|
raw: a
|
|
4476
4501
|
});
|
|
4477
|
-
return A.isEffect(r) ?
|
|
4502
|
+
return A.isEffect(r) ? As(t, e, r) : r;
|
|
4478
4503
|
}),
|
|
4479
4504
|
catch: (e) => e
|
|
4480
4505
|
})
|
|
4481
4506
|
},
|
|
4482
4507
|
expectations: i
|
|
4483
4508
|
};
|
|
4484
|
-
},
|
|
4509
|
+
}, Vs = (e) => A.gen(function* () {
|
|
4485
4510
|
let t = [];
|
|
4486
|
-
for (let { description: n, check: r } of e) (yield*
|
|
4511
|
+
for (let { description: n, check: r } of e) (yield* ks(r())) || t.push(n);
|
|
4487
4512
|
return t;
|
|
4488
|
-
}),
|
|
4489
|
-
let t = [], n = (e) => (n) => (!n && !t.some((t) =>
|
|
4513
|
+
}), Hs = (e) => e.kind === "table" ? e.table : `${e.table}.${e.name}`, Us = (e, t) => e.kind === t.kind && e.table === t.table && Hs(e) === Hs(t), Ws = (e) => {
|
|
4514
|
+
let t = [], n = (e) => (n) => (!n && !t.some((t) => Us(t, e)) && t.push(e), n), r = (e, t) => (...r) => e(...r).pipe(A.map(n(t(...r)))), i = {
|
|
4490
4515
|
tableExists: r(e.schema.tableExists, (e) => ({
|
|
4491
4516
|
kind: "table",
|
|
4492
4517
|
table: e
|
|
@@ -4517,9 +4542,9 @@ BEGIN
|
|
|
4517
4542
|
},
|
|
4518
4543
|
absent: () => t.slice()
|
|
4519
4544
|
};
|
|
4520
|
-
},
|
|
4545
|
+
}, Gs = (e) => {
|
|
4521
4546
|
let t = [], n = (e) => {
|
|
4522
|
-
t.some((t) =>
|
|
4547
|
+
t.some((t) => Us(t, e)) || t.push(e);
|
|
4523
4548
|
};
|
|
4524
4549
|
for (let t of e.operations) {
|
|
4525
4550
|
let e = t.op;
|
|
@@ -4562,17 +4587,17 @@ BEGIN
|
|
|
4562
4587
|
}
|
|
4563
4588
|
}
|
|
4564
4589
|
return t;
|
|
4565
|
-
},
|
|
4566
|
-
let n =
|
|
4590
|
+
}, Ks = (e, t) => {
|
|
4591
|
+
let n = Gs(t);
|
|
4567
4592
|
return n.length === 0 ? [] : e.flatMap((e) => {
|
|
4568
|
-
let t = e.absent.filter((e) => n.some((t) =>
|
|
4593
|
+
let t = e.absent.filter((e) => n.some((t) => Us(t, e)));
|
|
4569
4594
|
return t.length === 0 ? [] : [{
|
|
4570
4595
|
id: e.id,
|
|
4571
4596
|
reason: e.reason,
|
|
4572
4597
|
created: t
|
|
4573
4598
|
}];
|
|
4574
4599
|
});
|
|
4575
|
-
},
|
|
4600
|
+
}, qs = Ee({ scope: "voltro:migrate" }), Js = (e) => Te("sha256").update(e).digest("hex").slice(0, 16), Ys = /* @__PURE__ */ new Set([
|
|
4576
4601
|
"node_modules",
|
|
4577
4602
|
"dist",
|
|
4578
4603
|
"build",
|
|
@@ -4581,58 +4606,58 @@ BEGIN
|
|
|
4581
4606
|
".next",
|
|
4582
4607
|
".git",
|
|
4583
4608
|
".framework"
|
|
4584
|
-
]),
|
|
4609
|
+
]), Xs = async (e) => {
|
|
4585
4610
|
let t = [], n = async (e) => {
|
|
4586
|
-
let r = await
|
|
4611
|
+
let r = await De.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
4587
4612
|
for (let i of r) {
|
|
4588
|
-
if (
|
|
4589
|
-
let r =
|
|
4590
|
-
i.isDirectory() ? await n(r) : i.isFile() &&
|
|
4613
|
+
if (Ys.has(i.name)) continue;
|
|
4614
|
+
let r = Oe(e, i.name);
|
|
4615
|
+
i.isDirectory() ? await n(r) : i.isFile() && ue.test(i.name) && t.push(r);
|
|
4591
4616
|
}
|
|
4592
4617
|
};
|
|
4593
4618
|
return await n(e), t.sort((e, t) => {
|
|
4594
4619
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
4595
4620
|
return n.localeCompare(r);
|
|
4596
4621
|
});
|
|
4597
|
-
},
|
|
4598
|
-
let
|
|
4599
|
-
for (let
|
|
4600
|
-
let e = (await
|
|
4601
|
-
if (!
|
|
4602
|
-
|
|
4622
|
+
}, Zs = async (e) => await import(ke(e).href), Qs = async (e, t = Zs) => {
|
|
4623
|
+
let n = [];
|
|
4624
|
+
for (let r of e) {
|
|
4625
|
+
let e = (await t(r)).default;
|
|
4626
|
+
if (!ye(e)) {
|
|
4627
|
+
qs.warn("migration file has no default-exported `migration(...)` — skipped", { file: r });
|
|
4603
4628
|
continue;
|
|
4604
4629
|
}
|
|
4605
|
-
let
|
|
4606
|
-
|
|
4607
|
-
file:
|
|
4630
|
+
let i = await De.readFile(r, "utf8").catch(() => "");
|
|
4631
|
+
n.push({
|
|
4632
|
+
file: r,
|
|
4608
4633
|
migration: e,
|
|
4609
|
-
hash:
|
|
4634
|
+
hash: Js(i)
|
|
4610
4635
|
});
|
|
4611
4636
|
}
|
|
4612
|
-
return
|
|
4613
|
-
},
|
|
4637
|
+
return n;
|
|
4638
|
+
}, $s = "_voltro_migration_plans", ec = (e) => {
|
|
4614
4639
|
let t = N(e);
|
|
4615
|
-
return (t === "sqlite" ? e`SELECT COUNT(*) AS n FROM sqlite_master WHERE type = 'table' AND name = ${
|
|
4616
|
-
},
|
|
4640
|
+
return (t === "sqlite" ? e`SELECT COUNT(*) AS n FROM sqlite_master WHERE type = 'table' AND name = ${$s}` : t === "mysql" ? e`SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ${$s}` : t === "mssql" ? e`SELECT COUNT(*) AS n FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = ${$s}` : e`SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = ${$s}`).pipe(A.map((e) => Number(e[0]?.n ?? 0) > 0));
|
|
4641
|
+
}, tc = (e) => nc(e).pipe(A.map((e) => e.map((e) => e.id))), nc = (e) => ec(e).pipe(A.flatMap((t) => t ? e`
|
|
4617
4642
|
SELECT ${e("id")}, ${e("fingerprint")}
|
|
4618
|
-
FROM ${e(
|
|
4643
|
+
FROM ${e($s)}
|
|
4619
4644
|
WHERE ${e("source")} = 'file'
|
|
4620
4645
|
`.pipe(A.map((e) => e.map((e) => ({
|
|
4621
4646
|
id: e.id,
|
|
4622
4647
|
hash: e.fingerprint ?? ""
|
|
4623
|
-
})))) : A.succeed([]))),
|
|
4648
|
+
})))) : A.succeed([]))), rc = (e, t) => t.filter((t) => {
|
|
4624
4649
|
let n = e.get(t.migration.id);
|
|
4625
4650
|
return n !== void 0 && n !== "" && n !== t.hash;
|
|
4626
|
-
}).map((e) => e.migration.id),
|
|
4651
|
+
}).map((e) => e.migration.id), ic = (e) => y(ae(e))?.kind === "unique", ac = class extends Error {
|
|
4627
4652
|
migrationId;
|
|
4628
4653
|
file;
|
|
4629
4654
|
cause;
|
|
4630
4655
|
_tag = "FileMigrationLedgerError";
|
|
4631
4656
|
constructor(e, t, n) {
|
|
4632
|
-
super(
|
|
4657
|
+
super(ic(n) ? `migration ${e}: up() SUCCEEDED here, and ANOTHER process had already recorded the same migration.\n The body has run TWICE. The ledger row is correct — do not delete it; the next run will not apply ${t} again.\n Two processes applied it without being serialised by the migration lock: check that both reach the same database and lock schema.\n Cause: ${n instanceof Error ? n.message : String(n)}` : `migration ${e}: up() SUCCEEDED but the ledger row could not be written.\n The change IS in the database. It is NOT recorded, so the next run would apply it AGAIN.\n Do not re-run ${t} until this is resolved.\n Cause: ${n instanceof Error ? n.message : String(n)}`), this.migrationId = e, this.file = t, this.cause = n, this.name = "FileMigrationLedgerError";
|
|
4633
4658
|
}
|
|
4634
|
-
},
|
|
4635
|
-
let r = yield*
|
|
4659
|
+
}, oc = (e, t, n) => A.gen(function* () {
|
|
4660
|
+
let r = yield* H(e, n.appliedAtIso);
|
|
4636
4661
|
yield* e`
|
|
4637
4662
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
4638
4663
|
(${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
@@ -4646,19 +4671,19 @@ BEGIN
|
|
|
4646
4671
|
}])},
|
|
4647
4672
|
${n.appliedBy}, ${n.env}, ${"file"},
|
|
4648
4673
|
${n.durationMs}, ${r}, ${n.notes})
|
|
4649
|
-
`.pipe(A.mapError((e) => new
|
|
4650
|
-
}),
|
|
4651
|
-
for (let t of m(e)) if (t instanceof
|
|
4652
|
-
},
|
|
4653
|
-
let r =
|
|
4674
|
+
`.pipe(A.mapError((e) => new ac(t.migration.id, t.file, e)));
|
|
4675
|
+
}), sc = (e) => {
|
|
4676
|
+
for (let t of m(e)) if (t instanceof T) return t.reason;
|
|
4677
|
+
}, cc = (e, t, n) => A.gen(function* () {
|
|
4678
|
+
let r = Ws(t), i = r.ctx, a = e.migration.up(i), o = !A.isEffect(a), s = yield* (A.isEffect(a) ? a : A.tryPromise({
|
|
4654
4679
|
try: () => a,
|
|
4655
4680
|
catch: (e) => e
|
|
4656
4681
|
})).pipe(A.as(void 0), A.catchAll((e) => {
|
|
4657
|
-
let t =
|
|
4682
|
+
let t = sc(e);
|
|
4658
4683
|
return t === void 0 ? A.fail(e) : A.succeed(t);
|
|
4659
4684
|
}));
|
|
4660
4685
|
if (s === void 0) {
|
|
4661
|
-
let t = yield*
|
|
4686
|
+
let t = yield* Vs(n);
|
|
4662
4687
|
if (t.length > 0) return yield* A.fail(new x(e.migration.id, t));
|
|
4663
4688
|
}
|
|
4664
4689
|
return {
|
|
@@ -4666,7 +4691,7 @@ BEGIN
|
|
|
4666
4691
|
promiseForm: o,
|
|
4667
4692
|
absent: r.absent()
|
|
4668
4693
|
};
|
|
4669
|
-
}),
|
|
4694
|
+
}), lc = (e, t, n, r, i, a) => A.gen(function* () {
|
|
4670
4695
|
let o = Date.now(), s = (/* @__PURE__ */ new Date()).toISOString(), c = N(e), l = `migrations:file:${n.migration.id}`, u = (e) => ({
|
|
4671
4696
|
durationMs: Date.now() - o,
|
|
4672
4697
|
notes: e.skipped === void 0 ? n.migration.description : `skipped: ${e.skipped}`
|
|
@@ -4674,19 +4699,19 @@ BEGIN
|
|
|
4674
4699
|
if (n.migration.transactional !== !1 && !a) {
|
|
4675
4700
|
if (t.run === void 0) return yield* A.fail(/* @__PURE__ */ Error(`migration ${n.migration.id}: transactional: true needs a SQL-backed store`));
|
|
4676
4701
|
let a = c === "mysql" || c === "mariadb", o = `probe_${n.migration.id}_${Date.now().toString(36)}`;
|
|
4677
|
-
a && (yield*
|
|
4702
|
+
a && (yield* Ro(e, c));
|
|
4678
4703
|
let d = () => e`SELECT COUNT(*) AS n FROM ${e(P)} WHERE ${e("runId")} = ${o}`.pipe(A.map((e) => Number(e[0]?.n ?? 0) > 0)), f = yield* A.tryPromise({
|
|
4679
4704
|
try: () => t.transactional(async (t) => {
|
|
4680
4705
|
a && await t.run(e`INSERT INTO ${e(P)} (${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")}, ${e("status")}, ${e("opKind")}, ${e("opTarget")}, ${e("payload")})
|
|
4681
4706
|
VALUES (${`mop_${o}`}, ${o}, ${""}, ${0}, ${"pending"}, ${"probe"}, ${""}, ${"{}"})`);
|
|
4682
|
-
let { ctx: l, expectations: f } =
|
|
4707
|
+
let { ctx: l, expectations: f } = Bs({
|
|
4683
4708
|
sql: e,
|
|
4684
4709
|
store: t,
|
|
4685
4710
|
dialect: c,
|
|
4686
4711
|
migrationId: n.migration.id,
|
|
4687
4712
|
appliedAt: s
|
|
4688
|
-
}), p = await t.run(
|
|
4689
|
-
return await t.run(
|
|
4713
|
+
}), p = await t.run(cc(n, l, f)), m = a && await A.runPromise(d().pipe(A.provideService(j.SqlClient, e))), { durationMs: h, notes: g } = u(p);
|
|
4714
|
+
return await t.run(oc(e, n, {
|
|
4690
4715
|
env: r,
|
|
4691
4716
|
appliedBy: i,
|
|
4692
4717
|
durationMs: h,
|
|
@@ -4709,14 +4734,14 @@ BEGIN
|
|
|
4709
4734
|
}
|
|
4710
4735
|
});
|
|
4711
4736
|
}
|
|
4712
|
-
let { ctx: d, expectations: f } =
|
|
4737
|
+
let { ctx: d, expectations: f } = Bs({
|
|
4713
4738
|
sql: e,
|
|
4714
4739
|
store: t,
|
|
4715
4740
|
dialect: c,
|
|
4716
4741
|
migrationId: n.migration.id,
|
|
4717
4742
|
appliedAt: s
|
|
4718
|
-
}), p = yield*
|
|
4719
|
-
return p.promiseForm && p.skipped === void 0 && m < 2 && (yield* A.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(A.annotateLogs({ scope: l }))), p.skipped !== void 0 && (yield* A.logInfo(`migration ${n.migration.id} skipped: ${p.skipped}`).pipe(A.annotateLogs({ scope: l }))), yield*
|
|
4743
|
+
}), p = yield* cc(n, d, f), { durationMs: m, notes: h } = u(p);
|
|
4744
|
+
return p.promiseForm && p.skipped === void 0 && m < 2 && (yield* A.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(A.annotateLogs({ scope: l }))), p.skipped !== void 0 && (yield* A.logInfo(`migration ${n.migration.id} skipped: ${p.skipped}`).pipe(A.annotateLogs({ scope: l }))), yield* oc(e, n, {
|
|
4720
4745
|
env: r,
|
|
4721
4746
|
appliedBy: i,
|
|
4722
4747
|
durationMs: m,
|
|
@@ -4730,41 +4755,41 @@ BEGIN
|
|
|
4730
4755
|
absent: p.absent
|
|
4731
4756
|
}
|
|
4732
4757
|
};
|
|
4733
|
-
}),
|
|
4734
|
-
let
|
|
4735
|
-
try: () =>
|
|
4758
|
+
}), uc = (e, t, n, r) => A.gen(function* () {
|
|
4759
|
+
let i = yield* A.tryPromise({
|
|
4760
|
+
try: () => Xs(Oe(t, "migrations")),
|
|
4736
4761
|
catch: (e) => e
|
|
4737
4762
|
});
|
|
4738
|
-
if (
|
|
4763
|
+
if (i.length === 0) return {
|
|
4739
4764
|
pending: [],
|
|
4740
4765
|
alreadyApplied: [],
|
|
4741
4766
|
drifted: []
|
|
4742
4767
|
};
|
|
4743
|
-
let
|
|
4744
|
-
try: () =>
|
|
4768
|
+
let a = yield* A.tryPromise({
|
|
4769
|
+
try: () => Qs(i, r),
|
|
4745
4770
|
catch: (e) => e
|
|
4746
4771
|
});
|
|
4747
|
-
if (
|
|
4772
|
+
if (a.length === 0) return {
|
|
4748
4773
|
pending: [],
|
|
4749
4774
|
alreadyApplied: [],
|
|
4750
4775
|
drifted: []
|
|
4751
4776
|
};
|
|
4752
|
-
let
|
|
4753
|
-
for (let e of
|
|
4777
|
+
let o = new Map((yield* nc(e)).map((e) => [e.id, e.hash])), s = rc(o, a);
|
|
4778
|
+
for (let e of s) qs.warn("file migration: the body on disk is not the one that was applied — the file no longer describes this database", {
|
|
4754
4779
|
id: e,
|
|
4755
|
-
file:
|
|
4780
|
+
file: a.find((t) => t.migration.id === e)?.file
|
|
4756
4781
|
});
|
|
4757
|
-
let
|
|
4782
|
+
let c = n === void 0 ? a : a.filter((e) => e.migration.phase === n);
|
|
4758
4783
|
return {
|
|
4759
|
-
pending:
|
|
4760
|
-
alreadyApplied:
|
|
4761
|
-
drifted:
|
|
4784
|
+
pending: c.filter((e) => !o.has(e.migration.id)),
|
|
4785
|
+
alreadyApplied: c.filter((e) => o.has(e.migration.id)),
|
|
4786
|
+
drifted: s
|
|
4762
4787
|
};
|
|
4763
|
-
}),
|
|
4788
|
+
}), dc = (e, t, n, r) => uc(e, t, n, r).pipe(A.map((e) => e.pending.map((e) => e.migration.id))), fc = (e, t, n) => uc(e, t, n).pipe(A.map((e) => e.pending.map((e) => ({
|
|
4764
4789
|
id: e.migration.id,
|
|
4765
4790
|
phase: e.migration.phase,
|
|
4766
|
-
irreversible:
|
|
4767
|
-
})))),
|
|
4791
|
+
irreversible: D(e.migration.down)
|
|
4792
|
+
})))), pc = (e, t) => uc(e, t).pipe(A.map((e) => {
|
|
4768
4793
|
let t = new Set(e.drifted);
|
|
4769
4794
|
return [...e.alreadyApplied.map((e) => ({
|
|
4770
4795
|
id: e.migration.id,
|
|
@@ -4777,16 +4802,16 @@ BEGIN
|
|
|
4777
4802
|
applied: !1,
|
|
4778
4803
|
bodyChanged: !1
|
|
4779
4804
|
}))].sort((e, t) => e.id < t.id ? -1 : 1);
|
|
4780
|
-
})),
|
|
4781
|
-
let { pending: n, alreadyApplied: r } = yield*
|
|
4805
|
+
})), mc = (e, t) => A.gen(function* () {
|
|
4806
|
+
let { pending: n, alreadyApplied: r } = yield* uc(e, t.projectRoot, t.phase), i = r.map((e) => e.migration.id);
|
|
4782
4807
|
if (n.length === 0) return {
|
|
4783
4808
|
applied: [],
|
|
4784
4809
|
skipped: i,
|
|
4785
4810
|
skips: []
|
|
4786
4811
|
};
|
|
4787
|
-
yield*
|
|
4788
|
-
let a = yield* A.acquireUseRelease(
|
|
4789
|
-
let r = new Set((yield*
|
|
4812
|
+
yield* zo(e, N(e));
|
|
4813
|
+
let a = yield* A.acquireUseRelease(ft(e, { schema: t.lockSchema }), () => A.gen(function* () {
|
|
4814
|
+
let r = new Set((yield* nc(e)).map((e) => e.id)), i = n.filter((e) => !r.has(e.migration.id));
|
|
4790
4815
|
i.length < n.length && (yield* A.logInfo("file-based migrations applied by another process while this one waited for the migration lock").pipe(A.annotateLogs({
|
|
4791
4816
|
scope: "voltro:migrate",
|
|
4792
4817
|
ids: n.filter((e) => r.has(e.migration.id)).map((e) => e.migration.id).join(",")
|
|
@@ -4799,7 +4824,7 @@ BEGIN
|
|
|
4799
4824
|
file: n.file,
|
|
4800
4825
|
phase: n.migration.phase
|
|
4801
4826
|
}));
|
|
4802
|
-
let { durationMs: r, skip: i } = yield*
|
|
4827
|
+
let { durationMs: r, skip: i } = yield* lc(e, t.store, n, t.env, t.appliedBy, t.enclosed === !0);
|
|
4803
4828
|
a.push({
|
|
4804
4829
|
id: n.migration.id,
|
|
4805
4830
|
durationMs: r
|
|
@@ -4820,24 +4845,24 @@ BEGIN
|
|
|
4820
4845
|
skipped: i,
|
|
4821
4846
|
skips: a.skips
|
|
4822
4847
|
};
|
|
4823
|
-
}),
|
|
4848
|
+
}), hc = (e, t) => e`
|
|
4824
4849
|
SELECT ${e("id")}
|
|
4825
4850
|
FROM ${e("_voltro_migration_plans")}
|
|
4826
4851
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
4827
|
-
`,
|
|
4828
|
-
if (!(yield*
|
|
4852
|
+
`, gc = (t, n) => A.gen(function* () {
|
|
4853
|
+
if (!(yield* hc(t, n.id))[0]) return yield* A.fail(/* @__PURE__ */ Error(`rollback: ${n.id} not found in _voltro_migration_plans (file source)`));
|
|
4829
4854
|
let r = yield* A.tryPromise({
|
|
4830
|
-
try: () =>
|
|
4855
|
+
try: () => Xs(Oe(n.projectRoot, "migrations")),
|
|
4831
4856
|
catch: (e) => e
|
|
4832
4857
|
}), i = (yield* A.tryPromise({
|
|
4833
|
-
try: () =>
|
|
4858
|
+
try: () => Qs(r),
|
|
4834
4859
|
catch: (e) => e
|
|
4835
4860
|
})).find((e) => e.migration.id === n.id);
|
|
4836
4861
|
if (!i) return yield* A.fail(/* @__PURE__ */ Error(`rollback: file for migration ${n.id} not found on disk under ${n.projectRoot}/migrations/`));
|
|
4837
|
-
let a =
|
|
4838
|
-
return a === void 0 ? yield* A.acquireUseRelease(
|
|
4839
|
-
if ((yield*
|
|
4840
|
-
let e = Date.now(), { ctx: r } =
|
|
4862
|
+
let a = D(i.migration.down);
|
|
4863
|
+
return a === void 0 ? yield* A.acquireUseRelease(ft(t, { schema: n.lockSchema }), () => A.gen(function* () {
|
|
4864
|
+
if ((yield* hc(t, n.id))[0] === void 0) return yield* A.fail(/* @__PURE__ */ Error(`rollback: ${n.id} was rolled back by another process while this one waited for the migration lock — nothing to do`));
|
|
4865
|
+
let e = Date.now(), { ctx: r } = Bs({
|
|
4841
4866
|
sql: t,
|
|
4842
4867
|
store: n.store,
|
|
4843
4868
|
dialect: N(t),
|
|
@@ -4854,7 +4879,7 @@ BEGIN
|
|
|
4854
4879
|
durationMs: o
|
|
4855
4880
|
};
|
|
4856
4881
|
}), (e) => e.release.pipe(A.orDie)) : yield* A.fail(new e(n.id, a));
|
|
4857
|
-
}),
|
|
4882
|
+
}), _c = (e) => A.gen(function* () {
|
|
4858
4883
|
let t = yield* j.SqlClient, n = yield* t`
|
|
4859
4884
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
4860
4885
|
WHERE source = 'auto-diff'
|
|
@@ -4899,8 +4924,8 @@ BEGIN
|
|
|
4899
4924
|
snapshotFingerprint: e.fingerprint,
|
|
4900
4925
|
snapshotId: i
|
|
4901
4926
|
};
|
|
4902
|
-
}),
|
|
4903
|
-
if (
|
|
4927
|
+
}), vc = (e) => new Set(e.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), yc = (e, t) => t !== void 0 && "table" in e && t.createdTables.has(e.table), $ = { safe: !0 }, bc = (e, t) => {
|
|
4928
|
+
if (yc(e, t)) return $;
|
|
4904
4929
|
switch (e.kind) {
|
|
4905
4930
|
case "add-enum-value": return { safe: !0 };
|
|
4906
4931
|
case "drop-column": return {
|
|
@@ -4932,7 +4957,7 @@ BEGIN
|
|
|
4932
4957
|
reason: `instances on the previous release read/write "${e.table}"."${e.column}" as ${e.from}; the new ${e.to} type can reject their writes or fail to decode their reads`,
|
|
4933
4958
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
4934
4959
|
};
|
|
4935
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
4960
|
+
case "alter-column-nullability": return e.toNullable ? $ : {
|
|
4936
4961
|
safe: !1,
|
|
4937
4962
|
reason: `instances on the previous release may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
4938
4963
|
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)`
|
|
@@ -4943,12 +4968,12 @@ BEGIN
|
|
|
4943
4968
|
reason: `instances on the previous release still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
|
|
4944
4969
|
remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
|
|
4945
4970
|
};
|
|
4946
|
-
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ?
|
|
4971
|
+
case "reconcile-json-check": return e.previousValidation === "container" && e.validation === "value" ? $ : {
|
|
4947
4972
|
safe: !1,
|
|
4948
4973
|
reason: `instances on the previous release write "${e.table}"."${e.column}" without the new JSON validation, which now rejects them`,
|
|
4949
4974
|
remedy: "ensure all writers supply valid JSON in the required domain before enabling this check"
|
|
4950
4975
|
};
|
|
4951
|
-
case "add-check": return e.table.startsWith("_voltro_") ?
|
|
4976
|
+
case "add-check": return e.table.startsWith("_voltro_") ? $ : {
|
|
4952
4977
|
safe: !1,
|
|
4953
4978
|
reason: `instances on the previous release may write values to "${e.table}" the new CHECK rejects`,
|
|
4954
4979
|
remedy: "make code satisfy the constraint first and deploy that; add the CHECK in a LATER deploy"
|
|
@@ -4958,7 +4983,7 @@ BEGIN
|
|
|
4958
4983
|
reason: `instances on the previous release may write "${e.table}"."${e.column}" values with no matching parent row, which the new FK rejects`,
|
|
4959
4984
|
remedy: "make code guarantee the referent first and deploy that; add the FK in a LATER deploy"
|
|
4960
4985
|
};
|
|
4961
|
-
case "convert-charset": return e.charset === "utf8mb4" ?
|
|
4986
|
+
case "convert-charset": return e.charset === "utf8mb4" ? $ : {
|
|
4962
4987
|
safe: !1,
|
|
4963
4988
|
reason: `instances on the previous release may write 4-byte characters into "${e.table}", which utf8mb3 rejects with errno 1366`,
|
|
4964
4989
|
remedy: "keep utf8mb4 while any writer on the previous release remains; narrow in a LATER deploy, after every writer refuses such input itself"
|
|
@@ -4972,12 +4997,12 @@ BEGIN
|
|
|
4972
4997
|
case "drop-unique":
|
|
4973
4998
|
case "drop-unique-composite":
|
|
4974
4999
|
case "drop-foreign-key":
|
|
4975
|
-
case "drop-check": return
|
|
5000
|
+
case "drop-check": return $;
|
|
4976
5001
|
}
|
|
4977
|
-
},
|
|
4978
|
-
let t = [], n = { createdTables:
|
|
5002
|
+
}, xc = (e) => {
|
|
5003
|
+
let t = [], n = { createdTables: vc(e) };
|
|
4979
5004
|
for (let r of e) {
|
|
4980
|
-
let e =
|
|
5005
|
+
let e = bc(r.op, n);
|
|
4981
5006
|
e.safe || t.push({
|
|
4982
5007
|
op: r,
|
|
4983
5008
|
reason: e.reason,
|
|
@@ -4985,7 +5010,7 @@ BEGIN
|
|
|
4985
5010
|
});
|
|
4986
5011
|
}
|
|
4987
5012
|
return t;
|
|
4988
|
-
},
|
|
5013
|
+
}, Sc = (e) => {
|
|
4989
5014
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
4990
5015
|
refuse: !1,
|
|
4991
5016
|
warnForced: !1,
|
|
@@ -5001,18 +5026,18 @@ BEGIN
|
|
|
5001
5026
|
warnForced: !1,
|
|
5002
5027
|
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.`
|
|
5003
5028
|
};
|
|
5004
|
-
},
|
|
5029
|
+
}, Cc = (e) => {
|
|
5005
5030
|
let t = e.table;
|
|
5006
5031
|
if (typeof t == "string") return t;
|
|
5007
5032
|
let n = e.from;
|
|
5008
5033
|
return typeof n == "string" ? n : void 0;
|
|
5009
|
-
},
|
|
5034
|
+
}, wc = (e) => ({
|
|
5010
5035
|
kind: e.op.kind,
|
|
5011
|
-
table:
|
|
5036
|
+
table: Cc(e.op),
|
|
5012
5037
|
classification: e.classification,
|
|
5013
5038
|
reason: e.reason,
|
|
5014
5039
|
blockedFix: e.blocked?.fix
|
|
5015
|
-
}),
|
|
5040
|
+
}), Tc = (e) => e.operations.map(wc), Ec = async (e) => {
|
|
5016
5041
|
let t = e.log ?? (() => {}), n = {
|
|
5017
5042
|
branchId: e.branchId,
|
|
5018
5043
|
mechanism: e.mechanism,
|
|
@@ -5031,10 +5056,10 @@ BEGIN
|
|
|
5031
5056
|
applied: !1,
|
|
5032
5057
|
converged: !1,
|
|
5033
5058
|
residual: r,
|
|
5034
|
-
infidelity:
|
|
5059
|
+
infidelity: Tc(o)
|
|
5035
5060
|
};
|
|
5036
5061
|
else {
|
|
5037
|
-
let i = await e.plan(), o =
|
|
5062
|
+
let i = await e.plan(), o = Tc(i), s = o.filter((e) => e.classification === "lossy"), c = hs(i), l = c.operations.filter((e) => e.blocked !== void 0).map(wc);
|
|
5038
5063
|
if (l.length > 0) a = {
|
|
5039
5064
|
...n,
|
|
5040
5065
|
outcome: "blocked",
|
|
@@ -5059,7 +5084,7 @@ BEGIN
|
|
|
5059
5084
|
};
|
|
5060
5085
|
else {
|
|
5061
5086
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
5062
|
-
let i =
|
|
5087
|
+
let i = Tc(await e.replan());
|
|
5063
5088
|
a = {
|
|
5064
5089
|
...n,
|
|
5065
5090
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -5097,7 +5122,7 @@ BEGIN
|
|
|
5097
5122
|
...a,
|
|
5098
5123
|
tornDown: o
|
|
5099
5124
|
};
|
|
5100
|
-
},
|
|
5125
|
+
}, Dc = (e) => {
|
|
5101
5126
|
switch (e.outcome) {
|
|
5102
5127
|
case "clean": return 0;
|
|
5103
5128
|
case "lossy": return 2;
|
|
@@ -5106,28 +5131,28 @@ BEGIN
|
|
|
5106
5131
|
case "infidelity": return 1;
|
|
5107
5132
|
case "failed": return 1;
|
|
5108
5133
|
}
|
|
5109
|
-
},
|
|
5134
|
+
}, Oc = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, kc = (e) => {
|
|
5110
5135
|
let t = [];
|
|
5111
5136
|
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"}`);
|
|
5112
5137
|
else if (e.outcome === "infidelity") {
|
|
5113
5138
|
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:");
|
|
5114
|
-
for (let n of e.infidelity) t.push(
|
|
5139
|
+
for (let n of e.infidelity) t.push(Oc(n));
|
|
5115
5140
|
} else {
|
|
5116
5141
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
5117
|
-
for (let n of e.operations) t.push(
|
|
5118
|
-
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(
|
|
5142
|
+
for (let n of e.operations) t.push(Oc(n));
|
|
5143
|
+
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(Oc(n));
|
|
5119
5144
|
}
|
|
5120
5145
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
5121
|
-
},
|
|
5122
|
-
let e = yield* j.SqlClient, n =
|
|
5146
|
+
}, Ac = "tenant_", jc = (e) => e.map((e) => Object.fromEntries(Object.entries(e).map(([e, t]) => [e.toLowerCase(), t]))), Mc = async (e, t) => e(A.gen(function* () {
|
|
5147
|
+
let e = yield* j.SqlClient, n = jc(yield* e`
|
|
5123
5148
|
SELECT schema_name FROM information_schema.schemata
|
|
5124
|
-
WHERE schema_name LIKE ${`${
|
|
5149
|
+
WHERE schema_name LIKE ${`${Ac}%`} ORDER BY schema_name`), r = [];
|
|
5125
5150
|
for (let { schema_name: i } of n) {
|
|
5126
|
-
let n =
|
|
5151
|
+
let n = jc(yield* e`
|
|
5127
5152
|
SELECT table_name, column_name, data_type, character_set_name
|
|
5128
5153
|
FROM information_schema.columns
|
|
5129
5154
|
WHERE table_schema = ${i}
|
|
5130
|
-
ORDER BY table_name, ordinal_position`), a =
|
|
5155
|
+
ORDER BY table_name, ordinal_position`), a = jc(yield* e`
|
|
5131
5156
|
SELECT cc.table_name AS table_name, cc.check_clause AS check_clause
|
|
5132
5157
|
FROM information_schema.check_constraints cc
|
|
5133
5158
|
WHERE cc.constraint_schema = ${i}`.pipe(A.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set();
|
|
@@ -5147,7 +5172,7 @@ BEGIN
|
|
|
5147
5172
|
}, r = s.get(e.table_name) ?? [];
|
|
5148
5173
|
r.push(n), s.set(e.table_name, r);
|
|
5149
5174
|
}
|
|
5150
|
-
let c =
|
|
5175
|
+
let c = vr({
|
|
5151
5176
|
live: { tables: [...s].map(([e, t]) => ({
|
|
5152
5177
|
name: e,
|
|
5153
5178
|
columns: t,
|
|
@@ -5162,10 +5187,10 @@ BEGIN
|
|
|
5162
5187
|
});
|
|
5163
5188
|
}
|
|
5164
5189
|
return r;
|
|
5165
|
-
})),
|
|
5190
|
+
})), Nc = (e, ...t) => ({
|
|
5166
5191
|
_tag: "RawSqlFragment",
|
|
5167
5192
|
strings: [...e],
|
|
5168
5193
|
values: [...t]
|
|
5169
|
-
}),
|
|
5194
|
+
}), Pc = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
5170
5195
|
//#endregion
|
|
5171
|
-
export {
|
|
5196
|
+
export { Nt as DEFAULT_CDC_CHANNEL, z as DEPLOY_LEDGER_TABLE, ue as FILE_MIGRATION_PATTERN, ac as FileMigrationLedgerError, e as IrreversibleMigrationError, gt as MIGRATION_ATOMICITY, pt as MIGRATION_NEEDS_TWO_CONNECTIONS, le as MIGRATION_PHASES, dr as MYSQL_CHARSETS, x as MigrationExpectationFailed, S as MigrationNeedsSqlClient, T as MigrationSkipped, Pt as REACTIVE_TRIGGER_PREFIX, d as RewriteUnstableError, br as STORE_CHARSET_REMEDY, g as TransactionBrokenByBodyError, Ke as VOLTRO_MIGRATION_LOCK_KEY, li as _voltroDeploysTable, ft as acquireMigrationLock, Ao as addColumnDdl, H as appliedAtValue, tc as appliedFileMigrationIds, nc as appliedFileMigrations, Jo as appliedLedgerOperations, Nn as applyNamespacedSchema, ts as applyPlan, Cn as applySchema, Sc as assessRollingDeployGate, Dc as branchRehearsalExitCode, hr as charsetColumnsOf, Ti as chunkTables, bc as classifyRollingDeploySafety, Yo as clearResumeLedger, di as closeDeploy, pr as columnTakesCharset, vc as createdTablesOf, Tr as declaredSnapshot, Wt as defaultArrayClause, Ut as defaultClause, Gt as defaultJsonClause, ys as describeOutcome, Hs as describeProbe, yr as describeStoreCharsetFinding, ps as destructiveScope, Dr as detectReactiveTriggerDrift, to as emitAddIndexMysql, Ma as emitConvertCharsetMysql, Ka as emitCreateTableMssql, Na as emitCreateTableMysql, Ea as emitCreateTablePg, za as emitCreateTableSqlite, sa as emitDropColumnDdl, ca as emitDropColumnDdlMysql, Sn as emitFrameworkBootstrapSql, bn as emitNamespaceProvisionDdl, xn as emitNamespacedSchemaSql, yn as emitSchemaSql, Vi as engineFromVersion, Bo as ensureDeployLedgerTable, Ro as ensureLedgerTable, zo as ensurePlanLedgerTable, Vo as ensureReplaceMarkerTable, _n as enumRenameBlocks, gn as enumTypeBlocks, un as extensionBlocks, fi as failDeploy, Vs as failedExpectations, pc as fileMigrationStatus, L as fingerprintSchema, Qe as fnv1a64, kc as formatBranchRehearsal, Or as formatReactiveTriggerDrift, fs as ignoreTablesFromEnv, Bi as introspectSchema, b as irreversible, D as irreversibleReason, Ki as isAlreadySatisfied, ye as isFileMigration, fr as isMysqlCharset, Pc as isRawSqlFragment, Tn as isReRunSafeDdl, Bs as makeFileMigrationContext, gi as mapPgType, Ss as materialiseSnapshot, t as migration, _t as migrationAtomicityFor, Js as migrationBodyHash, $e as migrationLockKeyForSchema, et as migrationLockNameForSchema, Xa as mysqlIndexPrefixFor, zt as notifyFunctionName, Kt as numericIdSql, ui as openDeploy, hi as parseEnumCheck, dc as pendingFileMigrationIds, fc as pendingFileMigrationSummary, Ks as permanentSkips, ci as planMigrations, o as plannableLiveTables, Gs as plannedCreations, Pn as provisionTenantNamespace, Ft as reactiveTriggerName, ln as reactiveTriggerRepairSql, ss as recordUpToDate, Ue as registerSqlPoolCapacity, Ec as rehearseMigrationOnBranch, wc as rehearsedOperation, ka as renderColumnMysql, Ca as renderColumnPg, Je as resolveMigrationLockSchema, V as resolveMysqlEngine, gc as rollbackFileBasedMigration, xc as rollingDeployUnsafeOps, mc as runFileBasedMigrations, Fn as runFrameworkBootstrap, Mn as runMigrate, is as runMigrationOp, vs as runPlannedMigrations, X as runSchemaOp, ur as shortFingerprint, xr as snapshotColumn, Nc as sql, We as sqlPoolCapacity, I as sqlType, _c as squashMigrationPlans, mr as stampDeclaredCharset, vr as storeCharsetFindings, Mc as tenantNamespaceCharsetFindings, hs as unblockLossy, pi as unfinishedDeploys, Xs as walkMigrationFiles, ht as withMigrationLock, Ws as withSchemaProbeRecorder };
|