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