@voltro/database 0.63.0 → 0.64.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 +90 -0
- package/dist/{frameworkLiveTables-X6rOAleu.js → frameworkLiveTables-BURogL9N.js} +223 -188
- package/dist/index.d.ts +225 -35
- package/dist/index.js +840 -817
- package/dist/sql.d.ts +37 -11
- package/dist/sql.js +895 -888
- package/dist/wire-B28cPjEp.js +32 -0
- package/dist/wire.d.ts +21 -0
- package/dist/wire.js +2 -5
- package/package.json +2 -2
package/dist/sql.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Effect as
|
|
3
|
-
import { createHash as
|
|
4
|
-
import { createLogger as
|
|
1
|
+
import { C as e, Jt as t, Ot as n, St as r, a as i, an as a, at as o, b as s, c, ct as l, d as u, f as d, h as f, i as p, it as m, lt as h, m as g, o as _, on as v, qt as y, rt as b, s as x, u as S, y as ee } from "./frameworkLiveTables-BURogL9N.js";
|
|
2
|
+
import { Effect as C, Schedule as w } from "effect";
|
|
3
|
+
import { createHash as te } from "node:crypto";
|
|
4
|
+
import { createLogger as ne } from "@voltro/logger";
|
|
5
5
|
import { SqlClient as T } from "@effect/sql";
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL as
|
|
6
|
+
import { promises as re } from "node:fs";
|
|
7
|
+
import { join as ie } from "node:path";
|
|
8
|
+
import { pathToFileURL as ae } from "node:url";
|
|
9
9
|
//#region src/migrations/ddlError.ts
|
|
10
|
-
var
|
|
10
|
+
var oe = (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 = se(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
|
+
}, se = (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, ce = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, le = (e) => e.replace(/"/g, "`"), ue = (e) => typeof e == "string" ? e : e.name ?? String(e), de = (e, t) => `_ua_${t}_${e}`.slice(0, 64), fe = (e, t) => {
|
|
44
|
+
if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(ce)) return e;
|
|
45
45
|
let n = { ...e.fields }, r = [], i = [];
|
|
46
46
|
for (let t of e.appliedIndexes) {
|
|
47
|
-
if (!
|
|
47
|
+
if (!ce(t)) {
|
|
48
48
|
r.push(t);
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
51
|
-
let a =
|
|
51
|
+
let a = le(t.where), o = [];
|
|
52
52
|
for (let r of t.fields) {
|
|
53
|
-
let i =
|
|
53
|
+
let i = ue(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 = de(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
|
-
}, E = (e, t) => `${e}::${t}`,
|
|
78
|
+
}, E = (e, t) => `${e}::${t}`, pe = (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
|
+
}, me = 6322741009312437n, he = (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
|
+
}, ge = (e) => e?.schema === void 0 ? he(process.env.DB_SCHEMA) : he(e.schema), _e = 14695981039346656037n, ve = 1099511628211n, ye = 18446744073709551615n, be = (e) => {
|
|
91
|
+
let t = _e;
|
|
92
|
+
for (let n of new TextEncoder().encode(e)) t ^= BigInt(n), t = t * ve & ye;
|
|
93
93
|
return t;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
return t === void 0 ?
|
|
97
|
-
},
|
|
98
|
-
let t = `voltro_migration_${
|
|
94
|
+
}, xe = (e) => {
|
|
95
|
+
let t = he(e);
|
|
96
|
+
return t === void 0 ? me : be(`voltro_migration_lock:${t}`) & 9223372036854775807n;
|
|
97
|
+
}, Se = (e) => {
|
|
98
|
+
let t = `voltro_migration_${me.toString(36)}`, n = he(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${(be(`voltro_migration_lock:${n}`) & ye).toString(16)}`;
|
|
102
|
+
}, Ce = 250, we = () => {
|
|
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
|
+
}, Te = (e, t) => C.gen(function* () {
|
|
106
|
+
let n = we(), 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* C.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* C.sleep(`${Ce} millis`);
|
|
111
111
|
}
|
|
112
|
-
}),
|
|
112
|
+
}), Ee = (e, t) => C.gen(function* () {
|
|
113
113
|
yield* e`SELECT pg_advisory_unlock(${t.toString()}::bigint)`;
|
|
114
|
-
}),
|
|
114
|
+
}), De = 30, Oe = (e, t) => C.gen(function* () {
|
|
115
115
|
(yield* e`
|
|
116
|
-
SELECT GET_LOCK(${t}, ${
|
|
117
|
-
}),
|
|
116
|
+
SELECT GET_LOCK(${t}, ${De}) AS got`)[0]?.got !== 1 && (yield* C.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' within ${De}s (another migration is in progress, or a prior one left it held).`)));
|
|
117
|
+
}), ke = (e, t) => C.gen(function* () {
|
|
118
118
|
yield* e`SELECT RELEASE_LOCK(${t})`;
|
|
119
|
-
}),
|
|
119
|
+
}), Ae = 3e4, je = (e, t) => C.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 = ${Ae};
|
|
124
124
|
SELECT @res AS res`;
|
|
125
|
-
(n[0]?.res ?? -999) < 0 && (yield*
|
|
126
|
-
}),
|
|
125
|
+
(n[0]?.res ?? -999) < 0 && (yield* C.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${t}' (sp_getapplock returned ${n[0]?.res ?? "no row"}; another migration is in progress).`)));
|
|
126
|
+
}), Me = (e, t) => C.gen(function* () {
|
|
127
127
|
yield* e`EXEC sp_releaseapplock @Resource = ${t}, @LockOwner = 'Session'`;
|
|
128
|
-
}),
|
|
129
|
-
let n =
|
|
128
|
+
}), Ne = C.void, Pe = (e, t) => {
|
|
129
|
+
let n = ge(t);
|
|
130
130
|
return e.onDialectOrElse({
|
|
131
|
-
mysql: () =>
|
|
132
|
-
mssql: () =>
|
|
133
|
-
sqlite: () =>
|
|
134
|
-
orElse: () =>
|
|
131
|
+
mysql: () => Oe(e, Se(n)),
|
|
132
|
+
mssql: () => je(e, Se(n)),
|
|
133
|
+
sqlite: () => Ne,
|
|
134
|
+
orElse: () => Te(e, xe(n))
|
|
135
135
|
});
|
|
136
|
-
},
|
|
137
|
-
let n =
|
|
136
|
+
}, D = (e, t) => {
|
|
137
|
+
let n = ge(t);
|
|
138
138
|
return e.onDialectOrElse({
|
|
139
|
-
mysql: () =>
|
|
140
|
-
mssql: () =>
|
|
141
|
-
sqlite: () =>
|
|
142
|
-
orElse: () =>
|
|
139
|
+
mysql: () => ke(e, Se(n)),
|
|
140
|
+
mssql: () => Me(e, Se(n)),
|
|
141
|
+
sqlite: () => Ne,
|
|
142
|
+
orElse: () => Ee(e, xe(n))
|
|
143
143
|
});
|
|
144
|
-
},
|
|
144
|
+
}, Fe = (e, t, n) => C.acquireUseRelease(Pe(e, n), () => t, () => D(e, n).pipe(C.orDie)), Ie = (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
|
+
}), Le = {
|
|
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
|
+
}, Re = (e) => Le[e], O = "_voltro_migration_ops", ze = l(O, {
|
|
158
|
+
id: y({ prefix: "mop" }),
|
|
159
|
+
runId: a(),
|
|
160
|
+
planFingerprint: a(),
|
|
161
|
+
opIndex: t(),
|
|
162
|
+
opKind: a(),
|
|
163
|
+
opTarget: a(),
|
|
164
|
+
status: a(),
|
|
165
|
+
payload: a(),
|
|
166
|
+
startedAt: v().nullable(),
|
|
167
|
+
appliedAt: v().nullable(),
|
|
168
|
+
durationMs: t().nullable(),
|
|
169
|
+
createdAt: v().default("now")
|
|
170
|
+
}), Be = (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
|
+
}, Ve = (e) => [...Be(e)].join(" "), He = (e, t) => {
|
|
198
|
+
let n = Be(t);
|
|
199
|
+
for (let t of Be(e)) if (n.has(t)) return !0;
|
|
200
200
|
return !1;
|
|
201
|
-
},
|
|
201
|
+
}, Ue = (e, t) => e.operations.some((e) => He(e.op, t)), We = "__voltro_rebuild", Ge = "__shadow", Ke = "__old", qe = /* @__PURE__ */ new Set([
|
|
202
202
|
"add-unique",
|
|
203
203
|
"drop-unique",
|
|
204
204
|
"add-unique-composite",
|
|
@@ -210,21 +210,21 @@ var ie = (e, t, n, r = 400) => {
|
|
|
210
210
|
"alter-column-nullability",
|
|
211
211
|
"alter-column-type",
|
|
212
212
|
"alter-column-default"
|
|
213
|
-
]),
|
|
213
|
+
]), Je = /* @__PURE__ */ new Set(["alter-column-default", "alter-column-nullability"]), Ye = (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 && qe.has(e.kind) ? "artefact-repair" : Je.has(e.kind) ? "idempotent" : "probe-then-replay";
|
|
216
216
|
};
|
|
217
|
-
Object.keys(
|
|
217
|
+
Object.keys(Le);
|
|
218
218
|
//#endregion
|
|
219
219
|
//#region src/migrations/reactiveTriggerName.ts
|
|
220
|
-
var
|
|
220
|
+
var k = "framework_changes", Xe = "framework_changes_", Ze = (e, t) => t === "framework_changes" ? `${Xe}${e}` : `${Xe}${t}_${e}`, Qe = (e) => e === "framework_changes" ? "framework_notify_change" : `framework_notify_change_${e}`, $e = "voltro:notify:v2", et = (e, t) => {
|
|
221
221
|
if (e.type === "text" && e.generatedAs === void 0) {
|
|
222
222
|
if (e.maxLength !== void 0) return e.maxLength;
|
|
223
223
|
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
224
224
|
}
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
},
|
|
225
|
+
}, tt = ne({ scope: "voltro:migrate" }), A = (e) => {
|
|
226
|
+
tt.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
227
|
+
}, j = (e, t) => {
|
|
228
228
|
let n = e.type;
|
|
229
229
|
if (e.spatial) {
|
|
230
230
|
if (t === "postgres") return `${e.spatial.kind}(${e.spatial.geomKind},${e.spatial.srid})`;
|
|
@@ -235,14 +235,14 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
235
235
|
return e.rawDdl;
|
|
236
236
|
}
|
|
237
237
|
if (n === "array" && e.arrayElement) {
|
|
238
|
-
if (t === "postgres") return `${
|
|
238
|
+
if (t === "postgres") return `${j({
|
|
239
239
|
...e,
|
|
240
240
|
type: e.arrayElement,
|
|
241
241
|
arrayElement: void 0
|
|
242
242
|
}, t)}[]`;
|
|
243
243
|
if (t === "mysql" || t === "mariadb") return "JSON";
|
|
244
244
|
if (t === "mssql") return "NVARCHAR(MAX)";
|
|
245
|
-
if (
|
|
245
|
+
if (m(t)) return "TEXT";
|
|
246
246
|
}
|
|
247
247
|
if (n === "vector") {
|
|
248
248
|
let n = e.vectorDim;
|
|
@@ -251,27 +251,27 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
251
251
|
if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
|
|
252
252
|
if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
|
|
253
253
|
if (t === "mssql") return "VARBINARY(MAX)";
|
|
254
|
-
if (
|
|
254
|
+
if (m(t)) return "BLOB";
|
|
255
255
|
}
|
|
256
256
|
if (n === "interval") {
|
|
257
257
|
if (t === "postgres") return "INTERVAL";
|
|
258
258
|
if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
|
|
259
|
-
if (
|
|
259
|
+
if (m(t)) return "INTEGER";
|
|
260
260
|
}
|
|
261
261
|
if (n === "decimal") {
|
|
262
262
|
let n = e.precision, r = e.scale ?? 0;
|
|
263
263
|
if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
|
|
264
|
-
return
|
|
264
|
+
return m(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
|
|
265
265
|
}
|
|
266
|
-
if (n === "bigint") return
|
|
266
|
+
if (n === "bigint") return m(t) ? "INTEGER" : "BIGINT";
|
|
267
267
|
if (n === "enum") {
|
|
268
268
|
if (t === "postgres") return e.enumName ?? "TEXT";
|
|
269
269
|
if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
|
|
270
270
|
if (t === "mssql") return "NVARCHAR(255)";
|
|
271
|
-
if (
|
|
271
|
+
if (m(t)) return "TEXT";
|
|
272
272
|
}
|
|
273
|
-
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` :
|
|
274
|
-
if (
|
|
273
|
+
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` : m(t) ? "TEXT" : `VARCHAR(${e.maxLength})`;
|
|
274
|
+
if (m(t)) switch (n) {
|
|
275
275
|
case "id": return "TEXT";
|
|
276
276
|
case "text": return "TEXT";
|
|
277
277
|
case "integer": return "INTEGER";
|
|
@@ -306,7 +306,7 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
306
306
|
if (t === "mssql") switch (n) {
|
|
307
307
|
case "id": return "NVARCHAR(64)";
|
|
308
308
|
case "text": {
|
|
309
|
-
let t =
|
|
309
|
+
let t = et(e, !1);
|
|
310
310
|
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
311
311
|
}
|
|
312
312
|
case "integer": return "INT";
|
|
@@ -338,22 +338,22 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
338
338
|
case "array": return "TEXT[]";
|
|
339
339
|
case "interval": return "INTERVAL";
|
|
340
340
|
}
|
|
341
|
-
},
|
|
341
|
+
}, nt = (e, t) => {
|
|
342
342
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
343
343
|
let n = e.defaultValue;
|
|
344
|
-
return n === "now" ?
|
|
345
|
-
},
|
|
346
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
347
|
-
let r =
|
|
344
|
+
return n === "now" ? m(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) ? rt(n, e, t) : typeof n == "object" && n ? M(n, t) : null;
|
|
345
|
+
}, rt = (e, t, n) => {
|
|
346
|
+
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return M(e, n);
|
|
347
|
+
let r = j({
|
|
348
348
|
...t,
|
|
349
349
|
type: t.arrayElement,
|
|
350
350
|
arrayElement: void 0
|
|
351
351
|
}, n);
|
|
352
352
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
353
|
-
},
|
|
353
|
+
}, M = (e, t) => {
|
|
354
354
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
355
355
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
356
|
-
},
|
|
356
|
+
}, N = (e, t) => {
|
|
357
357
|
switch (t) {
|
|
358
358
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
359
359
|
case "mysql":
|
|
@@ -362,7 +362,7 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
362
362
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
363
363
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
364
364
|
}
|
|
365
|
-
},
|
|
365
|
+
}, P = (e, t) => {
|
|
366
366
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
367
367
|
switch (e) {
|
|
368
368
|
case "cascade": return "CASCADE";
|
|
@@ -370,118 +370,118 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
370
370
|
case "setNull": return "SET NULL";
|
|
371
371
|
case "noAction": return "NO ACTION";
|
|
372
372
|
}
|
|
373
|
-
},
|
|
373
|
+
}, it = (e, t, n) => n === null ? o(e, t) : `${o(n, t)}.${o(e, t)}`, at = 191, ot = (e, t) => {
|
|
374
374
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
375
|
-
let n =
|
|
375
|
+
let n = j(e, t).toUpperCase();
|
|
376
376
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
377
|
-
},
|
|
378
|
-
let r =
|
|
377
|
+
}, st = (e, t, n) => {
|
|
378
|
+
let r = o(e, n);
|
|
379
379
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
380
380
|
let i = t[e];
|
|
381
381
|
if (!i) return r;
|
|
382
|
-
let a =
|
|
383
|
-
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${
|
|
384
|
-
},
|
|
382
|
+
let a = j(i, n).toUpperCase();
|
|
383
|
+
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${at})` : r;
|
|
384
|
+
}, ct = (e, t) => {
|
|
385
385
|
if (!e.generatedAs) return null;
|
|
386
386
|
let { expr: n, stored: r } = e.generatedAs;
|
|
387
|
-
if (t === "postgres") return r ||
|
|
387
|
+
if (t === "postgres") return r || A("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
|
|
388
388
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
389
389
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
390
390
|
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.");
|
|
391
391
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
392
|
-
},
|
|
393
|
-
if (
|
|
394
|
-
let s =
|
|
395
|
-
|
|
396
|
-
let
|
|
397
|
-
if (
|
|
392
|
+
}, lt = (e, t, n, r, i = !1, a = !1) => {
|
|
393
|
+
if (t.type === "id" && t.idScheme?.kind === "numeric") return N(e, n);
|
|
394
|
+
let s = n === "mssql" ? et(t, r?.has(e) ?? !1) : void 0, c = s === void 0 ? j(t, n) : `NVARCHAR(${s})`, l = [o(e, n), c];
|
|
395
|
+
t.type === "id" && !a && l.push("PRIMARY KEY");
|
|
396
|
+
let u = ct(t, n);
|
|
397
|
+
if (u) l.push(u);
|
|
398
398
|
else {
|
|
399
|
-
|
|
400
|
-
let e =
|
|
401
|
-
e &&
|
|
402
|
-
}
|
|
403
|
-
if (
|
|
404
|
-
let e =
|
|
405
|
-
|
|
406
|
-
let
|
|
407
|
-
|
|
408
|
-
let i =
|
|
409
|
-
i !== "NO ACTION" &&
|
|
410
|
-
}
|
|
411
|
-
if (
|
|
412
|
-
let
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
if (
|
|
416
|
-
if (
|
|
417
|
-
let
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
if (
|
|
421
|
-
let
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
return
|
|
425
|
-
},
|
|
426
|
-
let
|
|
427
|
-
for (let
|
|
428
|
-
for (let
|
|
429
|
-
for (let [
|
|
430
|
-
let
|
|
431
|
-
let r =
|
|
432
|
-
return ` CONSTRAINT ${
|
|
433
|
-
}), u = (
|
|
434
|
-
if (a.type !== "reference" || !a.references || (
|
|
435
|
-
let
|
|
436
|
-
return [` CONSTRAINT ${
|
|
399
|
+
t.nullable || l.push("NOT NULL"), t.unique && t.type !== "id" && !ot(t, n) && l.push("UNIQUE");
|
|
400
|
+
let e = nt(t, n);
|
|
401
|
+
e && l.push(e);
|
|
402
|
+
}
|
|
403
|
+
if (t.type === "reference" && t.references && !i && !b(n)) {
|
|
404
|
+
let e = t.references();
|
|
405
|
+
l.push(`REFERENCES ${o(e.tableName, n)} (${o("id", n)})`);
|
|
406
|
+
let r = P(t.onDelete ?? "restrict", n);
|
|
407
|
+
l.push(`ON DELETE ${r}`);
|
|
408
|
+
let i = P(t.refOnUpdate ?? "noAction", n);
|
|
409
|
+
i !== "NO ACTION" && l.push(`ON UPDATE ${i}`);
|
|
410
|
+
}
|
|
411
|
+
if (t.oneOf && t.oneOf.length > 0) {
|
|
412
|
+
let r = t.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
413
|
+
l.push(`CHECK (${o(e, n)} IN (${r}))`);
|
|
414
|
+
}
|
|
415
|
+
if (t.checks && t.checks.length > 0) for (let e of t.checks) l.push(`CHECK (${e})`);
|
|
416
|
+
if (t.type === "enum" && t.enumValues && t.enumValues.length > 0 && (n === "mssql" || m(n))) {
|
|
417
|
+
let r = t.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
418
|
+
l.push(`CHECK (${o(e, n)} IN (${r}))`);
|
|
419
|
+
}
|
|
420
|
+
if (t.type === "json" || t.type === "array") {
|
|
421
|
+
let t = o(e, n);
|
|
422
|
+
m(n) ? l.push(`CHECK (${t} IS NULL OR json_valid(${t}))`) : n === "mssql" && l.push(`CHECK (${t} IS NULL OR ISJSON(${t}) = 1)`);
|
|
423
|
+
}
|
|
424
|
+
return l.join(" ");
|
|
425
|
+
}, ut = (e, t, n = null, r) => {
|
|
426
|
+
let i = /* @__PURE__ */ new Set();
|
|
427
|
+
for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
428
|
+
for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && i.add(e);
|
|
429
|
+
for (let [t, n] of Object.entries(e.fields)) n.unique && i.add(t);
|
|
430
|
+
let a = e.appliedPrimaryKey ?? [], s = a.length > 0, c = Object.entries(e.fields).map(([e, n]) => ` ${lt(e, n, t, i, r?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((n) => {
|
|
431
|
+
let r = n.fields.map((n) => st(n, e.fields, t)).join(", ");
|
|
432
|
+
return ` CONSTRAINT ${o(n.name, t)} UNIQUE (${r})`;
|
|
433
|
+
}), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${o(e.name, t)} CHECK (${e.expr})`), d = s ? [` PRIMARY KEY (${a.map((n) => st(n, e.fields, t)).join(", ")})`] : [], f = b(t) ? Object.entries(e.fields).flatMap(([i, a]) => {
|
|
434
|
+
if (a.type !== "reference" || !a.references || (r?.has(i) ?? !1)) return [];
|
|
435
|
+
let s = a.references(), c = P(a.onDelete ?? "restrict", t), l = P(a.refOnUpdate ?? "noAction", t);
|
|
436
|
+
return [` CONSTRAINT ${o(`${e.tableName}_${i}_fkey`, t)} FOREIGN KEY (${o(i, t)}) REFERENCES ${it(s.tableName, t, n)} (${o("id", t)}) ON DELETE ${c}${l === "NO ACTION" ? "" : ` ON UPDATE ${l}`}`];
|
|
437
437
|
}) : [], p = [
|
|
438
438
|
...d,
|
|
439
439
|
...l,
|
|
440
440
|
...u,
|
|
441
441
|
...f
|
|
442
|
-
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h =
|
|
443
|
-
if (
|
|
444
|
-
let
|
|
445
|
-
return `IF OBJECT_ID('${
|
|
442
|
+
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h = it(e.tableName, t, n);
|
|
443
|
+
if (t === "mssql") {
|
|
444
|
+
let t = n === null ? e.tableName : `${n}.${e.tableName}`, r = `CREATE TABLE ${h} (\n${m}\n)`;
|
|
445
|
+
return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${r.replace(/'/g, "''")}');`;
|
|
446
446
|
}
|
|
447
447
|
return [
|
|
448
448
|
`CREATE TABLE IF NOT EXISTS ${h} (`,
|
|
449
449
|
m,
|
|
450
450
|
");"
|
|
451
451
|
].join("\n");
|
|
452
|
-
},
|
|
453
|
-
let r = `${e}_${t.name}_fts`, i = (e) =>
|
|
454
|
-
return
|
|
455
|
-
},
|
|
456
|
-
let r = [], i = /* @__PURE__ */ new Set(),
|
|
457
|
-
let
|
|
452
|
+
}, dt = (e, t, n) => {
|
|
453
|
+
let r = `${e}_${t.name}_fts`, i = (e) => o(e, n), a = t.columns.map(i).join(", "), s = t.columns.map((e) => `new.${i(e)}`).join(", "), c = [];
|
|
454
|
+
return c.push(`CREATE VIRTUAL TABLE IF NOT EXISTS ${i(r)} USING fts5(${a}, row_id UNINDEXED, tokenize='porter');`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ai`)} AFTER INSERT ON ${i(e)} BEGIN\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${s}, new.${i("id")});\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_ad`)} AFTER DELETE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\nEND;`), c.push(`CREATE TRIGGER IF NOT EXISTS ${i(`${r}_au`)} AFTER UPDATE ON ${i(e)} BEGIN\n DELETE FROM ${i(r)} WHERE row_id = old.${i("id")};\n INSERT INTO ${i(r)} (${a}, row_id) VALUES (${s}, new.${i("id")});\nEND;`), c;
|
|
455
|
+
}, ft = (e, t, n = null) => {
|
|
456
|
+
let r = [], i = /* @__PURE__ */ new Set(), a = (e) => e.join("\0"), s = (e, n, r, i) => {
|
|
457
|
+
let a = {
|
|
458
458
|
using: "",
|
|
459
459
|
withSuffix: "",
|
|
460
460
|
skip: !1
|
|
461
461
|
};
|
|
462
|
-
if (r === void 0 || r === "btree") return
|
|
462
|
+
if (r === void 0 || r === "btree") return a;
|
|
463
463
|
if (r === "gist") return t === "postgres" ? {
|
|
464
464
|
using: " USING GIST",
|
|
465
465
|
withSuffix: "",
|
|
466
466
|
skip: !1
|
|
467
|
-
} : (
|
|
467
|
+
} : (A(`[voltro:migrate] index '${e}' on '${n}': ${t} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), a);
|
|
468
468
|
if (r === "gin") return t === "postgres" ? {
|
|
469
469
|
using: " USING GIN",
|
|
470
470
|
withSuffix: "",
|
|
471
471
|
skip: !1
|
|
472
|
-
} : t === "mysql" || t === "mariadb" ? (
|
|
472
|
+
} : t === "mysql" || t === "mariadb" ? (A(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — skipping (a btree on a JSON/array column can't serve containment/membership queries). Add a generated column for the specific path you query, then index that with .expressionIndex(...).`), {
|
|
473
473
|
using: "",
|
|
474
474
|
withSuffix: "",
|
|
475
475
|
skip: !0
|
|
476
|
-
}) : (
|
|
476
|
+
}) : (A(`[voltro:migrate] gin index '${e}' on '${n}': ${t} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), a);
|
|
477
477
|
if (r === "brin") return t === "postgres" ? {
|
|
478
478
|
using: " USING BRIN",
|
|
479
479
|
withSuffix: "",
|
|
480
480
|
skip: !1
|
|
481
|
-
} : (
|
|
481
|
+
} : (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);
|
|
482
482
|
if (r === "hnsw") {
|
|
483
483
|
if (t === "postgres") {
|
|
484
|
-
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ??
|
|
484
|
+
let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? h(i?.hnsw?.distance);
|
|
485
485
|
return {
|
|
486
486
|
using: " USING hnsw",
|
|
487
487
|
withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
|
|
@@ -489,73 +489,73 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
489
489
|
skip: !1
|
|
490
490
|
};
|
|
491
491
|
}
|
|
492
|
-
return
|
|
492
|
+
return A(`[voltro:migrate] hnsw index '${e}' on '${n}': ${t} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
|
|
493
493
|
using: "",
|
|
494
494
|
withSuffix: "",
|
|
495
495
|
skip: !0
|
|
496
496
|
};
|
|
497
497
|
}
|
|
498
|
-
return
|
|
498
|
+
return a;
|
|
499
499
|
}, c = (n, r) => {
|
|
500
500
|
let i = n.map((n) => {
|
|
501
|
-
if (typeof n == "string") return
|
|
501
|
+
if (typeof n == "string") return st(n, e.fields, t);
|
|
502
502
|
if ("jsonPath" in n) {
|
|
503
503
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
504
|
-
return `(${
|
|
504
|
+
return `(${ee(e, r, t, { numeric: i })})`;
|
|
505
505
|
}
|
|
506
506
|
return `(${n.expr})`;
|
|
507
507
|
});
|
|
508
508
|
return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
|
|
509
|
-
}, l = (e, r, i, a,
|
|
510
|
-
let
|
|
511
|
-
if (
|
|
512
|
-
let
|
|
513
|
-
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${
|
|
509
|
+
}, l = (e, r, i, a, l, u = "", d = !1) => {
|
|
510
|
+
let f = s(e, r, a, l);
|
|
511
|
+
if (f.skip) return "";
|
|
512
|
+
let p = c(i, f.opclass), m = `${f.withSuffix}${u}`, h = it(r, t, n), g = d ? "UNIQUE " : "";
|
|
513
|
+
return t === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${o(e, t)} ON ${h}${f.using} (${p})${m};` : t === "mysql" ? `CREATE ${g}INDEX ${o(e, t)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${o(e, t)} ON ${h}${f.using} (${p})${m};`;
|
|
514
514
|
};
|
|
515
515
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
516
|
-
if (!i.unique || i.type === "id" || !
|
|
516
|
+
if (!i.unique || i.type === "id" || !ot(i, t)) continue;
|
|
517
517
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
518
518
|
a && r.push(a);
|
|
519
519
|
}
|
|
520
520
|
for (let n of e.appliedFullText ?? []) if (t === "postgres") {
|
|
521
|
-
let i = n.config ?? "english", a = `${n.name}_tsv`,
|
|
521
|
+
let i = n.config ?? "english", a = `${n.name}_tsv`, s = n.columns.map((e) => {
|
|
522
522
|
let r = n.weights?.[e] ?? "A";
|
|
523
|
-
return `setweight(to_tsvector('${i}', coalesce(${
|
|
523
|
+
return `setweight(to_tsvector('${i}', coalesce(${o(e, t)}, '')), '${r}')`;
|
|
524
524
|
}).join(" || ");
|
|
525
|
-
r.push(`ALTER TABLE ${
|
|
525
|
+
r.push(`ALTER TABLE ${o(e.tableName, t)} ADD COLUMN IF NOT EXISTS ${o(a, t)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), r.push(`CREATE INDEX IF NOT EXISTS ${o(n.name, t)} ON ${o(e.tableName, t)} USING GIN (${o(a, t)});`);
|
|
526
526
|
} else if (t === "mysql" || t === "mariadb") {
|
|
527
|
-
let i = n.columns.map((e) =>
|
|
528
|
-
r.push(`CREATE FULLTEXT INDEX ${
|
|
527
|
+
let i = n.columns.map((e) => o(e, t)).join(", ");
|
|
528
|
+
r.push(`CREATE FULLTEXT INDEX ${o(n.name, t)} ON ${o(e.tableName, t)} (${i});`);
|
|
529
529
|
} else if (t === "turso") throw Error(`@voltro/sql-turso: full-text index '${n.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
|
|
530
|
-
else t === "sqlite" ? r.push(...
|
|
530
|
+
else t === "sqlite" ? r.push(...dt(e.tableName, n, t)) : A(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${t} uses a ranked LIKE search at query time (no native FTS catalog required).`);
|
|
531
531
|
for (let n of e.appliedIndexes) {
|
|
532
532
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
533
|
-
|
|
533
|
+
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(...).`);
|
|
534
534
|
continue;
|
|
535
535
|
}
|
|
536
536
|
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.`);
|
|
537
|
-
let
|
|
538
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ?
|
|
539
|
-
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions,
|
|
540
|
-
s !== "" && r.push(s), n.fields.every((e) => typeof e == "string") && i.add(
|
|
537
|
+
let o = "";
|
|
538
|
+
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`) : o = ` WHERE ${n.where}`);
|
|
539
|
+
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions, o, n.unique === !0);
|
|
540
|
+
s !== "" && r.push(s), n.fields.every((e) => typeof e == "string") && i.add(a(n.fields));
|
|
541
541
|
}
|
|
542
542
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
543
|
-
if (n.type !== "reference" || n.fkAutoIndex === !1 || i.has(
|
|
544
|
-
let
|
|
545
|
-
r.push(l(
|
|
543
|
+
if (n.type !== "reference" || n.fkAutoIndex === !1 || i.has(a([t]))) continue;
|
|
544
|
+
let o = `${e.tableName}_${t}_idx`;
|
|
545
|
+
r.push(l(o, e.tableName, [t])), i.add(a([t]));
|
|
546
546
|
}
|
|
547
547
|
return r.join("\n");
|
|
548
|
-
},
|
|
548
|
+
}, pt = (e, t, n = k) => {
|
|
549
549
|
if (t !== "postgres") return [];
|
|
550
550
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
551
|
-
return r.length === 0 ? [] : [
|
|
552
|
-
},
|
|
553
|
-
CREATE OR REPLACE FUNCTION ${
|
|
551
|
+
return r.length === 0 ? [] : [mt(n), ...r.map((e) => gt(e, n))];
|
|
552
|
+
}, mt = (e) => `
|
|
553
|
+
CREATE OR REPLACE FUNCTION ${Qe(e)}() RETURNS trigger AS $$
|
|
554
554
|
DECLARE
|
|
555
555
|
payload TEXT;
|
|
556
556
|
pk JSONB;
|
|
557
557
|
BEGIN
|
|
558
|
-
-- ${
|
|
558
|
+
-- ${$e}
|
|
559
559
|
payload := json_build_object(
|
|
560
560
|
'table', TG_TABLE_NAME,
|
|
561
561
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -609,22 +609,22 @@ BEGIN
|
|
|
609
609
|
RETURN COALESCE(NEW, OLD);
|
|
610
610
|
END;
|
|
611
611
|
$$ LANGUAGE plpgsql;
|
|
612
|
-
`.trim(),
|
|
613
|
-
let n =
|
|
612
|
+
`.trim(), ht = (e, t) => {
|
|
613
|
+
let n = Ze(e.tableName, t);
|
|
614
614
|
return [
|
|
615
615
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
616
616
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
617
|
-
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${
|
|
617
|
+
`CREATE TRIGGER ${n}\nAFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"\nFOR EACH ROW EXECUTE FUNCTION ${Qe(t)}()`
|
|
618
618
|
];
|
|
619
|
-
},
|
|
619
|
+
}, gt = (e, t) => ht(e, t).map((e) => `${e};`).join("\n"), _t = (e) => {
|
|
620
620
|
if (e.dialect !== "postgres") return [];
|
|
621
621
|
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));
|
|
622
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
623
|
-
for (let e of i) r.push(...
|
|
624
|
-
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${
|
|
622
|
+
(i.length > 0 || e.functionOutdated === !0) && r.push(mt(t));
|
|
623
|
+
for (let e of i) r.push(...ht(n.get(e), t));
|
|
624
|
+
for (let n of e.stale) r.push(`DROP TRIGGER IF EXISTS ${Ze(n, t)} ON "${n}"`), r.push(`ALTER TABLE "${n}" REPLICA IDENTITY DEFAULT`);
|
|
625
625
|
return r;
|
|
626
|
-
},
|
|
627
|
-
let t = new Map(e.map((e) => [e.tableName, e])), n =
|
|
626
|
+
}, vt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), yt = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), bt = (e) => {
|
|
627
|
+
let t = new Map(e.map((e) => [e.tableName, e])), n = pe(e.map((e) => e.tableName), (e) => {
|
|
628
628
|
let n = t.get(e);
|
|
629
629
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
630
630
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -660,30 +660,30 @@ $$ LANGUAGE plpgsql;
|
|
|
660
660
|
sorted: o,
|
|
661
661
|
cyclic: r
|
|
662
662
|
};
|
|
663
|
-
},
|
|
664
|
-
let r = (e) => n ? `${
|
|
663
|
+
}, xt = (e, t, n = null) => {
|
|
664
|
+
let r = (e) => n ? `${o(n, t)}.${o(e, t)}` : o(e, t), i = `${e.table}_${e.column}_fkey`, a = P(e.onDelete, t), s = P(e.onUpdate, t), c = ` ON DELETE ${a}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (n) => `ADD CONSTRAINT ${o(i, t)} FOREIGN KEY ${n ? "IF NOT EXISTS " : ""}(${o(e.column, t)}) REFERENCES ${r(e.targetTable)} (${o("id", t)})${c}`;
|
|
665
665
|
switch (t) {
|
|
666
666
|
case "postgres": return [
|
|
667
667
|
"DO $$ BEGIN",
|
|
668
668
|
" IF NOT EXISTS (SELECT 1 FROM pg_constraint",
|
|
669
669
|
` WHERE conname = '${i}' AND conrelid = '${n ? `${n}.` : ""}${e.table}'::regclass) THEN`,
|
|
670
|
-
` ALTER TABLE ${r(e.table)} ${
|
|
670
|
+
` ALTER TABLE ${r(e.table)} ${l(!1)};`,
|
|
671
671
|
" END IF;",
|
|
672
672
|
"END $$;"
|
|
673
673
|
].join("\n");
|
|
674
|
-
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${i}') ALTER TABLE ${r(e.table)} ${
|
|
675
|
-
case "mariadb": return `ALTER TABLE ${r(e.table)} ${
|
|
676
|
-
default: return `ALTER TABLE ${r(e.table)} ${
|
|
674
|
+
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${i}') ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
675
|
+
case "mariadb": return `ALTER TABLE ${r(e.table)} ${l(!0)};`;
|
|
676
|
+
default: return `ALTER TABLE ${r(e.table)} ${l(!1)};`;
|
|
677
677
|
}
|
|
678
|
-
},
|
|
678
|
+
}, St = (e, t) => {
|
|
679
679
|
let n = /* @__PURE__ */ new Map();
|
|
680
|
-
if (
|
|
680
|
+
if (m(t)) return n;
|
|
681
681
|
for (let t of e) {
|
|
682
682
|
let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
|
|
683
683
|
e.add(t.column), n.set(t.table, e);
|
|
684
684
|
}
|
|
685
685
|
return n;
|
|
686
|
-
},
|
|
686
|
+
}, Ct = (e, t) => {
|
|
687
687
|
if (t !== "postgres") return "";
|
|
688
688
|
let n = /* @__PURE__ */ new Map();
|
|
689
689
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -699,45 +699,45 @@ $$ LANGUAGE plpgsql;
|
|
|
699
699
|
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 $$;`);
|
|
700
700
|
}
|
|
701
701
|
return r.join("\n\n");
|
|
702
|
-
},
|
|
702
|
+
}, wt = (e, t) => {
|
|
703
703
|
if (t !== "postgres") return "";
|
|
704
|
-
let
|
|
705
|
-
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName &&
|
|
706
|
-
let
|
|
707
|
-
for (let e of
|
|
708
|
-
let
|
|
709
|
-
|
|
704
|
+
let r = /* @__PURE__ */ new Set();
|
|
705
|
+
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && r.add(e.enumName);
|
|
706
|
+
let i = [];
|
|
707
|
+
for (let e of r) for (let { from: t, to: r } of n(e)) {
|
|
708
|
+
let n = e.replace(/'/g, "''"), a = t.replace(/'/g, "''"), o = r.replace(/'/g, "''");
|
|
709
|
+
i.push(`DO \$\$
|
|
710
710
|
DECLARE
|
|
711
711
|
type_oid oid;
|
|
712
712
|
BEGIN
|
|
713
|
-
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${
|
|
713
|
+
SELECT oid INTO type_oid FROM pg_type WHERE typname = '${n}';\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', '${n}', '${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 $$;`);
|
|
714
714
|
}
|
|
715
|
-
return
|
|
716
|
-
},
|
|
715
|
+
return i.join("\n\n");
|
|
716
|
+
}, Tt = (e) => {
|
|
717
717
|
let t = [], n = [];
|
|
718
|
-
for (let r of e)
|
|
718
|
+
for (let r of e) s(r) ? n.push(r) : t.push(r);
|
|
719
719
|
return {
|
|
720
720
|
tables: t,
|
|
721
721
|
views: n
|
|
722
722
|
};
|
|
723
|
-
},
|
|
724
|
-
let { tables:
|
|
725
|
-
|
|
726
|
-
let u =
|
|
727
|
-
u &&
|
|
728
|
-
let d =
|
|
729
|
-
d &&
|
|
730
|
-
for (let e of
|
|
731
|
-
if (!
|
|
732
|
-
for (let e of
|
|
733
|
-
let
|
|
734
|
-
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
for (let
|
|
738
|
-
return
|
|
739
|
-
},
|
|
740
|
-
let r =
|
|
723
|
+
}, Et = (t, n, r = k) => {
|
|
724
|
+
let { tables: i, views: a } = Tt(t), { sorted: o, cyclic: s } = bt(i.map((e) => fe(e, n))), c = St(s, n), l = [];
|
|
725
|
+
n === "postgres" && vt(o) && l.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && yt(o) && l.push("CREATE EXTENSION IF NOT EXISTS postgis;");
|
|
726
|
+
let u = wt(o, n);
|
|
727
|
+
u && l.push(u);
|
|
728
|
+
let d = Ct(o, n);
|
|
729
|
+
d && l.push(d);
|
|
730
|
+
for (let e of o) l.push(ut(e, n, null, c.get(e.tableName)));
|
|
731
|
+
if (!m(n)) for (let e of s) l.push(xt(e, n));
|
|
732
|
+
for (let e of o) {
|
|
733
|
+
let t = ft(e, n);
|
|
734
|
+
t && l.push(t);
|
|
735
|
+
}
|
|
736
|
+
l.push(...pt(o, n, r));
|
|
737
|
+
for (let t of a) l.push(e(t, n));
|
|
738
|
+
return l.join("\n\n") + "\n";
|
|
739
|
+
}, Dt = (e, t, n) => {
|
|
740
|
+
let r = o(e, t);
|
|
741
741
|
switch (t) {
|
|
742
742
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${r};`;
|
|
743
743
|
case "mysql":
|
|
@@ -746,62 +746,62 @@ BEGIN
|
|
|
746
746
|
case "turso":
|
|
747
747
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${r};`;
|
|
748
748
|
}
|
|
749
|
-
},
|
|
750
|
-
let i =
|
|
751
|
-
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${
|
|
752
|
-
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${
|
|
753
|
-
let { sorted:
|
|
754
|
-
for (let e of
|
|
755
|
-
if (!
|
|
756
|
-
for (let e of
|
|
757
|
-
let r =
|
|
749
|
+
}, Ot = (e, t, n, r) => {
|
|
750
|
+
let i = Dt(n, t, r), a = o(n, t);
|
|
751
|
+
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${Et(e, t)}`;
|
|
752
|
+
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${Et(e, t)}`;
|
|
753
|
+
let { sorted: s, cyclic: c } = bt(e), l = St(c, t), u = [i];
|
|
754
|
+
for (let e of s) u.push(ut(e, t, n, l.get(e.tableName)));
|
|
755
|
+
if (!m(t)) for (let e of c) u.push(xt(e, t, n));
|
|
756
|
+
for (let e of s) {
|
|
757
|
+
let r = ft(e, t, n);
|
|
758
758
|
r && u.push(r);
|
|
759
759
|
}
|
|
760
760
|
return u.join("\n\n") + "\n";
|
|
761
|
-
},
|
|
762
|
-
let { sorted: r, cyclic: i } =
|
|
761
|
+
}, kt = (e, t, n = k) => {
|
|
762
|
+
let { sorted: r, cyclic: i } = bt(e), a = St(i, t), o = [], s = wt(r, t);
|
|
763
763
|
s && o.push(s);
|
|
764
|
-
let c =
|
|
764
|
+
let c = Ct(r, t);
|
|
765
765
|
c && o.push(c);
|
|
766
|
-
for (let e of r) o.push(
|
|
767
|
-
for (let e of i) o.push(
|
|
768
|
-
return o.push(...
|
|
769
|
-
},
|
|
766
|
+
for (let e of r) o.push(ut(e, t, null, a.get(e.tableName)));
|
|
767
|
+
for (let e of i) o.push(xt(e, t));
|
|
768
|
+
return o.push(...pt(r, t, n)), o.join("\n\n") + "\n";
|
|
769
|
+
}, At = (e, t = "postgres", n = k, r = {}) => C.gen(function* () {
|
|
770
770
|
let i = yield* T.SqlClient;
|
|
771
|
-
yield*
|
|
772
|
-
}),
|
|
771
|
+
yield* Fe(i, Lt(i, Et(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(C.orDie);
|
|
772
|
+
}), jt = (e, t) => {
|
|
773
773
|
let n = t.cause ?? {};
|
|
774
774
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
775
|
-
},
|
|
775
|
+
}, Mt = (e, t) => {
|
|
776
776
|
let n = e.trimStart();
|
|
777
777
|
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));
|
|
778
|
-
},
|
|
778
|
+
}, Nt = () => {
|
|
779
779
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
780
780
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
781
|
-
},
|
|
781
|
+
}, Pt = (e) => ({
|
|
782
782
|
while: e,
|
|
783
|
-
times:
|
|
784
|
-
schedule:
|
|
785
|
-
}),
|
|
783
|
+
times: Nt(),
|
|
784
|
+
schedule: w.jittered(w.exponential("50 millis"))
|
|
785
|
+
}), Ft = class {
|
|
786
786
|
statement;
|
|
787
787
|
error;
|
|
788
788
|
_tag = "DdlStatementFailed";
|
|
789
789
|
constructor(e, t) {
|
|
790
790
|
this.statement = e, this.error = t;
|
|
791
791
|
}
|
|
792
|
-
},
|
|
793
|
-
let r = yield* T.SqlClient, i = n !== void 0 &&
|
|
794
|
-
for (let a of
|
|
795
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
796
|
-
let e = r.unsafe(a).pipe(
|
|
797
|
-
|
|
792
|
+
}, It = (e, t, n) => C.gen(function* () {
|
|
793
|
+
let r = yield* T.SqlClient, i = n !== void 0 && Re(t) === "per-operation";
|
|
794
|
+
for (let a of Rt(e)) {
|
|
795
|
+
process.env.VOLTRO_MIGRATE_DEBUG === "1" && tt.debug(`EXEC: ${a.replace(/\s+/g, " ").slice(0, 180)}`);
|
|
796
|
+
let e = r.unsafe(a).pipe(C.catchIf((e) => jt(a, e), () => C.succeed([])), C.tapError((e) => C.sync(() => {
|
|
797
|
+
tt.error(oe("migrate: statement failed", a, e, 200));
|
|
798
798
|
})));
|
|
799
|
-
yield* (i && n !== void 0 &&
|
|
799
|
+
yield* (i && n !== void 0 && Mt(a, t) ? e.pipe(C.retry(Pt((e) => n(e) === "retry"))) : e).pipe(C.mapError((e) => new Ft(a, e)));
|
|
800
800
|
}
|
|
801
|
-
}),
|
|
802
|
-
let i = n === "turso" ?
|
|
803
|
-
return (r !== void 0 &&
|
|
804
|
-
},
|
|
801
|
+
}), Lt = (e, t, n, r) => {
|
|
802
|
+
let i = n === "turso" ? It(t, n, r) : e.withTransaction(It(t, n, r)), a = (e) => e instanceof Ft ? e.error : e;
|
|
803
|
+
return (r !== void 0 && Re(n) === "plan-transactional" ? i.pipe(C.retry(Pt((e) => r(a(e)) === "retry"))) : i).pipe(C.orDieWith((e) => e instanceof Ft ? Error(oe("migrate: statement failed", e.statement, e.error, 400).trim()) : e));
|
|
804
|
+
}, Rt = (e) => {
|
|
805
805
|
let t = [], n = "", r = !1;
|
|
806
806
|
for (let i = 0; i < e.length; i++) {
|
|
807
807
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -816,43 +816,43 @@ BEGIN
|
|
|
816
816
|
}
|
|
817
817
|
let i = n.trim();
|
|
818
818
|
return i.length > 0 && t.push(i), t;
|
|
819
|
-
},
|
|
820
|
-
await
|
|
821
|
-
},
|
|
822
|
-
let i =
|
|
823
|
-
yield*
|
|
824
|
-
}),
|
|
825
|
-
await
|
|
819
|
+
}, zt = async (e, t, n = "postgres", r = {}) => {
|
|
820
|
+
await C.runPromise(At(e, n, void 0, r).pipe(C.provide(t)));
|
|
821
|
+
}, Bt = (e, t, n = "postgres", r = {}) => C.gen(function* () {
|
|
822
|
+
let i = Ot(e, n, t), a = yield* T.SqlClient;
|
|
823
|
+
yield* Fe(a, Lt(a, i, n, r.retryFilter), { schema: r.lockSchema }).pipe(C.orDie);
|
|
824
|
+
}), Vt = async (e, t, n, r = "postgres", i = {}) => {
|
|
825
|
+
await C.runPromise(Bt(e, t, r, i).pipe(C.provide(n))), await f({
|
|
826
826
|
namespace: t,
|
|
827
827
|
dialect: r
|
|
828
828
|
});
|
|
829
|
-
},
|
|
830
|
-
await
|
|
831
|
-
let t =
|
|
832
|
-
yield*
|
|
833
|
-
}).pipe(
|
|
834
|
-
},
|
|
829
|
+
}, Ht = async (e, t, n = "postgres", r = {}) => {
|
|
830
|
+
await C.runPromise(C.gen(function* () {
|
|
831
|
+
let t = kt(e, n), i = yield* T.SqlClient;
|
|
832
|
+
yield* Fe(i, Lt(i, t, n, r.retryFilter), { schema: r.lockSchema }).pipe(C.orDie);
|
|
833
|
+
}).pipe(C.provide(t)));
|
|
834
|
+
}, Ut = (e) => {
|
|
835
835
|
if (e == null) return e;
|
|
836
|
-
if (Array.isArray(e)) return e.map(
|
|
836
|
+
if (Array.isArray(e)) return e.map(Ut);
|
|
837
837
|
if (typeof e != "object") return e;
|
|
838
838
|
let t = {};
|
|
839
839
|
for (let n of Object.keys(e).sort()) {
|
|
840
840
|
let r = e[n];
|
|
841
|
-
r !== void 0 && (t[n] =
|
|
841
|
+
r !== void 0 && (t[n] = Ut(r));
|
|
842
842
|
}
|
|
843
843
|
return t;
|
|
844
|
-
},
|
|
844
|
+
}, Wt = (e) => {
|
|
845
845
|
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs) return e;
|
|
846
846
|
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, ...a } = e;
|
|
847
847
|
return a;
|
|
848
|
-
},
|
|
848
|
+
}, Gt = (e) => [...e].map(Wt).sort((e, t) => e.name.localeCompare(t.name)), Kt = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), qt = (e) => [...e].map((e) => ({
|
|
849
849
|
name: e.name,
|
|
850
|
-
columns:
|
|
851
|
-
indexes:
|
|
852
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
853
|
-
let t = { tables:
|
|
854
|
-
return
|
|
855
|
-
},
|
|
850
|
+
columns: Gt(e.columns),
|
|
851
|
+
indexes: Kt(e.indexes)
|
|
852
|
+
})).sort((e, t) => e.name.localeCompare(t.name)), Jt = (e) => {
|
|
853
|
+
let t = { tables: qt(e.tables) }, n = JSON.stringify(Ut(t));
|
|
854
|
+
return te("sha256").update(n).digest("hex");
|
|
855
|
+
}, Yt = (e) => e.slice(0, 16), Xt = (e, t) => {
|
|
856
856
|
let n = t.references ? {
|
|
857
857
|
table: t.references().tableName,
|
|
858
858
|
column: "id",
|
|
@@ -891,59 +891,59 @@ BEGIN
|
|
|
891
891
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
892
892
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
893
893
|
};
|
|
894
|
-
},
|
|
895
|
-
let t = [], n = /* @__PURE__ */ new Set(),
|
|
894
|
+
}, Zt = (e) => {
|
|
895
|
+
let t = [], n = /* @__PURE__ */ new Set(), i = (e) => {
|
|
896
896
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
897
|
-
},
|
|
898
|
-
|
|
897
|
+
}, a = e.appliedPrimaryKey ?? [];
|
|
898
|
+
a.length > 0 ? i({
|
|
899
899
|
name: `${e.tableName}_pkey`,
|
|
900
900
|
table: e.tableName,
|
|
901
|
-
columns: [...
|
|
901
|
+
columns: [...a],
|
|
902
902
|
unique: !0
|
|
903
|
-
}) : e.fields.id &&
|
|
903
|
+
}) : e.fields.id && i({
|
|
904
904
|
name: `${e.tableName}_pkey`,
|
|
905
905
|
table: e.tableName,
|
|
906
906
|
columns: ["id"],
|
|
907
907
|
unique: !0
|
|
908
908
|
});
|
|
909
|
-
let
|
|
910
|
-
for (let t of
|
|
909
|
+
let o = e.appliedIndexes ?? [];
|
|
910
|
+
for (let t of o) {
|
|
911
911
|
if (t.unique && t.where) continue;
|
|
912
|
-
let n = t.fields.map((e) => typeof e == "string" ? e : "jsonPath" in e ? `(json:${e.jsonPath.column}->${e.jsonPath.path.join(".")}${e.jsonPath.numeric ? "::num" : ""})` : `(${e.expr})`),
|
|
913
|
-
|
|
912
|
+
let n = t.fields.map((e) => typeof e == "string" ? e : "jsonPath" in e ? `(json:${e.jsonPath.column}->${e.jsonPath.path.join(".")}${e.jsonPath.numeric ? "::num" : ""})` : `(${e.expr})`), r = t.fields.some((e) => typeof e != "string");
|
|
913
|
+
i({
|
|
914
914
|
name: t.name,
|
|
915
915
|
table: e.tableName,
|
|
916
916
|
columns: n,
|
|
917
917
|
unique: !1,
|
|
918
|
-
...
|
|
918
|
+
...r ? { expression: !0 } : {}
|
|
919
919
|
});
|
|
920
920
|
}
|
|
921
|
-
let
|
|
922
|
-
for (let t of
|
|
921
|
+
let s = e.appliedUniques ?? [];
|
|
922
|
+
for (let t of s) t.fields.length < 2 || i({
|
|
923
923
|
name: t.name,
|
|
924
924
|
table: e.tableName,
|
|
925
925
|
columns: t.fields,
|
|
926
926
|
unique: !0
|
|
927
927
|
});
|
|
928
|
-
let
|
|
929
|
-
for (let e of
|
|
928
|
+
let c = /* @__PURE__ */ new Set();
|
|
929
|
+
for (let e of o) e.fields.every((e) => typeof e == "string") && c.add(e.fields.join("\0"));
|
|
930
930
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
931
|
-
let
|
|
932
|
-
if (
|
|
933
|
-
let
|
|
934
|
-
|
|
935
|
-
name:
|
|
931
|
+
let a = n;
|
|
932
|
+
if (a.dropped || !a.references || a.fkAutoIndex === !1 || c.has(t)) continue;
|
|
933
|
+
let o = `${e.tableName}_${t}_idx`;
|
|
934
|
+
r(e.tableName, o, !0, [t]), i({
|
|
935
|
+
name: o,
|
|
936
936
|
table: e.tableName,
|
|
937
937
|
columns: [t],
|
|
938
938
|
unique: !1
|
|
939
939
|
});
|
|
940
940
|
}
|
|
941
941
|
return t;
|
|
942
|
-
},
|
|
942
|
+
}, Qt = (e) => {
|
|
943
943
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
944
944
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
945
945
|
if (i.dropped) continue;
|
|
946
|
-
let e =
|
|
946
|
+
let e = Xt(r, i);
|
|
947
947
|
n.push(t.has(r) ? {
|
|
948
948
|
...e,
|
|
949
949
|
unique: !0
|
|
@@ -953,27 +953,27 @@ BEGIN
|
|
|
953
953
|
return {
|
|
954
954
|
name: e.tableName,
|
|
955
955
|
columns: n,
|
|
956
|
-
indexes:
|
|
956
|
+
indexes: Zt(e),
|
|
957
957
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
958
958
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
959
959
|
};
|
|
960
|
-
},
|
|
960
|
+
}, $t = (e) => {
|
|
961
961
|
let t = /* @__PURE__ */ new Map();
|
|
962
962
|
for (let n of e) for (let e of n.indexes) {
|
|
963
963
|
let r = t.get(e.name);
|
|
964
964
|
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}').`);
|
|
965
965
|
t.set(e.name, n.name);
|
|
966
966
|
}
|
|
967
|
-
},
|
|
968
|
-
let n = e.filter((e) => !
|
|
969
|
-
return
|
|
970
|
-
},
|
|
967
|
+
}, F = (e, t) => {
|
|
968
|
+
let n = e.filter((e) => !c(e.tableName)).map((e) => Qt(fe(e, t)));
|
|
969
|
+
return $t(n), { tables: n };
|
|
970
|
+
}, en = (e, t, n = k) => C.gen(function* () {
|
|
971
971
|
let r = (yield* e`
|
|
972
972
|
SELECT p.prosrc
|
|
973
973
|
FROM pg_proc p
|
|
974
974
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
975
975
|
WHERE n.nspname = current_schema()
|
|
976
|
-
AND p.proname = ${
|
|
976
|
+
AND p.proname = ${Qe(n)}
|
|
977
977
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
978
978
|
if (a.length === 0) return {
|
|
979
979
|
missing: [],
|
|
@@ -987,10 +987,10 @@ BEGIN
|
|
|
987
987
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
988
988
|
WHERE NOT t.tgisinternal
|
|
989
989
|
AND n.nspname = current_schema()
|
|
990
|
-
AND t.tgname LIKE ${`${
|
|
990
|
+
AND t.tgname LIKE ${`${Xe}%`}
|
|
991
991
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
992
992
|
for (let e of a) {
|
|
993
|
-
let t = s.has(
|
|
993
|
+
let t = s.has(Ze(e.tableName, n)), r = e.isReactive !== !1;
|
|
994
994
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
995
995
|
}
|
|
996
996
|
return {
|
|
@@ -998,7 +998,7 @@ BEGIN
|
|
|
998
998
|
stale: l.sort(),
|
|
999
999
|
functionOutdated: i
|
|
1000
1000
|
};
|
|
1001
|
-
}),
|
|
1001
|
+
}), tn = (e) => {
|
|
1002
1002
|
let t = [];
|
|
1003
1003
|
if (e.missing.length > 0) {
|
|
1004
1004
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -1009,19 +1009,19 @@ BEGIN
|
|
|
1009
1009
|
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.`);
|
|
1010
1010
|
}
|
|
1011
1011
|
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;
|
|
1012
|
-
},
|
|
1012
|
+
}, nn = {
|
|
1013
1013
|
postgres: !0,
|
|
1014
1014
|
mysql: !0,
|
|
1015
1015
|
mariadb: !0,
|
|
1016
1016
|
mssql: !0,
|
|
1017
1017
|
sqlite: !0
|
|
1018
|
-
},
|
|
1018
|
+
}, rn = {
|
|
1019
1019
|
postgres: !0,
|
|
1020
1020
|
mysql: !1,
|
|
1021
1021
|
mariadb: !1,
|
|
1022
1022
|
mssql: !0,
|
|
1023
1023
|
sqlite: !0
|
|
1024
|
-
},
|
|
1024
|
+
}, an = (e) => {
|
|
1025
1025
|
switch (e) {
|
|
1026
1026
|
case "add-column":
|
|
1027
1027
|
case "drop-column":
|
|
@@ -1031,47 +1031,47 @@ BEGIN
|
|
|
1031
1031
|
case "add-foreign-key":
|
|
1032
1032
|
case "add-unique":
|
|
1033
1033
|
case "add-unique-composite":
|
|
1034
|
-
case "add-check": return
|
|
1035
|
-
default: return
|
|
1034
|
+
case "add-check": return rn;
|
|
1035
|
+
default: return nn;
|
|
1036
1036
|
}
|
|
1037
|
-
},
|
|
1037
|
+
}, on = (e, t) => {
|
|
1038
1038
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1039
1039
|
return new Map(e.map((e) => [e.tableName, {
|
|
1040
1040
|
table: e,
|
|
1041
1041
|
snapshot: n.get(e.tableName),
|
|
1042
1042
|
columnDefs: e.fields
|
|
1043
1043
|
}]));
|
|
1044
|
-
},
|
|
1044
|
+
}, I = (e) => {
|
|
1045
1045
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
1046
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
1046
|
+
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
1047
1047
|
let t = e;
|
|
1048
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
1049
|
-
},
|
|
1048
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
1049
|
+
}, sn = (e) => {
|
|
1050
1050
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
1051
1051
|
let t = e.defaultValue;
|
|
1052
1052
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
1053
1053
|
if (typeof t == "number") return String(t);
|
|
1054
|
-
if (typeof t != "string") return
|
|
1054
|
+
if (typeof t != "string") return I(t);
|
|
1055
1055
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
1056
1056
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
1057
1057
|
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);
|
|
1058
1058
|
if (o) try {
|
|
1059
|
-
return
|
|
1059
|
+
return I(JSON.parse(o[1]));
|
|
1060
1060
|
} catch {}
|
|
1061
1061
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1062
1062
|
if (s) try {
|
|
1063
|
-
return
|
|
1063
|
+
return I(JSON.parse(s[1]));
|
|
1064
1064
|
} catch {}
|
|
1065
1065
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1066
|
-
return
|
|
1066
|
+
return I(JSON.parse(a));
|
|
1067
1067
|
} catch {}
|
|
1068
1068
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1069
|
-
},
|
|
1070
|
-
let n =
|
|
1069
|
+
}, cn = (e, t) => {
|
|
1070
|
+
let n = sn(e), r = sn(t);
|
|
1071
1071
|
if (n === r) return !0;
|
|
1072
1072
|
let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
1073
1073
|
return i(n) === i(r);
|
|
1074
|
-
},
|
|
1074
|
+
}, ln = (e) => {
|
|
1075
1075
|
if (!e) return null;
|
|
1076
1076
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1077
1077
|
return {
|
|
@@ -1080,29 +1080,29 @@ BEGIN
|
|
|
1080
1080
|
onDelete: t(e.onDelete),
|
|
1081
1081
|
onUpdate: t(e.onUpdate)
|
|
1082
1082
|
};
|
|
1083
|
-
},
|
|
1083
|
+
}, un = (e, t) => {
|
|
1084
1084
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1085
1085
|
if (!n && !r) return !0;
|
|
1086
1086
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1087
1087
|
let i = [...n].sort(), a = [...r].sort();
|
|
1088
1088
|
return i.every((e, t) => e === a[t]);
|
|
1089
|
-
},
|
|
1089
|
+
}, dn = (e, t, n) => {
|
|
1090
1090
|
if (t === "mssql") {
|
|
1091
|
-
let t =
|
|
1091
|
+
let t = et(e, n);
|
|
1092
1092
|
if (t !== void 0) return t;
|
|
1093
1093
|
}
|
|
1094
1094
|
try {
|
|
1095
|
-
let n = /\((\d+)\)/.exec(
|
|
1095
|
+
let n = /\((\d+)\)/.exec(j(e, t));
|
|
1096
1096
|
return n ? Number(n[1]) : void 0;
|
|
1097
1097
|
} catch {
|
|
1098
1098
|
return;
|
|
1099
1099
|
}
|
|
1100
|
-
},
|
|
1100
|
+
}, fn = (e, t, n, r) => n === void 0 || m(n) ? !0 : e.type !== "text" || t.type !== "text" || dn(e, n, r) === t.maxLength, pn = (e, t, n, r) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && cn(e, t) && fn(e, t, n, r) && JSON.stringify(ln(e.references)) === JSON.stringify(ln(t.references)) && un(e.oneOf, t.oneOf), mn = (e, t) => t.oneOf && t.oneOf.length > 0 ? L({
|
|
1101
1101
|
kind: "add-check",
|
|
1102
1102
|
table: e,
|
|
1103
1103
|
column: t.name,
|
|
1104
1104
|
values: t.oneOf
|
|
1105
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1105
|
+
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, hn = (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])), gn = (e, t, n) => {
|
|
1106
1106
|
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [], c = new Set(e.indexes.flatMap((e) => e.columns));
|
|
1107
1107
|
for (let t of e.columns) {
|
|
1108
1108
|
let e = r.get(t.name);
|
|
@@ -1110,7 +1110,7 @@ BEGIN
|
|
|
1110
1110
|
a.push(t);
|
|
1111
1111
|
continue;
|
|
1112
1112
|
}
|
|
1113
|
-
|
|
1113
|
+
pn(t, e, n, c.has(t.name) || t.unique) || s.push({
|
|
1114
1114
|
declared: t,
|
|
1115
1115
|
live: e
|
|
1116
1116
|
});
|
|
@@ -1121,47 +1121,47 @@ BEGIN
|
|
|
1121
1121
|
removed: o,
|
|
1122
1122
|
changed: s
|
|
1123
1123
|
};
|
|
1124
|
-
},
|
|
1124
|
+
}, _n = (e, t, n) => {
|
|
1125
1125
|
let r = (e) => n === "turso" || n === "sqlite" ? e.toLowerCase() : e, i = new Map(t.indexes.map((e) => [r(e.name), e])), a = new Map(e.indexes.map((e) => [r(e.name), e])), o = [], s = [];
|
|
1126
1126
|
for (let t of e.indexes) {
|
|
1127
1127
|
let e = i.get(r(t.name));
|
|
1128
|
-
(!e || !
|
|
1128
|
+
(!e || !hn(t, e)) && o.push(t);
|
|
1129
1129
|
}
|
|
1130
1130
|
for (let e of t.indexes) a.has(r(e.name)) || s.push(e);
|
|
1131
1131
|
return {
|
|
1132
1132
|
added: o,
|
|
1133
1133
|
removed: s
|
|
1134
1134
|
};
|
|
1135
|
-
},
|
|
1135
|
+
}, L = (e, t, n, r) => ({
|
|
1136
1136
|
op: e,
|
|
1137
1137
|
classification: t,
|
|
1138
|
-
atomicByDialect:
|
|
1138
|
+
atomicByDialect: an(e.kind),
|
|
1139
1139
|
...n ? { reason: n } : {},
|
|
1140
1140
|
...r ? { blocked: r } : {}
|
|
1141
|
-
}),
|
|
1141
|
+
}), vn = (e, t, n) => {
|
|
1142
1142
|
let r = {
|
|
1143
1143
|
kind: "add-column",
|
|
1144
1144
|
table: e,
|
|
1145
1145
|
column: t
|
|
1146
1146
|
};
|
|
1147
|
-
return t.nullable ?
|
|
1148
|
-
},
|
|
1147
|
+
return t.nullable ? L(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? L(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? L(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : L(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` });
|
|
1148
|
+
}, yn = (e, t, n) => {
|
|
1149
1149
|
let r = {
|
|
1150
1150
|
kind: "drop-column",
|
|
1151
1151
|
table: e,
|
|
1152
1152
|
column: t.name
|
|
1153
1153
|
};
|
|
1154
|
-
return n?.dropped ?
|
|
1155
|
-
},
|
|
1154
|
+
return n?.dropped ? L(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : L(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
|
|
1155
|
+
}, bn = (e, t, n, r, i) => L({
|
|
1156
1156
|
kind: "create-table",
|
|
1157
1157
|
table: e,
|
|
1158
1158
|
columns: t,
|
|
1159
1159
|
indexes: n,
|
|
1160
1160
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1161
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1161
|
+
}, "safe", i ?? "new table — no data to preserve"), xn = (e) => L({
|
|
1162
1162
|
kind: "drop-table",
|
|
1163
1163
|
table: e
|
|
1164
|
-
}, "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" }),
|
|
1164
|
+
}, "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" }), Sn = 5e4, Cn = (e, t, n, r) => {
|
|
1165
1165
|
let i = (n ?? 0) >= r, a;
|
|
1166
1166
|
return a = t.unique ? t.columns.length === 1 ? {
|
|
1167
1167
|
kind: "add-unique",
|
|
@@ -1176,16 +1176,16 @@ BEGIN
|
|
|
1176
1176
|
kind: "add-index",
|
|
1177
1177
|
table: e,
|
|
1178
1178
|
index: t
|
|
1179
|
-
}, i ?
|
|
1180
|
-
},
|
|
1179
|
+
}, i ? L(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : L(a, "safe", t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index");
|
|
1180
|
+
}, wn = (e, t) => t.unique && t.columns.length > 1 ? L({
|
|
1181
1181
|
kind: "drop-unique-composite",
|
|
1182
1182
|
table: e,
|
|
1183
1183
|
name: t.name
|
|
1184
|
-
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") :
|
|
1184
|
+
}, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : L({
|
|
1185
1185
|
kind: "drop-index",
|
|
1186
1186
|
table: e,
|
|
1187
1187
|
index: t.name
|
|
1188
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1188
|
+
}, "safe", "drop index (no data loss — index is derived data)"), Tn = (e, t) => {
|
|
1189
1189
|
if (e === "reference") return "text";
|
|
1190
1190
|
switch (t) {
|
|
1191
1191
|
case "sqlite":
|
|
@@ -1193,10 +1193,10 @@ BEGIN
|
|
|
1193
1193
|
case "mssql": return e === "json" ? "text" : e;
|
|
1194
1194
|
default: return e;
|
|
1195
1195
|
}
|
|
1196
|
-
},
|
|
1196
|
+
}, En = (e, t, n) => {
|
|
1197
1197
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1198
1198
|
return n === "postgres" ? `${r} — add \`{ using: '${t.name}::${t.type}' }\` when the cast is not implicit, or use a file-based migration` : `${r} — ${n === void 0 ? "this dialect" : n} converts in place (\`using\` is postgres-only and is ignored here), so verify the conversion is value-preserving for your data, or use a file-based migration`;
|
|
1199
|
-
},
|
|
1199
|
+
}, Dn = (e, t, n, r, i, a) => {
|
|
1200
1200
|
let o = [];
|
|
1201
1201
|
if (t.nullable !== n.nullable) {
|
|
1202
1202
|
let n = {
|
|
@@ -1205,7 +1205,7 @@ BEGIN
|
|
|
1205
1205
|
column: t.name,
|
|
1206
1206
|
toNullable: t.nullable
|
|
1207
1207
|
};
|
|
1208
|
-
o.push(t.nullable ?
|
|
1208
|
+
o.push(t.nullable ? L(n, "safe", `loosen ${e}.${t.name} to nullable`) : L(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
|
|
1209
1209
|
}
|
|
1210
1210
|
if (t.unique !== n.unique) {
|
|
1211
1211
|
if (t.unique) {
|
|
@@ -1214,14 +1214,14 @@ BEGIN
|
|
|
1214
1214
|
table: e,
|
|
1215
1215
|
column: t.name
|
|
1216
1216
|
}, r = (i ?? 0) >= a;
|
|
1217
|
-
o.push(r ?
|
|
1218
|
-
} else o.push(
|
|
1217
|
+
o.push(r ? L(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : L(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
|
|
1218
|
+
} else o.push(L({
|
|
1219
1219
|
kind: "drop-unique",
|
|
1220
1220
|
table: e,
|
|
1221
1221
|
column: t.name
|
|
1222
1222
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1223
1223
|
}
|
|
1224
|
-
if (
|
|
1224
|
+
if (Tn(t.type, r) !== Tn(n.type, r)) {
|
|
1225
1225
|
let i = t.narrowedFrom;
|
|
1226
1226
|
if (i && i.from === n.type) {
|
|
1227
1227
|
let r = {
|
|
@@ -1232,7 +1232,7 @@ BEGIN
|
|
|
1232
1232
|
to: t.type,
|
|
1233
1233
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1234
1234
|
};
|
|
1235
|
-
o.push(
|
|
1235
|
+
o.push(L(r, "needs-backfill", `type change ${n.type} → ${t.type} on ${e}.${t.name} — narrowedFrom('${i.from}') declared` + (i.using ? ` with USING ${i.using}` : " (implicit cast)")));
|
|
1236
1236
|
} else {
|
|
1237
1237
|
let i = {
|
|
1238
1238
|
kind: "alter-column-type",
|
|
@@ -1241,12 +1241,12 @@ BEGIN
|
|
|
1241
1241
|
from: n.type,
|
|
1242
1242
|
to: t.type
|
|
1243
1243
|
};
|
|
1244
|
-
o.push(
|
|
1244
|
+
o.push(L(i, "lossy", `type change ${n.type} → ${t.type} on ${e}.${t.name} may not be value-preserving`, { fix: En(n.type, t, r) }));
|
|
1245
1245
|
}
|
|
1246
1246
|
}
|
|
1247
|
-
if (t.type === "text" && n.type === "text" && !
|
|
1247
|
+
if (t.type === "text" && n.type === "text" && !m(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1248
1248
|
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})`;
|
|
1249
|
-
o.push(
|
|
1249
|
+
o.push(L({
|
|
1250
1250
|
kind: "alter-column-type",
|
|
1251
1251
|
table: e,
|
|
1252
1252
|
column: t.name,
|
|
@@ -1254,7 +1254,7 @@ BEGIN
|
|
|
1254
1254
|
to: "text"
|
|
1255
1255
|
}, 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)}`));
|
|
1256
1256
|
}
|
|
1257
|
-
if (!
|
|
1257
|
+
if (!cn(t, n)) {
|
|
1258
1258
|
let n = {
|
|
1259
1259
|
kind: "alter-column-default",
|
|
1260
1260
|
table: e,
|
|
@@ -1262,23 +1262,23 @@ BEGIN
|
|
|
1262
1262
|
hasDefault: t.hasDefault,
|
|
1263
1263
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1264
1264
|
};
|
|
1265
|
-
o.push(
|
|
1265
|
+
o.push(L(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1266
1266
|
}
|
|
1267
|
-
if (!
|
|
1268
|
-
n.oneOf && n.oneOf.length > 0 && o.push(
|
|
1267
|
+
if (!un(t.oneOf, n.oneOf)) {
|
|
1268
|
+
n.oneOf && n.oneOf.length > 0 && o.push(L({
|
|
1269
1269
|
kind: "drop-check",
|
|
1270
1270
|
table: e,
|
|
1271
1271
|
column: t.name
|
|
1272
1272
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1273
|
-
let r =
|
|
1273
|
+
let r = mn(e, t);
|
|
1274
1274
|
r && o.push(r);
|
|
1275
1275
|
}
|
|
1276
|
-
return JSON.stringify(
|
|
1276
|
+
return JSON.stringify(ln(t.references)) !== JSON.stringify(ln(n.references)) && (n.references && o.push(L({
|
|
1277
1277
|
kind: "drop-foreign-key",
|
|
1278
1278
|
table: e,
|
|
1279
1279
|
column: t.name
|
|
1280
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1281
|
-
},
|
|
1280
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...On(e, t))), o;
|
|
1281
|
+
}, On = (e, t) => {
|
|
1282
1282
|
let n = [];
|
|
1283
1283
|
if (!t.references) return n;
|
|
1284
1284
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1290,15 +1290,15 @@ BEGIN
|
|
|
1290
1290
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1291
1291
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1292
1292
|
};
|
|
1293
|
-
return i === "null" && !t.nullable ? n.push(
|
|
1293
|
+
return i === "null" && !t.nullable ? n.push(L(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(L({
|
|
1294
1294
|
...a,
|
|
1295
1295
|
orphanPolicy: i
|
|
1296
|
-
}, "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(
|
|
1297
|
-
},
|
|
1296
|
+
}, "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(L(a, "needs-backfill", `add FK ${e}.${t.name} → ${r} — existing rows must already reference a valid ${r} (else set orphanPolicy:'null'/'delete')`)), n;
|
|
1297
|
+
}, kn = (e, t, n) => {
|
|
1298
1298
|
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));
|
|
1299
1299
|
for (let [n, c] of Object.entries(t)) {
|
|
1300
1300
|
let t = c.renamedFrom;
|
|
1301
|
-
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(
|
|
1301
|
+
t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(L({
|
|
1302
1302
|
kind: "rename-column",
|
|
1303
1303
|
table: e.tableName,
|
|
1304
1304
|
from: t,
|
|
@@ -1310,26 +1310,26 @@ BEGIN
|
|
|
1310
1310
|
consumedAddedNames: i,
|
|
1311
1311
|
consumedRemovedNames: a
|
|
1312
1312
|
};
|
|
1313
|
-
},
|
|
1313
|
+
}, An = /* @__PURE__ */ new Set([
|
|
1314
1314
|
"postgres",
|
|
1315
1315
|
"mysql",
|
|
1316
1316
|
"mariadb",
|
|
1317
1317
|
"mssql"
|
|
1318
|
-
]),
|
|
1318
|
+
]), jn = {
|
|
1319
1319
|
ops: [],
|
|
1320
1320
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1321
1321
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1322
|
-
},
|
|
1323
|
-
if (i === void 0 || !
|
|
1324
|
-
let a = t.added.filter((e) =>
|
|
1325
|
-
if (a.length === 0) return
|
|
1322
|
+
}, Mn = (e) => !e.unique && !e.expression, Nn = (e, t, n, r, i) => {
|
|
1323
|
+
if (i === void 0 || !An.has(i)) return jn;
|
|
1324
|
+
let a = t.added.filter((e) => Mn(e) && !r.has(e.name));
|
|
1325
|
+
if (a.length === 0) return jn;
|
|
1326
1326
|
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();
|
|
1327
1327
|
for (let n of t.removed) {
|
|
1328
|
-
if (!
|
|
1328
|
+
if (!Mn(n)) continue;
|
|
1329
1329
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1330
1330
|
if (r.length !== 1) continue;
|
|
1331
1331
|
let i = r[0];
|
|
1332
|
-
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(
|
|
1332
|
+
i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(L({
|
|
1333
1333
|
kind: "rename-index",
|
|
1334
1334
|
table: e,
|
|
1335
1335
|
from: n.name,
|
|
@@ -1341,7 +1341,7 @@ BEGIN
|
|
|
1341
1341
|
consumedAddedNames: l,
|
|
1342
1342
|
consumedRemovedNames: u
|
|
1343
1343
|
};
|
|
1344
|
-
},
|
|
1344
|
+
}, Pn = (e, t, n) => {
|
|
1345
1345
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1346
1346
|
for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
|
|
1347
1347
|
for (let c of e.tables) {
|
|
@@ -1352,7 +1352,7 @@ BEGIN
|
|
|
1352
1352
|
continue;
|
|
1353
1353
|
}
|
|
1354
1354
|
if (t.has(c.name)) {
|
|
1355
|
-
r.push(
|
|
1355
|
+
r.push(L({
|
|
1356
1356
|
kind: "rename-table",
|
|
1357
1357
|
from: e,
|
|
1358
1358
|
to: c.name
|
|
@@ -1360,14 +1360,14 @@ BEGIN
|
|
|
1360
1360
|
continue;
|
|
1361
1361
|
}
|
|
1362
1362
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1363
|
-
r.push(
|
|
1363
|
+
r.push(L({
|
|
1364
1364
|
kind: "rename-table",
|
|
1365
1365
|
from: e,
|
|
1366
1366
|
to: c.name
|
|
1367
1367
|
}, "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.` }));
|
|
1368
1368
|
continue;
|
|
1369
1369
|
}
|
|
1370
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1370
|
+
i.set(c.name, e), a.add(e), r.push(L({
|
|
1371
1371
|
kind: "rename-table",
|
|
1372
1372
|
from: e,
|
|
1373
1373
|
to: c.name
|
|
@@ -1381,19 +1381,19 @@ BEGIN
|
|
|
1381
1381
|
claimedOldNames: c,
|
|
1382
1382
|
refusals: o
|
|
1383
1383
|
};
|
|
1384
|
-
},
|
|
1384
|
+
}, Fn = (e, t, n, r) => {
|
|
1385
1385
|
if (t === void 0) return {
|
|
1386
1386
|
live: e,
|
|
1387
1387
|
ops: []
|
|
1388
1388
|
};
|
|
1389
|
-
let i = r !== void 0 &&
|
|
1389
|
+
let i = r !== void 0 && An.has(r), a = [], o = e.indexes.map((e) => {
|
|
1390
1390
|
if (!e.name.startsWith(t)) return e;
|
|
1391
1391
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1392
1392
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1393
1393
|
...e,
|
|
1394
1394
|
name: r,
|
|
1395
1395
|
table: n
|
|
1396
|
-
} : i ? (a.push(
|
|
1396
|
+
} : i ? (a.push(L({
|
|
1397
1397
|
kind: "rename-index",
|
|
1398
1398
|
table: n,
|
|
1399
1399
|
from: e.name,
|
|
@@ -1412,7 +1412,7 @@ BEGIN
|
|
|
1412
1412
|
},
|
|
1413
1413
|
ops: a
|
|
1414
1414
|
};
|
|
1415
|
-
},
|
|
1415
|
+
}, In = (e) => {
|
|
1416
1416
|
let t = {
|
|
1417
1417
|
safe: 0,
|
|
1418
1418
|
needsDefault: 0,
|
|
@@ -1445,42 +1445,42 @@ BEGIN
|
|
|
1445
1445
|
case "multi-step": t.multiStep++;
|
|
1446
1446
|
}
|
|
1447
1447
|
return t;
|
|
1448
|
-
},
|
|
1449
|
-
let t =
|
|
1448
|
+
}, Ln = (e) => {
|
|
1449
|
+
let t = F(e.declared, e.dialect), n = on(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? Sn, a = [], o = Pn(t, r, n);
|
|
1450
1450
|
a.push(...o.ops);
|
|
1451
1451
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1452
|
-
a.push(
|
|
1452
|
+
a.push(bn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1453
1453
|
for (let t of e.columns) {
|
|
1454
|
-
let n =
|
|
1454
|
+
let n = mn(e.name, t);
|
|
1455
1455
|
n && a.push(n);
|
|
1456
1456
|
}
|
|
1457
1457
|
}
|
|
1458
1458
|
let s = new Set(e.ignoreTables ?? []);
|
|
1459
|
-
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) ||
|
|
1459
|
+
for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || _(t.name) || x(t.name) || s.has(t.name) || a.push(xn(t.name));
|
|
1460
1460
|
for (let s of t.tables) {
|
|
1461
1461
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1462
1462
|
if (!c) continue;
|
|
1463
|
-
let l =
|
|
1463
|
+
let l = Fn(c, t, s.name, e.dialect);
|
|
1464
1464
|
a.push(...l.ops);
|
|
1465
|
-
let u = l.live, d = n.get(s.name),
|
|
1466
|
-
a.push(...
|
|
1467
|
-
for (let e of
|
|
1468
|
-
if (
|
|
1465
|
+
let u = l.live, d = n.get(s.name), f = gn(s, u, e.dialect), p = _n(s, u, e.dialect), m = kn(d.table, d.columnDefs, f);
|
|
1466
|
+
a.push(...m.ops);
|
|
1467
|
+
for (let e of f.removed) {
|
|
1468
|
+
if (m.consumedRemovedNames.has(e.name) || x(e.name)) continue;
|
|
1469
1469
|
let t = d.columnDefs[e.name];
|
|
1470
|
-
a.push(
|
|
1470
|
+
a.push(yn(s.name, e, t));
|
|
1471
1471
|
}
|
|
1472
|
-
for (let e of
|
|
1473
|
-
if (
|
|
1472
|
+
for (let e of f.added) {
|
|
1473
|
+
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1474
1474
|
let t = d.columnDefs[e.name];
|
|
1475
|
-
a.push(
|
|
1476
|
-
let n =
|
|
1477
|
-
n && a.push(n), a.push(...
|
|
1475
|
+
a.push(vn(s.name, e, t));
|
|
1476
|
+
let n = mn(s.name, e);
|
|
1477
|
+
n && a.push(n), a.push(...On(s.name, e));
|
|
1478
1478
|
}
|
|
1479
|
-
let
|
|
1480
|
-
a.push(...
|
|
1481
|
-
for (let e of
|
|
1482
|
-
for (let e of
|
|
1483
|
-
for (let { declared: t, live: n } of
|
|
1479
|
+
let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Nn(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
|
|
1480
|
+
a.push(...g.ops);
|
|
1481
|
+
for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(Cn(s.name, e, u.rowCount, i));
|
|
1482
|
+
for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(wn(s.name, e));
|
|
1483
|
+
for (let { declared: t, live: n } of f.changed) a.push(...Dn(s.name, t, n, e.dialect, u.rowCount, i));
|
|
1484
1484
|
}
|
|
1485
1485
|
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) => {
|
|
1486
1486
|
let t = l.get(e);
|
|
@@ -1488,8 +1488,8 @@ BEGIN
|
|
|
1488
1488
|
column: e.name,
|
|
1489
1489
|
target: e.references.table
|
|
1490
1490
|
}] : []) : [];
|
|
1491
|
-
}, d =
|
|
1492
|
-
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(E(e.name, t.name)) ||
|
|
1491
|
+
}, d = pe([...c], u), f = [];
|
|
1492
|
+
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(E(e.name, t.name)) || f.push(L({
|
|
1493
1493
|
kind: "add-foreign-key",
|
|
1494
1494
|
table: e.name,
|
|
1495
1495
|
column: t.name,
|
|
@@ -1514,24 +1514,24 @@ BEGIN
|
|
|
1514
1514
|
}
|
|
1515
1515
|
};
|
|
1516
1516
|
}
|
|
1517
|
-
a.push(...
|
|
1517
|
+
a.push(...f);
|
|
1518
1518
|
}
|
|
1519
|
-
let
|
|
1520
|
-
let n =
|
|
1519
|
+
let p = new Map(t.tables.map((e) => [e.name, e])), m = /* @__PURE__ */ new Map(), h = (e, t = /* @__PURE__ */ new Set()) => {
|
|
1520
|
+
let n = m.get(e);
|
|
1521
1521
|
if (n !== void 0) return n;
|
|
1522
1522
|
if (t.has(e)) return 0;
|
|
1523
|
-
let r =
|
|
1523
|
+
let r = p.get(e);
|
|
1524
1524
|
if (!r) return 0;
|
|
1525
1525
|
let i = new Set(t).add(e), a = 0;
|
|
1526
1526
|
for (let t of r.columns) {
|
|
1527
1527
|
let n = t.references?.table;
|
|
1528
|
-
n && n !== e && !d.has(E(e, t.name)) && (a = Math.max(a,
|
|
1528
|
+
n && n !== e && !d.has(E(e, t.name)) && (a = Math.max(a, h(n, i) + 1));
|
|
1529
1529
|
}
|
|
1530
|
-
return
|
|
1531
|
-
},
|
|
1530
|
+
return m.set(e, a), a;
|
|
1531
|
+
}, g = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, v = (e) => {
|
|
1532
1532
|
let t = "table" in e ? e.table : "";
|
|
1533
|
-
return e.kind === "create-table" ?
|
|
1534
|
-
},
|
|
1533
|
+
return e.kind === "create-table" ? h(t) : e.kind === "drop-table" ? -h(t) : 0;
|
|
1534
|
+
}, y = {
|
|
1535
1535
|
"add-column": 0,
|
|
1536
1536
|
"rename-column": 1,
|
|
1537
1537
|
"rename-index": 1,
|
|
@@ -1549,23 +1549,23 @@ BEGIN
|
|
|
1549
1549
|
"add-unique-composite": 5,
|
|
1550
1550
|
"add-foreign-key": 5,
|
|
1551
1551
|
"add-check": 5
|
|
1552
|
-
},
|
|
1553
|
-
let n =
|
|
1552
|
+
}, b = (e) => y[e] ?? 9, S = [...a].sort((e, t) => {
|
|
1553
|
+
let n = g(e.op.kind), r = g(t.op.kind);
|
|
1554
1554
|
if (n !== r) return n - r;
|
|
1555
|
-
let i =
|
|
1555
|
+
let i = v(e.op), a = v(t.op);
|
|
1556
1556
|
if (i !== a) return i - a;
|
|
1557
1557
|
let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
|
|
1558
1558
|
if (o !== s) return o.localeCompare(s);
|
|
1559
|
-
let c =
|
|
1559
|
+
let c = b(e.op.kind), l = b(t.op.kind);
|
|
1560
1560
|
return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
|
|
1561
1561
|
});
|
|
1562
1562
|
return {
|
|
1563
1563
|
operations: S,
|
|
1564
|
-
fromFingerprint:
|
|
1565
|
-
toFingerprint:
|
|
1566
|
-
summary:
|
|
1564
|
+
fromFingerprint: Jt(e.live),
|
|
1565
|
+
toFingerprint: Jt(t),
|
|
1566
|
+
summary: In(S)
|
|
1567
1567
|
};
|
|
1568
|
-
},
|
|
1568
|
+
}, Rn = (e) => {
|
|
1569
1569
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1570
1570
|
if (!t) return null;
|
|
1571
1571
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -1573,7 +1573,7 @@ BEGIN
|
|
|
1573
1573
|
column: t[1],
|
|
1574
1574
|
values: n
|
|
1575
1575
|
};
|
|
1576
|
-
},
|
|
1576
|
+
}, zn = (e, t) => {
|
|
1577
1577
|
if (t === "vector") return "vector";
|
|
1578
1578
|
switch (e) {
|
|
1579
1579
|
case "text":
|
|
@@ -1600,10 +1600,10 @@ BEGIN
|
|
|
1600
1600
|
case "USER-DEFINED": return "text";
|
|
1601
1601
|
default: return "text";
|
|
1602
1602
|
}
|
|
1603
|
-
},
|
|
1603
|
+
}, Bn = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1604
1604
|
expr: e,
|
|
1605
1605
|
stored: t
|
|
1606
|
-
} },
|
|
1606
|
+
} }, R = (e) => {
|
|
1607
1607
|
switch (e.toUpperCase()) {
|
|
1608
1608
|
case "CASCADE": return "cascade";
|
|
1609
1609
|
case "RESTRICT": return "restrict";
|
|
@@ -1611,25 +1611,25 @@ BEGIN
|
|
|
1611
1611
|
case "SET DEFAULT": return "noAction";
|
|
1612
1612
|
default: return "noAction";
|
|
1613
1613
|
}
|
|
1614
|
-
},
|
|
1614
|
+
}, Vn = (e, t) => {
|
|
1615
1615
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1616
1616
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1617
|
-
},
|
|
1617
|
+
}, Hn = () => Vn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Un = 300, Wn = () => {
|
|
1618
1618
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1619
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1620
|
-
},
|
|
1619
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Vn(e, 3e4);
|
|
1620
|
+
}, Gn = (e, t) => {
|
|
1621
1621
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1622
1622
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1623
1623
|
return r;
|
|
1624
|
-
},
|
|
1625
|
-
let t =
|
|
1624
|
+
}, Kn = (e) => {
|
|
1625
|
+
let t = Wn(), n = C.gen(function* () {
|
|
1626
1626
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1627
|
-
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i =
|
|
1627
|
+
let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Hn(), a = (e, t) => C.gen(function* () {
|
|
1628
1628
|
let r = [];
|
|
1629
|
-
for (let a of
|
|
1629
|
+
for (let a of Gn(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1630
1630
|
return r;
|
|
1631
1631
|
}), o = [];
|
|
1632
|
-
for (let t = 0;; t +=
|
|
1632
|
+
for (let t = 0;; t += Un) {
|
|
1633
1633
|
let n = yield* e`
|
|
1634
1634
|
SELECT c.relname AS table_name,
|
|
1635
1635
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1637,9 +1637,9 @@ BEGIN
|
|
|
1637
1637
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1638
1638
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1639
1639
|
ORDER BY c.relname
|
|
1640
|
-
LIMIT ${r(
|
|
1640
|
+
LIMIT ${r(Un)} OFFSET ${r(t)}
|
|
1641
1641
|
`;
|
|
1642
|
-
if (o.push(...n), n.length <
|
|
1642
|
+
if (o.push(...n), n.length < Un) break;
|
|
1643
1643
|
}
|
|
1644
1644
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1645
1645
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1725,7 +1725,7 @@ BEGIN
|
|
|
1725
1725
|
AND c.relname IN ${t}
|
|
1726
1726
|
)
|
|
1727
1727
|
SELECT * FROM ix ORDER BY table_name, index_name, position
|
|
1728
|
-
`), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(),
|
|
1728
|
+
`), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map();
|
|
1729
1729
|
for (let e of u) {
|
|
1730
1730
|
let t = _.get(e.table_name);
|
|
1731
1731
|
t || (t = [], _.set(e.table_name, t)), t.push(e);
|
|
@@ -1765,33 +1765,33 @@ BEGIN
|
|
|
1765
1765
|
t || (t = [], x.set(e.source_table, t)), t.push(e);
|
|
1766
1766
|
}
|
|
1767
1767
|
for (let e of g) {
|
|
1768
|
-
let t =
|
|
1769
|
-
t || (t = /* @__PURE__ */ new Map(),
|
|
1768
|
+
let t = S.get(e.table_name);
|
|
1769
|
+
t || (t = /* @__PURE__ */ new Map(), S.set(e.table_name, t));
|
|
1770
1770
|
let n = t.get(e.index_name);
|
|
1771
1771
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1772
1772
|
}
|
|
1773
1773
|
let w = [];
|
|
1774
1774
|
for (let e of c) {
|
|
1775
1775
|
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 = x.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) => {
|
|
1776
|
-
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" :
|
|
1776
|
+
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" : zn(t.data_type, t.udt_name), c = a ? {
|
|
1777
1777
|
table: a.target_table,
|
|
1778
1778
|
column: a.target_column,
|
|
1779
|
-
onDelete:
|
|
1780
|
-
onUpdate:
|
|
1779
|
+
onDelete: R(a.delete_rule),
|
|
1780
|
+
onUpdate: R(a.update_rule)
|
|
1781
1781
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1782
1782
|
return {
|
|
1783
1783
|
name: t.column_name,
|
|
1784
1784
|
type: s,
|
|
1785
|
-
...
|
|
1785
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
1786
1786
|
nullable: t.is_nullable === "YES",
|
|
1787
1787
|
unique: i.has(t.column_name) || n && t.column_name === "id",
|
|
1788
1788
|
hasDefault: t.column_default !== null,
|
|
1789
1789
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
1790
1790
|
...c ? { references: c } : {},
|
|
1791
1791
|
...l ? { oneOf: l } : {},
|
|
1792
|
-
...
|
|
1792
|
+
...Bn(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
1793
1793
|
};
|
|
1794
|
-
}), l = [], u =
|
|
1794
|
+
}), l = [], u = S.get(e.table_name);
|
|
1795
1795
|
if (u) for (let [t, n] of u) {
|
|
1796
1796
|
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) => {
|
|
1797
1797
|
let t = e.position;
|
|
@@ -1824,11 +1824,11 @@ BEGIN
|
|
|
1824
1824
|
}
|
|
1825
1825
|
return { tables: w };
|
|
1826
1826
|
});
|
|
1827
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
1827
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(C.catchAll((e) => {
|
|
1828
1828
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1829
|
-
return n.includes("statement timeout") || n.includes("57014") ?
|
|
1829
|
+
return n.includes("statement timeout") || n.includes("57014") ? C.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.`)) : C.fail(e);
|
|
1830
1830
|
}));
|
|
1831
|
-
},
|
|
1831
|
+
}, qn = (e, t) => {
|
|
1832
1832
|
switch (e.toLowerCase()) {
|
|
1833
1833
|
case "varchar":
|
|
1834
1834
|
case "char":
|
|
@@ -1860,21 +1860,21 @@ BEGIN
|
|
|
1860
1860
|
case "json": return "json";
|
|
1861
1861
|
default: return "text";
|
|
1862
1862
|
}
|
|
1863
|
-
},
|
|
1863
|
+
}, z = (e) => e.map((e) => {
|
|
1864
1864
|
let t = e, n = {};
|
|
1865
1865
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1866
1866
|
return n;
|
|
1867
|
-
}),
|
|
1868
|
-
let t =
|
|
1867
|
+
}), Jn = (e) => C.gen(function* () {
|
|
1868
|
+
let t = z(yield* e`
|
|
1869
1869
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1870
1870
|
FROM information_schema.tables
|
|
1871
1871
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1872
|
-
ORDER BY table_name`), n =
|
|
1872
|
+
ORDER BY table_name`), n = z(yield* e`
|
|
1873
1873
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1874
1874
|
character_maximum_length, generation_expression, extra
|
|
1875
1875
|
FROM information_schema.columns
|
|
1876
1876
|
WHERE table_schema = DATABASE()
|
|
1877
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
1877
|
+
ORDER BY table_name, ordinal_position`), r = z(yield* e`
|
|
1878
1878
|
SELECT k.table_name AS source_table,
|
|
1879
1879
|
k.column_name AS source_column,
|
|
1880
1880
|
k.referenced_table_name AS target_table,
|
|
@@ -1884,7 +1884,7 @@ BEGIN
|
|
|
1884
1884
|
JOIN information_schema.referential_constraints r
|
|
1885
1885
|
ON k.constraint_name = r.constraint_name
|
|
1886
1886
|
AND k.table_schema = r.constraint_schema
|
|
1887
|
-
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i =
|
|
1887
|
+
WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = z(yield* e`
|
|
1888
1888
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
1889
1889
|
FROM information_schema.statistics
|
|
1890
1890
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -1897,14 +1897,14 @@ BEGIN
|
|
|
1897
1897
|
JOIN information_schema.table_constraints tc
|
|
1898
1898
|
ON tc.constraint_schema = cc.constraint_schema
|
|
1899
1899
|
AND tc.constraint_name = cc.constraint_name
|
|
1900
|
-
WHERE cc.constraint_schema = DATABASE()`.unprepared, s =
|
|
1900
|
+
WHERE cc.constraint_schema = DATABASE()`.unprepared, s = z(yield* a.pipe(C.orElse(() => o), C.orElseSucceed(() => []))), c = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Map();
|
|
1901
1901
|
for (let e of s) {
|
|
1902
1902
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
1903
1903
|
if (t) {
|
|
1904
1904
|
c.add(`${e.table_name}.${t[1]}`);
|
|
1905
1905
|
continue;
|
|
1906
1906
|
}
|
|
1907
|
-
let n =
|
|
1907
|
+
let n = Rn(e.check_clause);
|
|
1908
1908
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
1909
1909
|
}
|
|
1910
1910
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -1927,23 +1927,23 @@ BEGIN
|
|
|
1927
1927
|
let t = u.get(e.table_name) ?? [], n = d.get(e.table_name) ?? [], r = new Map(n.map((e) => [e.source_column, e])), i = t.filter((e) => e.column_key === "PRI").map((e) => e.column_name), a = /* @__PURE__ */ new Set(), o = f.get(e.table_name);
|
|
1928
1928
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1929
1929
|
let s = t.map((t) => {
|
|
1930
|
-
let n = i.includes(t.column_name) && i.length === 1, o = r.get(t.column_name), s = o ? "reference" : n && t.column_name === "id" ? "id" : c.has(`${e.table_name}.${t.column_name}`) ? "json" :
|
|
1930
|
+
let n = i.includes(t.column_name) && i.length === 1, o = r.get(t.column_name), s = o ? "reference" : n && t.column_name === "id" ? "id" : c.has(`${e.table_name}.${t.column_name}`) ? "json" : qn(t.data_type, t.column_type), u = o ? {
|
|
1931
1931
|
table: o.target_table,
|
|
1932
1932
|
column: o.target_column,
|
|
1933
|
-
onDelete:
|
|
1934
|
-
onUpdate:
|
|
1933
|
+
onDelete: R(o.delete_rule),
|
|
1934
|
+
onUpdate: R(o.update_rule)
|
|
1935
1935
|
} : void 0, d = a.has(t.column_name) || n && t.column_name === "id", f = t.column_default === "NULL" ? null : t.column_default, p = l.get(`${e.table_name}.${t.column_name}`);
|
|
1936
1936
|
return {
|
|
1937
1937
|
name: t.column_name,
|
|
1938
1938
|
type: s,
|
|
1939
1939
|
nullable: t.is_nullable === "YES",
|
|
1940
|
-
...
|
|
1940
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
1941
1941
|
unique: d,
|
|
1942
1942
|
hasDefault: f !== null,
|
|
1943
1943
|
...f === null ? {} : { defaultValue: f },
|
|
1944
1944
|
...u ? { references: u } : {},
|
|
1945
1945
|
...p ? { oneOf: p } : {},
|
|
1946
|
-
...
|
|
1946
|
+
...Bn(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {}
|
|
1947
1947
|
};
|
|
1948
1948
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
1949
1949
|
if (o) for (let [t, n] of o) {
|
|
@@ -1970,10 +1970,10 @@ BEGIN
|
|
|
1970
1970
|
});
|
|
1971
1971
|
}
|
|
1972
1972
|
return { tables: p };
|
|
1973
|
-
}),
|
|
1973
|
+
}), Yn = (e) => {
|
|
1974
1974
|
let t = e.toUpperCase();
|
|
1975
1975
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
1976
|
-
},
|
|
1976
|
+
}, Xn = (e) => e === 1 || e === !0, Zn = (e) => C.gen(function* () {
|
|
1977
1977
|
let t = yield* e`
|
|
1978
1978
|
SELECT name, sql FROM sqlite_master
|
|
1979
1979
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -1987,14 +1987,14 @@ BEGIN
|
|
|
1987
1987
|
let o = yield* e.unsafe(`PRAGMA table_xinfo(${n(i)})`), s = yield* e.unsafe(`PRAGMA foreign_key_list(${n(i)})`), c = yield* e.unsafe(`PRAGMA index_list(${n(i)})`), l = new Map(s.map((e) => [e.from, e])), u = o.filter((e) => e.pk > 0).sort((e, t) => e.pk - t.pk).map((e) => e.name), d = new Map(o.map((e) => [e.name.toLowerCase(), e.name])), f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Set();
|
|
1988
1988
|
for (let t of c) {
|
|
1989
1989
|
let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null).map((e) => d.get(e.toLowerCase()) ?? e);
|
|
1990
|
-
f.set(t.name, r),
|
|
1990
|
+
f.set(t.name, r), Xn(t.unique) && r.length === 1 && p.add(r[0]);
|
|
1991
1991
|
}
|
|
1992
1992
|
let m = o.map((e) => {
|
|
1993
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
1993
|
+
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : Yn(e.type), a = r ? {
|
|
1994
1994
|
table: r.table,
|
|
1995
1995
|
column: r.to,
|
|
1996
|
-
onDelete:
|
|
1997
|
-
onUpdate:
|
|
1996
|
+
onDelete: R(r.on_delete),
|
|
1997
|
+
onUpdate: R(r.on_update)
|
|
1998
1998
|
} : void 0, o = t.get(e.name);
|
|
1999
1999
|
return {
|
|
2000
2000
|
name: e.name,
|
|
@@ -2005,17 +2005,17 @@ BEGIN
|
|
|
2005
2005
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
2006
2006
|
...a ? { references: a } : {},
|
|
2007
2007
|
...o ? { oneOf: o } : {},
|
|
2008
|
-
...
|
|
2008
|
+
...Bn(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
2009
2009
|
};
|
|
2010
2010
|
}), h = new Set(s.map((e) => e.from)), g = [];
|
|
2011
2011
|
for (let e of c) {
|
|
2012
2012
|
if (e.origin === "pk") continue;
|
|
2013
2013
|
let t = f.get(e.name) ?? [];
|
|
2014
|
-
t.length === 1 &&
|
|
2014
|
+
t.length === 1 && Xn(e.unique) || t.length === 1 && !Xn(e.unique) && h.has(t[0]) && e.name !== `${i}_${t[0]}_idx` || g.push({
|
|
2015
2015
|
name: e.name,
|
|
2016
2016
|
table: i,
|
|
2017
2017
|
columns: t,
|
|
2018
|
-
unique:
|
|
2018
|
+
unique: Xn(e.unique)
|
|
2019
2019
|
});
|
|
2020
2020
|
}
|
|
2021
2021
|
u.length > 0 && g.push({
|
|
@@ -2030,7 +2030,7 @@ BEGIN
|
|
|
2030
2030
|
});
|
|
2031
2031
|
}
|
|
2032
2032
|
return { tables: r };
|
|
2033
|
-
}),
|
|
2033
|
+
}), Qn = (e) => {
|
|
2034
2034
|
switch (e.toLowerCase()) {
|
|
2035
2035
|
case "int":
|
|
2036
2036
|
case "smallint":
|
|
@@ -2052,14 +2052,14 @@ BEGIN
|
|
|
2052
2052
|
case "image": return "bytes";
|
|
2053
2053
|
default: return "text";
|
|
2054
2054
|
}
|
|
2055
|
-
},
|
|
2055
|
+
}, B = (e) => e === !0 || e === 1, $n = (e) => C.gen(function* () {
|
|
2056
2056
|
let t = yield* e`
|
|
2057
2057
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2058
2058
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
2059
2059
|
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
|
|
2060
2060
|
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
2061
2061
|
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length
|
|
2062
|
-
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield*
|
|
2062
|
+
FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield* C.orElseSucceed(e`
|
|
2063
2063
|
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS definition,
|
|
2064
2064
|
cc.is_persisted AS is_persisted
|
|
2065
2065
|
FROM sys.computed_columns cc
|
|
@@ -2114,36 +2114,36 @@ BEGIN
|
|
|
2114
2114
|
let t = l.get(e) ?? [], n = u.get(e) ?? [], r = new Map(n.map((e) => [e.source_column, e])), a = new Set(n.map((e) => e.source_column)), o = d.get(e), s = [], p = /* @__PURE__ */ new Set();
|
|
2115
2115
|
if (o) for (let [, e] of o) {
|
|
2116
2116
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2117
|
-
if (
|
|
2118
|
-
else
|
|
2117
|
+
if (B(t[0].is_primary)) for (let e of t) s.push(e.column_name);
|
|
2118
|
+
else B(t[0].is_unique) && t.length === 1 && p.add(t[0].column_name);
|
|
2119
2119
|
}
|
|
2120
2120
|
let m = t.map((t) => {
|
|
2121
|
-
let n = s.length === 1 && s[0] === t.column_name, a = r.get(t.column_name), o = a ? "reference" : n && t.column_name === "id" ? "id" :
|
|
2121
|
+
let n = s.length === 1 && s[0] === t.column_name, a = r.get(t.column_name), o = a ? "reference" : n && t.column_name === "id" ? "id" : Qn(t.data_type), l = a ? {
|
|
2122
2122
|
table: a.target_table,
|
|
2123
2123
|
column: a.target_column,
|
|
2124
|
-
onDelete:
|
|
2125
|
-
onUpdate:
|
|
2126
|
-
} : void 0, u = t.column_default === null ? null :
|
|
2124
|
+
onDelete: er(a.delete_rule),
|
|
2125
|
+
onUpdate: er(a.update_rule)
|
|
2126
|
+
} : void 0, u = t.column_default === null ? null : tr(t.column_default), d = c.get(`${e}.${t.column_name}`);
|
|
2127
2127
|
return {
|
|
2128
2128
|
name: t.column_name,
|
|
2129
2129
|
type: o,
|
|
2130
2130
|
nullable: t.is_nullable === "YES",
|
|
2131
|
-
...
|
|
2131
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
2132
2132
|
unique: p.has(t.column_name) || n && t.column_name === "id",
|
|
2133
2133
|
hasDefault: u !== null,
|
|
2134
2134
|
...u === null ? {} : { defaultValue: u },
|
|
2135
2135
|
...l ? { references: l } : {},
|
|
2136
2136
|
...d ? { oneOf: d } : {},
|
|
2137
|
-
...
|
|
2137
|
+
...Bn(i.get(`${e}.${t.column_name}`)?.definition ?? null, B(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2138
2138
|
};
|
|
2139
2139
|
}), h = [];
|
|
2140
2140
|
if (o) for (let [t, n] of o) {
|
|
2141
2141
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2142
|
-
|
|
2142
|
+
B(r[0].is_primary) || r.length === 1 && B(r[0].is_unique) || r.length === 1 && !B(r[0].is_unique) && a.has(r[0].column_name) && t !== `${e}_${r[0].column_name}_idx` || h.push({
|
|
2143
2143
|
name: t,
|
|
2144
2144
|
table: e,
|
|
2145
2145
|
columns: r.map((e) => e.column_name),
|
|
2146
|
-
unique:
|
|
2146
|
+
unique: B(r[0].is_unique)
|
|
2147
2147
|
});
|
|
2148
2148
|
}
|
|
2149
2149
|
s.length > 0 && h.push({
|
|
@@ -2158,90 +2158,90 @@ BEGIN
|
|
|
2158
2158
|
});
|
|
2159
2159
|
}
|
|
2160
2160
|
return { tables: f };
|
|
2161
|
-
}),
|
|
2161
|
+
}), er = (e) => {
|
|
2162
2162
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2163
2163
|
case "CASCADE": return "cascade";
|
|
2164
2164
|
case "SET NULL": return "setNull";
|
|
2165
2165
|
case "SET DEFAULT": return "noAction";
|
|
2166
2166
|
default: return "noAction";
|
|
2167
2167
|
}
|
|
2168
|
-
},
|
|
2168
|
+
}, tr = (e) => {
|
|
2169
2169
|
let t = e.trim();
|
|
2170
2170
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2171
2171
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2172
|
-
},
|
|
2172
|
+
}, nr = /* @__PURE__ */ new Set([
|
|
2173
2173
|
"character varying",
|
|
2174
2174
|
"varchar",
|
|
2175
2175
|
"nvarchar",
|
|
2176
2176
|
"char",
|
|
2177
2177
|
"character",
|
|
2178
2178
|
"nchar"
|
|
2179
|
-
]),
|
|
2180
|
-
if (
|
|
2179
|
+
]), V = (e, t) => {
|
|
2180
|
+
if (!nr.has(e.toLowerCase())) return;
|
|
2181
2181
|
let n = Number(t);
|
|
2182
2182
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2183
|
-
},
|
|
2184
|
-
mysql: () =>
|
|
2185
|
-
mssql: () =>
|
|
2186
|
-
sqlite: () =>
|
|
2187
|
-
orElse: () =>
|
|
2188
|
-
}).pipe(
|
|
2183
|
+
}, rr = /* @__PURE__ */ new Set([O]), ir = (e) => e.onDialectOrElse({
|
|
2184
|
+
mysql: () => Jn(e),
|
|
2185
|
+
mssql: () => $n(e),
|
|
2186
|
+
sqlite: () => Zn(e),
|
|
2187
|
+
orElse: () => Kn(e)
|
|
2188
|
+
}).pipe(C.map((e) => ({
|
|
2189
2189
|
...e,
|
|
2190
|
-
tables: e.tables.filter((e) => !
|
|
2191
|
-
}))),
|
|
2192
|
-
let t =
|
|
2193
|
-
return t === void 0 ?
|
|
2194
|
-
}),
|
|
2190
|
+
tables: e.tables.filter((e) => !rr.has(e.name))
|
|
2191
|
+
}))), ar = (e) => /mariadb/i.test(e) ? "mariadb" : "mysql", or = /* @__PURE__ */ new WeakMap(), H = (e) => C.suspend(() => {
|
|
2192
|
+
let t = or.get(e);
|
|
2193
|
+
return t === void 0 ? sr(e).pipe(C.tap((t) => C.sync(() => or.set(e, t)))) : C.succeed(t);
|
|
2194
|
+
}), sr = (e) => e.unsafe("SELECT VERSION() AS v").pipe(C.map((e) => {
|
|
2195
2195
|
let t = e[0]?.v;
|
|
2196
|
-
return typeof t == "string" ?
|
|
2197
|
-
}),
|
|
2196
|
+
return typeof t == "string" ? ar(t) : "mysql";
|
|
2197
|
+
}), C.catchAll(() => C.succeed("mysql"))), cr = (e) => {
|
|
2198
2198
|
let t = e;
|
|
2199
2199
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2200
2200
|
let e = t;
|
|
2201
2201
|
if (typeof e.errno == "number") return e.errno;
|
|
2202
2202
|
t = e.cause;
|
|
2203
2203
|
}
|
|
2204
|
-
},
|
|
2204
|
+
}, lr = (e) => {
|
|
2205
2205
|
let t = [], n = e;
|
|
2206
2206
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2207
2207
|
let e = n;
|
|
2208
2208
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2209
2209
|
}
|
|
2210
2210
|
return t.join(" | ");
|
|
2211
|
-
},
|
|
2211
|
+
}, ur = (e, t) => {
|
|
2212
2212
|
if (t.length === 0) return !1;
|
|
2213
|
-
let n =
|
|
2213
|
+
let n = cr(e), r = lr(e);
|
|
2214
2214
|
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)));
|
|
2215
|
-
},
|
|
2215
|
+
}, dr = {
|
|
2216
2216
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2217
2217
|
errno: [1061]
|
|
2218
|
-
},
|
|
2218
|
+
}, fr = {
|
|
2219
2219
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2220
2220
|
errno: [1091]
|
|
2221
|
-
},
|
|
2221
|
+
}, pr = {
|
|
2222
2222
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2223
2223
|
messageIncludes: ["no such column"]
|
|
2224
|
-
},
|
|
2224
|
+
}, mr = {
|
|
2225
2225
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2226
2226
|
errno: [1091, 3940]
|
|
2227
2227
|
}, U = (e, t) => e.onDialectOrElse({
|
|
2228
|
-
mysql: () =>
|
|
2229
|
-
orElse: () =>
|
|
2230
|
-
}),
|
|
2231
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2228
|
+
mysql: () => C.succeed(t.replace("T", " ").replace("Z", "")),
|
|
2229
|
+
orElse: () => C.succeed(t)
|
|
2230
|
+
}), hr = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, gr = (e) => e.type === "text" && (e.hasDefault && e.defaultValue !== void 0 || e.oneOf !== void 0 && e.oneOf.length > 0), _r = (e, t) => {
|
|
2231
|
+
if ((e.type !== "text" || e.maxLength === void 0) && !gr(e) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
|
|
2232
2232
|
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;
|
|
2233
2233
|
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.`);
|
|
2234
|
-
return
|
|
2235
|
-
},
|
|
2236
|
-
let t =
|
|
2237
|
-
return t === void 0 ?
|
|
2238
|
-
},
|
|
2234
|
+
return j(e, t);
|
|
2235
|
+
}, vr = (e) => {
|
|
2236
|
+
let t = _r(e, "postgres");
|
|
2237
|
+
return t === void 0 ? yr(e) : t;
|
|
2238
|
+
}, yr = (e) => {
|
|
2239
2239
|
switch (e.type) {
|
|
2240
2240
|
case "id": return "text";
|
|
2241
2241
|
case "text": return "text";
|
|
2242
2242
|
case "integer": return "integer";
|
|
2243
2243
|
case "real": return "double precision";
|
|
2244
|
-
case "decimal": return
|
|
2244
|
+
case "decimal": return hr(e, "NUMERIC");
|
|
2245
2245
|
case "bigint": return "bigint";
|
|
2246
2246
|
case "boolean": return "boolean";
|
|
2247
2247
|
case "timestamp": return "timestamptz";
|
|
@@ -2255,15 +2255,15 @@ BEGIN
|
|
|
2255
2255
|
case "interval": return "interval";
|
|
2256
2256
|
case "raw": return e.rawDdl ?? "text";
|
|
2257
2257
|
}
|
|
2258
|
-
},
|
|
2259
|
-
let t =
|
|
2258
|
+
}, br = (e) => {
|
|
2259
|
+
let t = _r(e, "mariadb");
|
|
2260
2260
|
if (t !== void 0) return t;
|
|
2261
2261
|
switch (e.type) {
|
|
2262
2262
|
case "id": return "VARCHAR(64)";
|
|
2263
2263
|
case "text": return "LONGTEXT";
|
|
2264
2264
|
case "integer": return "INT";
|
|
2265
2265
|
case "real": return "DOUBLE";
|
|
2266
|
-
case "decimal": return
|
|
2266
|
+
case "decimal": return hr(e, "DECIMAL");
|
|
2267
2267
|
case "bigint": return "BIGINT";
|
|
2268
2268
|
case "boolean": return "TINYINT(1)";
|
|
2269
2269
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2277,38 +2277,38 @@ BEGIN
|
|
|
2277
2277
|
case "interval": return "BIGINT";
|
|
2278
2278
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2279
2279
|
}
|
|
2280
|
-
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``,
|
|
2280
|
+
}, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``, xr = (e) => e === "mariadb" ? "IF NOT EXISTS " : "", Sr = (e, t, n = !0) => `ALTER TABLE ${t(e.table)} DROP COLUMN ${n ? "IF EXISTS " : ""}${t(e.column)};`, Cr = (e, t = "mariadb") => `ALTER TABLE ${G(e.table)} DROP COLUMN ${t === "mariadb" ? "IF EXISTS " : ""}${G(e.column)}, ALGORITHM=COPY;`, wr = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Tr = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${$r(t)}`)};`, Er = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${Or(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, Dr = (e, t) => {
|
|
2281
2281
|
let { defaultFactory: n, ...r } = e;
|
|
2282
|
-
return
|
|
2282
|
+
return j(e, t) !== j({
|
|
2283
2283
|
...r,
|
|
2284
2284
|
hasDefault: !1
|
|
2285
2285
|
}, t);
|
|
2286
|
-
},
|
|
2286
|
+
}, Or = (e, t) => {
|
|
2287
2287
|
let n = t(e.defaultValue);
|
|
2288
2288
|
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.`);
|
|
2289
2289
|
return n;
|
|
2290
|
-
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n],
|
|
2290
|
+
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], kr = (e, t, n) => {
|
|
2291
2291
|
let r = K(e, t, n);
|
|
2292
|
-
return r ?
|
|
2293
|
-
},
|
|
2294
|
-
let r = n ?? e.nullable, i =
|
|
2292
|
+
return r ? Xt(n, r) : void 0;
|
|
2293
|
+
}, Ar = (e, t, n) => {
|
|
2294
|
+
let r = n ?? e.nullable, i = nt(e, "mariadb");
|
|
2295
2295
|
return [
|
|
2296
2296
|
G(t),
|
|
2297
|
-
|
|
2297
|
+
j(e, "mariadb"),
|
|
2298
2298
|
r ? null : "NOT NULL",
|
|
2299
2299
|
i
|
|
2300
2300
|
].filter(Boolean).join(" ");
|
|
2301
|
-
},
|
|
2301
|
+
}, jr = (e, t) => e == null ? null : Array.isArray(e) ? Mr(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, Mr = (e, t, n) => rt(e, t ?? { type: "json" }, n), Nr = (e, t) => e == null ? null : Array.isArray(e) ? Mr(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, Pr = (e, t) => {
|
|
2302
2302
|
if (!e.generatedAs) return null;
|
|
2303
2303
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2304
2304
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2305
|
-
},
|
|
2306
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2307
|
-
let t =
|
|
2308
|
-
if (t) return `${W(e.name)} ${
|
|
2309
|
-
let n = [W(e.name),
|
|
2305
|
+
}, Fr = (e) => {
|
|
2306
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "postgres");
|
|
2307
|
+
let t = Pr(e, "postgres");
|
|
2308
|
+
if (t) return `${W(e.name)} ${vr(e)} ${t}`;
|
|
2309
|
+
let n = [W(e.name), vr(e)];
|
|
2310
2310
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2311
|
-
let t =
|
|
2311
|
+
let t = Nr(e.defaultValue, e);
|
|
2312
2312
|
t && n.push(t);
|
|
2313
2313
|
}
|
|
2314
2314
|
return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
@@ -2317,24 +2317,24 @@ BEGIN
|
|
|
2317
2317
|
setNull: "SET NULL",
|
|
2318
2318
|
noAction: "NO ACTION"
|
|
2319
2319
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2320
|
-
},
|
|
2321
|
-
let t = e.columns.map((e) => ` ${
|
|
2322
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(
|
|
2320
|
+
}, Ir = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Lr = (e) => {
|
|
2321
|
+
let t = e.columns.map((e) => ` ${Fr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Ir(e, W)}\n)`];
|
|
2322
|
+
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(ii).join(", ")})`);
|
|
2323
2323
|
return n;
|
|
2324
|
-
},
|
|
2325
|
-
let t =
|
|
2324
|
+
}, Rr = 191, zr = (e) => {
|
|
2325
|
+
let t = br(e).toUpperCase();
|
|
2326
2326
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2327
|
-
},
|
|
2328
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2329
|
-
let t =
|
|
2330
|
-
if (t) return `${G(e.name)} ${
|
|
2331
|
-
let n = [G(e.name),
|
|
2332
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2333
|
-
let t =
|
|
2327
|
+
}, Br = (e) => {
|
|
2328
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mariadb");
|
|
2329
|
+
let t = Pr(e, "mariadb");
|
|
2330
|
+
if (t) return `${G(e.name)} ${br(e)} ${t}`;
|
|
2331
|
+
let n = [G(e.name), br(e)];
|
|
2332
|
+
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !zr(e) && n.push("UNIQUE"), e.hasDefault) {
|
|
2333
|
+
let t = jr(e.defaultValue, e);
|
|
2334
2334
|
t && n.push(t);
|
|
2335
2335
|
}
|
|
2336
2336
|
return n.join(" ");
|
|
2337
|
-
},
|
|
2337
|
+
}, Vr = (e) => e.columns.flatMap((t) => {
|
|
2338
2338
|
if (!t.references) return [];
|
|
2339
2339
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2340
2340
|
cascade: "CASCADE",
|
|
@@ -2343,26 +2343,26 @@ BEGIN
|
|
|
2343
2343
|
noAction: "NO ACTION"
|
|
2344
2344
|
}[t.references.onDelete]}` : "";
|
|
2345
2345
|
return [` CONSTRAINT ${G(`${e.table}_${t.name}_fkey`)} FOREIGN KEY (${G(t.name)}) REFERENCES ${G(t.references.table)} (${G(t.references.column)})${n}`];
|
|
2346
|
-
}),
|
|
2346
|
+
}), Hr = (e, t = "mariadb") => {
|
|
2347
2347
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2348
|
-
let t =
|
|
2348
|
+
let t = ni(n.get(e));
|
|
2349
2349
|
return t === void 0 ? G(e) : `${G(e)}(${t})`;
|
|
2350
|
-
}, i = e.columns.map((e) => ` ${
|
|
2351
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
2352
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2350
|
+
}, i = e.columns.map((e) => ` ${Br(e)}`).join(",\n"), a = Vr(e), o = a.length > 0 ? `${i},\n${a.join(",\n")}` : i, s = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${o}${Ir(e, r)}\n)`];
|
|
2351
|
+
for (let n of e.columns) n.unique && n.type !== "id" && zr(n) && s.push(`CREATE UNIQUE INDEX ${xr(t)}${G(`${e.table}_${n.name}_key`)} ON ${G(e.table)} (${r(n.name)})`);
|
|
2352
|
+
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${xr(t)}${G(n.name)} ON ${G(e.table)} (${n.columns.map(r).join(", ")})`);
|
|
2353
2353
|
return s;
|
|
2354
|
-
},
|
|
2354
|
+
}, Ur = {
|
|
2355
2355
|
cascade: "CASCADE",
|
|
2356
2356
|
restrict: "RESTRICT",
|
|
2357
2357
|
setNull: "SET NULL",
|
|
2358
2358
|
noAction: "NO ACTION"
|
|
2359
|
-
},
|
|
2359
|
+
}, Wr = {
|
|
2360
2360
|
cascade: "CASCADE",
|
|
2361
2361
|
restrict: "NO ACTION",
|
|
2362
2362
|
setNull: "SET NULL",
|
|
2363
2363
|
noAction: "NO ACTION"
|
|
2364
|
-
},
|
|
2365
|
-
let t =
|
|
2364
|
+
}, Gr = (e) => {
|
|
2365
|
+
let t = _r(e, "sqlite");
|
|
2366
2366
|
if (t !== void 0) return t;
|
|
2367
2367
|
switch (e.type) {
|
|
2368
2368
|
case "integer":
|
|
@@ -2373,29 +2373,29 @@ BEGIN
|
|
|
2373
2373
|
case "bytes": return "BLOB";
|
|
2374
2374
|
default: return "TEXT";
|
|
2375
2375
|
}
|
|
2376
|
-
},
|
|
2377
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2378
|
-
let t =
|
|
2379
|
-
if (t) return `${W(e.name)} ${
|
|
2380
|
-
let n = [W(e.name),
|
|
2376
|
+
}, q = (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, Kr = (e) => {
|
|
2377
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "sqlite");
|
|
2378
|
+
let t = Pr(e, "sqlite");
|
|
2379
|
+
if (t) return `${W(e.name)} ${Gr(e)} ${t}`;
|
|
2380
|
+
let n = [W(e.name), Gr(e)];
|
|
2381
2381
|
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
|
|
2382
|
-
let t =
|
|
2382
|
+
let t = q(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2383
2383
|
t && n.push(t);
|
|
2384
2384
|
}
|
|
2385
|
-
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${
|
|
2385
|
+
if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Ur[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
|
|
2386
2386
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2387
2387
|
n.push(`CHECK (${W(e.name)} IN (${t}))`);
|
|
2388
2388
|
}
|
|
2389
2389
|
return n.join(" ");
|
|
2390
|
-
},
|
|
2391
|
-
let t = e.columns.map((e) => ` ${
|
|
2390
|
+
}, qr = (e) => {
|
|
2391
|
+
let t = e.columns.map((e) => ` ${Kr(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${Ir(e, W)}\n)`];
|
|
2392
2392
|
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(W).join(", ")})`);
|
|
2393
2393
|
return n;
|
|
2394
2394
|
}, J = (e, t) => {
|
|
2395
2395
|
let n = t.find((t) => t.tableName === e);
|
|
2396
2396
|
if (!n) return [];
|
|
2397
|
-
let r =
|
|
2398
|
-
...
|
|
2397
|
+
let r = F([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => W(e.name)).join(", "), o = [
|
|
2398
|
+
...qr({
|
|
2399
2399
|
kind: "create-table",
|
|
2400
2400
|
table: i,
|
|
2401
2401
|
columns: r.columns,
|
|
@@ -2408,25 +2408,25 @@ BEGIN
|
|
|
2408
2408
|
];
|
|
2409
2409
|
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e)} (${t.columns.map(W).join(", ")})`);
|
|
2410
2410
|
return o;
|
|
2411
|
-
},
|
|
2411
|
+
}, Jr = (e, t, n, r) => {
|
|
2412
2412
|
let i = r ?? e.nullable;
|
|
2413
|
-
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${
|
|
2414
|
-
},
|
|
2413
|
+
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2414
|
+
}, Yr = (e, t) => {
|
|
2415
2415
|
let n = `DECLARE @dc sysname; SELECT @dc = dc.name FROM sys.default_constraints dc JOIN sys.columns col ON col.object_id = dc.parent_object_id AND col.column_id = dc.parent_column_id WHERE dc.parent_object_id = OBJECT_ID(N'${e.table.replace(/'/g, "''")}') AND col.name = N'${e.column.replace(/'/g, "''")}'; IF @dc IS NOT NULL EXEC(N'ALTER TABLE ${Y(e.table)} DROP CONSTRAINT [' + @dc + ']');` + (t ? ` ${t}` : "");
|
|
2416
2416
|
if (!e.hasDefault) return n;
|
|
2417
|
-
let r =
|
|
2417
|
+
let r = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2418
2418
|
if (!r) return n;
|
|
2419
2419
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2420
2420
|
return `${n} ALTER TABLE ${Y(e.table)} ADD DEFAULT ${i} FOR ${Y(e.column)};`;
|
|
2421
|
-
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2422
|
-
let t =
|
|
2421
|
+
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`, Xr = (e) => {
|
|
2422
|
+
let t = _r(e, "mssql");
|
|
2423
2423
|
if (t !== void 0) return t;
|
|
2424
2424
|
switch (e.type) {
|
|
2425
2425
|
case "id":
|
|
2426
2426
|
case "reference": return "NVARCHAR(64)";
|
|
2427
2427
|
case "integer": return "INT";
|
|
2428
2428
|
case "real": return "FLOAT";
|
|
2429
|
-
case "decimal": return
|
|
2429
|
+
case "decimal": return hr(e, "DECIMAL");
|
|
2430
2430
|
case "bigint": return "BIGINT";
|
|
2431
2431
|
case "boolean": return "BIT";
|
|
2432
2432
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2434,44 +2434,44 @@ BEGIN
|
|
|
2434
2434
|
case "bytes": return "VARBINARY(MAX)";
|
|
2435
2435
|
default: return "NVARCHAR(MAX)";
|
|
2436
2436
|
}
|
|
2437
|
-
},
|
|
2438
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2439
|
-
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" :
|
|
2437
|
+
}, Zr = (e, t) => {
|
|
2438
|
+
if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mssql");
|
|
2439
|
+
let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Xr(e), r = Pr(e, "mssql");
|
|
2440
2440
|
if (r) return `${Y(e.name)} ${r}`;
|
|
2441
2441
|
let i = [Y(e.name), n];
|
|
2442
2442
|
if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
|
|
2443
|
-
let t =
|
|
2443
|
+
let t = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2444
2444
|
t && i.push(t);
|
|
2445
2445
|
}
|
|
2446
|
-
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2447
|
-
},
|
|
2448
|
-
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((e) => ` ${
|
|
2446
|
+
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${Wr[e.references.onDelete]}`)), i.join(" ");
|
|
2447
|
+
}, Qr = (e) => {
|
|
2448
|
+
let t = (e) => e.replace(/'/g, "''"), n = /* @__PURE__ */ new Set([...e.indexes.flatMap((e) => e.columns), ...e.columns.filter((e) => e.unique).map((e) => e.name)]), r = e.columns.map((e) => ` ${Zr(e, n)}`).join(",\n"), i = `CREATE TABLE ${Y(e.table)} (\n${r}${Ir(e, Y)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
|
|
2449
2449
|
for (let n of e.indexes) {
|
|
2450
2450
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2451
2451
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Y(n.name)} ON ${Y(e.table)} (${n.columns.map(Y).join(", ")})`;
|
|
2452
2452
|
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)}')`);
|
|
2453
2453
|
}
|
|
2454
2454
|
return a;
|
|
2455
|
-
},
|
|
2456
|
-
let r = `${e.table}${
|
|
2455
|
+
}, $r = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, ei = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, ti = (e, t, n) => {
|
|
2456
|
+
let r = `${e.table}${$r(t)}`;
|
|
2457
2457
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2458
|
-
},
|
|
2459
|
-
if (e === void 0 || !
|
|
2458
|
+
}, ni = (e) => {
|
|
2459
|
+
if (e === void 0 || !zr(e)) return;
|
|
2460
2460
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2461
|
-
return t === void 0 ?
|
|
2462
|
-
},
|
|
2463
|
-
let r =
|
|
2461
|
+
return t === void 0 ? Rr : Math.min(Rr, t);
|
|
2462
|
+
}, ri = (e, t, n) => {
|
|
2463
|
+
let r = ni(kr(e, t, n));
|
|
2464
2464
|
return r === void 0 ? G(n) : `${G(n)}(${r})`;
|
|
2465
|
-
},
|
|
2465
|
+
}, ii = (e) => e.startsWith("(") ? e : W(e), ai = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)} (${e.index.columns.map(ii).join(", ")});`, oi = (e, t, n = "mariadb") => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${xr(n)}${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map((n) => ri(t, e.table, n)).join(", ")});`, si = (e) => `DROP INDEX IF EXISTS ${W(e.index)};`, ci = (e) => `DROP INDEX ${G(e.index)} ON ${G(e.table)};`, li = (e) => `DROP INDEX IF EXISTS ${Y(e.index)} ON ${Y(e.table)};`, ui = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, di = (e) => {
|
|
2466
2466
|
let t = (e) => e.replace(/'/g, "''");
|
|
2467
2467
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2468
|
-
},
|
|
2468
|
+
}, fi = (e) => `ALTER INDEX ${W(e.from)} RENAME TO ${W(e.to)};`, pi = (e) => `ALTER TABLE ${G(e.table)} RENAME INDEX ${G(e.from)} TO ${G(e.to)};`, mi = (e) => {
|
|
2469
2469
|
let t = (e) => e.replace(/'/g, "''");
|
|
2470
2470
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2471
|
-
},
|
|
2471
|
+
}, hi = (e) => {
|
|
2472
2472
|
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(", ")})`;
|
|
2473
2473
|
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)}');`;
|
|
2474
|
-
},
|
|
2474
|
+
}, gi = (e, t, n) => {
|
|
2475
2475
|
let r = n.find((t) => t.tableName === e);
|
|
2476
2476
|
if (!r) return [];
|
|
2477
2477
|
let i = [];
|
|
@@ -2480,13 +2480,13 @@ BEGIN
|
|
|
2480
2480
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Y(e)} ALTER COLUMN ${Y(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2481
2481
|
}
|
|
2482
2482
|
return i;
|
|
2483
|
-
},
|
|
2483
|
+
}, _i = (e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${W(e.column)});`, vi = (e, t) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${ri(t, e.table, e.column)});`, yi = (e) => {
|
|
2484
2484
|
let t = e.fields.map((e) => W(e)).join(", ");
|
|
2485
2485
|
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
|
|
2486
|
-
},
|
|
2487
|
-
let n = e.fields.map((n) =>
|
|
2486
|
+
}, bi = (e, t) => {
|
|
2487
|
+
let n = e.fields.map((n) => ri(t, e.table, n)).join(", ");
|
|
2488
2488
|
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
|
|
2489
|
-
},
|
|
2489
|
+
}, xi = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(e.name)};`, Si = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(e.name)};`, Ci = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_key`)};`, wi = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(`${e.table}_${e.column}_key`)};`, Ti = (e, t) => {
|
|
2490
2490
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2491
2491
|
if (e.orphanPolicy) {
|
|
2492
2492
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2504,34 +2504,34 @@ BEGIN
|
|
|
2504
2504
|
setNull: "SET NULL",
|
|
2505
2505
|
noAction: "NO ACTION"
|
|
2506
2506
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2507
|
-
},
|
|
2507
|
+
}, Ei = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_fkey`)};`, Di = (e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(`${e.table}_${e.column}_fkey`)};`, Oi = (e, t) => {
|
|
2508
2508
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2509
2509
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2510
|
-
},
|
|
2510
|
+
}, ki = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Ai = (e, t) => C.gen(function* () {
|
|
2511
2511
|
let n = yield* e`
|
|
2512
2512
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2513
2513
|
FROM information_schema.check_constraints cc
|
|
2514
|
-
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(
|
|
2514
|
+
WHERE cc.constraint_schema = DATABASE() AND cc.table_name = ${t.table}`.pipe(C.orElse(() => e`
|
|
2515
2515
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2516
2516
|
FROM information_schema.check_constraints cc
|
|
2517
2517
|
JOIN information_schema.table_constraints tc
|
|
2518
2518
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2519
2519
|
AND tc.constraint_name = cc.constraint_name
|
|
2520
|
-
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`),
|
|
2520
|
+
WHERE tc.table_schema = DATABASE() AND tc.table_name = ${t.table}`), C.orElseSucceed(() => []));
|
|
2521
2521
|
for (let e of n) {
|
|
2522
2522
|
let n = String(e.n ?? "");
|
|
2523
|
-
if (n !== "" &&
|
|
2523
|
+
if (n !== "" && Rn(String(e.c ?? ""))?.column === t.column) return n;
|
|
2524
2524
|
}
|
|
2525
|
-
}),
|
|
2526
|
-
let r = yield*
|
|
2527
|
-
r !== void 0 && (yield* X(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [
|
|
2528
|
-
let i = yield*
|
|
2525
|
+
}), ji = (e, t, n) => C.gen(function* () {
|
|
2526
|
+
let r = yield* Ai(e, t);
|
|
2527
|
+
r !== void 0 && (yield* X(e, `ALTER TABLE ${G(t.table)} DROP CONSTRAINT ${G(r)};`, t.kind, [mr]));
|
|
2528
|
+
let i = yield* Ai(e, t);
|
|
2529
2529
|
if (i === void 0) return;
|
|
2530
2530
|
let a = K(n, t.table, t.column);
|
|
2531
|
-
if (!a) return yield*
|
|
2532
|
-
yield* X(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${
|
|
2533
|
-
}),
|
|
2534
|
-
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? Y : W, s = a ?
|
|
2531
|
+
if (!a) return yield* C.die(/* @__PURE__ */ Error(`applier: cannot drop the CHECK on '${t.table}.${t.column}' — it is column-level (catalog name '${i}'), which this family removes only by redefining the column, and the declared column is not available to redefine it from.`));
|
|
2532
|
+
yield* X(e, `ALTER TABLE ${G(t.table)} MODIFY COLUMN ${Ar(a, t.column)};`, t.kind);
|
|
2533
|
+
}), Mi = (e, t, n, r) => {
|
|
2534
|
+
let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? Y : W, s = a ? br(i) : r === "mssql" ? Xr(i) : r === "sqlite" ? Gr(i) : vr(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? jr(e, i) : r === "mssql" ? q(e, "SYSUTCDATETIME()") : r === "sqlite" ? q(e, "CURRENT_TIMESTAMP") : Nr(e, i), u = Pr(i, r);
|
|
2535
2535
|
if (u) {
|
|
2536
2536
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2537
2537
|
return {
|
|
@@ -2559,7 +2559,7 @@ BEGIN
|
|
|
2559
2559
|
post: f ? [f] : []
|
|
2560
2560
|
};
|
|
2561
2561
|
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;
|
|
2562
|
-
},
|
|
2562
|
+
}, Ni = (e) => {
|
|
2563
2563
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2564
2564
|
return (e, n) => {
|
|
2565
2565
|
let r = t.get(e);
|
|
@@ -2579,47 +2579,47 @@ BEGIN
|
|
|
2579
2579
|
...o
|
|
2580
2580
|
};
|
|
2581
2581
|
};
|
|
2582
|
-
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(
|
|
2583
|
-
process.stderr.write(
|
|
2584
|
-
})),
|
|
2585
|
-
let r =
|
|
2582
|
+
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(C.catchIf((e) => ur(e, r), () => C.void), C.tapError((e) => C.sync(() => {
|
|
2583
|
+
process.stderr.write(oe(`applier: statement failed (op=${n})`, t, e, 400));
|
|
2584
|
+
})), C.mapError((e) => {
|
|
2585
|
+
let r = oe(`applier: statement failed (op=${n})`, t, e, 400).trim();
|
|
2586
2586
|
return Object.assign(e, { message: r });
|
|
2587
|
-
}),
|
|
2588
|
-
let n =
|
|
2589
|
-
if (!n) return yield*
|
|
2587
|
+
}), C.map(() => void 0)), Z = (e, t, n) => C.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, n, r) => e.unsafe(`SELECT ${r === void 0 ? "*" : o(r, t)} FROM ${o(n, t)} WHERE 1=0`).pipe(C.as(!0), C.catchAll(() => C.succeed(!1))), Pi = (e, t) => C.gen(function* () {
|
|
2588
|
+
let n = F([ze], t).tables[0];
|
|
2589
|
+
if (!n) return yield* C.die(/* @__PURE__ */ Error("migration applier: the resume-ledger table descriptor produced no snapshot. This is a framework bug."));
|
|
2590
2590
|
let r = {
|
|
2591
2591
|
kind: "create-table",
|
|
2592
|
-
table:
|
|
2592
|
+
table: O,
|
|
2593
2593
|
columns: n.columns,
|
|
2594
2594
|
indexes: []
|
|
2595
2595
|
}, i = yield* e.onDialectOrElse({
|
|
2596
|
-
mysql: () =>
|
|
2597
|
-
mssql: () =>
|
|
2598
|
-
sqlite: () =>
|
|
2599
|
-
orElse: () =>
|
|
2596
|
+
mysql: () => H(e).pipe(C.map((e) => Hr(r, e))),
|
|
2597
|
+
mssql: () => C.succeed(Qr(r)),
|
|
2598
|
+
sqlite: () => C.succeed(qr(r)),
|
|
2599
|
+
orElse: () => C.succeed(Lr(r))
|
|
2600
2600
|
});
|
|
2601
|
-
yield*
|
|
2602
|
-
}),
|
|
2601
|
+
yield* C.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2602
|
+
}), Fi = (e) => e`
|
|
2603
2603
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2604
2604
|
${e("status")}, ${e("payload")}
|
|
2605
|
-
FROM ${e(
|
|
2606
|
-
`,
|
|
2605
|
+
FROM ${e(O)}
|
|
2606
|
+
`, Ii = (e, t, n, r) => C.gen(function* () {
|
|
2607
2607
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2608
|
-
yield*
|
|
2609
|
-
INSERT INTO ${e(
|
|
2608
|
+
yield* C.forEach(r, ({ index: r, planned: a }) => e`
|
|
2609
|
+
INSERT INTO ${e(O)}
|
|
2610
2610
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2611
2611
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2612
2612
|
${e("createdAt")})
|
|
2613
2613
|
VALUES
|
|
2614
2614
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2615
|
-
${a.op.kind}, ${
|
|
2615
|
+
${a.op.kind}, ${Ve(a.op)}, ${"pending"},
|
|
2616
2616
|
${JSON.stringify(a)}, ${i})
|
|
2617
2617
|
`, { discard: !0 });
|
|
2618
|
-
}),
|
|
2618
|
+
}), Li = (e, t, n, r, i) => C.gen(function* () {
|
|
2619
2619
|
let a = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2620
2620
|
if (r === "applied") {
|
|
2621
2621
|
yield* e`
|
|
2622
|
-
UPDATE ${e(
|
|
2622
|
+
UPDATE ${e(O)}
|
|
2623
2623
|
SET ${e("status")} = ${r}, ${e("appliedAt")} = ${a},
|
|
2624
2624
|
${e("durationMs")} = ${i ?? null}
|
|
2625
2625
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
@@ -2627,50 +2627,50 @@ BEGIN
|
|
|
2627
2627
|
return;
|
|
2628
2628
|
}
|
|
2629
2629
|
yield* e`
|
|
2630
|
-
UPDATE ${e(
|
|
2630
|
+
UPDATE ${e(O)}
|
|
2631
2631
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2632
2632
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2633
2633
|
`;
|
|
2634
|
-
}),
|
|
2634
|
+
}), Ri = (e, t, n, r) => C.gen(function* () {
|
|
2635
2635
|
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2636
2636
|
r.length > 0 && (yield* e`
|
|
2637
|
-
UPDATE ${e(
|
|
2637
|
+
UPDATE ${e(O)}
|
|
2638
2638
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
2639
2639
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(r)}
|
|
2640
2640
|
`), n.length > 0 && (yield* e`
|
|
2641
|
-
UPDATE ${e(
|
|
2641
|
+
UPDATE ${e(O)}
|
|
2642
2642
|
SET ${e("status")} = ${"pending"}
|
|
2643
2643
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2644
2644
|
`);
|
|
2645
|
-
}),
|
|
2646
|
-
if (
|
|
2647
|
-
let r = n.op, i = (e) =>
|
|
2645
|
+
}), zi = (e, t) => t === void 0 ? e`DELETE FROM ${e(O)}`.pipe(C.asVoid) : e`DELETE FROM ${e(O)} WHERE ${e("runId")} = ${t}`.pipe(C.asVoid), Bi = (e, t, n) => C.gen(function* () {
|
|
2646
|
+
if (Ye(n.op, n.classification, t) !== "artefact-repair") return "clean";
|
|
2647
|
+
let r = n.op, i = (e) => o(e, t);
|
|
2648
2648
|
if (t === "sqlite" || t === "turso") {
|
|
2649
2649
|
if (!("table" in r)) return "clean";
|
|
2650
|
-
let n = `${r.table}${
|
|
2651
|
-
return (yield* $(e, t, n)) ? ((yield* $(e, t, r.table)) ? yield* X(e, `DROP TABLE ${i(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${i(n)} RENAME TO ${i(r.table)}`, "resume-repair"), yield*
|
|
2650
|
+
let n = `${r.table}${We}`;
|
|
2651
|
+
return (yield* $(e, t, n)) ? ((yield* $(e, t, r.table)) ? yield* X(e, `DROP TABLE ${i(n)}`, "resume-repair") : yield* X(e, `ALTER TABLE ${i(n)} RENAME TO ${i(r.table)}`, "resume-repair"), yield* C.logWarning(`migration resume: reconciled an interrupted sqlite table rebuild on '${r.table}' — replaying the operation`).pipe(C.annotateLogs({ scope: "voltro:migrate" })), "outstanding") : "clean";
|
|
2652
2652
|
}
|
|
2653
2653
|
if (r.kind !== "alter-column-type") return "clean";
|
|
2654
|
-
let a = `${r.column}${
|
|
2655
|
-
return !
|
|
2656
|
-
}),
|
|
2657
|
-
let i = process.hrtime.bigint(), a =
|
|
2654
|
+
let a = `${r.column}${Ge}`, s = `${r.column}${Ke}`, c = yield* $(e, t, r.table, r.column), l = yield* $(e, t, r.table, a), u = yield* $(e, t, r.table, s), d = (e) => C.logWarning(`migration resume: ${e}`).pipe(C.annotateLogs({ scope: "voltro:migrate" }));
|
|
2655
|
+
return !l && !u ? "clean" : c && l && !u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(a)}`, "resume-repair"), yield* d(`dropped a half-populated shadow column '${r.table}.${a}' — replaying the type change`), "outstanding") : !c && l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} RENAME COLUMN ${i(a)} TO ${i(r.column)}`, "resume-repair"), yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`completed an interrupted shadow swap on '${r.table}.${r.column}'`), "applied") : c && !l && u ? (yield* X(e, `ALTER TABLE ${i(r.table)} DROP COLUMN ${i(s)}`, "resume-repair"), yield* d(`dropped the leftover pre-swap column '${r.table}.${s}'`), "applied") : yield* C.die(/* @__PURE__ */ Error(`applyPlan: an interrupted online type change on '${r.table}.${r.column}' left a shadow-swap state this resume cannot classify (column=${c}, ${a}=${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.`));
|
|
2656
|
+
}), Vi = (e, t, n, r = "fresh") => C.gen(function* () {
|
|
2657
|
+
let i = process.hrtime.bigint(), a = Ni(n.declared), o = t.op;
|
|
2658
2658
|
switch (o.kind) {
|
|
2659
2659
|
case "create-table": {
|
|
2660
2660
|
let t = yield* e.onDialectOrElse({
|
|
2661
|
-
mysql: () =>
|
|
2662
|
-
mssql: () =>
|
|
2663
|
-
sqlite: () =>
|
|
2664
|
-
orElse: () =>
|
|
2661
|
+
mysql: () => H(e).pipe(C.map((e) => Hr(o, e))),
|
|
2662
|
+
mssql: () => C.succeed(Qr(o)),
|
|
2663
|
+
sqlite: () => C.succeed(qr(o)),
|
|
2664
|
+
orElse: () => C.succeed(Lr(o))
|
|
2665
2665
|
}), n = yield* e.onDialectOrElse({
|
|
2666
|
-
mysql: () =>
|
|
2667
|
-
orElse: () =>
|
|
2666
|
+
mysql: () => C.succeed([dr]),
|
|
2667
|
+
orElse: () => C.succeed([])
|
|
2668
2668
|
});
|
|
2669
2669
|
for (let r of t) yield* X(e, r, o.kind, n);
|
|
2670
2670
|
break;
|
|
2671
2671
|
}
|
|
2672
2672
|
case "drop-table": {
|
|
2673
|
-
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ?
|
|
2673
|
+
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? ti(o, n, e) : ei(o, e);
|
|
2674
2674
|
yield* e.onDialectOrElse({
|
|
2675
2675
|
mysql: () => X(e, r(G), o.kind),
|
|
2676
2676
|
orElse: () => X(e, r(W), o.kind)
|
|
@@ -2680,92 +2680,92 @@ BEGIN
|
|
|
2680
2680
|
case "drop-column": {
|
|
2681
2681
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2682
2682
|
yield* e.onDialectOrElse({
|
|
2683
|
-
mysql: () =>
|
|
2684
|
-
sqlite: () => X(e, t ?
|
|
2685
|
-
orElse: () => X(e, t ?
|
|
2683
|
+
mysql: () => H(e).pipe(C.flatMap((r) => X(e, t ? Tr(o, n, G) : Cr(o, r), o.kind, t ? [] : [fr]))),
|
|
2684
|
+
sqlite: () => X(e, t ? Tr(o, n, W) : Sr(o, W, !1), o.kind, t ? [] : [pr]),
|
|
2685
|
+
orElse: () => X(e, t ? Tr(o, n, W) : Sr(o, W), o.kind)
|
|
2686
2686
|
});
|
|
2687
2687
|
break;
|
|
2688
2688
|
}
|
|
2689
2689
|
case "rename-column":
|
|
2690
2690
|
yield* e.onDialectOrElse({
|
|
2691
|
-
mysql: () => X(e,
|
|
2691
|
+
mysql: () => X(e, wr(o, G), o.kind),
|
|
2692
2692
|
mssql: () => X(e, `EXEC sp_rename N'${o.table.replace(/'/g, "''")}.${o.from.replace(/'/g, "''")}', N'${o.to.replace(/'/g, "''")}', 'COLUMN';`, o.kind),
|
|
2693
|
-
orElse: () => X(e,
|
|
2693
|
+
orElse: () => X(e, wr(o, W), o.kind)
|
|
2694
2694
|
});
|
|
2695
2695
|
break;
|
|
2696
2696
|
case "add-index":
|
|
2697
2697
|
yield* e.onDialectOrElse({
|
|
2698
|
-
mysql: () =>
|
|
2699
|
-
mssql: () => Z(e, [...
|
|
2700
|
-
orElse: () => X(e,
|
|
2698
|
+
mysql: () => H(e).pipe(C.flatMap((t) => X(e, oi(o, n.declared, t), o.kind, [dr]))),
|
|
2699
|
+
mssql: () => Z(e, [...gi(o.table, o.index.columns, n.declared), hi(o)], o.kind),
|
|
2700
|
+
orElse: () => X(e, ai(o, t.classification === "online-required"), o.kind)
|
|
2701
2701
|
});
|
|
2702
2702
|
break;
|
|
2703
2703
|
case "drop-index":
|
|
2704
2704
|
yield* e.onDialectOrElse({
|
|
2705
|
-
mysql: () => X(e,
|
|
2706
|
-
mssql: () => X(e,
|
|
2707
|
-
orElse: () => X(e,
|
|
2705
|
+
mysql: () => X(e, ci(o), o.kind),
|
|
2706
|
+
mssql: () => X(e, li(o), o.kind),
|
|
2707
|
+
orElse: () => X(e, si(o), o.kind)
|
|
2708
2708
|
});
|
|
2709
2709
|
break;
|
|
2710
2710
|
case "rename-table":
|
|
2711
2711
|
yield* e.onDialectOrElse({
|
|
2712
|
-
mysql: () => X(e,
|
|
2713
|
-
mssql: () => X(e,
|
|
2714
|
-
orElse: () => X(e,
|
|
2712
|
+
mysql: () => X(e, ui(o, G), o.kind),
|
|
2713
|
+
mssql: () => X(e, di(o), o.kind),
|
|
2714
|
+
orElse: () => X(e, ui(o, W), o.kind)
|
|
2715
2715
|
});
|
|
2716
2716
|
break;
|
|
2717
2717
|
case "rename-index":
|
|
2718
2718
|
yield* e.onDialectOrElse({
|
|
2719
|
-
mysql: () => X(e,
|
|
2720
|
-
mssql: () => X(e,
|
|
2721
|
-
orElse: () => X(e,
|
|
2719
|
+
mysql: () => X(e, pi(o), o.kind),
|
|
2720
|
+
mssql: () => X(e, mi(o), o.kind),
|
|
2721
|
+
orElse: () => X(e, fi(o), o.kind)
|
|
2722
2722
|
});
|
|
2723
2723
|
break;
|
|
2724
2724
|
case "add-unique":
|
|
2725
2725
|
yield* e.onDialectOrElse({
|
|
2726
|
-
mysql: () => X(e,
|
|
2726
|
+
mysql: () => X(e, vi(o, n.declared), o.kind),
|
|
2727
2727
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2728
|
-
mssql: () => Z(e, [...
|
|
2729
|
-
orElse: () => X(e,
|
|
2728
|
+
mssql: () => Z(e, [...gi(o.table, [o.column], n.declared), _i(o)], o.kind),
|
|
2729
|
+
orElse: () => X(e, _i(o), o.kind)
|
|
2730
2730
|
});
|
|
2731
2731
|
break;
|
|
2732
2732
|
case "drop-unique":
|
|
2733
2733
|
yield* e.onDialectOrElse({
|
|
2734
|
-
mysql: () => X(e,
|
|
2734
|
+
mysql: () => X(e, wi(o), o.kind),
|
|
2735
2735
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2736
|
-
orElse: () => X(e,
|
|
2736
|
+
orElse: () => X(e, Ci(o), o.kind)
|
|
2737
2737
|
});
|
|
2738
2738
|
break;
|
|
2739
2739
|
case "add-unique-composite":
|
|
2740
2740
|
yield* e.onDialectOrElse({
|
|
2741
|
-
mysql: () => X(e,
|
|
2741
|
+
mysql: () => X(e, bi(o, n.declared), o.kind),
|
|
2742
2742
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2743
|
-
mssql: () => Z(e, [...
|
|
2744
|
-
orElse: () => X(e,
|
|
2743
|
+
mssql: () => Z(e, [...gi(o.table, o.fields, n.declared), yi(o)], o.kind),
|
|
2744
|
+
orElse: () => X(e, yi(o), o.kind)
|
|
2745
2745
|
});
|
|
2746
2746
|
break;
|
|
2747
2747
|
case "drop-unique-composite":
|
|
2748
2748
|
yield* e.onDialectOrElse({
|
|
2749
|
-
mysql: () => X(e,
|
|
2749
|
+
mysql: () => X(e, Si(o), o.kind),
|
|
2750
2750
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2751
|
-
orElse: () => X(e,
|
|
2751
|
+
orElse: () => X(e, xi(o), o.kind)
|
|
2752
2752
|
});
|
|
2753
2753
|
break;
|
|
2754
2754
|
case "add-foreign-key":
|
|
2755
2755
|
yield* e.onDialectOrElse({
|
|
2756
|
-
mysql: () => Z(e,
|
|
2756
|
+
mysql: () => Z(e, Ti(o, G), o.kind),
|
|
2757
2757
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2758
|
-
orElse: () => Z(e,
|
|
2758
|
+
orElse: () => Z(e, Ti(o, W), o.kind)
|
|
2759
2759
|
});
|
|
2760
2760
|
break;
|
|
2761
2761
|
case "add-column": {
|
|
2762
|
-
let n =
|
|
2763
|
-
mysql: () =>
|
|
2764
|
-
mssql: () =>
|
|
2765
|
-
sqlite: () =>
|
|
2766
|
-
orElse: () =>
|
|
2762
|
+
let n = Mi(o, t, a, yield* e.onDialectOrElse({
|
|
2763
|
+
mysql: () => C.succeed("mariadb"),
|
|
2764
|
+
mssql: () => C.succeed("mssql"),
|
|
2765
|
+
sqlite: () => C.succeed("sqlite"),
|
|
2766
|
+
orElse: () => C.succeed("postgres")
|
|
2767
2767
|
}));
|
|
2768
|
-
if (!(r === "resume" && (yield* $(e,
|
|
2768
|
+
if (!(r === "resume" && (yield* $(e, Ie(e), o.table, o.column.name)))) for (let t of n.pre) yield* X(e, t, o.kind);
|
|
2769
2769
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2770
2770
|
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2771
2771
|
else {
|
|
@@ -2774,10 +2774,10 @@ BEGIN
|
|
|
2774
2774
|
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)}`;
|
|
2775
2775
|
if (s.length === 0) break;
|
|
2776
2776
|
let c = s.map((e) => e.id);
|
|
2777
|
-
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield*
|
|
2777
|
+
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, a += s.length, yield* C.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows`).pipe(C.annotateLogs({
|
|
2778
2778
|
scope: "voltro:migrate",
|
|
2779
2779
|
mode: "sql-batched"
|
|
2780
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2780
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* C.sleep(`${r} millis`));
|
|
2781
2781
|
}
|
|
2782
2782
|
}
|
|
2783
2783
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
@@ -2786,17 +2786,17 @@ BEGIN
|
|
|
2786
2786
|
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)}`;
|
|
2787
2787
|
if (s.length === 0) break;
|
|
2788
2788
|
for (let t of s) {
|
|
2789
|
-
let r = yield*
|
|
2789
|
+
let r = yield* C.tryPromise({
|
|
2790
2790
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2791
2791
|
catch: (e) => e
|
|
2792
|
-
}).pipe(
|
|
2792
|
+
}).pipe(C.orDie);
|
|
2793
2793
|
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2794
2794
|
}
|
|
2795
|
-
a += s.length, yield*
|
|
2795
|
+
a += s.length, yield* C.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows processed`).pipe(C.annotateLogs({
|
|
2796
2796
|
scope: "voltro:migrate",
|
|
2797
2797
|
table: o.table,
|
|
2798
2798
|
column: o.column.name
|
|
2799
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2799
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* C.sleep(`${r} millis`));
|
|
2800
2800
|
}
|
|
2801
2801
|
}
|
|
2802
2802
|
for (let t of n.post) yield* X(e, t, o.kind);
|
|
@@ -2806,43 +2806,43 @@ BEGIN
|
|
|
2806
2806
|
yield* e.onDialectOrElse({
|
|
2807
2807
|
mysql: () => {
|
|
2808
2808
|
let t = K(n.declared, o.table, o.column);
|
|
2809
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2809
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Ar(t, o.column, o.toNullable)};`, o.kind) : C.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.`));
|
|
2810
2810
|
},
|
|
2811
2811
|
mssql: () => {
|
|
2812
2812
|
let t = K(n.declared, o.table, o.column);
|
|
2813
|
-
return t ? X(e,
|
|
2813
|
+
return t ? X(e, Jr(t, o.column, o.table, o.toNullable), o.kind) : C.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2814
2814
|
},
|
|
2815
2815
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2816
2816
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2817
2817
|
});
|
|
2818
2818
|
break;
|
|
2819
2819
|
case "alter-column-default": {
|
|
2820
|
-
let t =
|
|
2820
|
+
let t = kr(n.declared, o.table, o.column), r = K(n.declared, o.table, o.column), i = (e) => o.hasDefault && r !== void 0 && Dr(r, e) ? r : void 0;
|
|
2821
2821
|
yield* e.onDialectOrElse({
|
|
2822
2822
|
mysql: () => {
|
|
2823
2823
|
let n = i("mariadb");
|
|
2824
|
-
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2824
|
+
return X(e, n ? `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Ar(n, o.column)};` : Er(o, G, (e) => jr(e, t)), o.kind);
|
|
2825
2825
|
},
|
|
2826
2826
|
mssql: () => {
|
|
2827
2827
|
let t = i("mssql");
|
|
2828
|
-
return X(e,
|
|
2828
|
+
return X(e, Yr(o, t ? Jr(t, o.column, o.table) : void 0), o.kind);
|
|
2829
2829
|
},
|
|
2830
2830
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2831
|
-
orElse: () => X(e,
|
|
2831
|
+
orElse: () => X(e, Er(o, W, (e) => Nr(e, t)), o.kind)
|
|
2832
2832
|
});
|
|
2833
2833
|
break;
|
|
2834
2834
|
}
|
|
2835
2835
|
case "alter-column-type": {
|
|
2836
|
-
let r =
|
|
2836
|
+
let r = vr(kr(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2837
2837
|
if (t.classification !== "online-required") {
|
|
2838
2838
|
yield* e.onDialectOrElse({
|
|
2839
2839
|
mysql: () => {
|
|
2840
2840
|
let t = K(n.declared, o.table, o.column);
|
|
2841
|
-
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${
|
|
2841
|
+
return t ? X(e, `ALTER TABLE ${G(o.table)} MODIFY COLUMN ${Ar(t, o.column)};`, o.kind) : C.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.`));
|
|
2842
2842
|
},
|
|
2843
2843
|
mssql: () => {
|
|
2844
2844
|
let t = K(n.declared, o.table, o.column);
|
|
2845
|
-
return t ? X(e,
|
|
2845
|
+
return t ? X(e, Jr(t, o.column, o.table), o.kind) : C.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${o.table}.${o.column}'.`));
|
|
2846
2846
|
},
|
|
2847
2847
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2848
2848
|
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} TYPE ${r}${i};`, o.kind)
|
|
@@ -2850,8 +2850,8 @@ BEGIN
|
|
|
2850
2850
|
break;
|
|
2851
2851
|
}
|
|
2852
2852
|
yield* e.onDialectOrElse({
|
|
2853
|
-
mysql: () =>
|
|
2854
|
-
orElse: () =>
|
|
2853
|
+
mysql: () => C.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.`)),
|
|
2854
|
+
orElse: () => C.void
|
|
2855
2855
|
});
|
|
2856
2856
|
let a = `${o.column}__shadow`, s = `${o.column}__old`;
|
|
2857
2857
|
yield* e.unsafe(`ALTER TABLE ${W(o.table)} ADD COLUMN ${W(a)} ${r}`);
|
|
@@ -2861,27 +2861,27 @@ BEGIN
|
|
|
2861
2861
|
if (t.length === 0) break;
|
|
2862
2862
|
yield* e.unsafe(`UPDATE ${W(o.table)} SET ${W(a)} = ${c} WHERE ${W(o.column)} IS NOT NULL AND ${W(a)} IS NULL AND ${W("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
|
|
2863
2863
|
}
|
|
2864
|
-
yield*
|
|
2864
|
+
yield* C.logInfo(`alter-column-type shadow ${o.table}.${o.column}: shadow populated`).pipe(C.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${W(o.table)} RENAME COLUMN ${W(o.column)} TO ${W(s)}`), yield* e.unsafe(`ALTER TABLE ${W(o.table)} RENAME COLUMN ${W(a)} TO ${W(o.column)}`), yield* e.unsafe(`ALTER TABLE ${W(o.table)} DROP COLUMN ${W(s)}`);
|
|
2865
2865
|
break;
|
|
2866
2866
|
}
|
|
2867
2867
|
case "drop-foreign-key":
|
|
2868
2868
|
yield* e.onDialectOrElse({
|
|
2869
|
-
mysql: () => X(e,
|
|
2869
|
+
mysql: () => X(e, Di(o), o.kind),
|
|
2870
2870
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2871
|
-
orElse: () => X(e,
|
|
2871
|
+
orElse: () => X(e, Ei(o), o.kind)
|
|
2872
2872
|
});
|
|
2873
2873
|
break;
|
|
2874
2874
|
case "add-check":
|
|
2875
2875
|
yield* e.onDialectOrElse({
|
|
2876
|
-
mysql: () => X(e,
|
|
2876
|
+
mysql: () => X(e, Oi(o, G), o.kind),
|
|
2877
2877
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2878
|
-
orElse: () => X(e,
|
|
2878
|
+
orElse: () => X(e, Oi(o, W), o.kind)
|
|
2879
2879
|
});
|
|
2880
2880
|
break;
|
|
2881
2881
|
case "drop-check": yield* e.onDialectOrElse({
|
|
2882
|
-
mysql: () =>
|
|
2882
|
+
mysql: () => ji(e, o, n.declared),
|
|
2883
2883
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2884
|
-
orElse: () => X(e,
|
|
2884
|
+
orElse: () => X(e, ki(o), o.kind)
|
|
2885
2885
|
});
|
|
2886
2886
|
}
|
|
2887
2887
|
return {
|
|
@@ -2889,32 +2889,32 @@ BEGIN
|
|
|
2889
2889
|
status: "applied",
|
|
2890
2890
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2891
2891
|
};
|
|
2892
|
-
}),
|
|
2892
|
+
}), Hi = (e, t, n, r) => C.gen(function* () {
|
|
2893
2893
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2894
|
-
if (i.length > 1) return yield*
|
|
2894
|
+
if (i.length > 1) return yield* C.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.`));
|
|
2895
2895
|
let a = i[0], o = [...r].map((e) => ({
|
|
2896
2896
|
index: Number(e.opIndex),
|
|
2897
2897
|
status: e.status,
|
|
2898
2898
|
planned: JSON.parse(e.payload)
|
|
2899
2899
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
2900
|
-
if (c > 1) return yield*
|
|
2901
|
-
if (yield*
|
|
2900
|
+
if (c > 1) return yield* C.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.`));
|
|
2901
|
+
if (yield* C.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} ${Ve(s.planned.op)}` : ""}`).pipe(C.annotateLogs({ scope: "voltro:migrate" })), o.every((e) => e.status === "pending")) return {
|
|
2902
2902
|
kind: "discard",
|
|
2903
2903
|
runId: a,
|
|
2904
2904
|
why: "no operation had started — no DDL ran"
|
|
2905
2905
|
};
|
|
2906
|
-
let l = s ? yield*
|
|
2906
|
+
let l = s ? yield* Bi(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2907
2907
|
if (u !== n.toFingerprint) return {
|
|
2908
2908
|
kind: "discard",
|
|
2909
2909
|
runId: a,
|
|
2910
2910
|
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`
|
|
2911
2911
|
};
|
|
2912
|
-
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" :
|
|
2912
|
+
let d = (e) => e.status === "applied" ? !1 : s && e.index === s.index && l !== "clean" ? l === "outstanding" : Ue(n, e.planned.op), f = o.filter(d), p = o.filter((e) => e.status !== "applied" && !d(e));
|
|
2913
2913
|
return f.length === 0 ? {
|
|
2914
2914
|
kind: "discard",
|
|
2915
2915
|
runId: a,
|
|
2916
2916
|
why: "every recorded operation had already taken effect"
|
|
2917
|
-
} : (yield*
|
|
2917
|
+
} : (yield* Ri(e, a, f.map((e) => e.index), p.map((e) => e.index)), yield* C.logWarning(`migration resume: continuing run ${a} — replaying ${f.length} operation(s), ${o.length - f.length} already applied`).pipe(C.annotateLogs({ scope: "voltro:migrate" })), {
|
|
2918
2918
|
kind: "resume",
|
|
2919
2919
|
runId: a,
|
|
2920
2920
|
ops: f.map((e) => ({
|
|
@@ -2922,7 +2922,7 @@ BEGIN
|
|
|
2922
2922
|
planned: e.planned
|
|
2923
2923
|
}))
|
|
2924
2924
|
});
|
|
2925
|
-
}),
|
|
2925
|
+
}), Ui = (e) => {
|
|
2926
2926
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
2927
2927
|
return [
|
|
2928
2928
|
t.kind,
|
|
@@ -2931,64 +2931,64 @@ BEGIN
|
|
|
2931
2931
|
n("name"),
|
|
2932
2932
|
n("to")
|
|
2933
2933
|
].join("\0");
|
|
2934
|
-
},
|
|
2934
|
+
}, Wi = (e, t, n) => C.gen(function* () {
|
|
2935
2935
|
let r = t.operations.filter((e) => e.blocked);
|
|
2936
|
-
if (r.length > 0) return yield*
|
|
2937
|
-
yield*
|
|
2938
|
-
let i = Date.now(), a = [], o =
|
|
2936
|
+
if (r.length > 0) return yield* C.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
|
|
2937
|
+
yield* Pe(e, { schema: n.lockSchema });
|
|
2938
|
+
let i = Date.now(), a = [], o = Ie(e), s = yield* n.replan(e), c = new Set(t.operations.filter((e) => !e.blocked).map((e) => Ui(e))), l = {
|
|
2939
2939
|
...s,
|
|
2940
2940
|
operations: s.operations.map((e) => {
|
|
2941
|
-
if (!e.blocked || !c.has(
|
|
2941
|
+
if (!e.blocked || !c.has(Ui(e))) return e;
|
|
2942
2942
|
let { blocked: t, ...n } = e;
|
|
2943
2943
|
return n;
|
|
2944
2944
|
})
|
|
2945
2945
|
};
|
|
2946
|
-
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield*
|
|
2946
|
+
(l.operations.length !== t.operations.length || l.toFingerprint !== t.toFingerprint) && (yield* C.logInfo(`migration: re-planned under the lock — ${t.operations.length} operation(s) became ${l.operations.length}. Another writer changed the schema while this plan waited.`).pipe(C.annotateLogs({ scope: "voltro:migrate" })));
|
|
2947
2947
|
let u = l.operations.filter((e) => e.blocked);
|
|
2948
|
-
if (u.length > 0) return yield*
|
|
2949
|
-
let d =
|
|
2948
|
+
if (u.length > 0) return yield* D(e, { schema: n.lockSchema }).pipe(C.orDie), yield* C.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — re-planning under the migration lock found ${u.length} blocked operation(s). Run \`voltro db plan\` to see the fixes.`));
|
|
2949
|
+
let d = Re(o) === "plan-transactional", f = d ? l.operations.filter((e) => e.classification !== "online-required") : [], p = d ? l.operations.filter((e) => e.classification === "online-required") : l.operations, m = `plan_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, h = p.map((e, t) => ({
|
|
2950
2950
|
index: t,
|
|
2951
2951
|
planned: e
|
|
2952
|
-
})),
|
|
2952
|
+
})), _ = "fresh";
|
|
2953
2953
|
try {
|
|
2954
|
-
yield*
|
|
2955
|
-
let t = yield*
|
|
2954
|
+
yield* Pi(e, o);
|
|
2955
|
+
let t = yield* Fi(e);
|
|
2956
2956
|
if (t.length > 0) {
|
|
2957
|
-
let n = yield*
|
|
2958
|
-
n.kind === "resume" ? (m = n.runId, h = n.ops,
|
|
2957
|
+
let n = yield* Hi(e, o, l, t);
|
|
2958
|
+
n.kind === "resume" ? (m = n.runId, h = n.ops, _ = "resume") : (yield* C.logWarning(`migration resume: discarding the ledger of run ${n.runId} — ${n.why}`).pipe(C.annotateLogs({ scope: "voltro:migrate" })), yield* zi(e, n.runId));
|
|
2959
2959
|
}
|
|
2960
|
-
|
|
2960
|
+
_ === "fresh" && h.length > 0 && (yield* Ii(e, m, l.toFingerprint, h)), f.length > 0 && (yield* e.withTransaction(C.gen(function* () {
|
|
2961
2961
|
let e = yield* T.SqlClient;
|
|
2962
|
-
for (let t of f) a.push(yield*
|
|
2962
|
+
for (let t of f) a.push(yield* Vi(e, t, n));
|
|
2963
2963
|
})));
|
|
2964
2964
|
for (let { index: t, planned: r } of h) {
|
|
2965
|
-
yield*
|
|
2966
|
-
let i = a.length, o = yield*
|
|
2967
|
-
a.push(o), yield*
|
|
2965
|
+
yield* Li(e, m, t, "started");
|
|
2966
|
+
let i = a.length, o = yield* Vi(e, r, n, _).pipe(C.mapError((e) => Object.assign(e, { message: `${String(e?.message ?? e)}\n\n progress: ${i} of ${h.length + f.length} operation(s) applied before this one${f.length > 0 ? ` (${f.length} of them in a transaction)` : ""}.\n` + (d ? " This dialect applies a plan atomically, so the run is rolled back.\n" : ` This dialect does NOT apply a plan atomically: those ${i} are COMMITTED and there is no rollback.\n The next \`voltro db apply\` resumes from operation ${t} — the ledger records the sequence.\n`) })));
|
|
2967
|
+
a.push(o), yield* Li(e, m, t, "applied", o.durationMs);
|
|
2968
2968
|
}
|
|
2969
2969
|
} finally {
|
|
2970
|
-
yield*
|
|
2970
|
+
yield* D(e, { schema: n.lockSchema }).pipe(C.orDie);
|
|
2971
2971
|
}
|
|
2972
|
-
let
|
|
2973
|
-
if (
|
|
2974
|
-
let e =
|
|
2975
|
-
return yield*
|
|
2972
|
+
let v = yield* n.replan(e);
|
|
2973
|
+
if (v.operations.length > 0) {
|
|
2974
|
+
let e = v.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");
|
|
2975
|
+
return yield* C.die(/* @__PURE__ */ Error(`applyPlan: the migration did not converge. ${l.operations.length} operation(s) were executed without error, but re-planning against the live schema still finds ${v.operations.length}:\n${e}${v.operations.length > 10 ? `\n … and ${v.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.`));
|
|
2976
2976
|
}
|
|
2977
|
-
let y = a.filter((e) => e.status === "applied").length, b = Date.now() - i, x = m,
|
|
2977
|
+
let y = a.filter((e) => e.status === "applied").length, b = Date.now() - i, x = m, S = (/* @__PURE__ */ new Date()).toISOString(), ee = yield* U(e, S), w = [...f, ...h.map((e) => e.planned)];
|
|
2978
2978
|
yield* e`
|
|
2979
2979
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2980
2980
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
2981
2981
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
2982
2982
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
2983
2983
|
VALUES
|
|
2984
|
-
(${x}, ${l.toFingerprint}, ${
|
|
2984
|
+
(${x}, ${l.toFingerprint}, ${v.fromFingerprint}, ${JSON.stringify(w)},
|
|
2985
2985
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2986
2986
|
${b}, ${ee}, ${n.notes ?? null})
|
|
2987
|
-
`, yield*
|
|
2987
|
+
`, yield* zi(e, m);
|
|
2988
2988
|
let te = [...new Set(w.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
2989
|
-
return yield*
|
|
2989
|
+
return yield* C.promise(() => g({ changedTables: te }).catch(() => {})), {
|
|
2990
2990
|
id: x,
|
|
2991
|
-
appliedAt:
|
|
2991
|
+
appliedAt: S,
|
|
2992
2992
|
fingerprint: l.toFingerprint,
|
|
2993
2993
|
operations: w,
|
|
2994
2994
|
appliedBy: n.appliedBy,
|
|
@@ -2998,13 +2998,13 @@ BEGIN
|
|
|
2998
2998
|
source: n.source,
|
|
2999
2999
|
...n.notes ? { notes: n.notes } : {}
|
|
3000
3000
|
};
|
|
3001
|
-
}),
|
|
3001
|
+
}), Gi = (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"), Ki = (e) => e`
|
|
3002
3002
|
SELECT fingerprint
|
|
3003
3003
|
FROM _voltro_migration_plans
|
|
3004
3004
|
ORDER BY ${e("appliedAt")} DESC
|
|
3005
3005
|
LIMIT 1
|
|
3006
|
-
`.pipe(
|
|
3007
|
-
if ((yield*
|
|
3006
|
+
`.pipe(C.map((e) => e.length > 0 ? e[0].fingerprint : void 0), C.catchAll(() => C.succeed(void 0))), qi = (e, t, n) => C.gen(function* () {
|
|
3007
|
+
if ((yield* Ki(e)) === t.toFingerprint) return "already-current";
|
|
3008
3008
|
let r = `plan_${Date.now().toString(36)}`, i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
3009
3009
|
return yield* e`
|
|
3010
3010
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3016,8 +3016,8 @@ BEGIN
|
|
|
3016
3016
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3017
3017
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3018
3018
|
`, "recorded";
|
|
3019
|
-
}).pipe(
|
|
3020
|
-
let n =
|
|
3019
|
+
}).pipe(C.catchAll(() => C.succeed("already-current"))), Ji = (e, t) => C.gen(function* () {
|
|
3020
|
+
let n = Jt(F(t, Ie(e))), r = yield* Ki(e);
|
|
3021
3021
|
return r === n ? {
|
|
3022
3022
|
kind: "up-to-date",
|
|
3023
3023
|
fingerprint: n
|
|
@@ -3026,23 +3026,23 @@ BEGIN
|
|
|
3026
3026
|
expected: n,
|
|
3027
3027
|
...r === void 0 ? {} : { actual: r }
|
|
3028
3028
|
};
|
|
3029
|
-
}),
|
|
3029
|
+
}), Yi = [
|
|
3030
3030
|
"pgeagertest_",
|
|
3031
3031
|
"mig_e2e_",
|
|
3032
3032
|
"mig_test_",
|
|
3033
3033
|
"mysqleagertest_",
|
|
3034
3034
|
"mssqleagertest_",
|
|
3035
3035
|
"sqliteeagertest_"
|
|
3036
|
-
],
|
|
3036
|
+
], Xi = (e) => Yi.some((t) => e.startsWith(t)), Zi = (e, t) => C.gen(function* () {
|
|
3037
3037
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3038
|
-
let n = t.filter((e) =>
|
|
3038
|
+
let n = t.filter((e) => Xi(e.name)).map((e) => e.name);
|
|
3039
3039
|
if (n.length === 0) return [];
|
|
3040
|
-
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(
|
|
3040
|
+
for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(C.catchAll(() => C.void));
|
|
3041
3041
|
return n;
|
|
3042
|
-
}),
|
|
3042
|
+
}), Qi = () => {
|
|
3043
3043
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3044
3044
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3045
|
-
},
|
|
3045
|
+
}, $i = (e) => {
|
|
3046
3046
|
if (e === void 0) return;
|
|
3047
3047
|
let t = e.trim();
|
|
3048
3048
|
if (t === "") return;
|
|
@@ -3052,87 +3052,94 @@ BEGIN
|
|
|
3052
3052
|
kind: "tables",
|
|
3053
3053
|
tables: new Set(n)
|
|
3054
3054
|
} : void 0;
|
|
3055
|
-
},
|
|
3055
|
+
}, ea = (e) => typeof e.table == "string" ? e.table : void 0, ta = (e, t = { kind: "all" }) => ({
|
|
3056
3056
|
...e,
|
|
3057
3057
|
operations: e.operations.map((e) => {
|
|
3058
3058
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3059
3059
|
if (t?.kind === "tables") {
|
|
3060
|
-
let n =
|
|
3060
|
+
let n = ea(e.op);
|
|
3061
3061
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3062
3062
|
}
|
|
3063
3063
|
let { blocked: n, ...r } = e;
|
|
3064
3064
|
return r;
|
|
3065
3065
|
})
|
|
3066
|
-
}),
|
|
3067
|
-
let t =
|
|
3068
|
-
return t === void 0 ?
|
|
3069
|
-
}),
|
|
3070
|
-
let r =
|
|
3066
|
+
}), na = (e, t, n) => t === "postgres" ? en(e, n).pipe(C.flatMap((e) => {
|
|
3067
|
+
let t = tn(e);
|
|
3068
|
+
return t === void 0 ? C.void : C.logWarning(`auto-migrate: ${t}`).pipe(C.annotateLogs({ scope: "voltro:migrate" }));
|
|
3069
|
+
}), C.catchAll(() => C.void)) : C.void, ra = (e, t, n) => C.gen(function* () {
|
|
3070
|
+
let r = Ie(e), a = t;
|
|
3071
3071
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3072
|
-
let t =
|
|
3073
|
-
if ((yield*
|
|
3072
|
+
let t = Jt(F(a, r));
|
|
3073
|
+
if ((yield* Ki(e)) === t) return yield* na(e, r, a), {
|
|
3074
3074
|
kind: "up-to-date",
|
|
3075
3075
|
fingerprint: t
|
|
3076
3076
|
};
|
|
3077
3077
|
}
|
|
3078
|
-
let
|
|
3079
|
-
|
|
3078
|
+
let o = yield* ir(e), s = yield* Zi(e, o.tables);
|
|
3079
|
+
s.length > 0 && (yield* C.logInfo(`auto-migrate: reaped ${s.length} test-fixture leftover(s)`).pipe(C.annotateLogs({
|
|
3080
3080
|
scope: "voltro:migrate",
|
|
3081
|
-
count:
|
|
3082
|
-
})),
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3081
|
+
count: s.length
|
|
3082
|
+
})), o = yield* ir(e));
|
|
3083
|
+
{
|
|
3084
|
+
let e = n.softDropRetentionDays ?? 7, t = p(o, { retentionDays: e });
|
|
3085
|
+
t.length > 0 && (yield* C.logWarning(`auto-migrate: ${i(t, e)}`).pipe(C.annotateLogs({
|
|
3086
|
+
scope: "voltro:migrate",
|
|
3087
|
+
snapshots: t.map((e) => e.name)
|
|
3088
|
+
})));
|
|
3089
|
+
}
|
|
3090
|
+
let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !_(e.name) || c.has(e.name)), u = Ln({
|
|
3091
|
+
declared: a,
|
|
3092
|
+
live: { tables: l(o.tables) },
|
|
3086
3093
|
dialect: r,
|
|
3087
|
-
...
|
|
3094
|
+
...Qi()
|
|
3088
3095
|
});
|
|
3089
|
-
if (
|
|
3090
|
-
let e =
|
|
3091
|
-
if (t === void 0 || !e || (
|
|
3096
|
+
if (u.summary.blocked > 0) {
|
|
3097
|
+
let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = $i(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
3098
|
+
if (t === void 0 || !e || (u = ta(u, t), u.operations.some((e) => e.blocked))) return {
|
|
3092
3099
|
kind: "refused-blocked",
|
|
3093
|
-
plan:
|
|
3100
|
+
plan: u
|
|
3094
3101
|
};
|
|
3095
3102
|
}
|
|
3096
|
-
return
|
|
3103
|
+
return u.operations.length === 0 ? (yield* qi(e, u, {
|
|
3097
3104
|
appliedBy: n.appliedBy,
|
|
3098
3105
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3099
3106
|
source: "auto-diff"
|
|
3100
3107
|
}), {
|
|
3101
3108
|
kind: "up-to-date",
|
|
3102
|
-
fingerprint:
|
|
3109
|
+
fingerprint: u.toFingerprint
|
|
3103
3110
|
}) : {
|
|
3104
3111
|
kind: "applied",
|
|
3105
|
-
applied: yield*
|
|
3112
|
+
applied: yield* Wi(e, u, {
|
|
3106
3113
|
declared: t,
|
|
3107
3114
|
appliedBy: n.appliedBy,
|
|
3108
3115
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3109
3116
|
source: "auto-diff",
|
|
3110
|
-
replan: (e) =>
|
|
3111
|
-
let t = yield*
|
|
3112
|
-
return
|
|
3113
|
-
declared:
|
|
3114
|
-
live: { tables:
|
|
3117
|
+
replan: (e) => C.gen(function* () {
|
|
3118
|
+
let t = yield* ir(e);
|
|
3119
|
+
return Ln({
|
|
3120
|
+
declared: a,
|
|
3121
|
+
live: { tables: l(t.tables) },
|
|
3115
3122
|
dialect: r,
|
|
3116
|
-
...
|
|
3123
|
+
...Qi()
|
|
3117
3124
|
});
|
|
3118
3125
|
})
|
|
3119
3126
|
}),
|
|
3120
|
-
plan:
|
|
3127
|
+
plan: u
|
|
3121
3128
|
};
|
|
3122
|
-
}),
|
|
3129
|
+
}), ia = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? C.succeed({
|
|
3123
3130
|
kind: "skipped",
|
|
3124
3131
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3125
|
-
}) : n.environment === "prod" ?
|
|
3132
|
+
}) : n.environment === "prod" ? Ji(e, t) : ra(e, t, n), aa = (e, t) => {
|
|
3126
3133
|
switch (e.kind) {
|
|
3127
3134
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3128
|
-
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${
|
|
3135
|
+
case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${Yt(e.fingerprint)})`;
|
|
3129
3136
|
case "applied": {
|
|
3130
3137
|
let t = e.plan.summary;
|
|
3131
|
-
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=${
|
|
3138
|
+
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=${Yt(e.applied.fingerprint)}`;
|
|
3132
3139
|
}
|
|
3133
|
-
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${
|
|
3140
|
+
case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${Yt(e.expected)}` + (e.actual ? ` live=${Yt(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
|
|
3134
3141
|
case "refused-blocked": {
|
|
3135
|
-
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` +
|
|
3142
|
+
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` + Gi(e.plan), c = [""];
|
|
3136
3143
|
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) {
|
|
3137
3144
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3138
3145
|
for (let r of e.plan.operations) {
|
|
@@ -3149,7 +3156,7 @@ BEGIN
|
|
|
3149
3156
|
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");
|
|
3150
3157
|
}
|
|
3151
3158
|
}
|
|
3152
|
-
},
|
|
3159
|
+
}, oa = ne({ scope: "voltro:migrate" }), sa = /* @__PURE__ */ new Set([
|
|
3153
3160
|
"node_modules",
|
|
3154
3161
|
"dist",
|
|
3155
3162
|
"build",
|
|
@@ -3158,25 +3165,25 @@ BEGIN
|
|
|
3158
3165
|
".next",
|
|
3159
3166
|
".git",
|
|
3160
3167
|
".framework"
|
|
3161
|
-
]),
|
|
3168
|
+
]), ca = async (e) => {
|
|
3162
3169
|
let t = [], n = async (e) => {
|
|
3163
|
-
let r = await
|
|
3170
|
+
let r = await re.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3164
3171
|
for (let i of r) {
|
|
3165
|
-
if (
|
|
3166
|
-
let r =
|
|
3167
|
-
i.isDirectory() ? await n(r) : i.isFile() &&
|
|
3172
|
+
if (sa.has(i.name)) continue;
|
|
3173
|
+
let r = ie(e, i.name);
|
|
3174
|
+
i.isDirectory() ? await n(r) : i.isFile() && S.test(i.name) && t.push(r);
|
|
3168
3175
|
}
|
|
3169
3176
|
};
|
|
3170
3177
|
return await n(e), t.sort((e, t) => {
|
|
3171
3178
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3172
3179
|
return n.localeCompare(r);
|
|
3173
3180
|
});
|
|
3174
|
-
},
|
|
3181
|
+
}, la = async (e) => {
|
|
3175
3182
|
let t = [];
|
|
3176
3183
|
for (let n of e) {
|
|
3177
|
-
let e = (await import(
|
|
3178
|
-
if (!
|
|
3179
|
-
|
|
3184
|
+
let e = (await import(ae(n).href)).default;
|
|
3185
|
+
if (!u(e)) {
|
|
3186
|
+
oa.warn("migration file has no default-exported `migration(...)` — skipped", { file: n });
|
|
3180
3187
|
continue;
|
|
3181
3188
|
}
|
|
3182
3189
|
t.push({
|
|
@@ -3185,11 +3192,11 @@ BEGIN
|
|
|
3185
3192
|
});
|
|
3186
3193
|
}
|
|
3187
3194
|
return t;
|
|
3188
|
-
},
|
|
3195
|
+
}, ua = (e) => e`
|
|
3189
3196
|
SELECT ${e("id")}
|
|
3190
3197
|
FROM ${e("_voltro_migration_plans")}
|
|
3191
3198
|
WHERE ${e("source")} = 'file'
|
|
3192
|
-
`.pipe(
|
|
3199
|
+
`.pipe(C.map((e) => e.map((e) => e.id)), C.catchAll(() => C.succeed([]))), da = class extends Error {
|
|
3193
3200
|
migrationId;
|
|
3194
3201
|
file;
|
|
3195
3202
|
cause;
|
|
@@ -3197,27 +3204,27 @@ BEGIN
|
|
|
3197
3204
|
constructor(e, t, n) {
|
|
3198
3205
|
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";
|
|
3199
3206
|
}
|
|
3200
|
-
},
|
|
3207
|
+
}, fa = (e, t, n, r) => C.gen(function* () {
|
|
3201
3208
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3202
3209
|
sql: e,
|
|
3203
3210
|
log: {
|
|
3204
|
-
info: (e, n) =>
|
|
3211
|
+
info: (e, n) => C.logInfo(e).pipe(C.annotateLogs({
|
|
3205
3212
|
scope: `migrations:file:${t.migration.id}`,
|
|
3206
3213
|
...n ?? {}
|
|
3207
3214
|
})),
|
|
3208
|
-
warn: (e, n) =>
|
|
3215
|
+
warn: (e, n) => C.logWarning(e).pipe(C.annotateLogs({
|
|
3209
3216
|
scope: `migrations:file:${t.migration.id}`,
|
|
3210
3217
|
...n ?? {}
|
|
3211
3218
|
}))
|
|
3212
3219
|
},
|
|
3213
3220
|
appliedAt: a
|
|
3214
3221
|
}, s = t.migration.up(o);
|
|
3215
|
-
|
|
3222
|
+
C.isEffect(s) ? yield* s : yield* C.tryPromise({
|
|
3216
3223
|
try: () => s,
|
|
3217
3224
|
catch: (e) => e
|
|
3218
3225
|
});
|
|
3219
3226
|
let c = Date.now() - i;
|
|
3220
|
-
!
|
|
3227
|
+
!C.isEffect(s) && c < 2 && (yield* C.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(C.annotateLogs({ scope: `migrations:file:${t.migration.id}` })));
|
|
3221
3228
|
let l = yield* U(e, a);
|
|
3222
3229
|
return yield* e`
|
|
3223
3230
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
@@ -3231,94 +3238,94 @@ BEGIN
|
|
|
3231
3238
|
}])},
|
|
3232
3239
|
${r}, ${n}, ${"file"},
|
|
3233
3240
|
${c}, ${l}, ${t.migration.description})
|
|
3234
|
-
`.pipe(
|
|
3235
|
-
}),
|
|
3236
|
-
let n = yield*
|
|
3237
|
-
try: () =>
|
|
3241
|
+
`.pipe(C.mapError((e) => new da(t.migration.id, t.file, e))), { durationMs: c };
|
|
3242
|
+
}), pa = (e, t) => C.gen(function* () {
|
|
3243
|
+
let n = yield* C.tryPromise({
|
|
3244
|
+
try: () => ca(ie(t, "migrations")),
|
|
3238
3245
|
catch: (e) => e
|
|
3239
3246
|
});
|
|
3240
3247
|
if (n.length === 0) return {
|
|
3241
3248
|
pending: [],
|
|
3242
3249
|
skipped: []
|
|
3243
3250
|
};
|
|
3244
|
-
let r = yield*
|
|
3245
|
-
try: () =>
|
|
3251
|
+
let r = yield* C.tryPromise({
|
|
3252
|
+
try: () => la(n),
|
|
3246
3253
|
catch: (e) => e
|
|
3247
3254
|
});
|
|
3248
3255
|
if (r.length === 0) return {
|
|
3249
3256
|
pending: [],
|
|
3250
3257
|
skipped: []
|
|
3251
3258
|
};
|
|
3252
|
-
let i = new Set(yield*
|
|
3259
|
+
let i = new Set(yield* ua(e));
|
|
3253
3260
|
return {
|
|
3254
3261
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3255
3262
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3256
3263
|
};
|
|
3257
|
-
}),
|
|
3258
|
-
let { pending: n, skipped: r } = yield*
|
|
3264
|
+
}), ma = (e, t) => pa(e, t).pipe(C.map((e) => e.pending.map((e) => e.migration.id))), ha = (e, t) => C.gen(function* () {
|
|
3265
|
+
let { pending: n, skipped: r } = yield* pa(e, t.projectRoot);
|
|
3259
3266
|
if (n.length === 0) return {
|
|
3260
3267
|
applied: [],
|
|
3261
3268
|
skipped: r
|
|
3262
3269
|
};
|
|
3263
|
-
yield*
|
|
3270
|
+
yield* Pe(e, { schema: t.lockSchema });
|
|
3264
3271
|
let i = [];
|
|
3265
3272
|
try {
|
|
3266
3273
|
for (let r of n) {
|
|
3267
|
-
yield*
|
|
3274
|
+
yield* C.logInfo("file-based migration applying").pipe(C.annotateLogs({
|
|
3268
3275
|
scope: "voltro:migrate",
|
|
3269
3276
|
id: r.migration.id,
|
|
3270
3277
|
file: r.file
|
|
3271
3278
|
}));
|
|
3272
|
-
let { durationMs: n } = yield*
|
|
3279
|
+
let { durationMs: n } = yield* fa(e, r, t.env, t.appliedBy);
|
|
3273
3280
|
i.push({
|
|
3274
3281
|
id: r.migration.id,
|
|
3275
3282
|
durationMs: n
|
|
3276
|
-
}), yield*
|
|
3283
|
+
}), yield* C.logInfo("file-based migration applied").pipe(C.annotateLogs({
|
|
3277
3284
|
scope: "voltro:migrate",
|
|
3278
3285
|
id: r.migration.id,
|
|
3279
3286
|
durationMs: n
|
|
3280
3287
|
}));
|
|
3281
3288
|
}
|
|
3282
3289
|
} finally {
|
|
3283
|
-
yield*
|
|
3290
|
+
yield* D(e, { schema: t.lockSchema }).pipe(C.orDie);
|
|
3284
3291
|
}
|
|
3285
3292
|
return {
|
|
3286
3293
|
applied: i,
|
|
3287
3294
|
skipped: r
|
|
3288
3295
|
};
|
|
3289
|
-
}),
|
|
3296
|
+
}), ga = (e, t) => e`
|
|
3290
3297
|
SELECT ${e("id")}
|
|
3291
3298
|
FROM ${e("_voltro_migration_plans")}
|
|
3292
3299
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3293
3300
|
LIMIT 1
|
|
3294
|
-
`,
|
|
3295
|
-
if (!(yield*
|
|
3296
|
-
let n = yield*
|
|
3297
|
-
try: () =>
|
|
3301
|
+
`, _a = (e, t) => C.gen(function* () {
|
|
3302
|
+
if (!(yield* ga(e, t.id))[0]) return yield* C.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
|
|
3303
|
+
let n = yield* C.tryPromise({
|
|
3304
|
+
try: () => ca(ie(t.projectRoot, "migrations")),
|
|
3298
3305
|
catch: (e) => e
|
|
3299
|
-
}), r = (yield*
|
|
3300
|
-
try: () =>
|
|
3306
|
+
}), r = (yield* C.tryPromise({
|
|
3307
|
+
try: () => la(n),
|
|
3301
3308
|
catch: (e) => e
|
|
3302
3309
|
})).find((e) => e.migration.id === t.id);
|
|
3303
|
-
if (!r) return yield*
|
|
3304
|
-
yield*
|
|
3310
|
+
if (!r) return yield* C.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
|
|
3311
|
+
yield* Pe(e, { schema: t.lockSchema });
|
|
3305
3312
|
let i = Date.now();
|
|
3306
3313
|
try {
|
|
3307
3314
|
let n = {
|
|
3308
3315
|
sql: e,
|
|
3309
3316
|
log: {
|
|
3310
|
-
info: (e, n) =>
|
|
3317
|
+
info: (e, n) => C.logInfo(e).pipe(C.annotateLogs({
|
|
3311
3318
|
scope: `migrations:file:${t.id}`,
|
|
3312
3319
|
...n ?? {}
|
|
3313
3320
|
})),
|
|
3314
|
-
warn: (e, n) =>
|
|
3321
|
+
warn: (e, n) => C.logWarning(e).pipe(C.annotateLogs({
|
|
3315
3322
|
scope: `migrations:file:${t.id}`,
|
|
3316
3323
|
...n ?? {}
|
|
3317
3324
|
}))
|
|
3318
3325
|
},
|
|
3319
3326
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3320
3327
|
}, a = r.migration.down(n);
|
|
3321
|
-
|
|
3328
|
+
C.isEffect(a) ? yield* a : yield* C.tryPromise({
|
|
3322
3329
|
try: () => a,
|
|
3323
3330
|
catch: (e) => e
|
|
3324
3331
|
});
|
|
@@ -3328,9 +3335,9 @@ BEGIN
|
|
|
3328
3335
|
durationMs: o
|
|
3329
3336
|
};
|
|
3330
3337
|
} finally {
|
|
3331
|
-
yield*
|
|
3338
|
+
yield* D(e, { schema: t.lockSchema }).pipe(C.orDie);
|
|
3332
3339
|
}
|
|
3333
|
-
}),
|
|
3340
|
+
}), va = (e) => C.gen(function* () {
|
|
3334
3341
|
let t = yield* T.SqlClient, n = yield* t`
|
|
3335
3342
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3336
3343
|
WHERE source = 'auto-diff'
|
|
@@ -3338,9 +3345,9 @@ BEGIN
|
|
|
3338
3345
|
AND appliedAt < ${e.before}
|
|
3339
3346
|
ORDER BY appliedAt DESC
|
|
3340
3347
|
`;
|
|
3341
|
-
if (n.length === 0) return yield*
|
|
3348
|
+
if (n.length === 0) return yield* C.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3342
3349
|
let r = n[0];
|
|
3343
|
-
if (r.fingerprint !== e.fingerprint) return yield*
|
|
3350
|
+
if (r.fingerprint !== e.fingerprint) return yield* C.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.`));
|
|
3344
3351
|
yield* t`
|
|
3345
3352
|
UPDATE _voltro_migration_plans
|
|
3346
3353
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3375,7 +3382,7 @@ BEGIN
|
|
|
3375
3382
|
snapshotFingerprint: e.fingerprint,
|
|
3376
3383
|
snapshotId: i
|
|
3377
3384
|
};
|
|
3378
|
-
}),
|
|
3385
|
+
}), ya = { safe: !0 }, ba = (e) => {
|
|
3379
3386
|
switch (e.kind) {
|
|
3380
3387
|
case "drop-column": return {
|
|
3381
3388
|
safe: !1,
|
|
@@ -3402,7 +3409,7 @@ BEGIN
|
|
|
3402
3409
|
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`,
|
|
3403
3410
|
remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
|
|
3404
3411
|
};
|
|
3405
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3412
|
+
case "alter-column-nullability": return e.toNullable ? ya : {
|
|
3406
3413
|
safe: !1,
|
|
3407
3414
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3408
3415
|
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)`
|
|
@@ -3432,12 +3439,12 @@ BEGIN
|
|
|
3432
3439
|
case "drop-unique":
|
|
3433
3440
|
case "drop-unique-composite":
|
|
3434
3441
|
case "drop-foreign-key":
|
|
3435
|
-
case "drop-check": return
|
|
3442
|
+
case "drop-check": return ya;
|
|
3436
3443
|
}
|
|
3437
|
-
},
|
|
3444
|
+
}, xa = (e) => {
|
|
3438
3445
|
let t = [];
|
|
3439
3446
|
for (let n of e) {
|
|
3440
|
-
let e =
|
|
3447
|
+
let e = ba(n.op);
|
|
3441
3448
|
e.safe || t.push({
|
|
3442
3449
|
op: n,
|
|
3443
3450
|
reason: e.reason,
|
|
@@ -3445,7 +3452,7 @@ BEGIN
|
|
|
3445
3452
|
});
|
|
3446
3453
|
}
|
|
3447
3454
|
return t;
|
|
3448
|
-
},
|
|
3455
|
+
}, Sa = (e) => {
|
|
3449
3456
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3450
3457
|
refuse: !1,
|
|
3451
3458
|
warnForced: !1,
|
|
@@ -3461,18 +3468,18 @@ BEGIN
|
|
|
3461
3468
|
warnForced: !1,
|
|
3462
3469
|
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.`
|
|
3463
3470
|
};
|
|
3464
|
-
},
|
|
3471
|
+
}, Ca = (e) => {
|
|
3465
3472
|
let t = e.table;
|
|
3466
3473
|
if (typeof t == "string") return t;
|
|
3467
3474
|
let n = e.from;
|
|
3468
3475
|
return typeof n == "string" ? n : void 0;
|
|
3469
|
-
},
|
|
3476
|
+
}, wa = (e) => ({
|
|
3470
3477
|
kind: e.op.kind,
|
|
3471
|
-
table:
|
|
3478
|
+
table: Ca(e.op),
|
|
3472
3479
|
classification: e.classification,
|
|
3473
3480
|
reason: e.reason,
|
|
3474
3481
|
blockedFix: e.blocked?.fix
|
|
3475
|
-
}),
|
|
3482
|
+
}), Ta = (e) => e.operations.map(wa), Ea = async (e) => {
|
|
3476
3483
|
let t = e.log ?? (() => {}), n = {
|
|
3477
3484
|
branchId: e.branchId,
|
|
3478
3485
|
mechanism: e.mechanism,
|
|
@@ -3491,10 +3498,10 @@ BEGIN
|
|
|
3491
3498
|
applied: !1,
|
|
3492
3499
|
converged: !1,
|
|
3493
3500
|
residual: r,
|
|
3494
|
-
infidelity:
|
|
3501
|
+
infidelity: Ta(o)
|
|
3495
3502
|
};
|
|
3496
3503
|
else {
|
|
3497
|
-
let i = await e.plan(), o =
|
|
3504
|
+
let i = await e.plan(), o = Ta(i), s = o.filter((e) => e.classification === "lossy"), c = ta(i), l = c.operations.filter((e) => e.blocked !== void 0).map(wa);
|
|
3498
3505
|
if (l.length > 0) a = {
|
|
3499
3506
|
...n,
|
|
3500
3507
|
outcome: "blocked",
|
|
@@ -3519,7 +3526,7 @@ BEGIN
|
|
|
3519
3526
|
};
|
|
3520
3527
|
else {
|
|
3521
3528
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3522
|
-
let i =
|
|
3529
|
+
let i = Ta(await e.replan());
|
|
3523
3530
|
a = {
|
|
3524
3531
|
...n,
|
|
3525
3532
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3557,7 +3564,7 @@ BEGIN
|
|
|
3557
3564
|
...a,
|
|
3558
3565
|
tornDown: o
|
|
3559
3566
|
};
|
|
3560
|
-
},
|
|
3567
|
+
}, Da = (e) => {
|
|
3561
3568
|
switch (e.outcome) {
|
|
3562
3569
|
case "clean": return 0;
|
|
3563
3570
|
case "lossy": return 2;
|
|
@@ -3566,22 +3573,22 @@ BEGIN
|
|
|
3566
3573
|
case "infidelity": return 1;
|
|
3567
3574
|
case "failed": return 1;
|
|
3568
3575
|
}
|
|
3569
|
-
},
|
|
3576
|
+
}, Oa = (e) => ` ${e.classification === "lossy" ? "✗" : "•"} ${e.kind}${e.table ? ` ${e.table}` : ""} [${e.classification}]${e.reason ? ` — ${e.reason}` : ""}${e.blockedFix ? `\n ! ${e.blockedFix}` : ""}`, ka = (e) => {
|
|
3570
3577
|
let t = [];
|
|
3571
3578
|
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"}`);
|
|
3572
3579
|
else if (e.outcome === "infidelity") {
|
|
3573
3580
|
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:");
|
|
3574
|
-
for (let n of e.infidelity) t.push(
|
|
3581
|
+
for (let n of e.infidelity) t.push(Oa(n));
|
|
3575
3582
|
} else {
|
|
3576
3583
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3577
|
-
for (let n of e.operations) t.push(
|
|
3578
|
-
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(
|
|
3584
|
+
for (let n of e.operations) t.push(Oa(n));
|
|
3585
|
+
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(Oa(n));
|
|
3579
3586
|
}
|
|
3580
3587
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3581
|
-
},
|
|
3588
|
+
}, Aa = (e, ...t) => ({
|
|
3582
3589
|
_tag: "RawSqlFragment",
|
|
3583
3590
|
strings: [...e],
|
|
3584
3591
|
values: [...t]
|
|
3585
|
-
}),
|
|
3592
|
+
}), ja = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3586
3593
|
//#endregion
|
|
3587
|
-
export {
|
|
3594
|
+
export { k as DEFAULT_CDC_CHANNEL, S as FILE_MIGRATION_PATTERN, da as FileMigrationLedgerError, Xe as REACTIVE_TRIGGER_PREFIX, me as VOLTRO_MIGRATION_LOCK_KEY, Pe as acquireMigrationLock, U as appliedAtValue, Bt as applyNamespacedSchema, Wi as applyPlan, At as applySchema, Sa as assessRollingDeployGate, Da as branchRehearsalExitCode, Gn as chunkTables, ba as classifyRollingDeploySafety, F as declaredSnapshot, rt as defaultArrayClause, nt as defaultClause, M as defaultJsonClause, aa as describeOutcome, $i as destructiveScope, en as detectReactiveTriggerDrift, oi as emitAddIndexMysql, Hr as emitCreateTableMysql, Sr as emitDropColumnDdl, Cr as emitDropColumnDdlMysql, kt as emitFrameworkBootstrapSql, Dt as emitNamespaceProvisionDdl, Ot as emitNamespacedSchemaSql, Et as emitSchemaSql, ar as engineFromVersion, Jt as fingerprintSchema, be as fnv1a64, ka as formatBranchRehearsal, tn as formatReactiveTriggerDrift, Qi as ignoreTablesFromEnv, ir as introspectSchema, ur as isAlreadySatisfied, u as isFileMigration, ja as isRawSqlFragment, Mt as isReRunSafeDdl, zn as mapPgType, d as migration, xe as migrationLockKeyForSchema, Se as migrationLockNameForSchema, ni as mysqlIndexPrefixFor, Qe as notifyFunctionName, N as numericIdSql, Rn as parseEnumCheck, ma as pendingFileMigrationIds, Ln as planMigrations, Vt as provisionTenantNamespace, Ze as reactiveTriggerName, _t as reactiveTriggerRepairSql, qi as recordUpToDate, Ea as rehearseMigrationOnBranch, wa as rehearsedOperation, D as releaseMigrationLock, Br as renderColumnMysql, Fr as renderColumnPg, ge as resolveMigrationLockSchema, H as resolveMysqlEngine, _a as rollbackFileBasedMigration, xa as rollingDeployUnsafeOps, ha as runFileBasedMigrations, Ht as runFrameworkBootstrap, zt as runMigrate, ia as runPlannedMigrations, Yt as shortFingerprint, Xt as snapshotColumn, Aa as sql, j as sqlType, va as squashMigrationPlans, ta as unblockLossy, Fe as withMigrationLock };
|