@voltro/database 0.1.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 ADDED
@@ -0,0 +1,2569 @@
1
+ import { L as e, R as t, V as n, a as r, c as i, et as a, i as o, n as s, ot as c, r as l, t as u } from "./fileBased-cc9IzIjU.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";
9
+ //#region src/migrations/ddlError.ts
10
+ var _ = (e, t, n, r = 400) => {
11
+ let i = n, a = i.cause ?? {}, o = (e) => {
12
+ let t = a[e];
13
+ return t == null || t === "" ? void 0 : String(t);
14
+ }, s = [
15
+ "",
16
+ `═══ ${e} ═══`,
17
+ `statement: ${t.replace(/\s+/g, " ").slice(0, r)}${t.length > r ? " …" : ""}`,
18
+ `db.message: ${o("sqlMessage") ?? o("message") ?? i.message ?? "(none)"}`
19
+ ];
20
+ for (let e of [
21
+ "code",
22
+ "errno",
23
+ "sqlState",
24
+ "number",
25
+ "state",
26
+ "class",
27
+ "lineNumber",
28
+ "procName",
29
+ "serverName",
30
+ "detail",
31
+ "hint",
32
+ "table",
33
+ "column",
34
+ "constraint",
35
+ "position",
36
+ "routine"
37
+ ]) {
38
+ let t = o(e);
39
+ t !== void 0 && s.push(`db.${e}: ${t}`);
40
+ }
41
+ return s.push(""), s.join("\n");
42
+ }, v = (e, t) => `${e}::${t}`, y = (e, t) => {
43
+ let n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = (e) => {
44
+ n.add(e);
45
+ let o = [...t(e)].filter((t) => t.target !== e).sort((e, t) => e.column.localeCompare(t.column));
46
+ for (let t of o) n.has(t.target) ? i.add(v(e, t.column)) : r.has(t.target) || a(t.target);
47
+ n.delete(e), r.add(e);
48
+ };
49
+ for (let t of [...e].sort()) r.has(t) || a(t);
50
+ return i;
51
+ }, b = 6322741009312437n, x = 250, S = () => {
52
+ let e = Number(process.env.VOLTRO_MIGRATION_LOCK_TIMEOUT_MS);
53
+ return Number.isFinite(e) && e > 0 ? e : 3e4;
54
+ }, C = (e) => d.gen(function* () {
55
+ let t = S(), n = Date.now();
56
+ for (;;) {
57
+ if ((yield* e`
58
+ SELECT pg_try_advisory_lock(${"6322741009312437"}::bigint) AS got`)[0]?.got) return;
59
+ 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(`${x} millis`);
60
+ }
61
+ }), te = (e) => d.gen(function* () {
62
+ yield* e`SELECT pg_advisory_unlock(${b.toString()}::bigint)`;
63
+ }), ne = `voltro_migration_${b.toString(36)}`, re = 30, ie = (e) => d.gen(function* () {
64
+ (yield* e`
65
+ SELECT GET_LOCK(${ne}, ${re}) AS got`)[0]?.got !== 1 && (yield* d.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${ne}' within ${re}s (another migration is in progress, or a prior one left it held).`)));
66
+ }), ae = (e) => d.gen(function* () {
67
+ yield* e`SELECT RELEASE_LOCK(${ne})`;
68
+ }), oe = `voltro_migration_${b.toString(36)}`, se = 3e4, ce = (e) => d.gen(function* () {
69
+ let t = yield* e`
70
+ DECLARE @res int;
71
+ EXEC @res = sp_getapplock @Resource = ${oe}, @LockMode = 'Exclusive',
72
+ @LockOwner = 'Session', @LockTimeout = ${se};
73
+ SELECT @res AS res`;
74
+ (t[0]?.res ?? -999) < 0 && (yield* d.die(/* @__PURE__ */ Error(`could not acquire the migration lock '${oe}' (sp_getapplock returned ${t[0]?.res ?? "no row"}; another migration is in progress).`)));
75
+ }), le = (e) => d.gen(function* () {
76
+ yield* e`EXEC sp_releaseapplock @Resource = ${oe}, @LockOwner = 'Session'`;
77
+ }), ue = d.void, w = (e) => e.onDialectOrElse({
78
+ mysql: () => ie(e),
79
+ mssql: () => ce(e),
80
+ sqlite: () => ue,
81
+ orElse: () => C(e)
82
+ }), T = (e) => e.onDialectOrElse({
83
+ mysql: () => ae(e),
84
+ mssql: () => le(e),
85
+ sqlite: () => ue,
86
+ orElse: () => te(e)
87
+ }), E = (e, t) => d.acquireUseRelease(w(e), () => t, () => T(e).pipe(d.orDie)), de = f({ scope: "voltro:migrate" }), D = (e) => {
88
+ de.warn(e.replace(/^\[voltro:migrate\]\s*/, ""));
89
+ }, O = (t, n) => {
90
+ let r = t.type;
91
+ if (t.spatial) {
92
+ if (n === "postgres") return `${t.spatial.kind}(${t.spatial.geomKind},${t.spatial.srid})`;
93
+ 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.`);
94
+ }
95
+ if (r === "raw") {
96
+ if (t.rawDdl === void 0) throw Error("raw() column is missing its DDL fragment — this is a framework bug.");
97
+ return t.rawDdl;
98
+ }
99
+ if (r === "array" && t.arrayElement) {
100
+ if (n === "postgres") return `${O({
101
+ ...t,
102
+ type: t.arrayElement,
103
+ arrayElement: void 0
104
+ }, n)}[]`;
105
+ if (n === "mysql" || n === "mariadb") return "JSON";
106
+ if (n === "mssql") return "NVARCHAR(MAX)";
107
+ if (e(n)) return "TEXT";
108
+ }
109
+ if (r === "vector") {
110
+ let r = t.vectorDim;
111
+ if (r === void 0) throw Error("vector column is missing its dimension — this is a framework bug.");
112
+ let i = t.vectorPrecision === "half";
113
+ if (n === "postgres") return i ? `HALFVEC(${r})` : `VECTOR(${r})`;
114
+ if (n === "mysql" || n === "mariadb") return `VECTOR(${r})`;
115
+ if (n === "mssql") return "VARBINARY(MAX)";
116
+ if (e(n)) return "BLOB";
117
+ }
118
+ if (r === "interval") {
119
+ if (n === "postgres") return "INTERVAL";
120
+ if (n === "mysql" || n === "mariadb" || n === "mssql") return "BIGINT";
121
+ if (e(n)) return "INTEGER";
122
+ }
123
+ if (r === "decimal") {
124
+ let r = t.precision, i = t.scale ?? 0;
125
+ if (r === void 0) throw Error("decimal column is missing its precision — this is a framework bug.");
126
+ return e(n) ? "NUMERIC" : n === "postgres" ? `NUMERIC(${r}, ${i})` : `DECIMAL(${r}, ${i})`;
127
+ }
128
+ if (r === "bigint") return e(n) ? "INTEGER" : "BIGINT";
129
+ if (r === "enum") {
130
+ if (n === "postgres") return t.enumName ?? "TEXT";
131
+ if (n === "mysql" || n === "mariadb") return `ENUM(${(t.enumValues ?? []).map((e) => `'${e.replace(/'/g, "''")}'`).join(", ")})`;
132
+ if (n === "mssql") return "NVARCHAR(255)";
133
+ if (e(n)) return "TEXT";
134
+ }
135
+ if (r === "text" && t.maxLength !== void 0 && t.generatedAs === void 0) return n === "mssql" ? `NVARCHAR(${t.maxLength})` : e(n) ? "TEXT" : `VARCHAR(${t.maxLength})`;
136
+ if (e(n)) switch (r) {
137
+ case "id": return "TEXT";
138
+ case "text": return "TEXT";
139
+ case "integer": return "INTEGER";
140
+ case "real": return "REAL";
141
+ case "boolean": return "INTEGER";
142
+ case "timestamp": return "TEXT";
143
+ case "date": return "TEXT";
144
+ case "json": return "TEXT";
145
+ case "bytes": return "BLOB";
146
+ case "reference": return "TEXT";
147
+ case "vector": return "BLOB";
148
+ case "enum": return "TEXT";
149
+ case "array": return "TEXT";
150
+ case "interval": return "INTEGER";
151
+ }
152
+ if (n === "mysql" || n === "mariadb") switch (r) {
153
+ case "id": return "VARCHAR(64)";
154
+ case "text": return t.hasDefault && t.defaultFactory === void 0 || t.oneOf && t.oneOf.length > 0 ? "VARCHAR(255)" : t.generatedAs ? "TEXT" : "LONGTEXT";
155
+ case "integer": return "INT";
156
+ case "real": return "DOUBLE";
157
+ case "boolean": return "TINYINT(1)";
158
+ case "timestamp": return "DATETIME(6)";
159
+ case "date": return "DATE";
160
+ case "json": return "JSON";
161
+ case "bytes": return "LONGBLOB";
162
+ case "reference": return "VARCHAR(64)";
163
+ case "vector": return "VECTOR(0)";
164
+ case "enum": return "TEXT";
165
+ case "array": return "JSON";
166
+ case "interval": return "BIGINT";
167
+ }
168
+ if (n === "mssql") switch (r) {
169
+ case "id": return "NVARCHAR(64)";
170
+ case "text": return t.hasDefault && t.defaultFactory === void 0 || t.oneOf && t.oneOf.length > 0 ? "NVARCHAR(450)" : "NVARCHAR(MAX)";
171
+ case "integer": return "INT";
172
+ case "real": return "FLOAT";
173
+ case "boolean": return "BIT";
174
+ case "timestamp": return "DATETIME2(6)";
175
+ case "date": return "DATE";
176
+ case "json": return "NVARCHAR(MAX)";
177
+ case "bytes": return "VARBINARY(MAX)";
178
+ case "reference": return "NVARCHAR(64)";
179
+ case "vector": return "VARBINARY(MAX)";
180
+ case "enum": return "NVARCHAR(255)";
181
+ case "array": return "NVARCHAR(MAX)";
182
+ case "interval": return "BIGINT";
183
+ }
184
+ switch (r) {
185
+ case "id": return "TEXT";
186
+ case "text": return "TEXT";
187
+ case "integer": return "INTEGER";
188
+ case "real": return "DOUBLE PRECISION";
189
+ case "boolean": return "BOOLEAN";
190
+ case "timestamp": return "TIMESTAMPTZ";
191
+ case "date": return "DATE";
192
+ case "json": return "JSONB";
193
+ case "bytes": return "BYTEA";
194
+ case "reference": return "TEXT";
195
+ case "vector": return "VECTOR";
196
+ case "enum": return t.enumName ?? "TEXT";
197
+ case "array": return "TEXT[]";
198
+ case "interval": return "INTERVAL";
199
+ }
200
+ }, fe = (t, n) => {
201
+ if (!t.hasDefault || t.defaultFactory !== void 0) return null;
202
+ let r = t.defaultValue;
203
+ 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, "''")}'` : typeof r == "object" && r && !Array.isArray(r) ? k(r, n) : null;
204
+ }, k = (e, t) => {
205
+ let n = JSON.stringify(e).replace(/'/g, "''");
206
+ return t === "postgres" ? `DEFAULT '${n}'::jsonb` : t === "mysql" || t === "mariadb" ? `DEFAULT (CAST('${n}' AS JSON))` : `DEFAULT '${n}'`;
207
+ }, A = (e, t) => {
208
+ switch (t) {
209
+ case "postgres": return `"${e}" BIGSERIAL PRIMARY KEY`;
210
+ case "mysql":
211
+ case "mariadb": return `\`${e}\` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY`;
212
+ case "mssql": return `[${e}] BIGINT IDENTITY(1,1) PRIMARY KEY`;
213
+ case "sqlite": return `"${e}" INTEGER PRIMARY KEY AUTOINCREMENT`;
214
+ case "turso": return `"${e}" INTEGER PRIMARY KEY`;
215
+ }
216
+ }, j = (e, t) => {
217
+ if (e === "restrict" && t === "mssql") return "NO ACTION";
218
+ switch (e) {
219
+ case "cascade": return "CASCADE";
220
+ case "restrict": return "RESTRICT";
221
+ case "setNull": return "SET NULL";
222
+ case "noAction": return "NO ACTION";
223
+ }
224
+ }, pe = (e, n, r) => r === null ? t(e, n) : `${t(r, n)}.${t(e, n)}`, me = 191, he = (e, n, r) => {
225
+ let i = t(e, r);
226
+ if (r !== "mysql" && r !== "mariadb") return i;
227
+ let a = n[e];
228
+ if (!a) return i;
229
+ let o = O(a, r).toUpperCase();
230
+ return o.endsWith("TEXT") || o.endsWith("BLOB") ? `${i}(${me})` : i;
231
+ }, ge = (e, t) => {
232
+ if (!e.generatedAs) return null;
233
+ let { expr: n, stored: r } = e.generatedAs;
234
+ if (t === "postgres") return r || D("[voltro:migrate] generated column requested as VIRTUAL but postgres only supports STORED — promoting"), `GENERATED ALWAYS AS (${n}) STORED`;
235
+ if (t === "mysql" || t === "mariadb") return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
236
+ if (t === "mssql") return `AS (${n})${r ? " PERSISTED" : ""}`;
237
+ 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.");
238
+ return `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
239
+ }, _e = (n, r, i, a, o = !1, s = !1) => {
240
+ if (r.type === "id" && r.idScheme?.kind === "numeric") return A(n, i);
241
+ let c = i === "mssql" && r.type === "text" && !r.generatedAs && r.maxLength === void 0 && a?.has(n) ? "NVARCHAR(450)" : O(r, i), l = [t(n, i), c];
242
+ r.type === "id" && !s && l.push("PRIMARY KEY");
243
+ let u = ge(r, i);
244
+ if (u) l.push(u);
245
+ else {
246
+ r.nullable || l.push("NOT NULL"), r.unique && r.type !== "id" && l.push("UNIQUE");
247
+ let e = fe(r, i);
248
+ e && l.push(e);
249
+ }
250
+ if (r.type === "reference" && r.references && !o) {
251
+ let e = r.references();
252
+ l.push(`REFERENCES ${t(e.tableName, i)} (${t("id", i)})`);
253
+ let n = j(r.onDelete ?? "restrict", i);
254
+ l.push(`ON DELETE ${n}`);
255
+ let a = j(r.refOnUpdate ?? "noAction", i);
256
+ a !== "NO ACTION" && l.push(`ON UPDATE ${a}`);
257
+ }
258
+ if (r.oneOf && r.oneOf.length > 0) {
259
+ let e = r.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
260
+ l.push(`CHECK (${t(n, i)} IN (${e}))`);
261
+ }
262
+ if (r.checks && r.checks.length > 0) for (let e of r.checks) l.push(`CHECK (${e})`);
263
+ if (r.type === "enum" && r.enumValues && r.enumValues.length > 0 && (i === "mssql" || e(i))) {
264
+ let e = r.enumValues.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
265
+ l.push(`CHECK (${t(n, i)} IN (${e}))`);
266
+ }
267
+ if (r.type === "json" || r.type === "array") {
268
+ let r = t(n, i);
269
+ e(i) ? l.push(`CHECK (${r} IS NULL OR json_valid(${r}))`) : i === "mssql" && l.push(`CHECK (${r} IS NULL OR ISJSON(${r}) = 1)`);
270
+ }
271
+ return l.join(" ");
272
+ }, ve = (e, n, r = null, i) => {
273
+ let a = /* @__PURE__ */ new Set();
274
+ for (let t of e.appliedIndexes ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
275
+ for (let t of e.appliedUniques ?? []) for (let e of t.fields) typeof e == "string" && a.add(e);
276
+ let o = e.appliedPrimaryKey ?? [], s = o.length > 0, c = Object.entries(e.fields).map(([e, t]) => ` ${_e(e, t, n, a, i?.has(e) ?? !1, s)}`).join(",\n"), l = (e.appliedUniques ?? []).map((r) => {
277
+ let i = r.fields.map((t) => he(t, e.fields, n)).join(", ");
278
+ return ` CONSTRAINT ${t(r.name, n)} UNIQUE (${i})`;
279
+ }), u = (e.appliedChecks ?? []).map((e) => ` CONSTRAINT ${t(e.name, n)} CHECK (${e.expr})`), d = [
280
+ ...s ? [` PRIMARY KEY (${o.map((t) => he(t, e.fields, n)).join(", ")})`] : [],
281
+ ...l,
282
+ ...u
283
+ ], f = d.length > 0 ? `${c},\n${d.join(",\n")}` : c, p = pe(e.tableName, n, r);
284
+ if (n === "mssql") {
285
+ let t = r === null ? e.tableName : `${r}.${e.tableName}`, n = `CREATE TABLE ${p} (\n${f}\n)`;
286
+ return `IF OBJECT_ID('${t.replace(/'/g, "''")}', 'U') IS NULL EXEC(N'${n.replace(/'/g, "''")}');`;
287
+ }
288
+ return [
289
+ `CREATE TABLE IF NOT EXISTS ${p} (`,
290
+ f,
291
+ ");"
292
+ ].join("\n");
293
+ }, ye = (e, n, r) => {
294
+ 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 = [];
295
+ 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;
296
+ }, be = (e, r, i = null) => {
297
+ let a = [], s = /* @__PURE__ */ new Set(), c = (e) => e.join("\0"), l = (e, t, i, a) => {
298
+ let o = {
299
+ using: "",
300
+ withSuffix: "",
301
+ skip: !1
302
+ };
303
+ if (i === void 0 || i === "btree") return o;
304
+ if (i === "gist") return r === "postgres" ? {
305
+ using: " USING GIST",
306
+ withSuffix: "",
307
+ skip: !1
308
+ } : (D(`[voltro:migrate] index '${e}' on '${t}': ${r} doesn't support GiST — falling back to btree. Spatial queries on this column will fall back to sequential scan.`), o);
309
+ if (i === "gin") return r === "postgres" ? {
310
+ using: " USING GIN",
311
+ withSuffix: "",
312
+ skip: !1
313
+ } : r === "mysql" || r === "mariadb" ? (D(`[voltro:migrate] gin index '${e}' on '${t}': ${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(...).`), {
314
+ using: "",
315
+ withSuffix: "",
316
+ skip: !0
317
+ }) : (D(`[voltro:migrate] gin index '${e}' on '${t}': ${r} has no GIN access method — falling back to btree. Containment/membership queries won't use this index efficiently.`), o);
318
+ if (i === "brin") return r === "postgres" ? {
319
+ using: " USING BRIN",
320
+ withSuffix: "",
321
+ skip: !1
322
+ } : (D(`[voltro:migrate] brin index '${e}' on '${t}': ${r} has no BRIN access method — falling back to btree (larger on disk, but the range scan still works).`), o);
323
+ if (i === "hnsw") {
324
+ if (r === "postgres") {
325
+ let e = a?.hnsw?.m ?? 16, t = a?.hnsw?.efConstruction ?? 64, r = a?.hnsw?.opclass ?? n(a?.hnsw?.distance);
326
+ return {
327
+ using: " USING hnsw",
328
+ withSuffix: ` WITH (m = ${e}, ef_construction = ${t})`,
329
+ opclass: r,
330
+ skip: !1
331
+ };
332
+ }
333
+ return D(`[voltro:migrate] hnsw index '${e}' on '${t}': ${r} has no pgvector / HNSW access method — skipping. Nearest-neighbour queries on this column fall back to a sequential scan.`), {
334
+ using: "",
335
+ withSuffix: "",
336
+ skip: !0
337
+ };
338
+ }
339
+ return o;
340
+ }, u = (t, n) => {
341
+ let i = t.map((t) => {
342
+ if (typeof t == "string") return he(t, e.fields, r);
343
+ if ("jsonPath" in t) {
344
+ let { column: e, path: n, numeric: i } = t.jsonPath;
345
+ return `(${o(e, n, r, { numeric: i })})`;
346
+ }
347
+ return `(${t.expr})`;
348
+ });
349
+ return n !== void 0 && i.length === 1 ? `${i[0]} ${n}` : i.join(", ");
350
+ }, d = (e, n, a, o, s, c = "") => {
351
+ let d = l(e, n, o, s);
352
+ if (d.skip) return "";
353
+ let f = u(a, d.opclass), p = `${d.withSuffix}${c}`, m = pe(n, r, i);
354
+ return r === "mssql" ? `IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = '${e}') CREATE INDEX ${t(e, r)} ON ${m}${d.using} (${f})${p};` : r === "mysql" ? `CREATE INDEX ${t(e, r)} ON ${m}${d.using} (${f})${p};` : `CREATE INDEX IF NOT EXISTS ${t(e, r)} ON ${m}${d.using} (${f})${p};`;
355
+ };
356
+ for (let n of e.appliedFullText ?? []) if (r === "postgres") {
357
+ let i = n.config ?? "english", o = `${n.name}_tsv`, s = n.columns.map((e) => {
358
+ let a = n.weights?.[e] ?? "A";
359
+ return `setweight(to_tsvector('${i}', coalesce(${t(e, r)}, '')), '${a}')`;
360
+ }).join(" || ");
361
+ a.push(`ALTER TABLE ${t(e.tableName, r)} ADD COLUMN IF NOT EXISTS ${t(o, r)} tsvector GENERATED ALWAYS AS (${s}) STORED;`), a.push(`CREATE INDEX IF NOT EXISTS ${t(n.name, r)} ON ${t(e.tableName, r)} USING GIN (${t(o, r)});`);
362
+ } else if (r === "mysql" || r === "mariadb") {
363
+ let i = n.columns.map((e) => t(e, r)).join(", ");
364
+ a.push(`CREATE FULLTEXT INDEX ${t(n.name, r)} ON ${t(e.tableName, r)} (${i});`);
365
+ } else if (r === "turso") throw Error(`@voltro/sql-turso: full-text index '${n.name}' on '${e.tableName}' is not supported — Turso's MVCC mode has no FTS5 virtual tables. Drop .fullTextIndex(), or use the 'sqlite' / 'postgres' dialect for this table.`);
366
+ else r === "sqlite" ? a.push(...ye(e.tableName, n, r)) : D(`[voltro:migrate] full-text index '${n.name}' on '${e.tableName}': ${r} uses a ranked LIKE search at query time (no native FTS catalog required).`);
367
+ for (let t of e.appliedIndexes) {
368
+ if ((r === "mariadb" || r === "mssql") && t.fields.some((e) => typeof e != "string" && "jsonPath" in e)) {
369
+ D(`[voltro:migrate] json-path index '${t.name}' on '${e.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(...).`);
370
+ continue;
371
+ }
372
+ let n = "";
373
+ t.where !== void 0 && t.where.length > 0 && (r === "mysql" || r === "mariadb" ? D(`[voltro:migrate] partial index '${t.name}' on '${e.tableName}': ${r} does not support WHERE clauses on indexes — emitting a full index`) : n = ` WHERE ${t.where}`);
374
+ let i = d(t.name, e.tableName, t.fields, t.kind, t.kindOptions, n);
375
+ i !== "" && a.push(i), t.fields.every((e) => typeof e == "string") && s.add(c(t.fields));
376
+ }
377
+ for (let [t, n] of Object.entries(e.fields)) {
378
+ if (n.type !== "reference" || n.fkAutoIndex === !1 || s.has(c([t]))) continue;
379
+ let r = `${e.tableName}_${t}_idx`;
380
+ a.push(d(r, e.tableName, [t])), s.add(c([t]));
381
+ }
382
+ return a.join("\n");
383
+ }, xe = "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;", Se = (e) => `
384
+ ALTER TABLE "${e.tableName}" REPLICA IDENTITY FULL;
385
+ DROP TRIGGER IF EXISTS framework_changes_${e.tableName} ON "${e.tableName}";
386
+ CREATE TRIGGER framework_changes_${e.tableName}
387
+ AFTER INSERT OR UPDATE OR DELETE ON "${e.tableName}"
388
+ FOR EACH ROW EXECUTE FUNCTION framework_notify_change();
389
+ `.trim(), Ce = (e) => e.some((e) => Object.values(e.fields).some((e) => e.type === "vector")), we = (e) => e.some((e) => Object.values(e.fields).some((e) => e.spatial !== void 0)), Te = (e) => {
390
+ let t = new Map(e.map((e) => [e.tableName, e])), n = y(e.map((e) => e.tableName), (e) => {
391
+ let n = t.get(e);
392
+ return n ? Object.entries(n.fields).flatMap(([e, n]) => {
393
+ if (n.type !== "reference" || !n.references) return [];
394
+ let r = n.references().tableName;
395
+ return t.has(r) ? [{
396
+ column: e,
397
+ target: r
398
+ }] : [];
399
+ }) : [];
400
+ }), r = [];
401
+ for (let t of e) for (let [e, i] of Object.entries(t.fields)) i.type !== "reference" || !i.references || n.has(v(t.tableName, e)) && r.push({
402
+ table: t.tableName,
403
+ column: e,
404
+ targetTable: i.references().tableName,
405
+ onDelete: i.onDelete ?? "restrict",
406
+ onUpdate: i.refOnUpdate ?? "noAction"
407
+ });
408
+ let i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), o = [], s = (e) => {
409
+ if (!(i.has(e.tableName) || a.has(e.tableName))) {
410
+ a.add(e.tableName);
411
+ for (let [r, i] of Object.entries(e.fields)) {
412
+ if (i.type !== "reference" || !i.references || n.has(v(e.tableName, r))) continue;
413
+ let a = i.references();
414
+ if (a.tableName === e.tableName) continue;
415
+ let o = t.get(a.tableName);
416
+ o && s(o);
417
+ }
418
+ a.delete(e.tableName), i.add(e.tableName), o.push(e);
419
+ }
420
+ };
421
+ for (let t of e) s(t);
422
+ return {
423
+ sorted: o,
424
+ cyclic: r
425
+ };
426
+ }, Ee = (e, n, r = null) => {
427
+ let i = (e) => r ? `${t(r, n)}.${t(e, n)}` : t(e, n), a = `${e.table}_${e.column}_fkey`, o = j(e.onDelete, n), s = j(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}`;
428
+ switch (n) {
429
+ case "postgres": return [
430
+ "DO $$ BEGIN",
431
+ " IF NOT EXISTS (SELECT 1 FROM pg_constraint",
432
+ ` WHERE conname = '${a}' AND conrelid = '${r ? `${r}.` : ""}${e.table}'::regclass) THEN`,
433
+ ` ALTER TABLE ${i(e.table)} ${l(!1)};`,
434
+ " END IF;",
435
+ "END $$;"
436
+ ].join("\n");
437
+ case "mssql": return `IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = '${a}') ALTER TABLE ${i(e.table)} ${l(!1)};`;
438
+ case "mariadb": return `ALTER TABLE ${i(e.table)} ${l(!0)};`;
439
+ default: return `ALTER TABLE ${i(e.table)} ${l(!1)};`;
440
+ }
441
+ }, De = (t, n) => {
442
+ let r = /* @__PURE__ */ new Map();
443
+ if (e(n)) return r;
444
+ for (let e of t) {
445
+ let t = r.get(e.table) ?? /* @__PURE__ */ new Set();
446
+ t.add(e.column), r.set(e.table, t);
447
+ }
448
+ return r;
449
+ }, Oe = (e, t) => {
450
+ if (t !== "postgres") return "";
451
+ let n = /* @__PURE__ */ new Map();
452
+ for (let t of e) for (let e of Object.values(t.fields)) {
453
+ if (e.type !== "enum" || !e.enumName || !e.enumValues) continue;
454
+ let t = n.get(e.enumName);
455
+ if (t && t.length !== e.enumValues.length) throw Error(`dbEnum '${e.enumName}' declared with conflicting value sets across tables. Define it once and re-use the handle.`);
456
+ n.set(e.enumName, e.enumValues);
457
+ }
458
+ if (n.size === 0) return "";
459
+ let r = [];
460
+ for (let [e, t] of n) {
461
+ let n = t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
462
+ 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 $$;`);
463
+ }
464
+ return r.join("\n\n");
465
+ }, ke = (e, t) => {
466
+ if (t !== "postgres") return "";
467
+ let n = /* @__PURE__ */ new Set();
468
+ for (let t of e) for (let e of Object.values(t.fields)) e.type === "enum" && e.enumName && n.add(e.enumName);
469
+ let r = [];
470
+ for (let e of n) for (let { from: t, to: n } of c(e)) {
471
+ let i = e.replace(/'/g, "''"), a = t.replace(/'/g, "''"), o = n.replace(/'/g, "''");
472
+ r.push(`DO \$\$
473
+ DECLARE
474
+ type_oid oid;
475
+ BEGIN
476
+ 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 $$;`);
477
+ }
478
+ return r.join("\n\n");
479
+ }, Ae = (e) => {
480
+ let t = [], n = [];
481
+ for (let i of e) r(i) ? n.push(i) : t.push(i);
482
+ return {
483
+ tables: t,
484
+ views: n
485
+ };
486
+ }, M = (t, n) => {
487
+ let { tables: r, views: a } = Ae(t), { sorted: o, cyclic: s } = Te(r), c = De(s, n), l = [];
488
+ n === "postgres" && Ce(o) && l.push("CREATE EXTENSION IF NOT EXISTS vector;"), n === "postgres" && we(o) && l.push("CREATE EXTENSION IF NOT EXISTS postgis;");
489
+ let u = ke(o, n);
490
+ u && l.push(u);
491
+ let d = Oe(o, n);
492
+ d && l.push(d);
493
+ for (let e of o) l.push(ve(e, n, null, c.get(e.tableName)));
494
+ if (!e(n)) for (let e of s) l.push(Ee(e, n));
495
+ for (let e of o) {
496
+ let t = be(e, n);
497
+ t && l.push(t);
498
+ }
499
+ let f = o.filter((e) => e.isReactive);
500
+ if (f.length > 0 && n === "postgres") {
501
+ l.push(xe);
502
+ for (let e of f) l.push(Se(e));
503
+ }
504
+ for (let e of a) l.push(i(e, n));
505
+ return l.join("\n\n") + "\n";
506
+ }, je = (e, n, r) => {
507
+ let i = t(e, n);
508
+ switch (n) {
509
+ case "postgres": return `CREATE SCHEMA IF NOT EXISTS ${i};`;
510
+ case "mysql":
511
+ case "mariadb": return `CREATE DATABASE IF NOT EXISTS ${i};`;
512
+ case "mssql": return `IF SCHEMA_ID('${e.replace(/'/g, "''")}') IS NULL EXEC(N'CREATE SCHEMA ${i.replace(/'/g, "''")}');`;
513
+ case "turso":
514
+ case "sqlite": return `ATTACH DATABASE '${(r ?? `${e}.db`).replace(/'/g, "''")}' AS ${i};`;
515
+ }
516
+ }, Me = (n, r, i, a) => {
517
+ let o = je(i, r, a), s = t(i, r);
518
+ if (r === "postgres") return `${o}\n\nSET search_path TO ${s};\n\n${M(n, r)}`;
519
+ if (r === "mysql" || r === "mariadb") return `${o}\n\nUSE ${s};\n\n${M(n, r)}`;
520
+ let { sorted: c, cyclic: l } = Te(n), u = De(l, r), d = [o];
521
+ for (let e of c) d.push(ve(e, r, i, u.get(e.tableName)));
522
+ if (!e(r)) for (let e of l) d.push(Ee(e, r, i));
523
+ for (let e of c) {
524
+ let t = be(e, r, i);
525
+ t && d.push(t);
526
+ }
527
+ return d.join("\n\n") + "\n";
528
+ }, Ne = (e, n) => {
529
+ if (n !== "postgres") return M(e, n);
530
+ let { sorted: r, cyclic: i } = Te(e), a = De(i, n), o = [], s = ke(r, n);
531
+ s && o.push(s);
532
+ let c = Oe(r, n);
533
+ c && o.push(c);
534
+ for (let e of r) o.push(ve(e, n, null, a.get(e.tableName)));
535
+ for (let e of i) o.push(Ee(e, n));
536
+ for (let e of r) {
537
+ let r = Object.entries(e.fields);
538
+ if (r.length === 0) continue;
539
+ let i = r.map(([r, i]) => {
540
+ let o = _e(r, i, n, void 0, a.get(e.tableName)?.has(r) ?? !1);
541
+ return `ALTER TABLE ${t(e.tableName, n)} ADD COLUMN IF NOT EXISTS ${o};`;
542
+ });
543
+ o.push(i.join("\n"));
544
+ }
545
+ for (let e of r) {
546
+ let t = be(e, n);
547
+ t && o.push(t);
548
+ }
549
+ let l = r.filter((e) => e.isReactive);
550
+ if (l.length > 0) {
551
+ o.push(xe);
552
+ for (let e of l) o.push(Se(e));
553
+ }
554
+ return o.join("\n\n") + "\n";
555
+ }, Pe = (e, t = "postgres") => d.gen(function* () {
556
+ let n = yield* p.SqlClient;
557
+ yield* E(n, Le(n, M(e, t), t)).pipe(d.orDie);
558
+ }), Fe = (e, t) => {
559
+ let n = t.cause ?? {};
560
+ return (n.errno === 1061 || n.code === "ER_DUP_KEYNAME") && /^\s*CREATE\s+(UNIQUE\s+|FULLTEXT\s+)?INDEX\b/i.test(e);
561
+ }, Ie = (e) => d.gen(function* () {
562
+ let t = yield* p.SqlClient;
563
+ for (let n of Re(e)) process.env.VOLTRO_MIGRATE_DEBUG === "1" && de.debug(`EXEC: ${n.replace(/\s+/g, " ").slice(0, 180)}`), yield* t.unsafe(n).pipe(d.catchIf((e) => Fe(n, e), () => d.void), d.tapError((e) => d.sync(() => {
564
+ de.error(_("migrate: statement failed", n, e, 200));
565
+ })), d.orDieWith((e) => Error(_("migrate: statement failed", n, e, 400).trim())));
566
+ }), Le = (e, t, n) => (n === "turso" ? Ie(t) : e.withTransaction(Ie(t))).pipe(d.orDie), Re = (e) => {
567
+ let t = [], n = "", r = !1;
568
+ for (let i = 0; i < e.length; i++) {
569
+ if (e.slice(i, i + 2) === "$$") {
570
+ r = !r, n += "$$", i += 1;
571
+ continue;
572
+ }
573
+ let a = e[i];
574
+ if (a === ";" && !r) {
575
+ let e = n.trim();
576
+ e.length > 0 && t.push(e), n = "";
577
+ } else n += a;
578
+ }
579
+ let i = n.trim();
580
+ return i.length > 0 && t.push(i), t;
581
+ }, ze = async (e, t, n = "postgres") => {
582
+ await d.runPromise(Pe(e, n).pipe(d.provide(t)));
583
+ }, Be = (e, t, n = "postgres") => d.gen(function* () {
584
+ let r = Me(e, n, t), i = yield* p.SqlClient;
585
+ yield* E(i, Le(i, r, n)).pipe(d.orDie);
586
+ }), Ve = async (e, t, n, r = "postgres") => {
587
+ await d.runPromise(Be(e, t, r).pipe(d.provide(n)));
588
+ }, He = async (e, t, n = "postgres") => {
589
+ await d.runPromise(d.gen(function* () {
590
+ let t = Ne(e, n), r = yield* p.SqlClient;
591
+ yield* E(r, Le(r, t, n)).pipe(d.orDie);
592
+ }).pipe(d.provide(t)));
593
+ }, Ue = (e) => {
594
+ if (e == null) return e;
595
+ if (Array.isArray(e)) return e.map(Ue);
596
+ if (typeof e != "object") return e;
597
+ let t = {};
598
+ for (let n of Object.keys(e).sort()) {
599
+ let r = e[n];
600
+ r !== void 0 && (t[n] = Ue(r));
601
+ }
602
+ return t;
603
+ }, We = (e) => {
604
+ if (!e.idScheme) return e;
605
+ let { idScheme: t, ...n } = e;
606
+ return n;
607
+ }, Ge = (e) => [...e].map(We).sort((e, t) => e.name.localeCompare(t.name)), Ke = (e) => [...e].sort((e, t) => e.name.localeCompare(t.name)), qe = (e) => [...e].map((e) => ({
608
+ name: e.name,
609
+ columns: Ge(e.columns),
610
+ indexes: Ke(e.indexes)
611
+ })).sort((e, t) => e.name.localeCompare(t.name)), N = (e) => {
612
+ let t = { tables: qe(e.tables) }, n = JSON.stringify(Ue(t));
613
+ return m("sha256").update(n).digest("hex");
614
+ }, P = (e) => e.slice(0, 16), Je = (e, t) => {
615
+ let n = t.references ? {
616
+ table: t.references().tableName,
617
+ column: "id",
618
+ ...t.onDelete ? { onDelete: t.onDelete } : {},
619
+ ...t.refOnUpdate ? { onUpdate: t.refOnUpdate } : {},
620
+ ...t.orphanPolicy ? { orphanPolicy: t.orphanPolicy } : {}
621
+ } : void 0;
622
+ return {
623
+ name: e,
624
+ type: t.type,
625
+ nullable: t.generatedAs ? !0 : t.nullable,
626
+ unique: t.unique,
627
+ hasDefault: t.hasDefault,
628
+ ...t.hasDefault && t.defaultValue !== void 0 ? { defaultValue: t.defaultValue } : {},
629
+ ...n ? { references: n } : {},
630
+ ...t.oneOf && t.oneOf.length > 0 ? { oneOf: t.oneOf } : {},
631
+ ...t.idScheme ? { idScheme: { kind: t.idScheme.kind } } : {},
632
+ ...t.rawDdl === void 0 ? {} : { rawDdl: t.rawDdl },
633
+ ...t.precision === void 0 ? {} : { precision: t.precision },
634
+ ...t.scale === void 0 ? {} : { scale: t.scale },
635
+ ...t.generatedAs ? { generatedAs: {
636
+ expr: t.generatedAs.expr,
637
+ stored: t.generatedAs.stored
638
+ } } : {},
639
+ ...t.narrowedFrom ? { narrowedFrom: {
640
+ from: t.narrowedFrom.from,
641
+ ...t.narrowedFrom.using === void 0 ? {} : { using: t.narrowedFrom.using }
642
+ } } : {},
643
+ ...t.sensitive ? { sensitive: t.sensitive } : t.encrypted && !t.safe ? { sensitive: { class: "secret" } } : {},
644
+ ...t.safe ? { safe: !0 } : {}
645
+ };
646
+ }, Ye = (e) => {
647
+ let t = [], n = /* @__PURE__ */ new Set(), r = (e) => {
648
+ n.has(e.name) || (n.add(e.name), t.push(e));
649
+ }, i = e.appliedPrimaryKey ?? [];
650
+ i.length > 0 ? r({
651
+ name: `${e.tableName}_pkey`,
652
+ table: e.tableName,
653
+ columns: [...i],
654
+ unique: !0
655
+ }) : e.fields.id && r({
656
+ name: `${e.tableName}_pkey`,
657
+ table: e.tableName,
658
+ columns: ["id"],
659
+ unique: !0
660
+ });
661
+ let o = e.appliedIndexes ?? [];
662
+ for (let t of o) {
663
+ let n = t.fields.map((e) => typeof e == "string" ? e : "jsonPath" in e ? `(json:${e.jsonPath.column}->${e.jsonPath.path.join(".")}${e.jsonPath.numeric ? "::num" : ""})` : `(${e.expr})`), i = t.fields.some((e) => typeof e != "string");
664
+ r({
665
+ name: t.name,
666
+ table: e.tableName,
667
+ columns: n,
668
+ unique: !1,
669
+ ...i ? { expression: !0 } : {}
670
+ });
671
+ }
672
+ let s = e.appliedUniques ?? [];
673
+ for (let t of s) t.fields.length < 2 || r({
674
+ name: t.name,
675
+ table: e.tableName,
676
+ columns: t.fields,
677
+ unique: !0
678
+ });
679
+ let c = /* @__PURE__ */ new Set();
680
+ for (let e of o) e.fields.every((e) => typeof e == "string") && c.add(e.fields.join("\0"));
681
+ for (let [t, n] of Object.entries(e.fields)) {
682
+ let i = n;
683
+ if (i.dropped || !i.references || i.fkAutoIndex === !1 || c.has(t)) continue;
684
+ let o = `${e.tableName}_${t}_idx`;
685
+ a(e.tableName, o, !0, [t]), r({
686
+ name: o,
687
+ table: e.tableName,
688
+ columns: [t],
689
+ unique: !1
690
+ });
691
+ }
692
+ return t;
693
+ }, Xe = (e) => {
694
+ let t = new Set((e.appliedUniques ?? []).filter((e) => e.fields.length === 1).map((e) => e.fields[0])), n = [];
695
+ for (let [r, i] of Object.entries(e.fields)) {
696
+ if (i.dropped) continue;
697
+ let e = Je(r, i);
698
+ n.push(t.has(r) ? {
699
+ ...e,
700
+ unique: !0
701
+ } : e);
702
+ }
703
+ let r = e.appliedPrimaryKey ?? [];
704
+ return {
705
+ name: e.tableName,
706
+ columns: n,
707
+ indexes: Ye(e),
708
+ ...r.length > 0 ? { primaryKey: [...r] } : {}
709
+ };
710
+ }, Ze = (e) => {
711
+ let t = /* @__PURE__ */ new Map();
712
+ for (let n of e) for (let e of n.indexes) {
713
+ let r = t.get(e.name);
714
+ 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}').`);
715
+ t.set(e.name, n.name);
716
+ }
717
+ }, F = (e) => {
718
+ let t = e.map(Xe);
719
+ return Ze(t), { tables: t };
720
+ }, Qe = /* @__PURE__ */ new Set(["voltro_isr_cache"]), $e = (e) => Qe.has(e) || e.startsWith("_voltro_") || e.startsWith("_cloud_") || e.startsWith("cluster_"), et = {
721
+ postgres: !0,
722
+ mysql: !0,
723
+ mariadb: !0,
724
+ mssql: !0,
725
+ sqlite: !0
726
+ }, tt = {
727
+ postgres: !0,
728
+ mysql: !1,
729
+ mariadb: !1,
730
+ mssql: !0,
731
+ sqlite: !0
732
+ }, nt = (e) => {
733
+ switch (e) {
734
+ case "add-column":
735
+ case "drop-column":
736
+ case "rename-column":
737
+ case "alter-column-nullability":
738
+ case "alter-column-type":
739
+ case "add-foreign-key":
740
+ case "add-unique":
741
+ case "add-unique-composite":
742
+ case "add-check": return tt;
743
+ default: return et;
744
+ }
745
+ }, rt = (e, t) => {
746
+ let n = new Map(t.tables.map((e) => [e.name, e]));
747
+ return new Map(e.map((e) => [e.tableName, {
748
+ table: e,
749
+ snapshot: n.get(e.tableName),
750
+ columnDefs: e.fields
751
+ }]));
752
+ }, it = (e) => (t, n) => t.name === e ? -1 : n.name === e ? 1 : t.name.localeCompare(n.name), I = (e) => {
753
+ if (typeof e != "object" || !e) return JSON.stringify(e);
754
+ if (Array.isArray(e)) return `[${e.map(I).join(",")}]`;
755
+ let t = e;
756
+ return `{${Object.keys(t).sort().map((e) => `${JSON.stringify(e)}:${I(t[e])}`).join(",")}}`;
757
+ }, at = (e) => {
758
+ if (!e.hasDefault || e.defaultValue === void 0 || e.defaultValue === null) return null;
759
+ let t = e.defaultValue;
760
+ if (typeof t == "boolean") return t ? "__BOOL_TRUE__" : "__BOOL_FALSE__";
761
+ if (typeof t == "number") return String(t);
762
+ if (typeof t != "string") return I(t);
763
+ let n = t.trim(), r = n.toLowerCase().replace(/\s+/g, "");
764
+ if (r === "now" || r === "now()" || /^current_timestamp(\(\d*\))?$/.test(r) || r === "sysutcdatetime()" || r === "sysdatetime()" || r === "getutcdate()" || r === "getdate()") return "__NOW__";
765
+ 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);
766
+ if (o) try {
767
+ return I(JSON.parse(o[1]));
768
+ } catch {}
769
+ if (a.startsWith("{") || a.startsWith("[")) try {
770
+ return I(JSON.parse(a));
771
+ } catch {}
772
+ return /^-?\d+(\.\d+)?$/.test(a) ? String(Number(a)) : a;
773
+ }, ot = (e, t) => {
774
+ let n = at(e), r = at(t);
775
+ if (n === r) return !0;
776
+ let i = (e) => e === "1" || e === "true" ? "__BOOL_TRUE__" : e === "0" || e === "false" ? "__BOOL_FALSE__" : e;
777
+ return i(n) === i(r);
778
+ }, L = (e) => {
779
+ if (!e) return null;
780
+ let t = (e) => e === "restrict" ? "noAction" : e;
781
+ return {
782
+ table: e.table,
783
+ column: e.column,
784
+ onDelete: t(e.onDelete),
785
+ onUpdate: t(e.onUpdate)
786
+ };
787
+ }, st = (e, t) => {
788
+ let n = e && e.length > 0 ? e : void 0, r = t && t.length > 0 ? t : void 0;
789
+ if (!n && !r) return !0;
790
+ if (!n || !r || n.length !== r.length) return !1;
791
+ let i = [...n].sort(), a = [...r].sort();
792
+ return i.every((e, t) => e === a[t]);
793
+ }, ct = (e, t) => e.type === t.type && e.nullable === t.nullable && e.unique === t.unique && ot(e, t) && JSON.stringify(L(e.references)) === JSON.stringify(L(t.references)) && st(e.oneOf, t.oneOf), lt = (e, t) => t.oneOf && t.oneOf.length > 0 ? R({
794
+ kind: "add-check",
795
+ table: e,
796
+ column: t.name,
797
+ values: t.oneOf
798
+ }, "safe", `enum-membership CHECK on ${e}.${t.name}`) : void 0, ut = (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) => {
799
+ let n = new Map(t.columns.map((e) => [e.name, e])), r = new Map(e.columns.map((e) => [e.name, e])), i = [], a = [], o = [];
800
+ for (let t of e.columns) {
801
+ let e = n.get(t.name);
802
+ if (!e) {
803
+ i.push(t);
804
+ continue;
805
+ }
806
+ ct(t, e) || o.push({
807
+ declared: t,
808
+ live: e
809
+ });
810
+ }
811
+ for (let e of t.columns) r.has(e.name) || a.push(e);
812
+ return {
813
+ added: i,
814
+ removed: a,
815
+ changed: o
816
+ };
817
+ }, ft = (e, t) => {
818
+ let n = new Map(t.indexes.map((e) => [e.name, e])), r = new Map(e.indexes.map((e) => [e.name, e])), i = [], a = [];
819
+ for (let t of e.indexes) {
820
+ let e = n.get(t.name);
821
+ (!e || !ut(t, e)) && i.push(t);
822
+ }
823
+ for (let e of t.indexes) r.has(e.name) || a.push(e);
824
+ return {
825
+ added: i,
826
+ removed: a
827
+ };
828
+ }, R = (e, t, n, r) => ({
829
+ op: e,
830
+ classification: t,
831
+ atomicByDialect: nt(e.kind),
832
+ ...n ? { reason: n } : {},
833
+ ...r ? { blocked: r } : {}
834
+ }), pt = (e, t, n) => {
835
+ let r = {
836
+ kind: "add-column",
837
+ table: e,
838
+ column: t
839
+ };
840
+ 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` });
841
+ }, mt = (e, t, n) => {
842
+ let r = {
843
+ kind: "drop-column",
844
+ table: e,
845
+ column: t.name
846
+ };
847
+ 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` });
848
+ }, ht = (e, t, n, r) => R({
849
+ kind: "create-table",
850
+ table: e,
851
+ columns: t,
852
+ indexes: n,
853
+ ...r && r.length > 0 ? { primaryKey: r } : {}
854
+ }, "safe", "new table — no data to preserve"), gt = (e) => R({
855
+ kind: "drop-table",
856
+ table: e
857
+ }, "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" }), _t = 5e4, vt = (e, t, n, r) => {
858
+ let i = (n ?? 0) >= r, a;
859
+ return a = t.unique ? t.columns.length === 1 ? {
860
+ kind: "add-unique",
861
+ table: e,
862
+ column: t.columns[0]
863
+ } : {
864
+ kind: "add-unique-composite",
865
+ table: e,
866
+ name: t.name,
867
+ fields: t.columns
868
+ } : {
869
+ kind: "add-index",
870
+ table: e,
871
+ index: t
872
+ }, 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");
873
+ }, yt = (e, t) => t.unique && t.columns.length > 1 ? R({
874
+ kind: "drop-unique-composite",
875
+ table: e,
876
+ name: t.name
877
+ }, "safe", "drop composite UNIQUE constraint (no data loss — constraint is derived metadata)") : R({
878
+ kind: "drop-index",
879
+ table: e,
880
+ index: t.name
881
+ }, "safe", "drop index (no data loss — index is derived data)"), bt = (e, t) => {
882
+ if (e === "reference") return "text";
883
+ switch (t) {
884
+ case "sqlite":
885
+ case "turso": return e === "timestamp" || e === "date" || e === "json" ? "text" : e === "boolean" ? "integer" : e === "decimal" ? "text" : e === "bigint" ? "integer" : e;
886
+ case "mssql": return e === "json" ? "text" : e;
887
+ default: return e;
888
+ }
889
+ }, xt = (e, t, n, r, i, a) => {
890
+ let o = [];
891
+ if (t.nullable !== n.nullable) {
892
+ let n = {
893
+ kind: "alter-column-nullability",
894
+ table: e,
895
+ column: t.name,
896
+ toNullable: t.nullable
897
+ };
898
+ o.push(t.nullable ? R(n, "safe", `loosen ${e}.${t.name} to nullable`) : R(n, "needs-backfill", `tighten ${e}.${t.name} to NOT NULL — existing rows must already be non-null`));
899
+ }
900
+ if (t.unique !== n.unique) if (t.unique) {
901
+ let n = {
902
+ kind: "add-unique",
903
+ table: e,
904
+ column: t.name
905
+ }, r = (i ?? 0) >= a;
906
+ o.push(r ? R(n, "online-required", `online unique build on ${i} rows — CONCURRENTLY / INPLACE / WITH(ONLINE=ON) depending on dialect`) : R(n, "safe", `add unique constraint on ${e}.${t.name} — existing rows must already be distinct (else the DB rejects at migrate)`));
907
+ } else o.push(R({
908
+ kind: "drop-unique",
909
+ table: e,
910
+ column: t.name
911
+ }, "safe", `drop unique constraint on ${e}.${t.name} — constraint is derived metadata, no data loss`));
912
+ if (bt(t.type, r) !== bt(n.type, r)) {
913
+ let r = t.narrowedFrom;
914
+ if (r && r.from === n.type) {
915
+ let i = {
916
+ kind: "alter-column-type",
917
+ table: e,
918
+ column: t.name,
919
+ from: n.type,
920
+ to: t.type,
921
+ ...r.using === void 0 ? {} : { using: r.using }
922
+ };
923
+ o.push(R(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)")));
924
+ } else {
925
+ let r = {
926
+ kind: "alter-column-type",
927
+ table: e,
928
+ column: t.name,
929
+ from: n.type,
930
+ to: t.type
931
+ };
932
+ o.push(R(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` }));
933
+ }
934
+ }
935
+ if (!ot(t, n)) {
936
+ let n = {
937
+ kind: "alter-column-default",
938
+ table: e,
939
+ column: t.name,
940
+ hasDefault: t.hasDefault,
941
+ ...t.defaultValue === void 0 ? {} : { defaultValue: t.defaultValue }
942
+ };
943
+ o.push(R(n, "safe", `default change on ${e}.${t.name} affects only future inserts`));
944
+ }
945
+ if (!st(t.oneOf, n.oneOf)) {
946
+ n.oneOf && n.oneOf.length > 0 && o.push(R({
947
+ kind: "drop-check",
948
+ table: e,
949
+ column: t.name
950
+ }, "safe", `drop stale enum CHECK on ${e}.${t.name}`));
951
+ let r = lt(e, t);
952
+ r && o.push(r);
953
+ }
954
+ if (JSON.stringify(L(t.references)) !== JSON.stringify(L(n.references)) && (n.references && o.push(R({
955
+ kind: "drop-foreign-key",
956
+ table: e,
957
+ column: t.name
958
+ }, "safe", `drop FK on ${e}.${t.name} (→ ${n.references.table})`)), t.references)) {
959
+ let n = t.references.table, r = t.references.orphanPolicy ?? "fail", i = {
960
+ kind: "add-foreign-key",
961
+ table: e,
962
+ column: t.name,
963
+ targetTable: n,
964
+ targetColumn: t.references.column,
965
+ ...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
966
+ ...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
967
+ };
968
+ r === "null" && !t.nullable ? o.push(R(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(R({
969
+ ...i,
970
+ orphanPolicy: r
971
+ }, "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(R(i, "needs-backfill", `add FK ${e}.${t.name} → ${n} — existing rows must already reference a valid ${n} (else set orphanPolicy:'null'/'delete')`));
972
+ }
973
+ return o;
974
+ }, St = (e, t, n) => {
975
+ 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));
976
+ for (let [n, c] of Object.entries(t)) {
977
+ let t = c.renamedFrom;
978
+ t && o.has(t) && s.has(n) && (i.add(n), a.add(t), r.push(R({
979
+ kind: "rename-column",
980
+ table: e.tableName,
981
+ from: t,
982
+ to: n
983
+ }, "safe", `rename via \`.renamedFrom('${t}')\``)));
984
+ }
985
+ return {
986
+ ops: r,
987
+ consumedAddedNames: i,
988
+ consumedRemovedNames: a
989
+ };
990
+ }, Ct = (e) => {
991
+ let t = {
992
+ safe: 0,
993
+ needsDefault: 0,
994
+ needsBackfill: 0,
995
+ needsRenameAnnotation: 0,
996
+ lossy: 0,
997
+ onlineRequired: 0,
998
+ multiStep: 0,
999
+ blocked: 0
1000
+ };
1001
+ for (let n of e) switch (n.blocked && t.blocked++, n.classification) {
1002
+ case "safe":
1003
+ t.safe++;
1004
+ break;
1005
+ case "needs-default":
1006
+ t.needsDefault++;
1007
+ break;
1008
+ case "needs-backfill":
1009
+ t.needsBackfill++;
1010
+ break;
1011
+ case "needs-rename-annotation":
1012
+ t.needsRenameAnnotation++;
1013
+ break;
1014
+ case "lossy":
1015
+ t.lossy++;
1016
+ break;
1017
+ case "online-required":
1018
+ t.onlineRequired++;
1019
+ break;
1020
+ case "multi-step":
1021
+ t.multiStep++;
1022
+ break;
1023
+ }
1024
+ return t;
1025
+ }, wt = (e) => {
1026
+ let t = F(e.declared), n = rt(e.declared, t), r = new Map(e.live.tables.map((e) => [e.name, e])), i = e.onlineAfter ?? _t, a = [];
1027
+ for (let e of t.tables) if (!r.has(e.name)) {
1028
+ a.push(ht(e.name, e.columns, e.indexes, e.primaryKey));
1029
+ for (let t of e.columns) {
1030
+ let n = lt(e.name, t);
1031
+ n && a.push(n);
1032
+ }
1033
+ }
1034
+ let o = new Set(e.ignoreTables ?? []);
1035
+ for (let t of e.live.tables) n.has(t.name) || $e(t.name) || o.has(t.name) || a.push(gt(t.name));
1036
+ for (let o of t.tables) {
1037
+ let t = r.get(o.name);
1038
+ if (!t) continue;
1039
+ let s = n.get(o.name), c = dt(o, t), l = ft(o, t), u = St(s.table, s.columnDefs, c);
1040
+ a.push(...u.ops);
1041
+ for (let e of c.removed) {
1042
+ if (u.consumedRemovedNames.has(e.name)) continue;
1043
+ let t = s.columnDefs[e.name];
1044
+ a.push(mt(o.name, e, t));
1045
+ }
1046
+ for (let e of c.added) {
1047
+ if (u.consumedAddedNames.has(e.name)) continue;
1048
+ let t = s.columnDefs[e.name];
1049
+ a.push(pt(o.name, e, t));
1050
+ let n = lt(o.name, e);
1051
+ n && a.push(n);
1052
+ }
1053
+ for (let e of l.added) a.push(vt(o.name, e, t.rowCount, i));
1054
+ for (let e of l.removed) a.push(yt(o.name, e));
1055
+ for (let { declared: n, live: r } of c.changed) a.push(...xt(o.name, n, r, e.dialect, t.rowCount, i));
1056
+ }
1057
+ let s = new Set(a.flatMap((e) => e.op.kind === "create-table" ? [e.op.table] : [])), c = new Map(t.tables.map((e) => [e.name, e])), l = (e) => {
1058
+ let t = c.get(e);
1059
+ return t ? t.columns.flatMap((e) => e.references && s.has(e.references.table) ? [{
1060
+ column: e.name,
1061
+ target: e.references.table
1062
+ }] : []) : [];
1063
+ }, u = y([...s], l), d = [];
1064
+ for (let e of t.tables) if (s.has(e.name)) for (let t of e.columns) !t.references || !u.has(v(e.name, t.name)) || d.push(R({
1065
+ kind: "add-foreign-key",
1066
+ table: e.name,
1067
+ column: t.name,
1068
+ targetTable: t.references.table,
1069
+ targetColumn: t.references.column,
1070
+ ...t.references.onDelete ? { onDelete: t.references.onDelete } : {},
1071
+ ...t.references.onUpdate ? { onUpdate: t.references.onUpdate } : {}
1072
+ }, "safe", `deferred FK ${e.name}.${t.name} → ${t.references.table} — breaks a create-time table cycle`));
1073
+ if (u.size > 0) {
1074
+ let e = (e) => e.references ? Object.fromEntries(Object.entries(e).filter(([e]) => e !== "references")) : e;
1075
+ for (let t = 0; t < a.length; t += 1) {
1076
+ let n = a[t];
1077
+ if (n.op.kind !== "create-table") continue;
1078
+ let r = n.op;
1079
+ if (!r.columns.some((e) => u.has(v(r.table, e.name)))) continue;
1080
+ let i = r.columns.map((t) => u.has(v(r.table, t.name)) ? e(t) : t);
1081
+ a[t] = {
1082
+ ...n,
1083
+ op: {
1084
+ ...r,
1085
+ columns: i
1086
+ }
1087
+ };
1088
+ }
1089
+ a.push(...d);
1090
+ }
1091
+ let f = new Map(t.tables.map((e) => [e.name, e])), p = /* @__PURE__ */ new Map(), m = (e, t = /* @__PURE__ */ new Set()) => {
1092
+ let n = p.get(e);
1093
+ if (n !== void 0) return n;
1094
+ if (t.has(e)) return 0;
1095
+ let r = f.get(e);
1096
+ if (!r) return 0;
1097
+ let i = new Set(t).add(e), a = 0;
1098
+ for (let t of r.columns) {
1099
+ let n = t.references?.table;
1100
+ n && n !== e && !u.has(v(e, t.name)) && (a = Math.max(a, m(n, i) + 1));
1101
+ }
1102
+ return p.set(e, a), a;
1103
+ }, h = (e) => e === "create-table" ? 0 : e === "drop-table" ? 2 : 1, g = (e) => {
1104
+ let t = "table" in e ? e.table : "";
1105
+ return e.kind === "create-table" ? m(t) : e.kind === "drop-table" ? -m(t) : 0;
1106
+ }, ee = {
1107
+ "add-column": 0,
1108
+ "rename-column": 1,
1109
+ "alter-column-nullability": 2,
1110
+ "alter-column-type": 2,
1111
+ "alter-column-default": 2,
1112
+ "drop-index": 3,
1113
+ "drop-check": 3,
1114
+ "drop-unique": 3,
1115
+ "drop-unique-composite": 3,
1116
+ "drop-foreign-key": 3,
1117
+ "drop-column": 4,
1118
+ "add-index": 5,
1119
+ "add-unique": 5,
1120
+ "add-unique-composite": 5,
1121
+ "add-foreign-key": 5,
1122
+ "add-check": 5
1123
+ }, _ = (e) => ee[e] ?? 9, b = [...a].sort((e, t) => {
1124
+ let n = h(e.op.kind), r = h(t.op.kind);
1125
+ if (n !== r) return n - r;
1126
+ let i = g(e.op), a = g(t.op);
1127
+ if (i !== a) return i - a;
1128
+ let o = "table" in e.op ? e.op.table : "", s = "table" in t.op ? t.op.table : "";
1129
+ if (o !== s) return o.localeCompare(s);
1130
+ let c = _(e.op.kind), l = _(t.op.kind);
1131
+ return c === l ? e.op.kind.localeCompare(t.op.kind) : c - l;
1132
+ });
1133
+ return {
1134
+ operations: b,
1135
+ fromFingerprint: N(e.live),
1136
+ toFingerprint: N(t),
1137
+ summary: Ct(b)
1138
+ };
1139
+ }, Tt = (e) => {
1140
+ let t = /[`"[]?([A-Za-z_][A-Za-z0-9_]*)[`"\]]?\s*(?:in\b|=)/i.exec(e);
1141
+ if (!t) return null;
1142
+ let n = [...e.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
1143
+ return n.length === 0 ? null : {
1144
+ column: t[1],
1145
+ values: n
1146
+ };
1147
+ }, Et = (e, t) => {
1148
+ if (t === "vector") return "vector";
1149
+ switch (e) {
1150
+ case "text":
1151
+ case "character varying":
1152
+ case "varchar":
1153
+ case "uuid":
1154
+ case "character": return "text";
1155
+ case "integer":
1156
+ case "smallint": return "integer";
1157
+ case "bigint": return "bigint";
1158
+ case "double precision":
1159
+ case "real": return "real";
1160
+ case "numeric":
1161
+ case "decimal": return "decimal";
1162
+ case "boolean": return "boolean";
1163
+ case "bytea": return "bytes";
1164
+ case "timestamp without time zone":
1165
+ case "timestamp with time zone":
1166
+ case "timestamptz":
1167
+ case "timestamp": return "timestamp";
1168
+ case "date": return "date";
1169
+ case "json":
1170
+ case "jsonb": return "json";
1171
+ case "USER-DEFINED": return "text";
1172
+ default: return "text";
1173
+ }
1174
+ }, z = (e) => {
1175
+ switch (e.toUpperCase()) {
1176
+ case "CASCADE": return "cascade";
1177
+ case "RESTRICT": return "restrict";
1178
+ case "SET NULL": return "setNull";
1179
+ case "SET DEFAULT": return "noAction";
1180
+ default: return "noAction";
1181
+ }
1182
+ }, Dt = (e, t) => {
1183
+ let n = e !== void 0 && e !== "" ? Number(e) : NaN;
1184
+ return Number.isInteger(n) && n > 0 ? n : t;
1185
+ }, Ot = () => Dt(process.env.VOLTRO_INTROSPECT_BATCH, 20), kt = 300, At = () => {
1186
+ let e = process.env.VOLTRO_INTROSPECT_TIMEOUT_MS;
1187
+ return e !== void 0 && e.trim() === "0" ? 0 : Dt(e, 3e4);
1188
+ }, jt = (e, t) => {
1189
+ let n = Number.isFinite(t) && t >= 1 ? Math.floor(t) : 1, r = [];
1190
+ for (let t = 0; t < e.length; t += n) r.push(e.slice(t, t + n));
1191
+ return r;
1192
+ }, Mt = (e) => {
1193
+ let t = At(), n = d.gen(function* () {
1194
+ t > 0 && (yield* e.unsafe(`SET LOCAL statement_timeout = ${t}`));
1195
+ let n = (t) => e.unsafe("(" + t.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ") + ")"), r = (t) => e.unsafe(String(Math.max(0, Math.trunc(t)))), i = Ot(), a = (e, t) => d.gen(function* () {
1196
+ let r = [];
1197
+ for (let a of jt(e, i)) a.length !== 0 && r.push(...yield* t(n(a)));
1198
+ return r;
1199
+ }), o = [];
1200
+ for (let t = 0;; t += kt) {
1201
+ let n = yield* e`
1202
+ SELECT c.relname AS table_name,
1203
+ COALESCE(c.reltuples::bigint, 0) AS row_count
1204
+ FROM pg_class c
1205
+ JOIN pg_namespace n ON n.oid = c.relnamespace
1206
+ WHERE n.nspname = current_schema() AND c.relkind = 'r'
1207
+ ORDER BY c.relname
1208
+ LIMIT ${r(kt)} OFFSET ${r(t)}
1209
+ `;
1210
+ if (o.push(...n), n.length < kt) break;
1211
+ }
1212
+ let s = /* @__PURE__ */ new Set(), c = [];
1213
+ for (let e of o) s.has(e.table_name) || (s.add(e.table_name), c.push(e));
1214
+ let l = c.map((e) => e.table_name), u = yield* a(l, (t) => e`
1215
+ SELECT table_name, column_name, data_type, udt_name, is_nullable, column_default
1216
+ FROM information_schema.columns
1217
+ WHERE table_schema = current_schema() AND table_name IN ${t}
1218
+ ORDER BY table_name, ordinal_position
1219
+ `), f = yield* a(l, (t) => e`
1220
+ SELECT rel.relname AS table_name, att.attname AS column_name
1221
+ FROM pg_constraint con
1222
+ JOIN pg_class rel ON rel.oid = con.conrelid
1223
+ JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
1224
+ JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = ANY (con.conkey)
1225
+ WHERE con.contype = 'p' AND nsp.nspname = current_schema()
1226
+ AND rel.relname IN ${t}
1227
+ `), p = yield* a(l, (t) => e`
1228
+ SELECT rel.relname AS table_name, con.conname AS constraint_name,
1229
+ att.attname AS column_name, array_position(con.conkey, att.attnum) AS position
1230
+ FROM pg_constraint con
1231
+ JOIN pg_class rel ON rel.oid = con.conrelid
1232
+ JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
1233
+ JOIN pg_attribute att ON att.attrelid = rel.oid AND att.attnum = ANY (con.conkey)
1234
+ WHERE con.contype = 'u' AND nsp.nspname = current_schema() AND rel.relname IN ${t}
1235
+ `), m = yield* a(l, (t) => e`
1236
+ SELECT rel.relname AS table_name, att.attname AS column_name, pg_get_constraintdef(con.oid) AS def
1237
+ FROM pg_constraint con
1238
+ JOIN pg_class rel ON rel.oid = con.conrelid
1239
+ JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
1240
+ JOIN pg_attribute att ON att.attrelid = rel.oid AND att.attnum = con.conkey[1]
1241
+ WHERE con.contype = 'c' AND nsp.nspname = current_schema() AND array_length(con.conkey, 1) = 1
1242
+ AND rel.relname IN ${t}
1243
+ `), h = /* @__PURE__ */ new Map();
1244
+ for (let e of m) {
1245
+ let t = [...e.def.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
1246
+ t.length > 0 && h.set(`${e.table_name}.${e.column_name}`, t);
1247
+ }
1248
+ let g = yield* a(l, (t) => e`
1249
+ SELECT
1250
+ rel.relname AS source_table,
1251
+ att.attname AS source_column,
1252
+ frel.relname AS target_table,
1253
+ fatt.attname AS target_column,
1254
+ CASE con.confdeltype
1255
+ WHEN 'c' THEN 'CASCADE' WHEN 'r' THEN 'RESTRICT'
1256
+ WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT'
1257
+ ELSE 'NO ACTION' END AS delete_rule,
1258
+ CASE con.confupdtype
1259
+ WHEN 'c' THEN 'CASCADE' WHEN 'r' THEN 'RESTRICT'
1260
+ WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT'
1261
+ ELSE 'NO ACTION' END AS update_rule
1262
+ FROM pg_constraint con
1263
+ JOIN pg_class rel ON rel.oid = con.conrelid
1264
+ JOIN pg_class frel ON frel.oid = con.confrelid
1265
+ JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
1266
+ JOIN unnest(con.conkey) WITH ORDINALITY AS ck(attnum, ord) ON true
1267
+ JOIN unnest(con.confkey) WITH ORDINALITY AS fk(attnum, ord) ON fk.ord = ck.ord
1268
+ JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = ck.attnum
1269
+ JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = fk.attnum
1270
+ WHERE con.contype = 'f' AND nsp.nspname = current_schema()
1271
+ AND rel.relname IN ${t}
1272
+ ORDER BY rel.relname, con.conname, ck.ord
1273
+ `), ee = yield* a(l, (t) => e`
1274
+ WITH ix AS (
1275
+ SELECT
1276
+ c.relname AS table_name,
1277
+ i.relname AS index_name,
1278
+ ix2.indisunique AS is_unique,
1279
+ (0 = ANY (ix2.indkey::int[])) AS has_expression,
1280
+ a.attname AS column_name,
1281
+ array_position(ix2.indkey::int[], a.attnum) + 1 AS position
1282
+ FROM pg_index ix2
1283
+ JOIN pg_class i ON i.oid = ix2.indexrelid
1284
+ JOIN pg_class c ON c.oid = ix2.indrelid
1285
+ JOIN pg_namespace n ON n.oid = c.relnamespace
1286
+ LEFT JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY (ix2.indkey)
1287
+ LEFT JOIN pg_constraint con ON con.conindid = i.oid
1288
+ WHERE n.nspname = current_schema()
1289
+ AND NOT ix2.indisprimary
1290
+ AND con.conindid IS NULL
1291
+ AND c.relname IN ${t}
1292
+ )
1293
+ SELECT * FROM ix ORDER BY table_name, index_name, position
1294
+ `), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = /* @__PURE__ */ new Map();
1295
+ for (let e of u) {
1296
+ let t = _.get(e.table_name);
1297
+ t || (t = [], _.set(e.table_name, t)), t.push(e);
1298
+ }
1299
+ for (let e of f) {
1300
+ let t = v.get(e.table_name);
1301
+ t || (t = /* @__PURE__ */ new Set(), v.set(e.table_name, t)), t.add(e.column_name);
1302
+ }
1303
+ let C = /* @__PURE__ */ new Map();
1304
+ for (let e of p) {
1305
+ let t = `${e.table_name}${e.constraint_name}`, n = C.get(t);
1306
+ n || (n = {
1307
+ table: e.table_name,
1308
+ columns: []
1309
+ }, C.set(t, n)), n.columns.push({
1310
+ name: e.column_name,
1311
+ position: e.position
1312
+ });
1313
+ }
1314
+ for (let [e, t] of C) {
1315
+ let n = [...t.columns].sort((e, t) => e.position - t.position).map((e) => e.name);
1316
+ if (n.length === 1) {
1317
+ let e = y.get(t.table);
1318
+ e || (e = /* @__PURE__ */ new Set(), y.set(t.table, e)), e.add(n[0]);
1319
+ } else {
1320
+ let r = b.get(t.table);
1321
+ r || (r = [], b.set(t.table, r)), r.push({
1322
+ name: e.slice(e.indexOf("\0") + 1),
1323
+ table: t.table,
1324
+ columns: n,
1325
+ unique: !0
1326
+ });
1327
+ }
1328
+ }
1329
+ for (let e of g) {
1330
+ let t = x.get(e.source_table);
1331
+ t || (t = [], x.set(e.source_table, t)), t.push(e);
1332
+ }
1333
+ for (let e of ee) {
1334
+ let t = S.get(e.table_name);
1335
+ t || (t = /* @__PURE__ */ new Map(), S.set(e.table_name, t));
1336
+ let n = t.get(e.index_name);
1337
+ n || (n = [], t.set(e.index_name, n)), n.push(e);
1338
+ }
1339
+ let te = [];
1340
+ for (let e of c) {
1341
+ 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 = x.get(e.table_name) ?? [], o = new Map(a.map((e) => [e.source_column, e])), s = new Set(n.filter((e) => e.udt_name === "tsvector").map((e) => e.column_name)), c = n.filter((e) => !s.has(e.column_name)).map((t) => {
1342
+ 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" : Et(t.data_type, t.udt_name), c = a ? {
1343
+ table: a.target_table,
1344
+ column: a.target_column,
1345
+ onDelete: z(a.delete_rule),
1346
+ onUpdate: z(a.update_rule)
1347
+ } : void 0, l = h.get(`${e.table_name}.${t.column_name}`);
1348
+ return {
1349
+ name: t.column_name,
1350
+ type: s,
1351
+ nullable: t.is_nullable === "YES",
1352
+ unique: i.has(t.column_name) || n && t.column_name === "id",
1353
+ hasDefault: t.column_default !== null,
1354
+ ...t.column_default === null ? {} : { defaultValue: t.column_default },
1355
+ ...c ? { references: c } : {},
1356
+ ...l ? { oneOf: l } : {}
1357
+ };
1358
+ }), l = [], u = S.get(e.table_name);
1359
+ if (u) for (let [t, n] of u) {
1360
+ 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) => {
1361
+ let t = e.position;
1362
+ return r.has(t) ? !1 : (r.add(t), !0);
1363
+ });
1364
+ if (i.some((e) => s.has(e.column_name))) continue;
1365
+ let a = n.some((e) => e.has_expression);
1366
+ l.push({
1367
+ name: t,
1368
+ table: e.table_name,
1369
+ columns: i.map((e) => e.column_name),
1370
+ unique: n[0]?.is_unique ?? !1,
1371
+ ...a ? { expression: !0 } : {}
1372
+ });
1373
+ }
1374
+ for (let t of b.get(e.table_name) ?? []) l.push(t);
1375
+ r.size > 0 && l.push({
1376
+ name: `${e.table_name}_pkey`,
1377
+ table: e.table_name,
1378
+ columns: [...r],
1379
+ unique: !0
1380
+ });
1381
+ let d = Number(e.row_count ?? 0);
1382
+ te.push({
1383
+ name: e.table_name,
1384
+ columns: c,
1385
+ indexes: l,
1386
+ ...d > 0 ? { rowCount: d } : {}
1387
+ });
1388
+ }
1389
+ return { tables: te };
1390
+ });
1391
+ return (t > 0 ? e.withTransaction(n) : n).pipe(d.catchAll((e) => {
1392
+ let n = `${String(e)} ${String(e.cause ?? "")}`.toLowerCase();
1393
+ 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);
1394
+ }));
1395
+ }, Nt = (e, t) => {
1396
+ switch (e.toLowerCase()) {
1397
+ case "varchar":
1398
+ case "char":
1399
+ case "text":
1400
+ case "tinytext":
1401
+ case "mediumtext":
1402
+ case "longtext":
1403
+ case "enum": return "text";
1404
+ case "tinyint": return t.toLowerCase() === "tinyint(1)" ? "boolean" : "integer";
1405
+ case "int":
1406
+ case "integer":
1407
+ case "smallint":
1408
+ case "mediumint": return "integer";
1409
+ case "bigint": return "bigint";
1410
+ case "decimal":
1411
+ case "numeric": return "decimal";
1412
+ case "double":
1413
+ case "float":
1414
+ case "real": return "real";
1415
+ case "datetime":
1416
+ case "timestamp": return "timestamp";
1417
+ case "date": return "date";
1418
+ case "blob":
1419
+ case "tinyblob":
1420
+ case "mediumblob":
1421
+ case "longblob":
1422
+ case "binary":
1423
+ case "varbinary": return "bytes";
1424
+ case "json": return "json";
1425
+ default: return "text";
1426
+ }
1427
+ }, B = (e) => e.map((e) => {
1428
+ let t = e, n = {};
1429
+ for (let e of Object.keys(t)) n[e.toLowerCase()] = t[e];
1430
+ return n;
1431
+ }), Pt = (e) => d.gen(function* () {
1432
+ let t = B(yield* e`
1433
+ SELECT table_name, COALESCE(table_rows, 0) AS table_rows
1434
+ FROM information_schema.tables
1435
+ WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'
1436
+ ORDER BY table_name`), n = B(yield* e`
1437
+ SELECT table_name, column_name, data_type, column_type, is_nullable, column_default, column_key
1438
+ FROM information_schema.columns
1439
+ WHERE table_schema = DATABASE()
1440
+ ORDER BY table_name, ordinal_position`), r = B(yield* e`
1441
+ SELECT k.table_name AS source_table,
1442
+ k.column_name AS source_column,
1443
+ k.referenced_table_name AS target_table,
1444
+ k.referenced_column_name AS target_column,
1445
+ r.delete_rule, r.update_rule
1446
+ FROM information_schema.key_column_usage k
1447
+ JOIN information_schema.referential_constraints r
1448
+ ON k.constraint_name = r.constraint_name
1449
+ AND k.table_schema = r.constraint_schema
1450
+ WHERE k.table_schema = DATABASE() AND k.referenced_table_name IS NOT NULL`), i = B(yield* e`
1451
+ SELECT table_name, index_name, non_unique, column_name, seq_in_index
1452
+ FROM information_schema.statistics
1453
+ WHERE table_schema = DATABASE() AND index_name <> 'PRIMARY'
1454
+ ORDER BY table_name, index_name, seq_in_index`), a = B(yield* e`
1455
+ SELECT table_name, check_clause
1456
+ FROM information_schema.check_constraints
1457
+ WHERE constraint_schema = DATABASE()`.unprepared.pipe(d.orElseSucceed(() => []))), o = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
1458
+ for (let e of a) {
1459
+ let t = /json_valid\(`?([^`)]+)`?\)/i.exec(e.check_clause);
1460
+ if (t) {
1461
+ o.add(`${e.table_name}.${t[1]}`);
1462
+ continue;
1463
+ }
1464
+ let n = Tt(e.check_clause);
1465
+ n && s.set(`${e.table_name}.${n.column}`, n.values);
1466
+ }
1467
+ let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
1468
+ for (let e of n) {
1469
+ let t = c.get(e.table_name) ?? [];
1470
+ t.push(e), c.set(e.table_name, t);
1471
+ }
1472
+ for (let e of r) {
1473
+ let t = l.get(e.source_table) ?? [];
1474
+ t.push(e), l.set(e.source_table, t);
1475
+ }
1476
+ for (let e of i) {
1477
+ let t = u.get(e.table_name);
1478
+ t || (t = /* @__PURE__ */ new Map(), u.set(e.table_name, t));
1479
+ let n = t.get(e.index_name) ?? [];
1480
+ n.push(e), t.set(e.index_name, n);
1481
+ }
1482
+ let f = [];
1483
+ for (let e of t) {
1484
+ 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);
1485
+ if (d) for (let e of d.values()) e.length === 1 && e[0].non_unique === 0 && a.add(e[0].column_name);
1486
+ let p = t.map((t) => {
1487
+ 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" : Nt(t.data_type, t.column_type), u = c ? {
1488
+ table: c.target_table,
1489
+ column: c.target_column,
1490
+ onDelete: z(c.delete_rule),
1491
+ onUpdate: z(c.update_rule)
1492
+ } : 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}`);
1493
+ return {
1494
+ name: t.column_name,
1495
+ type: l,
1496
+ nullable: t.is_nullable === "YES",
1497
+ unique: d,
1498
+ hasDefault: f !== null,
1499
+ ...f === null ? {} : { defaultValue: f },
1500
+ ...u ? { references: u } : {},
1501
+ ...p ? { oneOf: p } : {}
1502
+ };
1503
+ }), m = new Set(n.map((e) => e.source_column)), h = [];
1504
+ if (d) for (let [t, n] of d) {
1505
+ let r = [...n].sort((e, t) => e.seq_in_index - t.seq_in_index);
1506
+ 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({
1507
+ name: t,
1508
+ table: e.table_name,
1509
+ columns: r.map((e) => e.column_name),
1510
+ unique: r[0].non_unique === 0
1511
+ });
1512
+ }
1513
+ i.length > 0 && h.push({
1514
+ name: `${e.table_name}_pkey`,
1515
+ table: e.table_name,
1516
+ columns: i,
1517
+ unique: !0
1518
+ });
1519
+ let g = Number(e.table_rows ?? 0);
1520
+ f.push({
1521
+ name: e.table_name,
1522
+ columns: p,
1523
+ indexes: h,
1524
+ ...g > 0 ? { rowCount: g } : {}
1525
+ });
1526
+ }
1527
+ return { tables: f };
1528
+ }), Ft = (e) => {
1529
+ let t = e.toUpperCase();
1530
+ return t.includes("INT") ? "integer" : t.includes("REAL") || t.includes("FLOA") || t.includes("DOUB") ? "real" : t.includes("BLOB") ? "bytes" : "text";
1531
+ }, It = (e) => d.gen(function* () {
1532
+ let t = yield* e`
1533
+ SELECT name, sql FROM sqlite_master
1534
+ WHERE type = 'table' AND name NOT LIKE 'sqlite_%'
1535
+ ORDER BY name`, n = (e) => `'${e.replace(/'/g, "''")}'`, r = [];
1536
+ for (let { name: i, sql: a } of t) {
1537
+ let t = /* @__PURE__ */ new Map();
1538
+ for (let e of (a ?? "").matchAll(/CHECK\s*\(\s*"([^"]+)"\s+IN\s*\(([^)]*)\)/gi)) {
1539
+ let n = [...e[2].matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
1540
+ n.length > 0 && t.set(e[1], n);
1541
+ }
1542
+ let o = yield* e.unsafe(`PRAGMA table_info(${n(i)})`), s = yield* e.unsafe(`PRAGMA foreign_key_list(${n(i)})`), c = yield* e.unsafe(`PRAGMA index_list(${n(i)})`), l = new Map(s.map((e) => [e.from, e])), u = o.filter((e) => e.pk > 0).sort((e, t) => e.pk - t.pk).map((e) => e.name), d = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Set();
1543
+ for (let t of c) {
1544
+ let r = (yield* e.unsafe(`PRAGMA index_info(${n(t.name)})`)).map((e) => e.name).filter((e) => e !== null);
1545
+ d.set(t.name, r), t.unique === 1 && r.length === 1 && f.add(r[0]);
1546
+ }
1547
+ let p = o.map((e) => {
1548
+ let n = u.length === 1 && u[0] === e.name, r = l.get(e.name), i = r ? "reference" : n && e.name === "id" ? "id" : Ft(e.type), a = r ? {
1549
+ table: r.table,
1550
+ column: r.to,
1551
+ onDelete: z(r.on_delete),
1552
+ onUpdate: z(r.on_update)
1553
+ } : void 0, o = t.get(e.name);
1554
+ return {
1555
+ name: e.name,
1556
+ type: i,
1557
+ nullable: e.notnull === 0,
1558
+ unique: f.has(e.name) || n && e.name === "id",
1559
+ hasDefault: e.dflt_value !== null,
1560
+ ...e.dflt_value === null ? {} : { defaultValue: e.dflt_value },
1561
+ ...a ? { references: a } : {},
1562
+ ...o ? { oneOf: o } : {}
1563
+ };
1564
+ }), m = new Set(s.map((e) => e.from)), h = [];
1565
+ for (let e of c) {
1566
+ if (e.origin === "pk") continue;
1567
+ let t = d.get(e.name) ?? [];
1568
+ t.length === 1 && e.unique === 1 || t.length === 1 && e.unique !== 1 && m.has(t[0]) && e.name !== `${i}_${t[0]}_idx` || h.push({
1569
+ name: e.name,
1570
+ table: i,
1571
+ columns: t,
1572
+ unique: e.unique === 1
1573
+ });
1574
+ }
1575
+ u.length > 0 && h.push({
1576
+ name: `${i}_pkey`,
1577
+ table: i,
1578
+ columns: u,
1579
+ unique: !0
1580
+ }), r.push({
1581
+ name: i,
1582
+ columns: p,
1583
+ indexes: h
1584
+ });
1585
+ }
1586
+ return { tables: r };
1587
+ }), Lt = (e) => {
1588
+ switch (e.toLowerCase()) {
1589
+ case "int":
1590
+ case "smallint":
1591
+ case "tinyint": return "integer";
1592
+ case "bigint": return "bigint";
1593
+ case "decimal":
1594
+ case "numeric":
1595
+ case "money": return "decimal";
1596
+ case "float":
1597
+ case "real": return "real";
1598
+ case "bit": return "boolean";
1599
+ case "datetime2":
1600
+ case "datetime":
1601
+ case "smalldatetime":
1602
+ case "datetimeoffset": return "timestamp";
1603
+ case "date": return "date";
1604
+ case "varbinary":
1605
+ case "binary":
1606
+ case "image": return "bytes";
1607
+ default: return "text";
1608
+ }
1609
+ }, V = (e) => e === !0 || e === 1, Rt = (e) => d.gen(function* () {
1610
+ let t = yield* e`
1611
+ SELECT TABLE_NAME AS table_name FROM INFORMATION_SCHEMA.TABLES
1612
+ WHERE TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`, n = yield* e`
1613
+ SELECT TABLE_NAME AS table_name, COLUMN_NAME AS column_name, DATA_TYPE AS data_type,
1614
+ IS_NULLABLE AS is_nullable, COLUMN_DEFAULT AS column_default
1615
+ FROM INFORMATION_SCHEMA.COLUMNS ORDER BY TABLE_NAME, ORDINAL_POSITION`, r = yield* e`
1616
+ SELECT st.name AS source_table, sc.name AS source_column,
1617
+ tt.name AS target_table, tc.name AS target_column,
1618
+ fk.delete_referential_action_desc AS delete_rule,
1619
+ fk.update_referential_action_desc AS update_rule
1620
+ FROM sys.foreign_keys fk
1621
+ JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
1622
+ JOIN sys.tables st ON st.object_id = fkc.parent_object_id
1623
+ JOIN sys.columns sc ON sc.object_id = fkc.parent_object_id AND sc.column_id = fkc.parent_column_id
1624
+ JOIN sys.tables tt ON tt.object_id = fkc.referenced_object_id
1625
+ JOIN sys.columns tc ON tc.object_id = fkc.referenced_object_id AND tc.column_id = fkc.referenced_column_id`, i = yield* e`
1626
+ SELECT t.name AS table_name, i.name AS index_name, i.is_unique AS is_unique,
1627
+ i.is_primary_key AS is_primary, c.name AS column_name, ic.key_ordinal AS key_ordinal
1628
+ FROM sys.indexes i
1629
+ JOIN sys.tables t ON t.object_id = i.object_id
1630
+ JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
1631
+ JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
1632
+ WHERE i.type > 0 AND ic.is_included_column = 0
1633
+ ORDER BY t.name, i.name, ic.key_ordinal`, a = yield* e`
1634
+ SELECT t.name AS table_name, c.name AS column_name, cc.definition AS def
1635
+ FROM sys.check_constraints cc
1636
+ JOIN sys.tables t ON t.object_id = cc.parent_object_id
1637
+ JOIN sys.columns c ON c.object_id = cc.parent_object_id AND c.column_id = cc.parent_column_id
1638
+ WHERE cc.parent_column_id <> 0`, o = /* @__PURE__ */ new Map();
1639
+ for (let e of a) {
1640
+ let t = [...e.def.matchAll(/'((?:[^']|'')*)'/g)].map((e) => e[1].replace(/''/g, "'"));
1641
+ t.length > 0 && o.set(`${e.table_name}.${e.column_name}`, t);
1642
+ }
1643
+ let s = /* @__PURE__ */ new Map();
1644
+ for (let e of n) {
1645
+ let t = s.get(e.table_name) ?? [];
1646
+ t.push(e), s.set(e.table_name, t);
1647
+ }
1648
+ let c = /* @__PURE__ */ new Map();
1649
+ for (let e of r) {
1650
+ let t = c.get(e.source_table) ?? [];
1651
+ t.push(e), c.set(e.source_table, t);
1652
+ }
1653
+ let l = /* @__PURE__ */ new Map();
1654
+ for (let e of i) {
1655
+ let t = l.get(e.table_name);
1656
+ t || (t = /* @__PURE__ */ new Map(), l.set(e.table_name, t));
1657
+ let n = t.get(e.index_name) ?? [];
1658
+ n.push(e), t.set(e.index_name, n);
1659
+ }
1660
+ let u = [];
1661
+ for (let { table_name: e } of t) {
1662
+ 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();
1663
+ if (a) for (let [, e] of a) {
1664
+ let t = [...e].sort((e, t) => e.key_ordinal - t.key_ordinal);
1665
+ if (V(t[0].is_primary)) for (let e of t) d.push(e.column_name);
1666
+ else V(t[0].is_unique) && t.length === 1 && f.add(t[0].column_name);
1667
+ }
1668
+ let p = t.map((t) => {
1669
+ 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" : Lt(t.data_type), s = i ? {
1670
+ table: i.target_table,
1671
+ column: i.target_column,
1672
+ onDelete: zt(i.delete_rule),
1673
+ onUpdate: zt(i.update_rule)
1674
+ } : void 0, c = t.column_default === null ? null : Bt(t.column_default), l = o.get(`${e}.${t.column_name}`);
1675
+ return {
1676
+ name: t.column_name,
1677
+ type: a,
1678
+ nullable: t.is_nullable === "YES",
1679
+ unique: f.has(t.column_name) || n && t.column_name === "id",
1680
+ hasDefault: c !== null,
1681
+ ...c === null ? {} : { defaultValue: c },
1682
+ ...s ? { references: s } : {},
1683
+ ...l ? { oneOf: l } : {}
1684
+ };
1685
+ }), m = [];
1686
+ if (a) for (let [t, n] of a) {
1687
+ let r = [...n].sort((e, t) => e.key_ordinal - t.key_ordinal);
1688
+ 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({
1689
+ name: t,
1690
+ table: e,
1691
+ columns: r.map((e) => e.column_name),
1692
+ unique: V(r[0].is_unique)
1693
+ });
1694
+ }
1695
+ d.length > 0 && m.push({
1696
+ name: `${e}_pkey`,
1697
+ table: e,
1698
+ columns: d,
1699
+ unique: !0
1700
+ }), u.push({
1701
+ name: e,
1702
+ columns: p,
1703
+ indexes: m
1704
+ });
1705
+ }
1706
+ return { tables: u };
1707
+ }), zt = (e) => {
1708
+ switch (e.toUpperCase().replace(/_/g, " ")) {
1709
+ case "CASCADE": return "cascade";
1710
+ case "SET NULL": return "setNull";
1711
+ case "SET DEFAULT": return "noAction";
1712
+ default: return "noAction";
1713
+ }
1714
+ }, Bt = (e) => {
1715
+ let t = e.trim();
1716
+ for (; t.startsWith("(") && t.endsWith(")");) t = t.slice(1, -1).trim();
1717
+ return t.startsWith("N'") && t.endsWith("'") ? t = t.slice(2, -1) : t.startsWith("'") && t.endsWith("'") && (t = t.slice(1, -1)), t;
1718
+ }, Vt = (e) => e.onDialectOrElse({
1719
+ mysql: () => Pt(e),
1720
+ mssql: () => Rt(e),
1721
+ sqlite: () => It(e),
1722
+ orElse: () => Mt(e)
1723
+ }), Ht = (e, t) => `${t}(${e.precision ?? 38}, ${e.scale ?? 0})`, H = (e) => {
1724
+ switch (e.type) {
1725
+ case "id": return "text";
1726
+ case "text": return "text";
1727
+ case "integer": return "integer";
1728
+ case "real": return "double precision";
1729
+ case "decimal": return Ht(e, "NUMERIC");
1730
+ case "bigint": return "bigint";
1731
+ case "boolean": return "boolean";
1732
+ case "timestamp": return "timestamptz";
1733
+ case "date": return "date";
1734
+ case "json": return "jsonb";
1735
+ case "bytes": return "bytea";
1736
+ case "reference": return "text";
1737
+ case "vector": return "text";
1738
+ case "enum": return "text";
1739
+ case "array": return "text";
1740
+ case "interval": return "interval";
1741
+ case "raw": return e.rawDdl ?? "text";
1742
+ }
1743
+ }, U = (e) => {
1744
+ switch (e.type) {
1745
+ case "id": return "VARCHAR(64)";
1746
+ case "text": return e.hasDefault && e.defaultValue !== void 0 || e.oneOf && e.oneOf.length > 0 ? "VARCHAR(255)" : "LONGTEXT";
1747
+ case "integer": return "INT";
1748
+ case "real": return "DOUBLE";
1749
+ case "decimal": return Ht(e, "DECIMAL");
1750
+ case "bigint": return "BIGINT";
1751
+ case "boolean": return "TINYINT(1)";
1752
+ case "timestamp": return "DATETIME(6)";
1753
+ case "date": return "DATE";
1754
+ case "json": return "JSON";
1755
+ case "bytes": return "LONGBLOB";
1756
+ case "reference": return "VARCHAR(64)";
1757
+ case "vector": return "BLOB";
1758
+ case "enum": return "TEXT";
1759
+ case "array": return "JSON";
1760
+ case "interval": return "BIGINT";
1761
+ case "raw": return e.rawDdl ?? "LONGTEXT";
1762
+ }
1763
+ }, W = (e) => `"${e}"`, G = (e) => `\`${e.replace(/`/g, "``")}\``, Ut = (e, t) => `ALTER TABLE ${t(e.table)} DROP COLUMN IF EXISTS ${t(e.column)};`, Wt = (e) => `ALTER TABLE ${G(e.table)} DROP COLUMN IF EXISTS ${G(e.column)}, ALGORITHM=COPY;`, Gt = (e, t) => `ALTER TABLE ${t(e.table)} RENAME COLUMN ${t(e.from)} TO ${t(e.to)};`, Kt = (e, t, n) => `ALTER TABLE ${n(e.table)} RENAME COLUMN ${n(e.column)} TO ${n(`${e.column}${mn(t)}`)};`, qt = (e, t, n) => e.hasDefault && e.defaultValue !== void 0 ? `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} SET ${n(e.defaultValue) ?? "DEFAULT NULL"};` : `ALTER TABLE ${t(e.table)} ALTER COLUMN ${t(e.column)} DROP DEFAULT;`, K = (e, t, n) => e.find((e) => e.tableName === t)?.fields[n], Jt = (e, t, n) => {
1764
+ let r = n ?? e.nullable, i = fe(e, "mariadb");
1765
+ return [
1766
+ G(t),
1767
+ O(e, "mariadb"),
1768
+ r ? null : "NOT NULL",
1769
+ i
1770
+ ].filter(Boolean).join(" ");
1771
+ }, Yt = (e) => e == null ? null : 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" && !Array.isArray(e) ? k(e, "mysql") : null, Xt = (e) => e == null ? null : 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" && !Array.isArray(e) ? k(e, "postgres") : null, q = (e, t) => {
1772
+ if (!e.generatedAs) return null;
1773
+ let { expr: n, stored: r } = e.generatedAs;
1774
+ return t === "postgres" ? `GENERATED ALWAYS AS (${n}) STORED` : t === "mssql" ? `AS (${n})${r ? " PERSISTED" : ""}` : `GENERATED ALWAYS AS (${n}) ${r ? "STORED" : "VIRTUAL"}`;
1775
+ }, Zt = (e) => {
1776
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return A(e.name, "postgres");
1777
+ let t = q(e, "postgres");
1778
+ if (t) return `${W(e.name)} ${H(e)} ${t}`;
1779
+ let n = [W(e.name), H(e)];
1780
+ if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
1781
+ let t = Xt(e.defaultValue);
1782
+ t && n.push(t);
1783
+ }
1784
+ return e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
1785
+ cascade: "CASCADE",
1786
+ restrict: "RESTRICT",
1787
+ setNull: "SET NULL",
1788
+ noAction: "NO ACTION"
1789
+ }[e.references.onDelete]}`)), n.join(" ");
1790
+ }, J = (e, t) => e.primaryKey && e.primaryKey.length > 0 ? `,\n PRIMARY KEY (${e.primaryKey.map(t).join(", ")})` : "", Qt = (e) => {
1791
+ let t = e.columns.map((e) => ` ${Zt(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${J(e, W)}\n)`];
1792
+ for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(yn).join(", ")})`);
1793
+ return n;
1794
+ }, $t = 191, en = (e) => {
1795
+ let t = U(e).toUpperCase();
1796
+ return t.endsWith("TEXT") || t.endsWith("BLOB");
1797
+ }, tn = (e) => {
1798
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return A(e.name, "mariadb");
1799
+ let t = q(e, "mariadb");
1800
+ if (t) return `${G(e.name)} ${U(e)} ${t}`;
1801
+ let n = [G(e.name), U(e)];
1802
+ 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) {
1803
+ let t = Yt(e.defaultValue);
1804
+ t && n.push(t);
1805
+ }
1806
+ return e.references && (n.push(`REFERENCES ${G(e.references.table)} (${G(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${{
1807
+ cascade: "CASCADE",
1808
+ restrict: "RESTRICT",
1809
+ setNull: "SET NULL",
1810
+ noAction: "NO ACTION"
1811
+ }[e.references.onDelete]}`)), n.join(" ");
1812
+ }, nn = (e) => {
1813
+ let t = new Map(e.columns.map((e) => [e.name, e])), n = (e) => {
1814
+ let n = t.get(e);
1815
+ return n && en(n) ? `${G(e)}(${$t})` : G(e);
1816
+ }, r = e.columns.map((e) => ` ${tn(e)}`).join(",\n"), i = [`CREATE TABLE IF NOT EXISTS ${G(e.table)} (\n${r}${J(e, n)}\n)`];
1817
+ for (let t of e.columns) t.unique && t.type !== "id" && en(t) && i.push(`CREATE UNIQUE INDEX IF NOT EXISTS ${G(`${e.table}_${t.name}_key`)} ON ${G(e.table)} (${n(t.name)})`);
1818
+ for (let t of e.indexes) t.name !== `${e.table}_pkey` && i.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(t.name)} ON ${G(e.table)} (${t.columns.map(n).join(", ")})`);
1819
+ return i;
1820
+ }, rn = {
1821
+ cascade: "CASCADE",
1822
+ restrict: "RESTRICT",
1823
+ setNull: "SET NULL",
1824
+ noAction: "NO ACTION"
1825
+ }, an = {
1826
+ cascade: "CASCADE",
1827
+ restrict: "NO ACTION",
1828
+ setNull: "SET NULL",
1829
+ noAction: "NO ACTION"
1830
+ }, on = (e) => {
1831
+ switch (e.type) {
1832
+ case "integer":
1833
+ case "boolean": return "INTEGER";
1834
+ case "bigint": return "INTEGER";
1835
+ case "real": return "REAL";
1836
+ case "decimal": return "NUMERIC";
1837
+ case "bytes": return "BLOB";
1838
+ default: return "TEXT";
1839
+ }
1840
+ }, 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" && !Array.isArray(e) ? k(e, "sqlite") : null, sn = (e) => {
1841
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return A(e.name, "sqlite");
1842
+ let t = q(e, "sqlite");
1843
+ if (t) return `${W(e.name)} ${on(e)} ${t}`;
1844
+ let n = [W(e.name), on(e)];
1845
+ if (e.type === "id" && n.push("PRIMARY KEY"), e.nullable || n.push("NOT NULL"), e.unique && e.type !== "id" && n.push("UNIQUE"), e.hasDefault) {
1846
+ let t = Y(e.defaultValue, "CURRENT_TIMESTAMP");
1847
+ t && n.push(t);
1848
+ }
1849
+ if (e.references && (n.push(`REFERENCES ${W(e.references.table)} (${W(e.references.column)})`), e.references.onDelete && n.push(`ON DELETE ${rn[e.references.onDelete]}`)), e.oneOf && e.oneOf.length > 0) {
1850
+ let t = e.oneOf.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
1851
+ n.push(`CHECK (${W(e.name)} IN (${t}))`);
1852
+ }
1853
+ return n.join(" ");
1854
+ }, cn = (e) => {
1855
+ let t = e.columns.map((e) => ` ${sn(e)}`).join(",\n"), n = [`CREATE TABLE IF NOT EXISTS ${W(e.table)} (\n${t}${J(e, W)}\n)`];
1856
+ for (let t of e.indexes) t.name !== `${e.table}_pkey` && n.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e.table)} (${t.columns.map(W).join(", ")})`);
1857
+ return n;
1858
+ }, X = (e, t) => {
1859
+ let n = t.find((t) => t.tableName === e);
1860
+ if (!n) return [];
1861
+ let r = F([n]).tables[0], i = `${e}__voltro_rebuild`, a = r.columns.map((e) => W(e.name)).join(", "), o = [
1862
+ ...cn({
1863
+ kind: "create-table",
1864
+ table: i,
1865
+ columns: r.columns,
1866
+ indexes: [],
1867
+ ...r.primaryKey ? { primaryKey: r.primaryKey } : {}
1868
+ }),
1869
+ `INSERT INTO ${W(i)} (${a}) SELECT ${a} FROM ${W(e)}`,
1870
+ `DROP TABLE ${W(e)}`,
1871
+ `ALTER TABLE ${W(i)} RENAME TO ${W(e)}`
1872
+ ];
1873
+ for (let t of r.indexes) t.name !== `${e}_pkey` && o.push(`CREATE ${t.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${W(t.name)} ON ${W(e)} (${t.columns.map(W).join(", ")})`);
1874
+ return o;
1875
+ }, ln = (e, t, n, r) => {
1876
+ let i = r ?? e.nullable;
1877
+ return `ALTER TABLE ${Z(n)} ALTER COLUMN ${Z(t)} ${O(e, "mssql")} ${i ? "NULL" : "NOT NULL"};`;
1878
+ }, un = (e) => {
1879
+ 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 + ']');`;
1880
+ if (!e.hasDefault) return t;
1881
+ let n = Y(e.defaultValue, "SYSUTCDATETIME()");
1882
+ if (!n) return t;
1883
+ let r = n.replace(/^DEFAULT\s+/i, "");
1884
+ return `${t} ALTER TABLE ${Z(e.table)} ADD DEFAULT ${r} FOR ${Z(e.column)};`;
1885
+ }, Z = (e) => `[${e.replace(/]/g, "]]")}]`, dn = (e) => {
1886
+ switch (e.type) {
1887
+ case "id":
1888
+ case "reference": return "NVARCHAR(64)";
1889
+ case "integer": return "INT";
1890
+ case "real": return "FLOAT";
1891
+ case "decimal": return Ht(e, "DECIMAL");
1892
+ case "bigint": return "BIGINT";
1893
+ case "boolean": return "BIT";
1894
+ case "timestamp": return "DATETIME2(6)";
1895
+ case "date": return "DATE";
1896
+ case "bytes": return "VARBINARY(MAX)";
1897
+ default: return "NVARCHAR(MAX)";
1898
+ }
1899
+ }, fn = (e, t) => {
1900
+ if (e.type === "id" && e.idScheme?.kind === "numeric") return A(e.name, "mssql");
1901
+ let n = e.type === "text" && t?.has(e.name) ? "NVARCHAR(450)" : dn(e), r = q(e, "mssql");
1902
+ if (r) return `${Z(e.name)} ${r}`;
1903
+ let i = [Z(e.name), n];
1904
+ if (e.type === "id" && i.push("PRIMARY KEY"), e.nullable || i.push("NOT NULL"), e.unique && e.type !== "id" && i.push("UNIQUE"), e.hasDefault) {
1905
+ let t = Y(e.defaultValue, "SYSUTCDATETIME()");
1906
+ t && i.push(t);
1907
+ }
1908
+ 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(" ");
1909
+ }, pn = (e) => {
1910
+ let t = (e) => e.replace(/'/g, "''"), n = new Set(e.indexes.flatMap((e) => e.columns)), r = e.columns.map((e) => ` ${fn(e, n)}`).join(",\n"), i = `CREATE TABLE ${Z(e.table)} (\n${r}${J(e, Z)}\n)`, a = [`IF OBJECT_ID(N'${t(e.table)}', N'U') IS NULL EXEC(N'${t(i)}')`];
1911
+ for (let n of e.indexes) {
1912
+ if (n.name === `${e.table}_pkey`) continue;
1913
+ let r = `CREATE ${n.unique ? "UNIQUE " : ""}INDEX ${Z(n.name)} ON ${Z(e.table)} (${n.columns.map(Z).join(", ")})`;
1914
+ 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)}')`);
1915
+ }
1916
+ return a;
1917
+ }, mn = (e) => `__dropped_${e.replace(/[-:T.Z]/g, "").slice(0, 14)}`, hn = (e, t) => `DROP TABLE IF EXISTS ${t(e.table)};`, gn = (e, t, n) => {
1918
+ let r = `${e.table}${mn(t)}`;
1919
+ return `ALTER TABLE ${n(e.table)} RENAME TO ${n(r)};`;
1920
+ }, _n = (e, t, n) => {
1921
+ let r = K(e, t, n);
1922
+ return r ? en({ type: r.type }) : !1;
1923
+ }, vn = (e, t, n) => _n(e, t, n) ? `${G(n)}(${$t})` : G(n), yn = (e) => e.startsWith("(") ? e : W(e), bn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX ${t ? "CONCURRENTLY " : ""}IF NOT EXISTS ${W(e.index.name)} ON ${W(e.table)} (${e.index.columns.map(yn).join(", ")});`, xn = (e, t) => `CREATE ${e.index.unique ? "UNIQUE " : ""}INDEX IF NOT EXISTS ${G(e.index.name)} ON ${G(e.table)} (${e.index.columns.map((n) => vn(t, e.table, n)).join(", ")});`, Sn = (e) => `DROP INDEX IF EXISTS ${W(e.index)};`, Cn = (e) => `DROP INDEX ${G(e.index)} ON ${G(e.table)};`, wn = (e) => `DROP INDEX IF EXISTS ${Z(e.index)} ON ${Z(e.table)};`, Tn = (e) => {
1924
+ 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(", ")})`;
1925
+ 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)}');`;
1926
+ }, En = (e, t, n) => {
1927
+ let r = n.find((t) => t.tableName === e);
1928
+ if (!r) return [];
1929
+ let i = [];
1930
+ for (let n of t) {
1931
+ let t = r.fields[n];
1932
+ t && t.type === "text" && !t.generatedAs && i.push(`ALTER TABLE ${Z(e)} ALTER COLUMN ${Z(n)} NVARCHAR(450) ${t.nullable ? "NULL" : "NOT NULL"};`);
1933
+ }
1934
+ return i;
1935
+ }, Dn = (e) => `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(`${e.table}_${e.column}_key`)} UNIQUE (${W(e.column)});`, On = (e, t) => `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(`${e.table}_${e.column}_key`)} UNIQUE (${vn(t, e.table, e.column)});`, kn = (e) => {
1936
+ let t = e.fields.map((e) => W(e)).join(", ");
1937
+ return `ALTER TABLE ${W(e.table)} ADD CONSTRAINT ${W(e.name)} UNIQUE (${t});`;
1938
+ }, An = (e, t) => {
1939
+ let n = e.fields.map((n) => vn(t, e.table, n)).join(", ");
1940
+ return `ALTER TABLE ${G(e.table)} ADD CONSTRAINT ${G(e.name)} UNIQUE (${n});`;
1941
+ }, jn = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(e.name)};`, Mn = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(e.name)};`, Nn = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_key`)};`, Pn = (e) => `ALTER TABLE ${G(e.table)} DROP INDEX ${G(`${e.table}_${e.column}_key`)};`, Fn = (e, t) => {
1942
+ let n = [], r = t(e.table), i = t(e.column), a = t(e.targetTable), o = t(e.targetColumn);
1943
+ if (e.orphanPolicy) {
1944
+ let t = `${i} IS NOT NULL AND ${i} NOT IN (SELECT ${o} FROM ${a})`;
1945
+ n.push(e.orphanPolicy === "delete" ? `DELETE FROM ${r} WHERE ${t};` : `UPDATE ${r} SET ${i} = NULL WHERE ${t};`);
1946
+ }
1947
+ let s = [
1948
+ `ALTER TABLE ${r}`,
1949
+ `ADD CONSTRAINT ${t(`${e.table}_${e.column}_fkey`)}`,
1950
+ `FOREIGN KEY (${i})`,
1951
+ `REFERENCES ${a} (${o})`
1952
+ ];
1953
+ return e.onDelete && s.push(`ON DELETE ${{
1954
+ cascade: "CASCADE",
1955
+ restrict: "RESTRICT",
1956
+ setNull: "SET NULL",
1957
+ noAction: "NO ACTION"
1958
+ }[e.onDelete]}`), n.push(s.join(" ") + ";"), n;
1959
+ }, In = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_fkey`)};`, Ln = (e) => `ALTER TABLE ${G(e.table)} DROP FOREIGN KEY ${G(`${e.table}_${e.column}_fkey`)};`, Rn = (e, t) => {
1960
+ let n = e.values.map((e) => `'${e.replace(/'/g, "''")}'`).join(", ");
1961
+ return `ALTER TABLE ${t(e.table)} ADD CONSTRAINT ${t(`${e.table}_${e.column}_check`)} CHECK (${t(e.column)} IN (${n}));`;
1962
+ }, zn = (e) => `ALTER TABLE ${W(e.table)} DROP CONSTRAINT IF EXISTS ${W(`${e.table}_${e.column}_check`)};`, Bn = (e) => `ALTER TABLE ${G(e.table)} DROP CHECK ${G(`${e.table}_${e.column}_check`)};`, Vn = (e, t, n, r) => {
1963
+ let i = e.column, a = r === "mariadb", o = a ? G : r === "mssql" ? Z : W, s = a ? U(i) : r === "mssql" ? dn(i) : r === "sqlite" ? on(i) : H(i), c = r === "mssql" ? "ADD" : "ADD COLUMN", l = (e) => a ? Yt(e) : r === "mssql" ? Y(e, "SYSUTCDATETIME()") : r === "sqlite" ? Y(e, "CURRENT_TIMESTAMP") : Xt(e), u = q(i, r);
1964
+ if (u) {
1965
+ let t = r === "mssql" ? `${o(i.name)} ${u}` : `${o(i.name)} ${s} ${u}`;
1966
+ return {
1967
+ pre: [`ALTER TABLE ${o(e.table)} ${c} ${t};`],
1968
+ post: []
1969
+ };
1970
+ }
1971
+ if (t.classification === "safe") {
1972
+ let t = [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s}`];
1973
+ return i.unique && t.push("UNIQUE"), {
1974
+ pre: [`${t.join(" ")};`],
1975
+ post: []
1976
+ };
1977
+ }
1978
+ if (t.classification === "needs-default") {
1979
+ let t = l(i.defaultValue) ?? "DEFAULT NULL";
1980
+ return {
1981
+ pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s} NOT NULL ${t};`],
1982
+ post: []
1983
+ };
1984
+ }
1985
+ let d = n(e.table, i.name), f = a ? `ALTER TABLE ${o(e.table)} MODIFY COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "mssql" ? `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} ${s} NOT NULL;` : r === "sqlite" ? null : `ALTER TABLE ${o(e.table)} ALTER COLUMN ${o(i.name)} SET NOT NULL;`, p = {
1986
+ pre: [`ALTER TABLE ${o(e.table)} ${c} ${o(i.name)} ${s};`],
1987
+ post: f ? [f] : []
1988
+ };
1989
+ 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;
1990
+ }, Hn = (e) => {
1991
+ let t = new Map(e.map((e) => [e.tableName, e]));
1992
+ return (e, n) => {
1993
+ let r = t.get(e);
1994
+ if (!r) return;
1995
+ let i = r.fields[n];
1996
+ if (!i || !i.backfill) return;
1997
+ let a = i.backfill, o = {
1998
+ ...a.batchSize === void 0 ? {} : { batchSize: a.batchSize },
1999
+ ...a.sleepMs === void 0 ? {} : { sleepMs: a.sleepMs }
2000
+ };
2001
+ if (a.kind === "sql" && a.sql) return {
2002
+ sql: a.sql,
2003
+ ...o
2004
+ };
2005
+ if (a.kind === "js" && a.fn) return {
2006
+ js: a.fn,
2007
+ ...o
2008
+ };
2009
+ };
2010
+ }, Q = (e, t, n) => e.unsafe(t).pipe(d.tapError((e) => d.sync(() => {
2011
+ process.stderr.write(_(`applier: statement failed (op=${n})`, t, e, 400));
2012
+ })), d.map(() => void 0)), $ = (e, t, n) => d.forEach(t, (t) => Q(e, t, n), { discard: !0 }), Un = (e, t, n) => d.gen(function* () {
2013
+ let r = process.hrtime.bigint(), i = Hn(n.declared), a = t.op;
2014
+ switch (a.kind) {
2015
+ case "create-table": {
2016
+ let t = yield* e.onDialectOrElse({
2017
+ mysql: () => d.succeed(nn(a)),
2018
+ mssql: () => d.succeed(pn(a)),
2019
+ sqlite: () => d.succeed(cn(a)),
2020
+ orElse: () => d.succeed(Qt(a))
2021
+ });
2022
+ for (let n of t) yield* Q(e, n, a.kind);
2023
+ break;
2024
+ }
2025
+ case "drop-table": {
2026
+ let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString(), r = (e) => t ? gn(a, n, e) : hn(a, e);
2027
+ yield* e.onDialectOrElse({
2028
+ mysql: () => Q(e, r(G), a.kind),
2029
+ orElse: () => Q(e, r(W), a.kind)
2030
+ });
2031
+ break;
2032
+ }
2033
+ case "drop-column": {
2034
+ let t = process.env.VOLTRO_SOFT_DROP === "1", n = (/* @__PURE__ */ new Date()).toISOString();
2035
+ yield* e.onDialectOrElse({
2036
+ mysql: () => Q(e, t ? Kt(a, n, G) : Wt(a), a.kind),
2037
+ orElse: () => Q(e, t ? Kt(a, n, W) : Ut(a, W), a.kind)
2038
+ });
2039
+ break;
2040
+ }
2041
+ case "rename-column":
2042
+ yield* e.onDialectOrElse({
2043
+ mysql: () => Q(e, Gt(a, G), a.kind),
2044
+ mssql: () => Q(e, `EXEC sp_rename N'${a.table.replace(/'/g, "''")}.${a.from.replace(/'/g, "''")}', N'${a.to.replace(/'/g, "''")}', 'COLUMN';`, a.kind),
2045
+ orElse: () => Q(e, Gt(a, W), a.kind)
2046
+ });
2047
+ break;
2048
+ case "add-index":
2049
+ yield* e.onDialectOrElse({
2050
+ mysql: () => Q(e, xn(a, n.declared), a.kind),
2051
+ mssql: () => $(e, [...En(a.table, a.index.columns, n.declared), Tn(a)], a.kind),
2052
+ orElse: () => Q(e, bn(a, t.classification === "online-required"), a.kind)
2053
+ });
2054
+ break;
2055
+ case "drop-index":
2056
+ yield* e.onDialectOrElse({
2057
+ mysql: () => Q(e, Cn(a), a.kind),
2058
+ mssql: () => Q(e, wn(a), a.kind),
2059
+ orElse: () => Q(e, Sn(a), a.kind)
2060
+ });
2061
+ break;
2062
+ case "add-unique":
2063
+ yield* e.onDialectOrElse({
2064
+ mysql: () => Q(e, On(a, n.declared), a.kind),
2065
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2066
+ mssql: () => $(e, [...En(a.table, [a.column], n.declared), Dn(a)], a.kind),
2067
+ orElse: () => Q(e, Dn(a), a.kind)
2068
+ });
2069
+ break;
2070
+ case "drop-unique":
2071
+ yield* e.onDialectOrElse({
2072
+ mysql: () => Q(e, Pn(a), a.kind),
2073
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2074
+ orElse: () => Q(e, Nn(a), a.kind)
2075
+ });
2076
+ break;
2077
+ case "add-unique-composite":
2078
+ yield* e.onDialectOrElse({
2079
+ mysql: () => Q(e, An(a, n.declared), a.kind),
2080
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2081
+ mssql: () => $(e, [...En(a.table, a.fields, n.declared), kn(a)], a.kind),
2082
+ orElse: () => Q(e, kn(a), a.kind)
2083
+ });
2084
+ break;
2085
+ case "drop-unique-composite":
2086
+ yield* e.onDialectOrElse({
2087
+ mysql: () => Q(e, Mn(a), a.kind),
2088
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2089
+ orElse: () => Q(e, jn(a), a.kind)
2090
+ });
2091
+ break;
2092
+ case "add-foreign-key":
2093
+ yield* e.onDialectOrElse({
2094
+ mysql: () => $(e, Fn(a, G), a.kind),
2095
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2096
+ orElse: () => $(e, Fn(a, W), a.kind)
2097
+ });
2098
+ break;
2099
+ case "add-column": {
2100
+ let n = Vn(a, t, i, yield* e.onDialectOrElse({
2101
+ mysql: () => d.succeed("mariadb"),
2102
+ mssql: () => d.succeed("mssql"),
2103
+ sqlite: () => d.succeed("sqlite"),
2104
+ orElse: () => d.succeed("postgres")
2105
+ }));
2106
+ for (let t of n.pre) yield* Q(e, t, a.kind);
2107
+ 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}`;
2108
+ else {
2109
+ let t = n.batchSize ?? 5e3, r = n.sleepMs ?? 0, i, o = 0;
2110
+ for (;;) {
2111
+ 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}`;
2112
+ if (s.length === 0) break;
2113
+ let c = s.map((e) => e.id);
2114
+ 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({
2115
+ scope: "voltro:migrate",
2116
+ mode: "sql-batched"
2117
+ })), i = s[s.length - 1].id, r > 0 && (yield* d.sleep(`${r} millis`));
2118
+ }
2119
+ }
2120
+ else if (n.backfillKind === "js" && n.backfillJs) {
2121
+ let t = n.batchSize ?? 1e3, r = n.sleepMs ?? 0, i, o = 0;
2122
+ for (;;) {
2123
+ 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}`;
2124
+ if (s.length === 0) break;
2125
+ for (let t of s) {
2126
+ let r = yield* d.tryPromise({
2127
+ try: () => Promise.resolve(n.backfillJs({ id: t.id })),
2128
+ catch: (e) => e
2129
+ }).pipe(d.orDie);
2130
+ yield* e`UPDATE ${e(a.table)} SET ${e(a.column.name)} = ${r} WHERE ${e("id")} = ${t.id}`;
2131
+ }
2132
+ o += s.length, yield* d.logInfo(`backfill ${a.table}.${a.column.name}: ${o} rows processed`).pipe(d.annotateLogs({
2133
+ scope: "voltro:migrate",
2134
+ table: a.table,
2135
+ column: a.column.name
2136
+ })), i = s[s.length - 1].id, r > 0 && (yield* d.sleep(`${r} millis`));
2137
+ }
2138
+ }
2139
+ for (let t of n.post) yield* Q(e, t, a.kind);
2140
+ break;
2141
+ }
2142
+ case "alter-column-nullability":
2143
+ yield* e.onDialectOrElse({
2144
+ mysql: () => {
2145
+ let t = K(n.declared, a.table, a.column);
2146
+ return t ? Q(e, `ALTER TABLE ${G(a.table)} MODIFY COLUMN ${Jt(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.`));
2147
+ },
2148
+ mssql: () => {
2149
+ let t = K(n.declared, a.table, a.column);
2150
+ return t ? Q(e, ln(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}'.`));
2151
+ },
2152
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2153
+ orElse: () => Q(e, `ALTER TABLE ${W(a.table)} ALTER COLUMN ${W(a.column)} ${a.toNullable ? "DROP NOT NULL" : "SET NOT NULL"};`, a.kind)
2154
+ });
2155
+ break;
2156
+ case "alter-column-default":
2157
+ yield* e.onDialectOrElse({
2158
+ mysql: () => Q(e, qt(a, G, Yt), a.kind),
2159
+ mssql: () => Q(e, un(a), a.kind),
2160
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2161
+ orElse: () => Q(e, qt(a, W, Xt), a.kind)
2162
+ });
2163
+ break;
2164
+ case "alter-column-type": {
2165
+ let r = H({ type: a.to }), i = a.using ? ` USING ${a.using}` : "";
2166
+ if (t.classification !== "online-required") {
2167
+ yield* e.onDialectOrElse({
2168
+ mysql: () => {
2169
+ let t = K(n.declared, a.table, a.column);
2170
+ return t ? Q(e, `ALTER TABLE ${G(a.table)} MODIFY COLUMN ${Jt(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.`));
2171
+ },
2172
+ mssql: () => {
2173
+ let t = K(n.declared, a.table, a.column);
2174
+ return t ? Q(e, ln(t, a.column, a.table), a.kind) : d.die(/* @__PURE__ */ Error(`alter-column-type on mssql needs the declared column '${a.table}.${a.column}'.`));
2175
+ },
2176
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2177
+ orElse: () => Q(e, `ALTER TABLE ${W(a.table)} ALTER COLUMN ${W(a.column)} TYPE ${r}${i};`, a.kind)
2178
+ });
2179
+ break;
2180
+ }
2181
+ yield* e.onDialectOrElse({
2182
+ 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.`)),
2183
+ orElse: () => d.void
2184
+ });
2185
+ let o = `${a.column}__shadow`, s = `${a.column}__old`;
2186
+ yield* e.unsafe(`ALTER TABLE ${W(a.table)} ADD COLUMN ${W(o)} ${r}`);
2187
+ let c = a.using ?? W(a.column), l;
2188
+ for (;;) {
2189
+ let t = l === void 0 ? yield* e`SELECT ${e("id")} FROM ${e(a.table)} WHERE ${e(o)} IS NULL ORDER BY ${e("id")} LIMIT 5000` : yield* e`SELECT ${e("id")} FROM ${e(a.table)} WHERE ${e(o)} IS NULL AND ${e("id")} > ${l} ORDER BY ${e("id")} LIMIT 5000`;
2190
+ if (t.length === 0) break;
2191
+ yield* e.unsafe(`UPDATE ${W(a.table)} SET ${W(o)} = ${c} WHERE ${W(a.column)} IS NOT NULL AND ${W(o)} IS NULL AND ${W("id")} IN (${t.map((e) => `'${e.id.replace(/'/g, "''")}'`).join(",")})`), l = t[t.length - 1].id;
2192
+ }
2193
+ yield* d.logInfo(`alter-column-type shadow ${a.table}.${a.column}: shadow populated`).pipe(d.annotateLogs({ scope: "voltro:migrate" })), yield* e.unsafe(`ALTER TABLE ${W(a.table)} RENAME COLUMN ${W(a.column)} TO ${W(s)}`), yield* e.unsafe(`ALTER TABLE ${W(a.table)} RENAME COLUMN ${W(o)} TO ${W(a.column)}`), yield* e.unsafe(`ALTER TABLE ${W(a.table)} DROP COLUMN ${W(s)}`);
2194
+ break;
2195
+ }
2196
+ case "drop-foreign-key":
2197
+ yield* e.onDialectOrElse({
2198
+ mysql: () => Q(e, Ln(a), a.kind),
2199
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2200
+ orElse: () => Q(e, In(a), a.kind)
2201
+ });
2202
+ break;
2203
+ case "add-check":
2204
+ yield* e.onDialectOrElse({
2205
+ mysql: () => Q(e, Rn(a, G), a.kind),
2206
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2207
+ orElse: () => Q(e, Rn(a, W), a.kind)
2208
+ });
2209
+ break;
2210
+ case "drop-check":
2211
+ yield* e.onDialectOrElse({
2212
+ mysql: () => Q(e, Bn(a), a.kind),
2213
+ sqlite: () => $(e, X(a.table, n.declared), a.kind),
2214
+ orElse: () => Q(e, zn(a), a.kind)
2215
+ });
2216
+ break;
2217
+ }
2218
+ return {
2219
+ op: a,
2220
+ status: "applied",
2221
+ durationMs: Number((process.hrtime.bigint() - r) / 1000000n)
2222
+ };
2223
+ }), Wn = (e, t, n) => d.gen(function* () {
2224
+ let r = t.operations.filter((e) => e.blocked);
2225
+ 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.`));
2226
+ yield* w(e);
2227
+ let i = Date.now(), a = [];
2228
+ try {
2229
+ let r = yield* e.onDialectOrElse({
2230
+ pg: () => d.succeed(!0),
2231
+ mssql: () => d.succeed(!0),
2232
+ orElse: () => d.succeed(!1)
2233
+ }), i = r ? t.operations.filter((e) => e.classification !== "online-required") : [], o = r ? t.operations.filter((e) => e.classification === "online-required") : t.operations;
2234
+ i.length > 0 && (yield* e.withTransaction(d.gen(function* () {
2235
+ let e = yield* p.SqlClient;
2236
+ for (let t of i) a.push(yield* Un(e, t, n));
2237
+ })));
2238
+ for (let t of o) a.push(yield* Un(e, t, n));
2239
+ } finally {
2240
+ yield* T(e).pipe(d.orDie);
2241
+ }
2242
+ let o = Date.now() - i, s = `plan_${Date.now().toString(36)}`, c = (/* @__PURE__ */ new Date()).toISOString(), l = yield* e.onDialectOrElse({
2243
+ mysql: () => d.succeed(c.replace("T", " ").replace("Z", "")),
2244
+ orElse: () => d.succeed(c)
2245
+ });
2246
+ return yield* e`
2247
+ INSERT INTO ${e("_voltro_migration_plans")}
2248
+ (${e("id")}, ${e("fingerprint")}, ${e("operations")},
2249
+ ${e("appliedBy")}, ${e("environment")}, ${e("source")},
2250
+ ${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
2251
+ VALUES
2252
+ (${s}, ${t.toFingerprint}, ${JSON.stringify(t.operations)},
2253
+ ${n.appliedBy}, ${n.environment}, ${n.source},
2254
+ ${o}, ${l}, ${n.notes ?? null})
2255
+ `, {
2256
+ id: s,
2257
+ appliedAt: c,
2258
+ fingerprint: t.toFingerprint,
2259
+ operations: t.operations,
2260
+ appliedBy: n.appliedBy,
2261
+ environment: n.environment,
2262
+ durationMs: o,
2263
+ source: n.source,
2264
+ ...n.notes ? { notes: n.notes } : {}
2265
+ };
2266
+ }), Gn = (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"), Kn = (e) => e`
2267
+ SELECT fingerprint
2268
+ FROM _voltro_migration_plans
2269
+ ORDER BY ${e("appliedAt")} DESC
2270
+ LIMIT 1
2271
+ `.pipe(d.map((e) => e.length > 0 ? e[0].fingerprint : void 0), d.catchAll(() => d.succeed(void 0))), qn = (e, t) => d.gen(function* () {
2272
+ let n = N(F(t)), r = yield* Kn(e);
2273
+ return r === n ? {
2274
+ kind: "up-to-date",
2275
+ fingerprint: n
2276
+ } : {
2277
+ kind: "prod-mismatch",
2278
+ expected: n,
2279
+ ...r === void 0 ? {} : { actual: r }
2280
+ };
2281
+ }), Jn = [
2282
+ "pgeagertest_",
2283
+ "mig_e2e_",
2284
+ "mig_test_",
2285
+ "mysqleagertest_",
2286
+ "mssqleagertest_",
2287
+ "sqliteeagertest_"
2288
+ ], Yn = (e) => Jn.some((t) => e.startsWith(t)), Xn = (e, t) => d.gen(function* () {
2289
+ if (process.env.VOLTRO_TEST_FIXTURE_GC === "off") return [];
2290
+ let n = t.filter((e) => Yn(e.name)).map((e) => e.name);
2291
+ if (n.length === 0) return [];
2292
+ for (let t of n) yield* e.unsafe(`DROP TABLE IF EXISTS "${t}" CASCADE`).pipe(d.catchAll(() => d.void));
2293
+ return n;
2294
+ }), Zn = () => {
2295
+ let e = (process.env.VOLTRO_DB_IGNORE_TABLES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0);
2296
+ return e.length > 0 ? { ignoreTables: e } : {};
2297
+ }, Qn = (e, t, n) => d.gen(function* () {
2298
+ let r = t.filter((e) => !$e(e.tableName));
2299
+ if (process.env.VOLTRO_MIGRATE_FORCE !== "1") {
2300
+ let t = N(F(r));
2301
+ if ((yield* Kn(e)) === t) return {
2302
+ kind: "up-to-date",
2303
+ fingerprint: t
2304
+ };
2305
+ }
2306
+ let i = yield* Vt(e), a = yield* Xn(e, i.tables);
2307
+ a.length > 0 && (yield* d.logInfo(`auto-migrate: reaped ${a.length} test-fixture leftover(s)`).pipe(d.annotateLogs({
2308
+ scope: "voltro:migrate",
2309
+ count: a.length
2310
+ })), i = yield* Vt(e));
2311
+ let o = wt({
2312
+ declared: r,
2313
+ live: { tables: i.tables.filter((e) => !$e(e.name)) },
2314
+ ...Zn()
2315
+ });
2316
+ if (o.summary.blocked > 0) {
2317
+ let e = o.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy");
2318
+ if (process.env.VOLTRO_DESTRUCTIVE_OK !== "1" || !e) return {
2319
+ kind: "refused-blocked",
2320
+ plan: o
2321
+ };
2322
+ }
2323
+ return o.operations.length === 0 ? {
2324
+ kind: "up-to-date",
2325
+ fingerprint: o.toFingerprint
2326
+ } : {
2327
+ kind: "applied",
2328
+ applied: yield* Wn(e, o, {
2329
+ declared: t,
2330
+ appliedBy: n.appliedBy,
2331
+ environment: n.environment === "prod" ? "dev" : n.environment,
2332
+ source: "auto-diff"
2333
+ }),
2334
+ plan: o
2335
+ };
2336
+ }), $n = (e, t, n) => process.env.VOLTRO_AUTO_MIGRATE === "0" ? d.succeed({
2337
+ kind: "skipped",
2338
+ reason: "VOLTRO_AUTO_MIGRATE=0"
2339
+ }) : n.environment === "prod" ? qn(e, t) : Qn(e, t, n), er = (e, t) => {
2340
+ switch (e.kind) {
2341
+ case "skipped": return `auto-migrate: skipped (${e.reason})`;
2342
+ case "up-to-date": return `auto-migrate: schema up to date (${t}, fingerprint=${P(e.fingerprint)})`;
2343
+ case "applied": {
2344
+ let t = e.plan.summary;
2345
+ return `auto-migrate: applied ${e.plan.operations.length} op(s) in ${e.applied.durationMs}ms [safe=${t.safe} needs-default=${t.needsDefault} needs-backfill=${t.needsBackfill} rename=${t.needsRenameAnnotation} lossy=${t.lossy}] fingerprint=${P(e.applied.fingerprint)}`;
2346
+ }
2347
+ case "prod-mismatch": return `auto-migrate: SCHEMA FINGERPRINT MISMATCH — declared=${P(e.expected)}` + (e.actual ? ` live=${P(e.actual)}` : " live=<no _voltro_migration_plans row>") + ". Run `voltro db apply --plan plan.json` from the deploy pipeline before serving.";
2348
+ case "refused-blocked": {
2349
+ 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 === "add-column").length, i = t.filter((e) => e.op.kind === "drop-column").length, a = t.filter((e) => e.classification === "needs-rename-annotation").length, o = `auto-migrate: REFUSED — ${e.plan.summary.blocked} blocked operation(s):\n` + Gn(e.plan), s = [""];
2350
+ return n > 0 && s.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=${t.filter((e) => e.op.kind === "drop-table").map((e) => "table" in e.op ? e.op.table : "").filter(Boolean).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.", " → Add it to your declared set + chain `.dropped()` on it, OR", " write a file-based migration in `migrations/` that DROPs it, OR", " set `VOLTRO_DESTRUCTIVE_OK=1` for ONE `voltro dev` run (acknowledges data loss).", " 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`)."), r > 0 && s.push(`${r} 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."), i > 0 && s.push(`${i} column(s) are missing from your declared schema.`, " → If intentional: chain `.dropped()` on the column slot in the table declaration.", " → If a typo: restore the field. Data survives until you drop it."), a > 0 && s.push(`${a} 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."), s.push("", "See `voltro db plan` for the full machine-readable diff."), o + "\n" + s.join("\n");
2351
+ }
2352
+ }
2353
+ }, tr = /* @__PURE__ */ new Set([
2354
+ "node_modules",
2355
+ "dist",
2356
+ "build",
2357
+ ".turbo",
2358
+ ".vite",
2359
+ ".next",
2360
+ ".git",
2361
+ ".framework"
2362
+ ]), nr = async (e) => {
2363
+ let t = [], n = async (e) => {
2364
+ let r = await h.readdir(e, { withFileTypes: !0 }).catch(() => []);
2365
+ for (let i of r) {
2366
+ if (tr.has(i.name)) continue;
2367
+ let r = g(e, i.name);
2368
+ i.isDirectory() ? await n(r) : i.isFile() && u.test(i.name) && t.push(r);
2369
+ }
2370
+ };
2371
+ return await n(e), t.sort((e, t) => {
2372
+ let n = e.split("/").pop() ?? e, r = t.split("/").pop() ?? t;
2373
+ return n.localeCompare(r);
2374
+ });
2375
+ }, rr = async (e) => {
2376
+ let t = [];
2377
+ for (let n of e) {
2378
+ let e = (await import(ee(n).href)).default;
2379
+ if (!s(e)) {
2380
+ process.stderr.write(`[voltro:migrate] ${n} has no default-exported \`migration(...)\` — skipped\n`);
2381
+ continue;
2382
+ }
2383
+ t.push({
2384
+ file: n,
2385
+ migration: e
2386
+ });
2387
+ }
2388
+ return t;
2389
+ }, ir = (e) => e`
2390
+ SELECT ${e("id")}
2391
+ FROM ${e("_voltro_migration_plans")}
2392
+ WHERE ${e("source")} = 'file'
2393
+ `.pipe(d.map((e) => e.map((e) => e.id)), d.catchAll(() => d.succeed([]))), ar = (e, t, n, r) => d.gen(function* () {
2394
+ let i = Date.now(), a = (/* @__PURE__ */ new Date()).toISOString(), o = {
2395
+ sql: e,
2396
+ log: {
2397
+ info: (e, n) => d.logInfo(e).pipe(d.annotateLogs({
2398
+ scope: `migrations:file:${t.migration.id}`,
2399
+ ...n ?? {}
2400
+ })),
2401
+ warn: (e, n) => d.logWarning(e).pipe(d.annotateLogs({
2402
+ scope: `migrations:file:${t.migration.id}`,
2403
+ ...n ?? {}
2404
+ }))
2405
+ },
2406
+ appliedAt: a
2407
+ }, s = t.migration.up(o);
2408
+ d.isEffect(s) ? yield* s : yield* d.tryPromise({
2409
+ try: () => s,
2410
+ catch: (e) => e
2411
+ });
2412
+ let c = Date.now() - i;
2413
+ 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`
2414
+ INSERT INTO ${e("_voltro_migration_plans")}
2415
+ (${e("id")}, ${e("fingerprint")}, ${e("operations")},
2416
+ ${e("appliedBy")}, ${e("environment")}, ${e("source")},
2417
+ ${e("durationMs")}, ${e("appliedAt")}, ${e("notes")})
2418
+ VALUES
2419
+ (${t.migration.id}, ${""}, ${JSON.stringify([{
2420
+ kind: "file",
2421
+ file: t.file
2422
+ }])},
2423
+ ${r}, ${n}, ${"file"},
2424
+ ${c}, ${a}, ${t.migration.description})
2425
+ `, { durationMs: c };
2426
+ }), or = (e, t) => d.gen(function* () {
2427
+ let n = yield* d.tryPromise({
2428
+ try: () => nr(g(t.projectRoot, "migrations")),
2429
+ catch: (e) => e
2430
+ });
2431
+ if (n.length === 0) return {
2432
+ applied: [],
2433
+ skipped: []
2434
+ };
2435
+ let r = yield* d.tryPromise({
2436
+ try: () => rr(n),
2437
+ catch: (e) => e
2438
+ });
2439
+ if (r.length === 0) return {
2440
+ applied: [],
2441
+ skipped: []
2442
+ };
2443
+ let i = new Set(yield* ir(e)), a = r.filter((e) => !i.has(e.migration.id)), o = r.filter((e) => i.has(e.migration.id)).map((e) => e.migration.id);
2444
+ if (a.length === 0) return {
2445
+ applied: [],
2446
+ skipped: o
2447
+ };
2448
+ yield* w(e);
2449
+ let s = [];
2450
+ try {
2451
+ for (let n of a) {
2452
+ yield* d.logInfo("file-based migration applying").pipe(d.annotateLogs({
2453
+ scope: "voltro:migrate",
2454
+ id: n.migration.id,
2455
+ file: n.file
2456
+ }));
2457
+ let { durationMs: r } = yield* ar(e, n, t.env, t.appliedBy);
2458
+ s.push({
2459
+ id: n.migration.id,
2460
+ durationMs: r
2461
+ }), yield* d.logInfo("file-based migration applied").pipe(d.annotateLogs({
2462
+ scope: "voltro:migrate",
2463
+ id: n.migration.id,
2464
+ durationMs: r
2465
+ }));
2466
+ }
2467
+ } finally {
2468
+ yield* T(e).pipe(d.orDie);
2469
+ }
2470
+ return {
2471
+ applied: s,
2472
+ skipped: o
2473
+ };
2474
+ }), sr = (e, t) => e`
2475
+ SELECT ${e("id")}
2476
+ FROM ${e("_voltro_migration_plans")}
2477
+ WHERE ${e("id")} = ${t} AND ${e("source")} = 'file'
2478
+ LIMIT 1
2479
+ `, cr = (e, t) => d.gen(function* () {
2480
+ if (!(yield* sr(e, t.id))[0]) return yield* d.fail(/* @__PURE__ */ Error(`rollback: ${t.id} not found in _voltro_migration_plans (file source)`));
2481
+ let n = yield* d.tryPromise({
2482
+ try: () => nr(g(t.projectRoot, "migrations")),
2483
+ catch: (e) => e
2484
+ }), r = (yield* d.tryPromise({
2485
+ try: () => rr(n),
2486
+ catch: (e) => e
2487
+ })).find((e) => e.migration.id === t.id);
2488
+ if (!r) return yield* d.fail(/* @__PURE__ */ Error(`rollback: file for migration ${t.id} not found on disk under ${t.projectRoot}/migrations/`));
2489
+ yield* w(e);
2490
+ let i = Date.now();
2491
+ try {
2492
+ let n = {
2493
+ sql: e,
2494
+ log: {
2495
+ info: (e, n) => d.logInfo(e).pipe(d.annotateLogs({
2496
+ scope: `migrations:file:${t.id}`,
2497
+ ...n ?? {}
2498
+ })),
2499
+ warn: (e, n) => d.logWarning(e).pipe(d.annotateLogs({
2500
+ scope: `migrations:file:${t.id}`,
2501
+ ...n ?? {}
2502
+ }))
2503
+ },
2504
+ appliedAt: (/* @__PURE__ */ new Date()).toISOString()
2505
+ }, a = r.migration.down(n);
2506
+ d.isEffect(a) ? yield* a : yield* d.tryPromise({
2507
+ try: () => a,
2508
+ catch: (e) => e
2509
+ });
2510
+ let o = Date.now() - i;
2511
+ return yield* e`DELETE FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t.id} AND ${e("source")} = 'file'`, {
2512
+ id: t.id,
2513
+ durationMs: o
2514
+ };
2515
+ } finally {
2516
+ yield* T(e).pipe(d.orDie);
2517
+ }
2518
+ }), lr = (e) => d.gen(function* () {
2519
+ let t = yield* p.SqlClient, n = yield* t`
2520
+ SELECT id, fingerprint, appliedAt FROM _voltro_migration_plans
2521
+ WHERE source = 'auto-diff'
2522
+ AND squashedAt IS NULL
2523
+ AND appliedAt < ${e.before}
2524
+ ORDER BY appliedAt DESC
2525
+ `;
2526
+ if (n.length === 0) return yield* d.fail(/* @__PURE__ */ Error(`squash: no rows applied before ${e.before}`));
2527
+ let r = n[0];
2528
+ 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.`));
2529
+ yield* t`
2530
+ UPDATE _voltro_migration_plans
2531
+ SET squashedAt = CURRENT_TIMESTAMP
2532
+ WHERE id IN ${t.in(n.map((e) => e.id))}
2533
+ `;
2534
+ let i = `plan_squash_${Math.floor(Date.now() / 1e3).toString(36)}`;
2535
+ return yield* t`
2536
+ INSERT INTO _voltro_migration_plans
2537
+ (id, fingerprint, operations, rollbackPlan, appliedBy, environment, source,
2538
+ onlineStrategy, durationMs, notes, squashedAt, appliedAt, createdAt, updatedAt)
2539
+ VALUES (
2540
+ ${i},
2541
+ ${e.fingerprint},
2542
+ ${JSON.stringify({
2543
+ kind: "squash-snapshot",
2544
+ rowsSquashed: n.length
2545
+ })},
2546
+ ${null},
2547
+ ${e.appliedBy},
2548
+ ${e.environment},
2549
+ ${"squash-snapshot"},
2550
+ ${null},
2551
+ ${0},
2552
+ ${e.note ?? null},
2553
+ ${null},
2554
+ ${"CURRENT_TIMESTAMP"},
2555
+ ${"CURRENT_TIMESTAMP"},
2556
+ ${"CURRENT_TIMESTAMP"}
2557
+ )
2558
+ `, {
2559
+ squashedCount: n.length,
2560
+ snapshotFingerprint: e.fingerprint,
2561
+ snapshotId: i
2562
+ };
2563
+ }), ur = (e, ...t) => ({
2564
+ _tag: "RawSqlFragment",
2565
+ strings: [...e],
2566
+ values: [...t]
2567
+ }), dr = (e) => typeof e == "object" && !!e && e._tag === "RawSqlFragment";
2568
+ //#endregion
2569
+ export { u as FILE_MIGRATION_PATTERN, b as VOLTRO_MIGRATION_LOCK_KEY, it as _internalCmp, w as acquireMigrationLock, Be as applyNamespacedSchema, Wn as applyPlan, Pe as applySchema, jt as chunkTables, F as declaredSnapshot, fe as defaultClause, k as defaultJsonClause, er as describeOutcome, Ut as emitDropColumnDdl, Wt as emitDropColumnDdlMysql, Ne as emitFrameworkBootstrapSql, je as emitNamespaceProvisionDdl, Me as emitNamespacedSchemaSql, M as emitSchemaSql, N as fingerprintSchema, Zn as ignoreTablesFromEnv, Vt as introspectSchema, s as isFileMigration, dr as isRawSqlFragment, Et as mapPgType, l as migration, A as numericIdSql, Tt as parseEnumCheck, wt as planMigrations, Ve as provisionTenantNamespace, T as releaseMigrationLock, tn as renderColumnMysql, Zt as renderColumnPg, cr as rollbackFileBasedMigration, or as runFileBasedMigrations, He as runFrameworkBootstrap, ze as runMigrate, $n as runPlannedMigrations, P as shortFingerprint, ur as sql, O as sqlType, lr as squashMigrationPlans, E as withMigrationLock };