@voltro/database 0.62.3 → 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 +104 -0
- package/dist/{frameworkLiveTables-CewCJ809.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 +973 -953
- 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
|
|
5
|
-
import { SqlClient as
|
|
6
|
-
import { promises as
|
|
7
|
-
import { join as
|
|
8
|
-
import { pathToFileURL 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
|
+
import { SqlClient as T } from "@effect/sql";
|
|
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 re = (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,99 +75,99 @@ var re = (e, t, n, r = 400) => {
|
|
|
75
75
|
appliedIndexes: r,
|
|
76
76
|
appliedUniques: [...e.appliedUniques ?? [], ...i]
|
|
77
77
|
};
|
|
78
|
-
},
|
|
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));
|
|
82
|
-
for (let t of o) n.has(t.target) ? i.add(
|
|
82
|
+
for (let t of o) n.has(t.target) ? i.add(E(e, t.column)) : r.has(t.target) || a(t.target);
|
|
83
83
|
n.delete(e), r.add(e);
|
|
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 re = (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,16 +210,21 @@ var re = (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
|
|
221
|
-
|
|
222
|
-
|
|
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
|
+
if (e.type === "text" && e.generatedAs === void 0) {
|
|
222
|
+
if (e.maxLength !== void 0) return e.maxLength;
|
|
223
|
+
if (t || e.hasDefault && e.defaultFactory === void 0 || e.oneOf !== void 0 && e.oneOf.length > 0) return 450;
|
|
224
|
+
}
|
|
225
|
+
}, tt = ne({ scope: "voltro:migrate" }), A = (e) => {
|
|
226
|
+
tt.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
|
|
227
|
+
}, j = (e, t) => {
|
|
223
228
|
let n = e.type;
|
|
224
229
|
if (e.spatial) {
|
|
225
230
|
if (t === "postgres") return `${e.spatial.kind}(${e.spatial.geomKind},${e.spatial.srid})`;
|
|
@@ -230,14 +235,14 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
230
235
|
return e.rawDdl;
|
|
231
236
|
}
|
|
232
237
|
if (n === "array" && e.arrayElement) {
|
|
233
|
-
if (t === "postgres") return `${
|
|
238
|
+
if (t === "postgres") return `${j({
|
|
234
239
|
...e,
|
|
235
240
|
type: e.arrayElement,
|
|
236
241
|
arrayElement: void 0
|
|
237
242
|
}, t)}[]`;
|
|
238
243
|
if (t === "mysql" || t === "mariadb") return "JSON";
|
|
239
244
|
if (t === "mssql") return "NVARCHAR(MAX)";
|
|
240
|
-
if (
|
|
245
|
+
if (m(t)) return "TEXT";
|
|
241
246
|
}
|
|
242
247
|
if (n === "vector") {
|
|
243
248
|
let n = e.vectorDim;
|
|
@@ -246,27 +251,27 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
246
251
|
if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
|
|
247
252
|
if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
|
|
248
253
|
if (t === "mssql") return "VARBINARY(MAX)";
|
|
249
|
-
if (
|
|
254
|
+
if (m(t)) return "BLOB";
|
|
250
255
|
}
|
|
251
256
|
if (n === "interval") {
|
|
252
257
|
if (t === "postgres") return "INTERVAL";
|
|
253
258
|
if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
|
|
254
|
-
if (
|
|
259
|
+
if (m(t)) return "INTEGER";
|
|
255
260
|
}
|
|
256
261
|
if (n === "decimal") {
|
|
257
262
|
let n = e.precision, r = e.scale ?? 0;
|
|
258
263
|
if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
|
|
259
|
-
return
|
|
264
|
+
return m(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
|
|
260
265
|
}
|
|
261
|
-
if (n === "bigint") return
|
|
266
|
+
if (n === "bigint") return m(t) ? "INTEGER" : "BIGINT";
|
|
262
267
|
if (n === "enum") {
|
|
263
268
|
if (t === "postgres") return e.enumName ?? "TEXT";
|
|
264
269
|
if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
|
|
265
270
|
if (t === "mssql") return "NVARCHAR(255)";
|
|
266
|
-
if (
|
|
271
|
+
if (m(t)) return "TEXT";
|
|
267
272
|
}
|
|
268
|
-
if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` :
|
|
269
|
-
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) {
|
|
270
275
|
case "id": return "TEXT";
|
|
271
276
|
case "text": return "TEXT";
|
|
272
277
|
case "integer": return "INTEGER";
|
|
@@ -300,7 +305,10 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
300
305
|
}
|
|
301
306
|
if (t === "mssql") switch (n) {
|
|
302
307
|
case "id": return "NVARCHAR(64)";
|
|
303
|
-
case "text":
|
|
308
|
+
case "text": {
|
|
309
|
+
let t = et(e, !1);
|
|
310
|
+
return t === void 0 ? "NVARCHAR(MAX)" : `NVARCHAR(${t})`;
|
|
311
|
+
}
|
|
304
312
|
case "integer": return "INT";
|
|
305
313
|
case "real": return "FLOAT";
|
|
306
314
|
case "boolean": return "BIT";
|
|
@@ -330,22 +338,22 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
330
338
|
case "array": return "TEXT[]";
|
|
331
339
|
case "interval": return "INTERVAL";
|
|
332
340
|
}
|
|
333
|
-
},
|
|
341
|
+
}, nt = (e, t) => {
|
|
334
342
|
if (!e.hasDefault || e.defaultFactory !== void 0) return null;
|
|
335
343
|
let n = e.defaultValue;
|
|
336
|
-
return n === "now" ?
|
|
337
|
-
},
|
|
338
|
-
if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return
|
|
339
|
-
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({
|
|
340
348
|
...t,
|
|
341
349
|
type: t.arrayElement,
|
|
342
350
|
arrayElement: void 0
|
|
343
351
|
}, n);
|
|
344
352
|
return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
|
|
345
|
-
},
|
|
353
|
+
}, M = (e, t) => {
|
|
346
354
|
let n = JSON.stringify(e).replace(/'/g, "''");
|
|
347
355
|
return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CONVERT('${n}' USING utf8mb4))` : `DEFAULT '${n}'`;
|
|
348
|
-
},
|
|
356
|
+
}, N = (e, t) => {
|
|
349
357
|
switch (t) {
|
|
350
358
|
case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
|
|
351
359
|
case "mysql":
|
|
@@ -354,7 +362,7 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
354
362
|
case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
|
|
355
363
|
case "turso": return `"${e}" INTEGER PRIMARY KEY`;
|
|
356
364
|
}
|
|
357
|
-
},
|
|
365
|
+
}, P = (e, t) => {
|
|
358
366
|
if (e === "restrict" && t === "mssql") return "NO ACTION";
|
|
359
367
|
switch (e) {
|
|
360
368
|
case "cascade": return "CASCADE";
|
|
@@ -362,117 +370,118 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
362
370
|
case "setNull": return "SET NULL";
|
|
363
371
|
case "noAction": return "NO ACTION";
|
|
364
372
|
}
|
|
365
|
-
},
|
|
373
|
+
}, it = (e, t, n) => n === null ? o(e, t) : `${o(n, t)}.${o(e, t)}`, at = 191, ot = (e, t) => {
|
|
366
374
|
if (!e || t !== "mysql" && t !== "mariadb") return !1;
|
|
367
|
-
let n =
|
|
375
|
+
let n = j(e, t).toUpperCase();
|
|
368
376
|
return n.endsWith("TEXT") || n.endsWith("BLOB");
|
|
369
|
-
},
|
|
370
|
-
let r =
|
|
377
|
+
}, st = (e, t, n) => {
|
|
378
|
+
let r = o(e, n);
|
|
371
379
|
if (n !== "mysql" && n !== "mariadb") return r;
|
|
372
380
|
let i = t[e];
|
|
373
381
|
if (!i) return r;
|
|
374
|
-
let a =
|
|
375
|
-
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${
|
|
376
|
-
},
|
|
382
|
+
let a = j(i, n).toUpperCase();
|
|
383
|
+
return a.endsWith("TEXT") || a.endsWith("BLOB") ? `${r}(${at})` : r;
|
|
384
|
+
}, ct = (e, t) => {
|
|
377
385
|
if (!e.generatedAs) return null;
|
|
378
386
|
let { expr: n, stored: r } = e.generatedAs;
|
|
379
|
-
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`;
|
|
380
388
|
if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
381
389
|
if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
|
|
382
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.");
|
|
383
391
|
return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
384
|
-
},
|
|
385
|
-
if (
|
|
386
|
-
let s =
|
|
387
|
-
|
|
388
|
-
let u =
|
|
389
|
-
if (u)
|
|
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);
|
|
390
398
|
else {
|
|
391
|
-
|
|
392
|
-
let e =
|
|
393
|
-
e &&
|
|
394
|
-
}
|
|
395
|
-
if (
|
|
396
|
-
let e =
|
|
397
|
-
|
|
398
|
-
let
|
|
399
|
-
|
|
400
|
-
let i =
|
|
401
|
-
i !== "NO ACTION" &&
|
|
402
|
-
}
|
|
403
|
-
if (
|
|
404
|
-
let
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
if (
|
|
408
|
-
if (
|
|
409
|
-
let
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
if (
|
|
413
|
-
let
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
return
|
|
417
|
-
},
|
|
418
|
-
let
|
|
419
|
-
for (let
|
|
420
|
-
for (let
|
|
421
|
-
let
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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}`}`];
|
|
428
437
|
}) : [], p = [
|
|
429
438
|
...d,
|
|
430
439
|
...l,
|
|
431
440
|
...u,
|
|
432
441
|
...f
|
|
433
|
-
], m = p.length > 0 ? `${c},\n${p.join(",\n")}` : c, h =
|
|
434
|
-
if (
|
|
435
|
-
let
|
|
436
|
-
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, "''")}');`;
|
|
437
446
|
}
|
|
438
447
|
return [
|
|
439
448
|
`CREATE TABLE IF NOT EXISTS ${h} (`,
|
|
440
449
|
m,
|
|
441
450
|
");"
|
|
442
451
|
].join("\n");
|
|
443
|
-
},
|
|
444
|
-
let r = `${e}_${t.name}_fts`, i = (e) =>
|
|
445
|
-
return
|
|
446
|
-
},
|
|
447
|
-
let r = [], i = /* @__PURE__ */ new Set(),
|
|
448
|
-
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 = {
|
|
449
458
|
using: "",
|
|
450
459
|
withSuffix: "",
|
|
451
460
|
skip: !1
|
|
452
461
|
};
|
|
453
|
-
if (r === void 0 || r === "btree") return
|
|
462
|
+
if (r === void 0 || r === "btree") return a;
|
|
454
463
|
if (r === "gist") return t === "postgres" ? {
|
|
455
464
|
using: " USING GIST",
|
|
456
465
|
withSuffix: "",
|
|
457
466
|
skip: !1
|
|
458
|
-
} : (
|
|
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);
|
|
459
468
|
if (r === "gin") return t === "postgres" ? {
|
|
460
469
|
using: " USING GIN",
|
|
461
470
|
withSuffix: "",
|
|
462
471
|
skip: !1
|
|
463
|
-
} : 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(...).`), {
|
|
464
473
|
using: "",
|
|
465
474
|
withSuffix: "",
|
|
466
475
|
skip: !0
|
|
467
|
-
}) : (
|
|
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);
|
|
468
477
|
if (r === "brin") return t === "postgres" ? {
|
|
469
478
|
using: " USING BRIN",
|
|
470
479
|
withSuffix: "",
|
|
471
480
|
skip: !1
|
|
472
|
-
} : (
|
|
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);
|
|
473
482
|
if (r === "hnsw") {
|
|
474
483
|
if (t === "postgres") {
|
|
475
|
-
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);
|
|
476
485
|
return {
|
|
477
486
|
using: " USING hnsw",
|
|
478
487
|
withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
|
|
@@ -480,73 +489,73 @@ var A = "framework_changes", qe = "framework_changes_", Je = (e, t) => t === "fr
|
|
|
480
489
|
skip: !1
|
|
481
490
|
};
|
|
482
491
|
}
|
|
483
|
-
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.`), {
|
|
484
493
|
using: "",
|
|
485
494
|
withSuffix: "",
|
|
486
495
|
skip: !0
|
|
487
496
|
};
|
|
488
497
|
}
|
|
489
|
-
return
|
|
498
|
+
return a;
|
|
490
499
|
}, c = (n, r) => {
|
|
491
500
|
let i = n.map((n) => {
|
|
492
|
-
if (typeof n == "string") return
|
|
501
|
+
if (typeof n == "string") return st(n, e.fields, t);
|
|
493
502
|
if ("jsonPath" in n) {
|
|
494
503
|
let { column: e, path: r, numeric: i } = n.jsonPath;
|
|
495
|
-
return `(${
|
|
504
|
+
return `(${ee(e, r, t, { numeric: i })})`;
|
|
496
505
|
}
|
|
497
506
|
return `(${n.expr})`;
|
|
498
507
|
});
|
|
499
508
|
return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
|
|
500
|
-
}, l = (e, r, i, a,
|
|
501
|
-
let
|
|
502
|
-
if (
|
|
503
|
-
let
|
|
504
|
-
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};`;
|
|
505
514
|
};
|
|
506
515
|
if (t === "mysql" || t === "mariadb") for (let [n, i] of Object.entries(e.fields)) {
|
|
507
|
-
if (!i.unique || i.type === "id" || !
|
|
516
|
+
if (!i.unique || i.type === "id" || !ot(i, t)) continue;
|
|
508
517
|
let a = l(`${e.tableName}_${n}_key`, e.tableName, [n], void 0, void 0, "", !0);
|
|
509
518
|
a && r.push(a);
|
|
510
519
|
}
|
|
511
520
|
for (let n of e.appliedFullText ?? []) if (t === "postgres") {
|
|
512
|
-
let i = n.config ?? "english", a = `${n.name}_tsv`,
|
|
521
|
+
let i = n.config ?? "english", a = `${n.name}_tsv`, s = n.columns.map((e) => {
|
|
513
522
|
let r = n.weights?.[e] ?? "A";
|
|
514
|
-
return `setweight(to_tsvector('${i}', coalesce(${
|
|
523
|
+
return `setweight(to_tsvector('${i}', coalesce(${o(e, t)}, '')), '${r}')`;
|
|
515
524
|
}).join(" || ");
|
|
516
|
-
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)});`);
|
|
517
526
|
} else if (t === "mysql" || t === "mariadb") {
|
|
518
|
-
let i = n.columns.map((e) =>
|
|
519
|
-
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});`);
|
|
520
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.`);
|
|
521
|
-
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).`);
|
|
522
531
|
for (let n of e.appliedIndexes) {
|
|
523
532
|
if ((t === "mariadb" || t === "mssql") && n.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
|
|
524
|
-
|
|
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(...).`);
|
|
525
534
|
continue;
|
|
526
535
|
}
|
|
527
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.`);
|
|
528
|
-
let
|
|
529
|
-
n.where !== void 0 && n.where.length > 0 && (t === "mysql" || t === "mariadb" ?
|
|
530
|
-
let s = l(n.name, e.tableName, n.fields, n.kind, n.kindOptions,
|
|
531
|
-
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));
|
|
532
541
|
}
|
|
533
542
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
534
|
-
if (n.type !== "reference" || n.fkAutoIndex === !1 || i.has(
|
|
535
|
-
let
|
|
536
|
-
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]));
|
|
537
546
|
}
|
|
538
547
|
return r.join("\n");
|
|
539
|
-
},
|
|
548
|
+
}, pt = (e, t, n = k) => {
|
|
540
549
|
if (t !== "postgres") return [];
|
|
541
550
|
let r = e.filter((e) => e.isReactive !== !1);
|
|
542
|
-
return r.length === 0 ? [] : [
|
|
543
|
-
},
|
|
544
|
-
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 $$
|
|
545
554
|
DECLARE
|
|
546
555
|
payload TEXT;
|
|
547
556
|
pk JSONB;
|
|
548
557
|
BEGIN
|
|
549
|
-
-- ${
|
|
558
|
+
-- ${$e}
|
|
550
559
|
payload := json_build_object(
|
|
551
560
|
'table', TG_TABLE_NAME,
|
|
552
561
|
-- The schema the write landed in. Under namespace isolation this is
|
|
@@ -600,22 +609,22 @@ BEGIN
|
|
|
600
609
|
RETURN COALESCE(NEW, OLD);
|
|
601
610
|
END;
|
|
602
611
|
$$ LANGUAGE plpgsql;
|
|
603
|
-
`.trim(),
|
|
604
|
-
let n =
|
|
612
|
+
`.trim(), ht = (e, t) => {
|
|
613
|
+
let n = Ze(e.tableName, t);
|
|
605
614
|
return [
|
|
606
615
|
`ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
|
|
607
616
|
`DROP TRIGGER IF EXISTS ${n} ON "${e.tableName}"`,
|
|
608
|
-
`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)}()`
|
|
609
618
|
];
|
|
610
|
-
},
|
|
619
|
+
}, gt = (e, t) => ht(e, t).map((e) => `${e};`).join("\n"), _t = (e) => {
|
|
611
620
|
if (e.dialect !== "postgres") return [];
|
|
612
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));
|
|
613
|
-
(i.length > 0 || e.functionOutdated === !0) && r.push(
|
|
614
|
-
for (let e of i) r.push(...
|
|
615
|
-
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`);
|
|
616
625
|
return r;
|
|
617
|
-
},
|
|
618
|
-
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) => {
|
|
619
628
|
let n = t.get(e);
|
|
620
629
|
return n ? Object.entries(n.fields).flatMap(([e, n]) => {
|
|
621
630
|
if (n.type !== "reference" || !n.references) return [];
|
|
@@ -626,7 +635,7 @@ $$ LANGUAGE plpgsql;
|
|
|
626
635
|
}] : [];
|
|
627
636
|
}) : [];
|
|
628
637
|
}), r = [];
|
|
629
|
-
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(
|
|
638
|
+
for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(E(t.tableName, e)) && r.push({
|
|
630
639
|
table: t.tableName,
|
|
631
640
|
column: e,
|
|
632
641
|
targetTable: i.references().tableName,
|
|
@@ -637,7 +646,7 @@ $$ LANGUAGE plpgsql;
|
|
|
637
646
|
if (!(i.has(e.tableName) || a.has(e.tableName))) {
|
|
638
647
|
a.add(e.tableName);
|
|
639
648
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
640
|
-
if (i.type !== "reference" || !i.references || n.has(
|
|
649
|
+
if (i.type !== "reference" || !i.references || n.has(E(e.tableName, r))) continue;
|
|
641
650
|
let a = i.references();
|
|
642
651
|
if (a.tableName === e.tableName) continue;
|
|
643
652
|
let o = t.get(a.tableName);
|
|
@@ -651,30 +660,30 @@ $$ LANGUAGE plpgsql;
|
|
|
651
660
|
sorted: o,
|
|
652
661
|
cyclic: r
|
|
653
662
|
};
|
|
654
|
-
},
|
|
655
|
-
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}`;
|
|
656
665
|
switch (t) {
|
|
657
666
|
case "postgres": return [
|
|
658
667
|
"DO $$ BEGIN",
|
|
659
668
|
" IF NOT EXISTS (SELECT 1 FROM pg_constraint",
|
|
660
669
|
` WHERE conname = '${i}' AND conrelid = '${n ? `${n}.` : ""}${e.table}'::regclass) THEN`,
|
|
661
|
-
` ALTER TABLE ${r(e.table)} ${
|
|
670
|
+
` ALTER TABLE ${r(e.table)} ${l(!1)};`,
|
|
662
671
|
" END IF;",
|
|
663
672
|
"END $$;"
|
|
664
673
|
].join("\n");
|
|
665
|
-
case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${i}') ALTER TABLE ${r(e.table)} ${
|
|
666
|
-
case "mariadb": return `ALTER TABLE ${r(e.table)} ${
|
|
667
|
-
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)};`;
|
|
668
677
|
}
|
|
669
|
-
},
|
|
678
|
+
}, St = (e, t) => {
|
|
670
679
|
let n = /* @__PURE__ */ new Map();
|
|
671
|
-
if (
|
|
680
|
+
if (m(t)) return n;
|
|
672
681
|
for (let t of e) {
|
|
673
682
|
let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
|
|
674
683
|
e.add(t.column), n.set(t.table, e);
|
|
675
684
|
}
|
|
676
685
|
return n;
|
|
677
|
-
},
|
|
686
|
+
}, Ct = (e, t) => {
|
|
678
687
|
if (t !== "postgres") return "";
|
|
679
688
|
let n = /* @__PURE__ */ new Map();
|
|
680
689
|
for (let t of e) for (let e of Object.values(t.fields)) {
|
|
@@ -690,45 +699,45 @@ $$ LANGUAGE plpgsql;
|
|
|
690
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 $$;`);
|
|
691
700
|
}
|
|
692
701
|
return r.join("\n\n");
|
|
693
|
-
},
|
|
702
|
+
}, wt = (e, t) => {
|
|
694
703
|
if (t !== "postgres") return "";
|
|
695
|
-
let
|
|
696
|
-
for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName &&
|
|
697
|
-
let
|
|
698
|
-
for (let e of
|
|
699
|
-
let
|
|
700
|
-
|
|
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 \$\$
|
|
701
710
|
DECLARE
|
|
702
711
|
type_oid oid;
|
|
703
712
|
BEGIN
|
|
704
|
-
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 $$;`);
|
|
705
714
|
}
|
|
706
|
-
return
|
|
707
|
-
},
|
|
715
|
+
return i.join("\n\n");
|
|
716
|
+
}, Tt = (e) => {
|
|
708
717
|
let t = [], n = [];
|
|
709
|
-
for (let r of e)
|
|
718
|
+
for (let r of e) s(r) ? n.push(r) : t.push(r);
|
|
710
719
|
return {
|
|
711
720
|
tables: t,
|
|
712
721
|
views: n
|
|
713
722
|
};
|
|
714
|
-
},
|
|
715
|
-
let { tables:
|
|
716
|
-
|
|
717
|
-
let u =
|
|
718
|
-
u &&
|
|
719
|
-
let d =
|
|
720
|
-
d &&
|
|
721
|
-
for (let e of
|
|
722
|
-
if (!
|
|
723
|
-
for (let e of
|
|
724
|
-
let
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
for (let
|
|
729
|
-
return
|
|
730
|
-
},
|
|
731
|
-
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);
|
|
732
741
|
switch (t) {
|
|
733
742
|
case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${r};`;
|
|
734
743
|
case "mysql":
|
|
@@ -737,62 +746,62 @@ BEGIN
|
|
|
737
746
|
case "turso":
|
|
738
747
|
case "sqlite": return `ATTACH DATABASE '${(n ?? `${e}.db`).replace(/'/g, "''")}' AS ${r};`;
|
|
739
748
|
}
|
|
740
|
-
},
|
|
741
|
-
let i =
|
|
742
|
-
if (t === "postgres") return `${i}\n\nSET search_path TO ${a};\n\n${
|
|
743
|
-
if (t === "mysql" || t === "mariadb") return `${i}\n\nUSE ${a};\n\n${
|
|
744
|
-
let { sorted:
|
|
745
|
-
for (let e of
|
|
746
|
-
if (!
|
|
747
|
-
for (let e of
|
|
748
|
-
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);
|
|
749
758
|
r && u.push(r);
|
|
750
759
|
}
|
|
751
760
|
return u.join("\n\n") + "\n";
|
|
752
|
-
},
|
|
753
|
-
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);
|
|
754
763
|
s && o.push(s);
|
|
755
|
-
let c =
|
|
764
|
+
let c = Ct(r, t);
|
|
756
765
|
c && o.push(c);
|
|
757
|
-
for (let e of r) o.push(
|
|
758
|
-
for (let e of i) o.push(
|
|
759
|
-
return o.push(...
|
|
760
|
-
},
|
|
761
|
-
let i = yield*
|
|
762
|
-
yield*
|
|
763
|
-
}),
|
|
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
|
+
let i = yield* T.SqlClient;
|
|
771
|
+
yield* Fe(i, Lt(i, Et(e, t, n), t, r.retryFilter), { schema: r.lockSchema }).pipe(C.orDie);
|
|
772
|
+
}), jt = (e, t) => {
|
|
764
773
|
let n = t.cause ?? {};
|
|
765
774
|
return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
|
|
766
|
-
},
|
|
775
|
+
}, Mt = (e, t) => {
|
|
767
776
|
let n = e.trimStart();
|
|
768
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));
|
|
769
|
-
},
|
|
778
|
+
}, Nt = () => {
|
|
770
779
|
let e = Number(process.env.VOLTRO_MIGRATION_DDL_RETRIES);
|
|
771
780
|
return Number.isInteger(e) && e >= 0 ? e : 4;
|
|
772
|
-
},
|
|
781
|
+
}, Pt = (e) => ({
|
|
773
782
|
while: e,
|
|
774
|
-
times:
|
|
775
|
-
schedule:
|
|
776
|
-
}),
|
|
783
|
+
times: Nt(),
|
|
784
|
+
schedule: w.jittered(w.exponential("50 millis"))
|
|
785
|
+
}), Ft = class {
|
|
777
786
|
statement;
|
|
778
787
|
error;
|
|
779
788
|
_tag = "DdlStatementFailed";
|
|
780
789
|
constructor(e, t) {
|
|
781
790
|
this.statement = e, this.error = t;
|
|
782
791
|
}
|
|
783
|
-
},
|
|
784
|
-
let r = yield*
|
|
785
|
-
for (let a of
|
|
786
|
-
process.env.VOLTRO_MIGRATE_DEBUG === "1" &&
|
|
787
|
-
let e = r.unsafe(a).pipe(
|
|
788
|
-
|
|
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));
|
|
789
798
|
})));
|
|
790
|
-
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)));
|
|
791
800
|
}
|
|
792
|
-
}),
|
|
793
|
-
let i = n === "turso" ?
|
|
794
|
-
return (r !== void 0 &&
|
|
795
|
-
},
|
|
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) => {
|
|
796
805
|
let t = [], n = "", r = !1;
|
|
797
806
|
for (let i = 0; i < e.length; i++) {
|
|
798
807
|
if (e.slice(i, i + 2) === "$$") {
|
|
@@ -807,43 +816,43 @@ BEGIN
|
|
|
807
816
|
}
|
|
808
817
|
let i = n.trim();
|
|
809
818
|
return i.length > 0 && t.push(i), t;
|
|
810
|
-
},
|
|
811
|
-
await
|
|
812
|
-
},
|
|
813
|
-
let i =
|
|
814
|
-
yield*
|
|
815
|
-
}),
|
|
816
|
-
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({
|
|
817
826
|
namespace: t,
|
|
818
827
|
dialect: r
|
|
819
828
|
});
|
|
820
|
-
},
|
|
821
|
-
await
|
|
822
|
-
let t =
|
|
823
|
-
yield*
|
|
824
|
-
}).pipe(
|
|
825
|
-
},
|
|
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) => {
|
|
826
835
|
if (e == null) return e;
|
|
827
|
-
if (Array.isArray(e)) return e.map(
|
|
836
|
+
if (Array.isArray(e)) return e.map(Ut);
|
|
828
837
|
if (typeof e != "object") return e;
|
|
829
838
|
let t = {};
|
|
830
839
|
for (let n of Object.keys(e).sort()) {
|
|
831
840
|
let r = e[n];
|
|
832
|
-
r !== void 0 && (t[n] =
|
|
841
|
+
r !== void 0 && (t[n] = Ut(r));
|
|
833
842
|
}
|
|
834
843
|
return t;
|
|
835
|
-
},
|
|
844
|
+
}, Wt = (e) => {
|
|
836
845
|
if (!e.idScheme && !e.sensitive && !e.safe && !e.generatedAs) return e;
|
|
837
846
|
let { idScheme: t, sensitive: n, safe: r, generatedAs: i, ...a } = e;
|
|
838
847
|
return a;
|
|
839
|
-
},
|
|
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) => ({
|
|
840
849
|
name: e.name,
|
|
841
|
-
columns:
|
|
842
|
-
indexes:
|
|
843
|
-
})).sort((e, t) => e.name.localeCompare(t.name)),
|
|
844
|
-
let t = { tables:
|
|
845
|
-
return
|
|
846
|
-
},
|
|
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) => {
|
|
847
856
|
let n = t.references ? {
|
|
848
857
|
table: t.references().tableName,
|
|
849
858
|
column: "id",
|
|
@@ -882,59 +891,59 @@ BEGIN
|
|
|
882
891
|
...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
|
|
883
892
|
...t.spatial === void 0 ? {} : { spatial: t.spatial }
|
|
884
893
|
};
|
|
885
|
-
},
|
|
886
|
-
let t = [], n = /* @__PURE__ */ new Set(),
|
|
894
|
+
}, Zt = (e) => {
|
|
895
|
+
let t = [], n = /* @__PURE__ */ new Set(), i = (e) => {
|
|
887
896
|
n.has(e.name) || (n.add(e.name), t.push(e));
|
|
888
|
-
},
|
|
889
|
-
|
|
897
|
+
}, a = e.appliedPrimaryKey ?? [];
|
|
898
|
+
a.length > 0 ? i({
|
|
890
899
|
name: `${e.tableName}_pkey`,
|
|
891
900
|
table: e.tableName,
|
|
892
|
-
columns: [...
|
|
901
|
+
columns: [...a],
|
|
893
902
|
unique: !0
|
|
894
|
-
}) : e.fields.id &&
|
|
903
|
+
}) : e.fields.id && i({
|
|
895
904
|
name: `${e.tableName}_pkey`,
|
|
896
905
|
table: e.tableName,
|
|
897
906
|
columns: ["id"],
|
|
898
907
|
unique: !0
|
|
899
908
|
});
|
|
900
|
-
let
|
|
901
|
-
for (let t of
|
|
909
|
+
let o = e.appliedIndexes ?? [];
|
|
910
|
+
for (let t of o) {
|
|
902
911
|
if (t.unique && t.where) continue;
|
|
903
|
-
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})`),
|
|
904
|
-
|
|
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({
|
|
905
914
|
name: t.name,
|
|
906
915
|
table: e.tableName,
|
|
907
916
|
columns: n,
|
|
908
917
|
unique: !1,
|
|
909
|
-
...
|
|
918
|
+
...r ? { expression: !0 } : {}
|
|
910
919
|
});
|
|
911
920
|
}
|
|
912
|
-
let
|
|
913
|
-
for (let t of
|
|
921
|
+
let s = e.appliedUniques ?? [];
|
|
922
|
+
for (let t of s) t.fields.length < 2 || i({
|
|
914
923
|
name: t.name,
|
|
915
924
|
table: e.tableName,
|
|
916
925
|
columns: t.fields,
|
|
917
926
|
unique: !0
|
|
918
927
|
});
|
|
919
|
-
let
|
|
920
|
-
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"));
|
|
921
930
|
for (let [t, n] of Object.entries(e.fields)) {
|
|
922
|
-
let
|
|
923
|
-
if (
|
|
924
|
-
let
|
|
925
|
-
|
|
926
|
-
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,
|
|
927
936
|
table: e.tableName,
|
|
928
937
|
columns: [t],
|
|
929
938
|
unique: !1
|
|
930
939
|
});
|
|
931
940
|
}
|
|
932
941
|
return t;
|
|
933
|
-
},
|
|
942
|
+
}, Qt = (e) => {
|
|
934
943
|
let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
|
|
935
944
|
for (let [r, i] of Object.entries(e.fields)) {
|
|
936
945
|
if (i.dropped) continue;
|
|
937
|
-
let e =
|
|
946
|
+
let e = Xt(r, i);
|
|
938
947
|
n.push(t.has(r) ? {
|
|
939
948
|
...e,
|
|
940
949
|
unique: !0
|
|
@@ -944,27 +953,27 @@ BEGIN
|
|
|
944
953
|
return {
|
|
945
954
|
name: e.tableName,
|
|
946
955
|
columns: n,
|
|
947
|
-
indexes:
|
|
956
|
+
indexes: Zt(e),
|
|
948
957
|
...r.length > 0 ? { primaryKey: [...r] } : {},
|
|
949
958
|
...i === void 0 ? {} : { renamedFrom: i }
|
|
950
959
|
};
|
|
951
|
-
},
|
|
960
|
+
}, $t = (e) => {
|
|
952
961
|
let t = /* @__PURE__ */ new Map();
|
|
953
962
|
for (let n of e) for (let e of n.indexes) {
|
|
954
963
|
let r = t.get(e.name);
|
|
955
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}').`);
|
|
956
965
|
t.set(e.name, n.name);
|
|
957
966
|
}
|
|
958
|
-
},
|
|
959
|
-
let n = e.filter((e) => !
|
|
960
|
-
return
|
|
961
|
-
},
|
|
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* () {
|
|
962
971
|
let r = (yield* e`
|
|
963
972
|
SELECT p.prosrc
|
|
964
973
|
FROM pg_proc p
|
|
965
974
|
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
966
975
|
WHERE n.nspname = current_schema()
|
|
967
|
-
AND p.proname = ${
|
|
976
|
+
AND p.proname = ${Qe(n)}
|
|
968
977
|
`)[0]?.prosrc, i = r !== void 0 && !r.includes("voltro:notify:v2"), a = t.filter((e) => !e.tableName.startsWith("_voltro_"));
|
|
969
978
|
if (a.length === 0) return {
|
|
970
979
|
missing: [],
|
|
@@ -978,10 +987,10 @@ BEGIN
|
|
|
978
987
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
979
988
|
WHERE NOT t.tgisinternal
|
|
980
989
|
AND n.nspname = current_schema()
|
|
981
|
-
AND t.tgname LIKE ${`${
|
|
990
|
+
AND t.tgname LIKE ${`${Xe}%`}
|
|
982
991
|
`, s = new Set(o.map((e) => e.tgname)), c = [], l = [];
|
|
983
992
|
for (let e of a) {
|
|
984
|
-
let t = s.has(
|
|
993
|
+
let t = s.has(Ze(e.tableName, n)), r = e.isReactive !== !1;
|
|
985
994
|
r && !t && c.push(e.tableName), !r && t && l.push(e.tableName);
|
|
986
995
|
}
|
|
987
996
|
return {
|
|
@@ -989,7 +998,7 @@ BEGIN
|
|
|
989
998
|
stale: l.sort(),
|
|
990
999
|
functionOutdated: i
|
|
991
1000
|
};
|
|
992
|
-
}),
|
|
1001
|
+
}), tn = (e) => {
|
|
993
1002
|
let t = [];
|
|
994
1003
|
if (e.missing.length > 0) {
|
|
995
1004
|
let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
|
|
@@ -1000,19 +1009,19 @@ BEGIN
|
|
|
1000
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.`);
|
|
1001
1010
|
}
|
|
1002
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;
|
|
1003
|
-
},
|
|
1012
|
+
}, nn = {
|
|
1004
1013
|
postgres: !0,
|
|
1005
1014
|
mysql: !0,
|
|
1006
1015
|
mariadb: !0,
|
|
1007
1016
|
mssql: !0,
|
|
1008
1017
|
sqlite: !0
|
|
1009
|
-
},
|
|
1018
|
+
}, rn = {
|
|
1010
1019
|
postgres: !0,
|
|
1011
1020
|
mysql: !1,
|
|
1012
1021
|
mariadb: !1,
|
|
1013
1022
|
mssql: !0,
|
|
1014
1023
|
sqlite: !0
|
|
1015
|
-
},
|
|
1024
|
+
}, an = (e) => {
|
|
1016
1025
|
switch (e) {
|
|
1017
1026
|
case "add-column":
|
|
1018
1027
|
case "drop-column":
|
|
@@ -1022,47 +1031,47 @@ BEGIN
|
|
|
1022
1031
|
case "add-foreign-key":
|
|
1023
1032
|
case "add-unique":
|
|
1024
1033
|
case "add-unique-composite":
|
|
1025
|
-
case "add-check": return
|
|
1026
|
-
default: return
|
|
1034
|
+
case "add-check": return rn;
|
|
1035
|
+
default: return nn;
|
|
1027
1036
|
}
|
|
1028
|
-
},
|
|
1037
|
+
}, on = (e, t) => {
|
|
1029
1038
|
let n = new Map(t.tables.map((e) => [e.name, e]));
|
|
1030
1039
|
return new Map(e.map((e) => [e.tableName, {
|
|
1031
1040
|
table: e,
|
|
1032
1041
|
snapshot: n.get(e.tableName),
|
|
1033
1042
|
columnDefs: e.fields
|
|
1034
1043
|
}]));
|
|
1035
|
-
},
|
|
1044
|
+
}, I = (e) => {
|
|
1036
1045
|
if (typeof e != "object" || !e) return JSON.stringify(e);
|
|
1037
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
1046
|
+
if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
|
|
1038
1047
|
let t = e;
|
|
1039
|
-
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${
|
|
1040
|
-
},
|
|
1048
|
+
return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
|
|
1049
|
+
}, sn = (e) => {
|
|
1041
1050
|
if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
|
|
1042
1051
|
let t = e.defaultValue;
|
|
1043
1052
|
if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
|
|
1044
1053
|
if (typeof t == "number") return String(t);
|
|
1045
|
-
if (typeof t != "string") return
|
|
1054
|
+
if (typeof t != "string") return I(t);
|
|
1046
1055
|
let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
|
|
1047
1056
|
if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
|
|
1048
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);
|
|
1049
1058
|
if (o) try {
|
|
1050
|
-
return
|
|
1059
|
+
return I(JSON.parse(o[1]));
|
|
1051
1060
|
} catch {}
|
|
1052
1061
|
let s = /^convert\(\s*(?:_\w+\s*)?\\?'(.*?)\\?'\s+using\s+[\w]+\s*\)$/i.exec(a);
|
|
1053
1062
|
if (s) try {
|
|
1054
|
-
return
|
|
1063
|
+
return I(JSON.parse(s[1]));
|
|
1055
1064
|
} catch {}
|
|
1056
1065
|
if (a.startsWith("{") || a.startsWith("[")) try {
|
|
1057
|
-
return
|
|
1066
|
+
return I(JSON.parse(a));
|
|
1058
1067
|
} catch {}
|
|
1059
1068
|
return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
|
|
1060
|
-
},
|
|
1061
|
-
let n =
|
|
1069
|
+
}, cn = (e, t) => {
|
|
1070
|
+
let n = sn(e), r = sn(t);
|
|
1062
1071
|
if (n === r) return !0;
|
|
1063
1072
|
let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
|
|
1064
1073
|
return i(n) === i(r);
|
|
1065
|
-
},
|
|
1074
|
+
}, ln = (e) => {
|
|
1066
1075
|
if (!e) return null;
|
|
1067
1076
|
let t = (e) => e === "restrict" ? "noAction" : e;
|
|
1068
1077
|
return {
|
|
@@ -1071,33 +1080,37 @@ BEGIN
|
|
|
1071
1080
|
onDelete: t(e.onDelete),
|
|
1072
1081
|
onUpdate: t(e.onUpdate)
|
|
1073
1082
|
};
|
|
1074
|
-
},
|
|
1083
|
+
}, un = (e, t) => {
|
|
1075
1084
|
let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
|
|
1076
1085
|
if (!n && !r) return !0;
|
|
1077
1086
|
if (!n || !r || n.length !== r.length) return !1;
|
|
1078
1087
|
let i = [...n].sort(), a = [...r].sort();
|
|
1079
1088
|
return i.every((e, t) => e === a[t]);
|
|
1080
|
-
},
|
|
1089
|
+
}, dn = (e, t, n) => {
|
|
1090
|
+
if (t === "mssql") {
|
|
1091
|
+
let t = et(e, n);
|
|
1092
|
+
if (t !== void 0) return t;
|
|
1093
|
+
}
|
|
1081
1094
|
try {
|
|
1082
|
-
let n = /\((\d+)\)/.exec(
|
|
1095
|
+
let n = /\((\d+)\)/.exec(j(e, t));
|
|
1083
1096
|
return n ? Number(n[1]) : void 0;
|
|
1084
1097
|
} catch {
|
|
1085
1098
|
return;
|
|
1086
1099
|
}
|
|
1087
|
-
},
|
|
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({
|
|
1088
1101
|
kind: "add-check",
|
|
1089
1102
|
table: e,
|
|
1090
1103
|
column: t.name,
|
|
1091
1104
|
values: t.oneOf
|
|
1092
|
-
}, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0,
|
|
1093
|
-
let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [];
|
|
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
|
+
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));
|
|
1094
1107
|
for (let t of e.columns) {
|
|
1095
1108
|
let e = r.get(t.name);
|
|
1096
1109
|
if (!e) {
|
|
1097
1110
|
a.push(t);
|
|
1098
1111
|
continue;
|
|
1099
1112
|
}
|
|
1100
|
-
|
|
1113
|
+
pn(t, e, n, c.has(t.name) || t.unique) || s.push({
|
|
1101
1114
|
declared: t,
|
|
1102
1115
|
live: e
|
|
1103
1116
|
});
|
|
@@ -1108,47 +1121,47 @@ BEGIN
|
|
|
1108
1121
|
removed: o,
|
|
1109
1122
|
changed: s
|
|
1110
1123
|
};
|
|
1111
|
-
},
|
|
1112
|
-
let n = new Map(t.indexes.map((e) => [e.name, e])),
|
|
1124
|
+
}, _n = (e, t, n) => {
|
|
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 = [];
|
|
1113
1126
|
for (let t of e.indexes) {
|
|
1114
|
-
let e =
|
|
1115
|
-
(!e || !
|
|
1127
|
+
let e = i.get(r(t.name));
|
|
1128
|
+
(!e || !hn(t, e)) && o.push(t);
|
|
1116
1129
|
}
|
|
1117
|
-
for (let e of t.indexes)
|
|
1130
|
+
for (let e of t.indexes) a.has(r(e.name)) || s.push(e);
|
|
1118
1131
|
return {
|
|
1119
|
-
added:
|
|
1120
|
-
removed:
|
|
1132
|
+
added: o,
|
|
1133
|
+
removed: s
|
|
1121
1134
|
};
|
|
1122
|
-
},
|
|
1135
|
+
}, L = (e, t, n, r) => ({
|
|
1123
1136
|
op: e,
|
|
1124
1137
|
classification: t,
|
|
1125
|
-
atomicByDialect:
|
|
1138
|
+
atomicByDialect: an(e.kind),
|
|
1126
1139
|
...n ? { reason: n } : {},
|
|
1127
1140
|
...r ? { blocked: r } : {}
|
|
1128
|
-
}),
|
|
1141
|
+
}), vn = (e, t, n) => {
|
|
1129
1142
|
let r = {
|
|
1130
1143
|
kind: "add-column",
|
|
1131
1144
|
table: e,
|
|
1132
1145
|
column: t
|
|
1133
1146
|
};
|
|
1134
|
-
return t.nullable ?
|
|
1135
|
-
},
|
|
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) => {
|
|
1136
1149
|
let r = {
|
|
1137
1150
|
kind: "drop-column",
|
|
1138
1151
|
table: e,
|
|
1139
1152
|
column: t.name
|
|
1140
1153
|
};
|
|
1141
|
-
return n?.dropped ?
|
|
1142
|
-
},
|
|
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({
|
|
1143
1156
|
kind: "create-table",
|
|
1144
1157
|
table: e,
|
|
1145
1158
|
columns: t,
|
|
1146
1159
|
indexes: n,
|
|
1147
1160
|
...r && r.length > 0 ? { primaryKey: r } : {}
|
|
1148
|
-
}, "safe", i ?? "new table — no data to preserve"),
|
|
1161
|
+
}, "safe", i ?? "new table — no data to preserve"), xn = (e) => L({
|
|
1149
1162
|
kind: "drop-table",
|
|
1150
1163
|
table: e
|
|
1151
|
-
}, "lossy", "table missing from declared schema", { fix: "if intentional, set VOLTRO_DESTRUCTIVE_OK=1 OR add a file-based migration. If a typo, restore the table declaration" }),
|
|
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) => {
|
|
1152
1165
|
let i = (n ?? 0) >= r, a;
|
|
1153
1166
|
return a = t.unique ? t.columns.length === 1 ? {
|
|
1154
1167
|
kind: "add-unique",
|
|
@@ -1163,16 +1176,16 @@ BEGIN
|
|
|
1163
1176
|
kind: "add-index",
|
|
1164
1177
|
table: e,
|
|
1165
1178
|
index: t
|
|
1166
|
-
}, i ?
|
|
1167
|
-
},
|
|
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({
|
|
1168
1181
|
kind: "drop-unique-composite",
|
|
1169
1182
|
table: e,
|
|
1170
1183
|
name: t.name
|
|
1171
|
-
}, "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({
|
|
1172
1185
|
kind: "drop-index",
|
|
1173
1186
|
table: e,
|
|
1174
1187
|
index: t.name
|
|
1175
|
-
}, "safe", "drop index (no data loss — index is derived data)"),
|
|
1188
|
+
}, "safe", "drop index (no data loss — index is derived data)"), Tn = (e, t) => {
|
|
1176
1189
|
if (e === "reference") return "text";
|
|
1177
1190
|
switch (t) {
|
|
1178
1191
|
case "sqlite":
|
|
@@ -1180,10 +1193,10 @@ BEGIN
|
|
|
1180
1193
|
case "mssql": return e === "json" ? "text" : e;
|
|
1181
1194
|
default: return e;
|
|
1182
1195
|
}
|
|
1183
|
-
},
|
|
1196
|
+
}, En = (e, t, n) => {
|
|
1184
1197
|
let r = `acknowledge it on the column: \`.narrowedFrom('${e}')\``;
|
|
1185
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`;
|
|
1186
|
-
},
|
|
1199
|
+
}, Dn = (e, t, n, r, i, a) => {
|
|
1187
1200
|
let o = [];
|
|
1188
1201
|
if (t.nullable !== n.nullable) {
|
|
1189
1202
|
let n = {
|
|
@@ -1192,7 +1205,7 @@ BEGIN
|
|
|
1192
1205
|
column: t.name,
|
|
1193
1206
|
toNullable: t.nullable
|
|
1194
1207
|
};
|
|
1195
|
-
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`));
|
|
1196
1209
|
}
|
|
1197
1210
|
if (t.unique !== n.unique) {
|
|
1198
1211
|
if (t.unique) {
|
|
@@ -1201,14 +1214,14 @@ BEGIN
|
|
|
1201
1214
|
table: e,
|
|
1202
1215
|
column: t.name
|
|
1203
1216
|
}, r = (i ?? 0) >= a;
|
|
1204
|
-
o.push(r ?
|
|
1205
|
-
} 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({
|
|
1206
1219
|
kind: "drop-unique",
|
|
1207
1220
|
table: e,
|
|
1208
1221
|
column: t.name
|
|
1209
1222
|
}, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
|
|
1210
1223
|
}
|
|
1211
|
-
if (
|
|
1224
|
+
if (Tn(t.type, r) !== Tn(n.type, r)) {
|
|
1212
1225
|
let i = t.narrowedFrom;
|
|
1213
1226
|
if (i && i.from === n.type) {
|
|
1214
1227
|
let r = {
|
|
@@ -1219,7 +1232,7 @@ BEGIN
|
|
|
1219
1232
|
to: t.type,
|
|
1220
1233
|
...i.using === void 0 ? {} : { using: i.using }
|
|
1221
1234
|
};
|
|
1222
|
-
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)")));
|
|
1223
1236
|
} else {
|
|
1224
1237
|
let i = {
|
|
1225
1238
|
kind: "alter-column-type",
|
|
@@ -1228,12 +1241,12 @@ BEGIN
|
|
|
1228
1241
|
from: n.type,
|
|
1229
1242
|
to: t.type
|
|
1230
1243
|
};
|
|
1231
|
-
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) }));
|
|
1232
1245
|
}
|
|
1233
1246
|
}
|
|
1234
|
-
if (t.type === "text" && n.type === "text" && !
|
|
1247
|
+
if (t.type === "text" && n.type === "text" && !m(r ?? "postgres") && t.maxLength !== n.maxLength) {
|
|
1235
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})`;
|
|
1236
|
-
o.push(
|
|
1249
|
+
o.push(L({
|
|
1237
1250
|
kind: "alter-column-type",
|
|
1238
1251
|
table: e,
|
|
1239
1252
|
column: t.name,
|
|
@@ -1241,7 +1254,7 @@ BEGIN
|
|
|
1241
1254
|
to: "text"
|
|
1242
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)}`));
|
|
1243
1256
|
}
|
|
1244
|
-
if (!
|
|
1257
|
+
if (!cn(t, n)) {
|
|
1245
1258
|
let n = {
|
|
1246
1259
|
kind: "alter-column-default",
|
|
1247
1260
|
table: e,
|
|
@@ -1249,23 +1262,23 @@ BEGIN
|
|
|
1249
1262
|
hasDefault: t.hasDefault,
|
|
1250
1263
|
...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
|
|
1251
1264
|
};
|
|
1252
|
-
o.push(
|
|
1265
|
+
o.push(L(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
|
|
1253
1266
|
}
|
|
1254
|
-
if (!
|
|
1255
|
-
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({
|
|
1256
1269
|
kind: "drop-check",
|
|
1257
1270
|
table: e,
|
|
1258
1271
|
column: t.name
|
|
1259
1272
|
}, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
|
|
1260
|
-
let r =
|
|
1273
|
+
let r = mn(e, t);
|
|
1261
1274
|
r && o.push(r);
|
|
1262
1275
|
}
|
|
1263
|
-
return JSON.stringify(
|
|
1276
|
+
return JSON.stringify(ln(t.references)) !== JSON.stringify(ln(n.references)) && (n.references && o.push(L({
|
|
1264
1277
|
kind: "drop-foreign-key",
|
|
1265
1278
|
table: e,
|
|
1266
1279
|
column: t.name
|
|
1267
|
-
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...
|
|
1268
|
-
},
|
|
1280
|
+
}, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), o.push(...On(e, t))), o;
|
|
1281
|
+
}, On = (e, t) => {
|
|
1269
1282
|
let n = [];
|
|
1270
1283
|
if (!t.references) return n;
|
|
1271
1284
|
let r = t.references.table, i = t.references.orphanPolicy ?? "fail", a = {
|
|
@@ -1277,15 +1290,15 @@ BEGIN
|
|
|
1277
1290
|
...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
|
|
1278
1291
|
...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
|
|
1279
1292
|
};
|
|
1280
|
-
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({
|
|
1281
1294
|
...a,
|
|
1282
1295
|
orphanPolicy: i
|
|
1283
|
-
}, "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(
|
|
1284
|
-
},
|
|
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) => {
|
|
1285
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));
|
|
1286
1299
|
for (let [n, c] of Object.entries(t)) {
|
|
1287
1300
|
let t = c.renamedFrom;
|
|
1288
|
-
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({
|
|
1289
1302
|
kind: "rename-column",
|
|
1290
1303
|
table: e.tableName,
|
|
1291
1304
|
from: t,
|
|
@@ -1297,26 +1310,26 @@ BEGIN
|
|
|
1297
1310
|
consumedAddedNames: i,
|
|
1298
1311
|
consumedRemovedNames: a
|
|
1299
1312
|
};
|
|
1300
|
-
},
|
|
1313
|
+
}, An = /* @__PURE__ */ new Set([
|
|
1301
1314
|
"postgres",
|
|
1302
1315
|
"mysql",
|
|
1303
1316
|
"mariadb",
|
|
1304
1317
|
"mssql"
|
|
1305
|
-
]),
|
|
1318
|
+
]), jn = {
|
|
1306
1319
|
ops: [],
|
|
1307
1320
|
consumedAddedNames: /* @__PURE__ */ new Set(),
|
|
1308
1321
|
consumedRemovedNames: /* @__PURE__ */ new Set()
|
|
1309
|
-
},
|
|
1310
|
-
if (i === void 0 || !
|
|
1311
|
-
let a = t.added.filter((e) =>
|
|
1312
|
-
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;
|
|
1313
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();
|
|
1314
1327
|
for (let n of t.removed) {
|
|
1315
|
-
if (!
|
|
1328
|
+
if (!Mn(n)) continue;
|
|
1316
1329
|
let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
|
|
1317
1330
|
if (r.length !== 1) continue;
|
|
1318
1331
|
let i = r[0];
|
|
1319
|
-
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({
|
|
1320
1333
|
kind: "rename-index",
|
|
1321
1334
|
table: e,
|
|
1322
1335
|
from: n.name,
|
|
@@ -1328,7 +1341,7 @@ BEGIN
|
|
|
1328
1341
|
consumedAddedNames: l,
|
|
1329
1342
|
consumedRemovedNames: u
|
|
1330
1343
|
};
|
|
1331
|
-
},
|
|
1344
|
+
}, Pn = (e, t, n) => {
|
|
1332
1345
|
let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
|
|
1333
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));
|
|
1334
1347
|
for (let c of e.tables) {
|
|
@@ -1339,7 +1352,7 @@ BEGIN
|
|
|
1339
1352
|
continue;
|
|
1340
1353
|
}
|
|
1341
1354
|
if (t.has(c.name)) {
|
|
1342
|
-
r.push(
|
|
1355
|
+
r.push(L({
|
|
1343
1356
|
kind: "rename-table",
|
|
1344
1357
|
from: e,
|
|
1345
1358
|
to: c.name
|
|
@@ -1347,14 +1360,14 @@ BEGIN
|
|
|
1347
1360
|
continue;
|
|
1348
1361
|
}
|
|
1349
1362
|
if ((s.get(e) ?? 0) !== 1) {
|
|
1350
|
-
r.push(
|
|
1363
|
+
r.push(L({
|
|
1351
1364
|
kind: "rename-table",
|
|
1352
1365
|
from: e,
|
|
1353
1366
|
to: c.name
|
|
1354
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.` }));
|
|
1355
1368
|
continue;
|
|
1356
1369
|
}
|
|
1357
|
-
i.set(c.name, e), a.add(e), r.push(
|
|
1370
|
+
i.set(c.name, e), a.add(e), r.push(L({
|
|
1358
1371
|
kind: "rename-table",
|
|
1359
1372
|
from: e,
|
|
1360
1373
|
to: c.name
|
|
@@ -1368,19 +1381,19 @@ BEGIN
|
|
|
1368
1381
|
claimedOldNames: c,
|
|
1369
1382
|
refusals: o
|
|
1370
1383
|
};
|
|
1371
|
-
},
|
|
1384
|
+
}, Fn = (e, t, n, r) => {
|
|
1372
1385
|
if (t === void 0) return {
|
|
1373
1386
|
live: e,
|
|
1374
1387
|
ops: []
|
|
1375
1388
|
};
|
|
1376
|
-
let i = r !== void 0 &&
|
|
1389
|
+
let i = r !== void 0 && An.has(r), a = [], o = e.indexes.map((e) => {
|
|
1377
1390
|
if (!e.name.startsWith(t)) return e;
|
|
1378
1391
|
let r = `${n}${e.name.slice(t.length)}`;
|
|
1379
1392
|
return r === e.name ? e : e.name === `${t}_pkey` ? {
|
|
1380
1393
|
...e,
|
|
1381
1394
|
name: r,
|
|
1382
1395
|
table: n
|
|
1383
|
-
} : i ? (a.push(
|
|
1396
|
+
} : i ? (a.push(L({
|
|
1384
1397
|
kind: "rename-index",
|
|
1385
1398
|
table: n,
|
|
1386
1399
|
from: e.name,
|
|
@@ -1399,7 +1412,7 @@ BEGIN
|
|
|
1399
1412
|
},
|
|
1400
1413
|
ops: a
|
|
1401
1414
|
};
|
|
1402
|
-
},
|
|
1415
|
+
}, In = (e) => {
|
|
1403
1416
|
let t = {
|
|
1404
1417
|
safe: 0,
|
|
1405
1418
|
needsDefault: 0,
|
|
@@ -1432,42 +1445,42 @@ BEGIN
|
|
|
1432
1445
|
case "multi-step": t.multiStep++;
|
|
1433
1446
|
}
|
|
1434
1447
|
return t;
|
|
1435
|
-
},
|
|
1436
|
-
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);
|
|
1437
1450
|
a.push(...o.ops);
|
|
1438
1451
|
for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
|
|
1439
|
-
a.push(
|
|
1452
|
+
a.push(bn(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
|
|
1440
1453
|
for (let t of e.columns) {
|
|
1441
|
-
let n =
|
|
1454
|
+
let n = mn(e.name, t);
|
|
1442
1455
|
n && a.push(n);
|
|
1443
1456
|
}
|
|
1444
1457
|
}
|
|
1445
1458
|
let s = new Set(e.ignoreTables ?? []);
|
|
1446
|
-
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));
|
|
1447
1460
|
for (let s of t.tables) {
|
|
1448
1461
|
let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
|
|
1449
1462
|
if (!c) continue;
|
|
1450
|
-
let l =
|
|
1463
|
+
let l = Fn(c, t, s.name, e.dialect);
|
|
1451
1464
|
a.push(...l.ops);
|
|
1452
|
-
let u = l.live, d = n.get(s.name),
|
|
1453
|
-
a.push(...
|
|
1454
|
-
for (let e of
|
|
1455
|
-
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;
|
|
1456
1469
|
let t = d.columnDefs[e.name];
|
|
1457
|
-
a.push(
|
|
1470
|
+
a.push(yn(s.name, e, t));
|
|
1458
1471
|
}
|
|
1459
|
-
for (let e of
|
|
1460
|
-
if (
|
|
1472
|
+
for (let e of f.added) {
|
|
1473
|
+
if (m.consumedAddedNames.has(e.name)) continue;
|
|
1461
1474
|
let t = d.columnDefs[e.name];
|
|
1462
|
-
a.push(
|
|
1463
|
-
let n =
|
|
1464
|
-
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));
|
|
1465
1478
|
}
|
|
1466
|
-
let
|
|
1467
|
-
a.push(...
|
|
1468
|
-
for (let e of
|
|
1469
|
-
for (let e of
|
|
1470
|
-
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));
|
|
1471
1484
|
}
|
|
1472
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) => {
|
|
1473
1486
|
let t = l.get(e);
|
|
@@ -1475,8 +1488,8 @@ BEGIN
|
|
|
1475
1488
|
column: e.name,
|
|
1476
1489
|
target: e.references.table
|
|
1477
1490
|
}] : []) : [];
|
|
1478
|
-
}, d =
|
|
1479
|
-
for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(
|
|
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({
|
|
1480
1493
|
kind: "add-foreign-key",
|
|
1481
1494
|
table: e.name,
|
|
1482
1495
|
column: t.name,
|
|
@@ -1491,8 +1504,8 @@ BEGIN
|
|
|
1491
1504
|
let n = a[t];
|
|
1492
1505
|
if (n.op.kind !== "create-table") continue;
|
|
1493
1506
|
let r = n.op;
|
|
1494
|
-
if (!r.columns.some((e) => d.has(
|
|
1495
|
-
let i = r.columns.map((t) => d.has(
|
|
1507
|
+
if (!r.columns.some((e) => d.has(E(r.table, e.name)))) continue;
|
|
1508
|
+
let i = r.columns.map((t) => d.has(E(r.table, t.name)) ? e(t) : t);
|
|
1496
1509
|
a[t] = {
|
|
1497
1510
|
...n,
|
|
1498
1511
|
op: {
|
|
@@ -1501,24 +1514,24 @@ BEGIN
|
|
|
1501
1514
|
}
|
|
1502
1515
|
};
|
|
1503
1516
|
}
|
|
1504
|
-
a.push(...
|
|
1517
|
+
a.push(...f);
|
|
1505
1518
|
}
|
|
1506
|
-
let
|
|
1507
|
-
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);
|
|
1508
1521
|
if (n !== void 0) return n;
|
|
1509
1522
|
if (t.has(e)) return 0;
|
|
1510
|
-
let r =
|
|
1523
|
+
let r = p.get(e);
|
|
1511
1524
|
if (!r) return 0;
|
|
1512
1525
|
let i = new Set(t).add(e), a = 0;
|
|
1513
1526
|
for (let t of r.columns) {
|
|
1514
1527
|
let n = t.references?.table;
|
|
1515
|
-
n && n !== e && !d.has(
|
|
1528
|
+
n && n !== e && !d.has(E(e, t.name)) && (a = Math.max(a, h(n, i) + 1));
|
|
1516
1529
|
}
|
|
1517
|
-
return
|
|
1518
|
-
},
|
|
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) => {
|
|
1519
1532
|
let t = "table" in e ? e.table : "";
|
|
1520
|
-
return e.kind === "create-table" ?
|
|
1521
|
-
},
|
|
1533
|
+
return e.kind === "create-table" ? h(t) : e.kind === "drop-table" ? -h(t) : 0;
|
|
1534
|
+
}, y = {
|
|
1522
1535
|
"add-column": 0,
|
|
1523
1536
|
"rename-column": 1,
|
|
1524
1537
|
"rename-index": 1,
|
|
@@ -1536,23 +1549,23 @@ BEGIN
|
|
|
1536
1549
|
"add-unique-composite": 5,
|
|
1537
1550
|
"add-foreign-key": 5,
|
|
1538
1551
|
"add-check": 5
|
|
1539
|
-
},
|
|
1540
|
-
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);
|
|
1541
1554
|
if (n !== r) return n - r;
|
|
1542
|
-
let i =
|
|
1555
|
+
let i = v(e.op), a = v(t.op);
|
|
1543
1556
|
if (i !== a) return i - a;
|
|
1544
1557
|
let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
|
|
1545
1558
|
if (o !== s) return o.localeCompare(s);
|
|
1546
|
-
let c =
|
|
1559
|
+
let c = b(e.op.kind), l = b(t.op.kind);
|
|
1547
1560
|
return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
|
|
1548
1561
|
});
|
|
1549
1562
|
return {
|
|
1550
1563
|
operations: S,
|
|
1551
|
-
fromFingerprint:
|
|
1552
|
-
toFingerprint:
|
|
1553
|
-
summary:
|
|
1564
|
+
fromFingerprint: Jt(e.live),
|
|
1565
|
+
toFingerprint: Jt(t),
|
|
1566
|
+
summary: In(S)
|
|
1554
1567
|
};
|
|
1555
|
-
},
|
|
1568
|
+
}, Rn = (e) => {
|
|
1556
1569
|
let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
|
|
1557
1570
|
if (!t) return null;
|
|
1558
1571
|
let n = [...e.replace(/\\'/g, "'").matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'")).filter((e) => e.length > 0);
|
|
@@ -1560,7 +1573,7 @@ BEGIN
|
|
|
1560
1573
|
column: t[1],
|
|
1561
1574
|
values: n
|
|
1562
1575
|
};
|
|
1563
|
-
},
|
|
1576
|
+
}, zn = (e, t) => {
|
|
1564
1577
|
if (t === "vector") return "vector";
|
|
1565
1578
|
switch (e) {
|
|
1566
1579
|
case "text":
|
|
@@ -1587,10 +1600,10 @@ BEGIN
|
|
|
1587
1600
|
case "USER-DEFINED": return "text";
|
|
1588
1601
|
default: return "text";
|
|
1589
1602
|
}
|
|
1590
|
-
},
|
|
1603
|
+
}, Bn = (e, t) => e == null || e === "" ? void 0 : { generatedAs: {
|
|
1591
1604
|
expr: e,
|
|
1592
1605
|
stored: t
|
|
1593
|
-
} },
|
|
1606
|
+
} }, R = (e) => {
|
|
1594
1607
|
switch (e.toUpperCase()) {
|
|
1595
1608
|
case "CASCADE": return "cascade";
|
|
1596
1609
|
case "RESTRICT": return "restrict";
|
|
@@ -1598,25 +1611,25 @@ BEGIN
|
|
|
1598
1611
|
case "SET DEFAULT": return "noAction";
|
|
1599
1612
|
default: return "noAction";
|
|
1600
1613
|
}
|
|
1601
|
-
},
|
|
1614
|
+
}, Vn = (e, t) => {
|
|
1602
1615
|
let n = e !== void 0 && e !== "" ? Number(e) : NaN;
|
|
1603
1616
|
return Number.isInteger(n) && n > 0 ? n : t;
|
|
1604
|
-
},
|
|
1617
|
+
}, Hn = () => Vn(process.env.VOLTRO_INTROSPECT_BATCH, 20), Un = 300, Wn = () => {
|
|
1605
1618
|
let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
|
|
1606
|
-
return e !== void 0 && e.trim() === "0" ? 0 :
|
|
1607
|
-
},
|
|
1619
|
+
return e !== void 0 && e.trim() === "0" ? 0 : Vn(e, 3e4);
|
|
1620
|
+
}, Gn = (e, t) => {
|
|
1608
1621
|
let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
|
|
1609
1622
|
for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
|
|
1610
1623
|
return r;
|
|
1611
|
-
},
|
|
1612
|
-
let t =
|
|
1624
|
+
}, Kn = (e) => {
|
|
1625
|
+
let t = Wn(), n = C.gen(function* () {
|
|
1613
1626
|
t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
|
|
1614
|
-
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* () {
|
|
1615
1628
|
let r = [];
|
|
1616
|
-
for (let a of
|
|
1629
|
+
for (let a of Gn(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
|
|
1617
1630
|
return r;
|
|
1618
1631
|
}), o = [];
|
|
1619
|
-
for (let t = 0;; t +=
|
|
1632
|
+
for (let t = 0;; t += Un) {
|
|
1620
1633
|
let n = yield* e`
|
|
1621
1634
|
SELECT c.relname AS table_name,
|
|
1622
1635
|
COALESCE(c.reltuples::bigint, 0) AS row_count
|
|
@@ -1624,9 +1637,9 @@ BEGIN
|
|
|
1624
1637
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1625
1638
|
WHERE n.nspname = current_schema() AND c.relkind = 'r'
|
|
1626
1639
|
ORDER BY c.relname
|
|
1627
|
-
LIMIT ${r(
|
|
1640
|
+
LIMIT ${r(Un)} OFFSET ${r(t)}
|
|
1628
1641
|
`;
|
|
1629
|
-
if (o.push(...n), n.length <
|
|
1642
|
+
if (o.push(...n), n.length < Un) break;
|
|
1630
1643
|
}
|
|
1631
1644
|
let s = /* @__PURE__ */ new Set(), c = [];
|
|
1632
1645
|
for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
|
|
@@ -1712,7 +1725,7 @@ BEGIN
|
|
|
1712
1725
|
AND c.relname IN ${t}
|
|
1713
1726
|
)
|
|
1714
1727
|
SELECT * FROM ix ORDER BY table_name, index_name, position
|
|
1715
|
-
`), _ = /* @__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();
|
|
1716
1729
|
for (let e of u) {
|
|
1717
1730
|
let t = _.get(e.table_name);
|
|
1718
1731
|
t || (t = [], _.set(e.table_name, t)), t.push(e);
|
|
@@ -1721,18 +1734,18 @@ BEGIN
|
|
|
1721
1734
|
let t = v.get(e.table_name);
|
|
1722
1735
|
t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
|
|
1723
1736
|
}
|
|
1724
|
-
let
|
|
1737
|
+
let ee = /* @__PURE__ */ new Map();
|
|
1725
1738
|
for (let e of f) {
|
|
1726
|
-
let t = `${e.table_name}\u0000${e.constraint_name}`, n =
|
|
1739
|
+
let t = `${e.table_name}\u0000${e.constraint_name}`, n = ee.get(t);
|
|
1727
1740
|
n || (n = {
|
|
1728
1741
|
table: e.table_name,
|
|
1729
1742
|
columns: []
|
|
1730
|
-
},
|
|
1743
|
+
}, ee.set(t, n)), n.columns.push({
|
|
1731
1744
|
name: e.column_name,
|
|
1732
1745
|
position: e.position
|
|
1733
1746
|
});
|
|
1734
1747
|
}
|
|
1735
|
-
for (let [e, t] of
|
|
1748
|
+
for (let [e, t] of ee) {
|
|
1736
1749
|
let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
|
|
1737
1750
|
if (n.length === 1) {
|
|
1738
1751
|
let e = y.get(t.table);
|
|
@@ -1752,33 +1765,33 @@ BEGIN
|
|
|
1752
1765
|
t || (t = [], x.set(e.source_table, t)), t.push(e);
|
|
1753
1766
|
}
|
|
1754
1767
|
for (let e of g) {
|
|
1755
|
-
let t =
|
|
1756
|
-
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));
|
|
1757
1770
|
let n = t.get(e.index_name);
|
|
1758
1771
|
n || (n = [], t.set(e.index_name, n)), n.push(e);
|
|
1759
1772
|
}
|
|
1760
|
-
let
|
|
1773
|
+
let w = [];
|
|
1761
1774
|
for (let e of c) {
|
|
1762
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) => {
|
|
1763
|
-
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 ? {
|
|
1764
1777
|
table: a.target_table,
|
|
1765
1778
|
column: a.target_column,
|
|
1766
|
-
onDelete:
|
|
1767
|
-
onUpdate:
|
|
1779
|
+
onDelete: R(a.delete_rule),
|
|
1780
|
+
onUpdate: R(a.update_rule)
|
|
1768
1781
|
} : void 0, l = m.get(`${e.table_name}.${t.column_name}`);
|
|
1769
1782
|
return {
|
|
1770
1783
|
name: t.column_name,
|
|
1771
1784
|
type: s,
|
|
1772
|
-
...
|
|
1785
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
1773
1786
|
nullable: t.is_nullable === "YES",
|
|
1774
1787
|
unique: i.has(t.column_name) || n && t.column_name === "id",
|
|
1775
1788
|
hasDefault: t.column_default !== null,
|
|
1776
1789
|
...t.column_default === null ? {} : { defaultValue: t.column_default },
|
|
1777
1790
|
...c ? { references: c } : {},
|
|
1778
1791
|
...l ? { oneOf: l } : {},
|
|
1779
|
-
...
|
|
1792
|
+
...Bn(t.is_generated === "ALWAYS" ? t.generation_expression ?? "generated" : null, !0) ?? {}
|
|
1780
1793
|
};
|
|
1781
|
-
}), l = [], u =
|
|
1794
|
+
}), l = [], u = S.get(e.table_name);
|
|
1782
1795
|
if (u) for (let [t, n] of u) {
|
|
1783
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) => {
|
|
1784
1797
|
let t = e.position;
|
|
@@ -1802,20 +1815,20 @@ BEGIN
|
|
|
1802
1815
|
unique: !0
|
|
1803
1816
|
});
|
|
1804
1817
|
let d = Number(e.row_count ?? 0);
|
|
1805
|
-
|
|
1818
|
+
w.push({
|
|
1806
1819
|
name: e.table_name,
|
|
1807
1820
|
columns: c,
|
|
1808
1821
|
indexes: l,
|
|
1809
1822
|
...d > 0 ? { rowCount: d } : {}
|
|
1810
1823
|
});
|
|
1811
1824
|
}
|
|
1812
|
-
return { tables:
|
|
1825
|
+
return { tables: w };
|
|
1813
1826
|
});
|
|
1814
|
-
return (t > 0 ? e.withTransaction(n) : n).pipe(
|
|
1827
|
+
return (t > 0 ? e.withTransaction(n) : n).pipe(C.catchAll((e) => {
|
|
1815
1828
|
let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
|
|
1816
|
-
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);
|
|
1817
1830
|
}));
|
|
1818
|
-
},
|
|
1831
|
+
}, qn = (e, t) => {
|
|
1819
1832
|
switch (e.toLowerCase()) {
|
|
1820
1833
|
case "varchar":
|
|
1821
1834
|
case "char":
|
|
@@ -1847,21 +1860,21 @@ BEGIN
|
|
|
1847
1860
|
case "json": return "json";
|
|
1848
1861
|
default: return "text";
|
|
1849
1862
|
}
|
|
1850
|
-
},
|
|
1863
|
+
}, z = (e) => e.map((e) => {
|
|
1851
1864
|
let t = e, n = {};
|
|
1852
1865
|
for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
|
|
1853
1866
|
return n;
|
|
1854
|
-
}),
|
|
1855
|
-
let t =
|
|
1867
|
+
}), Jn = (e) => C.gen(function* () {
|
|
1868
|
+
let t = z(yield* e`
|
|
1856
1869
|
SELECT table_name, COALESCE(table_rows, 0) AS table_rows
|
|
1857
1870
|
FROM information_schema.tables
|
|
1858
1871
|
WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
|
|
1859
|
-
ORDER BY table_name`), n =
|
|
1872
|
+
ORDER BY table_name`), n = z(yield* e`
|
|
1860
1873
|
SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
|
|
1861
1874
|
character_maximum_length, generation_expression, extra
|
|
1862
1875
|
FROM information_schema.columns
|
|
1863
1876
|
WHERE table_schema = DATABASE()
|
|
1864
|
-
ORDER BY table_name, ordinal_position`), r =
|
|
1877
|
+
ORDER BY table_name, ordinal_position`), r = z(yield* e`
|
|
1865
1878
|
SELECT k.table_name AS source_table,
|
|
1866
1879
|
k.column_name AS source_column,
|
|
1867
1880
|
k.referenced_table_name AS target_table,
|
|
@@ -1871,7 +1884,7 @@ BEGIN
|
|
|
1871
1884
|
JOIN information_schema.referential_constraints r
|
|
1872
1885
|
ON k.constraint_name = r.constraint_name
|
|
1873
1886
|
AND k.table_schema = r.constraint_schema
|
|
1874
|
-
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`
|
|
1875
1888
|
SELECT table_name, index_name, non_unique, column_name, seq_in_index
|
|
1876
1889
|
FROM information_schema.statistics
|
|
1877
1890
|
WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
|
|
@@ -1884,14 +1897,14 @@ BEGIN
|
|
|
1884
1897
|
JOIN information_schema.table_constraints tc
|
|
1885
1898
|
ON tc.constraint_schema = cc.constraint_schema
|
|
1886
1899
|
AND tc.constraint_name = cc.constraint_name
|
|
1887
|
-
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();
|
|
1888
1901
|
for (let e of s) {
|
|
1889
1902
|
let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
|
|
1890
1903
|
if (t) {
|
|
1891
1904
|
c.add(`${e.table_name}.${t[1]}`);
|
|
1892
1905
|
continue;
|
|
1893
1906
|
}
|
|
1894
|
-
let n =
|
|
1907
|
+
let n = Rn(e.check_clause);
|
|
1895
1908
|
n && l.set(`${e.table_name}.${n.column}`, n.values);
|
|
1896
1909
|
}
|
|
1897
1910
|
let u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map();
|
|
@@ -1914,23 +1927,23 @@ BEGIN
|
|
|
1914
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);
|
|
1915
1928
|
if (o) for (let e of o.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
|
|
1916
1929
|
let s = t.map((t) => {
|
|
1917
|
-
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 ? {
|
|
1918
1931
|
table: o.target_table,
|
|
1919
1932
|
column: o.target_column,
|
|
1920
|
-
onDelete:
|
|
1921
|
-
onUpdate:
|
|
1933
|
+
onDelete: R(o.delete_rule),
|
|
1934
|
+
onUpdate: R(o.update_rule)
|
|
1922
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}`);
|
|
1923
1936
|
return {
|
|
1924
1937
|
name: t.column_name,
|
|
1925
1938
|
type: s,
|
|
1926
1939
|
nullable: t.is_nullable === "YES",
|
|
1927
|
-
...
|
|
1940
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
1928
1941
|
unique: d,
|
|
1929
1942
|
hasDefault: f !== null,
|
|
1930
1943
|
...f === null ? {} : { defaultValue: f },
|
|
1931
1944
|
...u ? { references: u } : {},
|
|
1932
1945
|
...p ? { oneOf: p } : {},
|
|
1933
|
-
...
|
|
1946
|
+
...Bn(t.generation_expression, /STORED/i.test(t.extra ?? "")) ?? {}
|
|
1934
1947
|
};
|
|
1935
1948
|
}), m = new Set(n.map((e) => e.source_column)), h = [];
|
|
1936
1949
|
if (o) for (let [t, n] of o) {
|
|
@@ -1957,10 +1970,10 @@ BEGIN
|
|
|
1957
1970
|
});
|
|
1958
1971
|
}
|
|
1959
1972
|
return { tables: p };
|
|
1960
|
-
}),
|
|
1973
|
+
}), Yn = (e) => {
|
|
1961
1974
|
let t = e.toUpperCase();
|
|
1962
1975
|
return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
|
|
1963
|
-
},
|
|
1976
|
+
}, Xn = (e) => e === 1 || e === !0, Zn = (e) => C.gen(function* () {
|
|
1964
1977
|
let t = yield* e`
|
|
1965
1978
|
SELECT name, sql FROM sqlite_master
|
|
1966
1979
|
WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
|
|
@@ -1971,53 +1984,53 @@ BEGIN
|
|
|
1971
1984
|
let n = [...e[2].matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
|
|
1972
1985
|
n.length > 0 && t.set(e[1], n);
|
|
1973
1986
|
}
|
|
1974
|
-
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 = /* @__PURE__ */ new Map(),
|
|
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();
|
|
1975
1988
|
for (let t of c) {
|
|
1976
|
-
let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null);
|
|
1977
|
-
|
|
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), Xn(t.unique) && r.length === 1 && p.add(r[0]);
|
|
1978
1991
|
}
|
|
1979
|
-
let
|
|
1980
|
-
let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" :
|
|
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" : Yn(e.type), a = r ? {
|
|
1981
1994
|
table: r.table,
|
|
1982
1995
|
column: r.to,
|
|
1983
|
-
onDelete:
|
|
1984
|
-
onUpdate:
|
|
1996
|
+
onDelete: R(r.on_delete),
|
|
1997
|
+
onUpdate: R(r.on_update)
|
|
1985
1998
|
} : void 0, o = t.get(e.name);
|
|
1986
1999
|
return {
|
|
1987
2000
|
name: e.name,
|
|
1988
2001
|
type: i,
|
|
1989
2002
|
nullable: e.notnull === 0,
|
|
1990
|
-
unique:
|
|
2003
|
+
unique: p.has(e.name) || n && e.name === "id",
|
|
1991
2004
|
hasDefault: e.dflt_value !== null,
|
|
1992
2005
|
...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
|
|
1993
2006
|
...a ? { references: a } : {},
|
|
1994
2007
|
...o ? { oneOf: o } : {},
|
|
1995
|
-
...
|
|
2008
|
+
...Bn(e.hidden === 2 || e.hidden === 3 ? "generated" : null, e.hidden === 3) ?? {}
|
|
1996
2009
|
};
|
|
1997
|
-
}),
|
|
2010
|
+
}), h = new Set(s.map((e) => e.from)), g = [];
|
|
1998
2011
|
for (let e of c) {
|
|
1999
2012
|
if (e.origin === "pk") continue;
|
|
2000
|
-
let t =
|
|
2001
|
-
|
|
2013
|
+
let t = f.get(e.name) ?? [];
|
|
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({
|
|
2002
2015
|
name: e.name,
|
|
2003
2016
|
table: i,
|
|
2004
2017
|
columns: t,
|
|
2005
|
-
unique: e.unique
|
|
2006
|
-
})
|
|
2018
|
+
unique: Xn(e.unique)
|
|
2019
|
+
});
|
|
2007
2020
|
}
|
|
2008
|
-
u.length > 0 &&
|
|
2021
|
+
u.length > 0 && g.push({
|
|
2009
2022
|
name: `${i}_pkey`,
|
|
2010
2023
|
table: i,
|
|
2011
2024
|
columns: u,
|
|
2012
2025
|
unique: !0
|
|
2013
2026
|
}), r.push({
|
|
2014
2027
|
name: i,
|
|
2015
|
-
columns:
|
|
2016
|
-
indexes:
|
|
2028
|
+
columns: m,
|
|
2029
|
+
indexes: g
|
|
2017
2030
|
});
|
|
2018
2031
|
}
|
|
2019
2032
|
return { tables: r };
|
|
2020
|
-
}),
|
|
2033
|
+
}), Qn = (e) => {
|
|
2021
2034
|
switch (e.toLowerCase()) {
|
|
2022
2035
|
case "int":
|
|
2023
2036
|
case "smallint":
|
|
@@ -2039,14 +2052,14 @@ BEGIN
|
|
|
2039
2052
|
case "image": return "bytes";
|
|
2040
2053
|
default: return "text";
|
|
2041
2054
|
}
|
|
2042
|
-
},
|
|
2055
|
+
}, B = (e) => e === !0 || e === 1, $n = (e) => C.gen(function* () {
|
|
2043
2056
|
let t = yield* e`
|
|
2044
2057
|
SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
|
|
2045
2058
|
WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
|
|
2046
2059
|
SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
|
|
2047
2060
|
IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default,
|
|
2048
2061
|
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length
|
|
2049
|
-
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`
|
|
2050
2063
|
SELECT t.name AS table_name, c.name AS column_name, cc.definition AS definition,
|
|
2051
2064
|
cc.is_persisted AS is_persisted
|
|
2052
2065
|
FROM sys.computed_columns cc
|
|
@@ -2101,36 +2114,36 @@ BEGIN
|
|
|
2101
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();
|
|
2102
2115
|
if (o) for (let [, e] of o) {
|
|
2103
2116
|
let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2104
|
-
if (
|
|
2105
|
-
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);
|
|
2106
2119
|
}
|
|
2107
2120
|
let m = t.map((t) => {
|
|
2108
|
-
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 ? {
|
|
2109
2122
|
table: a.target_table,
|
|
2110
2123
|
column: a.target_column,
|
|
2111
|
-
onDelete:
|
|
2112
|
-
onUpdate:
|
|
2113
|
-
} : 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}`);
|
|
2114
2127
|
return {
|
|
2115
2128
|
name: t.column_name,
|
|
2116
2129
|
type: o,
|
|
2117
2130
|
nullable: t.is_nullable === "YES",
|
|
2118
|
-
...
|
|
2131
|
+
...V(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: V(t.data_type, t.character_maximum_length) },
|
|
2119
2132
|
unique: p.has(t.column_name) || n && t.column_name === "id",
|
|
2120
2133
|
hasDefault: u !== null,
|
|
2121
2134
|
...u === null ? {} : { defaultValue: u },
|
|
2122
2135
|
...l ? { references: l } : {},
|
|
2123
2136
|
...d ? { oneOf: d } : {},
|
|
2124
|
-
...
|
|
2137
|
+
...Bn(i.get(`${e}.${t.column_name}`)?.definition ?? null, B(i.get(`${e}.${t.column_name}`)?.is_persisted ?? !1)) ?? {}
|
|
2125
2138
|
};
|
|
2126
2139
|
}), h = [];
|
|
2127
2140
|
if (o) for (let [t, n] of o) {
|
|
2128
2141
|
let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
|
|
2129
|
-
|
|
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({
|
|
2130
2143
|
name: t,
|
|
2131
2144
|
table: e,
|
|
2132
2145
|
columns: r.map((e) => e.column_name),
|
|
2133
|
-
unique:
|
|
2146
|
+
unique: B(r[0].is_unique)
|
|
2134
2147
|
});
|
|
2135
2148
|
}
|
|
2136
2149
|
s.length > 0 && h.push({
|
|
@@ -2145,90 +2158,90 @@ BEGIN
|
|
|
2145
2158
|
});
|
|
2146
2159
|
}
|
|
2147
2160
|
return { tables: f };
|
|
2148
|
-
}),
|
|
2161
|
+
}), er = (e) => {
|
|
2149
2162
|
switch (e.toUpperCase().replace(/_/g, " ")) {
|
|
2150
2163
|
case "CASCADE": return "cascade";
|
|
2151
2164
|
case "SET NULL": return "setNull";
|
|
2152
2165
|
case "SET DEFAULT": return "noAction";
|
|
2153
2166
|
default: return "noAction";
|
|
2154
2167
|
}
|
|
2155
|
-
},
|
|
2168
|
+
}, tr = (e) => {
|
|
2156
2169
|
let t = e.trim();
|
|
2157
2170
|
for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
|
|
2158
2171
|
return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
|
|
2159
|
-
},
|
|
2172
|
+
}, nr = /* @__PURE__ */ new Set([
|
|
2160
2173
|
"character varying",
|
|
2161
2174
|
"varchar",
|
|
2162
2175
|
"nvarchar",
|
|
2163
2176
|
"char",
|
|
2164
2177
|
"character",
|
|
2165
2178
|
"nchar"
|
|
2166
|
-
]),
|
|
2167
|
-
if (!
|
|
2179
|
+
]), V = (e, t) => {
|
|
2180
|
+
if (!nr.has(e.toLowerCase())) return;
|
|
2168
2181
|
let n = Number(t);
|
|
2169
2182
|
if (!(!Number.isFinite(n) || n <= 0)) return n;
|
|
2170
|
-
},
|
|
2171
|
-
mysql: () =>
|
|
2172
|
-
mssql: () =>
|
|
2173
|
-
sqlite: () =>
|
|
2174
|
-
orElse: () =>
|
|
2175
|
-
}).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) => ({
|
|
2176
2189
|
...e,
|
|
2177
|
-
tables: e.tables.filter((e) => !
|
|
2178
|
-
}))),
|
|
2179
|
-
let t =
|
|
2180
|
-
return t === void 0 ?
|
|
2181
|
-
}),
|
|
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) => {
|
|
2182
2195
|
let t = e[0]?.v;
|
|
2183
|
-
return typeof t == "string" ?
|
|
2184
|
-
}),
|
|
2196
|
+
return typeof t == "string" ? ar(t) : "mysql";
|
|
2197
|
+
}), C.catchAll(() => C.succeed("mysql"))), cr = (e) => {
|
|
2185
2198
|
let t = e;
|
|
2186
2199
|
for (let e = 0; e < 6 && typeof t == "object" && t; e++) {
|
|
2187
2200
|
let e = t;
|
|
2188
2201
|
if (typeof e.errno == "number") return e.errno;
|
|
2189
2202
|
t = e.cause;
|
|
2190
2203
|
}
|
|
2191
|
-
},
|
|
2204
|
+
}, lr = (e) => {
|
|
2192
2205
|
let t = [], n = e;
|
|
2193
2206
|
for (let e = 0; e < 6 && typeof n == "object" && n; e++) {
|
|
2194
2207
|
let e = n;
|
|
2195
2208
|
typeof e.message == "string" && t.push(e.message), n = e.cause;
|
|
2196
2209
|
}
|
|
2197
2210
|
return t.join(" | ");
|
|
2198
|
-
},
|
|
2211
|
+
}, ur = (e, t) => {
|
|
2199
2212
|
if (t.length === 0) return !1;
|
|
2200
|
-
let n =
|
|
2213
|
+
let n = cr(e), r = lr(e);
|
|
2201
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)));
|
|
2202
|
-
},
|
|
2215
|
+
}, dr = {
|
|
2203
2216
|
why: "mysql has no CREATE INDEX IF NOT EXISTS; 1061 is exactly that condition",
|
|
2204
2217
|
errno: [1061]
|
|
2205
|
-
},
|
|
2218
|
+
}, fr = {
|
|
2206
2219
|
why: "mysql has no DROP COLUMN IF EXISTS; 1091 is exactly that condition",
|
|
2207
2220
|
errno: [1091]
|
|
2208
|
-
},
|
|
2221
|
+
}, pr = {
|
|
2209
2222
|
why: "sqlite has no DROP COLUMN IF EXISTS, and reports the absent column only in the message",
|
|
2210
2223
|
messageIncludes: ["no such column"]
|
|
2211
|
-
},
|
|
2224
|
+
}, mr = {
|
|
2212
2225
|
why: "mysql/mariadb DROP CONSTRAINT has no portable IF EXISTS; 1091 / 3940 are exactly \"already gone\"",
|
|
2213
2226
|
errno: [1091, 3940]
|
|
2214
|
-
},
|
|
2215
|
-
mysql: () =>
|
|
2216
|
-
orElse: () =>
|
|
2217
|
-
}),
|
|
2218
|
-
if ((e.type !== "text" || e.maxLength === void 0) && !
|
|
2227
|
+
}, U = (e, t) => e.onDialectOrElse({
|
|
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;
|
|
2219
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;
|
|
2220
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.`);
|
|
2221
|
-
return
|
|
2222
|
-
},
|
|
2223
|
-
let t =
|
|
2224
|
-
return t === void 0 ?
|
|
2225
|
-
},
|
|
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) => {
|
|
2226
2239
|
switch (e.type) {
|
|
2227
2240
|
case "id": return "text";
|
|
2228
2241
|
case "text": return "text";
|
|
2229
2242
|
case "integer": return "integer";
|
|
2230
2243
|
case "real": return "double precision";
|
|
2231
|
-
case "decimal": return
|
|
2244
|
+
case "decimal": return hr(e, "NUMERIC");
|
|
2232
2245
|
case "bigint": return "bigint";
|
|
2233
2246
|
case "boolean": return "boolean";
|
|
2234
2247
|
case "timestamp": return "timestamptz";
|
|
@@ -2242,15 +2255,15 @@ BEGIN
|
|
|
2242
2255
|
case "interval": return "interval";
|
|
2243
2256
|
case "raw": return e.rawDdl ?? "text";
|
|
2244
2257
|
}
|
|
2245
|
-
},
|
|
2246
|
-
let t =
|
|
2258
|
+
}, br = (e) => {
|
|
2259
|
+
let t = _r(e, "mariadb");
|
|
2247
2260
|
if (t !== void 0) return t;
|
|
2248
2261
|
switch (e.type) {
|
|
2249
2262
|
case "id": return "VARCHAR(64)";
|
|
2250
2263
|
case "text": return "LONGTEXT";
|
|
2251
2264
|
case "integer": return "INT";
|
|
2252
2265
|
case "real": return "DOUBLE";
|
|
2253
|
-
case "decimal": return
|
|
2266
|
+
case "decimal": return hr(e, "DECIMAL");
|
|
2254
2267
|
case "bigint": return "BIGINT";
|
|
2255
2268
|
case "boolean": return "TINYINT(1)";
|
|
2256
2269
|
case "timestamp": return "DATETIME(6)";
|
|
@@ -2264,64 +2277,64 @@ BEGIN
|
|
|
2264
2277
|
case "interval": return "BIGINT";
|
|
2265
2278
|
case "raw": return e.rawDdl ?? "LONGTEXT";
|
|
2266
2279
|
}
|
|
2267
|
-
},
|
|
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) => {
|
|
2268
2281
|
let { defaultFactory: n, ...r } = e;
|
|
2269
|
-
return
|
|
2282
|
+
return j(e, t) !== j({
|
|
2270
2283
|
...r,
|
|
2271
2284
|
hasDefault: !1
|
|
2272
2285
|
}, t);
|
|
2273
|
-
},
|
|
2286
|
+
}, Or = (e, t) => {
|
|
2274
2287
|
let n = t(e.defaultValue);
|
|
2275
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.`);
|
|
2276
2289
|
return n;
|
|
2277
|
-
},
|
|
2278
|
-
let r =
|
|
2279
|
-
return r ?
|
|
2280
|
-
},
|
|
2281
|
-
let r = n ?? e.nullable, i =
|
|
2290
|
+
}, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], kr = (e, t, n) => {
|
|
2291
|
+
let r = K(e, t, n);
|
|
2292
|
+
return r ? Xt(n, r) : void 0;
|
|
2293
|
+
}, Ar = (e, t, n) => {
|
|
2294
|
+
let r = n ?? e.nullable, i = nt(e, "mariadb");
|
|
2282
2295
|
return [
|
|
2283
|
-
|
|
2284
|
-
|
|
2296
|
+
G(t),
|
|
2297
|
+
j(e, "mariadb"),
|
|
2285
2298
|
r ? null : "NOT NULL",
|
|
2286
2299
|
i
|
|
2287
2300
|
].filter(Boolean).join(" ");
|
|
2288
|
-
},
|
|
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) => {
|
|
2289
2302
|
if (!e.generatedAs) return null;
|
|
2290
2303
|
let { expr: n, stored: r } = e.generatedAs;
|
|
2291
2304
|
return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
|
|
2292
|
-
},
|
|
2293
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2294
|
-
let t =
|
|
2295
|
-
if (t) return `${
|
|
2296
|
-
let n = [
|
|
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)];
|
|
2297
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) {
|
|
2298
|
-
let t =
|
|
2311
|
+
let t = Nr(e.defaultValue, e);
|
|
2299
2312
|
t && n.push(t);
|
|
2300
2313
|
}
|
|
2301
|
-
return e.references && (n.push(`REFERENCES ${
|
|
2314
|
+
return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
|
|
2302
2315
|
cascade: "CASCADE",
|
|
2303
2316
|
restrict: "RESTRICT",
|
|
2304
2317
|
setNull: "SET NULL",
|
|
2305
2318
|
noAction: "NO ACTION"
|
|
2306
2319
|
}[e.references.onDelete]}`)), n.join(" ");
|
|
2307
|
-
},
|
|
2308
|
-
let t = e.columns.map((e) => ` ${
|
|
2309
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
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(", ")})`);
|
|
2310
2323
|
return n;
|
|
2311
|
-
},
|
|
2312
|
-
let t =
|
|
2324
|
+
}, Rr = 191, zr = (e) => {
|
|
2325
|
+
let t = br(e).toUpperCase();
|
|
2313
2326
|
return t.endsWith("TEXT") || t.endsWith("BLOB");
|
|
2314
|
-
},
|
|
2315
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2316
|
-
let t =
|
|
2317
|
-
if (t) return `${
|
|
2318
|
-
let n = [
|
|
2319
|
-
if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !
|
|
2320
|
-
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);
|
|
2321
2334
|
t && n.push(t);
|
|
2322
2335
|
}
|
|
2323
2336
|
return n.join(" ");
|
|
2324
|
-
},
|
|
2337
|
+
}, Vr = (e) => e.columns.flatMap((t) => {
|
|
2325
2338
|
if (!t.references) return [];
|
|
2326
2339
|
let n = t.references.onDelete ? ` ON DELETE ${{
|
|
2327
2340
|
cascade: "CASCADE",
|
|
@@ -2329,27 +2342,27 @@ BEGIN
|
|
|
2329
2342
|
setNull: "SET NULL",
|
|
2330
2343
|
noAction: "NO ACTION"
|
|
2331
2344
|
}[t.references.onDelete]}` : "";
|
|
2332
|
-
return [` CONSTRAINT ${
|
|
2333
|
-
}),
|
|
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
|
+
}), Hr = (e, t = "mariadb") => {
|
|
2334
2347
|
let n = new Map(e.columns.map((e) => [e.name, e])), r = (e) => {
|
|
2335
|
-
let t =
|
|
2336
|
-
return t === void 0 ?
|
|
2337
|
-
}, i = e.columns.map((e) => ` ${
|
|
2338
|
-
for (let n of e.columns) n.unique && n.type !== "id" &&
|
|
2339
|
-
for (let n of e.indexes) n.name !== `${e.table}_pkey` && s.push(`CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${
|
|
2348
|
+
let t = ni(n.get(e));
|
|
2349
|
+
return t === void 0 ? G(e) : `${G(e)}(${t})`;
|
|
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(", ")})`);
|
|
2340
2353
|
return s;
|
|
2341
|
-
},
|
|
2354
|
+
}, Ur = {
|
|
2342
2355
|
cascade: "CASCADE",
|
|
2343
2356
|
restrict: "RESTRICT",
|
|
2344
2357
|
setNull: "SET NULL",
|
|
2345
2358
|
noAction: "NO ACTION"
|
|
2346
|
-
},
|
|
2359
|
+
}, Wr = {
|
|
2347
2360
|
cascade: "CASCADE",
|
|
2348
2361
|
restrict: "NO ACTION",
|
|
2349
2362
|
setNull: "SET NULL",
|
|
2350
2363
|
noAction: "NO ACTION"
|
|
2351
|
-
},
|
|
2352
|
-
let t =
|
|
2364
|
+
}, Gr = (e) => {
|
|
2365
|
+
let t = _r(e, "sqlite");
|
|
2353
2366
|
if (t !== void 0) return t;
|
|
2354
2367
|
switch (e.type) {
|
|
2355
2368
|
case "integer":
|
|
@@ -2360,60 +2373,60 @@ BEGIN
|
|
|
2360
2373
|
case "bytes": return "BLOB";
|
|
2361
2374
|
default: return "TEXT";
|
|
2362
2375
|
}
|
|
2363
|
-
},
|
|
2364
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2365
|
-
let t =
|
|
2366
|
-
if (t) return `${
|
|
2367
|
-
let n = [
|
|
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)];
|
|
2368
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) {
|
|
2369
|
-
let t =
|
|
2382
|
+
let t = q(e.defaultValue, "CURRENT_TIMESTAMP");
|
|
2370
2383
|
t && n.push(t);
|
|
2371
2384
|
}
|
|
2372
|
-
if (e.references && (n.push(`REFERENCES ${
|
|
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) {
|
|
2373
2386
|
let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2374
|
-
n.push(`CHECK (${
|
|
2387
|
+
n.push(`CHECK (${W(e.name)} IN (${t}))`);
|
|
2375
2388
|
}
|
|
2376
2389
|
return n.join(" ");
|
|
2377
|
-
},
|
|
2378
|
-
let t = e.columns.map((e) => ` ${
|
|
2379
|
-
for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
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
|
+
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(", ")})`);
|
|
2380
2393
|
return n;
|
|
2381
2394
|
}, J = (e, t) => {
|
|
2382
2395
|
let n = t.find((t) => t.tableName === e);
|
|
2383
2396
|
if (!n) return [];
|
|
2384
|
-
let r =
|
|
2385
|
-
...
|
|
2397
|
+
let r = F([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => W(e.name)).join(", "), o = [
|
|
2398
|
+
...qr({
|
|
2386
2399
|
kind: "create-table",
|
|
2387
2400
|
table: i,
|
|
2388
2401
|
columns: r.columns,
|
|
2389
2402
|
indexes: [],
|
|
2390
2403
|
...r.primaryKey ? { primaryKey: r.primaryKey } : {}
|
|
2391
2404
|
}),
|
|
2392
|
-
`INSERT INTO ${
|
|
2393
|
-
`DROP TABLE ${
|
|
2394
|
-
`ALTER TABLE ${
|
|
2405
|
+
`INSERT INTO ${W(i)} (${a}) SELECT ${a} FROM ${W(e)}`,
|
|
2406
|
+
`DROP TABLE ${W(e)}`,
|
|
2407
|
+
`ALTER TABLE ${W(i)} RENAME TO ${W(e)}`
|
|
2395
2408
|
];
|
|
2396
|
-
for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${
|
|
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(", ")})`);
|
|
2397
2410
|
return o;
|
|
2398
|
-
},
|
|
2411
|
+
}, Jr = (e, t, n, r) => {
|
|
2399
2412
|
let i = r ?? e.nullable;
|
|
2400
|
-
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${
|
|
2401
|
-
},
|
|
2413
|
+
return `ALTER TABLE ${Y(n)} ALTER COLUMN ${Y(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
|
|
2414
|
+
}, Yr = (e, t) => {
|
|
2402
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}` : "");
|
|
2403
2416
|
if (!e.hasDefault) return n;
|
|
2404
|
-
let r =
|
|
2417
|
+
let r = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2405
2418
|
if (!r) return n;
|
|
2406
2419
|
let i = r.replace(/^DEFAULT\s+/i, "");
|
|
2407
2420
|
return `${n} ALTER TABLE ${Y(e.table)} ADD DEFAULT ${i} FOR ${Y(e.column)};`;
|
|
2408
|
-
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`,
|
|
2409
|
-
let t =
|
|
2421
|
+
}, Y = (e) => `[${e.replace(/]/g, "]]")}]`, Xr = (e) => {
|
|
2422
|
+
let t = _r(e, "mssql");
|
|
2410
2423
|
if (t !== void 0) return t;
|
|
2411
2424
|
switch (e.type) {
|
|
2412
2425
|
case "id":
|
|
2413
2426
|
case "reference": return "NVARCHAR(64)";
|
|
2414
2427
|
case "integer": return "INT";
|
|
2415
2428
|
case "real": return "FLOAT";
|
|
2416
|
-
case "decimal": return
|
|
2429
|
+
case "decimal": return hr(e, "DECIMAL");
|
|
2417
2430
|
case "bigint": return "BIGINT";
|
|
2418
2431
|
case "boolean": return "BIT";
|
|
2419
2432
|
case "timestamp": return "DATETIME2(6)";
|
|
@@ -2421,44 +2434,44 @@ BEGIN
|
|
|
2421
2434
|
case "bytes": return "VARBINARY(MAX)";
|
|
2422
2435
|
default: return "NVARCHAR(MAX)";
|
|
2423
2436
|
}
|
|
2424
|
-
},
|
|
2425
|
-
if (e.type === "id" && e.idScheme?.kind === "numeric") return
|
|
2426
|
-
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");
|
|
2427
2440
|
if (r) return `${Y(e.name)} ${r}`;
|
|
2428
2441
|
let i = [Y(e.name), n];
|
|
2429
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) {
|
|
2430
|
-
let t =
|
|
2443
|
+
let t = q(e.defaultValue, "SYSUTCDATETIME()");
|
|
2431
2444
|
t && i.push(t);
|
|
2432
2445
|
}
|
|
2433
|
-
return e.references && (i.push(`REFERENCES ${Y(e.references.table)} (${Y(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${
|
|
2434
|
-
},
|
|
2435
|
-
let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), 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)}')`];
|
|
2436
2449
|
for (let n of e.indexes) {
|
|
2437
2450
|
if (n.name === `${e.table}_pkey`) continue;
|
|
2438
2451
|
let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Y(n.name)} ON ${Y(e.table)} (${n.columns.map(Y).join(", ")})`;
|
|
2439
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)}')`);
|
|
2440
2453
|
}
|
|
2441
2454
|
return a;
|
|
2442
|
-
},
|
|
2443
|
-
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)}`;
|
|
2444
2457
|
return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
|
|
2445
|
-
},
|
|
2446
|
-
if (e === void 0 || !
|
|
2458
|
+
}, ni = (e) => {
|
|
2459
|
+
if (e === void 0 || !zr(e)) return;
|
|
2447
2460
|
let t = typeof e.maxLength == "number" && e.maxLength > 0 ? e.maxLength : void 0;
|
|
2448
|
-
return t === void 0 ?
|
|
2449
|
-
},
|
|
2450
|
-
let r =
|
|
2451
|
-
return r === void 0 ?
|
|
2452
|
-
},
|
|
2461
|
+
return t === void 0 ? Rr : Math.min(Rr, t);
|
|
2462
|
+
}, ri = (e, t, n) => {
|
|
2463
|
+
let r = ni(kr(e, t, n));
|
|
2464
|
+
return r === void 0 ? G(n) : `${G(n)}(${r})`;
|
|
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) => {
|
|
2453
2466
|
let t = (e) => e.replace(/'/g, "''");
|
|
2454
2467
|
return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
|
|
2455
|
-
},
|
|
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) => {
|
|
2456
2469
|
let t = (e) => e.replace(/'/g, "''");
|
|
2457
2470
|
return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
|
|
2458
|
-
},
|
|
2471
|
+
}, hi = (e) => {
|
|
2459
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(", ")})`;
|
|
2460
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)}');`;
|
|
2461
|
-
},
|
|
2474
|
+
}, gi = (e, t, n) => {
|
|
2462
2475
|
let r = n.find((t) => t.tableName === e);
|
|
2463
2476
|
if (!r) return [];
|
|
2464
2477
|
let i = [];
|
|
@@ -2467,13 +2480,13 @@ BEGIN
|
|
|
2467
2480
|
t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Y(e)} ALTER COLUMN ${Y(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
|
|
2468
2481
|
}
|
|
2469
2482
|
return i;
|
|
2470
|
-
},
|
|
2471
|
-
let t = e.fields.map((e) =>
|
|
2472
|
-
return `ALTER TABLE ${
|
|
2473
|
-
},
|
|
2474
|
-
let n = e.fields.map((n) =>
|
|
2475
|
-
return `ALTER TABLE ${
|
|
2476
|
-
},
|
|
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
|
+
let t = e.fields.map((e) => W(e)).join(", ");
|
|
2485
|
+
return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
|
|
2486
|
+
}, bi = (e, t) => {
|
|
2487
|
+
let n = e.fields.map((n) => ri(t, e.table, n)).join(", ");
|
|
2488
|
+
return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
|
|
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) => {
|
|
2477
2490
|
let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
|
|
2478
2491
|
if (e.orphanPolicy) {
|
|
2479
2492
|
let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
|
|
@@ -2491,34 +2504,34 @@ BEGIN
|
|
|
2491
2504
|
setNull: "SET NULL",
|
|
2492
2505
|
noAction: "NO ACTION"
|
|
2493
2506
|
}[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
|
|
2494
|
-
},
|
|
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) => {
|
|
2495
2508
|
let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
|
|
2496
2509
|
return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
|
|
2497
|
-
},
|
|
2510
|
+
}, ki = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Ai = (e, t) => C.gen(function* () {
|
|
2498
2511
|
let n = yield* e`
|
|
2499
2512
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2500
2513
|
FROM information_schema.check_constraints cc
|
|
2501
|
-
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`
|
|
2502
2515
|
SELECT cc.constraint_name AS n, cc.check_clause AS c
|
|
2503
2516
|
FROM information_schema.check_constraints cc
|
|
2504
2517
|
JOIN information_schema.table_constraints tc
|
|
2505
2518
|
ON tc.constraint_schema = cc.constraint_schema
|
|
2506
2519
|
AND tc.constraint_name = cc.constraint_name
|
|
2507
|
-
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(() => []));
|
|
2508
2521
|
for (let e of n) {
|
|
2509
2522
|
let n = String(e.n ?? "");
|
|
2510
|
-
if (n !== "" &&
|
|
2523
|
+
if (n !== "" && Rn(String(e.c ?? ""))?.column === t.column) return n;
|
|
2511
2524
|
}
|
|
2512
|
-
}),
|
|
2513
|
-
let r = yield*
|
|
2514
|
-
r !== void 0 && (yield* X(e, `ALTER TABLE ${
|
|
2515
|
-
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);
|
|
2516
2529
|
if (i === void 0) return;
|
|
2517
|
-
let a =
|
|
2518
|
-
if (!a) return yield*
|
|
2519
|
-
yield* X(e, `ALTER TABLE ${
|
|
2520
|
-
}),
|
|
2521
|
-
let i = e.column, a = r === "mariadb", o = a ?
|
|
2530
|
+
let a = K(n, t.table, t.column);
|
|
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);
|
|
2522
2535
|
if (u) {
|
|
2523
2536
|
let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
|
|
2524
2537
|
return {
|
|
@@ -2546,7 +2559,7 @@ BEGIN
|
|
|
2546
2559
|
post: f ? [f] : []
|
|
2547
2560
|
};
|
|
2548
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;
|
|
2549
|
-
},
|
|
2562
|
+
}, Ni = (e) => {
|
|
2550
2563
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
2551
2564
|
return (e, n) => {
|
|
2552
2565
|
let r = t.get(e);
|
|
@@ -2566,47 +2579,47 @@ BEGIN
|
|
|
2566
2579
|
...o
|
|
2567
2580
|
};
|
|
2568
2581
|
};
|
|
2569
|
-
}, X = (e, t, n, r = []) => e.unsafe(t).pipe(
|
|
2570
|
-
process.stderr.write(
|
|
2571
|
-
})),
|
|
2572
|
-
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();
|
|
2573
2586
|
return Object.assign(e, { message: r });
|
|
2574
|
-
}),
|
|
2575
|
-
let n =
|
|
2576
|
-
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."));
|
|
2577
2590
|
let r = {
|
|
2578
2591
|
kind: "create-table",
|
|
2579
|
-
table:
|
|
2592
|
+
table: O,
|
|
2580
2593
|
columns: n.columns,
|
|
2581
2594
|
indexes: []
|
|
2582
2595
|
}, i = yield* e.onDialectOrElse({
|
|
2583
|
-
mysql: () =>
|
|
2584
|
-
mssql: () =>
|
|
2585
|
-
sqlite: () =>
|
|
2586
|
-
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))
|
|
2587
2600
|
});
|
|
2588
|
-
yield*
|
|
2589
|
-
}),
|
|
2601
|
+
yield* C.forEach(i, (t) => X(e, t, "resume-ledger-bootstrap"), { discard: !0 });
|
|
2602
|
+
}), Fi = (e) => e`
|
|
2590
2603
|
SELECT ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2591
2604
|
${e("status")}, ${e("payload")}
|
|
2592
|
-
FROM ${e(
|
|
2593
|
-
`,
|
|
2594
|
-
let i = yield*
|
|
2595
|
-
yield*
|
|
2596
|
-
INSERT INTO ${e(
|
|
2605
|
+
FROM ${e(O)}
|
|
2606
|
+
`, Ii = (e, t, n, r) => C.gen(function* () {
|
|
2607
|
+
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2608
|
+
yield* C.forEach(r, ({ index: r, planned: a }) => e`
|
|
2609
|
+
INSERT INTO ${e(O)}
|
|
2597
2610
|
(${e("id")}, ${e("runId")}, ${e("planFingerprint")}, ${e("opIndex")},
|
|
2598
2611
|
${e("opKind")}, ${e("opTarget")}, ${e("status")}, ${e("payload")},
|
|
2599
2612
|
${e("createdAt")})
|
|
2600
2613
|
VALUES
|
|
2601
2614
|
(${`mop_${t}_${r}`}, ${t}, ${n}, ${r},
|
|
2602
|
-
${a.op.kind}, ${
|
|
2615
|
+
${a.op.kind}, ${Ve(a.op)}, ${"pending"},
|
|
2603
2616
|
${JSON.stringify(a)}, ${i})
|
|
2604
2617
|
`, { discard: !0 });
|
|
2605
|
-
}),
|
|
2606
|
-
let a = yield*
|
|
2618
|
+
}), Li = (e, t, n, r, i) => C.gen(function* () {
|
|
2619
|
+
let a = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2607
2620
|
if (r === "applied") {
|
|
2608
2621
|
yield* e`
|
|
2609
|
-
UPDATE ${e(
|
|
2622
|
+
UPDATE ${e(O)}
|
|
2610
2623
|
SET ${e("status")} = ${r}, ${e("appliedAt")} = ${a},
|
|
2611
2624
|
${e("durationMs")} = ${i ?? null}
|
|
2612
2625
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
@@ -2614,145 +2627,145 @@ BEGIN
|
|
|
2614
2627
|
return;
|
|
2615
2628
|
}
|
|
2616
2629
|
yield* e`
|
|
2617
|
-
UPDATE ${e(
|
|
2630
|
+
UPDATE ${e(O)}
|
|
2618
2631
|
SET ${e("status")} = ${r}, ${e("startedAt")} = ${a}
|
|
2619
2632
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} = ${n}
|
|
2620
2633
|
`;
|
|
2621
|
-
}),
|
|
2622
|
-
let i = yield*
|
|
2634
|
+
}), Ri = (e, t, n, r) => C.gen(function* () {
|
|
2635
|
+
let i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2623
2636
|
r.length > 0 && (yield* e`
|
|
2624
|
-
UPDATE ${e(
|
|
2637
|
+
UPDATE ${e(O)}
|
|
2625
2638
|
SET ${e("status")} = ${"applied"}, ${e("appliedAt")} = ${i}
|
|
2626
2639
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(r)}
|
|
2627
2640
|
`), n.length > 0 && (yield* e`
|
|
2628
|
-
UPDATE ${e(
|
|
2641
|
+
UPDATE ${e(O)}
|
|
2629
2642
|
SET ${e("status")} = ${"pending"}
|
|
2630
2643
|
WHERE ${e("runId")} = ${t} AND ${e("opIndex")} IN ${e.in(n)}
|
|
2631
2644
|
`);
|
|
2632
|
-
}),
|
|
2633
|
-
if (
|
|
2634
|
-
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);
|
|
2635
2648
|
if (t === "sqlite" || t === "turso") {
|
|
2636
2649
|
if (!("table" in r)) return "clean";
|
|
2637
|
-
let n = `${r.table}${
|
|
2638
|
-
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";
|
|
2639
2652
|
}
|
|
2640
2653
|
if (r.kind !== "alter-column-type") return "clean";
|
|
2641
|
-
let a = `${r.column}${
|
|
2642
|
-
return !
|
|
2643
|
-
}),
|
|
2644
|
-
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;
|
|
2645
2658
|
switch (o.kind) {
|
|
2646
2659
|
case "create-table": {
|
|
2647
2660
|
let t = yield* e.onDialectOrElse({
|
|
2648
|
-
mysql: () =>
|
|
2649
|
-
mssql: () =>
|
|
2650
|
-
sqlite: () =>
|
|
2651
|
-
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))
|
|
2652
2665
|
}), n = yield* e.onDialectOrElse({
|
|
2653
|
-
mysql: () =>
|
|
2654
|
-
orElse: () =>
|
|
2666
|
+
mysql: () => C.succeed([dr]),
|
|
2667
|
+
orElse: () => C.succeed([])
|
|
2655
2668
|
});
|
|
2656
2669
|
for (let r of t) yield* X(e, r, o.kind, n);
|
|
2657
2670
|
break;
|
|
2658
2671
|
}
|
|
2659
2672
|
case "drop-table": {
|
|
2660
|
-
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);
|
|
2661
2674
|
yield* e.onDialectOrElse({
|
|
2662
|
-
mysql: () => X(e, r(
|
|
2663
|
-
orElse: () => X(e, r(
|
|
2675
|
+
mysql: () => X(e, r(G), o.kind),
|
|
2676
|
+
orElse: () => X(e, r(W), o.kind)
|
|
2664
2677
|
});
|
|
2665
2678
|
break;
|
|
2666
2679
|
}
|
|
2667
2680
|
case "drop-column": {
|
|
2668
2681
|
let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
|
|
2669
2682
|
yield* e.onDialectOrElse({
|
|
2670
|
-
mysql: () =>
|
|
2671
|
-
sqlite: () => X(e, t ?
|
|
2672
|
-
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)
|
|
2673
2686
|
});
|
|
2674
2687
|
break;
|
|
2675
2688
|
}
|
|
2676
2689
|
case "rename-column":
|
|
2677
2690
|
yield* e.onDialectOrElse({
|
|
2678
|
-
mysql: () => X(e,
|
|
2691
|
+
mysql: () => X(e, wr(o, G), o.kind),
|
|
2679
2692
|
mssql: () => X(e, `EXEC sp_rename N'${o.table.replace(/'/g, "''")}.${o.from.replace(/'/g, "''")}', N'${o.to.replace(/'/g, "''")}', 'COLUMN';`, o.kind),
|
|
2680
|
-
orElse: () => X(e,
|
|
2693
|
+
orElse: () => X(e, wr(o, W), o.kind)
|
|
2681
2694
|
});
|
|
2682
2695
|
break;
|
|
2683
2696
|
case "add-index":
|
|
2684
2697
|
yield* e.onDialectOrElse({
|
|
2685
|
-
mysql: () =>
|
|
2686
|
-
mssql: () => Z(e, [...
|
|
2687
|
-
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)
|
|
2688
2701
|
});
|
|
2689
2702
|
break;
|
|
2690
2703
|
case "drop-index":
|
|
2691
2704
|
yield* e.onDialectOrElse({
|
|
2692
|
-
mysql: () => X(e,
|
|
2693
|
-
mssql: () => X(e,
|
|
2694
|
-
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)
|
|
2695
2708
|
});
|
|
2696
2709
|
break;
|
|
2697
2710
|
case "rename-table":
|
|
2698
2711
|
yield* e.onDialectOrElse({
|
|
2699
|
-
mysql: () => X(e,
|
|
2700
|
-
mssql: () => X(e,
|
|
2701
|
-
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)
|
|
2702
2715
|
});
|
|
2703
2716
|
break;
|
|
2704
2717
|
case "rename-index":
|
|
2705
2718
|
yield* e.onDialectOrElse({
|
|
2706
|
-
mysql: () => X(e,
|
|
2707
|
-
mssql: () => X(e,
|
|
2708
|
-
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)
|
|
2709
2722
|
});
|
|
2710
2723
|
break;
|
|
2711
2724
|
case "add-unique":
|
|
2712
2725
|
yield* e.onDialectOrElse({
|
|
2713
|
-
mysql: () => X(e,
|
|
2726
|
+
mysql: () => X(e, vi(o, n.declared), o.kind),
|
|
2714
2727
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2715
|
-
mssql: () => Z(e, [...
|
|
2716
|
-
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)
|
|
2717
2730
|
});
|
|
2718
2731
|
break;
|
|
2719
2732
|
case "drop-unique":
|
|
2720
2733
|
yield* e.onDialectOrElse({
|
|
2721
|
-
mysql: () => X(e,
|
|
2734
|
+
mysql: () => X(e, wi(o), o.kind),
|
|
2722
2735
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2723
|
-
orElse: () => X(e,
|
|
2736
|
+
orElse: () => X(e, Ci(o), o.kind)
|
|
2724
2737
|
});
|
|
2725
2738
|
break;
|
|
2726
2739
|
case "add-unique-composite":
|
|
2727
2740
|
yield* e.onDialectOrElse({
|
|
2728
|
-
mysql: () => X(e,
|
|
2741
|
+
mysql: () => X(e, bi(o, n.declared), o.kind),
|
|
2729
2742
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2730
|
-
mssql: () => Z(e, [...
|
|
2731
|
-
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)
|
|
2732
2745
|
});
|
|
2733
2746
|
break;
|
|
2734
2747
|
case "drop-unique-composite":
|
|
2735
2748
|
yield* e.onDialectOrElse({
|
|
2736
|
-
mysql: () => X(e,
|
|
2749
|
+
mysql: () => X(e, Si(o), o.kind),
|
|
2737
2750
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2738
|
-
orElse: () => X(e,
|
|
2751
|
+
orElse: () => X(e, xi(o), o.kind)
|
|
2739
2752
|
});
|
|
2740
2753
|
break;
|
|
2741
2754
|
case "add-foreign-key":
|
|
2742
2755
|
yield* e.onDialectOrElse({
|
|
2743
|
-
mysql: () => Z(e,
|
|
2756
|
+
mysql: () => Z(e, Ti(o, G), o.kind),
|
|
2744
2757
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2745
|
-
orElse: () => Z(e,
|
|
2758
|
+
orElse: () => Z(e, Ti(o, W), o.kind)
|
|
2746
2759
|
});
|
|
2747
2760
|
break;
|
|
2748
2761
|
case "add-column": {
|
|
2749
|
-
let n =
|
|
2750
|
-
mysql: () =>
|
|
2751
|
-
mssql: () =>
|
|
2752
|
-
sqlite: () =>
|
|
2753
|
-
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")
|
|
2754
2767
|
}));
|
|
2755
|
-
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);
|
|
2756
2769
|
if (n.backfillKind === "sql" && n.backfillSql) {
|
|
2757
2770
|
if (t.classification !== "online-required" && n.batchSize === void 0) yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${n.backfillSql}`;
|
|
2758
2771
|
else {
|
|
@@ -2761,10 +2774,10 @@ BEGIN
|
|
|
2761
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)}`;
|
|
2762
2775
|
if (s.length === 0) break;
|
|
2763
2776
|
let c = s.map((e) => e.id);
|
|
2764
|
-
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({
|
|
2765
2778
|
scope: "voltro:migrate",
|
|
2766
2779
|
mode: "sql-batched"
|
|
2767
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2780
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* C.sleep(`${r} millis`));
|
|
2768
2781
|
}
|
|
2769
2782
|
}
|
|
2770
2783
|
} else if (n.backfillKind === "js" && n.backfillJs) {
|
|
@@ -2773,17 +2786,17 @@ BEGIN
|
|
|
2773
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)}`;
|
|
2774
2787
|
if (s.length === 0) break;
|
|
2775
2788
|
for (let t of s) {
|
|
2776
|
-
let r = yield*
|
|
2789
|
+
let r = yield* C.tryPromise({
|
|
2777
2790
|
try: () => Promise.resolve(n.backfillJs({ id: t.id })),
|
|
2778
2791
|
catch: (e) => e
|
|
2779
|
-
}).pipe(
|
|
2792
|
+
}).pipe(C.orDie);
|
|
2780
2793
|
yield* e`UPDATE ${e(o.table)} SET ${e(o.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
|
|
2781
2794
|
}
|
|
2782
|
-
a += s.length, yield*
|
|
2795
|
+
a += s.length, yield* C.logInfo(`backfill ${o.table}.${o.column.name}: ${a} rows processed`).pipe(C.annotateLogs({
|
|
2783
2796
|
scope: "voltro:migrate",
|
|
2784
2797
|
table: o.table,
|
|
2785
2798
|
column: o.column.name
|
|
2786
|
-
})), i = s[s.length - 1].id, r > 0 && (yield*
|
|
2799
|
+
})), i = s[s.length - 1].id, r > 0 && (yield* C.sleep(`${r} millis`));
|
|
2787
2800
|
}
|
|
2788
2801
|
}
|
|
2789
2802
|
for (let t of n.post) yield* X(e, t, o.kind);
|
|
@@ -2792,83 +2805,83 @@ BEGIN
|
|
|
2792
2805
|
case "alter-column-nullability":
|
|
2793
2806
|
yield* e.onDialectOrElse({
|
|
2794
2807
|
mysql: () => {
|
|
2795
|
-
let t =
|
|
2796
|
-
return t ? X(e, `ALTER TABLE ${
|
|
2808
|
+
let t = K(n.declared, o.table, o.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.`));
|
|
2797
2810
|
},
|
|
2798
2811
|
mssql: () => {
|
|
2799
|
-
let t =
|
|
2800
|
-
return t ? X(e,
|
|
2812
|
+
let t = K(n.declared, o.table, o.column);
|
|
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}'.`));
|
|
2801
2814
|
},
|
|
2802
2815
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2803
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
2816
|
+
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} ${o.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, o.kind)
|
|
2804
2817
|
});
|
|
2805
2818
|
break;
|
|
2806
2819
|
case "alter-column-default": {
|
|
2807
|
-
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;
|
|
2808
2821
|
yield* e.onDialectOrElse({
|
|
2809
2822
|
mysql: () => {
|
|
2810
2823
|
let n = i("mariadb");
|
|
2811
|
-
return X(e, n ? `ALTER TABLE ${
|
|
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);
|
|
2812
2825
|
},
|
|
2813
2826
|
mssql: () => {
|
|
2814
2827
|
let t = i("mssql");
|
|
2815
|
-
return X(e,
|
|
2828
|
+
return X(e, Yr(o, t ? Jr(t, o.column, o.table) : void 0), o.kind);
|
|
2816
2829
|
},
|
|
2817
2830
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2818
|
-
orElse: () => X(e,
|
|
2831
|
+
orElse: () => X(e, Er(o, W, (e) => Nr(e, t)), o.kind)
|
|
2819
2832
|
});
|
|
2820
2833
|
break;
|
|
2821
2834
|
}
|
|
2822
2835
|
case "alter-column-type": {
|
|
2823
|
-
let r =
|
|
2836
|
+
let r = vr(kr(n.declared, o.table, o.column) ?? { type: o.to }), i = o.using ? ` USING ${o.using}` : "";
|
|
2824
2837
|
if (t.classification !== "online-required") {
|
|
2825
2838
|
yield* e.onDialectOrElse({
|
|
2826
2839
|
mysql: () => {
|
|
2827
|
-
let t =
|
|
2828
|
-
return t ? X(e, `ALTER TABLE ${
|
|
2840
|
+
let t = K(n.declared, o.table, o.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.`));
|
|
2829
2842
|
},
|
|
2830
2843
|
mssql: () => {
|
|
2831
|
-
let t =
|
|
2832
|
-
return t ? X(e,
|
|
2844
|
+
let t = K(n.declared, o.table, o.column);
|
|
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}'.`));
|
|
2833
2846
|
},
|
|
2834
2847
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2835
|
-
orElse: () => X(e, `ALTER TABLE ${
|
|
2848
|
+
orElse: () => X(e, `ALTER TABLE ${W(o.table)} ALTER COLUMN ${W(o.column)} TYPE ${r}${i};`, o.kind)
|
|
2836
2849
|
});
|
|
2837
2850
|
break;
|
|
2838
2851
|
}
|
|
2839
2852
|
yield* e.onDialectOrElse({
|
|
2840
|
-
mysql: () =>
|
|
2841
|
-
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
|
|
2842
2855
|
});
|
|
2843
2856
|
let a = `${o.column}__shadow`, s = `${o.column}__old`;
|
|
2844
|
-
yield* e.unsafe(`ALTER TABLE ${
|
|
2845
|
-
let c = o.using ??
|
|
2857
|
+
yield* e.unsafe(`ALTER TABLE ${W(o.table)} ADD COLUMN ${W(a)} ${r}`);
|
|
2858
|
+
let c = o.using ?? W(o.column), l;
|
|
2846
2859
|
for (;;) {
|
|
2847
2860
|
let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(a)} IS NULL ORDER BY ${e("id")} ${Q(e, 5e3)}` : yield* e`SELECT ${e("id")} FROM ${e(o.table)} WHERE ${e(a)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} ${Q(e, 5e3)}`;
|
|
2848
2861
|
if (t.length === 0) break;
|
|
2849
|
-
yield* e.unsafe(`UPDATE ${
|
|
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;
|
|
2850
2863
|
}
|
|
2851
|
-
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)}`);
|
|
2852
2865
|
break;
|
|
2853
2866
|
}
|
|
2854
2867
|
case "drop-foreign-key":
|
|
2855
2868
|
yield* e.onDialectOrElse({
|
|
2856
|
-
mysql: () => X(e,
|
|
2869
|
+
mysql: () => X(e, Di(o), o.kind),
|
|
2857
2870
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2858
|
-
orElse: () => X(e,
|
|
2871
|
+
orElse: () => X(e, Ei(o), o.kind)
|
|
2859
2872
|
});
|
|
2860
2873
|
break;
|
|
2861
2874
|
case "add-check":
|
|
2862
2875
|
yield* e.onDialectOrElse({
|
|
2863
|
-
mysql: () => X(e,
|
|
2876
|
+
mysql: () => X(e, Oi(o, G), o.kind),
|
|
2864
2877
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2865
|
-
orElse: () => X(e,
|
|
2878
|
+
orElse: () => X(e, Oi(o, W), o.kind)
|
|
2866
2879
|
});
|
|
2867
2880
|
break;
|
|
2868
2881
|
case "drop-check": yield* e.onDialectOrElse({
|
|
2869
|
-
mysql: () =>
|
|
2882
|
+
mysql: () => ji(e, o, n.declared),
|
|
2870
2883
|
sqlite: () => Z(e, J(o.table, n.declared), o.kind),
|
|
2871
|
-
orElse: () => X(e,
|
|
2884
|
+
orElse: () => X(e, ki(o), o.kind)
|
|
2872
2885
|
});
|
|
2873
2886
|
}
|
|
2874
2887
|
return {
|
|
@@ -2876,32 +2889,32 @@ BEGIN
|
|
|
2876
2889
|
status: "applied",
|
|
2877
2890
|
durationMs: Number((process.hrtime.bigint() - i) / 1000000n)
|
|
2878
2891
|
};
|
|
2879
|
-
}),
|
|
2892
|
+
}), Hi = (e, t, n, r) => C.gen(function* () {
|
|
2880
2893
|
let i = [...new Set(r.map((e) => e.runId))];
|
|
2881
|
-
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.`));
|
|
2882
2895
|
let a = i[0], o = [...r].map((e) => ({
|
|
2883
2896
|
index: Number(e.opIndex),
|
|
2884
2897
|
status: e.status,
|
|
2885
2898
|
planned: JSON.parse(e.payload)
|
|
2886
2899
|
})).sort((e, t) => e.index - t.index), s = o.find((e) => e.status === "started"), c = o.filter((e) => e.status === "started").length;
|
|
2887
|
-
if (c > 1) return yield*
|
|
2888
|
-
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 {
|
|
2889
2902
|
kind: "discard",
|
|
2890
2903
|
runId: a,
|
|
2891
2904
|
why: "no operation had started — no DDL ran"
|
|
2892
2905
|
};
|
|
2893
|
-
let l = s ? yield*
|
|
2906
|
+
let l = s ? yield* Bi(e, t, s.planned) : "clean", u = r[0].planFingerprint;
|
|
2894
2907
|
if (u !== n.toFingerprint) return {
|
|
2895
2908
|
kind: "discard",
|
|
2896
2909
|
runId: a,
|
|
2897
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`
|
|
2898
2911
|
};
|
|
2899
|
-
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));
|
|
2900
2913
|
return f.length === 0 ? {
|
|
2901
2914
|
kind: "discard",
|
|
2902
2915
|
runId: a,
|
|
2903
2916
|
why: "every recorded operation had already taken effect"
|
|
2904
|
-
} : (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" })), {
|
|
2905
2918
|
kind: "resume",
|
|
2906
2919
|
runId: a,
|
|
2907
2920
|
ops: f.map((e) => ({
|
|
@@ -2909,7 +2922,7 @@ BEGIN
|
|
|
2909
2922
|
planned: e.planned
|
|
2910
2923
|
}))
|
|
2911
2924
|
});
|
|
2912
|
-
}),
|
|
2925
|
+
}), Ui = (e) => {
|
|
2913
2926
|
let t = e.op, n = (e) => typeof t[e] == "string" ? t[e] : "";
|
|
2914
2927
|
return [
|
|
2915
2928
|
t.kind,
|
|
@@ -2918,66 +2931,66 @@ BEGIN
|
|
|
2918
2931
|
n("name"),
|
|
2919
2932
|
n("to")
|
|
2920
2933
|
].join("\0");
|
|
2921
|
-
},
|
|
2934
|
+
}, Wi = (e, t, n) => C.gen(function* () {
|
|
2922
2935
|
let r = t.operations.filter((e) => e.blocked);
|
|
2923
|
-
if (r.length > 0) return yield*
|
|
2924
|
-
yield*
|
|
2925
|
-
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 = {
|
|
2926
2939
|
...s,
|
|
2927
2940
|
operations: s.operations.map((e) => {
|
|
2928
|
-
if (!e.blocked || !c.has(
|
|
2941
|
+
if (!e.blocked || !c.has(Ui(e))) return e;
|
|
2929
2942
|
let { blocked: t, ...n } = e;
|
|
2930
2943
|
return n;
|
|
2931
2944
|
})
|
|
2932
2945
|
};
|
|
2933
|
-
(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" })));
|
|
2934
2947
|
let u = l.operations.filter((e) => e.blocked);
|
|
2935
|
-
if (u.length > 0) return yield*
|
|
2936
|
-
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) => ({
|
|
2937
2950
|
index: t,
|
|
2938
2951
|
planned: e
|
|
2939
|
-
})),
|
|
2952
|
+
})), _ = "fresh";
|
|
2940
2953
|
try {
|
|
2941
|
-
yield*
|
|
2942
|
-
let t = yield*
|
|
2954
|
+
yield* Pi(e, o);
|
|
2955
|
+
let t = yield* Fi(e);
|
|
2943
2956
|
if (t.length > 0) {
|
|
2944
|
-
let n = yield*
|
|
2945
|
-
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));
|
|
2946
2959
|
}
|
|
2947
|
-
|
|
2948
|
-
let e = yield*
|
|
2949
|
-
for (let t of f) a.push(yield*
|
|
2960
|
+
_ === "fresh" && h.length > 0 && (yield* Ii(e, m, l.toFingerprint, h)), f.length > 0 && (yield* e.withTransaction(C.gen(function* () {
|
|
2961
|
+
let e = yield* T.SqlClient;
|
|
2962
|
+
for (let t of f) a.push(yield* Vi(e, t, n));
|
|
2950
2963
|
})));
|
|
2951
2964
|
for (let { index: t, planned: r } of h) {
|
|
2952
|
-
yield*
|
|
2953
|
-
let i = a.length, o = yield*
|
|
2954
|
-
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);
|
|
2955
2968
|
}
|
|
2956
2969
|
} finally {
|
|
2957
|
-
yield*
|
|
2970
|
+
yield* D(e, { schema: n.lockSchema }).pipe(C.orDie);
|
|
2958
2971
|
}
|
|
2959
|
-
let
|
|
2960
|
-
if (
|
|
2961
|
-
let e =
|
|
2962
|
-
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.`));
|
|
2963
2976
|
}
|
|
2964
|
-
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)];
|
|
2965
2978
|
yield* e`
|
|
2966
2979
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2967
2980
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
2968
2981
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
2969
2982
|
${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
|
|
2970
2983
|
VALUES
|
|
2971
|
-
(${x}, ${l.toFingerprint}, ${
|
|
2984
|
+
(${x}, ${l.toFingerprint}, ${v.fromFingerprint}, ${JSON.stringify(w)},
|
|
2972
2985
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
2973
|
-
${b}, ${
|
|
2974
|
-
`, yield*
|
|
2975
|
-
let
|
|
2976
|
-
return yield*
|
|
2986
|
+
${b}, ${ee}, ${n.notes ?? null})
|
|
2987
|
+
`, yield* zi(e, m);
|
|
2988
|
+
let te = [...new Set(w.flatMap((e) => e.op.kind === "rename-table" ? [e.op.to] : [e.op.table]))];
|
|
2989
|
+
return yield* C.promise(() => g({ changedTables: te }).catch(() => {})), {
|
|
2977
2990
|
id: x,
|
|
2978
|
-
appliedAt:
|
|
2991
|
+
appliedAt: S,
|
|
2979
2992
|
fingerprint: l.toFingerprint,
|
|
2980
|
-
operations:
|
|
2993
|
+
operations: w,
|
|
2981
2994
|
appliedBy: n.appliedBy,
|
|
2982
2995
|
environment: n.environment,
|
|
2983
2996
|
durationMs: b,
|
|
@@ -2985,14 +2998,14 @@ BEGIN
|
|
|
2985
2998
|
source: n.source,
|
|
2986
2999
|
...n.notes ? { notes: n.notes } : {}
|
|
2987
3000
|
};
|
|
2988
|
-
}),
|
|
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`
|
|
2989
3002
|
SELECT fingerprint
|
|
2990
3003
|
FROM _voltro_migration_plans
|
|
2991
3004
|
ORDER BY ${e("appliedAt")} DESC
|
|
2992
3005
|
LIMIT 1
|
|
2993
|
-
`.pipe(
|
|
2994
|
-
if ((yield*
|
|
2995
|
-
let r = `plan_${Date.now().toString(36)}`, i = 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
|
+
let r = `plan_${Date.now().toString(36)}`, i = yield* U(e, (/* @__PURE__ */ new Date()).toISOString());
|
|
2996
3009
|
return yield* e`
|
|
2997
3010
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
2998
3011
|
(${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
|
|
@@ -3003,8 +3016,8 @@ BEGIN
|
|
|
3003
3016
|
${n.appliedBy}, ${n.environment}, ${n.source},
|
|
3004
3017
|
${0}, ${i}, ${"no DDL — the declared schema already matched the database"})
|
|
3005
3018
|
`, "recorded";
|
|
3006
|
-
}).pipe(
|
|
3007
|
-
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);
|
|
3008
3021
|
return r === n ? {
|
|
3009
3022
|
kind: "up-to-date",
|
|
3010
3023
|
fingerprint: n
|
|
@@ -3013,23 +3026,23 @@ BEGIN
|
|
|
3013
3026
|
expected: n,
|
|
3014
3027
|
...r === void 0 ? {} : { actual: r }
|
|
3015
3028
|
};
|
|
3016
|
-
}),
|
|
3029
|
+
}), Yi = [
|
|
3017
3030
|
"pgeagertest_",
|
|
3018
3031
|
"mig_e2e_",
|
|
3019
3032
|
"mig_test_",
|
|
3020
3033
|
"mysqleagertest_",
|
|
3021
3034
|
"mssqleagertest_",
|
|
3022
3035
|
"sqliteeagertest_"
|
|
3023
|
-
],
|
|
3036
|
+
], Xi = (e) => Yi.some((t) => e.startsWith(t)), Zi = (e, t) => C.gen(function* () {
|
|
3024
3037
|
if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
|
|
3025
|
-
let n = t.filter((e) =>
|
|
3038
|
+
let n = t.filter((e) => Xi(e.name)).map((e) => e.name);
|
|
3026
3039
|
if (n.length === 0) return [];
|
|
3027
|
-
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));
|
|
3028
3041
|
return n;
|
|
3029
|
-
}),
|
|
3042
|
+
}), Qi = () => {
|
|
3030
3043
|
let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
|
|
3031
3044
|
return e.length > 0 ? { ignoreTables: e } : {};
|
|
3032
|
-
},
|
|
3045
|
+
}, $i = (e) => {
|
|
3033
3046
|
if (e === void 0) return;
|
|
3034
3047
|
let t = e.trim();
|
|
3035
3048
|
if (t === "") return;
|
|
@@ -3039,87 +3052,94 @@ BEGIN
|
|
|
3039
3052
|
kind: "tables",
|
|
3040
3053
|
tables: new Set(n)
|
|
3041
3054
|
} : void 0;
|
|
3042
|
-
},
|
|
3055
|
+
}, ea = (e) => typeof e.table == "string" ? e.table : void 0, ta = (e, t = { kind: "all" }) => ({
|
|
3043
3056
|
...e,
|
|
3044
3057
|
operations: e.operations.map((e) => {
|
|
3045
3058
|
if (!e.blocked || e.classification !== "lossy") return e;
|
|
3046
3059
|
if (t?.kind === "tables") {
|
|
3047
|
-
let n =
|
|
3060
|
+
let n = ea(e.op);
|
|
3048
3061
|
if (n === void 0 || !t.tables.has(n)) return e;
|
|
3049
3062
|
}
|
|
3050
3063
|
let { blocked: n, ...r } = e;
|
|
3051
3064
|
return r;
|
|
3052
3065
|
})
|
|
3053
|
-
}),
|
|
3054
|
-
let t =
|
|
3055
|
-
return t === void 0 ?
|
|
3056
|
-
}),
|
|
3057
|
-
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;
|
|
3058
3071
|
if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
|
|
3059
|
-
let t =
|
|
3060
|
-
if ((yield*
|
|
3072
|
+
let t = Jt(F(a, r));
|
|
3073
|
+
if ((yield* Ki(e)) === t) return yield* na(e, r, a), {
|
|
3061
3074
|
kind: "up-to-date",
|
|
3062
3075
|
fingerprint: t
|
|
3063
3076
|
};
|
|
3064
3077
|
}
|
|
3065
|
-
let
|
|
3066
|
-
|
|
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({
|
|
3067
3080
|
scope: "voltro:migrate",
|
|
3068
|
-
count:
|
|
3069
|
-
})),
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
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) },
|
|
3073
3093
|
dialect: r,
|
|
3074
|
-
...
|
|
3094
|
+
...Qi()
|
|
3075
3095
|
});
|
|
3076
|
-
if (
|
|
3077
|
-
let e =
|
|
3078
|
-
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 {
|
|
3079
3099
|
kind: "refused-blocked",
|
|
3080
|
-
plan:
|
|
3100
|
+
plan: u
|
|
3081
3101
|
};
|
|
3082
3102
|
}
|
|
3083
|
-
return
|
|
3103
|
+
return u.operations.length === 0 ? (yield* qi(e, u, {
|
|
3084
3104
|
appliedBy: n.appliedBy,
|
|
3085
3105
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3086
3106
|
source: "auto-diff"
|
|
3087
3107
|
}), {
|
|
3088
3108
|
kind: "up-to-date",
|
|
3089
|
-
fingerprint:
|
|
3109
|
+
fingerprint: u.toFingerprint
|
|
3090
3110
|
}) : {
|
|
3091
3111
|
kind: "applied",
|
|
3092
|
-
applied: yield*
|
|
3112
|
+
applied: yield* Wi(e, u, {
|
|
3093
3113
|
declared: t,
|
|
3094
3114
|
appliedBy: n.appliedBy,
|
|
3095
3115
|
environment: n.environment === "prod" ? "dev" : n.environment,
|
|
3096
3116
|
source: "auto-diff",
|
|
3097
|
-
replan: (e) =>
|
|
3098
|
-
let t = yield*
|
|
3099
|
-
return
|
|
3100
|
-
declared:
|
|
3101
|
-
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) },
|
|
3102
3122
|
dialect: r,
|
|
3103
|
-
...
|
|
3123
|
+
...Qi()
|
|
3104
3124
|
});
|
|
3105
3125
|
})
|
|
3106
3126
|
}),
|
|
3107
|
-
plan:
|
|
3127
|
+
plan: u
|
|
3108
3128
|
};
|
|
3109
|
-
}),
|
|
3129
|
+
}), ia = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? C.succeed({
|
|
3110
3130
|
kind: "skipped",
|
|
3111
3131
|
reason: "VOLTRO_AUTO_MIGRATE=0"
|
|
3112
|
-
}) : n.environment === "prod" ?
|
|
3132
|
+
}) : n.environment === "prod" ? Ji(e, t) : ra(e, t, n), aa = (e, t) => {
|
|
3113
3133
|
switch (e.kind) {
|
|
3114
3134
|
case "skipped": return `auto-migrate: skipped (${e.reason})`;
|
|
3115
|
-
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)})`;
|
|
3116
3136
|
case "applied": {
|
|
3117
3137
|
let t = e.plan.summary;
|
|
3118
|
-
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)}`;
|
|
3119
3139
|
}
|
|
3120
|
-
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.";
|
|
3121
3141
|
case "refused-blocked": {
|
|
3122
|
-
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 = [""];
|
|
3123
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) {
|
|
3124
3144
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
3125
3145
|
for (let r of e.plan.operations) {
|
|
@@ -3136,7 +3156,7 @@ BEGIN
|
|
|
3136
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");
|
|
3137
3157
|
}
|
|
3138
3158
|
}
|
|
3139
|
-
},
|
|
3159
|
+
}, oa = ne({ scope: "voltro:migrate" }), sa = /* @__PURE__ */ new Set([
|
|
3140
3160
|
"node_modules",
|
|
3141
3161
|
"dist",
|
|
3142
3162
|
"build",
|
|
@@ -3145,25 +3165,25 @@ BEGIN
|
|
|
3145
3165
|
".next",
|
|
3146
3166
|
".git",
|
|
3147
3167
|
".framework"
|
|
3148
|
-
]),
|
|
3168
|
+
]), ca = async (e) => {
|
|
3149
3169
|
let t = [], n = async (e) => {
|
|
3150
|
-
let r = await
|
|
3170
|
+
let r = await re.readdir(e, { withFileTypes: !0 }).catch(() => []);
|
|
3151
3171
|
for (let i of r) {
|
|
3152
|
-
if (
|
|
3153
|
-
let r =
|
|
3154
|
-
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);
|
|
3155
3175
|
}
|
|
3156
3176
|
};
|
|
3157
3177
|
return await n(e), t.sort((e, t) => {
|
|
3158
3178
|
let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
|
|
3159
3179
|
return n.localeCompare(r);
|
|
3160
3180
|
});
|
|
3161
|
-
},
|
|
3181
|
+
}, la = async (e) => {
|
|
3162
3182
|
let t = [];
|
|
3163
3183
|
for (let n of e) {
|
|
3164
|
-
let e = (await import(
|
|
3165
|
-
if (!
|
|
3166
|
-
|
|
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 });
|
|
3167
3187
|
continue;
|
|
3168
3188
|
}
|
|
3169
3189
|
t.push({
|
|
@@ -3172,11 +3192,11 @@ BEGIN
|
|
|
3172
3192
|
});
|
|
3173
3193
|
}
|
|
3174
3194
|
return t;
|
|
3175
|
-
},
|
|
3195
|
+
}, ua = (e) => e`
|
|
3176
3196
|
SELECT ${e("id")}
|
|
3177
3197
|
FROM ${e("_voltro_migration_plans")}
|
|
3178
3198
|
WHERE ${e("source")} = 'file'
|
|
3179
|
-
`.pipe(
|
|
3199
|
+
`.pipe(C.map((e) => e.map((e) => e.id)), C.catchAll(() => C.succeed([]))), da = class extends Error {
|
|
3180
3200
|
migrationId;
|
|
3181
3201
|
file;
|
|
3182
3202
|
cause;
|
|
@@ -3184,28 +3204,28 @@ BEGIN
|
|
|
3184
3204
|
constructor(e, t, n) {
|
|
3185
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";
|
|
3186
3206
|
}
|
|
3187
|
-
},
|
|
3207
|
+
}, fa = (e, t, n, r) => C.gen(function* () {
|
|
3188
3208
|
let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
|
|
3189
3209
|
sql: e,
|
|
3190
3210
|
log: {
|
|
3191
|
-
info: (e, n) =>
|
|
3211
|
+
info: (e, n) => C.logInfo(e).pipe(C.annotateLogs({
|
|
3192
3212
|
scope: `migrations:file:${t.migration.id}`,
|
|
3193
3213
|
...n ?? {}
|
|
3194
3214
|
})),
|
|
3195
|
-
warn: (e, n) =>
|
|
3215
|
+
warn: (e, n) => C.logWarning(e).pipe(C.annotateLogs({
|
|
3196
3216
|
scope: `migrations:file:${t.migration.id}`,
|
|
3197
3217
|
...n ?? {}
|
|
3198
3218
|
}))
|
|
3199
3219
|
},
|
|
3200
3220
|
appliedAt: a
|
|
3201
3221
|
}, s = t.migration.up(o);
|
|
3202
|
-
|
|
3222
|
+
C.isEffect(s) ? yield* s : yield* C.tryPromise({
|
|
3203
3223
|
try: () => s,
|
|
3204
3224
|
catch: (e) => e
|
|
3205
3225
|
});
|
|
3206
3226
|
let c = Date.now() - i;
|
|
3207
|
-
!
|
|
3208
|
-
let l = yield*
|
|
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}` })));
|
|
3228
|
+
let l = yield* U(e, a);
|
|
3209
3229
|
return yield* e`
|
|
3210
3230
|
INSERT INTO ${e("_voltro_migration_plans")}
|
|
3211
3231
|
(${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
@@ -3218,94 +3238,94 @@ BEGIN
|
|
|
3218
3238
|
}])},
|
|
3219
3239
|
${r}, ${n}, ${"file"},
|
|
3220
3240
|
${c}, ${l}, ${t.migration.description})
|
|
3221
|
-
`.pipe(
|
|
3222
|
-
}),
|
|
3223
|
-
let n = yield*
|
|
3224
|
-
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")),
|
|
3225
3245
|
catch: (e) => e
|
|
3226
3246
|
});
|
|
3227
3247
|
if (n.length === 0) return {
|
|
3228
3248
|
pending: [],
|
|
3229
3249
|
skipped: []
|
|
3230
3250
|
};
|
|
3231
|
-
let r = yield*
|
|
3232
|
-
try: () =>
|
|
3251
|
+
let r = yield* C.tryPromise({
|
|
3252
|
+
try: () => la(n),
|
|
3233
3253
|
catch: (e) => e
|
|
3234
3254
|
});
|
|
3235
3255
|
if (r.length === 0) return {
|
|
3236
3256
|
pending: [],
|
|
3237
3257
|
skipped: []
|
|
3238
3258
|
};
|
|
3239
|
-
let i = new Set(yield*
|
|
3259
|
+
let i = new Set(yield* ua(e));
|
|
3240
3260
|
return {
|
|
3241
3261
|
pending: r.filter((e) => !i.has(e.migration.id)),
|
|
3242
3262
|
skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
|
|
3243
3263
|
};
|
|
3244
|
-
}),
|
|
3245
|
-
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);
|
|
3246
3266
|
if (n.length === 0) return {
|
|
3247
3267
|
applied: [],
|
|
3248
3268
|
skipped: r
|
|
3249
3269
|
};
|
|
3250
|
-
yield*
|
|
3270
|
+
yield* Pe(e, { schema: t.lockSchema });
|
|
3251
3271
|
let i = [];
|
|
3252
3272
|
try {
|
|
3253
3273
|
for (let r of n) {
|
|
3254
|
-
yield*
|
|
3274
|
+
yield* C.logInfo("file-based migration applying").pipe(C.annotateLogs({
|
|
3255
3275
|
scope: "voltro:migrate",
|
|
3256
3276
|
id: r.migration.id,
|
|
3257
3277
|
file: r.file
|
|
3258
3278
|
}));
|
|
3259
|
-
let { durationMs: n } = yield*
|
|
3279
|
+
let { durationMs: n } = yield* fa(e, r, t.env, t.appliedBy);
|
|
3260
3280
|
i.push({
|
|
3261
3281
|
id: r.migration.id,
|
|
3262
3282
|
durationMs: n
|
|
3263
|
-
}), yield*
|
|
3283
|
+
}), yield* C.logInfo("file-based migration applied").pipe(C.annotateLogs({
|
|
3264
3284
|
scope: "voltro:migrate",
|
|
3265
3285
|
id: r.migration.id,
|
|
3266
3286
|
durationMs: n
|
|
3267
3287
|
}));
|
|
3268
3288
|
}
|
|
3269
3289
|
} finally {
|
|
3270
|
-
yield*
|
|
3290
|
+
yield* D(e, { schema: t.lockSchema }).pipe(C.orDie);
|
|
3271
3291
|
}
|
|
3272
3292
|
return {
|
|
3273
3293
|
applied: i,
|
|
3274
3294
|
skipped: r
|
|
3275
3295
|
};
|
|
3276
|
-
}),
|
|
3296
|
+
}), ga = (e, t) => e`
|
|
3277
3297
|
SELECT ${e("id")}
|
|
3278
3298
|
FROM ${e("_voltro_migration_plans")}
|
|
3279
3299
|
WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
|
|
3280
3300
|
LIMIT 1
|
|
3281
|
-
`,
|
|
3282
|
-
if (!(yield*
|
|
3283
|
-
let n = yield*
|
|
3284
|
-
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")),
|
|
3285
3305
|
catch: (e) => e
|
|
3286
|
-
}), r = (yield*
|
|
3287
|
-
try: () =>
|
|
3306
|
+
}), r = (yield* C.tryPromise({
|
|
3307
|
+
try: () => la(n),
|
|
3288
3308
|
catch: (e) => e
|
|
3289
3309
|
})).find((e) => e.migration.id === t.id);
|
|
3290
|
-
if (!r) return yield*
|
|
3291
|
-
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 });
|
|
3292
3312
|
let i = Date.now();
|
|
3293
3313
|
try {
|
|
3294
3314
|
let n = {
|
|
3295
3315
|
sql: e,
|
|
3296
3316
|
log: {
|
|
3297
|
-
info: (e, n) =>
|
|
3317
|
+
info: (e, n) => C.logInfo(e).pipe(C.annotateLogs({
|
|
3298
3318
|
scope: `migrations:file:${t.id}`,
|
|
3299
3319
|
...n ?? {}
|
|
3300
3320
|
})),
|
|
3301
|
-
warn: (e, n) =>
|
|
3321
|
+
warn: (e, n) => C.logWarning(e).pipe(C.annotateLogs({
|
|
3302
3322
|
scope: `migrations:file:${t.id}`,
|
|
3303
3323
|
...n ?? {}
|
|
3304
3324
|
}))
|
|
3305
3325
|
},
|
|
3306
3326
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3307
3327
|
}, a = r.migration.down(n);
|
|
3308
|
-
|
|
3328
|
+
C.isEffect(a) ? yield* a : yield* C.tryPromise({
|
|
3309
3329
|
try: () => a,
|
|
3310
3330
|
catch: (e) => e
|
|
3311
3331
|
});
|
|
@@ -3315,19 +3335,19 @@ BEGIN
|
|
|
3315
3335
|
durationMs: o
|
|
3316
3336
|
};
|
|
3317
3337
|
} finally {
|
|
3318
|
-
yield*
|
|
3338
|
+
yield* D(e, { schema: t.lockSchema }).pipe(C.orDie);
|
|
3319
3339
|
}
|
|
3320
|
-
}),
|
|
3321
|
-
let t = yield*
|
|
3340
|
+
}), va = (e) => C.gen(function* () {
|
|
3341
|
+
let t = yield* T.SqlClient, n = yield* t`
|
|
3322
3342
|
SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
|
|
3323
3343
|
WHERE source = 'auto-diff'
|
|
3324
3344
|
AND squashedAt IS NULL
|
|
3325
3345
|
AND appliedAt < ${e.before}
|
|
3326
3346
|
ORDER BY appliedAt DESC
|
|
3327
3347
|
`;
|
|
3328
|
-
if (n.length === 0) return yield*
|
|
3348
|
+
if (n.length === 0) return yield* C.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
|
|
3329
3349
|
let r = n[0];
|
|
3330
|
-
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.`));
|
|
3331
3351
|
yield* t`
|
|
3332
3352
|
UPDATE _voltro_migration_plans
|
|
3333
3353
|
SET squashedAt = CURRENT_TIMESTAMP
|
|
@@ -3362,7 +3382,7 @@ BEGIN
|
|
|
3362
3382
|
snapshotFingerprint: e.fingerprint,
|
|
3363
3383
|
snapshotId: i
|
|
3364
3384
|
};
|
|
3365
|
-
}),
|
|
3385
|
+
}), ya = { safe: !0 }, ba = (e) => {
|
|
3366
3386
|
switch (e.kind) {
|
|
3367
3387
|
case "drop-column": return {
|
|
3368
3388
|
safe: !1,
|
|
@@ -3389,7 +3409,7 @@ BEGIN
|
|
|
3389
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`,
|
|
3390
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"
|
|
3391
3411
|
};
|
|
3392
|
-
case "alter-column-nullability": return e.toNullable ?
|
|
3412
|
+
case "alter-column-nullability": return e.toNullable ? ya : {
|
|
3393
3413
|
safe: !1,
|
|
3394
3414
|
reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
|
|
3395
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)`
|
|
@@ -3419,12 +3439,12 @@ BEGIN
|
|
|
3419
3439
|
case "drop-unique":
|
|
3420
3440
|
case "drop-unique-composite":
|
|
3421
3441
|
case "drop-foreign-key":
|
|
3422
|
-
case "drop-check": return
|
|
3442
|
+
case "drop-check": return ya;
|
|
3423
3443
|
}
|
|
3424
|
-
},
|
|
3444
|
+
}, xa = (e) => {
|
|
3425
3445
|
let t = [];
|
|
3426
3446
|
for (let n of e) {
|
|
3427
|
-
let e =
|
|
3447
|
+
let e = ba(n.op);
|
|
3428
3448
|
e.safe || t.push({
|
|
3429
3449
|
op: n,
|
|
3430
3450
|
reason: e.reason,
|
|
@@ -3432,7 +3452,7 @@ BEGIN
|
|
|
3432
3452
|
});
|
|
3433
3453
|
}
|
|
3434
3454
|
return t;
|
|
3435
|
-
},
|
|
3455
|
+
}, Sa = (e) => {
|
|
3436
3456
|
if (!e.enabled || e.unsafeCount === 0) return {
|
|
3437
3457
|
refuse: !1,
|
|
3438
3458
|
warnForced: !1,
|
|
@@ -3448,18 +3468,18 @@ BEGIN
|
|
|
3448
3468
|
warnForced: !1,
|
|
3449
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.`
|
|
3450
3470
|
};
|
|
3451
|
-
},
|
|
3471
|
+
}, Ca = (e) => {
|
|
3452
3472
|
let t = e.table;
|
|
3453
3473
|
if (typeof t == "string") return t;
|
|
3454
3474
|
let n = e.from;
|
|
3455
3475
|
return typeof n == "string" ? n : void 0;
|
|
3456
|
-
},
|
|
3476
|
+
}, wa = (e) => ({
|
|
3457
3477
|
kind: e.op.kind,
|
|
3458
|
-
table:
|
|
3478
|
+
table: Ca(e.op),
|
|
3459
3479
|
classification: e.classification,
|
|
3460
3480
|
reason: e.reason,
|
|
3461
3481
|
blockedFix: e.blocked?.fix
|
|
3462
|
-
}),
|
|
3482
|
+
}), Ta = (e) => e.operations.map(wa), Ea = async (e) => {
|
|
3463
3483
|
let t = e.log ?? (() => {}), n = {
|
|
3464
3484
|
branchId: e.branchId,
|
|
3465
3485
|
mechanism: e.mechanism,
|
|
@@ -3478,10 +3498,10 @@ BEGIN
|
|
|
3478
3498
|
applied: !1,
|
|
3479
3499
|
converged: !1,
|
|
3480
3500
|
residual: r,
|
|
3481
|
-
infidelity:
|
|
3501
|
+
infidelity: Ta(o)
|
|
3482
3502
|
};
|
|
3483
3503
|
else {
|
|
3484
|
-
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);
|
|
3485
3505
|
if (l.length > 0) a = {
|
|
3486
3506
|
...n,
|
|
3487
3507
|
outcome: "blocked",
|
|
@@ -3506,7 +3526,7 @@ BEGIN
|
|
|
3506
3526
|
};
|
|
3507
3527
|
else {
|
|
3508
3528
|
await e.apply(c), t(`branch ${e.branchId}: applied ${o.length} operation(s)`);
|
|
3509
|
-
let i =
|
|
3529
|
+
let i = Ta(await e.replan());
|
|
3510
3530
|
a = {
|
|
3511
3531
|
...n,
|
|
3512
3532
|
outcome: i.length > 0 ? "diverged" : s.length > 0 ? "lossy" : "clean",
|
|
@@ -3544,7 +3564,7 @@ BEGIN
|
|
|
3544
3564
|
...a,
|
|
3545
3565
|
tornDown: o
|
|
3546
3566
|
};
|
|
3547
|
-
},
|
|
3567
|
+
}, Da = (e) => {
|
|
3548
3568
|
switch (e.outcome) {
|
|
3549
3569
|
case "clean": return 0;
|
|
3550
3570
|
case "lossy": return 2;
|
|
@@ -3553,22 +3573,22 @@ BEGIN
|
|
|
3553
3573
|
case "infidelity": return 1;
|
|
3554
3574
|
case "failed": return 1;
|
|
3555
3575
|
}
|
|
3556
|
-
},
|
|
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) => {
|
|
3557
3577
|
let t = [];
|
|
3558
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"}`);
|
|
3559
3579
|
else if (e.outcome === "infidelity") {
|
|
3560
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:");
|
|
3561
|
-
for (let n of e.infidelity) t.push(
|
|
3581
|
+
for (let n of e.infidelity) t.push(Oa(n));
|
|
3562
3582
|
} else {
|
|
3563
3583
|
t.push(` plan: ${e.operations.length} operation(s), ${e.lossy.length} lossy, ${e.blocked.length} refused`);
|
|
3564
|
-
for (let n of e.operations) t.push(
|
|
3565
|
-
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));
|
|
3566
3586
|
}
|
|
3567
3587
|
return t.push(e.tornDown ? ` branch ${e.branchId} torn down.` : ` branch ${e.branchId} KEPT — drop it when you are done.`), t.join("\n");
|
|
3568
|
-
},
|
|
3588
|
+
}, Aa = (e, ...t) => ({
|
|
3569
3589
|
_tag: "RawSqlFragment",
|
|
3570
3590
|
strings: [...e],
|
|
3571
3591
|
values: [...t]
|
|
3572
|
-
}),
|
|
3592
|
+
}), ja = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
|
|
3573
3593
|
//#endregion
|
|
3574
|
-
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 };
|