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