@voltro/database 0.22.1 → 0.24.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 { B as e, W as t, a as n, c as r, i, lt as a, n as o, r as s, rt as c, t as l, z as u } from "./fileBased-CDnutVVk.js";
2
- import { Effect as d } from "effect";
3
- import { createLogger as f } from "@voltro/logger";
4
- import { SqlClient as p } from "@effect/sql";
5
- import { createHash as m } from "node:crypto";
6
- import { promises as h } from "node:fs";
7
- import { join as g } from "node:path";
8
- import { pathToFileURL as ee } from "node:url";
1
+ import { H as e, U as t, a as n, c as r, d as i, ft as a, i as o, n as s, o as c, ot as l, q as u, r as d, s as f } from "./frameworkLiveTables-BvPIm2cD.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";
9
9
  //#region src/migrations/ddlError.ts
10
- var _ = (e, t, n, r = 400) => {
10
+ var b = (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 _ = (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
- }, v = (e) => e.unique === !0 && typeof e.where == "string" && e.where.length > 0, y = (e) => e.replace(/"/g, "`"), b = (e) => typeof e == "string" ? e : e.name ?? String(e), te = (e, t) => `_ua_${t}_${e}`.slice(0, 64), x = (e, t) => {
43
- if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(v)) return e;
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), te = (e, t) => {
43
+ if (t !== "mysql" && t !== "mariadb" || !e.appliedIndexes.some(x)) return e;
44
44
  let n = { ...e.fields }, r = [], i = [];
45
45
  for (let t of e.appliedIndexes) {
46
- if (!v(t)) {
46
+ if (!x(t)) {
47
47
  r.push(t);
48
48
  continue;
49
49
  }
50
- let a = y(t.where), o = [];
50
+ let a = S(t.where), o = [];
51
51
  for (let r of t.fields) {
52
- let i = b(r);
52
+ let i = ee(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 = te(t.name, i);
54
+ let s = C(t.name, i);
55
55
  o.push(s), n[s] = {
56
56
  type: "text",
57
57
  nullable: !0,
@@ -74,11 +74,11 @@ var _ = (e, t, n, r = 400) => {
74
74
  appliedIndexes: r,
75
75
  appliedUniques: [...e.appliedUniques ?? [], ...i]
76
76
  };
77
- }, S = (e, t) => `${e}::${t}`, ne = (e, t) => {
77
+ }, w = (e, t) => `${e}::${t}`, ne = (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(S(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);
@@ -86,89 +86,89 @@ var _ = (e, t, n, r = 400) => {
86
86
  }, re = 6322741009312437n, ie = 250, ae = () => {
87
87
  let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
88
88
  return Number.isFinite(e) && e > 0 ? e : 3e4;
89
- }, oe = (e) => d.gen(function* () {
89
+ }, oe = (e) => p.gen(function* () {
90
90
  let t = ae(), n = Date.now();
91
91
  for (;;) {
92
92
  if ((yield* e`
93
93
  SELECT pg_try_advisory_lock(${"6322741009312437"}::bigint) AS got`)[0]?.got) return;
94
- Date.now() - n >= t && (yield* d.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* d.sleep(`${ie} millis`);
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(`${ie} millis`);
95
95
  }
96
- }), se = (e) => d.gen(function* () {
96
+ }), se = (e) => p.gen(function* () {
97
97
  yield* e`SELECT pg_advisory_unlock(${re.toString()}::bigint)`;
98
- }), ce = `voltro_migration_${re.toString(36)}`, le = 30, ue = (e) => d.gen(function* () {
98
+ }), ce = `voltro_migration_${re.toString(36)}`, le = 30, ue = (e) => p.gen(function* () {
99
99
  (yield* e`
100
- SELECT GET_LOCK(${ce}, ${le}) AS got`)[0]?.got !== 1 && (yield* d.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${ce}' within ${le}s (another migration is in progress, or a prior one left it held).`)));
101
- }), de = (e) => d.gen(function* () {
100
+ SELECT GET_LOCK(${ce}, ${le}) AS got`)[0]?.got !== 1 && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${ce}' within ${le}s (another migration is in progress, or a prior one left it held).`)));
101
+ }), de = (e) => p.gen(function* () {
102
102
  yield* e`SELECT RELEASE_LOCK(${ce})`;
103
- }), fe = `voltro_migration_${re.toString(36)}`, pe = 3e4, me = (e) => d.gen(function* () {
103
+ }), fe = `voltro_migration_${re.toString(36)}`, pe = 3e4, me = (e) => p.gen(function* () {
104
104
  let t = yield* e`
105
105
  DECLARE @res int;
106
106
  EXEC @res = sp_getapplock @Resource = ${fe}, @LockMode = 'Exclusive',
107
107
  @LockOwner = 'Session', @LockTimeout = ${pe};
108
108
  SELECT @res AS res`;
109
- (t[0]?.res ?? -999) < 0 && (yield* d.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${fe}' (sp_getapplock returned ${t[0]?.res ?? "no row"}; another migration is in progress).`)));
110
- }), he = (e) => d.gen(function* () {
109
+ (t[0]?.res ?? -999) < 0 && (yield* p.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${fe}' (sp_getapplock returned ${t[0]?.res ?? "no row"}; another migration is in progress).`)));
110
+ }), he = (e) => p.gen(function* () {
111
111
  yield* e`EXEC sp_releaseapplock @Resource = ${fe}, @LockOwner = 'Session'`;
112
- }), ge = d.void, C = (e) => e.onDialectOrElse({
112
+ }), ge = p.void, T = (e) => e.onDialectOrElse({
113
113
  mysql: () => ue(e),
114
114
  mssql: () => me(e),
115
115
  sqlite: () => ge,
116
116
  orElse: () => oe(e)
117
- }), w = (e) => e.onDialectOrElse({
117
+ }), E = (e) => e.onDialectOrElse({
118
118
  mysql: () => de(e),
119
119
  mssql: () => he(e),
120
120
  sqlite: () => ge,
121
121
  orElse: () => se(e)
122
- }), _e = (e, t) => d.acquireUseRelease(C(e), () => t, () => w(e).pipe(d.orDie)), ve = f({ scope: "voltro:migrate" }), T = (e) => {
123
- ve.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
124
- }, E = (e, t) => {
125
- let n = e.type;
126
- if (e.spatial) {
127
- if (t === "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 '${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
- }
130
- if (n === "raw") {
131
- if (e.rawDdl === void 0) throw Error("raw() column is missing its DDL fragment — this is a framework bug.");
132
- return e.rawDdl;
133
- }
134
- if (n === "array" && e.arrayElement) {
135
- if (t === "postgres") return `${E({
136
- ...e,
137
- type: e.arrayElement,
122
+ }), D = (e, t) => p.acquireUseRelease(T(e), () => t, () => E(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 = (t, n) => {
125
+ let r = t.type;
126
+ if (t.spatial) {
127
+ if (n === "postgres") return `${t.spatial.kind}(${t.spatial.geomKind},${t.spatial.srid})`;
128
+ throw Error(`@voltro/plugin-postgis: ${t.spatial.kind}('${t.spatial.geomKind}', ${t.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.`);
129
+ }
130
+ if (r === "raw") {
131
+ if (t.rawDdl === void 0) throw Error("raw() column is missing its DDL fragment — this is a framework bug.");
132
+ return t.rawDdl;
133
+ }
134
+ if (r === "array" && t.arrayElement) {
135
+ if (n === "postgres") return `${j({
136
+ ...t,
137
+ type: t.arrayElement,
138
138
  arrayElement: void 0
139
- }, t)}[]`;
140
- if (t === "mysql" || t === "mariadb") return "JSON";
141
- if (t === "mssql") return "NVARCHAR(MAX)";
142
- if (u(t)) return "TEXT";
143
- }
144
- if (n === "vector") {
145
- let n = e.vectorDim;
146
- if (n === void 0) throw Error("vector column is missing its dimension — this is a framework bug.");
147
- let r = e.vectorPrecision === "half";
148
- if (t === "postgres") return r ? `HALFVEC(${n})` : `VECTOR(${n})`;
149
- if (t === "mysql" || t === "mariadb") return `VECTOR(${n})`;
150
- if (t === "mssql") return "VARBINARY(MAX)";
151
- if (u(t)) return "BLOB";
152
- }
153
- if (n === "interval") {
154
- if (t === "postgres") return "INTERVAL";
155
- if (t === "mysql" || t === "mariadb" || t === "mssql") return "BIGINT";
156
- if (u(t)) return "INTEGER";
157
- }
158
- if (n === "decimal") {
159
- let n = e.precision, r = e.scale ?? 0;
160
- if (n === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
161
- return u(t) ? "NUMERIC" : t === "postgres" ? `NUMERIC(${n}, ${r})` : `DECIMAL(${n}, ${r})`;
162
- }
163
- if (n === "bigint") return u(t) ? "INTEGER" : "BIGINT";
164
- if (n === "enum") {
165
- if (t === "postgres") return e.enumName ?? "TEXT";
166
- if (t === "mysql" || t === "mariadb") return `ENUM(${(e.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
167
- if (t === "mssql") return "NVARCHAR(255)";
168
- if (u(t)) return "TEXT";
169
- }
170
- if (n === "text" && e.maxLength !== void 0 && e.generatedAs === void 0) return t === "mssql" ? `NVARCHAR(${e.maxLength})` : u(t) ? "TEXT" : `VARCHAR(${e.maxLength})`;
171
- if (u(t)) switch (n) {
139
+ }, n)}[]`;
140
+ if (n === "mysql" || n === "mariadb") return "JSON";
141
+ if (n === "mssql") return "NVARCHAR(MAX)";
142
+ if (e(n)) return "TEXT";
143
+ }
144
+ if (r === "vector") {
145
+ let r = t.vectorDim;
146
+ if (r === void 0) throw Error("vector column is missing its dimension — this is a framework bug.");
147
+ let i = t.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 (e(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 (e(n)) return "INTEGER";
157
+ }
158
+ if (r === "decimal") {
159
+ let r = t.precision, i = t.scale ?? 0;
160
+ if (r === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
161
+ return e(n) ? "NUMERIC" : n === "postgres" ? `NUMERIC(${r}, ${i})` : `DECIMAL(${r}, ${i})`;
162
+ }
163
+ if (r === "bigint") return e(n) ? "INTEGER" : "BIGINT";
164
+ if (r === "enum") {
165
+ if (n === "postgres") return t.enumName ?? "TEXT";
166
+ if (n === "mysql" || n === "mariadb") return `ENUM(${(t.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
167
+ if (n === "mssql") return "NVARCHAR(255)";
168
+ if (e(n)) return "TEXT";
169
+ }
170
+ if (r === "text" && t.maxLength !== void 0 && t.generatedAs === void 0) return n === "mssql" ? `NVARCHAR(${t.maxLength})` : e(n) ? "TEXT" : `VARCHAR(${t.maxLength})`;
171
+ if (e(n)) switch (r) {
172
172
  case "id": return "TEXT";
173
173
  case "text": return "TEXT";
174
174
  case "integer": return "INTEGER";
@@ -184,9 +184,9 @@ var _ = (e, t, n, r = 400) => {
184
184
  case "array": return "TEXT";
185
185
  case "interval": return "INTEGER";
186
186
  }
187
- if (t === "mysql" || t === "mariadb") switch (n) {
187
+ if (n === "mysql" || n === "mariadb") switch (r) {
188
188
  case "id": return "VARCHAR(64)";
189
- case "text": return e.hasDefault && e.defaultFactory === void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : e.generatedAs ? "TEXT" : "LONGTEXT";
189
+ case "text": return t.hasDefault && t.defaultFactory === void 0 || t.oneOf && t.oneOf.length > 0 ? "VARCHAR(255)" : t.generatedAs ? "TEXT" : "LONGTEXT";
190
190
  case "integer": return "INT";
191
191
  case "real": return "DOUBLE";
192
192
  case "boolean": return "TINYINT(1)";
@@ -200,9 +200,9 @@ var _ = (e, t, n, r = 400) => {
200
200
  case "array": return "JSON";
201
201
  case "interval": return "BIGINT";
202
202
  }
203
- if (t === "mssql") switch (n) {
203
+ if (n === "mssql") switch (r) {
204
204
  case "id": return "NVARCHAR(64)";
205
- case "text": return e.hasDefault && e.defaultFactory === void 0 || e.oneOf && e.oneOf.length > 0 ? "NVARCHAR(450)" : "NVARCHAR(MAX)";
205
+ case "text": return t.hasDefault && t.defaultFactory === void 0 || t.oneOf && t.oneOf.length > 0 ? "NVARCHAR(450)" : "NVARCHAR(MAX)";
206
206
  case "integer": return "INT";
207
207
  case "real": return "FLOAT";
208
208
  case "boolean": return "BIT";
@@ -216,7 +216,7 @@ var _ = (e, t, n, r = 400) => {
216
216
  case "array": return "NVARCHAR(MAX)";
217
217
  case "interval": return "BIGINT";
218
218
  }
219
- switch (n) {
219
+ switch (r) {
220
220
  case "id": return "TEXT";
221
221
  case "text": return "TEXT";
222
222
  case "integer": return "INTEGER";
@@ -228,26 +228,26 @@ var _ = (e, t, n, r = 400) => {
228
228
  case "bytes": return "BYTEA";
229
229
  case "reference": return "TEXT";
230
230
  case "vector": return "VECTOR";
231
- case "enum": return e.enumName ?? "TEXT";
231
+ case "enum": return t.enumName ?? "TEXT";
232
232
  case "array": return "TEXT[]";
233
233
  case "interval": return "INTERVAL";
234
234
  }
235
- }, ye = (e, t) => {
236
- if (!e.hasDefault || e.defaultFactory !== void 0) return null;
237
- let n = e.defaultValue;
238
- return n === "now" ? u(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) ? be(n, e, t) : typeof n == "object" && n ? D(n, t) : null;
239
- }, be = (e, t, n) => {
240
- if (n !== "postgres" || t.type !== "array" || t.arrayElement === void 0) return D(e, n);
241
- let r = E({
235
+ }, be = (t, n) => {
236
+ if (!t.hasDefault || t.defaultFactory !== void 0) return null;
237
+ let r = t.defaultValue;
238
+ return r === "now" ? e(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, t, 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({
242
242
  ...t,
243
243
  type: t.arrayElement,
244
244
  arrayElement: void 0
245
245
  }, n);
246
246
  return `DEFAULT '{${e.map((e) => typeof e == "number" || typeof e == "boolean" ? String(e) : `"${String(e).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`).join(",").replace(/'/g, "''")}}'::${r}[]`;
247
- }, D = (e, t) => {
247
+ }, M = (e, t) => {
248
248
  let n = JSON.stringify(e).replace(/'/g, "''");
249
249
  return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CAST('${n}' AS JSON))` : `DEFAULT '${n}'`;
250
- }, O = (e, t) => {
250
+ }, N = (e, t) => {
251
251
  switch (t) {
252
252
  case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
253
253
  case "mysql":
@@ -256,7 +256,7 @@ var _ = (e, t, n, r = 400) => {
256
256
  case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
257
257
  case "turso": return `"${e}" INTEGER PRIMARY KEY`;
258
258
  }
259
- }, k = (e, t) => {
259
+ }, Se = (e, t) => {
260
260
  if (e === "restrict" && t === "mssql") return "NO ACTION";
261
261
  switch (e) {
262
262
  case "cascade": return "CASCADE";
@@ -264,173 +264,222 @@ var _ = (e, t, n, r = 400) => {
264
264
  case "setNull": return "SET NULL";
265
265
  case "noAction": return "NO ACTION";
266
266
  }
267
- }, xe = (t, n, r) => r === null ? e(t, n) : `${e(r, n)}.${e(t, n)}`, Se = 191, Ce = (t, n, r) => {
268
- let i = e(t, r);
267
+ }, Ce = (e, n, r) => r === null ? t(e, n) : `${t(r, n)}.${t(e, n)}`, we = 191, Te = (e, n, r) => {
268
+ let i = t(e, r);
269
269
  if (r !== "mysql" && r !== "mariadb") return i;
270
- let a = n[t];
270
+ let a = n[e];
271
271
  if (!a) return i;
272
- let o = E(a, r).toUpperCase();
273
- return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${Se})` : i;
274
- }, we = (e, t) => {
272
+ let o = j(a, r).toUpperCase();
273
+ return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${we})` : i;
274
+ }, Ee = (e, t) => {
275
275
  if (!e.generatedAs) return null;
276
276
  let { expr: n, stored: r } = e.generatedAs;
277
- if (t === "postgres") return r || T("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
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`;
278
278
  if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
279
279
  if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
280
280
  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
281
  return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
282
- }, Te = (t, n, r, i, a = !1, o = !1) => {
283
- if (n.type === "id" && n.idScheme?.kind === "numeric") return O(t, r);
284
- let s = r === "mssql" && n.type === "text" && !n.generatedAs && n.maxLength === void 0 && i?.has(t) ? "NVARCHAR(450)" : E(n, r), c = [e(t, r), s];
285
- n.type === "id" && !o && c.push("PRIMARY KEY");
286
- let l = we(n, r);
287
- if (l) c.push(l);
282
+ }, De = (n, r, i, a, o = !1, s = !1) => {
283
+ if (r.type === "id" && r.idScheme?.kind === "numeric") return N(n, i);
284
+ let c = i === "mssql" && r.type === "text" && !r.generatedAs && r.maxLength === void 0 && a?.has(n) ? "NVARCHAR(450)" : j(r, i), l = [t(n, i), c];
285
+ r.type === "id" && !s && l.push("PRIMARY KEY");
286
+ let u = Ee(r, i);
287
+ if (u) l.push(u);
288
288
  else {
289
- n.nullable || c.push("NOT NULL"), n.unique && n.type !== "id" && c.push("UNIQUE");
290
- let e = ye(n, r);
291
- e && c.push(e);
292
- }
293
- if (n.type === "reference" && n.references && !a) {
294
- let t = n.references();
295
- c.push(`REFERENCES ${e(t.tableName, r)} (${e("id", r)})`);
296
- let i = k(n.onDelete ?? "restrict", r);
297
- c.push(`ON DELETE ${i}`);
298
- let a = k(n.refOnUpdate ?? "noAction", r);
299
- a !== "NO ACTION" && c.push(`ON UPDATE ${a}`);
300
- }
301
- if (n.oneOf && n.oneOf.length > 0) {
302
- let i = n.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
303
- c.push(`CHECK (${e(t, r)} IN (${i}))`);
304
- }
305
- if (n.checks && n.checks.length > 0) for (let e of n.checks) c.push(`CHECK (${e})`);
306
- if (n.type === "enum" && n.enumValues && n.enumValues.length > 0 && (r === "mssql" || u(r))) {
307
- let i = n.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
308
- c.push(`CHECK (${e(t, r)} IN (${i}))`);
309
- }
310
- if (n.type === "json" || n.type === "array") {
311
- let n = e(t, r);
312
- u(r) ? c.push(`CHECK (${n} IS NULL OR json_valid(${n}))`) : r === "mssql" && c.push(`CHECK (${n} IS NULL OR ISJSON(${n}) = 1)`);
313
- }
314
- return c.join(" ");
315
- }, Ee = (t, n, r = null, i) => {
289
+ r.nullable || l.push("NOT NULL"), r.unique && r.type !== "id" && l.push("UNIQUE");
290
+ let e = be(r, i);
291
+ e && l.push(e);
292
+ }
293
+ if (r.type === "reference" && r.references && !o) {
294
+ let e = r.references();
295
+ l.push(`REFERENCES ${t(e.tableName, i)} (${t("id", i)})`);
296
+ let n = Se(r.onDelete ?? "restrict", i);
297
+ l.push(`ON DELETE ${n}`);
298
+ let a = Se(r.refOnUpdate ?? "noAction", i);
299
+ a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
300
+ }
301
+ if (r.oneOf && r.oneOf.length > 0) {
302
+ let e = r.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
303
+ l.push(`CHECK (${t(n, i)} IN (${e}))`);
304
+ }
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" || e(i))) {
307
+ let e = r.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
308
+ l.push(`CHECK (${t(n, i)} IN (${e}))`);
309
+ }
310
+ if (r.type === "json" || r.type === "array") {
311
+ let r = t(n, i);
312
+ e(i) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : i === "mssql" && l.push(`CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
313
+ }
314
+ return l.join(" ");
315
+ }, Oe = (e, n, r = null, i) => {
316
316
  let a = /* @__PURE__ */ new Set();
317
- for (let e of t.appliedIndexes ?? []) for (let t of e.fields) typeof t == "string" && a.add(t);
318
- for (let e of t.appliedUniques ?? []) for (let t of e.fields) typeof t == "string" && a.add(t);
319
- let o = t.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(t.fields).map(([e, t]) => ` ${Te(e, t, n, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (t.appliedUniques ?? []).map((r) => {
320
- let i = r.fields.map((e) => Ce(e, t.fields, n)).join(", ");
321
- return ` CONSTRAINT ${e(r.name, n)} UNIQUE (${i})`;
322
- }), u = (t.appliedChecks ?? []).map((t) => ` CONSTRAINT ${e(t.name, n)} CHECK (${t.expr})`), d = [
323
- ...s ? [` PRIMARY KEY (${o.map((e) => Ce(e, t.fields, n)).join(", ")})`] : [],
317
+ for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
318
+ 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, t]) => ` ${De(e, t, n, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((r) => {
320
+ let i = r.fields.map((t) => Te(t, e.fields, n)).join(", ");
321
+ return ` CONSTRAINT ${t(r.name, n)} UNIQUE (${i})`;
322
+ }), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${t(e.name, n)} CHECK (${e.expr})`), d = [
323
+ ...s ? [` PRIMARY KEY (${o.map((t) => Te(t, e.fields, n)).join(", ")})`] : [],
324
324
  ...l,
325
325
  ...u
326
- ], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p = xe(t.tableName, n, r);
326
+ ], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p = Ce(e.tableName, n, r);
327
327
  if (n === "mssql") {
328
- let e = r === null ? t.tableName : `${r}.${t.tableName}`, n = `CREATE TABLE ${p} (\n${f}\n)`;
329
- return `IF OBJECT_ID('${e.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${n.replace(/'/g, "''")}');`;
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, "''")}');`;
330
330
  }
331
331
  return [
332
332
  `CREATE TABLE IF NOT EXISTS ${p} (`,
333
333
  f,
334
334
  ");"
335
335
  ].join("\n");
336
- }, De = (t, n, r) => {
337
- let i = `${t}_${n.name}_fts`, a = (t) => e(t, r), o = n.columns.map(a).join(", "), s = n.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(t)} 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(t)} 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(t)} 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
- }, Oe = (n, r, a = null) => {
340
- let o = [], s = /* @__PURE__ */ new Set(), c = (e) => e.join("\0"), l = (e, n, i, a) => {
341
- let o = {
336
+ }, ke = (e, n, r) => {
337
+ let i = `${e}_${n.name}_fts`, a = (e) => t(e, r), o = n.columns.map(a).join(", "), s = n.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 = (e, n, r = null) => {
340
+ let i = [], a = /* @__PURE__ */ new Set(), o = (e) => e.join("\0"), s = (e, t, r, i) => {
341
+ let a = {
342
342
  using: "",
343
343
  withSuffix: "",
344
344
  skip: !1
345
345
  };
346
- if (i === void 0 || i === "btree") return o;
347
- if (i === "gist") return r === "postgres" ? {
346
+ if (r === void 0 || r === "btree") return a;
347
+ if (r === "gist") return n === "postgres" ? {
348
348
  using: " USING GIST",
349
349
  withSuffix: "",
350
350
  skip: !1
351
- } : (T(`[voltro:migrate] index '${e}' 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" ? {
351
+ } : (A(`[voltro:migrate] index '${e}' on '${t}': ${n} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), a);
352
+ if (r === "gin") return n === "postgres" ? {
353
353
  using: " USING GIN",
354
354
  withSuffix: "",
355
355
  skip: !1
356
- } : r === "mysql" || r === "mariadb" ? (T(`[voltro:migrate] gin index '${e}' 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(...).`), {
356
+ } : n === "mysql" || n === "mariadb" ? (A(`[voltro:migrate] gin index '${e}' on '${t}': ${n} 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
357
  using: "",
358
358
  withSuffix: "",
359
359
  skip: !0
360
- }) : (T(`[voltro:migrate] gin index '${e}' 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" ? {
360
+ }) : (A(`[voltro:migrate] gin index '${e}' on '${t}': ${n} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), a);
361
+ if (r === "brin") return n === "postgres" ? {
362
362
  using: " USING BRIN",
363
363
  withSuffix: "",
364
364
  skip: !1
365
- } : (T(`[voltro:migrate] brin index '${e}' 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 e = a?.hnsw?.m ?? 16, n = a?.hnsw?.efConstruction ?? 64, r = a?.hnsw?.opclass ?? t(a?.hnsw?.distance);
365
+ } : (A(`[voltro:migrate] brin index '${e}' on '${t}': ${n} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), a);
366
+ if (r === "hnsw") {
367
+ if (n === "postgres") {
368
+ let e = i?.hnsw?.m ?? 16, t = i?.hnsw?.efConstruction ?? 64, n = i?.hnsw?.opclass ?? u(i?.hnsw?.distance);
369
369
  return {
370
370
  using: " USING hnsw",
371
- withSuffix: ` WITH (m = ${e}, ef_construction = ${n})`,
372
- opclass: r,
371
+ withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
372
+ opclass: n,
373
373
  skip: !1
374
374
  };
375
375
  }
376
- return T(`[voltro:migrate] hnsw index '${e}' on '${n}': ${r} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
376
+ return A(`[voltro:migrate] hnsw index '${e}' on '${t}': ${n} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
377
377
  using: "",
378
378
  withSuffix: "",
379
379
  skip: !0
380
380
  };
381
381
  }
382
- return o;
383
- }, u = (e, t) => {
384
- let a = e.map((e) => {
385
- if (typeof e == "string") return Ce(e, n.fields, r);
386
- if ("jsonPath" in e) {
387
- let { column: t, path: n, numeric: a } = e.jsonPath;
388
- return `(${i(t, n, r, { numeric: a })})`;
382
+ return a;
383
+ }, c = (t, r) => {
384
+ let i = t.map((t) => {
385
+ if (typeof t == "string") return Te(t, e.fields, n);
386
+ if ("jsonPath" in t) {
387
+ let { column: e, path: r, numeric: i } = t.jsonPath;
388
+ return `(${f(e, r, n, { numeric: i })})`;
389
389
  }
390
- return `(${e.expr})`;
390
+ return `(${t.expr})`;
391
391
  });
392
- return t !== void 0 && a.length === 1 ? `${a[0]} ${t}` : a.join(", ");
393
- }, d = (t, n, i, o, s, c = "", d = !1) => {
394
- let f = l(t, n, o, s);
392
+ return r !== void 0 && i.length === 1 ? `${i[0]} ${r}` : i.join(", ");
393
+ }, l = (e, i, a, o, l, u = "", d = !1) => {
394
+ let f = s(e, i, o, l);
395
395
  if (f.skip) return "";
396
- let p = u(i, f.opclass), m = `${f.withSuffix}${c}`, h = xe(n, r, a), g = d ? "UNIQUE " : "";
397
- return r === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${t}') CREATE ${g}INDEX ${e(t, r)} ON ${h}${f.using} (${p})${m};` : r === "mysql" ? `CREATE ${g}INDEX ${e(t, r)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${e(t, r)} ON ${h}${f.using} (${p})${m};`;
396
+ let p = c(a, f.opclass), m = `${f.withSuffix}${u}`, h = Ce(i, n, r), g = d ? "UNIQUE " : "";
397
+ return n === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE ${g}INDEX ${t(e, n)} ON ${h}${f.using} (${p})${m};` : n === "mysql" ? `CREATE ${g}INDEX ${t(e, n)} ON ${h}${f.using} (${p})${m};` : `CREATE ${g}INDEX IF NOT EXISTS ${t(e, n)} ON ${h}${f.using} (${p})${m};`;
398
398
  };
399
- for (let t of n.appliedFullText ?? []) if (r === "postgres") {
400
- let i = t.config ?? "english", a = `${t.name}_tsv`, s = t.columns.map((n) => {
401
- let a = t.weights?.[n] ?? "A";
402
- return `setweight(to_tsvector('${i}', coalesce(${e(n, r)}, '')), '${a}')`;
399
+ for (let r of e.appliedFullText ?? []) if (n === "postgres") {
400
+ let a = r.config ?? "english", o = `${r.name}_tsv`, s = r.columns.map((e) => {
401
+ let i = r.weights?.[e] ?? "A";
402
+ return `setweight(to_tsvector('${a}', coalesce(${t(e, n)}, '')), '${i}')`;
403
403
  }).join(" || ");
404
- o.push(`ALTER TABLE ${e(n.tableName, r)} ADD COLUMN IF NOT EXISTS ${e(a, r)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), o.push(`CREATE INDEX IF NOT EXISTS ${e(t.name, r)} ON ${e(n.tableName, r)} USING GIN (${e(a, r)});`);
405
- } else if (r === "mysql" || r === "mariadb") {
406
- let i = t.columns.map((t) => e(t, r)).join(", ");
407
- o.push(`CREATE FULLTEXT INDEX ${e(t.name, r)} ON ${e(n.tableName, r)} (${i});`);
408
- } else if (r === "turso") throw Error(`@voltro/sql-turso: full-text index '${t.name}' on '${n.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" ? o.push(...De(n.tableName, t, r)) : T(`[voltro:migrate] full-text index '${t.name}' on '${n.tableName}': ${r} uses a ranked LIKE search at query time (no native FTS catalog required).`);
410
- for (let e of n.appliedIndexes) {
411
- if ((r === "mariadb" || r === "mssql") && e.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
412
- T(`[voltro:migrate] json-path index '${e.name}' on '${n.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(...).`);
404
+ i.push(`ALTER TABLE ${t(e.tableName, n)} ADD COLUMN IF NOT EXISTS ${t(o, n)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), i.push(`CREATE INDEX IF NOT EXISTS ${t(r.name, n)} ON ${t(e.tableName, n)} USING GIN (${t(o, n)});`);
405
+ } else if (n === "mysql" || n === "mariadb") {
406
+ let a = r.columns.map((e) => t(e, n)).join(", ");
407
+ i.push(`CREATE FULLTEXT INDEX ${t(r.name, n)} ON ${t(e.tableName, n)} (${a});`);
408
+ } else if (n === "turso") throw Error(`@voltro/sql-turso: full-text index '${r.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
409
+ else n === "sqlite" ? i.push(...ke(e.tableName, r, n)) : A(`[voltro:migrate] full-text index '${r.name}' on '${e.tableName}': ${n} uses a ranked LIKE search at query time (no native FTS catalog required).`);
410
+ for (let t of e.appliedIndexes) {
411
+ if ((n === "mariadb" || n === "mssql") && t.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
412
+ A(`[voltro:migrate] json-path index '${t.name}' on '${e.tableName}': ${n} cannot index a JSON expression directly — skipping. For an indexed JSON path on ${n}, add a generated column for the path (text().generatedAs(...) / .stored()) and .index([...]) it, then filter on that column instead of jsonField(...).`);
413
413
  continue;
414
414
  }
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 '${n.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 t = "";
417
- e.where !== void 0 && e.where.length > 0 && (r === "mysql" || r === "mariadb" ? T(`[voltro:migrate] partial index '${e.name}' on '${n.tableName}': ${r} does not support WHERE clauses on indexes — emitting a full index`) : t = ` WHERE ${e.where}`);
418
- let i = d(e.name, n.tableName, e.fields, e.kind, e.kindOptions, t, e.unique === !0);
419
- i !== "" && o.push(i), e.fields.every((e) => typeof e == "string") && s.add(c(e.fields));
420
- }
421
- for (let [e, t] of Object.entries(n.fields)) {
422
- if (t.type !== "reference" || t.fkAutoIndex === !1 || s.has(c([e]))) continue;
423
- let r = `${n.tableName}_${e}_idx`;
424
- o.push(d(r, n.tableName, [e])), s.add(c([e]));
425
- }
426
- return o.join("\n");
427
- }, ke = "CREATE OR REPLACE FUNCTION framework_notify_change() RETURNS trigger AS $$\nDECLARE\n payload TEXT;\nBEGIN\n payload := json_build_object(\n 'table', TG_TABLE_NAME,\n -- The schema the write landed in. Under namespace isolation this is\n -- the tenant schema (tenant_<id>); the CDC consumer uses it so a\n -- write in tenant A namespace does not spuriously wake tenant B\n -- subscriptions on the same-named table. public/absent = shared.\n 'schema', TG_TABLE_SCHEMA,\n 'op', lower(TG_OP),\n 'old', CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE row_to_json(OLD) END,\n 'new', CASE WHEN TG_OP = 'DELETE' THEN NULL ELSE row_to_json(NEW) END\n )::text;\n -- pg_notify hard-caps the payload at 8000 bytes; a wide reactive row\n -- (big text / json column) would otherwise abort the write itself.\n -- Fall back to a body-less notice — the CDC consumer treats absent\n -- old/new as \"all columns changed\" and re-queries, so correctness is\n -- preserved; only the delta-diff fast path is skipped for that write.\n IF octet_length(payload) >= 7999 THEN\n payload := json_build_object(\n 'table', TG_TABLE_NAME,\n 'schema', TG_TABLE_SCHEMA,\n 'op', lower(TG_OP),\n 'old', NULL,\n 'new', NULL,\n 'oversized', true\n )::text;\n END IF;\n PERFORM pg_notify('framework_changes', payload);\n RETURN COALESCE(NEW, OLD);\nEND;\n$$ LANGUAGE plpgsql;", Ae = (e) => `
428
- ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL;
429
- DROP TRIGGER IF EXISTS framework_changes_${e.tableName} ON "${e.tableName}";
430
- CREATE TRIGGER framework_changes_${e.tableName}
431
- AFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"
432
- FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
433
- `.trim(), je = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), Me = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), Ne = (e) => {
415
+ if (t.unique && t.where !== void 0 && t.where.length > 0 && (n === "mysql" || n === "mariadb")) throw Error(`@voltro/migrate: uniqueActive index '${t.name}' on '${e.tableName}' cannot be expressed on ${n} — 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 ${n}, or move this table to postgres/sqlite/mssql.`);
416
+ let r = "";
417
+ t.where !== void 0 && t.where.length > 0 && (n === "mysql" || n === "mariadb" ? A(`[voltro:migrate] partial index '${t.name}' on '${e.tableName}': ${n} does not support WHERE clauses on indexes — emitting a full index`) : r = ` WHERE ${t.where}`);
418
+ let s = l(t.name, e.tableName, t.fields, t.kind, t.kindOptions, r, t.unique === !0);
419
+ s !== "" && i.push(s), t.fields.every((e) => typeof e == "string") && a.add(o(t.fields));
420
+ }
421
+ for (let [t, n] of Object.entries(e.fields)) {
422
+ if (n.type !== "reference" || n.fkAutoIndex === !1 || a.has(o([t]))) continue;
423
+ let r = `${e.tableName}_${t}_idx`;
424
+ i.push(l(r, e.tableName, [t])), a.add(o([t]));
425
+ }
426
+ return i.join("\n");
427
+ }, je = (e, t, n = O) => {
428
+ if (t !== "postgres") return [];
429
+ 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 $$
433
+ DECLARE
434
+ payload TEXT;
435
+ BEGIN
436
+ payload := json_build_object(
437
+ 'table', TG_TABLE_NAME,
438
+ -- The schema the write landed in. Under namespace isolation this is
439
+ -- the tenant schema (tenant_<id>); the CDC consumer uses it so a
440
+ -- write in tenant A namespace does not spuriously wake tenant B
441
+ -- subscriptions on the same-named table. public/absent = shared.
442
+ 'schema', TG_TABLE_SCHEMA,
443
+ 'op', lower(TG_OP),
444
+ 'old', CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE row_to_json(OLD) END,
445
+ 'new', CASE WHEN TG_OP = 'DELETE' THEN NULL ELSE row_to_json(NEW) END
446
+ )::text;
447
+ -- 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.
452
+ IF octet_length(payload) >= 7999 THEN
453
+ payload := json_build_object(
454
+ 'table', TG_TABLE_NAME,
455
+ 'schema', TG_TABLE_SCHEMA,
456
+ 'op', lower(TG_OP),
457
+ 'old', NULL,
458
+ 'new', NULL,
459
+ 'oversized', true
460
+ )::text;
461
+ END IF;
462
+ PERFORM pg_notify('${e}', payload);
463
+ RETURN COALESCE(NEW, OLD);
464
+ END;
465
+ $$ LANGUAGE plpgsql;
466
+ `.trim(), Ne = (e, t) => {
467
+ let n = _e(e.tableName, t);
468
+ return [
469
+ `ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL`,
470
+ `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)}()`
472
+ ];
473
+ }, Pe = (e, t) => Ne(e, t).map((e) => `${e};`).join("\n"), Fe = (e) => {
474
+ if (e.dialect !== "postgres") return [];
475
+ 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`);
481
+ 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) => {
434
483
  let t = new Map(e.map((e) => [e.tableName, e])), n = ne(e.map((e) => e.tableName), (e) => {
435
484
  let n = t.get(e);
436
485
  return n ? Object.entries(n.fields).flatMap(([e, n]) => {
@@ -442,7 +491,7 @@ FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
442
491
  }] : [];
443
492
  }) : [];
444
493
  }), r = [];
445
- for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(S(t.tableName, e)) && r.push({
494
+ 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({
446
495
  table: t.tableName,
447
496
  column: e,
448
497
  targetTable: i.references().tableName,
@@ -453,7 +502,7 @@ FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
453
502
  if (!(i.has(e.tableName) || a.has(e.tableName))) {
454
503
  a.add(e.tableName);
455
504
  for (let [r, i] of Object.entries(e.fields)) {
456
- if (i.type !== "reference" || !i.references || n.has(S(e.tableName, r))) continue;
505
+ if (i.type !== "reference" || !i.references || n.has(w(e.tableName, r))) continue;
457
506
  let a = i.references();
458
507
  if (a.tableName === e.tableName) continue;
459
508
  let o = t.get(a.tableName);
@@ -467,30 +516,30 @@ FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
467
516
  sorted: o,
468
517
  cyclic: r
469
518
  };
470
- }, Pe = (t, n, r = null) => {
471
- let i = (t) => r ? `${e(r, n)}.${e(t, n)}` : e(t, n), a = `${t.table}_${t.column}_fkey`, o = k(t.onDelete, n), s = k(t.onUpdate, n), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (r) => `ADD CONSTRAINT ${e(a, n)} FOREIGN KEY ${r ? "IF NOT EXISTS " : ""}(${e(t.column, n)}) REFERENCES ${i(t.targetTable)} (${e("id", n)})${c}`;
519
+ }, ze = (e, n, r = null) => {
520
+ let i = (e) => r ? `${t(r, n)}.${t(e, n)}` : t(e, n), a = `${e.table}_${e.column}_fkey`, o = Se(e.onDelete, n), s = Se(e.onUpdate, n), c = ` ON DELETE ${o}${s === "NO ACTION" ? "" : ` ON UPDATE ${s}`}`, l = (r) => `ADD CONSTRAINT ${t(a, n)} FOREIGN KEY ${r ? "IF NOT EXISTS " : ""}(${t(e.column, n)}) REFERENCES ${i(e.targetTable)} (${t("id", n)})${c}`;
472
521
  switch (n) {
473
522
  case "postgres": return [
474
523
  "DO $$ BEGIN",
475
524
  " IF NOT EXISTS (SELECT 1 FROM pg_constraint",
476
- ` WHERE conname = '${a}' AND conrelid = '${r ? `${r}.` : ""}${t.table}'::regclass) THEN`,
477
- ` ALTER TABLE ${i(t.table)} ${l(!1)};`,
525
+ ` WHERE conname = '${a}' AND conrelid = '${r ? `${r}.` : ""}${e.table}'::regclass) THEN`,
526
+ ` ALTER TABLE ${i(e.table)} ${l(!1)};`,
478
527
  " END IF;",
479
528
  "END $$;"
480
529
  ].join("\n");
481
- case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${a}') ALTER TABLE ${i(t.table)} ${l(!1)};`;
482
- case "mariadb": return `ALTER TABLE ${i(t.table)} ${l(!0)};`;
483
- default: return `ALTER TABLE ${i(t.table)} ${l(!1)};`;
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)};`;
484
533
  }
485
- }, Fe = (e, t) => {
486
- let n = /* @__PURE__ */ new Map();
487
- if (u(t)) return n;
488
- for (let t of e) {
489
- let e = n.get(t.table) ?? /* @__PURE__ */ new Set();
490
- e.add(t.column), n.set(t.table, e);
534
+ }, Be = (t, n) => {
535
+ let r = /* @__PURE__ */ new Map();
536
+ if (e(n)) return r;
537
+ for (let e of t) {
538
+ let t = r.get(e.table) ?? /* @__PURE__ */ new Set();
539
+ t.add(e.column), r.set(e.table, t);
491
540
  }
492
- return n;
493
- }, Ie = (e, t) => {
541
+ return r;
542
+ }, Ve = (e, t) => {
494
543
  if (t !== "postgres") return "";
495
544
  let n = /* @__PURE__ */ new Map();
496
545
  for (let t of e) for (let e of Object.values(t.fields)) {
@@ -506,7 +555,7 @@ FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
506
555
  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 $$;`);
507
556
  }
508
557
  return r.join("\n\n");
509
- }, Le = (e, t) => {
558
+ }, He = (e, t) => {
510
559
  if (t !== "postgres") return "";
511
560
  let n = /* @__PURE__ */ new Set();
512
561
  for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
@@ -520,80 +569,71 @@ BEGIN
520
569
  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 $$;`);
521
570
  }
522
571
  return r.join("\n\n");
523
- }, Re = (e) => {
524
- let t = [], r = [];
525
- for (let i of e) n(i) ? r.push(i) : t.push(i);
572
+ }, Ue = (e) => {
573
+ let t = [], n = [];
574
+ for (let i of e) r(i) ? n.push(i) : t.push(i);
526
575
  return {
527
576
  tables: t,
528
- views: r
577
+ views: n
529
578
  };
530
- }, A = (e, t) => {
531
- let { tables: n, views: i } = Re(e), { sorted: a, cyclic: o } = Ne(n.map((e) => x(e, t))), s = Fe(o, t), c = [];
532
- t === "postgres" && je(a) && c.push("CREATE EXTENSION IF NOT EXISTS vector;"), t === "postgres" && Me(a) && c.push("CREATE EXTENSION IF NOT EXISTS postgis;");
533
- let l = Le(a, t);
534
- l && c.push(l);
535
- let d = Ie(a, t);
536
- d && c.push(d);
537
- for (let e of a) c.push(Ee(e, t, null, s.get(e.tableName)));
538
- if (!u(t)) for (let e of o) c.push(Pe(e, t));
539
- for (let e of a) {
540
- let n = Oe(e, t);
541
- n && c.push(n);
542
- }
543
- let f = a.filter((e) => e.isReactive !== !1);
544
- if (f.length > 0 && t === "postgres") {
545
- c.push(ke);
546
- for (let e of f) c.push(Ae(e));
547
- }
548
- for (let e of i) c.push(r(e, t));
549
- return c.join("\n\n") + "\n";
550
- }, ze = (t, n, r) => {
551
- let i = e(t, n);
579
+ }, We = (t, n, r = O) => {
580
+ let { tables: a, views: o } = Ue(t), { sorted: s, cyclic: c } = Re(a.map((e) => te(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);
583
+ d && u.push(d);
584
+ let f = Ve(s, n);
585
+ f && u.push(f);
586
+ for (let e of s) u.push(Oe(e, n, null, l.get(e.tableName)));
587
+ if (!e(n)) for (let e of c) u.push(ze(e, n));
588
+ for (let e of s) {
589
+ let t = Ae(e, n);
590
+ t && u.push(t);
591
+ }
592
+ u.push(...je(s, n, r));
593
+ for (let e of o) u.push(i(e, n));
594
+ return u.join("\n\n") + "\n";
595
+ }, Ge = (e, n, r) => {
596
+ let i = t(e, n);
552
597
  switch (n) {
553
598
  case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
554
599
  case "mysql":
555
600
  case "mariadb": return `CREATE DATABASE IF NOT EXISTS ${i};`;
556
- case "mssql": return `IF SCHEMA_ID('${t.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${i.replace(/'/g, "''")}');`;
601
+ case "mssql": return `IF SCHEMA_ID('${e.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${i.replace(/'/g, "''")}');`;
557
602
  case "turso":
558
- case "sqlite": return `ATTACH DATABASE '${(r ?? `${t}.db`).replace(/'/g, "''")}' AS ${i};`;
559
- }
560
- }, Be = (t, n, r, i) => {
561
- let a = ze(r, n, i), o = e(r, n);
562
- if (n === "postgres") return `${a}\n\nSET search_path TO ${o};\n\n${A(t, n)}`;
563
- if (n === "mysql" || n === "mariadb") return `${a}\n\nUSE ${o};\n\n${A(t, n)}`;
564
- let { sorted: s, cyclic: c } = Ne(t), l = Fe(c, n), d = [a];
565
- for (let e of s) d.push(Ee(e, n, r, l.get(e.tableName)));
566
- if (!u(n)) for (let e of c) d.push(Pe(e, n, r));
567
- for (let e of s) {
568
- let t = Oe(e, n, r);
603
+ case "sqlite": return `ATTACH DATABASE '${(r ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
604
+ }
605
+ }, Ke = (n, r, i, a) => {
606
+ let o = Ge(i, r, a), s = t(i, r);
607
+ if (r === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${We(n, r)}`;
608
+ if (r === "mysql" || r === "mariadb") return `${o}\n\nUSE ${s};\n\n${We(n, r)}`;
609
+ let { sorted: c, cyclic: l } = Re(n), u = Be(l, r), d = [o];
610
+ for (let e of c) d.push(Oe(e, r, i, u.get(e.tableName)));
611
+ if (!e(r)) for (let e of l) d.push(ze(e, r, i));
612
+ for (let e of c) {
613
+ let t = Ae(e, r, i);
569
614
  t && d.push(t);
570
615
  }
571
616
  return d.join("\n\n") + "\n";
572
- }, Ve = (e, t) => {
573
- let { sorted: n, cyclic: r } = Ne(e), i = Fe(r, t), a = [], o = Le(n, t);
574
- o && a.push(o);
575
- let s = Ie(n, t);
576
- s && a.push(s);
577
- for (let e of n) a.push(Ee(e, t, null, i.get(e.tableName)));
578
- for (let e of r) a.push(Pe(e, t));
579
- let c = n.filter((e) => e.isReactive);
580
- if (c.length > 0) {
581
- a.push(ke);
582
- for (let e of c) a.push(Ae(e));
583
- }
584
- return a.join("\n\n") + "\n";
585
- }, He = (e, t = "postgres") => d.gen(function* () {
586
- let n = yield* p.SqlClient;
587
- yield* _e(n, Ge(n, A(e, t), t)).pipe(d.orDie);
588
- }), Ue = (e, t) => {
617
+ }, qe = (e, t, n = O) => {
618
+ let { sorted: r, cyclic: i } = Re(e), a = Be(i, t), o = [], s = He(r, t);
619
+ s && o.push(s);
620
+ let c = Ve(r, t);
621
+ 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* D(r, Ze(r, We(e, t, n), t)).pipe(p.orDie);
628
+ }), Ye = (e, t) => {
589
629
  let n = t.cause ?? {};
590
630
  return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
591
- }, We = (e) => d.gen(function* () {
592
- let t = yield* p.SqlClient;
593
- for (let n of Ke(e)) process.env.VOLTRO_MIGRATE_DEBUG === "1" && ve.debug(`EXEC: ${n.replace(/\s+/g, " ").slice(0, 180)}`), yield* t.unsafe(n).pipe(d.catchIf((e) => Ue(n, e), () => d.void), d.tapError((e) => d.sync(() => {
594
- ve.error(_("migrate: statement failed", n, e, 200));
595
- })), d.orDieWith((e) => Error(_("migrate: statement failed", n, e, 400).trim())));
596
- }), Ge = (e, t, n) => (n === "turso" ? We(t) : e.withTransaction(We(t))).pipe(d.orDie), Ke = (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) => {
597
637
  let t = [], n = "", r = !1;
598
638
  for (let i = 0; i < e.length; i++) {
599
639
  if (e.slice(i, i + 2) === "$$") {
@@ -608,40 +648,40 @@ BEGIN
608
648
  }
609
649
  let i = n.trim();
610
650
  return i.length > 0 && t.push(i), t;
611
- }, qe = async (e, t, n = "postgres") => {
612
- await d.runPromise(He(e, n).pipe(d.provide(t)));
613
- }, Je = (e, t, n = "postgres") => d.gen(function* () {
614
- let r = Be(e, n, t), i = yield* p.SqlClient;
615
- yield* _e(i, Ge(i, r, n)).pipe(d.orDie);
616
- }), Ye = async (e, t, n, r = "postgres") => {
617
- await d.runPromise(Je(e, t, r).pipe(d.provide(n)));
618
- }, Xe = async (e, t, n = "postgres") => {
619
- await d.runPromise(d.gen(function* () {
620
- let t = Ve(e, n), r = yield* p.SqlClient;
621
- yield* _e(r, Ge(r, t, n)).pipe(d.orDie);
622
- }).pipe(d.provide(t)));
623
- }, Ze = (e) => {
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* D(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* D(r, Ze(r, t, n)).pipe(p.orDie);
662
+ }).pipe(p.provide(t)));
663
+ }, rt = (e) => {
624
664
  if (e == null) return e;
625
- if (Array.isArray(e)) return e.map(Ze);
665
+ if (Array.isArray(e)) return e.map(rt);
626
666
  if (typeof e != "object") return e;
627
667
  let t = {};
628
668
  for (let n of Object.keys(e).sort()) {
629
669
  let r = e[n];
630
- r !== void 0 && (t[n] = Ze(r));
670
+ r !== void 0 && (t[n] = rt(r));
631
671
  }
632
672
  return t;
633
- }, Qe = (e) => {
673
+ }, it = (e) => {
634
674
  if (!e.idScheme && !e.sensitive && !e.safe) return e;
635
675
  let { idScheme: t, sensitive: n, safe: r, ...i } = e;
636
676
  return i;
637
- }, $e = (e) => [...e].map(Qe).sort((e, t) => e.name.localeCompare(t.name)), et = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), tt = (e) => [...e].map((e) => ({
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) => ({
638
678
  name: e.name,
639
- columns: $e(e.columns),
640
- indexes: et(e.indexes)
641
- })).sort((e, t) => e.name.localeCompare(t.name)), j = (e) => {
642
- let t = { tables: tt(e.tables) }, n = JSON.stringify(Ze(t));
643
- return m("sha256").update(n).digest("hex");
644
- }, M = (e) => e.slice(0, 16), nt = (e, t) => {
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) => {
645
685
  let n = t.references ? {
646
686
  table: t.references().tableName,
647
687
  column: "id",
@@ -680,7 +720,7 @@ BEGIN
680
720
  ...t.enumValues === void 0 ? {} : { enumValues: t.enumValues },
681
721
  ...t.spatial === void 0 ? {} : { spatial: t.spatial }
682
722
  };
683
- }, rt = (e) => {
723
+ }, lt = (e) => {
684
724
  let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
685
725
  n.has(e.name) || (n.add(e.name), t.push(e));
686
726
  }, i = e.appliedPrimaryKey ?? [];
@@ -720,7 +760,7 @@ BEGIN
720
760
  let i = n;
721
761
  if (i.dropped || !i.references || i.fkAutoIndex === !1 || s.has(t)) continue;
722
762
  let a = `${e.tableName}_${t}_idx`;
723
- c(e.tableName, a, !0, [t]), r({
763
+ l(e.tableName, a, !0, [t]), r({
724
764
  name: a,
725
765
  table: e.tableName,
726
766
  columns: [t],
@@ -728,11 +768,11 @@ BEGIN
728
768
  });
729
769
  }
730
770
  return t;
731
- }, it = (e) => {
771
+ }, ut = (e) => {
732
772
  let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
733
773
  for (let [r, i] of Object.entries(e.fields)) {
734
774
  if (i.dropped) continue;
735
- let e = nt(r, i);
775
+ let e = ct(r, i);
736
776
  n.push(t.has(r) ? {
737
777
  ...e,
738
778
  unique: !0
@@ -742,44 +782,44 @@ BEGIN
742
782
  return {
743
783
  name: e.tableName,
744
784
  columns: n,
745
- indexes: rt(e),
785
+ indexes: lt(e),
746
786
  ...r.length > 0 ? { primaryKey: [...r] } : {},
747
787
  ...i === void 0 ? {} : { renamedFrom: i }
748
788
  };
749
- }, at = (e) => {
789
+ }, dt = (e) => {
750
790
  let t = /* @__PURE__ */ new Map();
751
791
  for (let n of e) for (let e of n.indexes) {
752
792
  let r = t.get(e.name);
753
793
  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}').`);
754
794
  t.set(e.name, n.name);
755
795
  }
756
- }, N = (e, t) => {
757
- let n = e.map((e) => it(x(e, t)));
758
- return at(n), { tables: n };
759
- }, ot = "framework_changes_", st = (e, t) => d.gen(function* () {
760
- let n = t.filter((e) => !e.tableName.startsWith("_voltro_"));
761
- if (n.length === 0) return {
796
+ }, I = (e, t) => {
797
+ let n = e.map((e) => ut(te(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 {
762
802
  missing: [],
763
803
  stale: []
764
804
  };
765
- let r = yield* e`
805
+ let i = yield* e`
766
806
  SELECT t.tgname
767
807
  FROM pg_trigger t
768
808
  JOIN pg_class c ON c.oid = t.tgrelid
769
809
  JOIN pg_namespace n ON n.oid = c.relnamespace
770
810
  WHERE NOT t.tgisinternal
771
811
  AND n.nspname = current_schema()
772
- AND t.tgname LIKE ${`${ot}%`}
773
- `, i = new Set(r.map((e) => e.tgname)), a = [], o = [];
774
- for (let e of n) {
775
- let t = i.has(`${ot}${e.tableName}`), n = e.isReactive !== !1;
776
- n && !t && a.push(e.tableName), !n && t && o.push(e.tableName);
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);
777
817
  }
778
818
  return {
779
- missing: a.sort(),
780
- stale: o.sort()
819
+ missing: o.sort(),
820
+ stale: s.sort()
781
821
  };
782
- }), ct = (e) => {
822
+ }), pt = (e) => {
783
823
  let t = [];
784
824
  if (e.missing.length > 0) {
785
825
  let n = e.missing.slice(0, 8).join(", "), r = e.missing.length > 8 ? `, … (+${e.missing.length - 8})` : "";
@@ -790,19 +830,19 @@ BEGIN
790
830
  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.`);
791
831
  }
792
832
  return t.length > 0 ? t.join("\n") : void 0;
793
- }, lt = /* @__PURE__ */ new Set(["voltro_isr_cache"]), ut = (e) => lt.has(e) || e.startsWith("_voltro_") || e.startsWith("_cloud_") || e.startsWith("cluster_"), dt = /__dropped_\d{14}$/, ft = (e) => dt.test(e), pt = {
833
+ }, mt = {
794
834
  postgres: !0,
795
835
  mysql: !0,
796
836
  mariadb: !0,
797
837
  mssql: !0,
798
838
  sqlite: !0
799
- }, mt = {
839
+ }, ht = {
800
840
  postgres: !0,
801
841
  mysql: !1,
802
842
  mariadb: !1,
803
843
  mssql: !0,
804
844
  sqlite: !0
805
- }, ht = (e) => {
845
+ }, gt = (e) => {
806
846
  switch (e) {
807
847
  case "add-column":
808
848
  case "drop-column":
@@ -812,43 +852,43 @@ BEGIN
812
852
  case "add-foreign-key":
813
853
  case "add-unique":
814
854
  case "add-unique-composite":
815
- case "add-check": return mt;
816
- default: return pt;
855
+ case "add-check": return ht;
856
+ default: return mt;
817
857
  }
818
- }, gt = (e, t) => {
858
+ }, _t = (e, t) => {
819
859
  let n = new Map(t.tables.map((e) => [e.name, e]));
820
860
  return new Map(e.map((e) => [e.tableName, {
821
861
  table: e,
822
862
  snapshot: n.get(e.tableName),
823
863
  columnDefs: e.fields
824
864
  }]));
825
- }, P = (e) => {
865
+ }, L = (e) => {
826
866
  if (typeof e != "object" || !e) return JSON.stringify(e);
827
- if (Array.isArray(e)) return `[${e.map(P).join(",")}]`;
867
+ if (Array.isArray(e)) return `[${e.map(L).join(",")}]`;
828
868
  let t = e;
829
- return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${P(t[e])}`).join(",")}}`;
830
- }, _t = (e) => {
869
+ return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${L(t[e])}`).join(",")}}`;
870
+ }, vt = (e) => {
831
871
  if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
832
872
  let t = e.defaultValue;
833
873
  if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
834
874
  if (typeof t == "number") return String(t);
835
- if (typeof t != "string") return P(t);
875
+ if (typeof t != "string") return L(t);
836
876
  let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
837
877
  if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
838
878
  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);
839
879
  if (o) try {
840
- return P(JSON.parse(o[1]));
880
+ return L(JSON.parse(o[1]));
841
881
  } catch {}
842
882
  if (a.startsWith("{") || a.startsWith("[")) try {
843
- return P(JSON.parse(a));
883
+ return L(JSON.parse(a));
844
884
  } catch {}
845
885
  return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
846
- }, vt = (e, t) => {
847
- let n = _t(e), r = _t(t);
886
+ }, yt = (e, t) => {
887
+ let n = vt(e), r = vt(t);
848
888
  if (n === r) return !0;
849
889
  let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
850
890
  return i(n) === i(r);
851
- }, F = (e) => {
891
+ }, bt = (e) => {
852
892
  if (!e) return null;
853
893
  let t = (e) => e === "restrict" ? "noAction" : e;
854
894
  return {
@@ -857,25 +897,25 @@ BEGIN
857
897
  onDelete: t(e.onDelete),
858
898
  onUpdate: t(e.onUpdate)
859
899
  };
860
- }, yt = (e, t) => {
900
+ }, xt = (e, t) => {
861
901
  let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
862
902
  if (!n && !r) return !0;
863
903
  if (!n || !r || n.length !== r.length) return !1;
864
904
  let i = [...n].sort(), a = [...r].sort();
865
905
  return i.every((e, t) => e === a[t]);
866
- }, bt = (e, t) => {
906
+ }, St = (e, t) => {
867
907
  try {
868
- let n = /\((\d+)\)/.exec(E(e, t));
908
+ let n = /\((\d+)\)/.exec(j(e, t));
869
909
  return n ? Number(n[1]) : void 0;
870
910
  } catch {
871
911
  return;
872
912
  }
873
- }, xt = (e, t, n) => n === void 0 || u(n) ? !0 : e.type !== "text" || t.type !== "text" || bt(e, n) === t.maxLength, St = (e, t, n) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && vt(e, t) && xt(e, t, n) && JSON.stringify(F(e.references)) === JSON.stringify(F(t.references)) && yt(e.oneOf, t.oneOf), Ct = (e, t) => t.oneOf && t.oneOf.length > 0 ? I({
913
+ }, Ct = (t, n, r) => r === void 0 || e(r) ? !0 : t.type !== "text" || n.type !== "text" || St(t, 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({
874
914
  kind: "add-check",
875
915
  table: e,
876
916
  column: t.name,
877
917
  values: t.oneOf
878
- }, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, wt = (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])), Tt = (e, t, n) => {
918
+ }, "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) => {
879
919
  let r = new Map(t.columns.map((e) => [e.name, e])), i = new Map(e.columns.map((e) => [e.name, e])), a = [], o = [], s = [];
880
920
  for (let t of e.columns) {
881
921
  let e = r.get(t.name);
@@ -883,7 +923,7 @@ BEGIN
883
923
  a.push(t);
884
924
  continue;
885
925
  }
886
- St(t, e, n) || s.push({
926
+ wt(t, e, n) || s.push({
887
927
  declared: t,
888
928
  live: e
889
929
  });
@@ -894,47 +934,47 @@ BEGIN
894
934
  removed: o,
895
935
  changed: s
896
936
  };
897
- }, Et = (e, t) => {
937
+ }, Ot = (e, t) => {
898
938
  let n = new Map(t.indexes.map((e) => [e.name, e])), r = new Map(e.indexes.map((e) => [e.name, e])), i = [], a = [];
899
939
  for (let t of e.indexes) {
900
940
  let e = n.get(t.name);
901
- (!e || !wt(t, e)) && i.push(t);
941
+ (!e || !Et(t, e)) && i.push(t);
902
942
  }
903
943
  for (let e of t.indexes) r.has(e.name) || a.push(e);
904
944
  return {
905
945
  added: i,
906
946
  removed: a
907
947
  };
908
- }, I = (e, t, n, r) => ({
948
+ }, R = (e, t, n, r) => ({
909
949
  op: e,
910
950
  classification: t,
911
- atomicByDialect: ht(e.kind),
951
+ atomicByDialect: gt(e.kind),
912
952
  ...n ? { reason: n } : {},
913
953
  ...r ? { blocked: r } : {}
914
- }), Dt = (e, t, n) => {
954
+ }), kt = (e, t, n) => {
915
955
  let r = {
916
956
  kind: "add-column",
917
957
  table: e,
918
958
  column: t
919
959
  };
920
- return t.nullable ? I(r, "safe", "nullable column add — no backfill needed") : t.hasDefault && t.defaultValue !== void 0 ? I(r, "needs-default", "NOT NULL with literal default — DDL DEFAULT will populate existing rows") : n?.backfill ? I(r, "needs-backfill", `backfill declared (kind=${n.backfill.kind}) — applier will run 3-step add/update/set-not-null`) : I(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` });
921
- }, Ot = (e, t, n) => {
960
+ 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` });
961
+ }, At = (e, t, n) => {
922
962
  let r = {
923
963
  kind: "drop-column",
924
964
  table: e,
925
965
  column: t.name
926
966
  };
927
- return n?.dropped ? I(r, "lossy", `column dropped via \`${t.name}: dropped()\` marker — intentional`) : I(r, "lossy", "column missing from declared schema", { fix: `if intentional, add \`${t.name}: dropped()\` to the schema. If a typo, restore the field` });
928
- }, kt = (e, t, n, r, i) => I({
967
+ 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` });
968
+ }, jt = (e, t, n, r, i) => R({
929
969
  kind: "create-table",
930
970
  table: e,
931
971
  columns: t,
932
972
  indexes: n,
933
973
  ...r && r.length > 0 ? { primaryKey: r } : {}
934
- }, "safe", i ?? "new table — no data to preserve"), At = (e) => I({
974
+ }, "safe", i ?? "new table — no data to preserve"), Mt = (e) => R({
935
975
  kind: "drop-table",
936
976
  table: e
937
- }, "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" }), jt = 5e4, Mt = (e, t, n, r) => {
977
+ }, "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) => {
938
978
  let i = (n ?? 0) >= r, a;
939
979
  return a = t.unique ? t.columns.length === 1 ? {
940
980
  kind: "add-unique",
@@ -949,16 +989,16 @@ BEGIN
949
989
  kind: "add-index",
950
990
  table: e,
951
991
  index: t
952
- }, i ? I(a, "online-required", `online build on ${n} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : I(a, "safe", t.unique ? t.columns.length === 1 ? "add unique constraint" : "add composite UNIQUE constraint" : "add B-tree index");
953
- }, Nt = (e, t) => t.unique && t.columns.length > 1 ? I({
992
+ }, 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");
993
+ }, Ft = (e, t) => t.unique && t.columns.length > 1 ? R({
954
994
  kind: "drop-unique-composite",
955
995
  table: e,
956
996
  name: t.name
957
- }, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : I({
997
+ }, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : R({
958
998
  kind: "drop-index",
959
999
  table: e,
960
1000
  index: t.name
961
- }, "safe", "drop index (no data loss — index is derived data)"), Pt = (e, t) => {
1001
+ }, "safe", "drop index (no data loss — index is derived data)"), It = (e, t) => {
962
1002
  if (e === "reference") return "text";
963
1003
  switch (t) {
964
1004
  case "sqlite":
@@ -966,106 +1006,106 @@ BEGIN
966
1006
  case "mssql": return e === "json" ? "text" : e;
967
1007
  default: return e;
968
1008
  }
969
- }, Ft = (e, t, n, r, i, a) => {
970
- let o = [];
971
- if (t.nullable !== n.nullable) {
972
- let n = {
1009
+ }, Lt = (t, n, r, i, a, o) => {
1010
+ let s = [];
1011
+ if (n.nullable !== r.nullable) {
1012
+ let e = {
973
1013
  kind: "alter-column-nullability",
974
- table: e,
975
- column: t.name,
976
- toNullable: t.nullable
1014
+ table: t,
1015
+ column: n.name,
1016
+ toNullable: n.nullable
977
1017
  };
978
- o.push(t.nullable ? I(n, "safe", `loosen ${e}.${t.name} to nullable`) : I(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
1018
+ s.push(n.nullable ? R(e, "safe", `loosen ${t}.${n.name} to nullable`) : R(e, "needs-backfill", `tighten ${t}.${n.name} to NOT NULL — existing rows must already be non-null`));
979
1019
  }
980
- if (t.unique !== n.unique) if (t.unique) {
981
- let n = {
1020
+ if (n.unique !== r.unique) if (n.unique) {
1021
+ let e = {
982
1022
  kind: "add-unique",
983
- table: e,
984
- column: t.name
985
- }, r = (i ?? 0) >= a;
986
- o.push(r ? I(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : I(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
987
- } else o.push(I({
1023
+ table: t,
1024
+ column: n.name
1025
+ }, r = (a ?? 0) >= o;
1026
+ s.push(r ? R(e, "online-required", `online unique build on ${a} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : R(e, "safe", `add unique constraint on ${t}.${n.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
1027
+ } else s.push(R({
988
1028
  kind: "drop-unique",
989
- table: e,
990
- column: t.name
991
- }, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
992
- if (Pt(t.type, r) !== Pt(n.type, r)) {
993
- let r = t.narrowedFrom;
994
- if (r && r.from === n.type) {
1029
+ table: t,
1030
+ column: n.name
1031
+ }, "safe", `drop unique constraint on ${t}.${n.name} — constraint is derived metadata, no data loss`));
1032
+ if (It(n.type, i) !== It(r.type, i)) {
1033
+ let e = n.narrowedFrom;
1034
+ if (e && e.from === r.type) {
995
1035
  let i = {
996
1036
  kind: "alter-column-type",
997
- table: e,
998
- column: t.name,
999
- from: n.type,
1000
- to: t.type,
1001
- ...r.using === void 0 ? {} : { using: r.using }
1037
+ table: t,
1038
+ column: n.name,
1039
+ from: r.type,
1040
+ to: n.type,
1041
+ ...e.using === void 0 ? {} : { using: e.using }
1002
1042
  };
1003
- o.push(I(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)")));
1043
+ s.push(R(i, "needs-backfill", `type change ${r.type} → ${n.type} on ${t}.${n.name} — narrowedFrom('${e.from}') declared` + (e.using ? ` with USING ${e.using}` : " (implicit cast)")));
1004
1044
  } else {
1005
- let r = {
1045
+ let e = {
1006
1046
  kind: "alter-column-type",
1007
- table: e,
1008
- column: t.name,
1009
- from: n.type,
1010
- to: t.type
1047
+ table: t,
1048
+ column: n.name,
1049
+ from: r.type,
1050
+ to: n.type
1011
1051
  };
1012
- o.push(I(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` }));
1052
+ s.push(R(e, "lossy", `type change ${r.type} → ${n.type} on ${t}.${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` }));
1013
1053
  }
1014
1054
  }
1015
- if (t.type === "text" && n.type === "text" && !u(r ?? "postgres") && t.maxLength !== n.maxLength) {
1016
- 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})`;
1017
- o.push(I({
1055
+ if (n.type === "text" && r.type === "text" && !e(i ?? "postgres") && n.maxLength !== r.maxLength) {
1056
+ let e = 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})`;
1057
+ s.push(R({
1018
1058
  kind: "alter-column-type",
1019
- table: e,
1020
- column: t.name,
1059
+ table: t,
1060
+ column: n.name,
1021
1061
  from: "text",
1022
1062
  to: "text"
1023
- }, 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)}`));
1063
+ }, e ? "safe" : "needs-backfill", e ? `text length ${i} → ${a} on ${t}.${n.name} — widening, no data can be lost` : `text length ${i} → ${a} on ${t}.${n.name} — NARROWING; the ALTER fails if any existing value is longer than ${String(n.maxLength)}. Check first: SELECT COUNT(*) FROM ${t} WHERE LENGTH(${n.name}) > ${String(n.maxLength)}`));
1024
1064
  }
1025
- if (!vt(t, n)) {
1026
- let n = {
1065
+ if (!yt(n, r)) {
1066
+ let e = {
1027
1067
  kind: "alter-column-default",
1028
- table: e,
1029
- column: t.name,
1030
- hasDefault: t.hasDefault,
1031
- ...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
1068
+ table: t,
1069
+ column: n.name,
1070
+ hasDefault: n.hasDefault,
1071
+ ...n.defaultValue === void 0 ? {} : { defaultValue: n.defaultValue }
1032
1072
  };
1033
- o.push(I(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
1073
+ s.push(R(e, "safe", `default change on ${t}.${n.name} affects only future inserts`));
1034
1074
  }
1035
- if (!yt(t.oneOf, n.oneOf)) {
1036
- n.oneOf && n.oneOf.length > 0 && o.push(I({
1075
+ if (!xt(n.oneOf, r.oneOf)) {
1076
+ r.oneOf && r.oneOf.length > 0 && s.push(R({
1037
1077
  kind: "drop-check",
1038
- table: e,
1039
- column: t.name
1040
- }, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
1041
- let r = Ct(e, t);
1042
- r && o.push(r);
1078
+ table: t,
1079
+ column: n.name
1080
+ }, "safe", `drop stale enum CHECK on ${t}.${n.name}`));
1081
+ let e = Tt(t, n);
1082
+ e && s.push(e);
1043
1083
  }
1044
- if (JSON.stringify(F(t.references)) !== JSON.stringify(F(n.references)) && (n.references && o.push(I({
1084
+ if (JSON.stringify(bt(n.references)) !== JSON.stringify(bt(r.references)) && (r.references && s.push(R({
1045
1085
  kind: "drop-foreign-key",
1046
- table: e,
1047
- column: t.name
1048
- }, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), t.references)) {
1049
- let n = t.references.table, r = t.references.orphanPolicy ?? "fail", i = {
1086
+ table: t,
1087
+ column: n.name
1088
+ }, "safe", `drop FK on ${t}.${n.name} (→ ${r.references.table})`)), n.references)) {
1089
+ let e = n.references.table, r = n.references.orphanPolicy ?? "fail", i = {
1050
1090
  kind: "add-foreign-key",
1051
- table: e,
1052
- column: t.name,
1053
- targetTable: n,
1054
- targetColumn: t.references.column,
1055
- ...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
1056
- ...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
1091
+ table: t,
1092
+ column: n.name,
1093
+ targetTable: e,
1094
+ targetColumn: n.references.column,
1095
+ ...n.references.onDelete ? { onDelete: n.references.onDelete } : {},
1096
+ ...n.references.onUpdate ? { onUpdate: n.references.onUpdate } : {}
1057
1097
  };
1058
- r === "null" && !t.nullable ? o.push(I(i, "lossy", `add FK ${e}.${t.name} → ${n}: 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` })) : r === "null" || r === "delete" ? o.push(I({
1098
+ r === "null" && !n.nullable ? s.push(R(i, "lossy", `add FK ${t}.${n.name} → ${e}: orphanPolicy 'null' needs a nullable column (the NULL-out would violate NOT NULL)`, { fix: `make ${n.name} \`.nullable()\`, OR use \`orphanPolicy: 'delete'\`, OR clean the orphans and drop the policy` })) : r === "null" || r === "delete" ? s.push(R({
1059
1099
  ...i,
1060
1100
  orphanPolicy: r
1061
- }, "lossy", r === "delete" ? `add FK ${e}.${t.name} → ${n}: orphanPolicy 'delete' first DELETES rows whose ${t.name} points at a missing ${n}` : `add FK ${e}.${t.name} → ${n}: orphanPolicy 'null' first NULLs ${t.name} where it points at a missing ${n}`)) : o.push(I(i, "needs-backfill", `add FK ${e}.${t.name} → ${n} — existing rows must already reference a valid ${n} (else set orphanPolicy:'null'/'delete')`));
1101
+ }, "lossy", r === "delete" ? `add FK ${t}.${n.name} → ${e}: orphanPolicy 'delete' first DELETES rows whose ${n.name} points at a missing ${e}` : `add FK ${t}.${n.name} → ${e}: orphanPolicy 'null' first NULLs ${n.name} where it points at a missing ${e}`)) : s.push(R(i, "needs-backfill", `add FK ${t}.${n.name} → ${e} — existing rows must already reference a valid ${e} (else set orphanPolicy:'null'/'delete')`));
1062
1102
  }
1063
- return o;
1064
- }, It = (e, t, n) => {
1103
+ return s;
1104
+ }, Rt = (e, t, n) => {
1065
1105
  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));
1066
1106
  for (let [n, c] of Object.entries(t)) {
1067
1107
  let t = c.renamedFrom;
1068
- t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(I({
1108
+ t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(R({
1069
1109
  kind: "rename-column",
1070
1110
  table: e.tableName,
1071
1111
  from: t,
@@ -1077,26 +1117,26 @@ BEGIN
1077
1117
  consumedAddedNames: i,
1078
1118
  consumedRemovedNames: a
1079
1119
  };
1080
- }, Lt = /* @__PURE__ */ new Set([
1120
+ }, zt = /* @__PURE__ */ new Set([
1081
1121
  "postgres",
1082
1122
  "mysql",
1083
1123
  "mariadb",
1084
1124
  "mssql"
1085
- ]), Rt = {
1125
+ ]), Bt = {
1086
1126
  ops: [],
1087
1127
  consumedAddedNames: /* @__PURE__ */ new Set(),
1088
1128
  consumedRemovedNames: /* @__PURE__ */ new Set()
1089
- }, zt = (e) => !e.unique && !e.expression, Bt = (e, t, n, r, i) => {
1090
- if (i === void 0 || !Lt.has(i)) return Rt;
1091
- let a = t.added.filter((e) => zt(e) && !r.has(e.name));
1092
- if (a.length === 0) return Rt;
1129
+ }, Vt = (e) => !e.unique && !e.expression, Ht = (e, t, n, r, i) => {
1130
+ if (i === void 0 || !zt.has(i)) return Bt;
1131
+ let a = t.added.filter((e) => Vt(e) && !r.has(e.name));
1132
+ if (a.length === 0) return Bt;
1093
1133
  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();
1094
1134
  for (let n of t.removed) {
1095
- if (!zt(n)) continue;
1135
+ if (!Vt(n)) continue;
1096
1136
  let t = o(n), r = a.filter((e) => !l.has(e.name) && s(e) === t);
1097
1137
  if (r.length !== 1) continue;
1098
1138
  let i = r[0];
1099
- i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(I({
1139
+ i.name !== n.name && (l.add(i.name), u.add(n.name), c.push(R({
1100
1140
  kind: "rename-index",
1101
1141
  table: e,
1102
1142
  from: n.name,
@@ -1108,33 +1148,33 @@ BEGIN
1108
1148
  consumedAddedNames: l,
1109
1149
  consumedRemovedNames: u
1110
1150
  };
1111
- }, Vt = (e, t, n) => {
1151
+ }, Ut = (e, t, n) => {
1112
1152
  let r = [], i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Set();
1113
1153
  for (let t of e.tables) t.renamedFrom !== void 0 && (s.set(t.renamedFrom, (s.get(t.renamedFrom) ?? 0) + 1), c.add(t.renamedFrom));
1114
1154
  for (let c of e.tables) {
1115
1155
  let e = c.renamedFrom;
1116
1156
  if (e !== void 0 && e !== c.name && t.has(e)) {
1157
+ if (n.has(e)) {
1158
+ o.set(c.name, `.renamedFrom('${e}') NOT applied — '${e}' is still declared by this schema, so it belongs to that declaration. This table is created empty; that is the intended outcome when an app owns a table of the same name.`);
1159
+ continue;
1160
+ }
1117
1161
  if (t.has(c.name)) {
1118
- r.push(I({
1162
+ r.push(R({
1119
1163
  kind: "rename-table",
1120
1164
  from: e,
1121
1165
  to: c.name
1122
1166
  }, "needs-rename-annotation", `.renamedFrom('${e}') cannot be applied — both '${e}' and '${c.name}' exist in the database`, { fix: `decide which holds the real rows: move them into '${c.name}' and drop '${e}', or drop the empty '${c.name}' so the rename can run. '${e}' is left untouched until you do.` }));
1123
1167
  continue;
1124
1168
  }
1125
- if (n.has(e)) {
1126
- o.set(c.name, `.renamedFrom('${e}') NOT applied — '${e}' is still declared by this schema, so it belongs to that declaration. This table is created empty; that is the intended outcome when an app owns a table of the same name.`);
1127
- continue;
1128
- }
1129
1169
  if ((s.get(e) ?? 0) !== 1) {
1130
- r.push(I({
1170
+ r.push(R({
1131
1171
  kind: "rename-table",
1132
1172
  from: e,
1133
1173
  to: c.name
1134
1174
  }, "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.` }));
1135
1175
  continue;
1136
1176
  }
1137
- i.set(c.name, e), a.add(e), r.push(I({
1177
+ i.set(c.name, e), a.add(e), r.push(R({
1138
1178
  kind: "rename-table",
1139
1179
  from: e,
1140
1180
  to: c.name
@@ -1148,19 +1188,19 @@ BEGIN
1148
1188
  claimedOldNames: c,
1149
1189
  refusals: o
1150
1190
  };
1151
- }, Ht = (e, t, n, r) => {
1191
+ }, Wt = (e, t, n, r) => {
1152
1192
  if (t === void 0) return {
1153
1193
  live: e,
1154
1194
  ops: []
1155
1195
  };
1156
- let i = r !== void 0 && Lt.has(r), a = [], o = e.indexes.map((e) => {
1196
+ let i = r !== void 0 && zt.has(r), a = [], o = e.indexes.map((e) => {
1157
1197
  if (!e.name.startsWith(t)) return e;
1158
1198
  let r = `${n}${e.name.slice(t.length)}`;
1159
1199
  return r === e.name ? e : e.name === `${t}_pkey` ? {
1160
1200
  ...e,
1161
1201
  name: r,
1162
1202
  table: n
1163
- } : i ? (a.push(I({
1203
+ } : i ? (a.push(R({
1164
1204
  kind: "rename-index",
1165
1205
  table: n,
1166
1206
  from: e.name,
@@ -1179,7 +1219,7 @@ BEGIN
1179
1219
  },
1180
1220
  ops: a
1181
1221
  };
1182
- }, Ut = (e) => {
1222
+ }, Gt = (e) => {
1183
1223
  let t = {
1184
1224
  safe: 0,
1185
1225
  needsDefault: 0,
@@ -1214,51 +1254,51 @@ BEGIN
1214
1254
  break;
1215
1255
  }
1216
1256
  return t;
1217
- }, Wt = (e) => {
1218
- let t = N(e.declared, e.dialect), n = gt(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? jt, a = [], o = Vt(t, r, n);
1257
+ }, Kt = (e) => {
1258
+ 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 = Ut(t, r, n);
1219
1259
  a.push(...o.ops);
1220
1260
  for (let e of t.tables) if (!o.renamedInto.has(e.name) && !r.has(e.name)) {
1221
- a.push(kt(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
1261
+ a.push(jt(e.name, e.columns, e.indexes, e.primaryKey, o.refusals.get(e.name)));
1222
1262
  for (let t of e.columns) {
1223
- let n = Ct(e.name, t);
1263
+ let n = Tt(e.name, t);
1224
1264
  n && a.push(n);
1225
1265
  }
1226
1266
  }
1227
- let s = new Set(e.ignoreTables ?? []);
1228
- for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || ut(t.name) || ft(t.name) || s.has(t.name) || a.push(At(t.name));
1267
+ let c = new Set(e.ignoreTables ?? []);
1268
+ for (let t of e.live.tables) n.has(t.name) || o.claimedOldNames.has(t.name) || s(t.name) || d(t.name) || c.has(t.name) || a.push(Mt(t.name));
1229
1269
  for (let s of t.tables) {
1230
1270
  let t = o.renamedInto.get(s.name), c = r.get(s.name) ?? (t === void 0 ? void 0 : r.get(t));
1231
1271
  if (!c) continue;
1232
- let l = Ht(c, t, s.name, e.dialect);
1272
+ let l = Wt(c, t, s.name, e.dialect);
1233
1273
  a.push(...l.ops);
1234
- let u = l.live, d = n.get(s.name), f = Tt(s, u, e.dialect), p = Et(s, u), m = It(d.table, d.columnDefs, f);
1235
- a.push(...m.ops);
1236
- for (let e of f.removed) {
1237
- if (m.consumedRemovedNames.has(e.name) || ft(e.name)) continue;
1238
- let t = d.columnDefs[e.name];
1239
- a.push(Ot(s.name, e, t));
1274
+ let u = l.live, f = n.get(s.name), p = Dt(s, u, e.dialect), m = Ot(s, u), h = Rt(f.table, f.columnDefs, p);
1275
+ a.push(...h.ops);
1276
+ for (let e of p.removed) {
1277
+ if (h.consumedRemovedNames.has(e.name) || d(e.name)) continue;
1278
+ let t = f.columnDefs[e.name];
1279
+ a.push(At(s.name, e, t));
1240
1280
  }
1241
- for (let e of f.added) {
1242
- if (m.consumedAddedNames.has(e.name)) continue;
1243
- let t = d.columnDefs[e.name];
1244
- a.push(Dt(s.name, e, t));
1245
- let n = Ct(s.name, e);
1281
+ for (let e of p.added) {
1282
+ if (h.consumedAddedNames.has(e.name)) continue;
1283
+ let t = f.columnDefs[e.name];
1284
+ a.push(kt(s.name, e, t));
1285
+ let n = Tt(s.name, e);
1246
1286
  n && a.push(n);
1247
1287
  }
1248
- let h = new Map(m.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), g = Bt(s.name, p, h, new Set(u.indexes.map((e) => e.name)), e.dialect);
1249
- a.push(...g.ops);
1250
- for (let e of p.added) g.consumedAddedNames.has(e.name) || a.push(Mt(s.name, e, u.rowCount, i));
1251
- for (let e of p.removed) g.consumedRemovedNames.has(e.name) || a.push(Nt(s.name, e));
1252
- for (let { declared: t, live: n } of f.changed) a.push(...Ft(s.name, t, n, e.dialect, u.rowCount, i));
1253
- }
1254
- 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) => {
1255
- let t = l.get(e);
1256
- return t ? t.columns.flatMap((e) => e.references && c.has(e.references.table) ? [{
1288
+ let g = new Map(h.ops.flatMap((e) => e.op.kind === "rename-column" ? [[e.op.from, e.op.to]] : [])), _ = Ht(s.name, m, g, new Set(u.indexes.map((e) => e.name)), e.dialect);
1289
+ a.push(..._.ops);
1290
+ for (let e of m.added) _.consumedAddedNames.has(e.name) || a.push(Pt(s.name, e, u.rowCount, i));
1291
+ for (let e of m.removed) _.consumedRemovedNames.has(e.name) || a.push(Ft(s.name, e));
1292
+ for (let { declared: t, live: n } of p.changed) a.push(...Lt(s.name, t, n, e.dialect, u.rowCount, i));
1293
+ }
1294
+ let l = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), u = new Map(t.tables.map((e) => [e.name, e])), f = (e) => {
1295
+ let t = u.get(e);
1296
+ return t ? t.columns.flatMap((e) => e.references && l.has(e.references.table) ? [{
1257
1297
  column: e.name,
1258
1298
  target: e.references.table
1259
1299
  }] : []) : [];
1260
- }, d = ne([...c], u), f = [];
1261
- for (let e of t.tables) if (c.has(e.name)) for (let t of e.columns) !t.references || !d.has(S(e.name, t.name)) || f.push(I({
1300
+ }, p = ne([...l], f), m = [];
1301
+ for (let e of t.tables) if (l.has(e.name)) for (let t of e.columns) !t.references || !p.has(w(e.name, t.name)) || m.push(R({
1262
1302
  kind: "add-foreign-key",
1263
1303
  table: e.name,
1264
1304
  column: t.name,
@@ -1267,14 +1307,14 @@ BEGIN
1267
1307
  ...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
1268
1308
  ...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
1269
1309
  }, "safe", `deferred FK ${e.name}.${t.name} → ${t.references.table} — breaks a create-time table cycle`));
1270
- if (d.size > 0) {
1310
+ if (p.size > 0) {
1271
1311
  let e = (e) => e.references ? Object.fromEntries(Object.entries(e).filter(([e]) => e !== "references")) : e;
1272
1312
  for (let t = 0; t < a.length; t += 1) {
1273
1313
  let n = a[t];
1274
1314
  if (n.op.kind !== "create-table") continue;
1275
1315
  let r = n.op;
1276
- if (!r.columns.some((e) => d.has(S(r.table, e.name)))) continue;
1277
- let i = r.columns.map((t) => d.has(S(r.table, t.name)) ? e(t) : t);
1316
+ if (!r.columns.some((e) => p.has(w(r.table, e.name)))) continue;
1317
+ let i = r.columns.map((t) => p.has(w(r.table, t.name)) ? e(t) : t);
1278
1318
  a[t] = {
1279
1319
  ...n,
1280
1320
  op: {
@@ -1283,24 +1323,24 @@ BEGIN
1283
1323
  }
1284
1324
  };
1285
1325
  }
1286
- a.push(...f);
1326
+ a.push(...m);
1287
1327
  }
1288
- let p = new Map(t.tables.map((e) => [e.name, e])), m = /* @__PURE__ */ new Map(), h = (e, t = /* @__PURE__ */ new Set()) => {
1289
- let n = m.get(e);
1328
+ let h = new Map(t.tables.map((e) => [e.name, e])), g = /* @__PURE__ */ new Map(), _ = (e, t = /* @__PURE__ */ new Set()) => {
1329
+ let n = g.get(e);
1290
1330
  if (n !== void 0) return n;
1291
1331
  if (t.has(e)) return 0;
1292
- let r = p.get(e);
1332
+ let r = h.get(e);
1293
1333
  if (!r) return 0;
1294
1334
  let i = new Set(t).add(e), a = 0;
1295
1335
  for (let t of r.columns) {
1296
1336
  let n = t.references?.table;
1297
- n && n !== e && !d.has(S(e, t.name)) && (a = Math.max(a, h(n, i) + 1));
1337
+ n && n !== e && !p.has(w(e, t.name)) && (a = Math.max(a, _(n, i) + 1));
1298
1338
  }
1299
- return m.set(e, a), a;
1300
- }, g = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, ee = (e) => {
1339
+ return g.set(e, a), a;
1340
+ }, v = (e) => e === "rename-table" ? -1 : e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, y = (e) => {
1301
1341
  let t = "table" in e ? e.table : "";
1302
- return e.kind === "create-table" ? h(t) : e.kind === "drop-table" ? -h(t) : 0;
1303
- }, _ = {
1342
+ return e.kind === "create-table" ? _(t) : e.kind === "drop-table" ? -_(t) : 0;
1343
+ }, b = {
1304
1344
  "add-column": 0,
1305
1345
  "rename-column": 1,
1306
1346
  "rename-index": 1,
@@ -1318,23 +1358,23 @@ BEGIN
1318
1358
  "add-unique-composite": 5,
1319
1359
  "add-foreign-key": 5,
1320
1360
  "add-check": 5
1321
- }, v = (e) => _[e] ?? 9, y = [...a].sort((e, t) => {
1322
- let n = g(e.op.kind), r = g(t.op.kind);
1361
+ }, x = (e) => b[e] ?? 9, S = [...a].sort((e, t) => {
1362
+ let n = v(e.op.kind), r = v(t.op.kind);
1323
1363
  if (n !== r) return n - r;
1324
- let i = ee(e.op), a = ee(t.op);
1364
+ let i = y(e.op), a = y(t.op);
1325
1365
  if (i !== a) return i - a;
1326
1366
  let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
1327
1367
  if (o !== s) return o.localeCompare(s);
1328
- let c = v(e.op.kind), l = v(t.op.kind);
1368
+ let c = x(e.op.kind), l = x(t.op.kind);
1329
1369
  return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
1330
1370
  });
1331
1371
  return {
1332
- operations: y,
1333
- fromFingerprint: j(e.live),
1334
- toFingerprint: j(t),
1335
- summary: Ut(y)
1372
+ operations: S,
1373
+ fromFingerprint: P(e.live),
1374
+ toFingerprint: P(t),
1375
+ summary: Gt(S)
1336
1376
  };
1337
- }, Gt = (e) => {
1377
+ }, qt = (e) => {
1338
1378
  let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
1339
1379
  if (!t) return null;
1340
1380
  let n = [...e.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
@@ -1342,7 +1382,7 @@ BEGIN
1342
1382
  column: t[1],
1343
1383
  values: n
1344
1384
  };
1345
- }, Kt = (e, t) => {
1385
+ }, Jt = (e, t) => {
1346
1386
  if (t === "vector") return "vector";
1347
1387
  switch (e) {
1348
1388
  case "text":
@@ -1369,7 +1409,7 @@ BEGIN
1369
1409
  case "USER-DEFINED": return "text";
1370
1410
  default: return "text";
1371
1411
  }
1372
- }, L = (e) => {
1412
+ }, z = (e) => {
1373
1413
  switch (e.toUpperCase()) {
1374
1414
  case "CASCADE": return "cascade";
1375
1415
  case "RESTRICT": return "restrict";
@@ -1377,25 +1417,25 @@ BEGIN
1377
1417
  case "SET DEFAULT": return "noAction";
1378
1418
  default: return "noAction";
1379
1419
  }
1380
- }, qt = (e, t) => {
1420
+ }, Yt = (e, t) => {
1381
1421
  let n = e !== void 0 && e !== "" ? Number(e) : NaN;
1382
1422
  return Number.isInteger(n) && n > 0 ? n : t;
1383
- }, Jt = () => qt(process.env.VOLTRO_INTROSPECT_BATCH, 20), Yt = 300, Xt = () => {
1423
+ }, Xt = () => Yt(process.env.VOLTRO_INTROSPECT_BATCH, 20), Zt = 300, Qt = () => {
1384
1424
  let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
1385
- return e !== void 0 && e.trim() === "0" ? 0 : qt(e, 3e4);
1386
- }, Zt = (e, t) => {
1425
+ return e !== void 0 && e.trim() === "0" ? 0 : Yt(e, 3e4);
1426
+ }, $t = (e, t) => {
1387
1427
  let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
1388
1428
  for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
1389
1429
  return r;
1390
- }, Qt = (e) => {
1391
- let t = Xt(), n = d.gen(function* () {
1430
+ }, en = (e) => {
1431
+ let t = Qt(), n = p.gen(function* () {
1392
1432
  t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
1393
- let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Jt(), a = (e, t) => d.gen(function* () {
1433
+ let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Xt(), a = (e, t) => p.gen(function* () {
1394
1434
  let r = [];
1395
- for (let a of Zt(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
1435
+ for (let a of $t(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
1396
1436
  return r;
1397
1437
  }), o = [];
1398
- for (let t = 0;; t += Yt) {
1438
+ for (let t = 0;; t += Zt) {
1399
1439
  let n = yield* e`
1400
1440
  SELECT c.relname AS table_name,
1401
1441
  COALESCE(c.reltuples::bigint, 0) AS row_count
@@ -1403,9 +1443,9 @@ BEGIN
1403
1443
  JOIN pg_namespace n ON n.oid = c.relnamespace
1404
1444
  WHERE n.nspname = current_schema() AND c.relkind = 'r'
1405
1445
  ORDER BY c.relname
1406
- LIMIT ${r(Yt)} OFFSET ${r(t)}
1446
+ LIMIT ${r(Zt)} OFFSET ${r(t)}
1407
1447
  `;
1408
- if (o.push(...n), n.length < Yt) break;
1448
+ if (o.push(...n), n.length < Zt) break;
1409
1449
  }
1410
1450
  let s = /* @__PURE__ */ new Set(), c = [];
1411
1451
  for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
@@ -1415,7 +1455,7 @@ BEGIN
1415
1455
  FROM information_schema.columns
1416
1456
  WHERE table_schema = current_schema() AND table_name IN ${t}
1417
1457
  ORDER BY table_name, ordinal_position
1418
- `), f = yield* a(l, (t) => e`
1458
+ `), d = yield* a(l, (t) => e`
1419
1459
  SELECT rel.relname AS table_name, att.attname AS column_name
1420
1460
  FROM pg_constraint con
1421
1461
  JOIN pg_class rel ON rel.oid = con.conrelid
@@ -1424,7 +1464,7 @@ BEGIN
1424
1464
  WHERE con.contype = 'p' AND nsp.nspname = current_schema()
1425
1465
  AND rel.relname IN ${t}
1426
1466
  ORDER BY rel.relname, array_position(con.conkey, att.attnum)
1427
- `), p = yield* a(l, (t) => e`
1467
+ `), f = yield* a(l, (t) => e`
1428
1468
  SELECT rel.relname AS table_name, con.conname AS constraint_name,
1429
1469
  att.attname AS column_name, array_position(con.conkey, att.attnum) AS position
1430
1470
  FROM pg_constraint con
@@ -1470,7 +1510,7 @@ BEGIN
1470
1510
  WHERE con.contype = 'f' AND nsp.nspname = current_schema()
1471
1511
  AND rel.relname IN ${t}
1472
1512
  ORDER BY rel.relname, con.conname, ck.ord
1473
- `), ee = yield* a(l, (t) => e`
1513
+ `), _ = yield* a(l, (t) => e`
1474
1514
  WITH ix AS (
1475
1515
  SELECT
1476
1516
  c.relname AS table_name,
@@ -1491,34 +1531,34 @@ BEGIN
1491
1531
  AND c.relname IN ${t}
1492
1532
  )
1493
1533
  SELECT * FROM ix ORDER BY table_name, index_name, position
1494
- `), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), te = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map();
1534
+ `), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map(), ee = /* @__PURE__ */ new Map();
1495
1535
  for (let e of u) {
1496
- let t = _.get(e.table_name);
1497
- t || (t = [], _.set(e.table_name, t)), t.push(e);
1498
- }
1499
- for (let e of f) {
1500
1536
  let t = v.get(e.table_name);
1501
- t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
1537
+ t || (t = [], v.set(e.table_name, t)), t.push(e);
1538
+ }
1539
+ for (let e of d) {
1540
+ let t = y.get(e.table_name);
1541
+ t || (t = /* @__PURE__ */ new Set(), y.set(e.table_name, t)), t.add(e.column_name);
1502
1542
  }
1503
- let S = /* @__PURE__ */ new Map();
1504
- for (let e of p) {
1505
- let t = `${e.table_name}\u0000${e.constraint_name}`, n = S.get(t);
1543
+ let C = /* @__PURE__ */ new Map();
1544
+ for (let e of f) {
1545
+ let t = `${e.table_name}\u0000${e.constraint_name}`, n = C.get(t);
1506
1546
  n || (n = {
1507
1547
  table: e.table_name,
1508
1548
  columns: []
1509
- }, S.set(t, n)), n.columns.push({
1549
+ }, C.set(t, n)), n.columns.push({
1510
1550
  name: e.column_name,
1511
1551
  position: e.position
1512
1552
  });
1513
1553
  }
1514
- for (let [e, t] of S) {
1554
+ for (let [e, t] of C) {
1515
1555
  let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
1516
1556
  if (n.length === 1) {
1517
- let e = y.get(t.table);
1518
- e || (e = /* @__PURE__ */ new Set(), y.set(t.table, e)), e.add(n[0]);
1557
+ let e = b.get(t.table);
1558
+ e || (e = /* @__PURE__ */ new Set(), b.set(t.table, e)), e.add(n[0]);
1519
1559
  } else {
1520
- let r = b.get(t.table);
1521
- r || (r = [], b.set(t.table, r)), r.push({
1560
+ let r = x.get(t.table);
1561
+ r || (r = [], x.set(t.table, r)), r.push({
1522
1562
  name: e.slice(e.indexOf("\0") + 1),
1523
1563
  table: t.table,
1524
1564
  columns: n,
@@ -1527,28 +1567,28 @@ BEGIN
1527
1567
  }
1528
1568
  }
1529
1569
  for (let e of g) {
1530
- let t = te.get(e.source_table);
1531
- t || (t = [], te.set(e.source_table, t)), t.push(e);
1570
+ let t = S.get(e.source_table);
1571
+ t || (t = [], S.set(e.source_table, t)), t.push(e);
1532
1572
  }
1533
- for (let e of ee) {
1534
- let t = x.get(e.table_name);
1535
- t || (t = /* @__PURE__ */ new Map(), x.set(e.table_name, t));
1573
+ for (let e of _) {
1574
+ let t = ee.get(e.table_name);
1575
+ t || (t = /* @__PURE__ */ new Map(), ee.set(e.table_name, t));
1536
1576
  let n = t.get(e.index_name);
1537
1577
  n || (n = [], t.set(e.index_name, n)), n.push(e);
1538
1578
  }
1539
- let ne = [];
1579
+ let te = [];
1540
1580
  for (let e of c) {
1541
- 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 = te.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) => {
1542
- 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" : Kt(t.data_type, t.udt_name), c = a ? {
1581
+ 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) => {
1582
+ 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" : Jt(t.data_type, t.udt_name), c = a ? {
1543
1583
  table: a.target_table,
1544
1584
  column: a.target_column,
1545
- onDelete: L(a.delete_rule),
1546
- onUpdate: L(a.update_rule)
1585
+ onDelete: z(a.delete_rule),
1586
+ onUpdate: z(a.update_rule)
1547
1587
  } : void 0, l = h.get(`${e.table_name}.${t.column_name}`);
1548
1588
  return {
1549
1589
  name: t.column_name,
1550
1590
  type: s,
1551
- ...B(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: B(t.data_type, t.character_maximum_length) },
1591
+ ...H(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: H(t.data_type, t.character_maximum_length) },
1552
1592
  nullable: t.is_nullable === "YES",
1553
1593
  unique: i.has(t.column_name) || n && t.column_name === "id",
1554
1594
  hasDefault: t.column_default !== null,
@@ -1556,7 +1596,7 @@ BEGIN
1556
1596
  ...c ? { references: c } : {},
1557
1597
  ...l ? { oneOf: l } : {}
1558
1598
  };
1559
- }), l = [], u = x.get(e.table_name);
1599
+ }), l = [], u = ee.get(e.table_name);
1560
1600
  if (u) for (let [t, n] of u) {
1561
1601
  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) => {
1562
1602
  let t = e.position;
@@ -1572,7 +1612,7 @@ BEGIN
1572
1612
  ...a ? { expression: !0 } : {}
1573
1613
  });
1574
1614
  }
1575
- for (let t of b.get(e.table_name) ?? []) l.push(t);
1615
+ for (let t of x.get(e.table_name) ?? []) l.push(t);
1576
1616
  r.size > 0 && l.push({
1577
1617
  name: `${e.table_name}_pkey`,
1578
1618
  table: e.table_name,
@@ -1580,20 +1620,20 @@ BEGIN
1580
1620
  unique: !0
1581
1621
  });
1582
1622
  let d = Number(e.row_count ?? 0);
1583
- ne.push({
1623
+ te.push({
1584
1624
  name: e.table_name,
1585
1625
  columns: c,
1586
1626
  indexes: l,
1587
1627
  ...d > 0 ? { rowCount: d } : {}
1588
1628
  });
1589
1629
  }
1590
- return { tables: ne };
1630
+ return { tables: te };
1591
1631
  });
1592
- return (t > 0 ? e.withTransaction(n) : n).pipe(d.catchAll((e) => {
1632
+ return (t > 0 ? e.withTransaction(n) : n).pipe(p.catchAll((e) => {
1593
1633
  let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
1594
- return n.includes("statement timeout") || n.includes("57014") ? d.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.`)) : d.fail(e);
1634
+ 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);
1595
1635
  }));
1596
- }, $t = (e, t) => {
1636
+ }, tn = (e, t) => {
1597
1637
  switch (e.toLowerCase()) {
1598
1638
  case "varchar":
1599
1639
  case "char":
@@ -1625,21 +1665,21 @@ BEGIN
1625
1665
  case "json": return "json";
1626
1666
  default: return "text";
1627
1667
  }
1628
- }, R = (e) => e.map((e) => {
1668
+ }, B = (e) => e.map((e) => {
1629
1669
  let t = e, n = {};
1630
1670
  for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
1631
1671
  return n;
1632
- }), en = (e) => d.gen(function* () {
1633
- let t = R(yield* e`
1672
+ }), nn = (e) => p.gen(function* () {
1673
+ let t = B(yield* e`
1634
1674
  SELECT table_name, COALESCE(table_rows, 0) AS table_rows
1635
1675
  FROM information_schema.tables
1636
1676
  WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
1637
- ORDER BY table_name`), n = R(yield* e`
1677
+ ORDER BY table_name`), n = B(yield* e`
1638
1678
  SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key,
1639
1679
  character_maximum_length
1640
1680
  FROM information_schema.columns
1641
1681
  WHERE table_schema = DATABASE()
1642
- ORDER BY table_name, ordinal_position`), r = R(yield* e`
1682
+ ORDER BY table_name, ordinal_position`), r = B(yield* e`
1643
1683
  SELECT k.table_name AS source_table,
1644
1684
  k.column_name AS source_column,
1645
1685
  k.referenced_table_name AS target_table,
@@ -1649,21 +1689,21 @@ BEGIN
1649
1689
  JOIN information_schema.referential_constraints r
1650
1690
  ON k.constraint_name = r.constraint_name
1651
1691
  AND k.table_schema = r.constraint_schema
1652
- WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = R(yield* e`
1692
+ WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = B(yield* e`
1653
1693
  SELECT table_name, index_name, non_unique, column_name, seq_in_index
1654
1694
  FROM information_schema.statistics
1655
1695
  WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
1656
- ORDER BY table_name, index_name, seq_in_index`), a = R(yield* e`
1696
+ ORDER BY table_name, index_name, seq_in_index`), a = B(yield* e`
1657
1697
  SELECT table_name, check_clause
1658
1698
  FROM information_schema.check_constraints
1659
- WHERE constraint_schema = DATABASE()`.unprepared.pipe(d.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
1699
+ WHERE constraint_schema = DATABASE()`.unprepared.pipe(p.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
1660
1700
  for (let e of a) {
1661
1701
  let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
1662
1702
  if (t) {
1663
1703
  o.add(`${e.table_name}.${t[1]}`);
1664
1704
  continue;
1665
1705
  }
1666
- let n = Gt(e.check_clause);
1706
+ let n = qt(e.check_clause);
1667
1707
  n && s.set(`${e.table_name}.${n.column}`, n.values);
1668
1708
  }
1669
1709
  let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
@@ -1681,22 +1721,22 @@ BEGIN
1681
1721
  let n = t.get(e.index_name) ?? [];
1682
1722
  n.push(e), t.set(e.index_name, n);
1683
1723
  }
1684
- let f = [];
1724
+ let d = [];
1685
1725
  for (let e of t) {
1686
- 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(), d = u.get(e.table_name);
1687
- if (d) for (let e of d.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
1726
+ 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);
1727
+ if (f) for (let e of f.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
1688
1728
  let p = t.map((t) => {
1689
- 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" : $t(t.data_type, t.column_type), u = c ? {
1729
+ 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" : tn(t.data_type, t.column_type), u = c ? {
1690
1730
  table: c.target_table,
1691
1731
  column: c.target_column,
1692
- onDelete: L(c.delete_rule),
1693
- onUpdate: L(c.update_rule)
1732
+ onDelete: z(c.delete_rule),
1733
+ onUpdate: z(c.update_rule)
1694
1734
  } : 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}`);
1695
1735
  return {
1696
1736
  name: t.column_name,
1697
1737
  type: l,
1698
1738
  nullable: t.is_nullable === "YES",
1699
- ...B(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: B(t.data_type, t.character_maximum_length) },
1739
+ ...H(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: H(t.data_type, t.character_maximum_length) },
1700
1740
  unique: d,
1701
1741
  hasDefault: f !== null,
1702
1742
  ...f === null ? {} : { defaultValue: f },
@@ -1704,7 +1744,7 @@ BEGIN
1704
1744
  ...p ? { oneOf: p } : {}
1705
1745
  };
1706
1746
  }), m = new Set(n.map((e) => e.source_column)), h = [];
1707
- if (d) for (let [t, n] of d) {
1747
+ if (f) for (let [t, n] of f) {
1708
1748
  let r = [...n].sort((e, t) => e.seq_in_index - t.seq_in_index);
1709
1749
  r.length === 1 && r[0].non_unique === 0 || r.length === 1 && r[0].non_unique !== 0 && m.has(r[0].column_name) && t !== `${e.table_name}_${r[0].column_name}_idx` || h.push({
1710
1750
  name: t,
@@ -1720,18 +1760,18 @@ BEGIN
1720
1760
  unique: !0
1721
1761
  });
1722
1762
  let g = Number(e.table_rows ?? 0);
1723
- f.push({
1763
+ d.push({
1724
1764
  name: e.table_name,
1725
1765
  columns: p,
1726
1766
  indexes: h,
1727
1767
  ...g > 0 ? { rowCount: g } : {}
1728
1768
  });
1729
1769
  }
1730
- return { tables: f };
1731
- }), tn = (e) => {
1770
+ return { tables: d };
1771
+ }), rn = (e) => {
1732
1772
  let t = e.toUpperCase();
1733
1773
  return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
1734
- }, nn = (e) => d.gen(function* () {
1774
+ }, an = (e) => p.gen(function* () {
1735
1775
  let t = yield* e`
1736
1776
  SELECT name, sql FROM sqlite_master
1737
1777
  WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
@@ -1748,11 +1788,11 @@ BEGIN
1748
1788
  d.set(t.name, r), t.unique === 1 && r.length === 1 && f.add(r[0]);
1749
1789
  }
1750
1790
  let p = o.map((e) => {
1751
- let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : tn(e.type), a = r ? {
1791
+ let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : rn(e.type), a = r ? {
1752
1792
  table: r.table,
1753
1793
  column: r.to,
1754
- onDelete: L(r.on_delete),
1755
- onUpdate: L(r.on_update)
1794
+ onDelete: z(r.on_delete),
1795
+ onUpdate: z(r.on_update)
1756
1796
  } : void 0, o = t.get(e.name);
1757
1797
  return {
1758
1798
  name: e.name,
@@ -1787,7 +1827,7 @@ BEGIN
1787
1827
  });
1788
1828
  }
1789
1829
  return { tables: r };
1790
- }), rn = (e) => {
1830
+ }), on = (e) => {
1791
1831
  switch (e.toLowerCase()) {
1792
1832
  case "int":
1793
1833
  case "smallint":
@@ -1809,7 +1849,7 @@ BEGIN
1809
1849
  case "image": return "bytes";
1810
1850
  default: return "text";
1811
1851
  }
1812
- }, z = (e) => e === !0 || e === 1, an = (e) => d.gen(function* () {
1852
+ }, V = (e) => e === !0 || e === 1, sn = (e) => p.gen(function* () {
1813
1853
  let t = yield* e`
1814
1854
  SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
1815
1855
  WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
@@ -1866,21 +1906,21 @@ BEGIN
1866
1906
  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();
1867
1907
  if (a) for (let [, e] of a) {
1868
1908
  let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
1869
- if (z(t[0].is_primary)) for (let e of t) d.push(e.column_name);
1870
- else z(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
1909
+ if (V(t[0].is_primary)) for (let e of t) d.push(e.column_name);
1910
+ else V(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
1871
1911
  }
1872
1912
  let p = t.map((t) => {
1873
- 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" : rn(t.data_type), s = i ? {
1913
+ 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" : on(t.data_type), s = i ? {
1874
1914
  table: i.target_table,
1875
1915
  column: i.target_column,
1876
- onDelete: on(i.delete_rule),
1877
- onUpdate: on(i.update_rule)
1878
- } : void 0, c = t.column_default === null ? null : sn(t.column_default), l = o.get(`${e}.${t.column_name}`);
1916
+ onDelete: cn(i.delete_rule),
1917
+ onUpdate: cn(i.update_rule)
1918
+ } : void 0, c = t.column_default === null ? null : ln(t.column_default), l = o.get(`${e}.${t.column_name}`);
1879
1919
  return {
1880
1920
  name: t.column_name,
1881
1921
  type: a,
1882
1922
  nullable: t.is_nullable === "YES",
1883
- ...B(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: B(t.data_type, t.character_maximum_length) },
1923
+ ...H(t.data_type, t.character_maximum_length) === void 0 ? {} : { maxLength: H(t.data_type, t.character_maximum_length) },
1884
1924
  unique: f.has(t.column_name) || n && t.column_name === "id",
1885
1925
  hasDefault: c !== null,
1886
1926
  ...c === null ? {} : { defaultValue: c },
@@ -1890,11 +1930,11 @@ BEGIN
1890
1930
  }), m = [];
1891
1931
  if (a) for (let [t, n] of a) {
1892
1932
  let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
1893
- z(r[0].is_primary) || r.length === 1 && z(r[0].is_unique) || r.length === 1 && !z(r[0].is_unique) && i.has(r[0].column_name) && t !== `${e}_${r[0].column_name}_idx` || m.push({
1933
+ 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({
1894
1934
  name: t,
1895
1935
  table: e,
1896
1936
  columns: r.map((e) => e.column_name),
1897
- unique: z(r[0].is_unique)
1937
+ unique: V(r[0].is_unique)
1898
1938
  });
1899
1939
  }
1900
1940
  d.length > 0 && m.push({
@@ -1909,48 +1949,51 @@ BEGIN
1909
1949
  });
1910
1950
  }
1911
1951
  return { tables: u };
1912
- }), on = (e) => {
1952
+ }), cn = (e) => {
1913
1953
  switch (e.toUpperCase().replace(/_/g, " ")) {
1914
1954
  case "CASCADE": return "cascade";
1915
1955
  case "SET NULL": return "setNull";
1916
1956
  case "SET DEFAULT": return "noAction";
1917
1957
  default: return "noAction";
1918
1958
  }
1919
- }, sn = (e) => {
1959
+ }, ln = (e) => {
1920
1960
  let t = e.trim();
1921
1961
  for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
1922
1962
  return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
1923
- }, cn = /* @__PURE__ */ new Set([
1963
+ }, un = /* @__PURE__ */ new Set([
1924
1964
  "character varying",
1925
1965
  "varchar",
1926
1966
  "nvarchar",
1927
1967
  "char",
1928
1968
  "character",
1929
1969
  "nchar"
1930
- ]), B = (e, t) => {
1931
- if (!cn.has(e.toLowerCase())) return;
1970
+ ]), H = (e, t) => {
1971
+ if (!un.has(e.toLowerCase())) return;
1932
1972
  let n = Number(t);
1933
1973
  if (!(!Number.isFinite(n) || n <= 0)) return n;
1934
- }, V = (e) => e.onDialectOrElse({
1935
- mysql: () => en(e),
1936
- mssql: () => an(e),
1937
- sqlite: () => nn(e),
1938
- orElse: () => Qt(e)
1939
- }), ln = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, H = (e, t) => {
1974
+ }, U = (e) => e.onDialectOrElse({
1975
+ mysql: () => nn(e),
1976
+ mssql: () => sn(e),
1977
+ sqlite: () => an(e),
1978
+ orElse: () => en(e)
1979
+ }), dn = (e, t) => e.onDialectOrElse({
1980
+ mysql: () => p.succeed(t.replace("T", " ").replace("Z", "")),
1981
+ orElse: () => p.succeed(t)
1982
+ }), fn = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, W = (e, t) => {
1940
1983
  if (!(e.type === "text" && e.maxLength !== void 0) && !e.spatial && e.type !== "vector" && e.type !== "array" && e.type !== "enum") return;
1941
1984
  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;
1942
1985
  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.`);
1943
- return E(e, t);
1944
- }, U = (e) => {
1945
- let t = H(e, "postgres");
1946
- return t === void 0 ? un(e) : t;
1947
- }, un = (e) => {
1986
+ return j(e, t);
1987
+ }, pn = (e) => {
1988
+ let t = W(e, "postgres");
1989
+ return t === void 0 ? mn(e) : t;
1990
+ }, mn = (e) => {
1948
1991
  switch (e.type) {
1949
1992
  case "id": return "text";
1950
1993
  case "text": return "text";
1951
1994
  case "integer": return "integer";
1952
1995
  case "real": return "double precision";
1953
- case "decimal": return ln(e, "NUMERIC");
1996
+ case "decimal": return fn(e, "NUMERIC");
1954
1997
  case "bigint": return "bigint";
1955
1998
  case "boolean": return "boolean";
1956
1999
  case "timestamp": return "timestamptz";
@@ -1964,15 +2007,15 @@ BEGIN
1964
2007
  case "interval": return "interval";
1965
2008
  case "raw": return e.rawDdl ?? "text";
1966
2009
  }
1967
- }, W = (e) => {
1968
- let t = H(e, "mariadb");
2010
+ }, hn = (e) => {
2011
+ let t = W(e, "mariadb");
1969
2012
  if (t !== void 0) return t;
1970
2013
  switch (e.type) {
1971
2014
  case "id": return "VARCHAR(64)";
1972
2015
  case "text": return e.hasDefault && e.defaultValue !== void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : "LONGTEXT";
1973
2016
  case "integer": return "INT";
1974
2017
  case "real": return "DOUBLE";
1975
- case "decimal": return ln(e, "DECIMAL");
2018
+ case "decimal": return fn(e, "DECIMAL");
1976
2019
  case "bigint": return "BIGINT";
1977
2020
  case "boolean": return "TINYINT(1)";
1978
2021
  case "timestamp": return "DATETIME(6)";
@@ -1986,32 +2029,32 @@ BEGIN
1986
2029
  case "interval": return "BIGINT";
1987
2030
  case "raw": return e.rawDdl ?? "LONGTEXT";
1988
2031
  }
1989
- }, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``, dn = (e, t) => `ALTER TABLE ${t(e.table)} DROP COLUMN IF EXISTS ${t(e.column)};`, fn = (e) => `ALTER TABLE ${K(e.table)} DROP COLUMN IF EXISTS ${K(e.column)}, ALGORITHM=COPY;`, pn = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, mn = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${zn(t)}`)};`, hn = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${gn(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, gn = (e, t) => {
2032
+ }, G = (e) => `"${e}"`, K = (e) => `\`${e.replace(/`/g, "``")}\``, gn = (e, t) => `ALTER TABLE ${t(e.table)} DROP COLUMN IF EXISTS ${t(e.column)};`, _n = (e) => `ALTER TABLE ${K(e.table)} DROP COLUMN IF EXISTS ${K(e.column)}, ALGORITHM=COPY;`, vn = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, yn = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${Wn(t)}`)};`, bn = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${xn(e, n)};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, xn = (e, t) => {
1990
2033
  let n = t(e.defaultValue);
1991
2034
  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.`);
1992
2035
  return n;
1993
- }, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], _n = (e, t, n) => {
2036
+ }, q = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Sn = (e, t, n) => {
1994
2037
  let r = q(e, t, n);
1995
- return r ? nt(n, r) : void 0;
1996
- }, vn = (e, t, n) => {
1997
- let r = n ?? e.nullable, i = ye(e, "mariadb");
2038
+ return r ? ct(n, r) : void 0;
2039
+ }, Cn = (e, t, n) => {
2040
+ let r = n ?? e.nullable, i = be(e, "mariadb");
1998
2041
  return [
1999
2042
  K(t),
2000
- E(e, "mariadb"),
2043
+ j(e, "mariadb"),
2001
2044
  r ? null : "NOT NULL",
2002
2045
  i
2003
2046
  ].filter(Boolean).join(" ");
2004
- }, yn = (e, t) => e == null ? null : Array.isArray(e) ? bn(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" ? D(e, "mysql") : null, bn = (e, t, n) => be(e, t ?? { type: "json" }, n), xn = (e, t) => e == null ? null : Array.isArray(e) ? bn(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" ? D(e, "postgres") : null, J = (e, t) => {
2047
+ }, wn = (e, t) => e == null ? null : Array.isArray(e) ? Tn(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, "mysql") : null, Tn = (e, t, n) => xe(e, t ?? { type: "json" }, n), En = (e, t) => e == null ? null : Array.isArray(e) ? Tn(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) => {
2005
2048
  if (!e.generatedAs) return null;
2006
2049
  let { expr: n, stored: r } = e.generatedAs;
2007
2050
  return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
2008
- }, Sn = (e) => {
2009
- if (e.type === "id" && e.idScheme?.kind === "numeric") return O(e.name, "postgres");
2051
+ }, Dn = (e) => {
2052
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "postgres");
2010
2053
  let t = J(e, "postgres");
2011
- if (t) return `${G(e.name)} ${U(e)} ${t}`;
2012
- let n = [G(e.name), U(e)];
2054
+ if (t) return `${G(e.name)} ${pn(e)} ${t}`;
2055
+ let n = [G(e.name), pn(e)];
2013
2056
  if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
2014
- let t = xn(e.defaultValue, e);
2057
+ let t = En(e.defaultValue, e);
2015
2058
  t && n.push(t);
2016
2059
  }
2017
2060
  return e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
@@ -2020,20 +2063,20 @@ BEGIN
2020
2063
  setNull: "SET NULL",
2021
2064
  noAction: "NO ACTION"
2022
2065
  }[e.references.onDelete]}`)), n.join(" ");
2023
- }, Cn = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", wn = (e) => {
2024
- let t = e.columns.map((e) => ` ${Sn(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${Cn(e, G)}\n)`];
2025
- 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(Wn).join(", ")})`);
2066
+ }, On = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", kn = (e) => {
2067
+ let t = e.columns.map((e) => ` ${Dn(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${On(e, G)}\n)`];
2068
+ 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(Yn).join(", ")})`);
2026
2069
  return n;
2027
- }, Tn = 191, En = (e) => {
2028
- let t = W(e).toUpperCase();
2070
+ }, An = 191, jn = (e) => {
2071
+ let t = hn(e).toUpperCase();
2029
2072
  return t.endsWith("TEXT") || t.endsWith("BLOB");
2030
- }, Dn = (e) => {
2031
- if (e.type === "id" && e.idScheme?.kind === "numeric") return O(e.name, "mariadb");
2073
+ }, Mn = (e) => {
2074
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mariadb");
2032
2075
  let t = J(e, "mariadb");
2033
- if (t) return `${K(e.name)} ${W(e)} ${t}`;
2034
- let n = [K(e.name), W(e)];
2035
- if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !En(e) && n.push("UNIQUE"), e.hasDefault) {
2036
- let t = yn(e.defaultValue, e);
2076
+ if (t) return `${K(e.name)} ${hn(e)} ${t}`;
2077
+ let n = [K(e.name), hn(e)];
2078
+ if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && !jn(e) && n.push("UNIQUE"), e.hasDefault) {
2079
+ let t = wn(e.defaultValue, e);
2037
2080
  t && n.push(t);
2038
2081
  }
2039
2082
  return e.references && (n.push(`REFERENCES ${K(e.references.table)} (${K(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
@@ -2042,26 +2085,26 @@ BEGIN
2042
2085
  setNull: "SET NULL",
2043
2086
  noAction: "NO ACTION"
2044
2087
  }[e.references.onDelete]}`)), n.join(" ");
2045
- }, On = (e) => {
2088
+ }, Nn = (e) => {
2046
2089
  let t = new Map(e.columns.map((e) => [e.name, e])), n = (e) => {
2047
2090
  let n = t.get(e);
2048
- return n && En(n) ? `${K(e)}(${Tn})` : K(e);
2049
- }, r = e.columns.map((e) => ` ${Dn(e)}`).join(",\n"), i = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${r}${Cn(e, n)}\n)`];
2050
- for (let t of e.columns) t.unique && t.type !== "id" && En(t) && i.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${K(`${e.table}_${t.name}_key`)} ON ${K(e.table)} (${n(t.name)})`);
2091
+ return n && jn(n) ? `${K(e)}(${An})` : K(e);
2092
+ }, r = e.columns.map((e) => ` ${Mn(e)}`).join(",\n"), i = [`CREATE TABLE IF NOT EXISTS ${K(e.table)} (\n${r}${On(e, n)}\n)`];
2093
+ for (let t of e.columns) t.unique && t.type !== "id" && jn(t) && i.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${K(`${e.table}_${t.name}_key`)} ON ${K(e.table)} (${n(t.name)})`);
2051
2094
  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(", ")})`);
2052
2095
  return i;
2053
- }, kn = {
2096
+ }, Pn = {
2054
2097
  cascade: "CASCADE",
2055
2098
  restrict: "RESTRICT",
2056
2099
  setNull: "SET NULL",
2057
2100
  noAction: "NO ACTION"
2058
- }, An = {
2101
+ }, Fn = {
2059
2102
  cascade: "CASCADE",
2060
2103
  restrict: "NO ACTION",
2061
2104
  setNull: "SET NULL",
2062
2105
  noAction: "NO ACTION"
2063
- }, jn = (e) => {
2064
- let t = H(e, "sqlite");
2106
+ }, In = (e) => {
2107
+ let t = W(e, "sqlite");
2065
2108
  if (t !== void 0) return t;
2066
2109
  switch (e.type) {
2067
2110
  case "integer":
@@ -2072,29 +2115,29 @@ BEGIN
2072
2115
  case "bytes": return "BLOB";
2073
2116
  default: return "TEXT";
2074
2117
  }
2075
- }, 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" ? D(e, "sqlite") : null, Mn = (e) => {
2076
- if (e.type === "id" && e.idScheme?.kind === "numeric") return O(e.name, "sqlite");
2118
+ }, 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, Ln = (e) => {
2119
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "sqlite");
2077
2120
  let t = J(e, "sqlite");
2078
- if (t) return `${G(e.name)} ${jn(e)} ${t}`;
2079
- let n = [G(e.name), jn(e)];
2121
+ if (t) return `${G(e.name)} ${In(e)} ${t}`;
2122
+ let n = [G(e.name), In(e)];
2080
2123
  if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
2081
2124
  let t = Y(e.defaultValue, "CURRENT_TIMESTAMP");
2082
2125
  t && n.push(t);
2083
2126
  }
2084
- if (e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${kn[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
2127
+ if (e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${Pn[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
2085
2128
  let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
2086
2129
  n.push(`CHECK (${G(e.name)} IN (${t}))`);
2087
2130
  }
2088
2131
  return n.join(" ");
2089
- }, Nn = (e) => {
2090
- let t = e.columns.map((e) => ` ${Mn(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${Cn(e, G)}\n)`];
2132
+ }, Rn = (e) => {
2133
+ let t = e.columns.map((e) => ` ${Ln(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${t}${On(e, G)}\n)`];
2091
2134
  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(", ")})`);
2092
2135
  return n;
2093
2136
  }, X = (e, t) => {
2094
2137
  let n = t.find((t) => t.tableName === e);
2095
2138
  if (!n) return [];
2096
- let r = N([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => G(e.name)).join(", "), o = [
2097
- ...Nn({
2139
+ let r = I([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => G(e.name)).join(", "), o = [
2140
+ ...Rn({
2098
2141
  kind: "create-table",
2099
2142
  table: i,
2100
2143
  columns: r.columns,
@@ -2107,25 +2150,25 @@ BEGIN
2107
2150
  ];
2108
2151
  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(", ")})`);
2109
2152
  return o;
2110
- }, Pn = (e, t, n, r) => {
2153
+ }, zn = (e, t, n, r) => {
2111
2154
  let i = r ?? e.nullable;
2112
- return `ALTER TABLE ${Z(n)} ALTER COLUMN ${Z(t)} ${E(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
2113
- }, Fn = (e) => {
2155
+ return `ALTER TABLE ${Z(n)} ALTER COLUMN ${Z(t)} ${j(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
2156
+ }, Bn = (e) => {
2114
2157
  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 + ']');`;
2115
2158
  if (!e.hasDefault) return t;
2116
2159
  let n = Y(e.defaultValue, "SYSUTCDATETIME()");
2117
2160
  if (!n) return t;
2118
2161
  let r = n.replace(/^DEFAULT\s+/i, "");
2119
2162
  return `${t} ALTER TABLE ${Z(e.table)} ADD DEFAULT ${r} FOR ${Z(e.column)};`;
2120
- }, Z = (e) => `[${e.replace(/]/g, "]]")}]`, In = (e) => {
2121
- let t = H(e, "mssql");
2163
+ }, Z = (e) => `[${e.replace(/]/g, "]]")}]`, Vn = (e) => {
2164
+ let t = W(e, "mssql");
2122
2165
  if (t !== void 0) return t;
2123
2166
  switch (e.type) {
2124
2167
  case "id":
2125
2168
  case "reference": return "NVARCHAR(64)";
2126
2169
  case "integer": return "INT";
2127
2170
  case "real": return "FLOAT";
2128
- case "decimal": return ln(e, "DECIMAL");
2171
+ case "decimal": return fn(e, "DECIMAL");
2129
2172
  case "bigint": return "BIGINT";
2130
2173
  case "boolean": return "BIT";
2131
2174
  case "timestamp": return "DATETIME2(6)";
@@ -2133,40 +2176,40 @@ BEGIN
2133
2176
  case "bytes": return "VARBINARY(MAX)";
2134
2177
  default: return "NVARCHAR(MAX)";
2135
2178
  }
2136
- }, Ln = (e, t) => {
2137
- if (e.type === "id" && e.idScheme?.kind === "numeric") return O(e.name, "mssql");
2138
- let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : In(e), r = J(e, "mssql");
2179
+ }, Hn = (e, t) => {
2180
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return N(e.name, "mssql");
2181
+ let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : Vn(e), r = J(e, "mssql");
2139
2182
  if (r) return `${Z(e.name)} ${r}`;
2140
2183
  let i = [Z(e.name), n];
2141
2184
  if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
2142
2185
  let t = Y(e.defaultValue, "SYSUTCDATETIME()");
2143
2186
  t && i.push(t);
2144
2187
  }
2145
- return e.references && (i.push(`REFERENCES ${Z(e.references.table)} (${Z(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${An[e.references.onDelete]}`)), i.join(" ");
2146
- }, Rn = (e) => {
2147
- let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${Ln(e, n)}`).join(",\n"), i = `CREATE TABLE ${Z(e.table)} (\n${r}${Cn(e, Z)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
2188
+ return e.references && (i.push(`REFERENCES ${Z(e.references.table)} (${Z(e.references.column)})`), e.references.onDelete && i.push(`ON DELETE ${Fn[e.references.onDelete]}`)), i.join(" ");
2189
+ }, Un = (e) => {
2190
+ let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${Hn(e, n)}`).join(",\n"), i = `CREATE TABLE ${Z(e.table)} (\n${r}${On(e, Z)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
2148
2191
  for (let n of e.indexes) {
2149
2192
  if (n.name === `${e.table}_pkey`) continue;
2150
2193
  let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Z(n.name)} ON ${Z(e.table)} (${n.columns.map(Z).join(", ")})`;
2151
2194
  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)}')`);
2152
2195
  }
2153
2196
  return a;
2154
- }, zn = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Bn = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Vn = (e, t, n) => {
2155
- let r = `${e.table}${zn(t)}`;
2197
+ }, Wn = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, Gn = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, Kn = (e, t, n) => {
2198
+ let r = `${e.table}${Wn(t)}`;
2156
2199
  return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
2157
- }, Hn = (e, t, n) => {
2200
+ }, qn = (e, t, n) => {
2158
2201
  let r = q(e, t, n);
2159
- return r ? En({ type: r.type }) : !1;
2160
- }, Un = (e, t, n) => Hn(e, t, n) ? `${K(n)}(${Tn})` : K(n), Wn = (e) => e.startsWith("(") ? e : G(e), Gn = (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(Wn).join(", ")});`, Kn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map((n) => Un(t, e.table, n)).join(", ")});`, qn = (e) => `DROP INDEX IF EXISTS ${G(e.index)};`, Jn = (e) => `DROP INDEX ${K(e.index)} ON ${K(e.table)};`, Yn = (e) => `DROP INDEX IF EXISTS ${Z(e.index)} ON ${Z(e.table)};`, Xn = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, Zn = (e) => {
2202
+ return r ? jn({ type: r.type }) : !1;
2203
+ }, Jn = (e, t, n) => qn(e, t, n) ? `${K(n)}(${An})` : K(n), Yn = (e) => e.startsWith("(") ? e : G(e), Xn = (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(Yn).join(", ")});`, Zn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${K(e.index.name)} ON ${K(e.table)} (${e.index.columns.map((n) => Jn(t, e.table, n)).join(", ")});`, Qn = (e) => `DROP INDEX IF EXISTS ${G(e.index)};`, $n = (e) => `DROP INDEX ${K(e.index)} ON ${K(e.table)};`, er = (e) => `DROP INDEX IF EXISTS ${Z(e.index)} ON ${Z(e.table)};`, tr = (e, t) => `ALTER TABLE ${t(e.from)} RENAME TO ${t(e.to)};`, nr = (e) => {
2161
2204
  let t = (e) => e.replace(/'/g, "''");
2162
2205
  return `EXEC sp_rename N'${t(e.from)}', N'${t(e.to)}';`;
2163
- }, Qn = (e) => `ALTER INDEX ${G(e.from)} RENAME TO ${G(e.to)};`, $n = (e) => `ALTER TABLE ${K(e.table)} RENAME INDEX ${K(e.from)} TO ${K(e.to)};`, er = (e) => {
2206
+ }, rr = (e) => `ALTER INDEX ${G(e.from)} RENAME TO ${G(e.to)};`, ir = (e) => `ALTER TABLE ${K(e.table)} RENAME INDEX ${K(e.from)} TO ${K(e.to)};`, ar = (e) => {
2164
2207
  let t = (e) => e.replace(/'/g, "''");
2165
2208
  return `EXEC sp_rename N'${t(e.table)}.${t(e.from)}', N'${t(e.to)}', N'INDEX';`;
2166
- }, tr = (e) => {
2209
+ }, or = (e) => {
2167
2210
  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(", ")})`;
2168
2211
  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)}');`;
2169
- }, nr = (e, t, n) => {
2212
+ }, sr = (e, t, n) => {
2170
2213
  let r = n.find((t) => t.tableName === e);
2171
2214
  if (!r) return [];
2172
2215
  let i = [];
@@ -2175,13 +2218,13 @@ BEGIN
2175
2218
  t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Z(e)} ALTER COLUMN ${Z(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
2176
2219
  }
2177
2220
  return i;
2178
- }, rr = (e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${G(e.column)});`, ir = (e, t) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${Un(t, e.table, e.column)});`, ar = (e) => {
2221
+ }, cr = (e) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${G(e.column)});`, lr = (e, t) => `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(`${e.table}_${e.column}_key`)} UNIQUE (${Jn(t, e.table, e.column)});`, ur = (e) => {
2179
2222
  let t = e.fields.map((e) => G(e)).join(", ");
2180
2223
  return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${t});`;
2181
- }, or = (e, t) => {
2182
- let n = e.fields.map((n) => Un(t, e.table, n)).join(", ");
2224
+ }, dr = (e, t) => {
2225
+ let n = e.fields.map((n) => Jn(t, e.table, n)).join(", ");
2183
2226
  return `ALTER TABLE ${K(e.table)} ADD CONSTRAINT ${K(e.name)} UNIQUE (${n});`;
2184
- }, sr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(e.name)};`, cr = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(e.name)};`, lr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_key`)};`, ur = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(`${e.table}_${e.column}_key`)};`, dr = (e, t) => {
2227
+ }, fr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(e.name)};`, pr = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(e.name)};`, mr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_key`)};`, hr = (e) => `ALTER TABLE ${K(e.table)} DROP INDEX ${K(`${e.table}_${e.column}_key`)};`, gr = (e, t) => {
2185
2228
  let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
2186
2229
  if (e.orphanPolicy) {
2187
2230
  let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
@@ -2199,11 +2242,11 @@ BEGIN
2199
2242
  setNull: "SET NULL",
2200
2243
  noAction: "NO ACTION"
2201
2244
  }[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
2202
- }, fr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_fkey`)};`, pr = (e) => `ALTER TABLE ${K(e.table)} DROP FOREIGN KEY ${K(`${e.table}_${e.column}_fkey`)};`, mr = (e, t) => {
2245
+ }, _r = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_fkey`)};`, vr = (e) => `ALTER TABLE ${K(e.table)} DROP FOREIGN KEY ${K(`${e.table}_${e.column}_fkey`)};`, yr = (e, t) => {
2203
2246
  let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
2204
2247
  return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
2205
- }, hr = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_check`)};`, gr = (e) => `ALTER TABLE ${K(e.table)} DROP CHECK ${K(`${e.table}_${e.column}_check`)};`, _r = (e, t, n, r) => {
2206
- let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? Z : G, s = a ? W(i) : r === "mssql" ? In(i) : r === "sqlite" ? jn(i) : U(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? yn(e, i) : r === "mssql" ? Y(e, "SYSUTCDATETIME()") : r === "sqlite" ? Y(e, "CURRENT_TIMESTAMP") : xn(e, i), u = J(i, r);
2248
+ }, br = (e) => `ALTER TABLE ${G(e.table)} DROP CONSTRAINT IF EXISTS ${G(`${e.table}_${e.column}_check`)};`, xr = (e) => `ALTER TABLE ${K(e.table)} DROP CHECK ${K(`${e.table}_${e.column}_check`)};`, Sr = (e, t, n, r) => {
2249
+ let i = e.column, a = r === "mariadb", o = a ? K : r === "mssql" ? Z : G, s = a ? hn(i) : r === "mssql" ? Vn(i) : r === "sqlite" ? In(i) : pn(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? wn(e, i) : r === "mssql" ? Y(e, "SYSUTCDATETIME()") : r === "sqlite" ? Y(e, "CURRENT_TIMESTAMP") : En(e, i), u = J(i, r);
2207
2250
  if (u) {
2208
2251
  let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
2209
2252
  return {
@@ -2231,7 +2274,7 @@ BEGIN
2231
2274
  post: f ? [f] : []
2232
2275
  };
2233
2276
  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;
2234
- }, vr = (e) => {
2277
+ }, Cr = (e) => {
2235
2278
  let t = new Map(e.map((e) => [e.tableName, e]));
2236
2279
  return (e, n) => {
2237
2280
  let r = t.get(e);
@@ -2251,26 +2294,26 @@ BEGIN
2251
2294
  ...o
2252
2295
  };
2253
2296
  };
2254
- }, Q = (e, t, n) => e.unsafe(t).pipe(d.tapError((e) => d.sync(() => {
2255
- process.stderr.write(_(`applier: statement failed (op=${n})`, t, e, 400));
2256
- })), d.mapError((e) => {
2257
- let r = _(`applier: statement failed (op=${n})`, t, e, 400).trim();
2297
+ }, Q = (e, t, n) => e.unsafe(t).pipe(p.tapError((e) => p.sync(() => {
2298
+ process.stderr.write(b(`applier: statement failed (op=${n})`, t, e, 400));
2299
+ })), p.mapError((e) => {
2300
+ let r = b(`applier: statement failed (op=${n})`, t, e, 400).trim();
2258
2301
  return Object.assign(e, { message: r });
2259
- }), d.map(() => void 0)), $ = (e, t, n) => d.forEach(t, (t) => Q(e, t, n), { discard: !0 }), yr = (e, t, n) => d.gen(function* () {
2260
- let r = process.hrtime.bigint(), i = vr(n.declared), a = t.op;
2302
+ }), p.map(() => void 0)), $ = (e, t, n) => p.forEach(t, (t) => Q(e, t, n), { discard: !0 }), wr = (e, t, n) => p.gen(function* () {
2303
+ let r = process.hrtime.bigint(), i = Cr(n.declared), a = t.op;
2261
2304
  switch (a.kind) {
2262
2305
  case "create-table": {
2263
2306
  let t = yield* e.onDialectOrElse({
2264
- mysql: () => d.succeed(On(a)),
2265
- mssql: () => d.succeed(Rn(a)),
2266
- sqlite: () => d.succeed(Nn(a)),
2267
- orElse: () => d.succeed(wn(a))
2307
+ mysql: () => p.succeed(Nn(a)),
2308
+ mssql: () => p.succeed(Un(a)),
2309
+ sqlite: () => p.succeed(Rn(a)),
2310
+ orElse: () => p.succeed(kn(a))
2268
2311
  });
2269
2312
  for (let n of t) yield* Q(e, n, a.kind);
2270
2313
  break;
2271
2314
  }
2272
2315
  case "drop-table": {
2273
- let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Vn(a, n, e) : Bn(a, e);
2316
+ let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? Kn(a, n, e) : Gn(a, e);
2274
2317
  yield* e.onDialectOrElse({
2275
2318
  mysql: () => Q(e, r(K), a.kind),
2276
2319
  orElse: () => Q(e, r(G), a.kind)
@@ -2280,89 +2323,89 @@ BEGIN
2280
2323
  case "drop-column": {
2281
2324
  let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
2282
2325
  yield* e.onDialectOrElse({
2283
- mysql: () => Q(e, t ? mn(a, n, K) : fn(a), a.kind),
2284
- orElse: () => Q(e, t ? mn(a, n, G) : dn(a, G), a.kind)
2326
+ mysql: () => Q(e, t ? yn(a, n, K) : _n(a), a.kind),
2327
+ orElse: () => Q(e, t ? yn(a, n, G) : gn(a, G), a.kind)
2285
2328
  });
2286
2329
  break;
2287
2330
  }
2288
2331
  case "rename-column":
2289
2332
  yield* e.onDialectOrElse({
2290
- mysql: () => Q(e, pn(a, K), a.kind),
2333
+ mysql: () => Q(e, vn(a, K), a.kind),
2291
2334
  mssql: () => Q(e, `EXEC sp_rename N'${a.table.replace(/'/g, "''")}.${a.from.replace(/'/g, "''")}', N'${a.to.replace(/'/g, "''")}', 'COLUMN';`, a.kind),
2292
- orElse: () => Q(e, pn(a, G), a.kind)
2335
+ orElse: () => Q(e, vn(a, G), a.kind)
2293
2336
  });
2294
2337
  break;
2295
2338
  case "add-index":
2296
2339
  yield* e.onDialectOrElse({
2297
- mysql: () => Q(e, Kn(a, n.declared), a.kind),
2298
- mssql: () => $(e, [...nr(a.table, a.index.columns, n.declared), tr(a)], a.kind),
2299
- orElse: () => Q(e, Gn(a, t.classification === "online-required"), a.kind)
2340
+ mysql: () => Q(e, Zn(a, n.declared), a.kind),
2341
+ mssql: () => $(e, [...sr(a.table, a.index.columns, n.declared), or(a)], a.kind),
2342
+ orElse: () => Q(e, Xn(a, t.classification === "online-required"), a.kind)
2300
2343
  });
2301
2344
  break;
2302
2345
  case "drop-index":
2303
2346
  yield* e.onDialectOrElse({
2304
- mysql: () => Q(e, Jn(a), a.kind),
2305
- mssql: () => Q(e, Yn(a), a.kind),
2306
- orElse: () => Q(e, qn(a), a.kind)
2347
+ mysql: () => Q(e, $n(a), a.kind),
2348
+ mssql: () => Q(e, er(a), a.kind),
2349
+ orElse: () => Q(e, Qn(a), a.kind)
2307
2350
  });
2308
2351
  break;
2309
2352
  case "rename-table":
2310
2353
  yield* e.onDialectOrElse({
2311
- mysql: () => Q(e, Xn(a, K), a.kind),
2312
- mssql: () => Q(e, Zn(a), a.kind),
2313
- orElse: () => Q(e, Xn(a, G), a.kind)
2354
+ mysql: () => Q(e, tr(a, K), a.kind),
2355
+ mssql: () => Q(e, nr(a), a.kind),
2356
+ orElse: () => Q(e, tr(a, G), a.kind)
2314
2357
  });
2315
2358
  break;
2316
2359
  case "rename-index":
2317
2360
  yield* e.onDialectOrElse({
2318
- mysql: () => Q(e, $n(a), a.kind),
2319
- mssql: () => Q(e, er(a), a.kind),
2320
- orElse: () => Q(e, Qn(a), a.kind)
2361
+ mysql: () => Q(e, ir(a), a.kind),
2362
+ mssql: () => Q(e, ar(a), a.kind),
2363
+ orElse: () => Q(e, rr(a), a.kind)
2321
2364
  });
2322
2365
  break;
2323
2366
  case "add-unique":
2324
2367
  yield* e.onDialectOrElse({
2325
- mysql: () => Q(e, ir(a, n.declared), a.kind),
2368
+ mysql: () => Q(e, lr(a, n.declared), a.kind),
2326
2369
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2327
- mssql: () => $(e, [...nr(a.table, [a.column], n.declared), rr(a)], a.kind),
2328
- orElse: () => Q(e, rr(a), a.kind)
2370
+ mssql: () => $(e, [...sr(a.table, [a.column], n.declared), cr(a)], a.kind),
2371
+ orElse: () => Q(e, cr(a), a.kind)
2329
2372
  });
2330
2373
  break;
2331
2374
  case "drop-unique":
2332
2375
  yield* e.onDialectOrElse({
2333
- mysql: () => Q(e, ur(a), a.kind),
2376
+ mysql: () => Q(e, hr(a), a.kind),
2334
2377
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2335
- orElse: () => Q(e, lr(a), a.kind)
2378
+ orElse: () => Q(e, mr(a), a.kind)
2336
2379
  });
2337
2380
  break;
2338
2381
  case "add-unique-composite":
2339
2382
  yield* e.onDialectOrElse({
2340
- mysql: () => Q(e, or(a, n.declared), a.kind),
2383
+ mysql: () => Q(e, dr(a, n.declared), a.kind),
2341
2384
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2342
- mssql: () => $(e, [...nr(a.table, a.fields, n.declared), ar(a)], a.kind),
2343
- orElse: () => Q(e, ar(a), a.kind)
2385
+ mssql: () => $(e, [...sr(a.table, a.fields, n.declared), ur(a)], a.kind),
2386
+ orElse: () => Q(e, ur(a), a.kind)
2344
2387
  });
2345
2388
  break;
2346
2389
  case "drop-unique-composite":
2347
2390
  yield* e.onDialectOrElse({
2348
- mysql: () => Q(e, cr(a), a.kind),
2391
+ mysql: () => Q(e, pr(a), a.kind),
2349
2392
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2350
- orElse: () => Q(e, sr(a), a.kind)
2393
+ orElse: () => Q(e, fr(a), a.kind)
2351
2394
  });
2352
2395
  break;
2353
2396
  case "add-foreign-key":
2354
2397
  yield* e.onDialectOrElse({
2355
- mysql: () => $(e, dr(a, K), a.kind),
2398
+ mysql: () => $(e, gr(a, K), a.kind),
2356
2399
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2357
- orElse: () => $(e, dr(a, G), a.kind)
2400
+ orElse: () => $(e, gr(a, G), a.kind)
2358
2401
  });
2359
2402
  break;
2360
2403
  case "add-column": {
2361
- let n = _r(a, t, i, yield* e.onDialectOrElse({
2362
- mysql: () => d.succeed("mariadb"),
2363
- mssql: () => d.succeed("mssql"),
2364
- sqlite: () => d.succeed("sqlite"),
2365
- orElse: () => d.succeed("postgres")
2404
+ let n = Sr(a, t, i, yield* e.onDialectOrElse({
2405
+ mysql: () => p.succeed("mariadb"),
2406
+ mssql: () => p.succeed("mssql"),
2407
+ sqlite: () => p.succeed("sqlite"),
2408
+ orElse: () => p.succeed("postgres")
2366
2409
  }));
2367
2410
  for (let t of n.pre) yield* Q(e, t, a.kind);
2368
2411
  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}`;
@@ -2372,10 +2415,10 @@ BEGIN
2372
2415
  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}`;
2373
2416
  if (s.length === 0) break;
2374
2417
  let c = s.map((e) => e.id);
2375
- yield* e`UPDATE ${e(a.table)} SET ${e(a.column.name)} = ${n.backfillSql} WHERE ${e("id")} IN ${e.in(c)}`, o += s.length, yield* d.logInfo(`backfill ${a.table}.${a.column.name}: ${o} rows`).pipe(d.annotateLogs({
2418
+ 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({
2376
2419
  scope: "voltro:migrate",
2377
2420
  mode: "sql-batched"
2378
- })), i = s[s.length - 1].id, r > 0 && (yield* d.sleep(`${r} millis`));
2421
+ })), i = s[s.length - 1].id, r > 0 && (yield* p.sleep(`${r} millis`));
2379
2422
  }
2380
2423
  }
2381
2424
  else if (n.backfillKind === "js" && n.backfillJs) {
@@ -2384,17 +2427,17 @@ BEGIN
2384
2427
  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}`;
2385
2428
  if (s.length === 0) break;
2386
2429
  for (let t of s) {
2387
- let r = yield* d.tryPromise({
2430
+ let r = yield* p.tryPromise({
2388
2431
  try: () => Promise.resolve(n.backfillJs({ id: t.id })),
2389
2432
  catch: (e) => e
2390
- }).pipe(d.orDie);
2433
+ }).pipe(p.orDie);
2391
2434
  yield* e`UPDATE ${e(a.table)} SET ${e(a.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
2392
2435
  }
2393
- o += s.length, yield* d.logInfo(`backfill ${a.table}.${a.column.name}: ${o} rows processed`).pipe(d.annotateLogs({
2436
+ o += s.length, yield* p.logInfo(`backfill ${a.table}.${a.column.name}: ${o} rows processed`).pipe(p.annotateLogs({
2394
2437
  scope: "voltro:migrate",
2395
2438
  table: a.table,
2396
2439
  column: a.column.name
2397
- })), i = s[s.length - 1].id, r > 0 && (yield* d.sleep(`${r} millis`));
2440
+ })), i = s[s.length - 1].id, r > 0 && (yield* p.sleep(`${r} millis`));
2398
2441
  }
2399
2442
  }
2400
2443
  for (let t of n.post) yield* Q(e, t, a.kind);
@@ -2404,37 +2447,37 @@ BEGIN
2404
2447
  yield* e.onDialectOrElse({
2405
2448
  mysql: () => {
2406
2449
  let t = q(n.declared, a.table, a.column);
2407
- return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${vn(t, a.column, a.toNullable)};`, a.kind) : d.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.`));
2450
+ return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${Cn(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.`));
2408
2451
  },
2409
2452
  mssql: () => {
2410
2453
  let t = q(n.declared, a.table, a.column);
2411
- return t ? Q(e, Pn(t, a.column, a.table, a.toNullable), a.kind) : d.die(/* @__PURE__ */ Error(`alter-column-nullability on mssql needs the declared column '${a.table}.${a.column}'.`));
2454
+ return t ? Q(e, zn(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}'.`));
2412
2455
  },
2413
2456
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2414
2457
  orElse: () => Q(e, `ALTER TABLE ${G(a.table)} ALTER COLUMN ${G(a.column)} ${a.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, a.kind)
2415
2458
  });
2416
2459
  break;
2417
2460
  case "alter-column-default": {
2418
- let t = _n(n.declared, a.table, a.column);
2461
+ let t = Sn(n.declared, a.table, a.column);
2419
2462
  yield* e.onDialectOrElse({
2420
- mysql: () => Q(e, hn(a, K, (e) => yn(e, t)), a.kind),
2421
- mssql: () => Q(e, Fn(a), a.kind),
2463
+ mysql: () => Q(e, bn(a, K, (e) => wn(e, t)), a.kind),
2464
+ mssql: () => Q(e, Bn(a), a.kind),
2422
2465
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2423
- orElse: () => Q(e, hn(a, G, (e) => xn(e, t)), a.kind)
2466
+ orElse: () => Q(e, bn(a, G, (e) => En(e, t)), a.kind)
2424
2467
  });
2425
2468
  break;
2426
2469
  }
2427
2470
  case "alter-column-type": {
2428
- let r = U(_n(n.declared, a.table, a.column) ?? { type: a.to }), i = a.using ? ` USING ${a.using}` : "";
2471
+ let r = pn(Sn(n.declared, a.table, a.column) ?? { type: a.to }), i = a.using ? ` USING ${a.using}` : "";
2429
2472
  if (t.classification !== "online-required") {
2430
2473
  yield* e.onDialectOrElse({
2431
2474
  mysql: () => {
2432
2475
  let t = q(n.declared, a.table, a.column);
2433
- return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${vn(t, a.column)};`, a.kind) : d.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.`));
2476
+ return t ? Q(e, `ALTER TABLE ${K(a.table)} MODIFY COLUMN ${Cn(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.`));
2434
2477
  },
2435
2478
  mssql: () => {
2436
2479
  let t = q(n.declared, a.table, a.column);
2437
- return t ? Q(e, Pn(t, a.column, a.table), a.kind) : d.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${a.table}.${a.column}'.`));
2480
+ return t ? Q(e, zn(t, a.column, a.table), a.kind) : p.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${a.table}.${a.column}'.`));
2438
2481
  },
2439
2482
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2440
2483
  orElse: () => Q(e, `ALTER TABLE ${G(a.table)} ALTER COLUMN ${G(a.column)} TYPE ${r}${i};`, a.kind)
@@ -2442,8 +2485,8 @@ BEGIN
2442
2485
  break;
2443
2486
  }
2444
2487
  yield* e.onDialectOrElse({
2445
- mysql: () => d.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.`)),
2446
- orElse: () => d.void
2488
+ 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.`)),
2489
+ orElse: () => p.void
2447
2490
  });
2448
2491
  let o = `${a.column}__shadow`, s = `${a.column}__old`;
2449
2492
  yield* e.unsafe(`ALTER TABLE ${G(a.table)} ADD COLUMN ${G(o)} ${r}`);
@@ -2453,28 +2496,28 @@ BEGIN
2453
2496
  if (t.length === 0) break;
2454
2497
  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;
2455
2498
  }
2456
- yield* d.logInfo(`alter-column-type shadow ${a.table}.${a.column}: shadow populated`).pipe(d.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)}`);
2499
+ 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)}`);
2457
2500
  break;
2458
2501
  }
2459
2502
  case "drop-foreign-key":
2460
2503
  yield* e.onDialectOrElse({
2461
- mysql: () => Q(e, pr(a), a.kind),
2504
+ mysql: () => Q(e, vr(a), a.kind),
2462
2505
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2463
- orElse: () => Q(e, fr(a), a.kind)
2506
+ orElse: () => Q(e, _r(a), a.kind)
2464
2507
  });
2465
2508
  break;
2466
2509
  case "add-check":
2467
2510
  yield* e.onDialectOrElse({
2468
- mysql: () => Q(e, mr(a, K), a.kind),
2511
+ mysql: () => Q(e, yr(a, K), a.kind),
2469
2512
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2470
- orElse: () => Q(e, mr(a, G), a.kind)
2513
+ orElse: () => Q(e, yr(a, G), a.kind)
2471
2514
  });
2472
2515
  break;
2473
2516
  case "drop-check":
2474
2517
  yield* e.onDialectOrElse({
2475
- mysql: () => Q(e, gr(a), a.kind),
2518
+ mysql: () => Q(e, xr(a), a.kind),
2476
2519
  sqlite: () => $(e, X(a.table, n.declared), a.kind),
2477
- orElse: () => Q(e, hr(a), a.kind)
2520
+ orElse: () => Q(e, br(a), a.kind)
2478
2521
  });
2479
2522
  break;
2480
2523
  }
@@ -2483,34 +2526,31 @@ BEGIN
2483
2526
  status: "applied",
2484
2527
  durationMs: Number((process.hrtime.bigint() - r) / 1000000n)
2485
2528
  };
2486
- }), br = (e, t, n) => d.gen(function* () {
2529
+ }), Tr = (e, t, n) => p.gen(function* () {
2487
2530
  let r = t.operations.filter((e) => e.blocked);
2488
- if (r.length > 0) return yield* d.die(/* @__PURE__ */ Error(`applyPlan: refusing to execute — ${r.length} blocked operations. Run \`voltro db plan\` to see the fixes.`));
2489
- yield* C(e);
2531
+ 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.`));
2532
+ yield* T(e);
2490
2533
  let i = Date.now(), a = [];
2491
2534
  try {
2492
2535
  let r = yield* e.onDialectOrElse({
2493
- pg: () => d.succeed(!0),
2494
- mssql: () => d.succeed(!0),
2495
- orElse: () => d.succeed(!1)
2536
+ pg: () => p.succeed(!0),
2537
+ mssql: () => p.succeed(!0),
2538
+ orElse: () => p.succeed(!1)
2496
2539
  }), i = r ? t.operations.filter((e) => e.classification !== "online-required") : [], o = r ? t.operations.filter((e) => e.classification === "online-required") : t.operations;
2497
- i.length > 0 && (yield* e.withTransaction(d.gen(function* () {
2498
- let e = yield* p.SqlClient;
2499
- for (let t of i) a.push(yield* yr(e, t, n));
2540
+ i.length > 0 && (yield* e.withTransaction(p.gen(function* () {
2541
+ let e = yield* h.SqlClient;
2542
+ for (let t of i) a.push(yield* wr(e, t, n));
2500
2543
  })));
2501
- for (let t of o) a.push(yield* yr(e, t, n));
2544
+ for (let t of o) a.push(yield* wr(e, t, n));
2502
2545
  } finally {
2503
- yield* w(e).pipe(d.orDie);
2546
+ yield* E(e).pipe(p.orDie);
2504
2547
  }
2505
2548
  let o = yield* n.replan(e);
2506
2549
  if (o.operations.length > 0) {
2507
2550
  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");
2508
- return yield* d.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.`));
2551
+ 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.`));
2509
2552
  }
2510
- let s = a.filter((e) => e.status === "applied").length, c = Date.now() - i, l = `plan_${Date.now().toString(36)}`, u = (/* @__PURE__ */ new Date()).toISOString(), f = yield* e.onDialectOrElse({
2511
- mysql: () => d.succeed(u.replace("T", " ").replace("Z", "")),
2512
- orElse: () => d.succeed(u)
2513
- });
2553
+ 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* dn(e, u);
2514
2554
  return yield* e`
2515
2555
  INSERT INTO ${e("_voltro_migration_plans")}
2516
2556
  (${e("id")}, ${e("fingerprint")}, ${e("liveFingerprint")}, ${e("operations")},
@@ -2519,7 +2559,7 @@ BEGIN
2519
2559
  VALUES
2520
2560
  (${l}, ${t.toFingerprint}, ${o.fromFingerprint}, ${JSON.stringify(t.operations)},
2521
2561
  ${n.appliedBy}, ${n.environment}, ${n.source},
2522
- ${c}, ${f}, ${n.notes ?? null})
2562
+ ${c}, ${d}, ${n.notes ?? null})
2523
2563
  `, {
2524
2564
  id: l,
2525
2565
  appliedAt: u,
@@ -2532,19 +2572,19 @@ BEGIN
2532
2572
  source: n.source,
2533
2573
  ...n.notes ? { notes: n.notes } : {}
2534
2574
  };
2535
- }), xr = (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"), Sr = (e) => e`
2575
+ }), Er = (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"), Dr = (e) => e`
2536
2576
  SELECT fingerprint
2537
2577
  FROM _voltro_migration_plans
2538
2578
  ORDER BY ${e("appliedAt")} DESC
2539
2579
  LIMIT 1
2540
- `.pipe(d.map((e) => e.length > 0 ? e[0].fingerprint : void 0), d.catchAll(() => d.succeed(void 0))), Cr = (e) => e.onDialectOrElse({
2580
+ `.pipe(p.map((e) => e.length > 0 ? e[0].fingerprint : void 0), p.catchAll(() => p.succeed(void 0))), Or = (e) => e.onDialectOrElse({
2541
2581
  pg: () => "postgres",
2542
2582
  mysql: () => "mysql",
2543
2583
  mssql: () => "mssql",
2544
2584
  sqlite: () => "sqlite",
2545
2585
  orElse: () => "sqlite"
2546
- }), wr = (e, t) => d.gen(function* () {
2547
- let n = j(N(t, Cr(e))), r = yield* Sr(e);
2586
+ }), kr = (e, t) => p.gen(function* () {
2587
+ let n = P(I(t, Or(e))), r = yield* Dr(e);
2548
2588
  return r === n ? {
2549
2589
  kind: "up-to-date",
2550
2590
  fingerprint: n
@@ -2553,23 +2593,23 @@ BEGIN
2553
2593
  expected: n,
2554
2594
  ...r === void 0 ? {} : { actual: r }
2555
2595
  };
2556
- }), Tr = [
2596
+ }), Ar = [
2557
2597
  "pgeagertest_",
2558
2598
  "mig_e2e_",
2559
2599
  "mig_test_",
2560
2600
  "mysqleagertest_",
2561
2601
  "mssqleagertest_",
2562
2602
  "sqliteeagertest_"
2563
- ], Er = (e) => Tr.some((t) => e.startsWith(t)), Dr = (e, t) => d.gen(function* () {
2603
+ ], jr = (e) => Ar.some((t) => e.startsWith(t)), Mr = (e, t) => p.gen(function* () {
2564
2604
  if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
2565
- let n = t.filter((e) => Er(e.name)).map((e) => e.name);
2605
+ let n = t.filter((e) => jr(e.name)).map((e) => e.name);
2566
2606
  if (n.length === 0) return [];
2567
- for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(d.catchAll(() => d.void));
2607
+ for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(p.catchAll(() => p.void));
2568
2608
  return n;
2569
- }), Or = () => {
2609
+ }), Nr = () => {
2570
2610
  let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
2571
2611
  return e.length > 0 ? { ignoreTables: e } : {};
2572
- }, kr = (e) => {
2612
+ }, Pr = (e) => {
2573
2613
  if (e === void 0) return;
2574
2614
  let t = e.trim();
2575
2615
  if (t === "") return;
@@ -2579,83 +2619,83 @@ BEGIN
2579
2619
  kind: "tables",
2580
2620
  tables: new Set(n)
2581
2621
  } : void 0;
2582
- }, Ar = (e) => typeof e.table == "string" ? e.table : void 0, jr = (e, t = { kind: "all" }) => ({
2622
+ }, Fr = (e) => typeof e.table == "string" ? e.table : void 0, Ir = (e, t = { kind: "all" }) => ({
2583
2623
  ...e,
2584
2624
  operations: e.operations.map((e) => {
2585
2625
  if (!e.blocked || e.classification !== "lossy") return e;
2586
2626
  if (t?.kind === "tables") {
2587
- let n = Ar(e.op);
2627
+ let n = Fr(e.op);
2588
2628
  if (n === void 0 || !t.tables.has(n)) return e;
2589
2629
  }
2590
2630
  let { blocked: n, ...r } = e;
2591
2631
  return r;
2592
2632
  })
2593
- }), Mr = (e, t, n) => t === "postgres" ? st(e, n).pipe(d.flatMap((e) => {
2594
- let t = ct(e);
2595
- return t === void 0 ? d.void : d.logWarning(`auto-migrate: ${t}`).pipe(d.annotateLogs({ scope: "voltro:migrate" }));
2596
- }), d.catchAll(() => d.void)) : d.void, Nr = (e, t, n) => d.gen(function* () {
2597
- let r = Cr(e), i = t;
2633
+ }), Lr = (e, t, n) => t === "postgres" ? ft(e, n).pipe(p.flatMap((e) => {
2634
+ let t = pt(e);
2635
+ return t === void 0 ? p.void : p.logWarning(`auto-migrate: ${t}`).pipe(p.annotateLogs({ scope: "voltro:migrate" }));
2636
+ }), p.catchAll(() => p.void)) : p.void, Rr = (e, t, n) => p.gen(function* () {
2637
+ let r = Or(e), i = t;
2598
2638
  if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
2599
- let t = j(N(i, r));
2600
- if ((yield* Sr(e)) === t) return yield* Mr(e, r, i), {
2639
+ let t = P(I(i, r));
2640
+ if ((yield* Dr(e)) === t) return yield* Lr(e, r, i), {
2601
2641
  kind: "up-to-date",
2602
2642
  fingerprint: t
2603
2643
  };
2604
2644
  }
2605
- let a = yield* V(e), o = yield* Dr(e, a.tables);
2606
- o.length > 0 && (yield* d.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(d.annotateLogs({
2645
+ let a = yield* U(e), o = yield* Mr(e, a.tables);
2646
+ o.length > 0 && (yield* p.logInfo(`auto-migrate: reaped ${o.length} test-fixture leftover(s)`).pipe(p.annotateLogs({
2607
2647
  scope: "voltro:migrate",
2608
2648
  count: o.length
2609
- })), a = yield* V(e));
2610
- let s = new Set(t.map((e) => e.tableName)), c = (e) => e.filter((e) => !ut(e.name) || s.has(e.name)), l = Wt({
2649
+ })), a = yield* U(e));
2650
+ let c = new Set(t.map((e) => e.tableName)), l = (e) => e.filter((e) => !s(e.name) || c.has(e.name)), u = Kt({
2611
2651
  declared: i,
2612
- live: { tables: c(a.tables) },
2652
+ live: { tables: l(a.tables) },
2613
2653
  dialect: r,
2614
- ...Or()
2654
+ ...Nr()
2615
2655
  });
2616
- if (l.summary.blocked > 0) {
2617
- let e = l.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = kr(process.env.VOLTRO_DESTRUCTIVE_OK);
2618
- if (t === void 0 || !e || (l = jr(l, t), l.operations.some((e) => e.blocked))) return {
2656
+ if (u.summary.blocked > 0) {
2657
+ let e = u.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy"), t = Pr(process.env.VOLTRO_DESTRUCTIVE_OK);
2658
+ if (t === void 0 || !e || (u = Ir(u, t), u.operations.some((e) => e.blocked))) return {
2619
2659
  kind: "refused-blocked",
2620
- plan: l
2660
+ plan: u
2621
2661
  };
2622
2662
  }
2623
- return l.operations.length === 0 ? {
2663
+ return u.operations.length === 0 ? {
2624
2664
  kind: "up-to-date",
2625
- fingerprint: l.toFingerprint
2665
+ fingerprint: u.toFingerprint
2626
2666
  } : {
2627
2667
  kind: "applied",
2628
- applied: yield* br(e, l, {
2668
+ applied: yield* Tr(e, u, {
2629
2669
  declared: t,
2630
2670
  appliedBy: n.appliedBy,
2631
2671
  environment: n.environment === "prod" ? "dev" : n.environment,
2632
2672
  source: "auto-diff",
2633
- replan: (e) => d.gen(function* () {
2634
- let t = yield* V(e);
2635
- return Wt({
2673
+ replan: (e) => p.gen(function* () {
2674
+ let t = yield* U(e);
2675
+ return Kt({
2636
2676
  declared: i,
2637
- live: { tables: c(t.tables) },
2677
+ live: { tables: l(t.tables) },
2638
2678
  dialect: r,
2639
- ...Or()
2679
+ ...Nr()
2640
2680
  });
2641
2681
  })
2642
2682
  }),
2643
- plan: l
2683
+ plan: u
2644
2684
  };
2645
- }), Pr = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? d.succeed({
2685
+ }), zr = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? p.succeed({
2646
2686
  kind: "skipped",
2647
2687
  reason: "VOLTRO_AUTO_MIGRATE=0"
2648
- }) : n.environment === "prod" ? wr(e, t) : Nr(e, t, n), Fr = (e, t) => {
2688
+ }) : n.environment === "prod" ? kr(e, t) : Rr(e, t, n), Br = (e, t) => {
2649
2689
  switch (e.kind) {
2650
2690
  case "skipped": return `auto-migrate: skipped (${e.reason})`;
2651
- case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${M(e.fingerprint)})`;
2691
+ case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${F(e.fingerprint)})`;
2652
2692
  case "applied": {
2653
2693
  let t = e.plan.summary;
2654
- 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=${M(e.applied.fingerprint)}`;
2694
+ 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)}`;
2655
2695
  }
2656
- case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${M(e.expected)}` + (e.actual ? ` live=${M(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
2696
+ 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.";
2657
2697
  case "refused-blocked": {
2658
- 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` + xr(e.plan), c = [""];
2698
+ 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` + Er(e.plan), c = [""];
2659
2699
  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) {
2660
2700
  let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
2661
2701
  for (let r of e.plan.operations) {
@@ -2672,7 +2712,7 @@ BEGIN
2672
2712
  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");
2673
2713
  }
2674
2714
  }
2675
- }, Ir = /* @__PURE__ */ new Set([
2715
+ }, Vr = /* @__PURE__ */ new Set([
2676
2716
  "node_modules",
2677
2717
  "dist",
2678
2718
  "build",
@@ -2681,58 +2721,68 @@ BEGIN
2681
2721
  ".next",
2682
2722
  ".git",
2683
2723
  ".framework"
2684
- ]), Lr = async (e) => {
2724
+ ]), Hr = async (e) => {
2685
2725
  let t = [], n = async (e) => {
2686
- let r = await h.readdir(e, { withFileTypes: !0 }).catch(() => []);
2726
+ let r = await _.readdir(e, { withFileTypes: !0 }).catch(() => []);
2687
2727
  for (let i of r) {
2688
- if (Ir.has(i.name)) continue;
2689
- let r = g(e, i.name);
2690
- i.isDirectory() ? await n(r) : i.isFile() && l.test(i.name) && t.push(r);
2728
+ if (Vr.has(i.name)) continue;
2729
+ let r = v(e, i.name);
2730
+ i.isDirectory() ? await n(r) : i.isFile() && o.test(i.name) && t.push(r);
2691
2731
  }
2692
2732
  };
2693
2733
  return await n(e), t.sort((e, t) => {
2694
2734
  let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
2695
2735
  return n.localeCompare(r);
2696
2736
  });
2697
- }, Rr = async (e) => {
2737
+ }, Ur = async (e) => {
2698
2738
  let t = [];
2699
- for (let n of e) {
2700
- let e = (await import(ee(n).href)).default;
2701
- if (!o(e)) {
2702
- process.stderr.write(`[voltro:migrate] ${n} has no default-exported \`migration(...)\` — skipped\n`);
2739
+ for (let r of e) {
2740
+ let e = (await import(y(r).href)).default;
2741
+ if (!n(e)) {
2742
+ process.stderr.write(`[voltro:migrate] ${r} has no default-exported \`migration(...)\` — skipped\n`);
2703
2743
  continue;
2704
2744
  }
2705
2745
  t.push({
2706
- file: n,
2746
+ file: r,
2707
2747
  migration: e
2708
2748
  });
2709
2749
  }
2710
2750
  return t;
2711
- }, zr = (e) => e`
2751
+ }, Wr = (e) => e`
2712
2752
  SELECT ${e("id")}
2713
2753
  FROM ${e("_voltro_migration_plans")}
2714
2754
  WHERE ${e("source")} = 'file'
2715
- `.pipe(d.map((e) => e.map((e) => e.id)), d.catchAll(() => d.succeed([]))), Br = (e, t, n, r) => d.gen(function* () {
2755
+ `.pipe(p.map((e) => e.map((e) => e.id)), p.catchAll(() => p.succeed([]))), Gr = class extends Error {
2756
+ migrationId;
2757
+ file;
2758
+ cause;
2759
+ _tag = "FileMigrationLedgerError";
2760
+ constructor(e, t, n) {
2761
+ 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";
2762
+ }
2763
+ }, Kr = (e, t, n, r) => p.gen(function* () {
2716
2764
  let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
2717
2765
  sql: e,
2718
2766
  log: {
2719
- info: (e, n) => d.logInfo(e).pipe(d.annotateLogs({
2767
+ info: (e, n) => p.logInfo(e).pipe(p.annotateLogs({
2720
2768
  scope: `migrations:file:${t.migration.id}`,
2721
2769
  ...n ?? {}
2722
2770
  })),
2723
- warn: (e, n) => d.logWarning(e).pipe(d.annotateLogs({
2771
+ warn: (e, n) => p.logWarning(e).pipe(p.annotateLogs({
2724
2772
  scope: `migrations:file:${t.migration.id}`,
2725
2773
  ...n ?? {}
2726
2774
  }))
2727
2775
  },
2728
2776
  appliedAt: a
2729
2777
  }, s = t.migration.up(o);
2730
- d.isEffect(s) ? yield* s : yield* d.tryPromise({
2778
+ p.isEffect(s) ? yield* s : yield* p.tryPromise({
2731
2779
  try: () => s,
2732
2780
  catch: (e) => e
2733
2781
  });
2734
2782
  let c = Date.now() - i;
2735
- return !d.isEffect(s) && c < 2 && (yield* d.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(d.annotateLogs({ scope: `migrations:file:${t.migration.id}` }))), yield* e`
2783
+ !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}` })));
2784
+ let l = yield* dn(e, a);
2785
+ return yield* e`
2736
2786
  INSERT INTO ${e("_voltro_migration_plans")}
2737
2787
  (${e("id")}, ${e("fingerprint")}, ${e("operations")},
2738
2788
  ${e("appliedBy")}, ${e("environment")}, ${e("source")},
@@ -2743,95 +2793,95 @@ BEGIN
2743
2793
  file: t.file
2744
2794
  }])},
2745
2795
  ${r}, ${n}, ${"file"},
2746
- ${c}, ${a}, ${t.migration.description})
2747
- `, { durationMs: c };
2748
- }), Vr = (e, t) => d.gen(function* () {
2749
- let n = yield* d.tryPromise({
2750
- try: () => Lr(g(t, "migrations")),
2796
+ ${c}, ${l}, ${t.migration.description})
2797
+ `.pipe(p.mapError((e) => new Gr(t.migration.id, t.file, e))), { durationMs: c };
2798
+ }), qr = (e, t) => p.gen(function* () {
2799
+ let n = yield* p.tryPromise({
2800
+ try: () => Hr(v(t, "migrations")),
2751
2801
  catch: (e) => e
2752
2802
  });
2753
2803
  if (n.length === 0) return {
2754
2804
  pending: [],
2755
2805
  skipped: []
2756
2806
  };
2757
- let r = yield* d.tryPromise({
2758
- try: () => Rr(n),
2807
+ let r = yield* p.tryPromise({
2808
+ try: () => Ur(n),
2759
2809
  catch: (e) => e
2760
2810
  });
2761
2811
  if (r.length === 0) return {
2762
2812
  pending: [],
2763
2813
  skipped: []
2764
2814
  };
2765
- let i = new Set(yield* zr(e));
2815
+ let i = new Set(yield* Wr(e));
2766
2816
  return {
2767
2817
  pending: r.filter((e) => !i.has(e.migration.id)),
2768
2818
  skipped: r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id)
2769
2819
  };
2770
- }), Hr = (e, t) => Vr(e, t).pipe(d.map((e) => e.pending.map((e) => e.migration.id))), Ur = (e, t) => d.gen(function* () {
2771
- let { pending: n, skipped: r } = yield* Vr(e, t.projectRoot);
2820
+ }), Jr = (e, t) => qr(e, t).pipe(p.map((e) => e.pending.map((e) => e.migration.id))), Yr = (e, t) => p.gen(function* () {
2821
+ let { pending: n, skipped: r } = yield* qr(e, t.projectRoot);
2772
2822
  if (n.length === 0) return {
2773
2823
  applied: [],
2774
2824
  skipped: r
2775
2825
  };
2776
- yield* C(e);
2826
+ yield* T(e);
2777
2827
  let i = [];
2778
2828
  try {
2779
2829
  for (let r of n) {
2780
- yield* d.logInfo("file-based migration applying").pipe(d.annotateLogs({
2830
+ yield* p.logInfo("file-based migration applying").pipe(p.annotateLogs({
2781
2831
  scope: "voltro:migrate",
2782
2832
  id: r.migration.id,
2783
2833
  file: r.file
2784
2834
  }));
2785
- let { durationMs: n } = yield* Br(e, r, t.env, t.appliedBy);
2835
+ let { durationMs: n } = yield* Kr(e, r, t.env, t.appliedBy);
2786
2836
  i.push({
2787
2837
  id: r.migration.id,
2788
2838
  durationMs: n
2789
- }), yield* d.logInfo("file-based migration applied").pipe(d.annotateLogs({
2839
+ }), yield* p.logInfo("file-based migration applied").pipe(p.annotateLogs({
2790
2840
  scope: "voltro:migrate",
2791
2841
  id: r.migration.id,
2792
2842
  durationMs: n
2793
2843
  }));
2794
2844
  }
2795
2845
  } finally {
2796
- yield* w(e).pipe(d.orDie);
2846
+ yield* E(e).pipe(p.orDie);
2797
2847
  }
2798
2848
  return {
2799
2849
  applied: i,
2800
2850
  skipped: r
2801
2851
  };
2802
- }), Wr = (e, t) => e`
2852
+ }), Xr = (e, t) => e`
2803
2853
  SELECT ${e("id")}
2804
2854
  FROM ${e("_voltro_migration_plans")}
2805
2855
  WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
2806
2856
  LIMIT 1
2807
- `, Gr = (e, t) => d.gen(function* () {
2808
- if (!(yield* Wr(e, t.id))[0]) return yield* d.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
2809
- let n = yield* d.tryPromise({
2810
- try: () => Lr(g(t.projectRoot, "migrations")),
2857
+ `, Zr = (e, t) => p.gen(function* () {
2858
+ if (!(yield* Xr(e, t.id))[0]) return yield* p.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
2859
+ let n = yield* p.tryPromise({
2860
+ try: () => Hr(v(t.projectRoot, "migrations")),
2811
2861
  catch: (e) => e
2812
- }), r = (yield* d.tryPromise({
2813
- try: () => Rr(n),
2862
+ }), r = (yield* p.tryPromise({
2863
+ try: () => Ur(n),
2814
2864
  catch: (e) => e
2815
2865
  })).find((e) => e.migration.id === t.id);
2816
- if (!r) return yield* d.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
2817
- yield* C(e);
2866
+ if (!r) return yield* p.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
2867
+ yield* T(e);
2818
2868
  let i = Date.now();
2819
2869
  try {
2820
2870
  let n = {
2821
2871
  sql: e,
2822
2872
  log: {
2823
- info: (e, n) => d.logInfo(e).pipe(d.annotateLogs({
2873
+ info: (e, n) => p.logInfo(e).pipe(p.annotateLogs({
2824
2874
  scope: `migrations:file:${t.id}`,
2825
2875
  ...n ?? {}
2826
2876
  })),
2827
- warn: (e, n) => d.logWarning(e).pipe(d.annotateLogs({
2877
+ warn: (e, n) => p.logWarning(e).pipe(p.annotateLogs({
2828
2878
  scope: `migrations:file:${t.id}`,
2829
2879
  ...n ?? {}
2830
2880
  }))
2831
2881
  },
2832
2882
  appliedAt: (/* @__PURE__ */ new Date()).toISOString()
2833
2883
  }, a = r.migration.down(n);
2834
- d.isEffect(a) ? yield* a : yield* d.tryPromise({
2884
+ p.isEffect(a) ? yield* a : yield* p.tryPromise({
2835
2885
  try: () => a,
2836
2886
  catch: (e) => e
2837
2887
  });
@@ -2841,19 +2891,19 @@ BEGIN
2841
2891
  durationMs: o
2842
2892
  };
2843
2893
  } finally {
2844
- yield* w(e).pipe(d.orDie);
2894
+ yield* E(e).pipe(p.orDie);
2845
2895
  }
2846
- }), Kr = (e) => d.gen(function* () {
2847
- let t = yield* p.SqlClient, n = yield* t`
2896
+ }), Qr = (e) => p.gen(function* () {
2897
+ let t = yield* h.SqlClient, n = yield* t`
2848
2898
  SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
2849
2899
  WHERE source = 'auto-diff'
2850
2900
  AND squashedAt IS NULL
2851
2901
  AND appliedAt < ${e.before}
2852
2902
  ORDER BY appliedAt DESC
2853
2903
  `;
2854
- if (n.length === 0) return yield* d.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
2904
+ if (n.length === 0) return yield* p.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
2855
2905
  let r = n[0];
2856
- if (r.fingerprint !== e.fingerprint) return yield* d.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.`));
2906
+ 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.`));
2857
2907
  yield* t`
2858
2908
  UPDATE _voltro_migration_plans
2859
2909
  SET squashedAt = CURRENT_TIMESTAMP
@@ -2888,10 +2938,80 @@ BEGIN
2888
2938
  snapshotFingerprint: e.fingerprint,
2889
2939
  snapshotId: i
2890
2940
  };
2891
- }), qr = (e, ...t) => ({
2941
+ }), $r = { safe: !0 }, ei = (e) => {
2942
+ switch (e.kind) {
2943
+ case "drop-column": return {
2944
+ safe: !1,
2945
+ reason: `old instances still SELECT/INSERT "${e.table}"."${e.column}"; after the drop those queries error mid-rollout`,
2946
+ remedy: "stop reading the column in code and deploy that first; drop it in a LATER deploy (expand/contract)"
2947
+ };
2948
+ case "drop-table": return {
2949
+ safe: !1,
2950
+ reason: `old instances still query table "${e.table}"; after the drop every such query errors mid-rollout`,
2951
+ remedy: `remove all code that touches "${e.table}" and deploy that first; drop the table in a LATER deploy`
2952
+ };
2953
+ case "rename-column": return {
2954
+ safe: !1,
2955
+ reason: `old instances reference "${e.table}"."${e.from}", which no longer exists after the rename`,
2956
+ remedy: `add "${e.to}" alongside "${e.from}" + backfill + dual-write, cut code over, then drop "${e.from}" in a LATER deploy`
2957
+ };
2958
+ case "rename-table": return {
2959
+ safe: !1,
2960
+ reason: `old instances query table "${e.from}", which no longer exists after the rename`,
2961
+ remedy: `create "${e.to}" as a copy + dual-write, cut code over, then drop "${e.from}" in a LATER deploy`
2962
+ };
2963
+ case "alter-column-type": return {
2964
+ safe: !1,
2965
+ 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`,
2966
+ remedy: "add a new column of the target type + backfill + dual-write, cut code over, then drop the old column in a LATER deploy"
2967
+ };
2968
+ case "alter-column-nullability": return e.toNullable ? $r : {
2969
+ safe: !1,
2970
+ reason: `old instances may INSERT "${e.table}" without (or with NULL in) "${e.column}", which the new NOT NULL rejects`,
2971
+ 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)`
2972
+ };
2973
+ case "add-unique":
2974
+ case "add-unique-composite": return {
2975
+ safe: !1,
2976
+ reason: `old instances still write "${e.table}" without honouring the new uniqueness; a colliding insert now fails mid-rollout`,
2977
+ remedy: "make code enforce uniqueness first and deploy that; add the constraint in a LATER deploy once no old writer remains"
2978
+ };
2979
+ case "add-check": return {
2980
+ safe: !1,
2981
+ reason: `old instances may write values to "${e.table}" the new CHECK rejects`,
2982
+ remedy: "make code satisfy the constraint first and deploy that; add the CHECK in a LATER deploy"
2983
+ };
2984
+ case "add-foreign-key": return {
2985
+ safe: !1,
2986
+ reason: `old instances may write "${e.table}"."${e.column}" values with no matching parent row, which the new FK rejects`,
2987
+ remedy: "make code guarantee the referent first and deploy that; add the FK in a LATER deploy"
2988
+ };
2989
+ case "create-table":
2990
+ case "add-column":
2991
+ case "add-index":
2992
+ case "drop-index":
2993
+ case "rename-index":
2994
+ case "alter-column-default":
2995
+ case "drop-unique":
2996
+ case "drop-unique-composite":
2997
+ case "drop-foreign-key":
2998
+ case "drop-check": return $r;
2999
+ }
3000
+ }, ti = (e) => {
3001
+ let t = [];
3002
+ for (let n of e) {
3003
+ let e = ei(n.op);
3004
+ e.safe || t.push({
3005
+ op: n,
3006
+ reason: e.reason,
3007
+ remedy: e.remedy
3008
+ });
3009
+ }
3010
+ return t;
3011
+ }, ni = (e, ...t) => ({
2892
3012
  _tag: "RawSqlFragment",
2893
3013
  strings: [...e],
2894
3014
  values: [...t]
2895
- }), Jr = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
3015
+ }), ri = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
2896
3016
  //#endregion
2897
- export { l as FILE_MIGRATION_PATTERN, ot as REACTIVE_TRIGGER_PREFIX, re as VOLTRO_MIGRATION_LOCK_KEY, C as acquireMigrationLock, Je as applyNamespacedSchema, br as applyPlan, He as applySchema, Zt as chunkTables, N as declaredSnapshot, be as defaultArrayClause, ye as defaultClause, D as defaultJsonClause, Fr as describeOutcome, kr as destructiveScope, st as detectReactiveTriggerDrift, dn as emitDropColumnDdl, fn as emitDropColumnDdlMysql, Ve as emitFrameworkBootstrapSql, ze as emitNamespaceProvisionDdl, Be as emitNamespacedSchemaSql, A as emitSchemaSql, j as fingerprintSchema, ct as formatReactiveTriggerDrift, Or as ignoreTablesFromEnv, V as introspectSchema, o as isFileMigration, Jr as isRawSqlFragment, Kt as mapPgType, s as migration, O as numericIdSql, Gt as parseEnumCheck, Hr as pendingFileMigrationIds, Wt as planMigrations, Ye as provisionTenantNamespace, w as releaseMigrationLock, Dn as renderColumnMysql, Sn as renderColumnPg, Gr as rollbackFileBasedMigration, Ur as runFileBasedMigrations, Xe as runFrameworkBootstrap, qe as runMigrate, Pr as runPlannedMigrations, M as shortFingerprint, nt as snapshotColumn, qr as sql, E as sqlType, Kr as squashMigrationPlans, jr as unblockLossy, _e as withMigrationLock };
3017
+ export { O as DEFAULT_CDC_CHANNEL, o as FILE_MIGRATION_PATTERN, Gr as FileMigrationLedgerError, k as REACTIVE_TRIGGER_PREFIX, re as VOLTRO_MIGRATION_LOCK_KEY, T as acquireMigrationLock, et as applyNamespacedSchema, Tr as applyPlan, Je as applySchema, $t as chunkTables, ei as classifyRollingDeploySafety, I as declaredSnapshot, xe as defaultArrayClause, be as defaultClause, M as defaultJsonClause, Br as describeOutcome, Pr as destructiveScope, ft as detectReactiveTriggerDrift, gn as emitDropColumnDdl, _n as emitDropColumnDdlMysql, qe as emitFrameworkBootstrapSql, Ge as emitNamespaceProvisionDdl, Ke as emitNamespacedSchemaSql, We as emitSchemaSql, P as fingerprintSchema, pt as formatReactiveTriggerDrift, Nr as ignoreTablesFromEnv, U as introspectSchema, n as isFileMigration, ri as isRawSqlFragment, Jt as mapPgType, c as migration, N as numericIdSql, qt as parseEnumCheck, Jr as pendingFileMigrationIds, Kt as planMigrations, tt as provisionTenantNamespace, Fe as reactiveTriggerRepairSql, E as releaseMigrationLock, Mn as renderColumnMysql, Dn as renderColumnPg, Zr as rollbackFileBasedMigration, ti as rollingDeployUnsafeOps, Yr as runFileBasedMigrations, nt as runFrameworkBootstrap, $e as runMigrate, zr as runPlannedMigrations, F as shortFingerprint, ct as snapshotColumn, ni as sql, j as sqlType, Qr as squashMigrationPlans, Ir as unblockLossy, D as withMigrationLock };