@voltro/database 0.40.0 → 0.42.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 +171 -0
- package/dist/{frameworkLiveTables-BS6FuivX.js → frameworkLiveTables-XPFqj8n3.js} +247 -247
- package/dist/index.d.ts +162 -0
- package/dist/index.js +815 -657
- package/dist/sql.d.ts +44 -4
- package/dist/sql.js +854 -796
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Effect as
|
|
3
|
-
import { createLogger as
|
|
1
|
+
import { Jt as e, Lt as t, Q as n, Rt as r, X as i, Yt as a, Z as o, _ as s, a as c, c as l, ht as u, i as d, l as f, m as p, n as m, nt as h, o as g, p as _, r as v, tt as y, xt as b } from "./frameworkLiveTables-XPFqj8n3.js";
|
|
2
|
+
import { Effect as x, Schedule as S } from "effect";
|
|
3
|
+
import { createLogger as ee } from "@voltro/logger";
|
|
4
4
|
import { SqlClient as C } from "@effect/sql";
|
|
5
|
-
import { createHash as
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
5
|
+
import { createHash as te } from "node:crypto";
|
|
6
|
+
import { promises as ne } from "node:fs";
|
|
7
|
+
import { join as re } from "node:path";
|
|
8
|
+
import { pathToFileURL as ie } from "node:url";
|
|
9
9
|
//#region src/migrations/ddlError.ts
|
|
10
|
-
var
|
|
10
|
+
var ae = (e, t, n, r = 400) => {
|
|
11
11
|
let i = n, a = i.cause ?? {}, o = (e) => {
|
|
12
12
|
let t = a[e];
|
|
13
13
|
return t == null || t === "" ? void 0 : String(t);
|
|
@@ -38,21 +38,21 @@ var ie = (e, t, n, r = 400) => {
|
|
|
38
38
|
let t = o(e);
|
|
39
39
|
t !== void 0 && s.push(`db.${e}: ${t}`);
|
|
40
40
|
}
|
|
41
|
-
let c =
|
|
41
|
+
let c = oe(o("code"));
|
|
42
42
|
return c !== void 0 && s.push("", c), s.push(""), s.join("\n");
|
|
43
|
-
},
|
|
44
|
-
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(
|
|
43
|
+
}, oe = (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, se = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, ce = (e) => e.replace(/"/g, "`"), le = (e) => typeof e == "string" ? e : e.name ?? String(e), ue = (e, t) => `_ua_${t}_${e}`.slice(0, 64), de = (e, t) => {
|
|
44
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(se)) return e;
|
|
45
45
|
let n = { ...e.fields }, r = [], i = [];
|
|
46
46
|
for (let t of e.appliedIndexes) {
|
|
47
|
-
if (!
|
|
47
|
+
if (!se(t)) {
|
|
48
48
|
r.push(t);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
|
-
let a =
|
|
51
|
+
let a = ce(t.where), o = [];
|
|
52
52
|
for (let r of t.fields) {
|
|
53
|
-
let i =
|
|
53
|
+
let i = le(r);
|
|
54
54
|
if (!(i in e.fields)) throw Error(`@voltro/migrate: uniqueActive '${t.name}' on '${e.tableName}' references unknown column '${i}'.`);
|
|
55
|
-
let s =
|
|
55
|
+
let s = ue(t.name, i);
|
|
56
56
|
o.push(s), n[s] = {
|
|
57
57
|
type: "text",
|
|
58
58
|
nullable: !0,
|
|
@@ -75,7 +75,7 @@ var ie = (e, t, n, r = 400) => {
|
|
|
75
75
|
appliedIndexes: r,
|
|
76
76
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
77
77
|
};
|
|
78
|
-
}, w = (e, t) => `${e}::${t}`,
|
|
78
|
+
}, w = (e, t) => `${e}::${t}`, fe = (e, t) => {
|
|
79
79
|
let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
|
|
80
80
|
n.add(e);
|
|
81
81
|
let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
|
|
@@ -84,90 +84,90 @@ var ie = (e, t, n, r = 400) => {
|
|
|
84
84
|
};
|
|
85
85
|
for (let t of [...e].sort()) r.has(t) || a(t);
|
|
86
86
|
return i;
|
|
87
|
-
},
|
|
87
|
+
}, pe = 6322741009312437n, me = (e) => {
|
|
88
88
|
let t = e?.trim();
|
|
89
89
|
return t === void 0 || t === "" || t === "public" ? void 0 : t;
|
|
90
|
-
},
|
|
91
|
-
let t =
|
|
92
|
-
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t *
|
|
90
|
+
}, he = (e) => e?.schema === void 0 ? me(process.env.DB_SCHEMA) : me(e.schema), ge = 14695981039346656037n, _e = 1099511628211n, ve = 18446744073709551615n, ye = (e) => {
|
|
91
|
+
let t = ge;
|
|
92
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * _e & ve;
|
|
93
93
|
return t;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
return t === void 0 ?
|
|
94
|
+
}, be = (e) => {
|
|
95
|
+
let t = me(e);
|
|
96
|
+
return t === void 0 ? pe : ye(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
97
97
|
}, T = (e) => {
|
|
98
|
-
let t = `voltro_migration_${
|
|
98
|
+
let t = `voltro_migration_${pe.toString(36)}`, n = me(e);
|
|
99
99
|
if (n === void 0) return t;
|
|
100
100
|
let r = `${t}_${n}`;
|
|
101
|
-
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(
|
|
102
|
-
},
|
|
101
|
+
return /^[A-Za-z0-9_]+$/.test(n) && r.length <= 64 ? r : `${t}_h${(ye(`voltro_migration_lock:${n}`) & ve).toString(16)}`;
|
|
102
|
+
}, xe = 250, Se = () => {
|
|
103
103
|
let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
|
|
104
104
|
return Number.isFinite(e) && e > 0 ? e : 3e4;
|
|
105
|
-
},
|
|
106
|
-
let n =
|
|
105
|
+
}, Ce = (e, t) => x.gen(function* () {
|
|
106
|
+
let n = Se(), r = Date.now();
|
|
107
107
|
for (;;) {
|
|
108
108
|
if ((yield* e`
|
|
109
109
|
SELECT pg_try_advisory_lock(${t.toString()}::bigint) AS got`)[0]?.got) return;
|
|
110
|
-
Date.now() - r >= n && (yield*
|
|
110
|
+
Date.now() - r >= n && (yield* x.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* x.sleep(`${xe} millis`);
|
|
111
111
|
}
|
|
112
|
-
}),
|
|
112
|
+
}), we = (e, t) => x.gen(function* () {
|
|
113
113
|
yield* e`SELECT pg_advisory_unlock(${t.toString()}::bigint)`;
|
|
114
|
-
}),
|
|
114
|
+
}), Te = 30, Ee = (e, t) => x.gen(function* () {
|
|
115
115
|
(yield* e`
|
|
116
|
-
SELECT GET_LOCK(${t}, ${
|
|
117
|
-
}),
|
|
116
|
+
SELECT GET_LOCK(${t}, ${Te}) AS got`)[0]?.got !== 1 && (yield* x.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${Te}s (another migration is in progress, or a prior one left it held).`)));
|
|
117
|
+
}), De = (e, t) => x.gen(function* () {
|
|
118
118
|
yield* e`SELECT RELEASE_LOCK(${t})`;
|
|
119
|
-
}),
|
|
119
|
+
}), Oe = 3e4, ke = (e, t) => x.gen(function* () {
|
|
120
120
|
let n = yield* e`
|
|
121
121
|
DECLARE @res int;
|
|
122
122
|
EXEC @res = sp_getapplock @Resource = ${t}, @LockMode = 'Exclusive',
|
|
123
|
-
@LockOwner = 'Session', @LockTimeout = ${
|
|
123
|
+
@LockOwner = 'Session', @LockTimeout = ${Oe};
|
|
124
124
|
SELECT @res AS res`;
|
|
125
|
-
(n[0]?.res ?? -999) < 0 && (yield*
|
|
126
|
-
}),
|
|
125
|
+
(n[0]?.res ?? -999) < 0 && (yield* x.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
126
|
+
}), Ae = (e, t) => x.gen(function* () {
|
|
127
127
|
yield* e`EXEC sp_releaseapplock @Resource = ${t}, @LockOwner = 'Session'`;
|
|
128
|
-
}),
|
|
129
|
-
let n =
|
|
128
|
+
}), je = x.void, E = (e, t) => {
|
|
129
|
+
let n = he(t);
|
|
130
130
|
return e.onDialectOrElse({
|
|
131
|
-
mysql: () =>
|
|
132
|
-
mssql: () =>
|
|
133
|
-
sqlite: () =>
|
|
134
|
-
orElse: () =>
|
|
131
|
+
mysql: () => Ee(e, T(n)),
|
|
132
|
+
mssql: () => ke(e, T(n)),
|
|
133
|
+
sqlite: () => je,
|
|
134
|
+
orElse: () => Ce(e, be(n))
|
|
135
135
|
});
|
|
136
136
|
}, D = (e, t) => {
|
|
137
|
-
let n =
|
|
137
|
+
let n = he(t);
|
|
138
138
|
return e.onDialectOrElse({
|
|
139
|
-
mysql: () =>
|
|
140
|
-
mssql: () =>
|
|
141
|
-
sqlite: () =>
|
|
142
|
-
orElse: () =>
|
|
139
|
+
mysql: () => De(e, T(n)),
|
|
140
|
+
mssql: () => Ae(e, T(n)),
|
|
141
|
+
sqlite: () => je,
|
|
142
|
+
orElse: () => we(e, be(n))
|
|
143
143
|
});
|
|
144
|
-
},
|
|
144
|
+
}, Me = (e, t, n) => x.acquireUseRelease(E(e, n), () => t, () => D(e, n).pipe(x.orDie)), Ne = (e) => e.onDialectOrElse({
|
|
145
145
|
pg: () => "postgres",
|
|
146
146
|
mysql: () => "mysql",
|
|
147
147
|
mssql: () => "mssql",
|
|
148
148
|
sqlite: () => "sqlite",
|
|
149
149
|
orElse: () => "sqlite"
|
|
150
|
-
}),
|
|
150
|
+
}), Pe = {
|
|
151
151
|
postgres: "plan-transactional",
|
|
152
152
|
mssql: "plan-transactional",
|
|
153
153
|
mysql: "per-operation",
|
|
154
154
|
mariadb: "per-operation",
|
|
155
155
|
sqlite: "per-operation",
|
|
156
156
|
turso: "per-operation"
|
|
157
|
-
},
|
|
158
|
-
id:
|
|
159
|
-
runId:
|
|
160
|
-
planFingerprint:
|
|
161
|
-
opIndex:
|
|
162
|
-
opKind:
|
|
163
|
-
opTarget:
|
|
164
|
-
status:
|
|
165
|
-
payload:
|
|
166
|
-
startedAt:
|
|
167
|
-
appliedAt:
|
|
168
|
-
durationMs:
|
|
169
|
-
createdAt:
|
|
170
|
-
}),
|
|
157
|
+
}, Fe = (e) => Pe[e], O = "_voltro_migration_ops", Ie = y(O, {
|
|
158
|
+
id: t({ prefix: "mop" }),
|
|
159
|
+
runId: e(),
|
|
160
|
+
planFingerprint: e(),
|
|
161
|
+
opIndex: r(),
|
|
162
|
+
opKind: e(),
|
|
163
|
+
opTarget: e(),
|
|
164
|
+
status: e(),
|
|
165
|
+
payload: e(),
|
|
166
|
+
startedAt: a().nullable(),
|
|
167
|
+
appliedAt: a().nullable(),
|
|
168
|
+
durationMs: r().nullable(),
|
|
169
|
+
createdAt: a().default("now")
|
|
170
|
+
}), Le = (e) => {
|
|
171
171
|
switch (e.kind) {
|
|
172
172
|
case "create-table": return /* @__PURE__ */ new Set([
|
|
173
173
|
`table:${e.table}`,
|
|
@@ -194,11 +194,11 @@ var ie = (e, t, n, r = 400) => {
|
|
|
194
194
|
case "add-unique-composite":
|
|
195
195
|
case "drop-unique-composite": return /* @__PURE__ */ new Set([`unique:${e.table}.${e.name}`]);
|
|
196
196
|
}
|
|
197
|
-
},
|
|
198
|
-
let n =
|
|
199
|
-
for (let t of
|
|
197
|
+
}, Re = (e) => [...Le(e)].join(" "), ze = (e, t) => {
|
|
198
|
+
let n = Le(t);
|
|
199
|
+
for (let t of Le(e)) if (n.has(t)) return !0;
|
|
200
200
|
return !1;
|
|
201
|
-
},
|
|
201
|
+
}, Be = (e, t) => e.operations.some((e) => ze(e.op, t)), Ve = "__voltro_rebuild", He = "__shadow", Ue = "__old", We = /* @__PURE__ */ new Set([
|
|
202
202
|
"add-unique",
|
|
203
203
|
"drop-unique",
|
|
204
204
|
"add-unique-composite",
|
|
@@ -210,15 +210,15 @@ var ie = (e, t, n, r = 400) => {
|
|
|
210
210
|
"alter-column-nullability",
|
|
211
211
|
"alter-column-type",
|
|
212
212
|
"alter-column-default"
|
|
213
|
-
]),
|
|
213
|
+
]), Ge = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Ke = (e, t, n) => {
|
|
214
214
|
let r = n === "sqlite" || n === "turso";
|
|
215
|
-
return e.kind === "alter-column-type" && t === "online-required" || r &&
|
|
215
|
+
return e.kind === "alter-column-type" && t === "online-required" || r && We.has(e.kind) ? "artefact-repair" : Ge.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
216
216
|
};
|
|
217
|
-
Object.keys(
|
|
217
|
+
Object.keys(Pe);
|
|
218
218
|
//#endregion
|
|
219
219
|
//#region src/migrations/reactiveTriggerName.ts
|
|
220
|
-
var k = "framework_changes",
|
|
221
|
-
|
|
220
|
+
var k = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "framework_changes" ? `${qe}${e}` : `${qe}${t}_${e}`, Ye = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, Xe = "voltro:notify:v2", Ze = ee({ scope: "voltro:migrate" }), A = (e) => {
|
|
221
|
+
Ze.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
222
222
|
}, j = (e, t) => {
|
|
223
223
|
let n = e.type;
|
|
224
224
|
if (e.spatial) {
|
|
@@ -237,36 +237,36 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
237
237
|
}, t)}[]`;
|
|
238
238
|
if (t === "mysql" || t === "mariadb") return "JSON";
|
|
239
239
|
if (t === "mssql") return "NVARCHAR(MAX)";
|
|
240
|
-
if (
|
|
240
|
+
if (o(t)) return "TEXT";
|
|
241
241
|
}
|
|
242
242
|
if (n === "vector") {
|
|
243
243
|
let n = e.vectorDim;
|
|
244
244
|
if (n === void 0) throw Error("vector column is missing its dimension — this is a framework bug.");
|
|
245
|
-
let
|
|
246
|
-
if (t === "postgres") return
|
|
245
|
+
let r = e.vectorPrecision === "half";
|
|
246
|
+
if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
|
|
247
247
|
if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
|
|
248
248
|
if (t === "mssql") return "VARBINARY(MAX)";
|
|
249
|
-
if (
|
|
249
|
+
if (o(t)) return "BLOB";
|
|
250
250
|
}
|
|
251
251
|
if (n === "interval") {
|
|
252
252
|
if (t === "postgres") return "INTERVAL";
|
|
253
253
|
if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
|
|
254
|
-
if (
|
|
254
|
+
if (o(t)) return "INTEGER";
|
|
255
255
|
}
|
|
256
256
|
if (n === "decimal") {
|
|
257
|
-
let n = e.precision,
|
|
257
|
+
let n = e.precision, r = e.scale ?? 0;
|
|
258
258
|
if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
|
|
259
|
-
return
|
|
259
|
+
return o(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
|
|
260
260
|
}
|
|
261
|
-
if (n === "bigint") return
|
|
261
|
+
if (n === "bigint") return o(t) ? "INTEGER" : "BIGINT";
|
|
262
262
|
if (n === "enum") {
|
|
263
263
|
if (t === "postgres") return e.enumName ?? "TEXT";
|
|
264
264
|
if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
|
|
265
265
|
if (t === "mssql") return "NVARCHAR(255)";
|
|
266
|
-
if (
|
|
266
|
+
if (o(t)) return "TEXT";
|
|
267
267
|
}
|
|
268
|
-
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` :
|
|
269
|
-
if (
|
|
268
|
+
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` : o(t) ? "TEXT" : `VARCHAR(${e.maxLength})`;
|
|
269
|
+
if (o(t)) switch (n) {
|
|
270
270
|
case "id": return "TEXT";
|
|
271
271
|
case "text": return "TEXT";
|
|
272
272
|
case "integer": return "INTEGER";
|
|
@@ -330,11 +330,11 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
330
330
|
case "array": return "TEXT[]";
|
|
331
331
|
case "interval": return "INTERVAL";
|
|
332
332
|
}
|
|
333
|
-
},
|
|
333
|
+
}, Qe = (e, t) => {
|
|
334
334
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
335
335
|
let n = e.defaultValue;
|
|
336
|
-
return n === "now" ?
|
|
337
|
-
},
|
|
336
|
+
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) ? $e(n, e, t) : typeof n == "object" && n ? M(n, t) : null;
|
|
337
|
+
}, $e = (e, t, n) => {
|
|
338
338
|
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return M(e, n);
|
|
339
339
|
let r = j({
|
|
340
340
|
...t,
|
|
@@ -354,7 +354,7 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
354
354
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
355
355
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
356
356
|
}
|
|
357
|
-
},
|
|
357
|
+
}, P = (e, t) => {
|
|
358
358
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
359
359
|
switch (e) {
|
|
360
360
|
case "cascade": return "CASCADE";
|
|
@@ -362,14 +362,18 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
362
362
|
case "setNull": return "SET NULL";
|
|
363
363
|
case "noAction": return "NO ACTION";
|
|
364
364
|
}
|
|
365
|
-
}, et = (e, t,
|
|
366
|
-
|
|
367
|
-
|
|
365
|
+
}, et = (e, t, r) => r === null ? n(e, t) : `${n(r, t)}.${n(e, t)}`, tt = 191, nt = (e, t) => {
|
|
366
|
+
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
367
|
+
let n = j(e, t).toUpperCase();
|
|
368
|
+
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
369
|
+
}, rt = (e, t, r) => {
|
|
370
|
+
let i = n(e, r);
|
|
371
|
+
if (r !== "mysql" && r !== "mariadb") return i;
|
|
368
372
|
let a = t[e];
|
|
369
|
-
if (!a) return
|
|
370
|
-
let o = j(a,
|
|
371
|
-
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${
|
|
372
|
-
},
|
|
373
|
+
if (!a) return i;
|
|
374
|
+
let o = j(a, r).toUpperCase();
|
|
375
|
+
return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${tt})` : i;
|
|
376
|
+
}, it = (e, t) => {
|
|
373
377
|
if (!e.generatedAs) return null;
|
|
374
378
|
let { expr: n, stored: r } = e.generatedAs;
|
|
375
379
|
if (t === "postgres") return r || A("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
@@ -377,65 +381,70 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
377
381
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
378
382
|
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.");
|
|
379
383
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
380
|
-
},
|
|
381
|
-
if (t.type === "id" && t.idScheme?.kind === "numeric") return N(e,
|
|
382
|
-
let
|
|
383
|
-
t.type === "id" && !
|
|
384
|
-
let
|
|
385
|
-
if (
|
|
384
|
+
}, at = (e, t, r, a, s = !1, c = !1) => {
|
|
385
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return N(e, r);
|
|
386
|
+
let l = r === "mssql" && t.type === "text" && !t.generatedAs && t.maxLength === void 0 && a?.has(e) ? "NVARCHAR(450)" : j(t, r), u = [n(e, r), l];
|
|
387
|
+
t.type === "id" && !c && u.push("PRIMARY KEY");
|
|
388
|
+
let d = it(t, r);
|
|
389
|
+
if (d) u.push(d);
|
|
386
390
|
else {
|
|
387
|
-
t.nullable ||
|
|
388
|
-
let e =
|
|
389
|
-
e &&
|
|
391
|
+
t.nullable || u.push("NOT NULL"), t.unique && t.type !== "id" && !nt(t, r) && u.push("UNIQUE");
|
|
392
|
+
let e = Qe(t, r);
|
|
393
|
+
e && u.push(e);
|
|
390
394
|
}
|
|
391
|
-
if (t.type === "reference" && t.references && !
|
|
395
|
+
if (t.type === "reference" && t.references && !s && !i(r)) {
|
|
392
396
|
let e = t.references();
|
|
393
|
-
|
|
394
|
-
let
|
|
395
|
-
|
|
396
|
-
let a =
|
|
397
|
-
a !== "NO ACTION" &&
|
|
397
|
+
u.push(`REFERENCES ${n(e.tableName, r)} (${n("id", r)})`);
|
|
398
|
+
let i = P(t.onDelete ?? "restrict", r);
|
|
399
|
+
u.push(`ON DELETE ${i}`);
|
|
400
|
+
let a = P(t.refOnUpdate ?? "noAction", r);
|
|
401
|
+
a !== "NO ACTION" && u.push(`ON UPDATE ${a}`);
|
|
398
402
|
}
|
|
399
403
|
if (t.oneOf && t.oneOf.length > 0) {
|
|
400
|
-
let
|
|
401
|
-
|
|
404
|
+
let i = t.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
405
|
+
u.push(`CHECK (${n(e, r)} IN (${i}))`);
|
|
402
406
|
}
|
|
403
|
-
if (t.checks && t.checks.length > 0) for (let e of t.checks)
|
|
404
|
-
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (
|
|
405
|
-
let
|
|
406
|
-
|
|
407
|
+
if (t.checks && t.checks.length > 0) for (let e of t.checks) u.push(`CHECK (${e})`);
|
|
408
|
+
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (r === "mssql" || o(r))) {
|
|
409
|
+
let i = t.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
410
|
+
u.push(`CHECK (${n(e, r)} IN (${i}))`);
|
|
407
411
|
}
|
|
408
412
|
if (t.type === "json" || t.type === "array") {
|
|
409
|
-
let t =
|
|
410
|
-
r
|
|
411
|
-
}
|
|
412
|
-
return
|
|
413
|
-
},
|
|
414
|
-
let
|
|
415
|
-
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" &&
|
|
416
|
-
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" &&
|
|
417
|
-
let
|
|
418
|
-
let
|
|
419
|
-
return ` CONSTRAINT ${
|
|
420
|
-
}),
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
413
|
+
let t = n(e, r);
|
|
414
|
+
o(r) ? u.push(`CHECK (${t} IS NULL OR json_valid(${t}))`) : r === "mssql" && u.push(`CHECK (${t} IS NULL OR ISJSON(${t}) = 1)`);
|
|
415
|
+
}
|
|
416
|
+
return u.join(" ");
|
|
417
|
+
}, ot = (e, t, r = null, a) => {
|
|
418
|
+
let o = /* @__PURE__ */ new Set();
|
|
419
|
+
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
420
|
+
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && o.add(e);
|
|
421
|
+
let s = e.appliedPrimaryKey ?? [], c = s.length > 0, l = Object.entries(e.fields).map(([e, n]) => ` ${at(e, n, t, o, a?.has(e) ?? !1, c)}`).join(",\n"), u = (e.appliedUniques ?? []).map((r) => {
|
|
422
|
+
let i = r.fields.map((n) => rt(n, e.fields, t)).join(", ");
|
|
423
|
+
return ` CONSTRAINT ${n(r.name, t)} UNIQUE (${i})`;
|
|
424
|
+
}), d = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${n(e.name, t)} CHECK (${e.expr})`), f = c ? [` PRIMARY KEY (${s.map((n) => rt(n, e.fields, t)).join(", ")})`] : [], p = i(t) ? Object.entries(e.fields).flatMap(([i, o]) => {
|
|
425
|
+
if (o.type !== "reference" || !o.references || (a?.has(i) ?? !1)) return [];
|
|
426
|
+
let s = o.references(), c = P(o.onDelete ?? "restrict", t), l = P(o.refOnUpdate ?? "noAction", t);
|
|
427
|
+
return [` CONSTRAINT ${n(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${n(i, t)}) REFERENCES ${et(s.tableName, t, r)} (${n("id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
428
|
+
}) : [], m = [
|
|
429
|
+
...f,
|
|
430
|
+
...u,
|
|
431
|
+
...d,
|
|
432
|
+
...p
|
|
433
|
+
], h = m.length > 0 ? `${l},\n${m.join(",\n")}` : l, g = et(e.tableName, t, r);
|
|
425
434
|
if (t === "mssql") {
|
|
426
|
-
let t =
|
|
427
|
-
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${
|
|
435
|
+
let t = r === null ? e.tableName : `${r}.${e.tableName}`, n = `CREATE TABLE ${g} (\n${h}\n)`;
|
|
436
|
+
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${n.replace(/'/g, "''")}');`;
|
|
428
437
|
}
|
|
429
438
|
return [
|
|
430
|
-
`CREATE TABLE IF NOT EXISTS ${
|
|
431
|
-
|
|
439
|
+
`CREATE TABLE IF NOT EXISTS ${g} (`,
|
|
440
|
+
h,
|
|
432
441
|
");"
|
|
433
442
|
].join("\n");
|
|
434
|
-
},
|
|
435
|
-
let
|
|
436
|
-
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${a(
|
|
437
|
-
},
|
|
438
|
-
let
|
|
443
|
+
}, st = (e, t, r) => {
|
|
444
|
+
let i = `${e}_${t.name}_fts`, a = (e) => n(e, r), o = t.columns.map(a).join(", "), s = t.columns.map((e) => `new.${a(e)}`).join(", "), c = [];
|
|
445
|
+
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${a(i)} USING fts5(${o}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_ai`)} AFTER INSERT ON ${a(e)} BEGIN\n INSERT INTO ${a(i)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_ad`)} AFTER DELETE ON ${a(e)} BEGIN\n DELETE FROM ${a(i)} WHERE row_id = old.${a("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${a(`${i}_au`)} AFTER UPDATE ON ${a(e)} BEGIN\n DELETE FROM ${a(i)} WHERE row_id = old.${a("id")};\n INSERT INTO ${a(i)} (${o}, row_id) VALUES (${s}, new.${a("id")});\nEND;`), c;
|
|
446
|
+
}, ct = (e, t, r = null) => {
|
|
447
|
+
let i = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, n, r, i) => {
|
|
439
448
|
let a = {
|
|
440
449
|
using: "",
|
|
441
450
|
withSuffix: "",
|
|
@@ -463,7 +472,7 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
463
472
|
} : (A(`[voltro:migrate] brin index '${e}' on '${n}': ${t} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), a);
|
|
464
473
|
if (r === "hnsw") {
|
|
465
474
|
if (t === "postgres") {
|
|
466
|
-
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ??
|
|
475
|
+
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? h(i?.hnsw?.distance);
|
|
467
476
|
return {
|
|
468
477
|
using: " USING hnsw",
|
|
469
478
|
withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
|
|
@@ -480,59 +489,64 @@ var k = "framework_changes", Ke = "framework_changes_", qe = (e, t) => t === "fr
|
|
|
480
489
|
return a;
|
|
481
490
|
}, c = (n, r) => {
|
|
482
491
|
let i = n.map((n) => {
|
|
483
|
-
if (typeof n == "string") return
|
|
492
|
+
if (typeof n == "string") return rt(n, e.fields, t);
|
|
484
493
|
if ("jsonPath" in n) {
|
|
485
494
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
486
|
-
return `(${
|
|
495
|
+
return `(${_(e, r, t, { numeric: i })})`;
|
|
487
496
|
}
|
|
488
497
|
return `(${n.expr})`;
|
|
489
498
|
});
|
|
490
499
|
return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
|
|
491
|
-
}, l = (e,
|
|
492
|
-
let f = s(e,
|
|
500
|
+
}, l = (e, i, a, o, l, u = "", d = !1) => {
|
|
501
|
+
let f = s(e, i, o, l);
|
|
493
502
|
if (f.skip) return "";
|
|
494
|
-
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h = et(
|
|
495
|
-
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${
|
|
503
|
+
let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h = et(i, t, r), g = d ? "UNIQUE " : "";
|
|
504
|
+
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${n(e, t)} ON ${h}${f.using} (${p})${m};` : t === "mysql" ? `CREATE ${g}INDEX ${n(e, t)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${n(e, t)} ON ${h}${f.using} (${p})${m};`;
|
|
496
505
|
};
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
506
|
+
if (t === "mysql" || t === "mariadb") for (let [n, r] of Object.entries(e.fields)) {
|
|
507
|
+
if (!r.unique || r.type === "id" || !nt(r, t)) continue;
|
|
508
|
+
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
509
|
+
a && i.push(a);
|
|
510
|
+
}
|
|
511
|
+
for (let r of e.appliedFullText ?? []) if (t === "postgres") {
|
|
512
|
+
let a = r.config ?? "english", o = `${r.name}_tsv`, s = r.columns.map((e) => {
|
|
513
|
+
let i = r.weights?.[e] ?? "A";
|
|
514
|
+
return `setweight(to_tsvector('${a}', coalesce(${n(e, t)}, '')), '${i}')`;
|
|
501
515
|
}).join(" || ");
|
|
502
|
-
|
|
516
|
+
i.push(`ALTER TABLE ${n(e.tableName, t)} ADD COLUMN IF NOT EXISTS ${n(o, t)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), i.push(`CREATE INDEX IF NOT EXISTS ${n(r.name, t)} ON ${n(e.tableName, t)} USING GIN (${n(o, t)});`);
|
|
503
517
|
} else if (t === "mysql" || t === "mariadb") {
|
|
504
|
-
let a =
|
|
505
|
-
|
|
506
|
-
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${
|
|
507
|
-
else t === "sqlite" ?
|
|
518
|
+
let a = r.columns.map((e) => n(e, t)).join(", ");
|
|
519
|
+
i.push(`CREATE FULLTEXT INDEX ${n(r.name, t)} ON ${n(e.tableName, t)} (${a});`);
|
|
520
|
+
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${r.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
|
|
521
|
+
else t === "sqlite" ? i.push(...st(e.tableName, r, t)) : A(`[voltro:migrate] full-text index '${r.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
508
522
|
for (let n of e.appliedIndexes) {
|
|
509
523
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
510
524
|
A(`[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(...).`);
|
|
511
525
|
continue;
|
|
512
526
|
}
|
|
513
527
|
if (n.unique && n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb")) throw Error(`@voltro/migrate: uniqueActive index '${n.name}' on '${e.tableName}' cannot be expressed on ${t} — it has no partial (WHERE) index support, and a full UNIQUE index would forbid re-creating a soft-deleted row. Use a generated STORED column (text().generatedAs("CASE WHEN \`deletedAt\` IS NULL THEN <key> ELSE NULL END", { stored: true })) + .unique([...]) on ${t}, or move this table to postgres/sqlite/mssql.`);
|
|
514
|
-
let
|
|
515
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? A(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) :
|
|
516
|
-
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions,
|
|
517
|
-
s !== "" &&
|
|
528
|
+
let r = "";
|
|
529
|
+
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ? A(`[voltro:migrate] partial index '${n.name}' on '${e.tableName}': ${t} does not support WHERE clauses on indexes — emitting a full index`) : r = ` WHERE ${n.where}`);
|
|
530
|
+
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions, r, n.unique === !0);
|
|
531
|
+
s !== "" && i.push(s), n.fields.every((e) => typeof e == "string") && a.add(o(n.fields));
|
|
518
532
|
}
|
|
519
533
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
520
534
|
if (n.type !== "reference" || n.fkAutoIndex === !1 || a.has(o([t]))) continue;
|
|
521
|
-
let
|
|
522
|
-
|
|
535
|
+
let r = `${e.tableName}_${t}_idx`;
|
|
536
|
+
i.push(l(r, e.tableName, [t])), a.add(o([t]));
|
|
523
537
|
}
|
|
524
|
-
return
|
|
525
|
-
},
|
|
538
|
+
return i.join("\n");
|
|
539
|
+
}, lt = (e, t, n = k) => {
|
|
526
540
|
if (t !== "postgres") return [];
|
|
527
541
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
528
|
-
return r.length === 0 ? [] : [
|
|
529
|
-
},
|
|
530
|
-
CREATE OR REPLACE FUNCTION ${
|
|
542
|
+
return r.length === 0 ? [] : [ut(n), ...r.map((e) => ft(e, n))];
|
|
543
|
+
}, ut = (e) => `
|
|
544
|
+
CREATE OR REPLACE FUNCTION ${Ye(e)}() RETURNS trigger AS $$
|
|
531
545
|
DECLARE
|
|
532
546
|
payload TEXT;
|
|
533
547
|
pk JSONB;
|
|
534
548
|
BEGIN
|
|
535
|
-
-- ${
|
|
549
|
+
-- ${Xe}
|
|
536
550
|
payload := json_build_object(
|
|
537
551
|
'table', TG_TABLE_NAME,
|
|
538
552
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -586,22 +600,22 @@ BEGIN
|
|
|
586
600
|
RETURN COALESCE(NEW, OLD);
|
|
587
601
|
END;
|
|
588
602
|
$$ LANGUAGE plpgsql;
|
|
589
|
-
`.trim(),
|
|
590
|
-
let n =
|
|
603
|
+
`.trim(), dt = (e, t) => {
|
|
604
|
+
let n = Je(e.tableName, t);
|
|
591
605
|
return [
|
|
592
606
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
593
607
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
594
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
608
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${Ye(t)}()`
|
|
595
609
|
];
|
|
596
|
-
},
|
|
610
|
+
}, ft = (e, t) => dt(e, t).map((e) => `${e};`).join("\n"), pt = (e) => {
|
|
597
611
|
if (e.dialect !== "postgres") return [];
|
|
598
612
|
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));
|
|
599
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
600
|
-
for (let e of i) r.push(...
|
|
601
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
613
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(ut(t));
|
|
614
|
+
for (let e of i) r.push(...dt(n.get(e), t));
|
|
615
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${Je(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
602
616
|
return r;
|
|
603
|
-
},
|
|
604
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
617
|
+
}, mt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), ht = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), gt = (e) => {
|
|
618
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = fe(e.map((e) => e.tableName), (e) => {
|
|
605
619
|
let n = t.get(e);
|
|
606
620
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
607
621
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -637,30 +651,30 @@ $$ LANGUAGE plpgsql;
|
|
|
637
651
|
sorted: o,
|
|
638
652
|
cyclic: r
|
|
639
653
|
};
|
|
640
|
-
},
|
|
641
|
-
let
|
|
654
|
+
}, _t = (e, t, r = null) => {
|
|
655
|
+
let i = (e) => r ? `${n(r, t)}.${n(e, t)}` : n(e, t), a = `${e.table}_${e.column}_fkey`, o = P(e.onDelete, t), s = P(e.onUpdate, t), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (r) => `ADD CONSTRAINT ${n(a, t)} FOREIGN KEY ${r ? "IF NOT EXISTS " : ""}(${n(e.column, t)}) REFERENCES ${i(e.targetTable)} (${n("id", t)})${c}`;
|
|
642
656
|
switch (t) {
|
|
643
657
|
case "postgres": return [
|
|
644
658
|
"DO $$ BEGIN",
|
|
645
659
|
" IF NOT EXISTS (SELECT 1 FROM pg_constraint",
|
|
646
|
-
` WHERE conname = '${a}' AND conrelid = '${
|
|
647
|
-
` ALTER TABLE ${
|
|
660
|
+
` WHERE conname = '${a}' AND conrelid = '${r ? `${r}.` : ""}${e.table}'::regclass) THEN`,
|
|
661
|
+
` ALTER TABLE ${i(e.table)} ${l(!1)};`,
|
|
648
662
|
" END IF;",
|
|
649
663
|
"END $$;"
|
|
650
664
|
].join("\n");
|
|
651
|
-
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${a}') ALTER TABLE ${
|
|
652
|
-
case "mariadb": return `ALTER TABLE ${
|
|
653
|
-
default: return `ALTER TABLE ${
|
|
665
|
+
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${a}') ALTER TABLE ${i(e.table)} ${l(!1)};`;
|
|
666
|
+
case "mariadb": return `ALTER TABLE ${i(e.table)} ${l(!0)};`;
|
|
667
|
+
default: return `ALTER TABLE ${i(e.table)} ${l(!1)};`;
|
|
654
668
|
}
|
|
655
|
-
},
|
|
669
|
+
}, vt = (e, t) => {
|
|
656
670
|
let n = /* @__PURE__ */ new Map();
|
|
657
|
-
if (
|
|
671
|
+
if (o(t)) return n;
|
|
658
672
|
for (let t of e) {
|
|
659
673
|
let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
|
|
660
674
|
e.add(t.column), n.set(t.table, e);
|
|
661
675
|
}
|
|
662
676
|
return n;
|
|
663
|
-
},
|
|
677
|
+
}, yt = (e, t) => {
|
|
664
678
|
if (t !== "postgres") return "";
|
|
665
679
|
let n = /* @__PURE__ */ new Map();
|
|
666
680
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -676,12 +690,12 @@ $$ LANGUAGE plpgsql;
|
|
|
676
690
|
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 $$;`);
|
|
677
691
|
}
|
|
678
692
|
return r.join("\n\n");
|
|
679
|
-
},
|
|
693
|
+
}, bt = (e, t) => {
|
|
680
694
|
if (t !== "postgres") return "";
|
|
681
695
|
let n = /* @__PURE__ */ new Set();
|
|
682
696
|
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
|
|
683
697
|
let r = [];
|
|
684
|
-
for (let e of n) for (let { from: t, to: n } of
|
|
698
|
+
for (let e of n) for (let { from: t, to: n } of b(e)) {
|
|
685
699
|
let i = e.replace(/'/g, "''"), a = t.replace(/'/g, "''"), o = n.replace(/'/g, "''");
|
|
686
700
|
r.push(`DO \$\$
|
|
687
701
|
DECLARE
|
|
@@ -690,95 +704,95 @@ BEGIN
|
|
|
690
704
|
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 $$;`);
|
|
691
705
|
}
|
|
692
706
|
return r.join("\n\n");
|
|
693
|
-
},
|
|
707
|
+
}, xt = (e) => {
|
|
694
708
|
let t = [], n = [];
|
|
695
|
-
for (let r of e)
|
|
709
|
+
for (let r of e) p(r) ? n.push(r) : t.push(r);
|
|
696
710
|
return {
|
|
697
711
|
tables: t,
|
|
698
712
|
views: n
|
|
699
713
|
};
|
|
700
|
-
},
|
|
701
|
-
let { tables:
|
|
702
|
-
t === "postgres" &&
|
|
703
|
-
let d =
|
|
714
|
+
}, St = (e, t, n = k) => {
|
|
715
|
+
let { tables: r, views: i } = xt(e), { sorted: a, cyclic: c } = gt(r.map((e) => de(e, t))), l = vt(c, t), u = [];
|
|
716
|
+
t === "postgres" && mt(a) && u.push("CREATE EXTENSION IF NOT EXISTS vector;"), t === "postgres" && ht(a) && u.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
717
|
+
let d = bt(a, t);
|
|
704
718
|
d && u.push(d);
|
|
705
|
-
let f =
|
|
719
|
+
let f = yt(a, t);
|
|
706
720
|
f && u.push(f);
|
|
707
|
-
for (let e of
|
|
708
|
-
if (!
|
|
709
|
-
for (let e of
|
|
710
|
-
let n =
|
|
721
|
+
for (let e of a) u.push(ot(e, t, null, l.get(e.tableName)));
|
|
722
|
+
if (!o(t)) for (let e of c) u.push(_t(e, t));
|
|
723
|
+
for (let e of a) {
|
|
724
|
+
let n = ct(e, t);
|
|
711
725
|
n && u.push(n);
|
|
712
726
|
}
|
|
713
|
-
u.push(...
|
|
714
|
-
for (let e of
|
|
727
|
+
u.push(...lt(a, t, n));
|
|
728
|
+
for (let e of i) u.push(s(e, t));
|
|
715
729
|
return u.join("\n\n") + "\n";
|
|
716
|
-
},
|
|
717
|
-
let
|
|
730
|
+
}, Ct = (e, t, r) => {
|
|
731
|
+
let i = n(e, t);
|
|
718
732
|
switch (t) {
|
|
719
|
-
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${
|
|
733
|
+
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
|
|
720
734
|
case "mysql":
|
|
721
|
-
case "mariadb": return `CREATE DATABASE IF NOT EXISTS ${
|
|
722
|
-
case "mssql": return `IF SCHEMA_ID('${e.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${
|
|
735
|
+
case "mariadb": return `CREATE DATABASE IF NOT EXISTS ${i};`;
|
|
736
|
+
case "mssql": return `IF SCHEMA_ID('${e.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${i.replace(/'/g, "''")}');`;
|
|
723
737
|
case "turso":
|
|
724
|
-
case "sqlite": return `ATTACH DATABASE '${(
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
let
|
|
728
|
-
if (t === "postgres") return `${
|
|
729
|
-
if (t === "mysql" || t === "mariadb") return `${
|
|
730
|
-
let { sorted: c, cyclic: l } =
|
|
731
|
-
for (let e of c) d.push(
|
|
732
|
-
if (!
|
|
738
|
+
case "sqlite": return `ATTACH DATABASE '${(r ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
|
|
739
|
+
}
|
|
740
|
+
}, wt = (e, t, r, i) => {
|
|
741
|
+
let a = Ct(r, t, i), s = n(r, t);
|
|
742
|
+
if (t === "postgres") return `${a}\n\nSET search_path TO ${s};\n\n${St(e, t)}`;
|
|
743
|
+
if (t === "mysql" || t === "mariadb") return `${a}\n\nUSE ${s};\n\n${St(e, t)}`;
|
|
744
|
+
let { sorted: c, cyclic: l } = gt(e), u = vt(l, t), d = [a];
|
|
745
|
+
for (let e of c) d.push(ot(e, t, r, u.get(e.tableName)));
|
|
746
|
+
if (!o(t)) for (let e of l) d.push(_t(e, t, r));
|
|
733
747
|
for (let e of c) {
|
|
734
|
-
let
|
|
735
|
-
|
|
748
|
+
let n = ct(e, t, r);
|
|
749
|
+
n && d.push(n);
|
|
736
750
|
}
|
|
737
751
|
return d.join("\n\n") + "\n";
|
|
738
|
-
},
|
|
739
|
-
let { sorted: r, cyclic: i } =
|
|
752
|
+
}, Tt = (e, t, n = k) => {
|
|
753
|
+
let { sorted: r, cyclic: i } = gt(e), a = vt(i, t), o = [], s = bt(r, t);
|
|
740
754
|
s && o.push(s);
|
|
741
|
-
let c =
|
|
755
|
+
let c = yt(r, t);
|
|
742
756
|
c && o.push(c);
|
|
743
|
-
for (let e of r) o.push(
|
|
744
|
-
for (let e of i) o.push(
|
|
745
|
-
return o.push(...
|
|
746
|
-
},
|
|
757
|
+
for (let e of r) o.push(ot(e, t, null, a.get(e.tableName)));
|
|
758
|
+
for (let e of i) o.push(_t(e, t));
|
|
759
|
+
return o.push(...lt(r, t, n)), o.join("\n\n") + "\n";
|
|
760
|
+
}, Et = (e, t = "postgres", n = k, r = {}) => x.gen(function* () {
|
|
747
761
|
let i = yield* C.SqlClient;
|
|
748
|
-
yield*
|
|
749
|
-
}),
|
|
762
|
+
yield* Me(i, Nt(i, St(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(x.orDie);
|
|
763
|
+
}), Dt = (e, t) => {
|
|
750
764
|
let n = t.cause ?? {};
|
|
751
765
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
752
|
-
},
|
|
766
|
+
}, Ot = (e, t) => {
|
|
753
767
|
let n = e.trimStart();
|
|
754
768
|
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));
|
|
755
|
-
},
|
|
769
|
+
}, kt = () => {
|
|
756
770
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
757
771
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
758
|
-
},
|
|
772
|
+
}, At = (e) => ({
|
|
759
773
|
while: e,
|
|
760
|
-
times:
|
|
761
|
-
schedule:
|
|
762
|
-
}),
|
|
774
|
+
times: kt(),
|
|
775
|
+
schedule: S.jittered(S.exponential("50 millis"))
|
|
776
|
+
}), jt = class {
|
|
763
777
|
statement;
|
|
764
778
|
error;
|
|
765
779
|
_tag = "DdlStatementFailed";
|
|
766
780
|
constructor(e, t) {
|
|
767
781
|
this.statement = e, this.error = t;
|
|
768
782
|
}
|
|
769
|
-
},
|
|
770
|
-
let r = yield* C.SqlClient, i = n !== void 0 &&
|
|
771
|
-
for (let a of
|
|
772
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
773
|
-
let e = r.unsafe(a).pipe(
|
|
774
|
-
|
|
783
|
+
}, Mt = (e, t, n) => x.gen(function* () {
|
|
784
|
+
let r = yield* C.SqlClient, i = n !== void 0 && Fe(t) === "per-operation";
|
|
785
|
+
for (let a of Pt(e)) {
|
|
786
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && Ze.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
787
|
+
let e = r.unsafe(a).pipe(x.catchIf((e) => Dt(a, e), () => x.succeed([])), x.tapError((e) => x.sync(() => {
|
|
788
|
+
Ze.error(ae("migrate: statement failed", a, e, 200));
|
|
775
789
|
})));
|
|
776
|
-
yield* (i && n !== void 0 &&
|
|
790
|
+
yield* (i && n !== void 0 && Ot(a, t) ? e.pipe(x.retry(At((e) => n(e) === "retry"))) : e).pipe(x.mapError((e) => new jt(a, e)));
|
|
777
791
|
}
|
|
778
|
-
}),
|
|
779
|
-
let i = n === "turso" ?
|
|
780
|
-
return (r !== void 0 &&
|
|
781
|
-
},
|
|
792
|
+
}), Nt = (e, t, n, r) => {
|
|
793
|
+
let i = n === "turso" ? Mt(t, n, r) : e.withTransaction(Mt(t, n, r)), a = (e) => e instanceof jt ? e.error : e;
|
|
794
|
+
return (r !== void 0 && Fe(n) === "plan-transactional" ? i.pipe(x.retry(At((e) => r(a(e)) === "retry"))) : i).pipe(x.orDieWith((e) => e instanceof jt ? Error(ae("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
795
|
+
}, Pt = (e) => {
|
|
782
796
|
let t = [], n = "", r = !1;
|
|
783
797
|
for (let i = 0; i < e.length; i++) {
|
|
784
798
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -793,43 +807,43 @@ BEGIN
|
|
|
793
807
|
}
|
|
794
808
|
let i = n.trim();
|
|
795
809
|
return i.length > 0 && t.push(i), t;
|
|
796
|
-
},
|
|
797
|
-
await
|
|
798
|
-
},
|
|
799
|
-
let i =
|
|
800
|
-
yield*
|
|
801
|
-
}),
|
|
802
|
-
await
|
|
810
|
+
}, Ft = async (e, t, n = "postgres", r = {}) => {
|
|
811
|
+
await x.runPromise(Et(e, n, void 0, r).pipe(x.provide(t)));
|
|
812
|
+
}, It = (e, t, n = "postgres", r = {}) => x.gen(function* () {
|
|
813
|
+
let i = wt(e, n, t), a = yield* C.SqlClient;
|
|
814
|
+
yield* Me(a, Nt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(x.orDie);
|
|
815
|
+
}), Lt = async (e, t, n, r = "postgres", i = {}) => {
|
|
816
|
+
await x.runPromise(It(e, t, r, i).pipe(x.provide(n))), await f({
|
|
803
817
|
namespace: t,
|
|
804
818
|
dialect: r
|
|
805
819
|
});
|
|
806
|
-
},
|
|
807
|
-
await
|
|
808
|
-
let t =
|
|
809
|
-
yield*
|
|
810
|
-
}).pipe(
|
|
811
|
-
},
|
|
820
|
+
}, Rt = async (e, t, n = "postgres", r = {}) => {
|
|
821
|
+
await x.runPromise(x.gen(function* () {
|
|
822
|
+
let t = Tt(e, n), i = yield* C.SqlClient;
|
|
823
|
+
yield* Me(i, Nt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(x.orDie);
|
|
824
|
+
}).pipe(x.provide(t)));
|
|
825
|
+
}, zt = (e) => {
|
|
812
826
|
if (e == null) return e;
|
|
813
|
-
if (Array.isArray(e)) return e.map(
|
|
827
|
+
if (Array.isArray(e)) return e.map(zt);
|
|
814
828
|
if (typeof e != "object") return e;
|
|
815
829
|
let t = {};
|
|
816
830
|
for (let n of Object.keys(e).sort()) {
|
|
817
831
|
let r = e[n];
|
|
818
|
-
r !== void 0 && (t[n] =
|
|
832
|
+
r !== void 0 && (t[n] = zt(r));
|
|
819
833
|
}
|
|
820
834
|
return t;
|
|
821
|
-
},
|
|
835
|
+
}, Bt = (e) => {
|
|
822
836
|
if (!e.idScheme && !e.sensitive && !e.safe) return e;
|
|
823
837
|
let { idScheme: t, sensitive: n, safe: r, ...i } = e;
|
|
824
838
|
return i;
|
|
825
|
-
},
|
|
839
|
+
}, Vt = (e) => [...e].map(Bt).sort((e, t) => e.name.localeCompare(t.name)), Ht = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), Ut = (e) => [...e].map((e) => ({
|
|
826
840
|
name: e.name,
|
|
827
|
-
columns:
|
|
828
|
-
indexes:
|
|
829
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
830
|
-
let t = { tables:
|
|
831
|
-
return
|
|
832
|
-
},
|
|
841
|
+
columns: Vt(e.columns),
|
|
842
|
+
indexes: Ht(e.indexes)
|
|
843
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), F = (e) => {
|
|
844
|
+
let t = { tables: Ut(e.tables) }, n = JSON.stringify(zt(t));
|
|
845
|
+
return te("sha256").update(n).digest("hex");
|
|
846
|
+
}, I = (e) => e.slice(0, 16), Wt = (e, t) => {
|
|
833
847
|
let n = t.references ? {
|
|
834
848
|
table: t.references().tableName,
|
|
835
849
|
column: "id",
|
|
@@ -868,7 +882,7 @@ BEGIN
|
|
|
868
882
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
869
883
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
870
884
|
};
|
|
871
|
-
},
|
|
885
|
+
}, Gt = (e) => {
|
|
872
886
|
let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
873
887
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
874
888
|
}, i = e.appliedPrimaryKey ?? [];
|
|
@@ -908,7 +922,7 @@ BEGIN
|
|
|
908
922
|
let i = n;
|
|
909
923
|
if (i.dropped || !i.references || i.fkAutoIndex === !1 || s.has(t)) continue;
|
|
910
924
|
let a = `${e.tableName}_${t}_idx`;
|
|
911
|
-
|
|
925
|
+
u(e.tableName, a, !0, [t]), r({
|
|
912
926
|
name: a,
|
|
913
927
|
table: e.tableName,
|
|
914
928
|
columns: [t],
|
|
@@ -916,11 +930,11 @@ BEGIN
|
|
|
916
930
|
});
|
|
917
931
|
}
|
|
918
932
|
return t;
|
|
919
|
-
},
|
|
933
|
+
}, Kt = (e) => {
|
|
920
934
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
921
935
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
922
936
|
if (i.dropped) continue;
|
|
923
|
-
let e =
|
|
937
|
+
let e = Wt(r, i);
|
|
924
938
|
n.push(t.has(r) ? {
|
|
925
939
|
...e,
|
|
926
940
|
unique: !0
|
|
@@ -930,27 +944,27 @@ BEGIN
|
|
|
930
944
|
return {
|
|
931
945
|
name: e.tableName,
|
|
932
946
|
columns: n,
|
|
933
|
-
indexes:
|
|
947
|
+
indexes: Gt(e),
|
|
934
948
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
935
949
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
936
950
|
};
|
|
937
|
-
},
|
|
951
|
+
}, qt = (e) => {
|
|
938
952
|
let t = /* @__PURE__ */ new Map();
|
|
939
953
|
for (let n of e) for (let e of n.indexes) {
|
|
940
954
|
let r = t.get(e.name);
|
|
941
955
|
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}').`);
|
|
942
956
|
t.set(e.name, n.name);
|
|
943
957
|
}
|
|
944
|
-
},
|
|
945
|
-
let n = e.map((e) =>
|
|
946
|
-
return
|
|
947
|
-
},
|
|
958
|
+
}, L = (e, t) => {
|
|
959
|
+
let n = e.map((e) => Kt(de(e, t)));
|
|
960
|
+
return qt(n), { tables: n };
|
|
961
|
+
}, Jt = (e, t, n = k) => x.gen(function* () {
|
|
948
962
|
let r = (yield* e`
|
|
949
963
|
SELECT p.prosrc
|
|
950
964
|
FROM pg_proc p
|
|
951
965
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
952
966
|
WHERE n.nspname = current_schema()
|
|
953
|
-
AND p.proname = ${
|
|
967
|
+
AND p.proname = ${Ye(n)}
|
|
954
968
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
955
969
|
if (a.length === 0) return {
|
|
956
970
|
missing: [],
|
|
@@ -964,10 +978,10 @@ BEGIN
|
|
|
964
978
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
965
979
|
WHERE NOT t.tgisinternal
|
|
966
980
|
AND n.nspname = current_schema()
|
|
967
|
-
AND t.tgname LIKE ${`${
|
|
981
|
+
AND t.tgname LIKE ${`${qe}%`}
|
|
968
982
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
969
983
|
for (let e of a) {
|
|
970
|
-
let t = s.has(
|
|
984
|
+
let t = s.has(Je(e.tableName, n)), r = e.isReactive !== !1;
|
|
971
985
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
972
986
|
}
|
|
973
987
|
return {
|
|
@@ -975,7 +989,7 @@ BEGIN
|
|
|
975
989
|
stale: l.sort(),
|
|
976
990
|
functionOutdated: i
|
|
977
991
|
};
|
|
978
|
-
}),
|
|
992
|
+
}), Yt = (e) => {
|
|
979
993
|
let t = [];
|
|
980
994
|
if (e.missing.length > 0) {
|
|
981
995
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -986,19 +1000,19 @@ BEGIN
|
|
|
986
1000
|
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.`);
|
|
987
1001
|
}
|
|
988
1002
|
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;
|
|
989
|
-
},
|
|
1003
|
+
}, Xt = {
|
|
990
1004
|
postgres: !0,
|
|
991
1005
|
mysql: !0,
|
|
992
1006
|
mariadb: !0,
|
|
993
1007
|
mssql: !0,
|
|
994
1008
|
sqlite: !0
|
|
995
|
-
},
|
|
1009
|
+
}, Zt = {
|
|
996
1010
|
postgres: !0,
|
|
997
1011
|
mysql: !1,
|
|
998
1012
|
mariadb: !1,
|
|
999
1013
|
mssql: !0,
|
|
1000
1014
|
sqlite: !0
|
|
1001
|
-
},
|
|
1015
|
+
}, Qt = (e) => {
|
|
1002
1016
|
switch (e) {
|
|
1003
1017
|
case "add-column":
|
|
1004
1018
|
case "drop-column":
|
|
@@ -1008,47 +1022,47 @@ BEGIN
|
|
|
1008
1022
|
case "add-foreign-key":
|
|
1009
1023
|
case "add-unique":
|
|
1010
1024
|
case "add-unique-composite":
|
|
1011
|
-
case "add-check": return
|
|
1012
|
-
default: return
|
|
1025
|
+
case "add-check": return Zt;
|
|
1026
|
+
default: return Xt;
|
|
1013
1027
|
}
|
|
1014
|
-
},
|
|
1028
|
+
}, $t = (e, t) => {
|
|
1015
1029
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1016
1030
|
return new Map(e.map((e) => [e.tableName, {
|
|
1017
1031
|
table: e,
|
|
1018
1032
|
snapshot: n.get(e.tableName),
|
|
1019
1033
|
columnDefs: e.fields
|
|
1020
1034
|
}]));
|
|
1021
|
-
},
|
|
1035
|
+
}, R = (e) => {
|
|
1022
1036
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
1023
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
1037
|
+
if (Array.isArray(e)) return `[${e.map(R).join(",")}]`;
|
|
1024
1038
|
let t = e;
|
|
1025
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
1026
|
-
},
|
|
1039
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${R(t[e])}`).join(",")}}`;
|
|
1040
|
+
}, en = (e) => {
|
|
1027
1041
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
1028
1042
|
let t = e.defaultValue;
|
|
1029
1043
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
1030
1044
|
if (typeof t == "number") return String(t);
|
|
1031
|
-
if (typeof t != "string") return
|
|
1045
|
+
if (typeof t != "string") return R(t);
|
|
1032
1046
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
1033
1047
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
1034
1048
|
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);
|
|
1035
1049
|
if (o) try {
|
|
1036
|
-
return
|
|
1050
|
+
return R(JSON.parse(o[1]));
|
|
1037
1051
|
} catch {}
|
|
1038
1052
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1039
1053
|
if (s) try {
|
|
1040
|
-
return
|
|
1054
|
+
return R(JSON.parse(s[1]));
|
|
1041
1055
|
} catch {}
|
|
1042
1056
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1043
|
-
return
|
|
1057
|
+
return R(JSON.parse(a));
|
|
1044
1058
|
} catch {}
|
|
1045
1059
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1046
|
-
},
|
|
1047
|
-
let n =
|
|
1060
|
+
}, tn = (e, t) => {
|
|
1061
|
+
let n = en(e), r = en(t);
|
|
1048
1062
|
if (n === r) return !0;
|
|
1049
1063
|
let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
1050
1064
|
return i(n) === i(r);
|
|
1051
|
-
},
|
|
1065
|
+
}, nn = (e) => {
|
|
1052
1066
|
if (!e) return null;
|
|
1053
1067
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1054
1068
|
return {
|
|
@@ -1057,25 +1071,25 @@ BEGIN
|
|
|
1057
1071
|
onDelete: t(e.onDelete),
|
|
1058
1072
|
onUpdate: t(e.onUpdate)
|
|
1059
1073
|
};
|
|
1060
|
-
},
|
|
1074
|
+
}, rn = (e, t) => {
|
|
1061
1075
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1062
1076
|
if (!n && !r) return !0;
|
|
1063
1077
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1064
1078
|
let i = [...n].sort(), a = [...r].sort();
|
|
1065
1079
|
return i.every((e, t) => e === a[t]);
|
|
1066
|
-
},
|
|
1080
|
+
}, an = (e, t) => {
|
|
1067
1081
|
try {
|
|
1068
1082
|
let n = /\((\d+)\)/.exec(j(e, t));
|
|
1069
1083
|
return n ? Number(n[1]) : void 0;
|
|
1070
1084
|
} catch {
|
|
1071
1085
|
return;
|
|
1072
1086
|
}
|
|
1073
|
-
},
|
|
1087
|
+
}, on = (e, t, n) => n === void 0 || o(n) ? !0 : e.type !== "text" || t.type !== "text" || an(e, n) === t.maxLength, sn = (e, t, n) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && tn(e, t) && on(e, t, n) && JSON.stringify(nn(e.references)) === JSON.stringify(nn(t.references)) && rn(e.oneOf, t.oneOf), cn = (e, t) => t.oneOf && t.oneOf.length > 0 ? z({
|
|
1074
1088
|
kind: "add-check",
|
|
1075
1089
|
table: e,
|
|
1076
1090
|
column: t.name,
|
|
1077
1091
|
values: t.oneOf
|
|
1078
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1092
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, ln = (e, t) => e.unique === t.unique && (e.expression || t.expression ? !0 : e.columns.length === t.columns.length && e.columns.every((e, n) => e === t.columns[n])), un = (e, t, n) => {
|
|
1079
1093
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [];
|
|
1080
1094
|
for (let t of e.columns) {
|
|
1081
1095
|
let e = r.get(t.name);
|
|
@@ -1083,7 +1097,7 @@ BEGIN
|
|
|
1083
1097
|
a.push(t);
|
|
1084
1098
|
continue;
|
|
1085
1099
|
}
|
|
1086
|
-
|
|
1100
|
+
sn(t, e, n) || s.push({
|
|
1087
1101
|
declared: t,
|
|
1088
1102
|
live: e
|
|
1089
1103
|
});
|
|
@@ -1094,47 +1108,47 @@ BEGIN
|
|
|
1094
1108
|
removed: o,
|
|
1095
1109
|
changed: s
|
|
1096
1110
|
};
|
|
1097
|
-
},
|
|
1111
|
+
}, dn = (e, t) => {
|
|
1098
1112
|
let n = new Map(t.indexes.map((e) => [e.name, e])), r = new Map(e.indexes.map((e) => [e.name, e])), i = [], a = [];
|
|
1099
1113
|
for (let t of e.indexes) {
|
|
1100
1114
|
let e = n.get(t.name);
|
|
1101
|
-
(!e || !
|
|
1115
|
+
(!e || !ln(t, e)) && i.push(t);
|
|
1102
1116
|
}
|
|
1103
1117
|
for (let e of t.indexes) r.has(e.name) || a.push(e);
|
|
1104
1118
|
return {
|
|
1105
1119
|
added: i,
|
|
1106
1120
|
removed: a
|
|
1107
1121
|
};
|
|
1108
|
-
},
|
|
1122
|
+
}, z = (e, t, n, r) => ({
|
|
1109
1123
|
op: e,
|
|
1110
1124
|
classification: t,
|
|
1111
|
-
atomicByDialect:
|
|
1125
|
+
atomicByDialect: Qt(e.kind),
|
|
1112
1126
|
...n ? { reason: n } : {},
|
|
1113
1127
|
...r ? { blocked: r } : {}
|
|
1114
|
-
}),
|
|
1128
|
+
}), fn = (e, t, n) => {
|
|
1115
1129
|
let r = {
|
|
1116
1130
|
kind: "add-column",
|
|
1117
1131
|
table: e,
|
|
1118
1132
|
column: t
|
|
1119
1133
|
};
|
|
1120
|
-
return t.nullable ?
|
|
1121
|
-
},
|
|
1134
|
+
return t.nullable ? z(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? z(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? z(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : z(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` });
|
|
1135
|
+
}, pn = (e, t, n) => {
|
|
1122
1136
|
let r = {
|
|
1123
1137
|
kind: "drop-column",
|
|
1124
1138
|
table: e,
|
|
1125
1139
|
column: t.name
|
|
1126
1140
|
};
|
|
1127
|
-
return n?.dropped ?
|
|
1128
|
-
},
|
|
1141
|
+
return n?.dropped ? z(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : z(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1142
|
+
}, mn = (e, t, n, r, i) => z({
|
|
1129
1143
|
kind: "create-table",
|
|
1130
1144
|
table: e,
|
|
1131
1145
|
columns: t,
|
|
1132
1146
|
indexes: n,
|
|
1133
1147
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1134
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1148
|
+
}, "safe", i ?? "new table — no data to preserve"), hn = (e) => z({
|
|
1135
1149
|
kind: "drop-table",
|
|
1136
1150
|
table: e
|
|
1137
|
-
}, "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" }),
|
|
1151
|
+
}, "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" }), gn = 5e4, _n = (e, t, n, r) => {
|
|
1138
1152
|
let i = (n ?? 0) >= r, a;
|
|
1139
1153
|
return a = t.unique ? t.columns.length === 1 ? {
|
|
1140
1154
|
kind: "add-unique",
|
|
@@ -1149,16 +1163,16 @@ BEGIN
|
|
|
1149
1163
|
kind: "add-index",
|
|
1150
1164
|
table: e,
|
|
1151
1165
|
index: t
|
|
1152
|
-
}, i ?
|
|
1153
|
-
},
|
|
1166
|
+
}, i ? z(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : z(a, "safe", t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index");
|
|
1167
|
+
}, vn = (e, t) => t.unique && t.columns.length > 1 ? z({
|
|
1154
1168
|
kind: "drop-unique-composite",
|
|
1155
1169
|
table: e,
|
|
1156
1170
|
name: t.name
|
|
1157
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1171
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : z({
|
|
1158
1172
|
kind: "drop-index",
|
|
1159
1173
|
table: e,
|
|
1160
1174
|
index: t.name
|
|
1161
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1175
|
+
}, "safe", "drop index (no data loss — index is derived data)"), yn = (e, t) => {
|
|
1162
1176
|
if (e === "reference") return "text";
|
|
1163
1177
|
switch (t) {
|
|
1164
1178
|
case "sqlite":
|
|
@@ -1166,7 +1180,7 @@ BEGIN
|
|
|
1166
1180
|
case "mssql": return e === "json" ? "text" : e;
|
|
1167
1181
|
default: return e;
|
|
1168
1182
|
}
|
|
1169
|
-
},
|
|
1183
|
+
}, bn = (e, t, n, r, i, a) => {
|
|
1170
1184
|
let s = [];
|
|
1171
1185
|
if (t.nullable !== n.nullable) {
|
|
1172
1186
|
let n = {
|
|
@@ -1175,7 +1189,7 @@ BEGIN
|
|
|
1175
1189
|
column: t.name,
|
|
1176
1190
|
toNullable: t.nullable
|
|
1177
1191
|
};
|
|
1178
|
-
s.push(t.nullable ?
|
|
1192
|
+
s.push(t.nullable ? z(n, "safe", `loosen ${e}.${t.name} to nullable`) : z(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1179
1193
|
}
|
|
1180
1194
|
if (t.unique !== n.unique) {
|
|
1181
1195
|
if (t.unique) {
|
|
@@ -1183,15 +1197,15 @@ BEGIN
|
|
|
1183
1197
|
kind: "add-unique",
|
|
1184
1198
|
table: e,
|
|
1185
1199
|
column: t.name
|
|
1186
|
-
}, r = (
|
|
1187
|
-
s.push(r ?
|
|
1188
|
-
} else s.push(
|
|
1200
|
+
}, r = (i ?? 0) >= a;
|
|
1201
|
+
s.push(r ? z(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : z(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1202
|
+
} else s.push(z({
|
|
1189
1203
|
kind: "drop-unique",
|
|
1190
1204
|
table: e,
|
|
1191
1205
|
column: t.name
|
|
1192
1206
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1193
1207
|
}
|
|
1194
|
-
if (
|
|
1208
|
+
if (yn(t.type, r) !== yn(n.type, r)) {
|
|
1195
1209
|
let r = t.narrowedFrom;
|
|
1196
1210
|
if (r && r.from === n.type) {
|
|
1197
1211
|
let i = {
|
|
@@ -1202,7 +1216,7 @@ BEGIN
|
|
|
1202
1216
|
to: t.type,
|
|
1203
1217
|
...r.using === void 0 ? {} : { using: r.using }
|
|
1204
1218
|
};
|
|
1205
|
-
s.push(
|
|
1219
|
+
s.push(z(i, "needs-backfill", `type change ${n.type} → ${t.type} on ${e}.${t.name} — narrowedFrom('${r.from}') declared` + (r.using ? ` with USING ${r.using}` : " (implicit cast)")));
|
|
1206
1220
|
} else {
|
|
1207
1221
|
let r = {
|
|
1208
1222
|
kind: "alter-column-type",
|
|
@@ -1211,12 +1225,12 @@ BEGIN
|
|
|
1211
1225
|
from: n.type,
|
|
1212
1226
|
to: t.type
|
|
1213
1227
|
};
|
|
1214
|
-
s.push(
|
|
1228
|
+
s.push(z(r, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: `acknowledge it on the column: \`.narrowedFrom('${n.type}', { using: '${t.name}::${t.type}' })\` (drop \`using\` if the cast is implicit), or use a file-based migration` }));
|
|
1215
1229
|
}
|
|
1216
1230
|
}
|
|
1217
|
-
if (t.type === "text" && n.type === "text" && !r
|
|
1231
|
+
if (t.type === "text" && n.type === "text" && !o(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1218
1232
|
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})`;
|
|
1219
|
-
s.push(
|
|
1233
|
+
s.push(z({
|
|
1220
1234
|
kind: "alter-column-type",
|
|
1221
1235
|
table: e,
|
|
1222
1236
|
column: t.name,
|
|
@@ -1224,7 +1238,7 @@ BEGIN
|
|
|
1224
1238
|
to: "text"
|
|
1225
1239
|
}, r ? "safe" : "needs-backfill", r ? `text length ${i} → ${a} on ${e}.${t.name} — widening, no data can be lost` : `text length ${i} → ${a} on ${e}.${t.name} — NARROWING; the ALTER fails if any existing value is longer than ${String(t.maxLength)}. Check first: SELECT COUNT(*) FROM ${e} WHERE LENGTH(${t.name}) > ${String(t.maxLength)}`));
|
|
1226
1240
|
}
|
|
1227
|
-
if (!
|
|
1241
|
+
if (!tn(t, n)) {
|
|
1228
1242
|
let n = {
|
|
1229
1243
|
kind: "alter-column-default",
|
|
1230
1244
|
table: e,
|
|
@@ -1232,23 +1246,23 @@ BEGIN
|
|
|
1232
1246
|
hasDefault: t.hasDefault,
|
|
1233
1247
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1234
1248
|
};
|
|
1235
|
-
s.push(
|
|
1249
|
+
s.push(z(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1236
1250
|
}
|
|
1237
|
-
if (!
|
|
1238
|
-
n.oneOf && n.oneOf.length > 0 && s.push(
|
|
1251
|
+
if (!rn(t.oneOf, n.oneOf)) {
|
|
1252
|
+
n.oneOf && n.oneOf.length > 0 && s.push(z({
|
|
1239
1253
|
kind: "drop-check",
|
|
1240
1254
|
table: e,
|
|
1241
1255
|
column: t.name
|
|
1242
1256
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1243
|
-
let r =
|
|
1257
|
+
let r = cn(e, t);
|
|
1244
1258
|
r && s.push(r);
|
|
1245
1259
|
}
|
|
1246
|
-
return JSON.stringify(
|
|
1260
|
+
return JSON.stringify(nn(t.references)) !== JSON.stringify(nn(n.references)) && (n.references && s.push(z({
|
|
1247
1261
|
kind: "drop-foreign-key",
|
|
1248
1262
|
table: e,
|
|
1249
1263
|
column: t.name
|
|
1250
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), s.push(...
|
|
1251
|
-
},
|
|
1264
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), s.push(...xn(e, t))), s;
|
|
1265
|
+
}, xn = (e, t) => {
|
|
1252
1266
|
let n = [];
|
|
1253
1267
|
if (!t.references) return n;
|
|
1254
1268
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1260,15 +1274,15 @@ BEGIN
|
|
|
1260
1274
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1261
1275
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1262
1276
|
};
|
|
1263
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1277
|
+
return i === "null" && !t.nullable ? n.push(z(a, "lossy", `add FK ${e}.${t.name} → ${r}: orphanPolicy 'null' needs a nullable column (the NULL-out would violate NOT NULL)`, { fix: `make ${t.name} \`.nullable()\`, OR use \`orphanPolicy: 'delete'\`, OR clean the orphans and drop the policy` })) : i === "null" || i === "delete" ? n.push(z({
|
|
1264
1278
|
...a,
|
|
1265
1279
|
orphanPolicy: i
|
|
1266
|
-
}, "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(
|
|
1267
|
-
},
|
|
1280
|
+
}, "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(z(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1281
|
+
}, Sn = (e, t, n) => {
|
|
1268
1282
|
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));
|
|
1269
1283
|
for (let [n, c] of Object.entries(t)) {
|
|
1270
1284
|
let t = c.renamedFrom;
|
|
1271
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1285
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(z({
|
|
1272
1286
|
kind: "rename-column",
|
|
1273
1287
|
table: e.tableName,
|
|
1274
1288
|
from: t,
|
|
@@ -1280,26 +1294,26 @@ BEGIN
|
|
|
1280
1294
|
consumedAddedNames: i,
|
|
1281
1295
|
consumedRemovedNames: a
|
|
1282
1296
|
};
|
|
1283
|
-
},
|
|
1297
|
+
}, Cn = /* @__PURE__ */ new Set([
|
|
1284
1298
|
"postgres",
|
|
1285
1299
|
"mysql",
|
|
1286
1300
|
"mariadb",
|
|
1287
1301
|
"mssql"
|
|
1288
|
-
]),
|
|
1302
|
+
]), wn = {
|
|
1289
1303
|
ops: [],
|
|
1290
1304
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1291
1305
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1292
|
-
},
|
|
1293
|
-
if (i === void 0 || !
|
|
1294
|
-
let a = t.added.filter((e) =>
|
|
1295
|
-
if (a.length === 0) return
|
|
1306
|
+
}, Tn = (e) => !e.unique && !e.expression, En = (e, t, n, r, i) => {
|
|
1307
|
+
if (i === void 0 || !Cn.has(i)) return wn;
|
|
1308
|
+
let a = t.added.filter((e) => Tn(e) && !r.has(e.name));
|
|
1309
|
+
if (a.length === 0) return wn;
|
|
1296
1310
|
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();
|
|
1297
1311
|
for (let n of t.removed) {
|
|
1298
|
-
if (!
|
|
1312
|
+
if (!Tn(n)) continue;
|
|
1299
1313
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1300
1314
|
if (r.length !== 1) continue;
|
|
1301
1315
|
let i = r[0];
|
|
1302
|
-
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(
|
|
1316
|
+
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(z({
|
|
1303
1317
|
kind: "rename-index",
|
|
1304
1318
|
table: e,
|
|
1305
1319
|
from: n.name,
|
|
@@ -1311,7 +1325,7 @@ BEGIN
|
|
|
1311
1325
|
consumedAddedNames: l,
|
|
1312
1326
|
consumedRemovedNames: u
|
|
1313
1327
|
};
|
|
1314
|
-
},
|
|
1328
|
+
}, Dn = (e, t, n) => {
|
|
1315
1329
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1316
1330
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1317
1331
|
for (let c of e.tables) {
|
|
@@ -1322,7 +1336,7 @@ BEGIN
|
|
|
1322
1336
|
continue;
|
|
1323
1337
|
}
|
|
1324
1338
|
if (t.has(c.name)) {
|
|
1325
|
-
r.push(
|
|
1339
|
+
r.push(z({
|
|
1326
1340
|
kind: "rename-table",
|
|
1327
1341
|
from: e,
|
|
1328
1342
|
to: c.name
|
|
@@ -1330,14 +1344,14 @@ BEGIN
|
|
|
1330
1344
|
continue;
|
|
1331
1345
|
}
|
|
1332
1346
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1333
|
-
r.push(
|
|
1347
|
+
r.push(z({
|
|
1334
1348
|
kind: "rename-table",
|
|
1335
1349
|
from: e,
|
|
1336
1350
|
to: c.name
|
|
1337
1351
|
}, "needs-rename-annotation", `.renamedFrom('${e}') is claimed by ${s.get(e)} tables — nothing says which receives its rows`, { fix: `remove the \`.renamedFrom('${e}')\` marker from all but one of them.` }));
|
|
1338
1352
|
continue;
|
|
1339
1353
|
}
|
|
1340
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1354
|
+
i.set(c.name, e), a.add(e), r.push(z({
|
|
1341
1355
|
kind: "rename-table",
|
|
1342
1356
|
from: e,
|
|
1343
1357
|
to: c.name
|
|
@@ -1351,19 +1365,19 @@ BEGIN
|
|
|
1351
1365
|
claimedOldNames: c,
|
|
1352
1366
|
refusals: o
|
|
1353
1367
|
};
|
|
1354
|
-
},
|
|
1368
|
+
}, On = (e, t, n, r) => {
|
|
1355
1369
|
if (t === void 0) return {
|
|
1356
1370
|
live: e,
|
|
1357
1371
|
ops: []
|
|
1358
1372
|
};
|
|
1359
|
-
let i = r !== void 0 &&
|
|
1373
|
+
let i = r !== void 0 && Cn.has(r), a = [], o = e.indexes.map((e) => {
|
|
1360
1374
|
if (!e.name.startsWith(t)) return e;
|
|
1361
1375
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1362
1376
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1363
1377
|
...e,
|
|
1364
1378
|
name: r,
|
|
1365
1379
|
table: n
|
|
1366
|
-
} : i ? (a.push(
|
|
1380
|
+
} : i ? (a.push(z({
|
|
1367
1381
|
kind: "rename-index",
|
|
1368
1382
|
table: n,
|
|
1369
1383
|
from: e.name,
|
|
@@ -1382,7 +1396,7 @@ BEGIN
|
|
|
1382
1396
|
},
|
|
1383
1397
|
ops: a
|
|
1384
1398
|
};
|
|
1385
|
-
},
|
|
1399
|
+
}, kn = (e) => {
|
|
1386
1400
|
let t = {
|
|
1387
1401
|
safe: 0,
|
|
1388
1402
|
needsDefault: 0,
|
|
@@ -1415,42 +1429,42 @@ BEGIN
|
|
|
1415
1429
|
case "multi-step": t.multiStep++;
|
|
1416
1430
|
}
|
|
1417
1431
|
return t;
|
|
1418
|
-
},
|
|
1419
|
-
let t =
|
|
1432
|
+
}, An = (e) => {
|
|
1433
|
+
let t = L(e.declared, e.dialect), n = $t(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? gn, a = [], o = Dn(t, r, n);
|
|
1420
1434
|
a.push(...o.ops);
|
|
1421
1435
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1422
|
-
a.push(
|
|
1436
|
+
a.push(mn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1423
1437
|
for (let t of e.columns) {
|
|
1424
|
-
let n =
|
|
1438
|
+
let n = cn(e.name, t);
|
|
1425
1439
|
n && a.push(n);
|
|
1426
1440
|
}
|
|
1427
1441
|
}
|
|
1428
1442
|
let s = new Set(e.ignoreTables ?? []);
|
|
1429
|
-
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || m(t.name) || v(t.name) || s.has(t.name) || a.push(
|
|
1443
|
+
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || m(t.name) || v(t.name) || s.has(t.name) || a.push(hn(t.name));
|
|
1430
1444
|
for (let s of t.tables) {
|
|
1431
1445
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1432
1446
|
if (!c) continue;
|
|
1433
|
-
let l =
|
|
1447
|
+
let l = On(c, t, s.name, e.dialect);
|
|
1434
1448
|
a.push(...l.ops);
|
|
1435
|
-
let u = l.live, d = n.get(s.name), f =
|
|
1449
|
+
let u = l.live, d = n.get(s.name), f = un(s, u, e.dialect), p = dn(s, u), m = Sn(d.table, d.columnDefs, f);
|
|
1436
1450
|
a.push(...m.ops);
|
|
1437
1451
|
for (let e of f.removed) {
|
|
1438
1452
|
if (m.consumedRemovedNames.has(e.name) || v(e.name)) continue;
|
|
1439
1453
|
let t = d.columnDefs[e.name];
|
|
1440
|
-
a.push(
|
|
1454
|
+
a.push(pn(s.name, e, t));
|
|
1441
1455
|
}
|
|
1442
1456
|
for (let e of f.added) {
|
|
1443
1457
|
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1444
1458
|
let t = d.columnDefs[e.name];
|
|
1445
|
-
a.push(
|
|
1446
|
-
let n =
|
|
1447
|
-
n && a.push(n), a.push(...
|
|
1459
|
+
a.push(fn(s.name, e, t));
|
|
1460
|
+
let n = cn(s.name, e);
|
|
1461
|
+
n && a.push(n), a.push(...xn(s.name, e));
|
|
1448
1462
|
}
|
|
1449
|
-
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g =
|
|
1463
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = En(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1450
1464
|
a.push(...g.ops);
|
|
1451
|
-
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(
|
|
1452
|
-
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(
|
|
1453
|
-
for (let { declared: t, live: n } of f.changed) a.push(...
|
|
1465
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(_n(s.name, e, u.rowCount, i));
|
|
1466
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(vn(s.name, e));
|
|
1467
|
+
for (let { declared: t, live: n } of f.changed) a.push(...bn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1454
1468
|
}
|
|
1455
1469
|
let c = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), l = new Map(t.tables.map((e) => [e.name, e])), u = (e) => {
|
|
1456
1470
|
let t = l.get(e);
|
|
@@ -1458,8 +1472,8 @@ BEGIN
|
|
|
1458
1472
|
column: e.name,
|
|
1459
1473
|
target: e.references.table
|
|
1460
1474
|
}] : []) : [];
|
|
1461
|
-
}, d =
|
|
1462
|
-
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(w(e.name, t.name)) || f.push(
|
|
1475
|
+
}, d = fe([...c], u), f = [];
|
|
1476
|
+
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(w(e.name, t.name)) || f.push(z({
|
|
1463
1477
|
kind: "add-foreign-key",
|
|
1464
1478
|
table: e.name,
|
|
1465
1479
|
column: t.name,
|
|
@@ -1531,19 +1545,19 @@ BEGIN
|
|
|
1531
1545
|
});
|
|
1532
1546
|
return {
|
|
1533
1547
|
operations: S,
|
|
1534
|
-
fromFingerprint:
|
|
1535
|
-
toFingerprint:
|
|
1536
|
-
summary:
|
|
1548
|
+
fromFingerprint: F(e.live),
|
|
1549
|
+
toFingerprint: F(t),
|
|
1550
|
+
summary: kn(S)
|
|
1537
1551
|
};
|
|
1538
|
-
},
|
|
1552
|
+
}, jn = (e) => {
|
|
1539
1553
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1540
1554
|
if (!t) return null;
|
|
1541
|
-
let n = [...e.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
|
|
1555
|
+
let n = [...e.replace(/\\'/g, "''").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
1542
1556
|
return n.length === 0 ? null : {
|
|
1543
1557
|
column: t[1],
|
|
1544
1558
|
values: n
|
|
1545
1559
|
};
|
|
1546
|
-
},
|
|
1560
|
+
}, Mn = (e, t) => {
|
|
1547
1561
|
if (t === "vector") return "vector";
|
|
1548
1562
|
switch (e) {
|
|
1549
1563
|
case "text":
|
|
@@ -1570,7 +1584,7 @@ BEGIN
|
|
|
1570
1584
|
case "USER-DEFINED": return "text";
|
|
1571
1585
|
default: return "text";
|
|
1572
1586
|
}
|
|
1573
|
-
},
|
|
1587
|
+
}, B = (e) => {
|
|
1574
1588
|
switch (e.toUpperCase()) {
|
|
1575
1589
|
case "CASCADE": return "cascade";
|
|
1576
1590
|
case "RESTRICT": return "restrict";
|
|
@@ -1578,25 +1592,25 @@ BEGIN
|
|
|
1578
1592
|
case "SET DEFAULT": return "noAction";
|
|
1579
1593
|
default: return "noAction";
|
|
1580
1594
|
}
|
|
1581
|
-
},
|
|
1595
|
+
}, Nn = (e, t) => {
|
|
1582
1596
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1583
1597
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1584
|
-
},
|
|
1598
|
+
}, Pn = () => Nn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Fn = 300, In = () => {
|
|
1585
1599
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1586
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1587
|
-
},
|
|
1600
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Nn(e, 3e4);
|
|
1601
|
+
}, Ln = (e, t) => {
|
|
1588
1602
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1589
1603
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1590
1604
|
return r;
|
|
1591
|
-
},
|
|
1592
|
-
let t =
|
|
1605
|
+
}, Rn = (e) => {
|
|
1606
|
+
let t = In(), n = x.gen(function* () {
|
|
1593
1607
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1594
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
1608
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Pn(), a = (e, t) => x.gen(function* () {
|
|
1595
1609
|
let r = [];
|
|
1596
|
-
for (let a of
|
|
1610
|
+
for (let a of Ln(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1597
1611
|
return r;
|
|
1598
1612
|
}), o = [];
|
|
1599
|
-
for (let t = 0;; t +=
|
|
1613
|
+
for (let t = 0;; t += Fn) {
|
|
1600
1614
|
let n = yield* e`
|
|
1601
1615
|
SELECT c.relname AS table_name,
|
|
1602
1616
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1604,9 +1618,9 @@ BEGIN
|
|
|
1604
1618
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1605
1619
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1606
1620
|
ORDER BY c.relname
|
|
1607
|
-
LIMIT ${r(
|
|
1621
|
+
LIMIT ${r(Fn)} OFFSET ${r(t)}
|
|
1608
1622
|
`;
|
|
1609
|
-
if (o.push(...n), n.length <
|
|
1623
|
+
if (o.push(...n), n.length < Fn) break;
|
|
1610
1624
|
}
|
|
1611
1625
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1612
1626
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1692,7 +1706,7 @@ BEGIN
|
|
|
1692
1706
|
AND c.relname IN ${t}
|
|
1693
1707
|
)
|
|
1694
1708
|
SELECT * FROM ix ORDER BY table_name, index_name, position
|
|
1695
|
-
`), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(),
|
|
1709
|
+
`), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map(), ee = /* @__PURE__ */ new Map();
|
|
1696
1710
|
for (let e of u) {
|
|
1697
1711
|
let t = _.get(e.table_name);
|
|
1698
1712
|
t || (t = [], _.set(e.table_name, t)), t.push(e);
|
|
@@ -1701,25 +1715,25 @@ BEGIN
|
|
|
1701
1715
|
let t = v.get(e.table_name);
|
|
1702
1716
|
t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
|
|
1703
1717
|
}
|
|
1704
|
-
let
|
|
1718
|
+
let C = /* @__PURE__ */ new Map();
|
|
1705
1719
|
for (let e of f) {
|
|
1706
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
1720
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = C.get(t);
|
|
1707
1721
|
n || (n = {
|
|
1708
1722
|
table: e.table_name,
|
|
1709
1723
|
columns: []
|
|
1710
|
-
},
|
|
1724
|
+
}, C.set(t, n)), n.columns.push({
|
|
1711
1725
|
name: e.column_name,
|
|
1712
1726
|
position: e.position
|
|
1713
1727
|
});
|
|
1714
1728
|
}
|
|
1715
|
-
for (let [e, t] of
|
|
1729
|
+
for (let [e, t] of C) {
|
|
1716
1730
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
1717
1731
|
if (n.length === 1) {
|
|
1718
1732
|
let e = y.get(t.table);
|
|
1719
1733
|
e || (e = /* @__PURE__ */ new Set(), y.set(t.table, e)), e.add(n[0]);
|
|
1720
1734
|
} else {
|
|
1721
|
-
let r =
|
|
1722
|
-
r || (r = [],
|
|
1735
|
+
let r = b.get(t.table);
|
|
1736
|
+
r || (r = [], b.set(t.table, r)), r.push({
|
|
1723
1737
|
name: e.slice(e.indexOf("\0") + 1),
|
|
1724
1738
|
table: t.table,
|
|
1725
1739
|
columns: n,
|
|
@@ -1732,24 +1746,24 @@ BEGIN
|
|
|
1732
1746
|
t || (t = [], S.set(e.source_table, t)), t.push(e);
|
|
1733
1747
|
}
|
|
1734
1748
|
for (let e of g) {
|
|
1735
|
-
let t =
|
|
1736
|
-
t || (t = /* @__PURE__ */ new Map(),
|
|
1749
|
+
let t = ee.get(e.table_name);
|
|
1750
|
+
t || (t = /* @__PURE__ */ new Map(), ee.set(e.table_name, t));
|
|
1737
1751
|
let n = t.get(e.index_name);
|
|
1738
1752
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1739
1753
|
}
|
|
1740
1754
|
let te = [];
|
|
1741
1755
|
for (let e of c) {
|
|
1742
1756
|
let t = /* @__PURE__ */ new Set(), n = (_.get(e.table_name) ?? []).filter((e) => !t.has(e.column_name) && (t.add(e.column_name), !0)), r = v.get(e.table_name) ?? /* @__PURE__ */ new Set(), i = y.get(e.table_name) ?? /* @__PURE__ */ new Set(), a = S.get(e.table_name) ?? [], o = new Map(a.map((e) => [e.source_column, e])), s = new Set(n.filter((e) => e.udt_name === "tsvector").map((e) => e.column_name)), c = n.filter((e) => !s.has(e.column_name)).map((t) => {
|
|
1743
|
-
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" :
|
|
1757
|
+
let n = r.has(t.column_name) && r.size === 1, a = o.get(t.column_name), s = a ? "reference" : n && t.column_name === "id" ? "id" : Mn(t.data_type, t.udt_name), c = a ? {
|
|
1744
1758
|
table: a.target_table,
|
|
1745
1759
|
column: a.target_column,
|
|
1746
|
-
onDelete:
|
|
1747
|
-
onUpdate:
|
|
1760
|
+
onDelete: B(a.delete_rule),
|
|
1761
|
+
onUpdate: B(a.update_rule)
|
|
1748
1762
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1749
1763
|
return {
|
|
1750
1764
|
name: t.column_name,
|
|
1751
1765
|
type: s,
|
|
1752
|
-
...
|
|
1766
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
1753
1767
|
nullable: t.is_nullable === "YES",
|
|
1754
1768
|
unique: i.has(t.column_name) || n && t.column_name === "id",
|
|
1755
1769
|
hasDefault: t.column_default !== null,
|
|
@@ -1757,7 +1771,7 @@ BEGIN
|
|
|
1757
1771
|
...c ? { references: c } : {},
|
|
1758
1772
|
...l ? { oneOf: l } : {}
|
|
1759
1773
|
};
|
|
1760
|
-
}), l = [], u =
|
|
1774
|
+
}), l = [], u = ee.get(e.table_name);
|
|
1761
1775
|
if (u) for (let [t, n] of u) {
|
|
1762
1776
|
let r = /* @__PURE__ */ new Set(), i = [...n].filter((e) => e.column_name !== null && e.position !== null).sort((e, t) => (e.position ?? 0) - (t.position ?? 0)).filter((e) => {
|
|
1763
1777
|
let t = e.position;
|
|
@@ -1773,7 +1787,7 @@ BEGIN
|
|
|
1773
1787
|
...a ? { expression: !0 } : {}
|
|
1774
1788
|
});
|
|
1775
1789
|
}
|
|
1776
|
-
for (let t of
|
|
1790
|
+
for (let t of b.get(e.table_name) ?? []) l.push(t);
|
|
1777
1791
|
r.size > 0 && l.push({
|
|
1778
1792
|
name: `${e.table_name}_pkey`,
|
|
1779
1793
|
table: e.table_name,
|
|
@@ -1790,11 +1804,11 @@ BEGIN
|
|
|
1790
1804
|
}
|
|
1791
1805
|
return { tables: te };
|
|
1792
1806
|
});
|
|
1793
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
1807
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(x.catchAll((e) => {
|
|
1794
1808
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1795
|
-
return n.includes("statement timeout") || n.includes("57014") ?
|
|
1809
|
+
return n.includes("statement timeout") || n.includes("57014") ? x.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.`)) : x.fail(e);
|
|
1796
1810
|
}));
|
|
1797
|
-
},
|
|
1811
|
+
}, zn = (e, t) => {
|
|
1798
1812
|
switch (e.toLowerCase()) {
|
|
1799
1813
|
case "varchar":
|
|
1800
1814
|
case "char":
|
|
@@ -1826,21 +1840,21 @@ BEGIN
|
|
|
1826
1840
|
case "json": return "json";
|
|
1827
1841
|
default: return "text";
|
|
1828
1842
|
}
|
|
1829
|
-
},
|
|
1843
|
+
}, V = (e) => e.map((e) => {
|
|
1830
1844
|
let t = e, n = {};
|
|
1831
1845
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1832
1846
|
return n;
|
|
1833
|
-
}),
|
|
1834
|
-
let t =
|
|
1847
|
+
}), Bn = (e) => x.gen(function* () {
|
|
1848
|
+
let t = V(yield* e`
|
|
1835
1849
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1836
1850
|
FROM information_schema.tables
|
|
1837
1851
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1838
|
-
ORDER BY table_name`), n =
|
|
1852
|
+
ORDER BY table_name`), n = V(yield* e`
|
|
1839
1853
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1840
1854
|
character_maximum_length
|
|
1841
1855
|
FROM information_schema.columns
|
|
1842
1856
|
WHERE table_schema = DATABASE()
|
|
1843
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
1857
|
+
ORDER BY table_name, ordinal_position`), r = V(yield* e`
|
|
1844
1858
|
SELECT k.table_name AS source_table,
|
|
1845
1859
|
k.column_name AS source_column,
|
|
1846
1860
|
k.referenced_table_name AS target_table,
|
|
@@ -1850,21 +1864,24 @@ BEGIN
|
|
|
1850
1864
|
JOIN information_schema.referential_constraints r
|
|
1851
1865
|
ON k.constraint_name = r.constraint_name
|
|
1852
1866
|
AND k.table_schema = r.constraint_schema
|
|
1853
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
1867
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = V(yield* e`
|
|
1854
1868
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
1855
1869
|
FROM information_schema.statistics
|
|
1856
1870
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
1857
|
-
ORDER BY table_name, index_name, seq_in_index`), a =
|
|
1858
|
-
SELECT table_name, check_clause
|
|
1859
|
-
FROM information_schema.check_constraints
|
|
1860
|
-
|
|
1871
|
+
ORDER BY table_name, index_name, seq_in_index`), a = V(yield* e`
|
|
1872
|
+
SELECT tc.table_name AS table_name, cc.check_clause AS check_clause
|
|
1873
|
+
FROM information_schema.check_constraints cc
|
|
1874
|
+
JOIN information_schema.table_constraints tc
|
|
1875
|
+
ON tc.constraint_schema = cc.constraint_schema
|
|
1876
|
+
AND tc.constraint_name = cc.constraint_name
|
|
1877
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared.pipe(x.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
|
|
1861
1878
|
for (let e of a) {
|
|
1862
1879
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
1863
1880
|
if (t) {
|
|
1864
1881
|
o.add(`${e.table_name}.${t[1]}`);
|
|
1865
1882
|
continue;
|
|
1866
1883
|
}
|
|
1867
|
-
let n =
|
|
1884
|
+
let n = jn(e.check_clause);
|
|
1868
1885
|
n && s.set(`${e.table_name}.${n.column}`, n.values);
|
|
1869
1886
|
}
|
|
1870
1887
|
let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
|
|
@@ -1887,17 +1904,17 @@ BEGIN
|
|
|
1887
1904
|
let t = c.get(e.table_name) ?? [], n = l.get(e.table_name) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = t.filter((e) => e.column_key === "PRI").map((e) => e.column_name), a = /* @__PURE__ */ new Set(), f = u.get(e.table_name);
|
|
1888
1905
|
if (f) for (let e of f.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1889
1906
|
let p = t.map((t) => {
|
|
1890
|
-
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" :
|
|
1907
|
+
let n = i.includes(t.column_name) && i.length === 1, c = r.get(t.column_name), l = c ? "reference" : n && t.column_name === "id" ? "id" : o.has(`${e.table_name}.${t.column_name}`) ? "json" : zn(t.data_type, t.column_type), u = c ? {
|
|
1891
1908
|
table: c.target_table,
|
|
1892
1909
|
column: c.target_column,
|
|
1893
|
-
onDelete:
|
|
1894
|
-
onUpdate:
|
|
1910
|
+
onDelete: B(c.delete_rule),
|
|
1911
|
+
onUpdate: B(c.update_rule)
|
|
1895
1912
|
} : void 0, d = a.has(t.column_name) || n && t.column_name === "id", f = t.column_default === "NULL" ? null : t.column_default, p = s.get(`${e.table_name}.${t.column_name}`);
|
|
1896
1913
|
return {
|
|
1897
1914
|
name: t.column_name,
|
|
1898
1915
|
type: l,
|
|
1899
1916
|
nullable: t.is_nullable === "YES",
|
|
1900
|
-
...
|
|
1917
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
1901
1918
|
unique: d,
|
|
1902
1919
|
hasDefault: f !== null,
|
|
1903
1920
|
...f === null ? {} : { defaultValue: f },
|
|
@@ -1929,10 +1946,10 @@ BEGIN
|
|
|
1929
1946
|
});
|
|
1930
1947
|
}
|
|
1931
1948
|
return { tables: d };
|
|
1932
|
-
}),
|
|
1949
|
+
}), Vn = (e) => {
|
|
1933
1950
|
let t = e.toUpperCase();
|
|
1934
1951
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
1935
|
-
},
|
|
1952
|
+
}, Hn = (e) => x.gen(function* () {
|
|
1936
1953
|
let t = yield* e`
|
|
1937
1954
|
SELECT name, sql FROM sqlite_master
|
|
1938
1955
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -1949,11 +1966,11 @@ BEGIN
|
|
|
1949
1966
|
d.set(t.name, r), t.unique === 1 && r.length === 1 && f.add(r[0]);
|
|
1950
1967
|
}
|
|
1951
1968
|
let p = o.map((e) => {
|
|
1952
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
1969
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : Vn(e.type), a = r ? {
|
|
1953
1970
|
table: r.table,
|
|
1954
1971
|
column: r.to,
|
|
1955
|
-
onDelete:
|
|
1956
|
-
onUpdate:
|
|
1972
|
+
onDelete: B(r.on_delete),
|
|
1973
|
+
onUpdate: B(r.on_update)
|
|
1957
1974
|
} : void 0, o = t.get(e.name);
|
|
1958
1975
|
return {
|
|
1959
1976
|
name: e.name,
|
|
@@ -1988,7 +2005,7 @@ BEGIN
|
|
|
1988
2005
|
});
|
|
1989
2006
|
}
|
|
1990
2007
|
return { tables: r };
|
|
1991
|
-
}),
|
|
2008
|
+
}), Un = (e) => {
|
|
1992
2009
|
switch (e.toLowerCase()) {
|
|
1993
2010
|
case "int":
|
|
1994
2011
|
case "smallint":
|
|
@@ -2010,7 +2027,7 @@ BEGIN
|
|
|
2010
2027
|
case "image": return "bytes";
|
|
2011
2028
|
default: return "text";
|
|
2012
2029
|
}
|
|
2013
|
-
},
|
|
2030
|
+
}, H = (e) => e === !0 || e === 1, Wn = (e) => x.gen(function* () {
|
|
2014
2031
|
let t = yield* e`
|
|
2015
2032
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2016
2033
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
@@ -2067,21 +2084,21 @@ BEGIN
|
|
|
2067
2084
|
let t = s.get(e) ?? [], n = c.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = new Set(n.map((e) => e.source_column)), a = l.get(e), d = [], f = /* @__PURE__ */ new Set();
|
|
2068
2085
|
if (a) for (let [, e] of a) {
|
|
2069
2086
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2070
|
-
if (
|
|
2071
|
-
else
|
|
2087
|
+
if (H(t[0].is_primary)) for (let e of t) d.push(e.column_name);
|
|
2088
|
+
else H(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
|
|
2072
2089
|
}
|
|
2073
2090
|
let p = t.map((t) => {
|
|
2074
|
-
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" :
|
|
2091
|
+
let n = d.length === 1 && d[0] === t.column_name, i = r.get(t.column_name), a = i ? "reference" : n && t.column_name === "id" ? "id" : Un(t.data_type), s = i ? {
|
|
2075
2092
|
table: i.target_table,
|
|
2076
2093
|
column: i.target_column,
|
|
2077
|
-
onDelete:
|
|
2078
|
-
onUpdate:
|
|
2079
|
-
} : void 0, c = t.column_default === null ? null :
|
|
2094
|
+
onDelete: Gn(i.delete_rule),
|
|
2095
|
+
onUpdate: Gn(i.update_rule)
|
|
2096
|
+
} : void 0, c = t.column_default === null ? null : Kn(t.column_default), l = o.get(`${e}.${t.column_name}`);
|
|
2080
2097
|
return {
|
|
2081
2098
|
name: t.column_name,
|
|
2082
2099
|
type: a,
|
|
2083
2100
|
nullable: t.is_nullable === "YES",
|
|
2084
|
-
...
|
|
2101
|
+
...U(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: U(t.data_type, t.character_maximum_length) },
|
|
2085
2102
|
unique: f.has(t.column_name) || n && t.column_name === "id",
|
|
2086
2103
|
hasDefault: c !== null,
|
|
2087
2104
|
...c === null ? {} : { defaultValue: c },
|
|
@@ -2091,11 +2108,11 @@ BEGIN
|
|
|
2091
2108
|
}), m = [];
|
|
2092
2109
|
if (a) for (let [t, n] of a) {
|
|
2093
2110
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2094
|
-
|
|
2111
|
+
H(r[0].is_primary) || r.length === 1 && H(r[0].is_unique) || r.length === 1 && !H(r[0].is_unique) && i.has(r[0].column_name) && t !== `${e}_${r[0].column_name}_idx` || m.push({
|
|
2095
2112
|
name: t,
|
|
2096
2113
|
table: e,
|
|
2097
2114
|
columns: r.map((e) => e.column_name),
|
|
2098
|
-
unique:
|
|
2115
|
+
unique: H(r[0].is_unique)
|
|
2099
2116
|
});
|
|
2100
2117
|
}
|
|
2101
2118
|
d.length > 0 && m.push({
|
|
@@ -2110,54 +2127,87 @@ BEGIN
|
|
|
2110
2127
|
});
|
|
2111
2128
|
}
|
|
2112
2129
|
return { tables: u };
|
|
2113
|
-
}),
|
|
2130
|
+
}), Gn = (e) => {
|
|
2114
2131
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2115
2132
|
case "CASCADE": return "cascade";
|
|
2116
2133
|
case "SET NULL": return "setNull";
|
|
2117
2134
|
case "SET DEFAULT": return "noAction";
|
|
2118
2135
|
default: return "noAction";
|
|
2119
2136
|
}
|
|
2120
|
-
},
|
|
2137
|
+
}, Kn = (e) => {
|
|
2121
2138
|
let t = e.trim();
|
|
2122
2139
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2123
2140
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2124
|
-
},
|
|
2141
|
+
}, qn = /* @__PURE__ */ new Set([
|
|
2125
2142
|
"character varying",
|
|
2126
2143
|
"varchar",
|
|
2127
2144
|
"nvarchar",
|
|
2128
2145
|
"char",
|
|
2129
2146
|
"character",
|
|
2130
2147
|
"nchar"
|
|
2131
|
-
]),
|
|
2132
|
-
if (!
|
|
2148
|
+
]), U = (e, t) => {
|
|
2149
|
+
if (!qn.has(e.toLowerCase())) return;
|
|
2133
2150
|
let n = Number(t);
|
|
2134
2151
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2135
|
-
},
|
|
2136
|
-
mysql: () =>
|
|
2137
|
-
mssql: () =>
|
|
2138
|
-
sqlite: () =>
|
|
2139
|
-
orElse: () =>
|
|
2140
|
-
}).pipe(
|
|
2152
|
+
}, Jn = /* @__PURE__ */ new Set([O]), Yn = (e) => e.onDialectOrElse({
|
|
2153
|
+
mysql: () => Bn(e),
|
|
2154
|
+
mssql: () => Wn(e),
|
|
2155
|
+
sqlite: () => Hn(e),
|
|
2156
|
+
orElse: () => Rn(e)
|
|
2157
|
+
}).pipe(x.map((e) => ({
|
|
2141
2158
|
...e,
|
|
2142
|
-
tables: e.tables.filter((e) => !
|
|
2143
|
-
}))),
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
}),
|
|
2159
|
+
tables: e.tables.filter((e) => !Jn.has(e.name))
|
|
2160
|
+
}))), Xn = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", Zn = /* @__PURE__ */ new WeakMap(), W = (e) => x.suspend(() => {
|
|
2161
|
+
let t = Zn.get(e);
|
|
2162
|
+
return t === void 0 ? Qn(e).pipe(x.tap((t) => x.sync(() => Zn.set(e, t)))) : x.succeed(t);
|
|
2163
|
+
}), Qn = (e) => e.unsafe("SELECT VERSION() AS v").pipe(x.map((e) => {
|
|
2164
|
+
let t = e[0]?.v;
|
|
2165
|
+
return typeof t == "string" ? Xn(t) : "mysql";
|
|
2166
|
+
}), x.catchAll(() => x.succeed("mysql"))), $n = (e) => {
|
|
2167
|
+
let t = e;
|
|
2168
|
+
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2169
|
+
let e = t;
|
|
2170
|
+
if (typeof e.errno == "number") return e.errno;
|
|
2171
|
+
t = e.cause;
|
|
2172
|
+
}
|
|
2173
|
+
}, er = (e) => {
|
|
2174
|
+
let t = [], n = e;
|
|
2175
|
+
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2176
|
+
let e = n;
|
|
2177
|
+
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2178
|
+
}
|
|
2179
|
+
return t.join(" | ");
|
|
2180
|
+
}, tr = (e, t) => {
|
|
2181
|
+
if (t.length === 0) return !1;
|
|
2182
|
+
let n = $n(e), r = er(e);
|
|
2183
|
+
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)));
|
|
2184
|
+
}, nr = {
|
|
2185
|
+
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2186
|
+
errno: [1061]
|
|
2187
|
+
}, rr = {
|
|
2188
|
+
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2189
|
+
errno: [1091]
|
|
2190
|
+
}, ir = {
|
|
2191
|
+
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2192
|
+
messageIncludes: ["no such column"]
|
|
2193
|
+
}, G = (e, t) => e.onDialectOrElse({
|
|
2194
|
+
mysql: () => x.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2195
|
+
orElse: () => x.succeed(t)
|
|
2196
|
+
}), ar = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, or = (e, t) => {
|
|
2147
2197
|
if ((e.type !== "text" || e.maxLength === void 0) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2148
2198
|
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;
|
|
2149
2199
|
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.`);
|
|
2150
2200
|
return j(e, t);
|
|
2151
|
-
},
|
|
2152
|
-
let t =
|
|
2153
|
-
return t === void 0 ?
|
|
2154
|
-
},
|
|
2201
|
+
}, sr = (e) => {
|
|
2202
|
+
let t = or(e, "postgres");
|
|
2203
|
+
return t === void 0 ? cr(e) : t;
|
|
2204
|
+
}, cr = (e) => {
|
|
2155
2205
|
switch (e.type) {
|
|
2156
2206
|
case "id": return "text";
|
|
2157
2207
|
case "text": return "text";
|
|
2158
2208
|
case "integer": return "integer";
|
|
2159
2209
|
case "real": return "double precision";
|
|
2160
|
-
case "decimal": return
|
|
2210
|
+
case "decimal": return ar(e, "NUMERIC");
|
|
2161
2211
|
case "bigint": return "bigint";
|
|
2162
2212
|
case "boolean": return "boolean";
|
|
2163
2213
|
case "timestamp": return "timestamptz";
|
|
@@ -2171,15 +2221,15 @@ BEGIN
|
|
|
2171
2221
|
case "interval": return "interval";
|
|
2172
2222
|
case "raw": return e.rawDdl ?? "text";
|
|
2173
2223
|
}
|
|
2174
|
-
},
|
|
2175
|
-
let t =
|
|
2224
|
+
}, lr = (e) => {
|
|
2225
|
+
let t = or(e, "mariadb");
|
|
2176
2226
|
if (t !== void 0) return t;
|
|
2177
2227
|
switch (e.type) {
|
|
2178
2228
|
case "id": return "VARCHAR(64)";
|
|
2179
2229
|
case "text": return e.hasDefault && e.defaultValue !== void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : "LONGTEXT";
|
|
2180
2230
|
case "integer": return "INT";
|
|
2181
2231
|
case "real": return "DOUBLE";
|
|
2182
|
-
case "decimal": return
|
|
2232
|
+
case "decimal": return ar(e, "DECIMAL");
|
|
2183
2233
|
case "bigint": return "BIGINT";
|
|
2184
2234
|
case "boolean": return "TINYINT(1)";
|
|
2185
2235
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2193,82 +2243,86 @@ BEGIN
|
|
|
2193
2243
|
case "interval": return "BIGINT";
|
|
2194
2244
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2195
2245
|
}
|
|
2196
|
-
},
|
|
2246
|
+
}, K = (e) => `"${e}"`, q = (e) => `\`${e.replace(/`/g, "``")}\``, ur = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", dr = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, fr = (e, t = "mariadb") => `ALTER TABLE ${q(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${q(e.column)}, ALGORITHM=COPY;`, pr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, mr = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${Ur(t)}`)};`, hr = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${gr(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, gr = (e, t) => {
|
|
2197
2247
|
let n = t(e.defaultValue);
|
|
2198
2248
|
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.`);
|
|
2199
2249
|
return n;
|
|
2200
|
-
},
|
|
2201
|
-
let r =
|
|
2202
|
-
return r ?
|
|
2203
|
-
},
|
|
2204
|
-
let r = n ?? e.nullable, i =
|
|
2250
|
+
}, _r = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], vr = (e, t, n) => {
|
|
2251
|
+
let r = _r(e, t, n);
|
|
2252
|
+
return r ? Wt(n, r) : void 0;
|
|
2253
|
+
}, yr = (e, t, n) => {
|
|
2254
|
+
let r = n ?? e.nullable, i = Qe(e, "mariadb");
|
|
2205
2255
|
return [
|
|
2206
|
-
|
|
2256
|
+
q(t),
|
|
2207
2257
|
j(e, "mariadb"),
|
|
2208
2258
|
r ? null : "NOT NULL",
|
|
2209
2259
|
i
|
|
2210
2260
|
].filter(Boolean).join(" ");
|
|
2211
|
-
},
|
|
2261
|
+
}, br = (e, t) => e == null ? null : Array.isArray(e) ? xr(e, t, "mariadb") : e === "now" ? "DEFAULT CURRENT_TIMESTAMP(6)" : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "mariadb") : null, xr = (e, t, n) => $e(e, t ?? { type: "json" }, n), Sr = (e, t) => e == null ? null : Array.isArray(e) ? xr(e, t, "postgres") : e === "now" ? "DEFAULT now()" : typeof e == "boolean" || typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|::|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "postgres") : null, Cr = (e, t) => {
|
|
2212
2262
|
if (!e.generatedAs) return null;
|
|
2213
2263
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2214
2264
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2215
|
-
},
|
|
2265
|
+
}, wr = (e) => {
|
|
2216
2266
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "postgres");
|
|
2217
|
-
let t =
|
|
2218
|
-
if (t) return `${
|
|
2219
|
-
let n = [
|
|
2267
|
+
let t = Cr(e, "postgres");
|
|
2268
|
+
if (t) return `${K(e.name)} ${sr(e)} ${t}`;
|
|
2269
|
+
let n = [K(e.name), sr(e)];
|
|
2220
2270
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2221
|
-
let t =
|
|
2271
|
+
let t = Sr(e.defaultValue, e);
|
|
2222
2272
|
t && n.push(t);
|
|
2223
2273
|
}
|
|
2224
|
-
return e.references && (n.push(`REFERENCES ${
|
|
2274
|
+
return e.references && (n.push(`REFERENCES ${K(e.references.table)} (${K(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
2225
2275
|
cascade: "CASCADE",
|
|
2226
2276
|
restrict: "RESTRICT",
|
|
2227
2277
|
setNull: "SET NULL",
|
|
2228
2278
|
noAction: "NO ACTION"
|
|
2229
2279
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2230
|
-
},
|
|
2231
|
-
let t = e.columns.map((e) => ` ${
|
|
2232
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2280
|
+
}, Tr = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Er = (e) => {
|
|
2281
|
+
let t = e.columns.map((e) => ` ${wr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${t}${Tr(e, K)}\n)`];
|
|
2282
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(t.name)} ON ${K(e.table)} (${t.columns.map(Jr).join(", ")})`);
|
|
2233
2283
|
return n;
|
|
2234
|
-
},
|
|
2235
|
-
let t =
|
|
2284
|
+
}, Dr = 191, Or = (e) => {
|
|
2285
|
+
let t = lr(e).toUpperCase();
|
|
2236
2286
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2237
|
-
},
|
|
2287
|
+
}, kr = (e) => {
|
|
2238
2288
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mariadb");
|
|
2239
|
-
let t =
|
|
2240
|
-
if (t) return `${
|
|
2241
|
-
let n = [
|
|
2242
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2243
|
-
let t =
|
|
2289
|
+
let t = Cr(e, "mariadb");
|
|
2290
|
+
if (t) return `${q(e.name)} ${lr(e)} ${t}`;
|
|
2291
|
+
let n = [q(e.name), lr(e)];
|
|
2292
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !Or(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2293
|
+
let t = br(e.defaultValue, e);
|
|
2244
2294
|
t && n.push(t);
|
|
2245
2295
|
}
|
|
2246
|
-
return
|
|
2296
|
+
return n.join(" ");
|
|
2297
|
+
}, Ar = (e) => e.columns.flatMap((t) => {
|
|
2298
|
+
if (!t.references) return [];
|
|
2299
|
+
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2247
2300
|
cascade: "CASCADE",
|
|
2248
2301
|
restrict: "RESTRICT",
|
|
2249
2302
|
setNull: "SET NULL",
|
|
2250
2303
|
noAction: "NO ACTION"
|
|
2251
|
-
}[
|
|
2252
|
-
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
for (let
|
|
2259
|
-
|
|
2260
|
-
|
|
2304
|
+
}[t.references.onDelete]}` : "";
|
|
2305
|
+
return [` CONSTRAINT ${q(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${q(t.name)}) REFERENCES ${q(t.references.table)} (${q(t.references.column)})${n}`];
|
|
2306
|
+
}), jr = (e, t = "mariadb") => {
|
|
2307
|
+
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2308
|
+
let t = Kr(n.get(e));
|
|
2309
|
+
return t === void 0 ? q(e) : `${q(e)}(${t})`;
|
|
2310
|
+
}, i = e.columns.map((e) => ` ${kr(e)}`).join(",\n"), a = Ar(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${q(e.table)} (\n${o}${Tr(e, r)}\n)`];
|
|
2311
|
+
for (let n of e.columns) n.unique && n.type !== "id" && Or(n) && s.push(`CREATE UNIQUE INDEX ${ur(t)}${q(`${e.table}_${n.name}_key`)} ON ${q(e.table)} (${r(n.name)})`);
|
|
2312
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${ur(t)}${q(n.name)} ON ${q(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2313
|
+
return s;
|
|
2314
|
+
}, Mr = {
|
|
2261
2315
|
cascade: "CASCADE",
|
|
2262
2316
|
restrict: "RESTRICT",
|
|
2263
2317
|
setNull: "SET NULL",
|
|
2264
2318
|
noAction: "NO ACTION"
|
|
2265
|
-
},
|
|
2319
|
+
}, Nr = {
|
|
2266
2320
|
cascade: "CASCADE",
|
|
2267
2321
|
restrict: "NO ACTION",
|
|
2268
2322
|
setNull: "SET NULL",
|
|
2269
2323
|
noAction: "NO ACTION"
|
|
2270
|
-
},
|
|
2271
|
-
let t =
|
|
2324
|
+
}, Pr = (e) => {
|
|
2325
|
+
let t = or(e, "sqlite");
|
|
2272
2326
|
if (t !== void 0) return t;
|
|
2273
2327
|
switch (e.type) {
|
|
2274
2328
|
case "integer":
|
|
@@ -2279,60 +2333,60 @@ BEGIN
|
|
|
2279
2333
|
case "bytes": return "BLOB";
|
|
2280
2334
|
default: return "TEXT";
|
|
2281
2335
|
}
|
|
2282
|
-
},
|
|
2336
|
+
}, Fr = (e, t) => e == null ? null : e === "now" ? `DEFAULT ${t}` : typeof e == "boolean" ? `DEFAULT ${+!!e}` : typeof e == "number" ? `DEFAULT ${e}` : typeof e == "string" ? /[()]|^'/.test(e) ? `DEFAULT ${e}` : `DEFAULT '${e.replace(/'/g, "''")}'` : typeof e == "object" ? M(e, "sqlite") : null, Ir = (e) => {
|
|
2283
2337
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "sqlite");
|
|
2284
|
-
let t =
|
|
2285
|
-
if (t) return `${
|
|
2286
|
-
let n = [
|
|
2338
|
+
let t = Cr(e, "sqlite");
|
|
2339
|
+
if (t) return `${K(e.name)} ${Pr(e)} ${t}`;
|
|
2340
|
+
let n = [K(e.name), Pr(e)];
|
|
2287
2341
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2288
|
-
let t =
|
|
2342
|
+
let t = Fr(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2289
2343
|
t && n.push(t);
|
|
2290
2344
|
}
|
|
2291
|
-
if (e.references && (n.push(`REFERENCES ${
|
|
2345
|
+
if (e.references && (n.push(`REFERENCES ${K(e.references.table)} (${K(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Mr[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2292
2346
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2293
|
-
n.push(`CHECK (${
|
|
2347
|
+
n.push(`CHECK (${K(e.name)} IN (${t}))`);
|
|
2294
2348
|
}
|
|
2295
2349
|
return n.join(" ");
|
|
2296
|
-
},
|
|
2297
|
-
let t = e.columns.map((e) => ` ${
|
|
2298
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2350
|
+
}, Lr = (e) => {
|
|
2351
|
+
let t = e.columns.map((e) => ` ${Ir(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${t}${Tr(e, K)}\n)`];
|
|
2352
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(t.name)} ON ${K(e.table)} (${t.columns.map(K).join(", ")})`);
|
|
2299
2353
|
return n;
|
|
2300
2354
|
}, J = (e, t) => {
|
|
2301
2355
|
let n = t.find((t) => t.tableName === e);
|
|
2302
2356
|
if (!n) return [];
|
|
2303
|
-
let r =
|
|
2304
|
-
...
|
|
2357
|
+
let r = L([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => K(e.name)).join(", "), o = [
|
|
2358
|
+
...Lr({
|
|
2305
2359
|
kind: "create-table",
|
|
2306
2360
|
table: i,
|
|
2307
2361
|
columns: r.columns,
|
|
2308
2362
|
indexes: [],
|
|
2309
2363
|
...r.primaryKey ? { primaryKey: r.primaryKey } : {}
|
|
2310
2364
|
}),
|
|
2311
|
-
`INSERT INTO ${
|
|
2312
|
-
`DROP TABLE ${
|
|
2313
|
-
`ALTER TABLE ${
|
|
2365
|
+
`INSERT INTO ${K(i)} (${a}) SELECT ${a} FROM ${K(e)}`,
|
|
2366
|
+
`DROP TABLE ${K(e)}`,
|
|
2367
|
+
`ALTER TABLE ${K(i)} RENAME TO ${K(e)}`
|
|
2314
2368
|
];
|
|
2315
|
-
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
2369
|
+
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(t.name)} ON ${K(e)} (${t.columns.map(K).join(", ")})`);
|
|
2316
2370
|
return o;
|
|
2317
|
-
},
|
|
2371
|
+
}, Rr = (e, t, n, r) => {
|
|
2318
2372
|
let i = r ?? e.nullable;
|
|
2319
2373
|
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2320
|
-
},
|
|
2374
|
+
}, zr = (e) => {
|
|
2321
2375
|
let t = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${Y(e.table)} DROP CONSTRAINT [' + @dc + ']');`;
|
|
2322
2376
|
if (!e.hasDefault) return t;
|
|
2323
|
-
let n =
|
|
2377
|
+
let n = Fr(e.defaultValue, "SYSUTCDATETIME()");
|
|
2324
2378
|
if (!n) return t;
|
|
2325
2379
|
let r = n.replace(/^DEFAULT\s+/i, "");
|
|
2326
2380
|
return `${t} ALTER TABLE ${Y(e.table)} ADD DEFAULT ${r} FOR ${Y(e.column)};`;
|
|
2327
|
-
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2328
|
-
let t =
|
|
2381
|
+
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`, Br = (e) => {
|
|
2382
|
+
let t = or(e, "mssql");
|
|
2329
2383
|
if (t !== void 0) return t;
|
|
2330
2384
|
switch (e.type) {
|
|
2331
2385
|
case "id":
|
|
2332
2386
|
case "reference": return "NVARCHAR(64)";
|
|
2333
2387
|
case "integer": return "INT";
|
|
2334
2388
|
case "real": return "FLOAT";
|
|
2335
|
-
case "decimal": return
|
|
2389
|
+
case "decimal": return ar(e, "DECIMAL");
|
|
2336
2390
|
case "bigint": return "BIGINT";
|
|
2337
2391
|
case "boolean": return "BIT";
|
|
2338
2392
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2340,44 +2394,44 @@ BEGIN
|
|
|
2340
2394
|
case "bytes": return "VARBINARY(MAX)";
|
|
2341
2395
|
default: return "NVARCHAR(MAX)";
|
|
2342
2396
|
}
|
|
2343
|
-
},
|
|
2397
|
+
}, Vr = (e, t) => {
|
|
2344
2398
|
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mssql");
|
|
2345
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2399
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Br(e), r = Cr(e, "mssql");
|
|
2346
2400
|
if (r) return `${Y(e.name)} ${r}`;
|
|
2347
2401
|
let i = [Y(e.name), n];
|
|
2348
2402
|
if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
|
|
2349
|
-
let t =
|
|
2403
|
+
let t = Fr(e.defaultValue, "SYSUTCDATETIME()");
|
|
2350
2404
|
t && i.push(t);
|
|
2351
2405
|
}
|
|
2352
|
-
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2353
|
-
},
|
|
2354
|
-
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${
|
|
2406
|
+
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${Nr[e.references.onDelete]}`)), i.join(" ");
|
|
2407
|
+
}, Hr = (e) => {
|
|
2408
|
+
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${Vr(e, n)}`).join(",\n"), i = `CREATE TABLE ${Y(e.table)} (\n${r}${Tr(e, Y)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2355
2409
|
for (let n of e.indexes) {
|
|
2356
2410
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2357
2411
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Y(n.name)} ON ${Y(e.table)} (${n.columns.map(Y).join(", ")})`;
|
|
2358
2412
|
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)}')`);
|
|
2359
2413
|
}
|
|
2360
2414
|
return a;
|
|
2361
|
-
},
|
|
2362
|
-
let r = `${e.table}${
|
|
2415
|
+
}, Ur = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Wr = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Gr = (e, t, n) => {
|
|
2416
|
+
let r = `${e.table}${Ur(t)}`;
|
|
2363
2417
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2364
|
-
},
|
|
2365
|
-
if (e === void 0 || !
|
|
2418
|
+
}, Kr = (e) => {
|
|
2419
|
+
if (e === void 0 || !Or(e)) return;
|
|
2366
2420
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2367
|
-
return t === void 0 ?
|
|
2368
|
-
},
|
|
2369
|
-
let r =
|
|
2370
|
-
return r === void 0 ?
|
|
2371
|
-
},
|
|
2421
|
+
return t === void 0 ? Dr : Math.min(Dr, t);
|
|
2422
|
+
}, qr = (e, t, n) => {
|
|
2423
|
+
let r = Kr(vr(e, t, n));
|
|
2424
|
+
return r === void 0 ? q(n) : `${q(n)}(${r})`;
|
|
2425
|
+
}, Jr = (e) => e.startsWith("(") ? e : K(e), Yr = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map(Jr).join(", ")});`, Xr = (e, t, n = "mariadb") => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${ur(n)}${q(e.index.name)} ON ${q(e.table)} (${e.index.columns.map((n) => qr(t, e.table, n)).join(", ")});`, Zr = (e) => `DROP INDEX IF EXISTS ${K(e.index)};`, Qr = (e) => `DROP INDEX ${q(e.index)} ON ${q(e.table)};`, $r = (e) => `DROP INDEX IF EXISTS ${Y(e.index)} ON ${Y(e.table)};`, ei = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, ti = (e) => {
|
|
2372
2426
|
let t = (e) => e.replace(/'/g, "''");
|
|
2373
2427
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2374
|
-
},
|
|
2428
|
+
}, ni = (e) => `ALTER INDEX ${K(e.from)} RENAME TO ${K(e.to)};`, ri = (e) => `ALTER TABLE ${q(e.table)} RENAME INDEX ${q(e.from)} TO ${q(e.to)};`, ii = (e) => {
|
|
2375
2429
|
let t = (e) => e.replace(/'/g, "''");
|
|
2376
2430
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2377
|
-
},
|
|
2431
|
+
}, ai = (e) => {
|
|
2378
2432
|
let t = (e) => e.replace(/'/g, "''"), n = `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${Y(e.index.name)} ON ${Y(e.table)} (${e.index.columns.map(Y).join(", ")})`;
|
|
2379
2433
|
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)}');`;
|
|
2380
|
-
},
|
|
2434
|
+
}, oi = (e, t, n) => {
|
|
2381
2435
|
let r = n.find((t) => t.tableName === e);
|
|
2382
2436
|
if (!r) return [];
|
|
2383
2437
|
let i = [];
|
|
@@ -2386,13 +2440,13 @@ BEGIN
|
|
|
2386
2440
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Y(e)} ALTER COLUMN ${Y(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2387
2441
|
}
|
|
2388
2442
|
return i;
|
|
2389
|
-
},
|
|
2390
|
-
let t = e.fields.map((e) =>
|
|
2391
|
-
return `ALTER TABLE ${
|
|
2392
|
-
},
|
|
2393
|
-
let n = e.fields.map((n) =>
|
|
2394
|
-
return `ALTER TABLE ${
|
|
2395
|
-
},
|
|
2443
|
+
}, si = (e) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${K(e.column)});`, ci = (e, t) => `ALTER TABLE ${q(e.table)} ADD CONSTRAINT ${q(`${e.table}_${e.column}_key`)} UNIQUE (${qr(t, e.table, e.column)});`, li = (e) => {
|
|
2444
|
+
let t = e.fields.map((e) => K(e)).join(", ");
|
|
2445
|
+
return `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(e.name)} UNIQUE (${t});`;
|
|
2446
|
+
}, ui = (e, t) => {
|
|
2447
|
+
let n = e.fields.map((n) => qr(t, e.table, n)).join(", ");
|
|
2448
|
+
return `ALTER TABLE ${q(e.table)} ADD CONSTRAINT ${q(e.name)} UNIQUE (${n});`;
|
|
2449
|
+
}, di = (e) => `ALTER TABLE ${K(e.table)} DROP CONSTRAINT IF EXISTS ${K(e.name)};`, fi = (e) => `ALTER TABLE ${q(e.table)} DROP INDEX ${q(e.name)};`, pi = (e) => `ALTER TABLE ${K(e.table)} DROP CONSTRAINT IF EXISTS ${K(`${e.table}_${e.column}_key`)};`, mi = (e) => `ALTER TABLE ${q(e.table)} DROP INDEX ${q(`${e.table}_${e.column}_key`)};`, hi = (e, t) => {
|
|
2396
2450
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2397
2451
|
if (e.orphanPolicy) {
|
|
2398
2452
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2410,11 +2464,11 @@ BEGIN
|
|
|
2410
2464
|
setNull: "SET NULL",
|
|
2411
2465
|
noAction: "NO ACTION"
|
|
2412
2466
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2413
|
-
},
|
|
2467
|
+
}, gi = (e) => `ALTER TABLE ${K(e.table)} DROP CONSTRAINT IF EXISTS ${K(`${e.table}_${e.column}_fkey`)};`, _i = (e) => `ALTER TABLE ${q(e.table)} DROP FOREIGN KEY ${q(`${e.table}_${e.column}_fkey`)};`, vi = (e, t) => {
|
|
2414
2468
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2415
2469
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2416
|
-
},
|
|
2417
|
-
let i = e.column, a = r === "mariadb", o = a ?
|
|
2470
|
+
}, yi = (e) => `ALTER TABLE ${K(e.table)} DROP CONSTRAINT IF EXISTS ${K(`${e.table}_${e.column}_check`)};`, bi = (e) => `ALTER TABLE ${q(e.table)} DROP CHECK ${q(`${e.table}_${e.column}_check`)};`, xi = (e, t, n, r) => {
|
|
2471
|
+
let i = e.column, a = r === "mariadb", o = a ? q : r === "mssql" ? Y : K, s = a ? lr(i) : r === "mssql" ? Br(i) : r === "sqlite" ? Pr(i) : sr(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? br(e, i) : r === "mssql" ? Fr(e, "SYSUTCDATETIME()") : r === "sqlite" ? Fr(e, "CURRENT_TIMESTAMP") : Sr(e, i), u = Cr(i, r);
|
|
2418
2472
|
if (u) {
|
|
2419
2473
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2420
2474
|
return {
|
|
@@ -2442,7 +2496,7 @@ BEGIN
|
|
|
2442
2496
|
post: f ? [f] : []
|
|
2443
2497
|
};
|
|
2444
2498
|
return d?.sql && (p.backfillKind = "sql", p.backfillSql = d.sql), d?.js && (p.backfillKind = "js", p.backfillJs = d.js), d?.batchSize !== void 0 && (p.batchSize = d.batchSize), d?.sleepMs !== void 0 && (p.sleepMs = d.sleepMs), p;
|
|
2445
|
-
},
|
|
2499
|
+
}, Si = (e) => {
|
|
2446
2500
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2447
2501
|
return (e, n) => {
|
|
2448
2502
|
let r = t.get(e);
|
|
@@ -2462,44 +2516,44 @@ BEGIN
|
|
|
2462
2516
|
...o
|
|
2463
2517
|
};
|
|
2464
2518
|
};
|
|
2465
|
-
}, X = (e, t, n) => e.unsafe(t).pipe(
|
|
2466
|
-
process.stderr.write(
|
|
2467
|
-
})),
|
|
2468
|
-
let r =
|
|
2519
|
+
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(x.catchIf((e) => tr(e, r), () => x.void), x.tapError((e) => x.sync(() => {
|
|
2520
|
+
process.stderr.write(ae(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2521
|
+
})), x.mapError((e) => {
|
|
2522
|
+
let r = ae(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2469
2523
|
return Object.assign(e, { message: r });
|
|
2470
|
-
}),
|
|
2471
|
-
let n =
|
|
2472
|
-
if (!n) return yield*
|
|
2524
|
+
}), x.map(() => void 0)), Z = (e, t, n) => x.forEach(t, (t) => X(e, t, n), { discard: !0 }), Q = (e, t) => e.literal(`LIMIT ${Math.max(1, Math.floor(Number.isFinite(t) ? t : 1))}`), $ = (e, t, r, i) => e.unsafe(`SELECT ${i === void 0 ? "*" : n(i, t)} FROM ${n(r, t)} WHERE 1=0`).pipe(x.as(!0), x.catchAll(() => x.succeed(!1))), Ci = (e, t) => x.gen(function* () {
|
|
2525
|
+
let n = L([Ie], t).tables[0];
|
|
2526
|
+
if (!n) return yield* x.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2473
2527
|
let r = {
|
|
2474
2528
|
kind: "create-table",
|
|
2475
2529
|
table: O,
|
|
2476
2530
|
columns: n.columns,
|
|
2477
2531
|
indexes: []
|
|
2478
2532
|
}, i = yield* e.onDialectOrElse({
|
|
2479
|
-
mysql: () =>
|
|
2480
|
-
mssql: () =>
|
|
2481
|
-
sqlite: () =>
|
|
2482
|
-
orElse: () =>
|
|
2533
|
+
mysql: () => W(e).pipe(x.map((e) => jr(r, e))),
|
|
2534
|
+
mssql: () => x.succeed(Hr(r)),
|
|
2535
|
+
sqlite: () => x.succeed(Lr(r)),
|
|
2536
|
+
orElse: () => x.succeed(Er(r))
|
|
2483
2537
|
});
|
|
2484
|
-
yield*
|
|
2485
|
-
}),
|
|
2538
|
+
yield* x.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2539
|
+
}), wi = (e) => e`
|
|
2486
2540
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2487
2541
|
${e("status")}, ${e("payload")}
|
|
2488
2542
|
FROM ${e(O)}
|
|
2489
|
-
`,
|
|
2490
|
-
let i = yield*
|
|
2491
|
-
yield*
|
|
2543
|
+
`, Ti = (e, t, n, r) => x.gen(function* () {
|
|
2544
|
+
let i = yield* G(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2545
|
+
yield* x.forEach(r, ({ index: r, planned: a }) => e`
|
|
2492
2546
|
INSERT INTO ${e(O)}
|
|
2493
2547
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2494
2548
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2495
2549
|
${e("createdAt")})
|
|
2496
2550
|
VALUES
|
|
2497
2551
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2498
|
-
${a.op.kind}, ${
|
|
2552
|
+
${a.op.kind}, ${Re(a.op)}, ${"pending"},
|
|
2499
2553
|
${JSON.stringify(a)}, ${i})
|
|
2500
2554
|
`, { discard: !0 });
|
|
2501
|
-
}),
|
|
2502
|
-
let a = yield*
|
|
2555
|
+
}), Ei = (e, t, n, r, i) => x.gen(function* () {
|
|
2556
|
+
let a = yield* G(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2503
2557
|
if (r === "applied") {
|
|
2504
2558
|
yield* e`
|
|
2505
2559
|
UPDATE ${e(O)}
|
|
@@ -2514,8 +2568,8 @@ BEGIN
|
|
|
2514
2568
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2515
2569
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2516
2570
|
`;
|
|
2517
|
-
}),
|
|
2518
|
-
let i = yield*
|
|
2571
|
+
}), Di = (e, t, n, r) => x.gen(function* () {
|
|
2572
|
+
let i = yield* G(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2519
2573
|
r.length > 0 && (yield* e`
|
|
2520
2574
|
UPDATE ${e(O)}
|
|
2521
2575
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
@@ -2525,126 +2579,130 @@ BEGIN
|
|
|
2525
2579
|
SET ${e("status")} = ${"pending"}
|
|
2526
2580
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2527
2581
|
`);
|
|
2528
|
-
}),
|
|
2529
|
-
if (
|
|
2530
|
-
let
|
|
2582
|
+
}), Oi = (e, t) => t === void 0 ? e`DELETE FROM ${e(O)}`.pipe(x.asVoid) : e`DELETE FROM ${e(O)} WHERE ${e("runId")} = ${t}`.pipe(x.asVoid), ki = (e, t, r) => x.gen(function* () {
|
|
2583
|
+
if (Ke(r.op, r.classification, t) !== "artefact-repair") return "clean";
|
|
2584
|
+
let i = r.op, a = (e) => n(e, t);
|
|
2531
2585
|
if (t === "sqlite" || t === "turso") {
|
|
2532
|
-
if (!("table" in
|
|
2533
|
-
let n = `${
|
|
2534
|
-
return (yield* $(e, t, n)) ? ((yield* $(e, t,
|
|
2535
|
-
}
|
|
2536
|
-
if (
|
|
2537
|
-
let o = `${
|
|
2538
|
-
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${a(
|
|
2539
|
-
}),
|
|
2540
|
-
let i = process.hrtime.bigint(), a =
|
|
2586
|
+
if (!("table" in i)) return "clean";
|
|
2587
|
+
let n = `${i.table}${Ve}`;
|
|
2588
|
+
return (yield* $(e, t, n)) ? ((yield* $(e, t, i.table)) ? yield* X(e, `DROP TABLE ${a(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${a(n)} RENAME TO ${a(i.table)}`, "resume-repair"), yield* x.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${i.table}' — replaying the operation`).pipe(x.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
2589
|
+
}
|
|
2590
|
+
if (i.kind !== "alter-column-type") return "clean";
|
|
2591
|
+
let o = `${i.column}${He}`, s = `${i.column}${Ue}`, c = yield* $(e, t, i.table, i.column), l = yield* $(e, t, i.table, o), u = yield* $(e, t, i.table, s), d = (e) => x.logWarning(`migration resume: ${e}`).pipe(x.annotateLogs({ scope: "voltro:migrate" }));
|
|
2592
|
+
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(o)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${i.table}.${o}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* X(e, `ALTER TABLE ${a(i.table)} RENAME COLUMN ${a(o)} TO ${a(i.column)}`, "resume-repair"), yield* X(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${i.table}.${i.column}'`), "applied") : c && !l && u ? (yield* X(e, `ALTER TABLE ${a(i.table)} DROP COLUMN ${a(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${i.table}.${s}'`), "applied") : yield* x.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${i.table}.${i.column}' left a shadow-swap state this resume cannot classify (column=${c}, ${o}=${l}, ${s}=${u}).\nNothing was changed. Inspect those three columns and reconcile them by hand — the data is in whichever of them is populated — then re-run the migration.`));
|
|
2593
|
+
}), Ai = (e, t, n, r = "fresh") => x.gen(function* () {
|
|
2594
|
+
let i = process.hrtime.bigint(), a = Si(n.declared), o = t.op;
|
|
2541
2595
|
switch (o.kind) {
|
|
2542
2596
|
case "create-table": {
|
|
2543
2597
|
let t = yield* e.onDialectOrElse({
|
|
2544
|
-
mysql: () =>
|
|
2545
|
-
mssql: () =>
|
|
2546
|
-
sqlite: () =>
|
|
2547
|
-
orElse: () =>
|
|
2598
|
+
mysql: () => W(e).pipe(x.map((e) => jr(o, e))),
|
|
2599
|
+
mssql: () => x.succeed(Hr(o)),
|
|
2600
|
+
sqlite: () => x.succeed(Lr(o)),
|
|
2601
|
+
orElse: () => x.succeed(Er(o))
|
|
2602
|
+
}), n = yield* e.onDialectOrElse({
|
|
2603
|
+
mysql: () => x.succeed([nr]),
|
|
2604
|
+
orElse: () => x.succeed([])
|
|
2548
2605
|
});
|
|
2549
|
-
for (let
|
|
2606
|
+
for (let r of t) yield* X(e, r, o.kind, n);
|
|
2550
2607
|
break;
|
|
2551
2608
|
}
|
|
2552
2609
|
case "drop-table": {
|
|
2553
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2610
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Gr(o, n, e) : Wr(o, e);
|
|
2554
2611
|
yield* e.onDialectOrElse({
|
|
2555
|
-
mysql: () => X(e, r(
|
|
2556
|
-
orElse: () => X(e, r(
|
|
2612
|
+
mysql: () => X(e, r(q), o.kind),
|
|
2613
|
+
orElse: () => X(e, r(K), o.kind)
|
|
2557
2614
|
});
|
|
2558
2615
|
break;
|
|
2559
2616
|
}
|
|
2560
2617
|
case "drop-column": {
|
|
2561
2618
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2562
2619
|
yield* e.onDialectOrElse({
|
|
2563
|
-
mysql: () => X(e, t ?
|
|
2564
|
-
|
|
2620
|
+
mysql: () => W(e).pipe(x.flatMap((r) => X(e, t ? mr(o, n, q) : fr(o, r), o.kind, t ? [] : [rr]))),
|
|
2621
|
+
sqlite: () => X(e, t ? mr(o, n, K) : dr(o, K, !1), o.kind, t ? [] : [ir]),
|
|
2622
|
+
orElse: () => X(e, t ? mr(o, n, K) : dr(o, K), o.kind)
|
|
2565
2623
|
});
|
|
2566
2624
|
break;
|
|
2567
2625
|
}
|
|
2568
2626
|
case "rename-column":
|
|
2569
2627
|
yield* e.onDialectOrElse({
|
|
2570
|
-
mysql: () => X(e,
|
|
2628
|
+
mysql: () => X(e, pr(o, q), o.kind),
|
|
2571
2629
|
mssql: () => X(e, `EXEC sp_rename N'${o.table.replace(/'/g, "''")}.${o.from.replace(/'/g, "''")}', N'${o.to.replace(/'/g, "''")}', 'COLUMN';`, o.kind),
|
|
2572
|
-
orElse: () => X(e,
|
|
2630
|
+
orElse: () => X(e, pr(o, K), o.kind)
|
|
2573
2631
|
});
|
|
2574
2632
|
break;
|
|
2575
2633
|
case "add-index":
|
|
2576
2634
|
yield* e.onDialectOrElse({
|
|
2577
|
-
mysql: () => X(e,
|
|
2578
|
-
mssql: () => Z(e, [...
|
|
2579
|
-
orElse: () => X(e,
|
|
2635
|
+
mysql: () => W(e).pipe(x.flatMap((t) => X(e, Xr(o, n.declared, t), o.kind, [nr]))),
|
|
2636
|
+
mssql: () => Z(e, [...oi(o.table, o.index.columns, n.declared), ai(o)], o.kind),
|
|
2637
|
+
orElse: () => X(e, Yr(o, t.classification === "online-required"), o.kind)
|
|
2580
2638
|
});
|
|
2581
2639
|
break;
|
|
2582
2640
|
case "drop-index":
|
|
2583
2641
|
yield* e.onDialectOrElse({
|
|
2584
|
-
mysql: () => X(e,
|
|
2585
|
-
mssql: () => X(e,
|
|
2586
|
-
orElse: () => X(e,
|
|
2642
|
+
mysql: () => X(e, Qr(o), o.kind),
|
|
2643
|
+
mssql: () => X(e, $r(o), o.kind),
|
|
2644
|
+
orElse: () => X(e, Zr(o), o.kind)
|
|
2587
2645
|
});
|
|
2588
2646
|
break;
|
|
2589
2647
|
case "rename-table":
|
|
2590
2648
|
yield* e.onDialectOrElse({
|
|
2591
|
-
mysql: () => X(e,
|
|
2592
|
-
mssql: () => X(e,
|
|
2593
|
-
orElse: () => X(e,
|
|
2649
|
+
mysql: () => X(e, ei(o, q), o.kind),
|
|
2650
|
+
mssql: () => X(e, ti(o), o.kind),
|
|
2651
|
+
orElse: () => X(e, ei(o, K), o.kind)
|
|
2594
2652
|
});
|
|
2595
2653
|
break;
|
|
2596
2654
|
case "rename-index":
|
|
2597
2655
|
yield* e.onDialectOrElse({
|
|
2598
|
-
mysql: () => X(e,
|
|
2599
|
-
mssql: () => X(e,
|
|
2600
|
-
orElse: () => X(e,
|
|
2656
|
+
mysql: () => X(e, ri(o), o.kind),
|
|
2657
|
+
mssql: () => X(e, ii(o), o.kind),
|
|
2658
|
+
orElse: () => X(e, ni(o), o.kind)
|
|
2601
2659
|
});
|
|
2602
2660
|
break;
|
|
2603
2661
|
case "add-unique":
|
|
2604
2662
|
yield* e.onDialectOrElse({
|
|
2605
|
-
mysql: () => X(e,
|
|
2663
|
+
mysql: () => X(e, ci(o, n.declared), o.kind),
|
|
2606
2664
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2607
|
-
mssql: () => Z(e, [...
|
|
2608
|
-
orElse: () => X(e,
|
|
2665
|
+
mssql: () => Z(e, [...oi(o.table, [o.column], n.declared), si(o)], o.kind),
|
|
2666
|
+
orElse: () => X(e, si(o), o.kind)
|
|
2609
2667
|
});
|
|
2610
2668
|
break;
|
|
2611
2669
|
case "drop-unique":
|
|
2612
2670
|
yield* e.onDialectOrElse({
|
|
2613
|
-
mysql: () => X(e,
|
|
2671
|
+
mysql: () => X(e, mi(o), o.kind),
|
|
2614
2672
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2615
|
-
orElse: () => X(e,
|
|
2673
|
+
orElse: () => X(e, pi(o), o.kind)
|
|
2616
2674
|
});
|
|
2617
2675
|
break;
|
|
2618
2676
|
case "add-unique-composite":
|
|
2619
2677
|
yield* e.onDialectOrElse({
|
|
2620
|
-
mysql: () => X(e,
|
|
2678
|
+
mysql: () => X(e, ui(o, n.declared), o.kind),
|
|
2621
2679
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2622
|
-
mssql: () => Z(e, [...
|
|
2623
|
-
orElse: () => X(e,
|
|
2680
|
+
mssql: () => Z(e, [...oi(o.table, o.fields, n.declared), li(o)], o.kind),
|
|
2681
|
+
orElse: () => X(e, li(o), o.kind)
|
|
2624
2682
|
});
|
|
2625
2683
|
break;
|
|
2626
2684
|
case "drop-unique-composite":
|
|
2627
2685
|
yield* e.onDialectOrElse({
|
|
2628
|
-
mysql: () => X(e,
|
|
2686
|
+
mysql: () => X(e, fi(o), o.kind),
|
|
2629
2687
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2630
|
-
orElse: () => X(e,
|
|
2688
|
+
orElse: () => X(e, di(o), o.kind)
|
|
2631
2689
|
});
|
|
2632
2690
|
break;
|
|
2633
2691
|
case "add-foreign-key":
|
|
2634
2692
|
yield* e.onDialectOrElse({
|
|
2635
|
-
mysql: () => Z(e,
|
|
2693
|
+
mysql: () => Z(e, hi(o, q), o.kind),
|
|
2636
2694
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2637
|
-
orElse: () => Z(e,
|
|
2695
|
+
orElse: () => Z(e, hi(o, K), o.kind)
|
|
2638
2696
|
});
|
|
2639
2697
|
break;
|
|
2640
2698
|
case "add-column": {
|
|
2641
|
-
let n =
|
|
2642
|
-
mysql: () =>
|
|
2643
|
-
mssql: () =>
|
|
2644
|
-
sqlite: () =>
|
|
2645
|
-
orElse: () =>
|
|
2699
|
+
let n = xi(o, t, a, yield* e.onDialectOrElse({
|
|
2700
|
+
mysql: () => x.succeed("mariadb"),
|
|
2701
|
+
mssql: () => x.succeed("mssql"),
|
|
2702
|
+
sqlite: () => x.succeed("sqlite"),
|
|
2703
|
+
orElse: () => x.succeed("postgres")
|
|
2646
2704
|
}));
|
|
2647
|
-
if (!(r === "resume" && (yield* $(e,
|
|
2705
|
+
if (!(r === "resume" && (yield* $(e, Ne(e), o.table, o.column.name)))) for (let t of n.pre) yield* X(e, t, o.kind);
|
|
2648
2706
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2649
2707
|
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2650
2708
|
else {
|
|
@@ -2653,10 +2711,10 @@ BEGIN
|
|
|
2653
2711
|
let s = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
2654
2712
|
if (s.length === 0) break;
|
|
2655
2713
|
let c = s.map((e) => e.id);
|
|
2656
|
-
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield*
|
|
2714
|
+
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield* x.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows`).pipe(x.annotateLogs({
|
|
2657
2715
|
scope: "voltro:migrate",
|
|
2658
2716
|
mode: "sql-batched"
|
|
2659
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2717
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* x.sleep(`${r} millis`));
|
|
2660
2718
|
}
|
|
2661
2719
|
}
|
|
2662
2720
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
@@ -2665,17 +2723,17 @@ BEGIN
|
|
|
2665
2723
|
let s = i === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL ORDER BY ${e("id")} ${Q(e, t)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(o.column.name)} IS NULL AND ${e("id")} > ${i} ORDER BY ${e("id")} ${Q(e, t)}`;
|
|
2666
2724
|
if (s.length === 0) break;
|
|
2667
2725
|
for (let t of s) {
|
|
2668
|
-
let r = yield*
|
|
2726
|
+
let r = yield* x.tryPromise({
|
|
2669
2727
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2670
2728
|
catch: (e) => e
|
|
2671
|
-
}).pipe(
|
|
2729
|
+
}).pipe(x.orDie);
|
|
2672
2730
|
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2673
2731
|
}
|
|
2674
|
-
a += s.length, yield*
|
|
2732
|
+
a += s.length, yield* x.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows processed`).pipe(x.annotateLogs({
|
|
2675
2733
|
scope: "voltro:migrate",
|
|
2676
2734
|
table: o.table,
|
|
2677
2735
|
column: o.column.name
|
|
2678
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2736
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* x.sleep(`${r} millis`));
|
|
2679
2737
|
}
|
|
2680
2738
|
}
|
|
2681
2739
|
for (let t of n.post) yield* X(e, t, o.kind);
|
|
@@ -2684,77 +2742,77 @@ BEGIN
|
|
|
2684
2742
|
case "alter-column-nullability":
|
|
2685
2743
|
yield* e.onDialectOrElse({
|
|
2686
2744
|
mysql: () => {
|
|
2687
|
-
let t =
|
|
2688
|
-
return t ? X(e, `ALTER TABLE ${
|
|
2745
|
+
let t = _r(n.declared, o.table, o.column);
|
|
2746
|
+
return t ? X(e, `ALTER TABLE ${q(o.table)} MODIFY COLUMN ${yr(t, o.column, o.toNullable)};`, o.kind) : x.die(/* @__PURE__ */ Error(`alter-column-nullability on mariadb needs the declared column '${o.table}.${o.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2689
2747
|
},
|
|
2690
2748
|
mssql: () => {
|
|
2691
|
-
let t =
|
|
2692
|
-
return t ? X(e,
|
|
2749
|
+
let t = _r(n.declared, o.table, o.column);
|
|
2750
|
+
return t ? X(e, Rr(t, o.column, o.table, o.toNullable), o.kind) : x.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2693
2751
|
},
|
|
2694
2752
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2695
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
2753
|
+
orElse: () => X(e, `ALTER TABLE ${K(o.table)} ALTER COLUMN ${K(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2696
2754
|
});
|
|
2697
2755
|
break;
|
|
2698
2756
|
case "alter-column-default": {
|
|
2699
|
-
let t =
|
|
2757
|
+
let t = vr(n.declared, o.table, o.column);
|
|
2700
2758
|
yield* e.onDialectOrElse({
|
|
2701
|
-
mysql: () => X(e,
|
|
2702
|
-
mssql: () => X(e,
|
|
2759
|
+
mysql: () => X(e, hr(o, q, (e) => br(e, t)), o.kind),
|
|
2760
|
+
mssql: () => X(e, zr(o), o.kind),
|
|
2703
2761
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2704
|
-
orElse: () => X(e,
|
|
2762
|
+
orElse: () => X(e, hr(o, K, (e) => Sr(e, t)), o.kind)
|
|
2705
2763
|
});
|
|
2706
2764
|
break;
|
|
2707
2765
|
}
|
|
2708
2766
|
case "alter-column-type": {
|
|
2709
|
-
let r =
|
|
2767
|
+
let r = sr(vr(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2710
2768
|
if (t.classification !== "online-required") {
|
|
2711
2769
|
yield* e.onDialectOrElse({
|
|
2712
2770
|
mysql: () => {
|
|
2713
|
-
let t =
|
|
2714
|
-
return t ? X(e, `ALTER TABLE ${
|
|
2771
|
+
let t = _r(n.declared, o.table, o.column);
|
|
2772
|
+
return t ? X(e, `ALTER TABLE ${q(o.table)} MODIFY COLUMN ${yr(t, o.column)};`, o.kind) : x.die(/* @__PURE__ */ Error(`alter-column-type on mariadb needs the declared column '${o.table}.${o.column}' (to render MODIFY COLUMN); it was not in ctx.declared.`));
|
|
2715
2773
|
},
|
|
2716
2774
|
mssql: () => {
|
|
2717
|
-
let t =
|
|
2718
|
-
return t ? X(e,
|
|
2775
|
+
let t = _r(n.declared, o.table, o.column);
|
|
2776
|
+
return t ? X(e, Rr(t, o.column, o.table), o.kind) : x.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2719
2777
|
},
|
|
2720
2778
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2721
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
2779
|
+
orElse: () => X(e, `ALTER TABLE ${K(o.table)} ALTER COLUMN ${K(o.column)} TYPE ${r}${i};`, o.kind)
|
|
2722
2780
|
});
|
|
2723
2781
|
break;
|
|
2724
2782
|
}
|
|
2725
2783
|
yield* e.onDialectOrElse({
|
|
2726
|
-
mysql: () =>
|
|
2727
|
-
orElse: () =>
|
|
2784
|
+
mysql: () => x.die(/* @__PURE__ */ Error(`online-required alter-column-type on ${o.table}.${o.column} is not supported on mariadb (the shadow-swap path is postgres-only). Use a smaller-table window or an external online-DDL tool.`)),
|
|
2785
|
+
orElse: () => x.void
|
|
2728
2786
|
});
|
|
2729
2787
|
let a = `${o.column}__shadow`, s = `${o.column}__old`;
|
|
2730
|
-
yield* e.unsafe(`ALTER TABLE ${
|
|
2731
|
-
let c = o.using ??
|
|
2788
|
+
yield* e.unsafe(`ALTER TABLE ${K(o.table)} ADD COLUMN ${K(a)} ${r}`);
|
|
2789
|
+
let c = o.using ?? K(o.column), l;
|
|
2732
2790
|
for (;;) {
|
|
2733
2791
|
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${Q(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${Q(e, 5e3)}`;
|
|
2734
2792
|
if (t.length === 0) break;
|
|
2735
|
-
yield* e.unsafe(`UPDATE ${
|
|
2793
|
+
yield* e.unsafe(`UPDATE ${K(o.table)} SET ${K(a)} = ${c} WHERE ${K(o.column)} IS NOT NULL AND ${K(a)} IS NULL AND ${K("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
2736
2794
|
}
|
|
2737
|
-
yield*
|
|
2795
|
+
yield* x.logInfo(`alter-column-type shadow ${o.table}.${o.column}: shadow populated`).pipe(x.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${K(o.table)} RENAME COLUMN ${K(o.column)} TO ${K(s)}`), yield* e.unsafe(`ALTER TABLE ${K(o.table)} RENAME COLUMN ${K(a)} TO ${K(o.column)}`), yield* e.unsafe(`ALTER TABLE ${K(o.table)} DROP COLUMN ${K(s)}`);
|
|
2738
2796
|
break;
|
|
2739
2797
|
}
|
|
2740
2798
|
case "drop-foreign-key":
|
|
2741
2799
|
yield* e.onDialectOrElse({
|
|
2742
|
-
mysql: () => X(e,
|
|
2800
|
+
mysql: () => X(e, _i(o), o.kind),
|
|
2743
2801
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2744
|
-
orElse: () => X(e,
|
|
2802
|
+
orElse: () => X(e, gi(o), o.kind)
|
|
2745
2803
|
});
|
|
2746
2804
|
break;
|
|
2747
2805
|
case "add-check":
|
|
2748
2806
|
yield* e.onDialectOrElse({
|
|
2749
|
-
mysql: () => X(e,
|
|
2807
|
+
mysql: () => X(e, vi(o, q), o.kind),
|
|
2750
2808
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2751
|
-
orElse: () => X(e,
|
|
2809
|
+
orElse: () => X(e, vi(o, K), o.kind)
|
|
2752
2810
|
});
|
|
2753
2811
|
break;
|
|
2754
2812
|
case "drop-check": yield* e.onDialectOrElse({
|
|
2755
|
-
mysql: () => X(e,
|
|
2813
|
+
mysql: () => X(e, bi(o), o.kind),
|
|
2756
2814
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2757
|
-
orElse: () => X(e,
|
|
2815
|
+
orElse: () => X(e, yi(o), o.kind)
|
|
2758
2816
|
});
|
|
2759
2817
|
}
|
|
2760
2818
|
return {
|
|
@@ -2762,32 +2820,32 @@ BEGIN
|
|
|
2762
2820
|
status: "applied",
|
|
2763
2821
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2764
2822
|
};
|
|
2765
|
-
}),
|
|
2823
|
+
}), ji = (e, t, n, r) => x.gen(function* () {
|
|
2766
2824
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2767
|
-
if (i.length > 1) return yield*
|
|
2825
|
+
if (i.length > 1) return yield* x.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 \`${O}\`, reconcile the schema by hand, and delete the rows of the run you have finished.`));
|
|
2768
2826
|
let a = i[0], o = [...r].map((e) => ({
|
|
2769
2827
|
index: Number(e.opIndex),
|
|
2770
2828
|
status: e.status,
|
|
2771
2829
|
planned: JSON.parse(e.payload)
|
|
2772
2830
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
2773
|
-
if (c > 1) return yield*
|
|
2774
|
-
if (yield*
|
|
2831
|
+
if (c > 1) return yield* x.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 \`${O}\` by hand before re-running.`));
|
|
2832
|
+
if (yield* x.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} ${Re(s.planned.op)}` : ""}`).pipe(x.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
2775
2833
|
kind: "discard",
|
|
2776
2834
|
runId: a,
|
|
2777
2835
|
why: "no operation had started — no DDL ran"
|
|
2778
2836
|
};
|
|
2779
|
-
let l = s ? yield*
|
|
2837
|
+
let l = s ? yield* ki(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2780
2838
|
if (u !== n.toFingerprint) return {
|
|
2781
2839
|
kind: "discard",
|
|
2782
2840
|
runId: a,
|
|
2783
2841
|
why: `the declared schema changed since the interruption (recorded target ${u.slice(0, 12)}…, current ${n.toFingerprint.slice(0, 12)}…) — applying the freshly-diffed plan instead`
|
|
2784
2842
|
};
|
|
2785
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
2843
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : Be(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
2786
2844
|
return f.length === 0 ? {
|
|
2787
2845
|
kind: "discard",
|
|
2788
2846
|
runId: a,
|
|
2789
2847
|
why: "every recorded operation had already taken effect"
|
|
2790
|
-
} : (yield*
|
|
2848
|
+
} : (yield* Di(e, a, f.map((e) => e.index), p.map((e) => e.index)), yield* x.logWarning(`migration resume: continuing run ${a} — replaying ${f.length} operation(s), ${o.length - f.length} already applied`).pipe(x.annotateLogs({ scope: "voltro:migrate" })), {
|
|
2791
2849
|
kind: "resume",
|
|
2792
2850
|
runId: a,
|
|
2793
2851
|
ops: f.map((e) => ({
|
|
@@ -2795,55 +2853,55 @@ BEGIN
|
|
|
2795
2853
|
planned: e.planned
|
|
2796
2854
|
}))
|
|
2797
2855
|
});
|
|
2798
|
-
}),
|
|
2856
|
+
}), Mi = (e, t, n) => x.gen(function* () {
|
|
2799
2857
|
let r = t.operations.filter((e) => e.blocked);
|
|
2800
|
-
if (r.length > 0) return yield*
|
|
2858
|
+
if (r.length > 0) return yield* x.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
2801
2859
|
yield* E(e, { schema: n.lockSchema });
|
|
2802
|
-
let i = Date.now(), a = [], o =
|
|
2860
|
+
let i = Date.now(), a = [], o = Ne(e), s = Fe(o) === "plan-transactional", c = s ? t.operations.filter((e) => e.classification !== "online-required") : [], u = s ? t.operations.filter((e) => e.classification === "online-required") : t.operations, d = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, f = u.map((e, t) => ({
|
|
2803
2861
|
index: t,
|
|
2804
2862
|
planned: e
|
|
2805
2863
|
})), p = "fresh";
|
|
2806
2864
|
try {
|
|
2807
|
-
yield*
|
|
2808
|
-
let r = yield*
|
|
2865
|
+
yield* Ci(e, o);
|
|
2866
|
+
let r = yield* wi(e);
|
|
2809
2867
|
if (r.length > 0) {
|
|
2810
|
-
let n = yield*
|
|
2811
|
-
n.kind === "resume" ? (d = n.runId, f = n.ops, p = "resume") : (yield*
|
|
2868
|
+
let n = yield* ji(e, o, t, r);
|
|
2869
|
+
n.kind === "resume" ? (d = n.runId, f = n.ops, p = "resume") : (yield* x.logWarning(`migration resume: discarding the ledger of run ${n.runId} — ${n.why}`).pipe(x.annotateLogs({ scope: "voltro:migrate" })), yield* Oi(e, n.runId));
|
|
2812
2870
|
}
|
|
2813
|
-
p === "fresh" && f.length > 0 && (yield*
|
|
2871
|
+
p === "fresh" && f.length > 0 && (yield* Ti(e, d, t.toFingerprint, f)), c.length > 0 && (yield* e.withTransaction(x.gen(function* () {
|
|
2814
2872
|
let e = yield* C.SqlClient;
|
|
2815
|
-
for (let t of
|
|
2873
|
+
for (let t of c) a.push(yield* Ai(e, t, n));
|
|
2816
2874
|
})));
|
|
2817
2875
|
for (let { index: t, planned: r } of f) {
|
|
2818
|
-
yield*
|
|
2819
|
-
let i = yield*
|
|
2820
|
-
a.push(i), yield*
|
|
2876
|
+
yield* Ei(e, d, t, "started");
|
|
2877
|
+
let i = yield* Ai(e, r, n, p);
|
|
2878
|
+
a.push(i), yield* Ei(e, d, t, "applied", i.durationMs);
|
|
2821
2879
|
}
|
|
2822
2880
|
} finally {
|
|
2823
|
-
yield* D(e, { schema: n.lockSchema }).pipe(
|
|
2881
|
+
yield* D(e, { schema: n.lockSchema }).pipe(x.orDie);
|
|
2824
2882
|
}
|
|
2825
2883
|
let m = yield* n.replan(e);
|
|
2826
2884
|
if (m.operations.length > 0) {
|
|
2827
2885
|
let e = m.operations.slice(0, 10).map((e) => ` - ${e.op.kind} ${"table" in e.op ? e.op.table : ""}${"column" in e.op ? `.${String(e.op.column)}` : ""}`).join("\n");
|
|
2828
|
-
return yield*
|
|
2886
|
+
return yield* x.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${t.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${m.operations.length}:\n${e}${m.operations.length > 10 ? `\n … and ${m.operations.length - 10} more` : ""}\nNo fingerprint was recorded — recording one would make the next boot report "schema up to date" for a schema that was never applied. This is a framework bug; the schema is unchanged and safe.\nTwo causes look identical from here, so read the list before assuming either:\n - the DDL for those operations is a no-op (it succeeded and changed nothing), or\n - the planner cannot see what the DDL did, so it proposes the same work again — which is what an\n operation naming an object a PREVIOUS operation created or renamed usually means.\nReport the operation kinds above with the column types involved.`));
|
|
2829
2887
|
}
|
|
2830
|
-
let h = a.filter((e) => e.status === "applied").length, g = Date.now() - i, _ = d, v = (/* @__PURE__ */ new Date()).toISOString(), y = yield*
|
|
2888
|
+
let h = a.filter((e) => e.status === "applied").length, g = Date.now() - i, _ = d, v = (/* @__PURE__ */ new Date()).toISOString(), y = yield* G(e, v), b = [...c, ...f.map((e) => e.planned)];
|
|
2831
2889
|
yield* e`
|
|
2832
2890
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2833
2891
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
2834
2892
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
2835
2893
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
2836
2894
|
VALUES
|
|
2837
|
-
(${_}, ${t.toFingerprint}, ${m.fromFingerprint}, ${JSON.stringify(
|
|
2895
|
+
(${_}, ${t.toFingerprint}, ${m.fromFingerprint}, ${JSON.stringify(b)},
|
|
2838
2896
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2839
2897
|
${g}, ${y}, ${n.notes ?? null})
|
|
2840
|
-
`, yield*
|
|
2841
|
-
let S = [...new Set(
|
|
2842
|
-
return yield*
|
|
2898
|
+
`, yield* Oi(e, d);
|
|
2899
|
+
let S = [...new Set(b.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
2900
|
+
return yield* x.promise(() => l({ changedTables: S }).catch(() => {})), {
|
|
2843
2901
|
id: _,
|
|
2844
2902
|
appliedAt: v,
|
|
2845
2903
|
fingerprint: t.toFingerprint,
|
|
2846
|
-
operations:
|
|
2904
|
+
operations: b,
|
|
2847
2905
|
appliedBy: n.appliedBy,
|
|
2848
2906
|
environment: n.environment,
|
|
2849
2907
|
durationMs: g,
|
|
@@ -2851,14 +2909,14 @@ BEGIN
|
|
|
2851
2909
|
source: n.source,
|
|
2852
2910
|
...n.notes ? { notes: n.notes } : {}
|
|
2853
2911
|
};
|
|
2854
|
-
}),
|
|
2912
|
+
}), Ni = (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"), Pi = (e) => e`
|
|
2855
2913
|
SELECT fingerprint
|
|
2856
2914
|
FROM _voltro_migration_plans
|
|
2857
2915
|
ORDER BY ${e("appliedAt")} DESC
|
|
2858
2916
|
LIMIT 1
|
|
2859
|
-
`.pipe(
|
|
2860
|
-
if ((yield*
|
|
2861
|
-
let r = `plan_${Date.now().toString(36)}`, i = yield*
|
|
2917
|
+
`.pipe(x.map((e) => e.length > 0 ? e[0].fingerprint : void 0), x.catchAll(() => x.succeed(void 0))), Fi = (e, t, n) => x.gen(function* () {
|
|
2918
|
+
if ((yield* Pi(e)) === t.toFingerprint) return "already-current";
|
|
2919
|
+
let r = `plan_${Date.now().toString(36)}`, i = yield* G(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2862
2920
|
return yield* e`
|
|
2863
2921
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2864
2922
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -2869,8 +2927,8 @@ BEGIN
|
|
|
2869
2927
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2870
2928
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
2871
2929
|
`, "recorded";
|
|
2872
|
-
}).pipe(
|
|
2873
|
-
let n =
|
|
2930
|
+
}).pipe(x.catchAll(() => x.succeed("already-current"))), Ii = (e, t) => x.gen(function* () {
|
|
2931
|
+
let n = F(L(t, Ne(e))), r = yield* Pi(e);
|
|
2874
2932
|
return r === n ? {
|
|
2875
2933
|
kind: "up-to-date",
|
|
2876
2934
|
fingerprint: n
|
|
@@ -2879,23 +2937,23 @@ BEGIN
|
|
|
2879
2937
|
expected: n,
|
|
2880
2938
|
...r === void 0 ? {} : { actual: r }
|
|
2881
2939
|
};
|
|
2882
|
-
}),
|
|
2940
|
+
}), Li = [
|
|
2883
2941
|
"pgeagertest_",
|
|
2884
2942
|
"mig_e2e_",
|
|
2885
2943
|
"mig_test_",
|
|
2886
2944
|
"mysqleagertest_",
|
|
2887
2945
|
"mssqleagertest_",
|
|
2888
2946
|
"sqliteeagertest_"
|
|
2889
|
-
],
|
|
2947
|
+
], Ri = (e) => Li.some((t) => e.startsWith(t)), zi = (e, t) => x.gen(function* () {
|
|
2890
2948
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
2891
|
-
let n = t.filter((e) =>
|
|
2949
|
+
let n = t.filter((e) => Ri(e.name)).map((e) => e.name);
|
|
2892
2950
|
if (n.length === 0) return [];
|
|
2893
|
-
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(
|
|
2951
|
+
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(x.catchAll(() => x.void));
|
|
2894
2952
|
return n;
|
|
2895
|
-
}),
|
|
2953
|
+
}), Bi = () => {
|
|
2896
2954
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
2897
2955
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
2898
|
-
},
|
|
2956
|
+
}, Vi = (e) => {
|
|
2899
2957
|
if (e === void 0) return;
|
|
2900
2958
|
let t = e.trim();
|
|
2901
2959
|
if (t === "") return;
|
|
@@ -2905,48 +2963,48 @@ BEGIN
|
|
|
2905
2963
|
kind: "tables",
|
|
2906
2964
|
tables: new Set(n)
|
|
2907
2965
|
} : void 0;
|
|
2908
|
-
},
|
|
2966
|
+
}, Hi = (e) => typeof e.table == "string" ? e.table : void 0, Ui = (e, t = { kind: "all" }) => ({
|
|
2909
2967
|
...e,
|
|
2910
2968
|
operations: e.operations.map((e) => {
|
|
2911
2969
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
2912
2970
|
if (t?.kind === "tables") {
|
|
2913
|
-
let n =
|
|
2971
|
+
let n = Hi(e.op);
|
|
2914
2972
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
2915
2973
|
}
|
|
2916
2974
|
let { blocked: n, ...r } = e;
|
|
2917
2975
|
return r;
|
|
2918
2976
|
})
|
|
2919
|
-
}),
|
|
2920
|
-
let t =
|
|
2921
|
-
return t === void 0 ?
|
|
2922
|
-
}),
|
|
2923
|
-
let r =
|
|
2977
|
+
}), Wi = (e, t, n) => t === "postgres" ? Jt(e, n).pipe(x.flatMap((e) => {
|
|
2978
|
+
let t = Yt(e);
|
|
2979
|
+
return t === void 0 ? x.void : x.logWarning(`auto-migrate: ${t}`).pipe(x.annotateLogs({ scope: "voltro:migrate" }));
|
|
2980
|
+
}), x.catchAll(() => x.void)) : x.void, Gi = (e, t, n) => x.gen(function* () {
|
|
2981
|
+
let r = Ne(e), i = t;
|
|
2924
2982
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
2925
|
-
let t =
|
|
2926
|
-
if ((yield*
|
|
2983
|
+
let t = F(L(i, r));
|
|
2984
|
+
if ((yield* Pi(e)) === t) return yield* Wi(e, r, i), {
|
|
2927
2985
|
kind: "up-to-date",
|
|
2928
2986
|
fingerprint: t
|
|
2929
2987
|
};
|
|
2930
2988
|
}
|
|
2931
|
-
let a = yield*
|
|
2932
|
-
o.length > 0 && (yield*
|
|
2989
|
+
let a = yield* Yn(e), o = yield* zi(e, a.tables);
|
|
2990
|
+
o.length > 0 && (yield* x.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(x.annotateLogs({
|
|
2933
2991
|
scope: "voltro:migrate",
|
|
2934
2992
|
count: o.length
|
|
2935
|
-
})), a = yield*
|
|
2936
|
-
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !m(e.name) || s.has(e.name)), l =
|
|
2993
|
+
})), a = yield* Yn(e));
|
|
2994
|
+
let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !m(e.name) || s.has(e.name)), l = An({
|
|
2937
2995
|
declared: i,
|
|
2938
2996
|
live: { tables: c(a.tables) },
|
|
2939
2997
|
dialect: r,
|
|
2940
|
-
...
|
|
2998
|
+
...Bi()
|
|
2941
2999
|
});
|
|
2942
3000
|
if (l.summary.blocked > 0) {
|
|
2943
|
-
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t =
|
|
2944
|
-
if (t === void 0 || !e || (l =
|
|
3001
|
+
let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Vi(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3002
|
+
if (t === void 0 || !e || (l = Ui(l, t), l.operations.some((e) => e.blocked))) return {
|
|
2945
3003
|
kind: "refused-blocked",
|
|
2946
3004
|
plan: l
|
|
2947
3005
|
};
|
|
2948
3006
|
}
|
|
2949
|
-
return l.operations.length === 0 ? (yield*
|
|
3007
|
+
return l.operations.length === 0 ? (yield* Fi(e, l, {
|
|
2950
3008
|
appliedBy: n.appliedBy,
|
|
2951
3009
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
2952
3010
|
source: "auto-diff"
|
|
@@ -2955,37 +3013,37 @@ BEGIN
|
|
|
2955
3013
|
fingerprint: l.toFingerprint
|
|
2956
3014
|
}) : {
|
|
2957
3015
|
kind: "applied",
|
|
2958
|
-
applied: yield*
|
|
3016
|
+
applied: yield* Mi(e, l, {
|
|
2959
3017
|
declared: t,
|
|
2960
3018
|
appliedBy: n.appliedBy,
|
|
2961
3019
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
2962
3020
|
source: "auto-diff",
|
|
2963
|
-
replan: (e) =>
|
|
2964
|
-
let t = yield*
|
|
2965
|
-
return
|
|
3021
|
+
replan: (e) => x.gen(function* () {
|
|
3022
|
+
let t = yield* Yn(e);
|
|
3023
|
+
return An({
|
|
2966
3024
|
declared: i,
|
|
2967
3025
|
live: { tables: c(t.tables) },
|
|
2968
3026
|
dialect: r,
|
|
2969
|
-
...
|
|
3027
|
+
...Bi()
|
|
2970
3028
|
});
|
|
2971
3029
|
})
|
|
2972
3030
|
}),
|
|
2973
3031
|
plan: l
|
|
2974
3032
|
};
|
|
2975
|
-
}),
|
|
3033
|
+
}), Ki = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? x.succeed({
|
|
2976
3034
|
kind: "skipped",
|
|
2977
3035
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
2978
|
-
}) : n.environment === "prod" ?
|
|
3036
|
+
}) : n.environment === "prod" ? Ii(e, t) : Gi(e, t, n), qi = (e, t) => {
|
|
2979
3037
|
switch (e.kind) {
|
|
2980
3038
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
2981
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
3039
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${I(e.fingerprint)})`;
|
|
2982
3040
|
case "applied": {
|
|
2983
3041
|
let t = e.plan.summary;
|
|
2984
|
-
return `auto-migrate: applied ${e.applied.appliedOps} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${
|
|
3042
|
+
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=${I(e.applied.fingerprint)}`;
|
|
2985
3043
|
}
|
|
2986
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
3044
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${I(e.expected)}` + (e.actual ? ` live=${I(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
2987
3045
|
case "refused-blocked": {
|
|
2988
|
-
let t = e.plan.operations.filter((e) => e.blocked), n = t.filter((e) => e.op.kind === "drop-table").length, r = t.filter((e) => e.op.kind === "drop-table").map((e) => "table" in e.op ? e.op.table : "").filter(Boolean), i = t.filter((e) => e.op.kind === "add-column").length, a = t.filter((e) => e.op.kind === "drop-column").length, o = t.filter((e) => e.classification === "needs-rename-annotation").length, s = `auto-migrate: REFUSED — ${e.plan.summary.blocked} blocked operation(s):\n` +
|
|
3046
|
+
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` + Ni(e.plan), c = [""];
|
|
2989
3047
|
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) {
|
|
2990
3048
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2991
3049
|
for (let r of e.plan.operations) {
|
|
@@ -3002,7 +3060,7 @@ BEGIN
|
|
|
3002
3060
|
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");
|
|
3003
3061
|
}
|
|
3004
3062
|
}
|
|
3005
|
-
},
|
|
3063
|
+
}, Ji = /* @__PURE__ */ new Set([
|
|
3006
3064
|
"node_modules",
|
|
3007
3065
|
"dist",
|
|
3008
3066
|
"build",
|
|
@@ -3011,24 +3069,24 @@ BEGIN
|
|
|
3011
3069
|
".next",
|
|
3012
3070
|
".git",
|
|
3013
3071
|
".framework"
|
|
3014
|
-
]),
|
|
3072
|
+
]), Yi = async (e) => {
|
|
3015
3073
|
let t = [], n = async (e) => {
|
|
3016
|
-
let r = await
|
|
3074
|
+
let r = await ne.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3017
3075
|
for (let i of r) {
|
|
3018
|
-
if (
|
|
3019
|
-
let r =
|
|
3020
|
-
i.isDirectory() ? await n(r) : i.isFile() &&
|
|
3076
|
+
if (Ji.has(i.name)) continue;
|
|
3077
|
+
let r = re(e, i.name);
|
|
3078
|
+
i.isDirectory() ? await n(r) : i.isFile() && d.test(i.name) && t.push(r);
|
|
3021
3079
|
}
|
|
3022
3080
|
};
|
|
3023
3081
|
return await n(e), t.sort((e, t) => {
|
|
3024
3082
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3025
3083
|
return n.localeCompare(r);
|
|
3026
3084
|
});
|
|
3027
|
-
},
|
|
3085
|
+
}, Xi = async (e) => {
|
|
3028
3086
|
let t = [];
|
|
3029
3087
|
for (let n of e) {
|
|
3030
|
-
let e = (await import(
|
|
3031
|
-
if (!
|
|
3088
|
+
let e = (await import(ie(n).href)).default;
|
|
3089
|
+
if (!c(e)) {
|
|
3032
3090
|
process.stderr.write(`[voltro:migrate] ${n} has no default-exported \`migration(...)\` — skipped\n`);
|
|
3033
3091
|
continue;
|
|
3034
3092
|
}
|
|
@@ -3038,11 +3096,11 @@ BEGIN
|
|
|
3038
3096
|
});
|
|
3039
3097
|
}
|
|
3040
3098
|
return t;
|
|
3041
|
-
},
|
|
3099
|
+
}, Zi = (e) => e`
|
|
3042
3100
|
SELECT ${e("id")}
|
|
3043
3101
|
FROM ${e("_voltro_migration_plans")}
|
|
3044
3102
|
WHERE ${e("source")} = 'file'
|
|
3045
|
-
`.pipe(
|
|
3103
|
+
`.pipe(x.map((e) => e.map((e) => e.id)), x.catchAll(() => x.succeed([]))), Qi = class extends Error {
|
|
3046
3104
|
migrationId;
|
|
3047
3105
|
file;
|
|
3048
3106
|
cause;
|
|
@@ -3050,28 +3108,28 @@ BEGIN
|
|
|
3050
3108
|
constructor(e, t, n) {
|
|
3051
3109
|
super(`migration ${e}: up() SUCCEEDED but the ledger row could not be written.\n The change IS in the database. It is NOT recorded, so the next run would apply it AGAIN.\n Do not re-run ${t} until this is resolved.\n Cause: ${n instanceof Error ? n.message : String(n)}`), this.migrationId = e, this.file = t, this.cause = n, this.name = "FileMigrationLedgerError";
|
|
3052
3110
|
}
|
|
3053
|
-
},
|
|
3111
|
+
}, $i = (e, t, n, r) => x.gen(function* () {
|
|
3054
3112
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3055
3113
|
sql: e,
|
|
3056
3114
|
log: {
|
|
3057
|
-
info: (e, n) =>
|
|
3115
|
+
info: (e, n) => x.logInfo(e).pipe(x.annotateLogs({
|
|
3058
3116
|
scope: `migrations:file:${t.migration.id}`,
|
|
3059
3117
|
...n ?? {}
|
|
3060
3118
|
})),
|
|
3061
|
-
warn: (e, n) =>
|
|
3119
|
+
warn: (e, n) => x.logWarning(e).pipe(x.annotateLogs({
|
|
3062
3120
|
scope: `migrations:file:${t.migration.id}`,
|
|
3063
3121
|
...n ?? {}
|
|
3064
3122
|
}))
|
|
3065
3123
|
},
|
|
3066
3124
|
appliedAt: a
|
|
3067
3125
|
}, s = t.migration.up(o);
|
|
3068
|
-
|
|
3126
|
+
x.isEffect(s) ? yield* s : yield* x.tryPromise({
|
|
3069
3127
|
try: () => s,
|
|
3070
3128
|
catch: (e) => e
|
|
3071
3129
|
});
|
|
3072
3130
|
let c = Date.now() - i;
|
|
3073
|
-
!
|
|
3074
|
-
let l = yield*
|
|
3131
|
+
!x.isEffect(s) && c < 2 && (yield* x.logWarning(`migration ${t.migration.id}: up() resolved in ${c}ms — did the body \`await\` an \`@effect/sql\` Effect by accident? \`sql.unsafe(...)\` returns an Effect, not a Promise; \`await\` on it is a silent no-op. Switch the body to \`Effect.gen(function* () { yield* sql.unsafe(...) })\` form.`).pipe(x.annotateLogs({ scope: `migrations:file:${t.migration.id}` })));
|
|
3132
|
+
let l = yield* G(e, a);
|
|
3075
3133
|
return yield* e`
|
|
3076
3134
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3077
3135
|
(${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
@@ -3084,31 +3142,31 @@ BEGIN
|
|
|
3084
3142
|
}])},
|
|
3085
3143
|
${r}, ${n}, ${"file"},
|
|
3086
3144
|
${c}, ${l}, ${t.migration.description})
|
|
3087
|
-
`.pipe(
|
|
3088
|
-
}),
|
|
3089
|
-
let n = yield*
|
|
3090
|
-
try: () =>
|
|
3145
|
+
`.pipe(x.mapError((e) => new Qi(t.migration.id, t.file, e))), { durationMs: c };
|
|
3146
|
+
}), ea = (e, t) => x.gen(function* () {
|
|
3147
|
+
let n = yield* x.tryPromise({
|
|
3148
|
+
try: () => Yi(re(t, "migrations")),
|
|
3091
3149
|
catch: (e) => e
|
|
3092
3150
|
});
|
|
3093
3151
|
if (n.length === 0) return {
|
|
3094
3152
|
pending: [],
|
|
3095
3153
|
skipped: []
|
|
3096
3154
|
};
|
|
3097
|
-
let r = yield*
|
|
3098
|
-
try: () =>
|
|
3155
|
+
let r = yield* x.tryPromise({
|
|
3156
|
+
try: () => Xi(n),
|
|
3099
3157
|
catch: (e) => e
|
|
3100
3158
|
});
|
|
3101
3159
|
if (r.length === 0) return {
|
|
3102
3160
|
pending: [],
|
|
3103
3161
|
skipped: []
|
|
3104
3162
|
};
|
|
3105
|
-
let i = new Set(yield*
|
|
3163
|
+
let i = new Set(yield* Zi(e));
|
|
3106
3164
|
return {
|
|
3107
3165
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3108
3166
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3109
3167
|
};
|
|
3110
|
-
}),
|
|
3111
|
-
let { pending: n, skipped: r } = yield*
|
|
3168
|
+
}), ta = (e, t) => ea(e, t).pipe(x.map((e) => e.pending.map((e) => e.migration.id))), na = (e, t) => x.gen(function* () {
|
|
3169
|
+
let { pending: n, skipped: r } = yield* ea(e, t.projectRoot);
|
|
3112
3170
|
if (n.length === 0) return {
|
|
3113
3171
|
applied: [],
|
|
3114
3172
|
skipped: r
|
|
@@ -3117,61 +3175,61 @@ BEGIN
|
|
|
3117
3175
|
let i = [];
|
|
3118
3176
|
try {
|
|
3119
3177
|
for (let r of n) {
|
|
3120
|
-
yield*
|
|
3178
|
+
yield* x.logInfo("file-based migration applying").pipe(x.annotateLogs({
|
|
3121
3179
|
scope: "voltro:migrate",
|
|
3122
3180
|
id: r.migration.id,
|
|
3123
3181
|
file: r.file
|
|
3124
3182
|
}));
|
|
3125
|
-
let { durationMs: n } = yield*
|
|
3183
|
+
let { durationMs: n } = yield* $i(e, r, t.env, t.appliedBy);
|
|
3126
3184
|
i.push({
|
|
3127
3185
|
id: r.migration.id,
|
|
3128
3186
|
durationMs: n
|
|
3129
|
-
}), yield*
|
|
3187
|
+
}), yield* x.logInfo("file-based migration applied").pipe(x.annotateLogs({
|
|
3130
3188
|
scope: "voltro:migrate",
|
|
3131
3189
|
id: r.migration.id,
|
|
3132
3190
|
durationMs: n
|
|
3133
3191
|
}));
|
|
3134
3192
|
}
|
|
3135
3193
|
} finally {
|
|
3136
|
-
yield* D(e, { schema: t.lockSchema }).pipe(
|
|
3194
|
+
yield* D(e, { schema: t.lockSchema }).pipe(x.orDie);
|
|
3137
3195
|
}
|
|
3138
3196
|
return {
|
|
3139
3197
|
applied: i,
|
|
3140
3198
|
skipped: r
|
|
3141
3199
|
};
|
|
3142
|
-
}),
|
|
3200
|
+
}), ra = (e, t) => e`
|
|
3143
3201
|
SELECT ${e("id")}
|
|
3144
3202
|
FROM ${e("_voltro_migration_plans")}
|
|
3145
3203
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3146
3204
|
LIMIT 1
|
|
3147
|
-
`,
|
|
3148
|
-
if (!(yield*
|
|
3149
|
-
let n = yield*
|
|
3150
|
-
try: () =>
|
|
3205
|
+
`, ia = (e, t) => x.gen(function* () {
|
|
3206
|
+
if (!(yield* ra(e, t.id))[0]) return yield* x.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3207
|
+
let n = yield* x.tryPromise({
|
|
3208
|
+
try: () => Yi(re(t.projectRoot, "migrations")),
|
|
3151
3209
|
catch: (e) => e
|
|
3152
|
-
}), r = (yield*
|
|
3153
|
-
try: () =>
|
|
3210
|
+
}), r = (yield* x.tryPromise({
|
|
3211
|
+
try: () => Xi(n),
|
|
3154
3212
|
catch: (e) => e
|
|
3155
3213
|
})).find((e) => e.migration.id === t.id);
|
|
3156
|
-
if (!r) return yield*
|
|
3214
|
+
if (!r) return yield* x.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
3157
3215
|
yield* E(e, { schema: t.lockSchema });
|
|
3158
3216
|
let i = Date.now();
|
|
3159
3217
|
try {
|
|
3160
3218
|
let n = {
|
|
3161
3219
|
sql: e,
|
|
3162
3220
|
log: {
|
|
3163
|
-
info: (e, n) =>
|
|
3221
|
+
info: (e, n) => x.logInfo(e).pipe(x.annotateLogs({
|
|
3164
3222
|
scope: `migrations:file:${t.id}`,
|
|
3165
3223
|
...n ?? {}
|
|
3166
3224
|
})),
|
|
3167
|
-
warn: (e, n) =>
|
|
3225
|
+
warn: (e, n) => x.logWarning(e).pipe(x.annotateLogs({
|
|
3168
3226
|
scope: `migrations:file:${t.id}`,
|
|
3169
3227
|
...n ?? {}
|
|
3170
3228
|
}))
|
|
3171
3229
|
},
|
|
3172
3230
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3173
3231
|
}, a = r.migration.down(n);
|
|
3174
|
-
|
|
3232
|
+
x.isEffect(a) ? yield* a : yield* x.tryPromise({
|
|
3175
3233
|
try: () => a,
|
|
3176
3234
|
catch: (e) => e
|
|
3177
3235
|
});
|
|
@@ -3181,9 +3239,9 @@ BEGIN
|
|
|
3181
3239
|
durationMs: o
|
|
3182
3240
|
};
|
|
3183
3241
|
} finally {
|
|
3184
|
-
yield* D(e, { schema: t.lockSchema }).pipe(
|
|
3242
|
+
yield* D(e, { schema: t.lockSchema }).pipe(x.orDie);
|
|
3185
3243
|
}
|
|
3186
|
-
}),
|
|
3244
|
+
}), aa = (e) => x.gen(function* () {
|
|
3187
3245
|
let t = yield* C.SqlClient, n = yield* t`
|
|
3188
3246
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3189
3247
|
WHERE source = 'auto-diff'
|
|
@@ -3191,9 +3249,9 @@ BEGIN
|
|
|
3191
3249
|
AND appliedAt < ${e.before}
|
|
3192
3250
|
ORDER BY appliedAt DESC
|
|
3193
3251
|
`;
|
|
3194
|
-
if (n.length === 0) return yield*
|
|
3252
|
+
if (n.length === 0) return yield* x.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3195
3253
|
let r = n[0];
|
|
3196
|
-
if (r.fingerprint !== e.fingerprint) return yield*
|
|
3254
|
+
if (r.fingerprint !== e.fingerprint) return yield* x.fail(/* @__PURE__ */ Error(`squash: latest pre-squash fingerprint (${r.fingerprint.slice(0, 12)}…) differs from current declared-schema fingerprint (${e.fingerprint.slice(0, 12)}…). This means the working tree carries un-applied changes — squashing now would lock the drift in.\n\nFix: run \`voltro db apply\` first to align the live schema with the working tree, then re-squash.`));
|
|
3197
3255
|
yield* t`
|
|
3198
3256
|
UPDATE _voltro_migration_plans
|
|
3199
3257
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3228,7 +3286,7 @@ BEGIN
|
|
|
3228
3286
|
snapshotFingerprint: e.fingerprint,
|
|
3229
3287
|
snapshotId: i
|
|
3230
3288
|
};
|
|
3231
|
-
}),
|
|
3289
|
+
}), oa = { safe: !0 }, sa = (e) => {
|
|
3232
3290
|
switch (e.kind) {
|
|
3233
3291
|
case "drop-column": return {
|
|
3234
3292
|
safe: !1,
|
|
@@ -3255,7 +3313,7 @@ BEGIN
|
|
|
3255
3313
|
reason: `old instances read/write "${e.table}"."${e.column}" as ${e.from}; the new ${e.to} type can reject their writes or fail to decode their reads`,
|
|
3256
3314
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
3257
3315
|
};
|
|
3258
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3316
|
+
case "alter-column-nullability": return e.toNullable ? oa : {
|
|
3259
3317
|
safe: !1,
|
|
3260
3318
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3261
3319
|
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)`
|
|
@@ -3285,12 +3343,12 @@ BEGIN
|
|
|
3285
3343
|
case "drop-unique":
|
|
3286
3344
|
case "drop-unique-composite":
|
|
3287
3345
|
case "drop-foreign-key":
|
|
3288
|
-
case "drop-check": return
|
|
3346
|
+
case "drop-check": return oa;
|
|
3289
3347
|
}
|
|
3290
|
-
},
|
|
3348
|
+
}, ca = (e) => {
|
|
3291
3349
|
let t = [];
|
|
3292
3350
|
for (let n of e) {
|
|
3293
|
-
let e =
|
|
3351
|
+
let e = sa(n.op);
|
|
3294
3352
|
e.safe || t.push({
|
|
3295
3353
|
op: n,
|
|
3296
3354
|
reason: e.reason,
|
|
@@ -3298,7 +3356,7 @@ BEGIN
|
|
|
3298
3356
|
});
|
|
3299
3357
|
}
|
|
3300
3358
|
return t;
|
|
3301
|
-
},
|
|
3359
|
+
}, la = (e) => {
|
|
3302
3360
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3303
3361
|
refuse: !1,
|
|
3304
3362
|
warnForced: !1,
|
|
@@ -3314,18 +3372,18 @@ BEGIN
|
|
|
3314
3372
|
warnForced: !1,
|
|
3315
3373
|
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.`
|
|
3316
3374
|
};
|
|
3317
|
-
},
|
|
3375
|
+
}, ua = (e) => {
|
|
3318
3376
|
let t = e.table;
|
|
3319
3377
|
if (typeof t == "string") return t;
|
|
3320
3378
|
let n = e.from;
|
|
3321
3379
|
return typeof n == "string" ? n : void 0;
|
|
3322
|
-
},
|
|
3380
|
+
}, da = (e) => ({
|
|
3323
3381
|
kind: e.op.kind,
|
|
3324
|
-
table:
|
|
3382
|
+
table: ua(e.op),
|
|
3325
3383
|
classification: e.classification,
|
|
3326
3384
|
reason: e.reason,
|
|
3327
3385
|
blockedFix: e.blocked?.fix
|
|
3328
|
-
}),
|
|
3386
|
+
}), fa = (e) => e.operations.map(da), pa = async (e) => {
|
|
3329
3387
|
let t = e.log ?? (() => {}), n = {
|
|
3330
3388
|
branchId: e.branchId,
|
|
3331
3389
|
mechanism: e.mechanism,
|
|
@@ -3344,10 +3402,10 @@ BEGIN
|
|
|
3344
3402
|
applied: !1,
|
|
3345
3403
|
converged: !1,
|
|
3346
3404
|
residual: r,
|
|
3347
|
-
infidelity:
|
|
3405
|
+
infidelity: fa(o)
|
|
3348
3406
|
};
|
|
3349
3407
|
else {
|
|
3350
|
-
let i = await e.plan(), o =
|
|
3408
|
+
let i = await e.plan(), o = fa(i), s = o.filter((e) => e.classification === "lossy"), c = Ui(i), l = c.operations.filter((e) => e.blocked !== void 0).map(da);
|
|
3351
3409
|
if (l.length > 0) a = {
|
|
3352
3410
|
...n,
|
|
3353
3411
|
outcome: "blocked",
|
|
@@ -3372,7 +3430,7 @@ BEGIN
|
|
|
3372
3430
|
};
|
|
3373
3431
|
else {
|
|
3374
3432
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3375
|
-
let i =
|
|
3433
|
+
let i = fa(await e.replan());
|
|
3376
3434
|
a = {
|
|
3377
3435
|
...n,
|
|
3378
3436
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3410,7 +3468,7 @@ BEGIN
|
|
|
3410
3468
|
...a,
|
|
3411
3469
|
tornDown: o
|
|
3412
3470
|
};
|
|
3413
|
-
},
|
|
3471
|
+
}, ma = (e) => {
|
|
3414
3472
|
switch (e.outcome) {
|
|
3415
3473
|
case "clean": return 0;
|
|
3416
3474
|
case "lossy": return 2;
|
|
@@ -3419,22 +3477,22 @@ BEGIN
|
|
|
3419
3477
|
case "infidelity": return 1;
|
|
3420
3478
|
case "failed": return 1;
|
|
3421
3479
|
}
|
|
3422
|
-
},
|
|
3480
|
+
}, ha = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, ga = (e) => {
|
|
3423
3481
|
let t = [];
|
|
3424
3482
|
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"}`);
|
|
3425
3483
|
else if (e.outcome === "infidelity") {
|
|
3426
3484
|
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:");
|
|
3427
|
-
for (let n of e.infidelity) t.push(
|
|
3485
|
+
for (let n of e.infidelity) t.push(ha(n));
|
|
3428
3486
|
} else {
|
|
3429
3487
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3430
|
-
for (let n of e.operations) t.push(
|
|
3431
|
-
if (e.lossy.length > 0 && (t.push(""), t.push(` ⚠ ${e.lossy.length} operation(s) DESTROY DATA. They were executed on the branch (it is`), t.push(" disposable) so they are rehearsed, but production refuses them until you set"), t.push(" VOLTRO_DESTRUCTIVE_OK — naming the tables, not `1`.")), e.blocked.length > 0 && (t.push(""), t.push(` ${e.blocked.length} operation(s) the planner will not auto-apply anywhere — the plan was NOT executed.`)), e.applied && (t.push(""), t.push(e.converged ? " ✓ applied on the branch, and the re-plan is EMPTY (the migration converges)." : ` ✗ applied, but the re-plan STILL proposes ${e.residual.length} operation(s) — this migration does not converge:`), !e.converged)) for (let n of e.residual) t.push(
|
|
3488
|
+
for (let n of e.operations) t.push(ha(n));
|
|
3489
|
+
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(ha(n));
|
|
3432
3490
|
}
|
|
3433
3491
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3434
|
-
},
|
|
3492
|
+
}, _a = (e, ...t) => ({
|
|
3435
3493
|
_tag: "RawSqlFragment",
|
|
3436
3494
|
strings: [...e],
|
|
3437
3495
|
values: [...t]
|
|
3438
|
-
}),
|
|
3496
|
+
}), va = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3439
3497
|
//#endregion
|
|
3440
|
-
export { k as DEFAULT_CDC_CHANNEL,
|
|
3498
|
+
export { k as DEFAULT_CDC_CHANNEL, d as FILE_MIGRATION_PATTERN, Qi as FileMigrationLedgerError, qe as REACTIVE_TRIGGER_PREFIX, pe as VOLTRO_MIGRATION_LOCK_KEY, E as acquireMigrationLock, G as appliedAtValue, It as applyNamespacedSchema, Mi as applyPlan, Et as applySchema, la as assessRollingDeployGate, ma as branchRehearsalExitCode, Ln as chunkTables, sa as classifyRollingDeploySafety, L as declaredSnapshot, $e as defaultArrayClause, Qe as defaultClause, M as defaultJsonClause, qi as describeOutcome, Vi as destructiveScope, Jt as detectReactiveTriggerDrift, Xr as emitAddIndexMysql, jr as emitCreateTableMysql, dr as emitDropColumnDdl, fr as emitDropColumnDdlMysql, Tt as emitFrameworkBootstrapSql, Ct as emitNamespaceProvisionDdl, wt as emitNamespacedSchemaSql, St as emitSchemaSql, Xn as engineFromVersion, F as fingerprintSchema, ye as fnv1a64, ga as formatBranchRehearsal, Yt as formatReactiveTriggerDrift, Bi as ignoreTablesFromEnv, Yn as introspectSchema, tr as isAlreadySatisfied, c as isFileMigration, va as isRawSqlFragment, Ot as isReRunSafeDdl, Mn as mapPgType, g as migration, be as migrationLockKeyForSchema, T as migrationLockNameForSchema, Kr as mysqlIndexPrefixFor, Ye as notifyFunctionName, N as numericIdSql, jn as parseEnumCheck, ta as pendingFileMigrationIds, An as planMigrations, Lt as provisionTenantNamespace, Je as reactiveTriggerName, pt as reactiveTriggerRepairSql, Fi as recordUpToDate, pa as rehearseMigrationOnBranch, da as rehearsedOperation, D as releaseMigrationLock, kr as renderColumnMysql, wr as renderColumnPg, he as resolveMigrationLockSchema, W as resolveMysqlEngine, ia as rollbackFileBasedMigration, ca as rollingDeployUnsafeOps, na as runFileBasedMigrations, Rt as runFrameworkBootstrap, Ft as runMigrate, Ki as runPlannedMigrations, I as shortFingerprint, Wt as snapshotColumn, _a as sql, j as sqlType, aa as squashMigrationPlans, Ui as unblockLossy, Me as withMigrationLock };
|