@vibeorm/sql 2.0.2 → 2.1.1

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.
Files changed (43) hide show
  1. package/dist/ast.d.ts +54 -7
  2. package/dist/ast.d.ts.map +1 -1
  3. package/dist/codecs.d.ts +2 -3
  4. package/dist/codecs.d.ts.map +1 -1
  5. package/dist/composable.d.ts +70 -0
  6. package/dist/composable.d.ts.map +1 -0
  7. package/dist/dialect.d.ts +82 -6
  8. package/dist/dialect.d.ts.map +1 -1
  9. package/dist/dialects/constraint-owned-index.d.ts +9 -0
  10. package/dist/dialects/constraint-owned-index.d.ts.map +1 -0
  11. package/dist/dialects/migration-history.d.ts +8 -0
  12. package/dist/dialects/migration-history.d.ts.map +1 -0
  13. package/dist/dialects/migration-inventory.d.ts +24 -0
  14. package/dist/dialects/migration-inventory.d.ts.map +1 -0
  15. package/dist/dialects/migration-objects.d.ts +37 -0
  16. package/dist/dialects/migration-objects.d.ts.map +1 -0
  17. package/dist/dialects/migration-visibility.d.ts +8 -0
  18. package/dist/dialects/migration-visibility.d.ts.map +1 -0
  19. package/dist/dialects/mysql-check-probe.d.ts +16 -0
  20. package/dist/dialects/mysql-check-probe.d.ts.map +1 -0
  21. package/dist/dialects/mysql.d.ts.map +1 -1
  22. package/dist/dialects/postgres-rls-readiness.d.ts +3 -0
  23. package/dist/dialects/postgres-rls-readiness.d.ts.map +1 -1
  24. package/dist/dialects/postgres.d.ts.map +1 -1
  25. package/dist/dialects/sqlite-constraints.d.ts +16 -0
  26. package/dist/dialects/sqlite-constraints.d.ts.map +1 -0
  27. package/dist/dialects/sqlite-table-definition.d.ts +19 -0
  28. package/dist/dialects/sqlite-table-definition.d.ts.map +1 -0
  29. package/dist/dialects/sqlite.d.ts.map +1 -1
  30. package/dist/exclusion.d.ts +32 -0
  31. package/dist/exclusion.d.ts.map +1 -0
  32. package/dist/index.d.ts +21 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +1590 -408
  35. package/dist/index.js.map +26 -13
  36. package/dist/locks.d.ts +57 -0
  37. package/dist/locks.d.ts.map +1 -0
  38. package/dist/predicate.d.ts +53 -0
  39. package/dist/predicate.d.ts.map +1 -0
  40. package/dist/render.d.ts.map +1 -1
  41. package/dist/result-decoder.d.ts +49 -0
  42. package/dist/result-decoder.d.ts.map +1 -0
  43. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,4 +1,878 @@
1
1
  // @bun
2
+ // packages/sql/src/composable.ts
3
+ import { VibeError } from "@vibeorm/schema";
4
+
5
+ // packages/sql/src/params.ts
6
+ class ParamCollector {
7
+ dialect;
8
+ values;
9
+ constructor(dialect) {
10
+ this.dialect = dialect;
11
+ this.values = [];
12
+ }
13
+ add(value) {
14
+ this.values.push(value);
15
+ return this.dialect.placeholder({ index: this.values.length });
16
+ }
17
+ addMany(values) {
18
+ return values.map((value) => this.add(value));
19
+ }
20
+ }
21
+
22
+ // packages/sql/src/composable.ts
23
+ var fragments = new WeakMap;
24
+ function invalid(message) {
25
+ throw new VibeError({ code: "VIBE_VALIDATION", message });
26
+ }
27
+ function construct(parts) {
28
+ const snapshot = Object.freeze([...parts]);
29
+ const fragment = Object.freeze(Object.defineProperty(Object.create(null), "toJSON", {
30
+ value: () => ({ parts: snapshot })
31
+ }));
32
+ fragments.set(fragment, snapshot);
33
+ return fragment;
34
+ }
35
+ function isSqlFragment(value) {
36
+ return typeof value === "object" && value !== null && fragments.has(value);
37
+ }
38
+ function partsOf(value) {
39
+ return fragments.get(value) ?? invalid("Expected a constructed SQL fragment");
40
+ }
41
+ function identifier(parts) {
42
+ if (!Array.isArray(parts) || parts.length === 0 || parts.some((part) => typeof part !== "string" || part.length === 0 || part.includes("\x00"))) {
43
+ invalid("SQL identifiers require non-empty, NUL-free name components");
44
+ }
45
+ }
46
+ function template(strings, ...values) {
47
+ if (!Array.isArray(strings) || !Array.isArray(strings.raw) || strings.length !== values.length + 1 || strings.some((text) => typeof text !== "string")) {
48
+ invalid("Use sql as a template tag");
49
+ }
50
+ const parts = [];
51
+ for (let index = 0;index < strings.length; index++) {
52
+ parts.push(strings[index]);
53
+ if (index < values.length) {
54
+ const value = values[index];
55
+ if (isSqlFragment(value))
56
+ parts.push(...partsOf(value));
57
+ else
58
+ parts.push(Object.freeze({ value }));
59
+ }
60
+ }
61
+ return construct(parts);
62
+ }
63
+ var sql = Object.freeze(Object.assign(template, {
64
+ text: ({ text }) => {
65
+ if (typeof text !== "string" || text.includes("\x00"))
66
+ invalid("SQL text must be a NUL-free string");
67
+ return construct([text]);
68
+ },
69
+ ident: ({ parts }) => {
70
+ identifier(parts);
71
+ return construct([Object.freeze({ ident: Object.freeze([...parts]) })]);
72
+ },
73
+ value: ({ value, decoder }) => construct([Object.freeze({ value, ...decoder === undefined ? {} : { decoder } })]),
74
+ join: ({ items, separator }) => {
75
+ if (!Array.isArray(items))
76
+ invalid("sql.join requires an array");
77
+ const between = separator === undefined ? [", "] : partsOf(separator);
78
+ const parts = [];
79
+ items.forEach((value, index) => {
80
+ if (index > 0)
81
+ parts.push(...between);
82
+ parts.push(...isSqlFragment(value) ? partsOf(value) : [Object.freeze({ value })]);
83
+ });
84
+ return construct(parts);
85
+ },
86
+ existing: ({ column }) => {
87
+ identifier([column]);
88
+ return construct([Object.freeze({ row: "existing", column })]);
89
+ },
90
+ incoming: ({ column }) => {
91
+ identifier([column]);
92
+ return construct([Object.freeze({ row: "incoming", column })]);
93
+ },
94
+ greatest: ({ values }) => {
95
+ if (!Array.isArray(values) || values.length !== 2 || values.some((value) => !isSqlFragment(value)))
96
+ invalid("sql.greatest requires two SQL fragments");
97
+ return construct([Object.freeze({ greatest: Object.freeze([...values]) })]);
98
+ }
99
+ }));
100
+ function renderSqlFragment(params) {
101
+ const { dialect, collector, conflict } = params;
102
+ const render = (fragment) => renderSqlFragment({ ...params, fragment });
103
+ return partsOf(params.fragment).map((part) => {
104
+ if (typeof part === "string")
105
+ return part;
106
+ if ("value" in part) {
107
+ if (part.value === undefined)
108
+ invalid("SQL parameters cannot be undefined; use null explicitly");
109
+ return collector.add(part.decoder === undefined ? part.value : part.decoder.encode({ value: part.value, dialect: dialect.name }));
110
+ }
111
+ if ("ident" in part)
112
+ return part.ident.map((name) => dialect.quoteIdent({ name })).join(".");
113
+ if ("row" in part) {
114
+ if (conflict === undefined)
115
+ invalid("Existing/incoming row references require a conflict update");
116
+ const name = conflict.columns === undefined ? part.column : conflict.columns[part.column];
117
+ if (name === undefined)
118
+ invalid(`Unknown conflict-expression field "${part.column}"`);
119
+ const ref = dialect.excludedRowRef;
120
+ const qualifier = part.row === "existing" ? dialect.quoteIdent({ name: conflict.table }) : ref.form === "keyword" ? ref.name : dialect.quoteIdent({ name: ref.alias });
121
+ return `${qualifier}.${dialect.quoteIdent({ name })}`;
122
+ }
123
+ return render(part.greatest.reduce((left, right) => sql`(CASE WHEN ${left} IS NULL THEN ${right} WHEN ${right} IS NULL THEN ${left} WHEN ${left} >= ${right} THEN ${left} ELSE ${right} END)`));
124
+ }).join("");
125
+ }
126
+ function mapConflictColumns(params) {
127
+ return construct(partsOf(params.fragment).map((part) => {
128
+ if (typeof part === "string")
129
+ return part;
130
+ if ("row" in part) {
131
+ const column = Object.hasOwn(params.columns, part.column) ? params.columns[part.column] : undefined;
132
+ if (column === undefined)
133
+ invalid(`Unknown conflict-expression field "${part.column}"`);
134
+ return Object.freeze({ ...part, column });
135
+ }
136
+ if ("greatest" in part)
137
+ return Object.freeze({ greatest: Object.freeze(part.greatest.map((fragment) => mapConflictColumns({ ...params, fragment }))) });
138
+ return part;
139
+ }));
140
+ }
141
+ function compileSql(params) {
142
+ const collector = new ParamCollector(params.dialect);
143
+ const text = renderSqlFragment({ dialect: params.dialect, fragment: params.query, collector });
144
+ return { text, values: collector.values };
145
+ }
146
+ function sqlUsesIncoming(params) {
147
+ return partsOf(params.fragment).some((part) => typeof part !== "string" && (("row" in part) && part.row === "incoming" || ("greatest" in part) && part.greatest.some((fragment) => sqlUsesIncoming({ fragment }))));
148
+ }
149
+ // packages/sql/src/result-decoder.ts
150
+ import { VibeError as VibeError3 } from "@vibeorm/schema";
151
+
152
+ // packages/sql/src/pg-array.ts
153
+ var PG_ARRAY_QUOTE = /^$|^NULL$|[{},"\\\s]/i;
154
+ function toPgArrayLiteral(params) {
155
+ const { values } = params;
156
+ const parts = values.map((value) => {
157
+ if (value === null || value === undefined)
158
+ return "NULL";
159
+ const text = String(value);
160
+ return PG_ARRAY_QUOTE.test(text) ? `"${text.replace(/["\\]/g, (char) => `\\${char}`)}"` : text;
161
+ });
162
+ return `{${parts.join(",")}}`;
163
+ }
164
+ function parsePgArrayLiteral(params) {
165
+ const { literal } = params;
166
+ if (literal.length < 2 || !literal.startsWith("{") || !literal.endsWith("}"))
167
+ return null;
168
+ const inner = literal.slice(1, -1);
169
+ if (inner.length === 0)
170
+ return [];
171
+ const out = [];
172
+ let index = 0;
173
+ while (index < inner.length) {
174
+ if (inner[index] === '"') {
175
+ let text = "";
176
+ index++;
177
+ while (index < inner.length) {
178
+ const char = inner[index];
179
+ if (char === "\\") {
180
+ text += inner[index + 1] ?? "";
181
+ index += 2;
182
+ continue;
183
+ }
184
+ index++;
185
+ if (char === '"')
186
+ break;
187
+ text += char;
188
+ }
189
+ out.push(text);
190
+ } else {
191
+ let text = "";
192
+ while (index < inner.length && inner[index] !== ",") {
193
+ text += inner[index];
194
+ index++;
195
+ }
196
+ out.push(text === "NULL" ? null : text);
197
+ }
198
+ if (inner[index] === ",")
199
+ index++;
200
+ }
201
+ return out;
202
+ }
203
+
204
+ // packages/sql/src/codecs.ts
205
+ import { VibeError as VibeError2, invalidStoredData } from "@vibeorm/schema";
206
+ function enumMembershipCodec(params) {
207
+ const { model, field, enum: enumName } = params;
208
+ const members = new Set(params.members);
209
+ return {
210
+ encode: (value) => {
211
+ if (typeof value === "string" && members.has(value))
212
+ return value;
213
+ throw new VibeError2({
214
+ code: "VIBE_VALIDATION",
215
+ message: `Invalid value for enum ${enumName} on ${model}.${field}`,
216
+ meta: { model, field, enum: enumName }
217
+ });
218
+ },
219
+ decode: (value) => {
220
+ if (typeof value === "string" && members.has(value))
221
+ return value;
222
+ throw invalidStoredData({ model, field, enum: enumName, value });
223
+ }
224
+ };
225
+ }
226
+ function decodeIsNoop(params) {
227
+ const { scalarType, wire } = params;
228
+ if (wire === undefined)
229
+ return false;
230
+ if (scalarType === "DateTime")
231
+ return false;
232
+ if (scalarType === "Json")
233
+ return wire.json === "parsed";
234
+ if (scalarType === "Int" || scalarType === "Float")
235
+ return wire.numbers === "native";
236
+ return false;
237
+ }
238
+ var identity = (value) => value;
239
+ var passthroughCodec = { encode: identity, decode: identity };
240
+ var numberCodec = {
241
+ encode: identity,
242
+ decode: (value) => typeof value === "string" ? Number(value) : value
243
+ };
244
+ var bigIntCodec = {
245
+ encode: (value) => typeof value === "bigint" ? value.toString() : value,
246
+ decode: (value) => {
247
+ if (typeof value === "bigint")
248
+ return value;
249
+ if (typeof value === "string" || typeof value === "number")
250
+ return BigInt(value);
251
+ return value;
252
+ }
253
+ };
254
+ var decimalCodec = {
255
+ encode: (value) => typeof value === "number" || typeof value === "bigint" ? String(value) : value,
256
+ decode: identity
257
+ };
258
+ var mysqlDecimalCodec = {
259
+ encode: decimalCodec.encode,
260
+ decode: (value) => {
261
+ if (typeof value !== "string" || !value.includes("."))
262
+ return value;
263
+ const trimmed = value.replace(/0+$/, "").replace(/\.$/, "");
264
+ return trimmed === "" || trimmed === "-" ? "0" : trimmed;
265
+ }
266
+ };
267
+ var ZONE_LESS_DATETIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?$/;
268
+ function parseDateTimeText(params) {
269
+ const trimmed = params.text.trim();
270
+ if (ZONE_LESS_DATETIME.test(trimmed)) {
271
+ const asUtc = new Date(`${trimmed.replace(" ", "T").replace(/(\.\d{3})\d+$/, "$1")}Z`);
272
+ if (!Number.isNaN(asUtc.getTime()))
273
+ return asUtc;
274
+ }
275
+ const parsed = new Date(trimmed);
276
+ return Number.isNaN(parsed.getTime()) ? undefined : parsed;
277
+ }
278
+ var dateNativeCodec = {
279
+ encode: (value) => {
280
+ if (value instanceof Date && !Number.isFinite(value.getTime()) || typeof value === "number" && !Number.isFinite(value) || typeof value === "string" && /^[+-]?infinity$/i.test(value.trim())) {
281
+ throw new VibeError2({ code: "VIBE_VALIDATION", message: "DateTime parameters require finite timestamps; use an extended timestamp encoder for infinity" });
282
+ }
283
+ return value;
284
+ },
285
+ decode: (value) => {
286
+ const date = value instanceof Date ? value : typeof value === "string" ? parseDateTimeText({ text: value }) : typeof value === "number" ? new Date(value) : undefined;
287
+ if (date !== undefined && Number.isFinite(date.getTime()))
288
+ return date;
289
+ throw new VibeError2({ code: "VIBE_DATA_INVALID", message: "DateTime requires a finite timestamp; use an explicit extended timestamp decoder for infinity" });
290
+ }
291
+ };
292
+ var dateTextCodec = {
293
+ encode: (value) => {
294
+ dateNativeCodec.encode(value);
295
+ return value instanceof Date ? value.toISOString() : value;
296
+ },
297
+ decode: dateNativeCodec.decode
298
+ };
299
+ var mysqlDateCodec = {
300
+ encode: (value) => {
301
+ dateNativeCodec.encode(value);
302
+ if (value instanceof Date)
303
+ return value;
304
+ if (typeof value === "number") {
305
+ const parsed = new Date(value);
306
+ if (!Number.isNaN(parsed.getTime()))
307
+ return parsed;
308
+ return value;
309
+ }
310
+ if (typeof value === "string")
311
+ return parseDateTimeText({ text: value }) ?? value;
312
+ return value;
313
+ },
314
+ decode: dateNativeCodec.decode
315
+ };
316
+ var booleanIntCodec = {
317
+ encode: (value) => typeof value === "boolean" ? value ? 1 : 0 : value,
318
+ decode: (value) => typeof value === "number" ? value !== 0 : value
319
+ };
320
+ var booleanNativeInCodec = {
321
+ encode: identity,
322
+ decode: booleanIntCodec.decode
323
+ };
324
+ var jsonCodec = {
325
+ encode: (value) => JSON.stringify(value),
326
+ decode: (value) => {
327
+ if (typeof value !== "string")
328
+ return value;
329
+ try {
330
+ return JSON.parse(value);
331
+ } catch (cause) {
332
+ throw new VibeError2({
333
+ code: "VIBE_INTERNAL",
334
+ message: "a Json column returned text that is not valid JSON",
335
+ meta: { value },
336
+ cause
337
+ });
338
+ }
339
+ }
340
+ };
341
+ var POSTGRES_CODECS = {
342
+ String: passthroughCodec,
343
+ Boolean: passthroughCodec,
344
+ Int: numberCodec,
345
+ BigInt: bigIntCodec,
346
+ Float: numberCodec,
347
+ Decimal: decimalCodec,
348
+ DateTime: dateNativeCodec,
349
+ Json: jsonCodec,
350
+ Bytes: passthroughCodec
351
+ };
352
+ var SQLITE_CODECS = {
353
+ String: passthroughCodec,
354
+ Boolean: booleanIntCodec,
355
+ Int: numberCodec,
356
+ BigInt: bigIntCodec,
357
+ Float: numberCodec,
358
+ Decimal: decimalCodec,
359
+ DateTime: dateTextCodec,
360
+ Json: jsonCodec,
361
+ Bytes: passthroughCodec
362
+ };
363
+ var MYSQL_CODECS = {
364
+ String: passthroughCodec,
365
+ Boolean: booleanNativeInCodec,
366
+ Int: numberCodec,
367
+ BigInt: bigIntCodec,
368
+ Float: numberCodec,
369
+ Decimal: mysqlDecimalCodec,
370
+ DateTime: mysqlDateCodec,
371
+ Json: jsonCodec,
372
+ Bytes: passthroughCodec
373
+ };
374
+ var DIALECT_CODECS = {
375
+ postgres: POSTGRES_CODECS,
376
+ sqlite: SQLITE_CODECS,
377
+ mysql: MYSQL_CODECS
378
+ };
379
+
380
+ // packages/sql/src/result-decoder.ts
381
+ function refuse(encoding, message) {
382
+ throw new VibeError3({ code: encoding ? "VIBE_VALIDATION" : "VIBE_DATA_INVALID", message });
383
+ }
384
+ function scalar(type, valid) {
385
+ const convert = (params, encoding) => {
386
+ const { value, dialect } = params;
387
+ if (value === null || value === undefined)
388
+ refuse(encoding, `A non-null ${type} projection received null or a missing column`);
389
+ if (type === "BigInt" && !(typeof value === "bigint" || typeof value === "string" && /^[+-]?\d+$/.test(value) || typeof value === "number" && Number.isSafeInteger(value))) {
390
+ refuse(encoding, "BigInt requires exact integer text, bigint, or a safe integer");
391
+ }
392
+ if (type === "Boolean" && value !== true && value !== false && value !== 0 && value !== 1)
393
+ refuse(encoding, "Boolean requires true, false, 0, or 1");
394
+ if (type === "Decimal" && typeof value === "number")
395
+ refuse(encoding, "Decimal requires exact decimal text, not a floating-point number");
396
+ if ((type === "Int" || type === "Float") && typeof value === "string" && !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(value)) {
397
+ refuse(encoding, `Invalid ${type} text`);
398
+ }
399
+ const codec = DIALECT_CODECS[dialect][type];
400
+ const result = type === "Json" && params.wire?.json === "parsed" ? value : codec.decode(value);
401
+ if (!valid(result))
402
+ refuse(encoding, `Invalid ${type} projection value`);
403
+ return result;
404
+ };
405
+ return Object.freeze({
406
+ decode: (params) => convert(params, false),
407
+ encode: (params) => {
408
+ const value = type === "Json" ? params.value : convert(params, true);
409
+ if (value === undefined || value === null)
410
+ refuse(true, `A non-null ${type} parameter cannot be null or undefined`);
411
+ return DIALECT_CODECS[params.dialect][type].encode(value);
412
+ }
413
+ });
414
+ }
415
+ var stringDecoder = scalar("String", (value) => typeof value === "string");
416
+ var dateDecoder = scalar("DateTime", (value) => value instanceof Date && Number.isFinite(value.getTime()));
417
+ var extendedDecoder = Object.freeze({
418
+ decode: (params) => {
419
+ if (params.value === "infinity" || params.value === Infinity)
420
+ return "infinity";
421
+ if (params.value === "-infinity" || params.value === -Infinity)
422
+ return "-infinity";
423
+ return dateDecoder.decode(params);
424
+ },
425
+ encode: (params) => {
426
+ if (params.value === "infinity" || params.value === "-infinity") {
427
+ if (params.dialect !== "postgres")
428
+ throw new VibeError3({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Timestamp infinity parameters require PostgreSQL" });
429
+ return params.value;
430
+ }
431
+ return dateDecoder.encode(params);
432
+ }
433
+ });
434
+ var decode = Object.freeze({
435
+ string: stringDecoder,
436
+ boolean: scalar("Boolean", (value) => typeof value === "boolean"),
437
+ int: scalar("Int", (value) => typeof value === "number" && Number.isSafeInteger(value)),
438
+ float: scalar("Float", (value) => typeof value === "number" && Number.isFinite(value)),
439
+ bigInt: scalar("BigInt", (value) => typeof value === "bigint"),
440
+ decimal: scalar("Decimal", (value) => typeof value === "string" && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(value)),
441
+ dateTime: dateDecoder,
442
+ extendedDateTime: extendedDecoder,
443
+ json: scalar("Json", (value) => value !== undefined),
444
+ bytes: scalar("Bytes", (value) => value instanceof Uint8Array),
445
+ nullable: ({ decoder }) => Object.freeze({
446
+ decode: (params) => params.value === null ? null : decoder.decode(params),
447
+ encode: (params) => params.value === null ? null : decoder.encode(params)
448
+ }),
449
+ array: ({ decoder }) => Object.freeze({
450
+ decode: (params) => {
451
+ const raw = params.value;
452
+ const value = params.dialect === "postgres" && typeof raw === "string" ? parsePgArrayLiteral({ literal: raw }) : ArrayBuffer.isView(raw) && ("length" in raw) ? Array.from(raw) : raw;
453
+ if (!Array.isArray(value))
454
+ refuse(false, "Expected an array projection");
455
+ return value.map((element) => decoder.decode({ ...params, value: element }));
456
+ },
457
+ encode: (params) => {
458
+ if (!Array.isArray(params.value))
459
+ refuse(true, "Expected an array parameter");
460
+ return params.value.map((value) => decoder.encode({ ...params, value }));
461
+ }
462
+ }),
463
+ enum: ({ values }) => {
464
+ const members = new Set(values);
465
+ return Object.freeze({
466
+ decode: ({ value }) => typeof value === "string" && members.has(value) ? value : refuse(false, "Unknown enum projection member"),
467
+ encode: ({ value }) => typeof value === "string" && members.has(value) ? value : refuse(true, "Unknown enum parameter member")
468
+ });
469
+ },
470
+ object: ({ fields }) => {
471
+ const entries = Object.entries(fields);
472
+ const convert = (params, encoding) => {
473
+ if (typeof params.value !== "object" || params.value === null || Array.isArray(params.value))
474
+ refuse(encoding, "Expected a result row object");
475
+ const row = params.value;
476
+ return Object.fromEntries(entries.map(([name, decoder]) => {
477
+ if (!Object.hasOwn(row, name))
478
+ refuse(encoding, `Missing projection column "${name}"`);
479
+ return [name, encoding ? decoder.encode({ ...params, value: row[name] }) : decoder.decode({ ...params, value: row[name] })];
480
+ }));
481
+ };
482
+ return Object.freeze({ decode: (params) => convert(params, false), encode: (params) => convert(params, true) });
483
+ }
484
+ });
485
+ // packages/sql/src/exclusion.ts
486
+ import { VibeError as VibeError5, fieldTypeIdentity as fieldTypeIdentity2, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
487
+
488
+ // packages/sql/src/predicate.ts
489
+ import { VibeError as VibeError4, fieldTypeIdentity, isEnumType, unsupportedCapability } from "@vibeorm/schema";
490
+ function renderPredicate(params) {
491
+ if (params.usage === "exclusionPredicate" && !params.dialect.capabilities.exclusionConstraints)
492
+ throw unsupportedCapability({ dialect: params.dialect.name, feature: "exclusionConstraints" });
493
+ if (params.usage === "indexPredicate" && !params.dialect.capabilities.partialIndexes) {
494
+ throw unsupportedCapability({ dialect: params.dialect.name, feature: "partialIndexes" });
495
+ }
496
+ const context = {
497
+ model: params.model,
498
+ dialect: params.dialect,
499
+ enums: params.enums ?? [],
500
+ usage: params.usage,
501
+ site: params.site
502
+ };
503
+ return renderNode({ node: params.predicate, context });
504
+ }
505
+ var PRECEDENCE = {
506
+ or: 1,
507
+ and: 2,
508
+ not: 3,
509
+ compare: 4,
510
+ inList: 4,
511
+ isNull: 4
512
+ };
513
+ var COMPARISON_SQL = {
514
+ eq: "=",
515
+ ne: "<>",
516
+ gt: ">",
517
+ gte: ">=",
518
+ lt: "<",
519
+ lte: "<="
520
+ };
521
+ var EXACT_INTEGER = /^-?(0|[1-9]\d*)$/;
522
+ var EXACT_DECIMAL = /^-?(0|[1-9]\d*)(\.\d+)?$/;
523
+ var INT32_MIN = -2147483648n;
524
+ var INT32_MAX = 2147483647n;
525
+ var INT64_MIN = -(2n ** 63n);
526
+ var INT64_MAX = 2n ** 63n - 1n;
527
+ function refuse2(params) {
528
+ const { context, rule, message } = params;
529
+ throw new VibeError4({
530
+ code: "VIBE_SCHEMA_INVALID",
531
+ message: `${context.site} on "${context.model.name}": ${message}`,
532
+ meta: { rule, model: context.model.name, site: context.site, ...params.meta ?? {} }
533
+ });
534
+ }
535
+ function renderChild(params) {
536
+ const { node, parent, context } = params;
537
+ if ((node.kind === "and" || node.kind === "or") && node.operands.length === 1) {
538
+ return renderChild({ node: node.operands[0], parent, context });
539
+ }
540
+ const text = renderNode({ node, context });
541
+ return PRECEDENCE[node.kind] < PRECEDENCE[parent] ? `(${text})` : text;
542
+ }
543
+ function renderNode(params) {
544
+ const { node, context } = params;
545
+ switch (node.kind) {
546
+ case "and":
547
+ case "or": {
548
+ if (node.operands.length === 0) {
549
+ refuse2({
550
+ context,
551
+ rule: "predicate-empty",
552
+ message: `${node.kind === "and" ? "and()" : "or()"} has no operands \u2014 an empty boolean group has no honest SQL spelling`
553
+ });
554
+ }
555
+ if (node.operands.length === 1)
556
+ return renderNode({ node: node.operands[0], context });
557
+ const separator = node.kind === "and" ? " AND " : " OR ";
558
+ return node.operands.map((operand) => renderChild({ node: operand, parent: node.kind, context })).join(separator);
559
+ }
560
+ case "not":
561
+ return `NOT ${renderChild({ node: node.operand, parent: "not", context })}`;
562
+ case "isNull": {
563
+ const field = resolveField({ name: node.field.name, context });
564
+ return `${quoteColumn({ field, context })} IS ${node.negate === true ? "NOT NULL" : "NULL"}`;
565
+ }
566
+ case "compare": {
567
+ const left = resolveField({ name: node.left.name, context });
568
+ const right = renderOperand({ operand: node.right, field: left, context });
569
+ return `${compareColumn({ field: left, context })} ${COMPARISON_SQL[node.op]} ${right}`;
570
+ }
571
+ case "inList": {
572
+ if (node.values.length === 0) {
573
+ refuse2({
574
+ context,
575
+ rule: "predicate-empty",
576
+ message: `inList("${node.field.name}") has no values \u2014 an empty IN list is UNKNOWN on every row and never what an author means`,
577
+ meta: { field: node.field.name }
578
+ });
579
+ }
580
+ const field = resolveField({ name: node.field.name, context });
581
+ const values = node.values.map((value) => renderLiteral({ value, field, context })).join(", ");
582
+ return `${compareColumn({ field, context })} ${node.negate === true ? "NOT IN" : "IN"} (${values})`;
583
+ }
584
+ }
585
+ }
586
+ function resolveField(params) {
587
+ const { name, context } = params;
588
+ const field = context.model.fields.find((candidate) => candidate.name === name);
589
+ if (field === undefined) {
590
+ refuse2({
591
+ context,
592
+ rule: "predicate-unknown-field",
593
+ message: `references field "${name}", which the model does not declare`,
594
+ meta: { field: name }
595
+ });
596
+ }
597
+ if (field.isList) {
598
+ refuse2({
599
+ context,
600
+ rule: "predicate-list-field",
601
+ message: `compares scalar list "${name}" \u2014 array operators differ per dialect; use a raw expression for them`,
602
+ meta: { field: name }
603
+ });
604
+ }
605
+ if (field.isUnsupported === true) {
606
+ refuse2({
607
+ context,
608
+ rule: "predicate-unsupported-type",
609
+ message: `references "${name}", an Unsupported("${field.nativeType ?? "?"}") column whose operators VibeORM does not model \u2014 use a raw expression`,
610
+ meta: { field: name }
611
+ });
612
+ }
613
+ if (field.type === "Json" || field.type === "Bytes") {
614
+ refuse2({
615
+ context,
616
+ rule: "predicate-unsupported-type",
617
+ message: `references ${field.type} column "${name}" \u2014 ${field.type} comparison operators differ per dialect; use a raw expression`,
618
+ meta: { field: name, type: field.type }
619
+ });
620
+ }
621
+ if (context.usage === "check" && context.dialect.name === "mysql" && field.default?.kind === "autoincrement") {
622
+ throw unsupportedCapability({
623
+ dialect: "mysql",
624
+ feature: `CHECK constraint referencing auto-increment column "${context.model.name}.${name}"`,
625
+ hint: "mysql refuses this with error 3818 \u2014 enforce the rule in application code or on a non-generated column"
626
+ });
627
+ }
628
+ return field;
629
+ }
630
+ function quoteColumn(params) {
631
+ const { field, context } = params;
632
+ return context.dialect.quoteIdent({ name: field.dbName ?? field.name });
633
+ }
634
+ function compareColumn(params) {
635
+ const { field, context } = params;
636
+ const quoted = quoteColumn({ field, context });
637
+ return context.dialect.name === "sqlite" && field.type === "Decimal" ? `CAST(${quoted} AS REAL)` : quoted;
638
+ }
639
+ function renderOperand(params) {
640
+ const { operand, field, context } = params;
641
+ if (operand.kind === "value")
642
+ return renderLiteral({ value: operand, field, context });
643
+ const other = resolveField({ name: operand.name, context });
644
+ const leftType = fieldTypeIdentity({ type: field.type });
645
+ const rightType = fieldTypeIdentity({ type: other.type });
646
+ if (leftType !== rightType) {
647
+ refuse2({
648
+ context,
649
+ rule: "predicate-type-mismatch",
650
+ message: `compares "${field.name}" (${leftType}) with "${other.name}" (${rightType}) \u2014 both sides of a comparison need the same scalar type`,
651
+ meta: { field: field.name, other: other.name, fieldType: leftType, otherType: rightType }
652
+ });
653
+ }
654
+ return compareColumn({ field: other, context });
655
+ }
656
+ function renderLiteral(params) {
657
+ const { field, context } = params;
658
+ const { value } = params.value;
659
+ const type = field.type;
660
+ const wrongCarrier = (expected) => refuse2({
661
+ context,
662
+ rule: "predicate-type-mismatch",
663
+ message: `compares ${fieldTypeIdentity({ type })} field "${field.name}" with ${describe({ value })} \u2014 ${expected}`,
664
+ meta: { field: field.name, fieldType: fieldTypeIdentity({ type }), value }
665
+ });
666
+ if (isEnumType(type)) {
667
+ if (typeof value !== "string")
668
+ return wrongCarrier(`enum ${type.enum} takes one of its member names as a string`);
669
+ const declared = context.enums.find((entry) => entry.name === type.enum);
670
+ if (declared !== undefined && !declared.values.includes(value)) {
671
+ refuse2({
672
+ context,
673
+ rule: "predicate-enum-member",
674
+ message: `compares "${field.name}" with "${value}", which is not a member of enum ${type.enum} (${declared.values.join(", ")})`,
675
+ meta: { field: field.name, enum: type.enum, value, members: [...declared.values] }
676
+ });
677
+ }
678
+ return stringLiteral({ value, context, field });
679
+ }
680
+ switch (type) {
681
+ case "String":
682
+ if (typeof value !== "string")
683
+ return wrongCarrier("a String column takes a string literal");
684
+ return stringLiteral({ value, context, field });
685
+ case "Boolean":
686
+ if (typeof value !== "boolean")
687
+ return wrongCarrier("a Boolean column takes `true` or `false`");
688
+ return value ? context.dialect.booleanLiteral.true : context.dialect.booleanLiteral.false;
689
+ case "Int":
690
+ return integerLiteral({ value, field, context, min: INT32_MIN, max: INT32_MAX, label: "Int" });
691
+ case "BigInt":
692
+ return integerLiteral({ value, field, context, min: INT64_MIN, max: INT64_MAX, label: "BigInt" });
693
+ case "Float": {
694
+ if (typeof value !== "number")
695
+ return wrongCarrier("a Float column takes a number");
696
+ if (!Number.isFinite(value)) {
697
+ refuse2({
698
+ context,
699
+ rule: "predicate-literal-invalid",
700
+ message: `compares "${field.name}" with ${String(value)} \u2014 a Float literal must be finite`,
701
+ meta: { field: field.name, value: String(value) }
702
+ });
703
+ }
704
+ return String(value);
705
+ }
706
+ case "Decimal": {
707
+ if (typeof value !== "string") {
708
+ return wrongCarrier('a Decimal column takes exact decimal TEXT ("0", "19.99") \u2014 a JS number cannot carry an exact decimal');
709
+ }
710
+ if (!EXACT_DECIMAL.test(value)) {
711
+ refuse2({
712
+ context,
713
+ rule: "predicate-literal-invalid",
714
+ message: `compares "${field.name}" with "${value}", which is not an exact decimal literal`,
715
+ meta: { field: field.name, value }
716
+ });
717
+ }
718
+ return value;
719
+ }
720
+ case "DateTime":
721
+ refuse2({
722
+ context,
723
+ rule: "predicate-unsupported-literal",
724
+ message: `compares DateTime field "${field.name}" with a literal \u2014 DateTime literals are spelled differently on postgres, mysql and sqlite, so VibeORM does not guess one. Compare two DateTime columns, or write a raw expression for a fixed instant`,
725
+ meta: { field: field.name }
726
+ });
727
+ case "Json":
728
+ case "Bytes":
729
+ return wrongCarrier(`${type} columns take no predicate literal`);
730
+ }
731
+ }
732
+ function integerLiteral(params) {
733
+ const { value, field, context, min, max, label } = params;
734
+ let text;
735
+ if (typeof value === "number") {
736
+ if (!Number.isSafeInteger(value)) {
737
+ refuse2({
738
+ context,
739
+ rule: "predicate-literal-invalid",
740
+ message: `compares "${field.name}" with ${String(value)} \u2014 an ${label} literal must be an exact integer JavaScript can represent; pass a bigint or a decimal string for larger values`,
741
+ meta: { field: field.name, value: String(value) }
742
+ });
743
+ }
744
+ text = String(value);
745
+ } else if (typeof value === "string") {
746
+ if (!EXACT_INTEGER.test(value)) {
747
+ refuse2({
748
+ context,
749
+ rule: "predicate-literal-invalid",
750
+ message: `compares "${field.name}" with "${value}", which is not an exact integer literal`,
751
+ meta: { field: field.name, value }
752
+ });
753
+ }
754
+ text = value;
755
+ } else {
756
+ refuse2({
757
+ context,
758
+ rule: "predicate-type-mismatch",
759
+ message: `compares ${label} field "${field.name}" with ${describe({ value })} \u2014 an ${label} column takes an integer`,
760
+ meta: { field: field.name, value }
761
+ });
762
+ }
763
+ const parsed = BigInt(text);
764
+ if (parsed < min || parsed > max) {
765
+ refuse2({
766
+ context,
767
+ rule: "predicate-literal-invalid",
768
+ message: `compares "${field.name}" with ${text}, which is outside the range an ${label} column can hold (${min}\u2026${max})`,
769
+ meta: { field: field.name, value: text }
770
+ });
771
+ }
772
+ return text;
773
+ }
774
+ function stringLiteral(params) {
775
+ const { value, context, field } = params;
776
+ if (value.includes("\x00")) {
777
+ refuse2({
778
+ context,
779
+ rule: "predicate-literal-invalid",
780
+ message: `compares "${field.name}" with a string containing a NUL byte, which no dialect here can store`,
781
+ meta: { field: field.name }
782
+ });
783
+ }
784
+ return context.dialect.quoteStringLiteral({ value });
785
+ }
786
+ function describe(params) {
787
+ const { value } = params;
788
+ return typeof value === "string" ? `the string ${JSON.stringify(value)}` : `the ${typeof value} ${String(value)}`;
789
+ }
790
+
791
+ // packages/sql/src/exclusion.ts
792
+ function invalid2(rule) {
793
+ throw new VibeError5({ code: "VIBE_SCHEMA_INVALID", message: `Invalid exclusion constraint: ${rule}`, meta: { rule: `exclusion-${rule}` } });
794
+ }
795
+ function compileExclusion(params) {
796
+ const { exclusion: spec, model, dialect } = params;
797
+ if (!dialect.capabilities.exclusionConstraints)
798
+ throw unsupportedCapability2({ dialect: dialect.name, feature: "exclusionConstraints" });
799
+ if (!spec.name || spec.name.includes("\x00"))
800
+ invalid2("name");
801
+ if (!["int8range", "tsrange", "tstzrange"].includes(spec.range.type))
802
+ invalid2("range-type");
803
+ if (!["[)", "[]", "()", "(]"].includes(spec.range.bounds))
804
+ invalid2("bounds");
805
+ const field = (name) => {
806
+ const value = model.fields.find((entry) => entry.name === name);
807
+ if (value === undefined || value.isList || value.isUnsupported)
808
+ invalid2("field");
809
+ return value;
810
+ };
811
+ const endpoint = (value) => {
812
+ if ("unbounded" in value)
813
+ return "NULL";
814
+ const infinity = "infinity" in value ? value.infinity : value.nullAs;
815
+ if (infinity !== undefined && (spec.range.type === "int8range" || !["infinity", "-infinity"].includes(infinity)))
816
+ invalid2("infinity");
817
+ const literal = infinity === undefined ? undefined : `${dialect.quoteStringLiteral({ value: infinity })}::${spec.range.type === "tsrange" ? "timestamp" : "timestamptz"}`;
818
+ if ("infinity" in value)
819
+ return literal;
820
+ const column = field(value.field);
821
+ if (fieldTypeIdentity2({ type: column.type }) !== (spec.range.type === "int8range" ? "BigInt" : "DateTime"))
822
+ invalid2("range-field-type");
823
+ if (column.type === "DateTime") {
824
+ const timezone = /timestamptz|timestamp.*with time zone/i.test(column.nativeType ?? "timestamptz");
825
+ if (timezone !== (spec.range.type === "tstzrange"))
826
+ invalid2("range-timezone");
827
+ }
828
+ const sql2 = dialect.quoteIdent({ name: column.dbName ?? column.name });
829
+ return literal === undefined ? sql2 : `COALESCE(${sql2}, ${literal})`;
830
+ };
831
+ const keys = spec.keys.map((key) => {
832
+ if ("expression" in key) {
833
+ if (!key.expression.trim() || key.expression.includes("\x00") || key.fields.length === 0)
834
+ invalid2("expression");
835
+ key.fields.forEach(field);
836
+ return `(${key.expression}) WITH =`;
837
+ }
838
+ const column = field(key.field);
839
+ if (column.isOptional)
840
+ invalid2("nullable-key-requires-expression");
841
+ if (!["String", "Int", "BigInt", "Float", "Decimal", "Boolean", "DateTime"].includes(fieldTypeIdentity2({ type: column.type })))
842
+ invalid2("key-type");
843
+ return `${dialect.quoteIdent({ name: column.dbName ?? column.name })} WITH =`;
844
+ });
845
+ keys.push(`${spec.range.type}(${endpoint(spec.range.lower)}, ${endpoint(spec.range.upper)}, ${dialect.quoteStringLiteral({ value: spec.range.bounds })}) WITH &&`);
846
+ const where = spec.where === undefined ? "" : ` WHERE (${renderPredicate({ predicate: spec.where, model, dialect, usage: "exclusionPredicate", site: spec.name })})`;
847
+ return { name: spec.name, definition: `EXCLUDE USING gist (${keys.join(", ")})${where}`, source: spec, requiredExtensions: spec.keys.length === 0 ? [] : dialect.capabilities.exclusionExtensions };
848
+ }
849
+ function renderExclusionSetup(params) {
850
+ if (!params.dialect.capabilities.exclusionConstraints)
851
+ throw unsupportedCapability2({ dialect: params.dialect.name, feature: "exclusionConstraints" });
852
+ return params.exclusion.requiredExtensions.map((name) => `CREATE EXTENSION IF NOT EXISTS ${params.dialect.quoteIdent({ name })};`);
853
+ }
854
+ function renderExclusionDdl(params) {
855
+ const { dialect, table, exclusion, operation } = params;
856
+ if (!dialect.capabilities.exclusionConstraints)
857
+ throw unsupportedCapability2({ dialect: dialect.name, feature: "exclusionConstraints" });
858
+ const target = `ALTER TABLE ${dialect.quoteIdent({ name: table })}`;
859
+ if (operation === "drop")
860
+ return [`${target} DROP CONSTRAINT ${dialect.quoteIdent({ name: exclusion.name })};`];
861
+ return [...renderExclusionSetup({ dialect, exclusion }), `${target} ADD CONSTRAINT ${dialect.quoteIdent({ name: exclusion.name })} ${exclusion.definition};`];
862
+ }
863
+ function renderExclusionCatalog(params) {
864
+ const { dialect, probe } = params;
865
+ if (!dialect.capabilities.exclusionConstraints)
866
+ throw unsupportedCapability2({ dialect: dialect.name, feature: "exclusionConstraints" });
867
+ const scope = probe === undefined ? "n.nspname = 'public'" : `t.oid = ${dialect.quoteStringLiteral({ value: probe })}::regclass`;
868
+ return `SELECT t.relname AS table_name, c.conname AS constraint_name, pg_catalog.pg_get_constraintdef(c.oid, true) AS definition, c.convalidated AS validated, i.indisvalid AS valid, i.indisready AS ready FROM pg_catalog.pg_constraint c JOIN pg_catalog.pg_class t ON t.oid = c.conrelid JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace JOIN pg_catalog.pg_index i ON i.indexrelid = c.conindid WHERE c.contype = 'x' AND ${scope} ORDER BY t.relname, c.conname`;
869
+ }
870
+ function renderExclusionProbe(params) {
871
+ const { dialect, table, probe, definition } = params;
872
+ if (!dialect.capabilities.exclusionConstraints)
873
+ throw unsupportedCapability2({ dialect: dialect.name, feature: "exclusionConstraints" });
874
+ return [`CREATE TEMP TABLE ${dialect.quoteIdent({ name: probe })} (LIKE ${dialect.quoteIdent({ name: "public" })}.${dialect.quoteIdent({ name: table })})`, `ALTER TABLE ${dialect.quoteIdent({ name: probe })} ADD CONSTRAINT ${dialect.quoteIdent({ name: `${probe}_x` })} ${definition}`];
875
+ }
2
876
  // packages/sql/src/ast.ts
3
877
  var SET_OPERATORS = ["increment", "decrement", "multiply", "divide"];
4
878
  function isSetOperation(value) {
@@ -48,6 +922,90 @@ function excludedRef(params) {
48
922
  function isExcludedRef(value) {
49
923
  return typeof value === "object" && value !== null && value.__excluded === true;
50
924
  }
925
+ var ADVISORY_LOCK_RESULT_COLUMN = "acquired";
926
+ // packages/sql/src/locks.ts
927
+ import { internalError, unsupportedCapability as unsupportedCapability3 } from "@vibeorm/schema";
928
+ var ROW_LOCK_PROSE = Object.freeze({
929
+ strengths: Object.freeze({
930
+ update: "FOR UPDATE",
931
+ noKeyUpdate: "FOR NO KEY UPDATE",
932
+ share: "FOR SHARE",
933
+ keyShare: "FOR KEY SHARE"
934
+ }),
935
+ wait: Object.freeze({ wait: "", nowait: " NOWAIT", skipLocked: " SKIP LOCKED" })
936
+ });
937
+ function describeRowLock(params) {
938
+ const { strength, wait } = params.lock;
939
+ return `${ROW_LOCK_PROSE.strengths[strength]}${ROW_LOCK_PROSE.wait[wait]}`;
940
+ }
941
+ function renderRowLockClause(params) {
942
+ const { dialect, lock } = params;
943
+ const syntax = dialect.rowLockSyntax;
944
+ if (syntax === null) {
945
+ if (lock.strength === "update" && lock.wait === "wait")
946
+ return null;
947
+ throw unsupportedCapability3({
948
+ dialect: dialect.name,
949
+ feature: `a ${describeRowLock({ lock })} locking read`,
950
+ hint: `${dialect.name} has no locking-read clause at all`
951
+ });
952
+ }
953
+ const strengthText = syntax.strengths[lock.strength];
954
+ if (strengthText === undefined) {
955
+ throw unsupportedCapability3({
956
+ dialect: dialect.name,
957
+ feature: `the ${describeRowLock({ lock: { ...lock, wait: "wait" } })} row-lock strength`,
958
+ hint: `${dialect.name} can express: ${Object.keys(syntax.strengths).join(", ")}`
959
+ });
960
+ }
961
+ const waitText = syntax.wait[lock.wait];
962
+ if (waitText === undefined) {
963
+ throw unsupportedCapability3({
964
+ dialect: dialect.name,
965
+ feature: `the "${lock.wait}" lock wait policy`,
966
+ hint: `${dialect.name} can express: ${Object.keys(syntax.wait).join(", ")}`
967
+ });
968
+ }
969
+ return `${strengthText}${waitText}`;
970
+ }
971
+ var ADVISORY_KEY_BOUNDS = Object.freeze({
972
+ single: Object.freeze({ min: -(2n ** 63n), max: 2n ** 63n - 1n }),
973
+ pair: Object.freeze({ min: -(2 ** 31), max: 2 ** 31 - 1 })
974
+ });
975
+ function isSingleKey(key) {
976
+ return "key" in key;
977
+ }
978
+ function renderAdvisoryLock(params) {
979
+ const { dialect, statement, collector } = params;
980
+ const functions = dialect.advisoryLockFunctions;
981
+ if (functions === null) {
982
+ throw unsupportedCapability3({
983
+ dialect: dialect.name,
984
+ feature: "advisory locks",
985
+ hint: dialect.name === "mysql" ? "mysql's GET_LOCK is SESSION-scoped \u2014 it survives a rollback, so it cannot be released with the transaction" : `${dialect.name} has no advisory-lock functions`
986
+ });
987
+ }
988
+ const mode = statement.mode;
989
+ const fn = (mode === "exclusive" ? functions.exclusive : functions.shared)[statement.wait];
990
+ const key = statement.key;
991
+ const args = isSingleKey(key) ? `${collector.add(key.key.toString())}${functions.keyCast.single}` : `${collector.add(String(assertInt32({ value: key.classId, part: "classId" })))}${functions.keyCast.pair}, ` + `${collector.add(String(assertInt32({ value: key.objectId, part: "objectId" })))}${functions.keyCast.pair}`;
992
+ const projection = statement.wait === "nowait" ? ` AS ${dialect.quoteIdent({ name: ADVISORY_LOCK_RESULT_COLUMN })}` : "";
993
+ return {
994
+ text: `SELECT ${fn}(${args})${projection}`,
995
+ values: collector.values,
996
+ returning: "none"
997
+ };
998
+ }
999
+ function assertInt32(params) {
1000
+ const { value, part } = params;
1001
+ if (!Number.isInteger(value) || value < ADVISORY_KEY_BOUNDS.pair.min || value > ADVISORY_KEY_BOUNDS.pair.max) {
1002
+ throw internalError({
1003
+ message: `advisory lock ${part} must be a 32-bit integer, got ${String(value)}`,
1004
+ meta: { part, value }
1005
+ });
1006
+ }
1007
+ return value;
1008
+ }
51
1009
  // packages/sql/src/json-transport.ts
52
1010
  var JSON_TRANSPORT = Object.freeze({ chunkSize: 100 });
53
1011
  function projectionOutputName(params) {
@@ -93,12 +1051,35 @@ var postgresDialect = {
93
1051
  ],
94
1052
  jsonParamCast: "::text::jsonb",
95
1053
  lastInsertIdSql: null,
96
- selectForUpdate: " FOR UPDATE",
1054
+ rowLockSyntax: {
1055
+ strengths: Object.freeze({
1056
+ update: "FOR UPDATE",
1057
+ noKeyUpdate: "FOR NO KEY UPDATE",
1058
+ share: "FOR SHARE",
1059
+ keyShare: "FOR KEY SHARE"
1060
+ }),
1061
+ wait: Object.freeze({ wait: "", nowait: " NOWAIT", skipLocked: " SKIP LOCKED" })
1062
+ },
1063
+ advisoryLockFunctions: {
1064
+ exclusive: Object.freeze({
1065
+ wait: "pg_catalog.pg_advisory_xact_lock",
1066
+ nowait: "pg_catalog.pg_try_advisory_xact_lock"
1067
+ }),
1068
+ shared: Object.freeze({
1069
+ wait: "pg_catalog.pg_advisory_xact_lock_shared",
1070
+ nowait: "pg_catalog.pg_try_advisory_xact_lock_shared"
1071
+ }),
1072
+ keyCast: Object.freeze({ single: "::bigint", pair: "::int4" })
1073
+ },
97
1074
  rowDefaultKeyword: true,
98
1075
  paramBudget: 30000,
1076
+ booleanLiteral: { true: "true", false: "false" },
99
1077
  quoteIdent({ name }) {
100
1078
  return `"${name.replaceAll('"', '""')}"`;
101
1079
  },
1080
+ quoteStringLiteral({ value }) {
1081
+ return `'${value.replaceAll("'", "''")}'`;
1082
+ },
102
1083
  placeholder({ index }) {
103
1084
  return `$${index}`;
104
1085
  },
@@ -127,260 +1108,104 @@ var sqliteDialect = {
127
1108
  orderByNullsMode: "native",
128
1109
  offsetRequiresLimit: { limitText: "-1" },
129
1110
  likeEscapeClause: " ESCAPE '\\'",
130
- jsonPathMode: "sqliteExtract",
131
- supportedJsonOps: [
132
- "equals",
133
- "string_contains",
134
- "string_starts_with",
135
- "string_ends_with",
136
- "array_contains",
137
- "array_starts_with",
138
- "array_ends_with"
139
- ],
140
- jsonParamCast: "",
141
- lastInsertIdSql: null,
142
- selectForUpdate: null,
143
- rowDefaultKeyword: false,
144
- paramBudget: 900,
145
- quoteIdent({ name }) {
146
- return `"${name.replaceAll('"', '""')}"`;
147
- },
148
- placeholder() {
149
- return "?";
150
- },
151
- renderDbNow({ offsetSeconds, collector }) {
152
- if (offsetSeconds === 0)
153
- return `strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
154
- return `strftime('%Y-%m-%dT%H:%M:%fZ', 'now', ${collector.add(offsetSeconds)} || ' seconds')`;
155
- }
156
- };
157
- // packages/sql/src/dialects/mysql.ts
158
- var mysqlDialect = {
159
- name: "mysql",
160
- capabilities: MYSQL_CAPABILITIES,
161
- inArrayStrategy: "expand",
162
- tupleInStrategy: "rowValue",
163
- upsertForm: "onDuplicateKey",
164
- conflictKeyEquality: {
165
- foldingScalars: ["Decimal"],
166
- defaultStringMaxLength: 191,
167
- textIsBinaryByDefault: false,
168
- duplicatesInOneStatement: "lastWriteWins"
169
- },
170
- excludedRowRef: { form: "rowAlias", alias: "new" },
171
- doNothingForm: "insertIgnore",
172
- insensitiveLike: "lower",
173
- strictMatchStrategy: "binary",
174
- orderByNullsMode: "emulate",
175
- offsetRequiresLimit: { limitText: "18446744073709551615" },
176
- likeEscapeClause: null,
177
- jsonPathMode: "mysqlExtract",
178
- supportedJsonOps: [
179
- "equals",
180
- "string_contains",
181
- "string_starts_with",
182
- "string_ends_with",
183
- "array_contains",
184
- "array_starts_with",
185
- "array_ends_with"
186
- ],
187
- jsonParamCast: "",
188
- lastInsertIdSql: "SELECT LAST_INSERT_ID() AS `id`",
189
- selectForUpdate: " FOR UPDATE",
190
- rowDefaultKeyword: true,
191
- paramBudget: 1e4,
192
- quoteIdent({ name }) {
193
- return `\`${name.replaceAll("`", "``")}\``;
194
- },
195
- placeholder() {
196
- return "?";
197
- },
198
- renderDbNow({ offsetSeconds, collector }) {
199
- if (offsetSeconds === 0)
200
- return "NOW(6)";
201
- return `DATE_ADD(NOW(6), INTERVAL ${collector.add(offsetSeconds)} SECOND)`;
202
- }
203
- };
204
- // packages/sql/src/dialects/registry.ts
205
- var SQL_DIALECTS = {
206
- postgres: postgresDialect,
207
- sqlite: sqliteDialect,
208
- mysql: mysqlDialect
209
- };
210
- function getSqlDialect(params) {
211
- return SQL_DIALECTS[params.dialect];
212
- }
213
- // packages/sql/src/codecs.ts
214
- import { VibeError, invalidStoredData } from "@vibeorm/schema";
215
- function enumMembershipCodec(params) {
216
- const { model, field, enum: enumName } = params;
217
- const members = new Set(params.members);
218
- return {
219
- encode: (value) => {
220
- if (typeof value === "string" && members.has(value))
221
- return value;
222
- throw new VibeError({
223
- code: "VIBE_VALIDATION",
224
- message: `Invalid value for enum ${enumName} on ${model}.${field}`,
225
- meta: { model, field, enum: enumName }
226
- });
227
- },
228
- decode: (value) => {
229
- if (typeof value === "string" && members.has(value))
230
- return value;
231
- throw invalidStoredData({ model, field, enum: enumName, value });
232
- }
233
- };
234
- }
235
- function decodeIsNoop(params) {
236
- const { scalarType, wire } = params;
237
- if (wire === undefined)
238
- return false;
239
- if (scalarType === "DateTime")
240
- return wire.dateTime === "native";
241
- if (scalarType === "Json")
242
- return wire.json === "parsed";
243
- if (scalarType === "Int" || scalarType === "Float")
244
- return wire.numbers === "native";
245
- return false;
246
- }
247
- var identity = (value) => value;
248
- var passthroughCodec = { encode: identity, decode: identity };
249
- var numberCodec = {
250
- encode: identity,
251
- decode: (value) => typeof value === "string" ? Number(value) : value
252
- };
253
- var bigIntCodec = {
254
- encode: (value) => typeof value === "bigint" ? value.toString() : value,
255
- decode: (value) => {
256
- if (typeof value === "bigint")
257
- return value;
258
- if (typeof value === "string" || typeof value === "number")
259
- return BigInt(value);
260
- return value;
261
- }
262
- };
263
- var decimalCodec = {
264
- encode: (value) => typeof value === "number" || typeof value === "bigint" ? String(value) : value,
265
- decode: identity
266
- };
267
- var mysqlDecimalCodec = {
268
- encode: decimalCodec.encode,
269
- decode: (value) => {
270
- if (typeof value !== "string" || !value.includes("."))
271
- return value;
272
- const trimmed = value.replace(/0+$/, "").replace(/\.$/, "");
273
- return trimmed === "" || trimmed === "-" ? "0" : trimmed;
274
- }
275
- };
276
- var ZONE_LESS_DATETIME = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?$/;
277
- function parseDateTimeText(params) {
278
- const trimmed = params.text.trim();
279
- if (ZONE_LESS_DATETIME.test(trimmed)) {
280
- const asUtc = new Date(`${trimmed.replace(" ", "T").replace(/(\.\d{3})\d+$/, "$1")}Z`);
281
- if (!Number.isNaN(asUtc.getTime()))
282
- return asUtc;
283
- }
284
- const parsed = new Date(trimmed);
285
- return Number.isNaN(parsed.getTime()) ? undefined : parsed;
286
- }
287
- var dateNativeCodec = {
288
- encode: identity,
289
- decode: (value) => {
290
- if (value instanceof Date)
291
- return value;
292
- if (typeof value === "string")
293
- return parseDateTimeText({ text: value }) ?? new Date(value);
294
- if (typeof value === "number")
295
- return new Date(value);
296
- return value;
297
- }
298
- };
299
- var dateTextCodec = {
300
- encode: (value) => value instanceof Date ? value.toISOString() : value,
301
- decode: dateNativeCodec.decode
302
- };
303
- var mysqlDateCodec = {
304
- encode: (value) => {
305
- if (value instanceof Date)
306
- return value;
307
- if (typeof value === "number") {
308
- const parsed = new Date(value);
309
- if (!Number.isNaN(parsed.getTime()))
310
- return parsed;
311
- return value;
312
- }
313
- if (typeof value === "string")
314
- return parseDateTimeText({ text: value }) ?? value;
315
- return value;
316
- },
317
- decode: dateNativeCodec.decode
318
- };
319
- var booleanIntCodec = {
320
- encode: (value) => typeof value === "boolean" ? value ? 1 : 0 : value,
321
- decode: (value) => typeof value === "number" ? value !== 0 : value
322
- };
323
- var booleanNativeInCodec = {
324
- encode: identity,
325
- decode: booleanIntCodec.decode
326
- };
327
- var jsonCodec = {
328
- encode: (value) => JSON.stringify(value),
329
- decode: (value) => {
330
- if (typeof value !== "string")
331
- return value;
332
- try {
333
- return JSON.parse(value);
334
- } catch (cause) {
335
- throw new VibeError({
336
- code: "VIBE_INTERNAL",
337
- message: "a Json column returned text that is not valid JSON",
338
- meta: { value },
339
- cause
340
- });
341
- }
1111
+ jsonPathMode: "sqliteExtract",
1112
+ supportedJsonOps: [
1113
+ "equals",
1114
+ "string_contains",
1115
+ "string_starts_with",
1116
+ "string_ends_with",
1117
+ "array_contains",
1118
+ "array_starts_with",
1119
+ "array_ends_with"
1120
+ ],
1121
+ jsonParamCast: "",
1122
+ lastInsertIdSql: null,
1123
+ rowLockSyntax: null,
1124
+ advisoryLockFunctions: null,
1125
+ rowDefaultKeyword: false,
1126
+ paramBudget: 900,
1127
+ booleanLiteral: { true: "1", false: "0" },
1128
+ quoteIdent({ name }) {
1129
+ return `"${name.replaceAll('"', '""')}"`;
1130
+ },
1131
+ quoteStringLiteral({ value }) {
1132
+ return `'${value.replaceAll("'", "''")}'`;
1133
+ },
1134
+ placeholder() {
1135
+ return "?";
1136
+ },
1137
+ renderDbNow({ offsetSeconds, collector }) {
1138
+ if (offsetSeconds === 0)
1139
+ return `strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;
1140
+ return `strftime('%Y-%m-%dT%H:%M:%fZ', 'now', ${collector.add(offsetSeconds)} || ' seconds')`;
342
1141
  }
343
1142
  };
344
- var POSTGRES_CODECS = {
345
- String: passthroughCodec,
346
- Boolean: passthroughCodec,
347
- Int: numberCodec,
348
- BigInt: bigIntCodec,
349
- Float: numberCodec,
350
- Decimal: decimalCodec,
351
- DateTime: dateNativeCodec,
352
- Json: jsonCodec,
353
- Bytes: passthroughCodec
354
- };
355
- var SQLITE_CODECS = {
356
- String: passthroughCodec,
357
- Boolean: booleanIntCodec,
358
- Int: numberCodec,
359
- BigInt: bigIntCodec,
360
- Float: numberCodec,
361
- Decimal: decimalCodec,
362
- DateTime: dateTextCodec,
363
- Json: jsonCodec,
364
- Bytes: passthroughCodec
365
- };
366
- var MYSQL_CODECS = {
367
- String: passthroughCodec,
368
- Boolean: booleanNativeInCodec,
369
- Int: numberCodec,
370
- BigInt: bigIntCodec,
371
- Float: numberCodec,
372
- Decimal: mysqlDecimalCodec,
373
- DateTime: mysqlDateCodec,
374
- Json: jsonCodec,
375
- Bytes: passthroughCodec
1143
+ // packages/sql/src/dialects/mysql.ts
1144
+ var mysqlDialect = {
1145
+ name: "mysql",
1146
+ capabilities: MYSQL_CAPABILITIES,
1147
+ inArrayStrategy: "expand",
1148
+ tupleInStrategy: "rowValue",
1149
+ upsertForm: "onDuplicateKey",
1150
+ conflictKeyEquality: {
1151
+ foldingScalars: ["Decimal"],
1152
+ defaultStringMaxLength: 191,
1153
+ textIsBinaryByDefault: false,
1154
+ duplicatesInOneStatement: "lastWriteWins"
1155
+ },
1156
+ excludedRowRef: { form: "rowAlias", alias: "new" },
1157
+ doNothingForm: "insertIgnore",
1158
+ insensitiveLike: "lower",
1159
+ strictMatchStrategy: "binary",
1160
+ orderByNullsMode: "emulate",
1161
+ offsetRequiresLimit: { limitText: "18446744073709551615" },
1162
+ likeEscapeClause: null,
1163
+ jsonPathMode: "mysqlExtract",
1164
+ supportedJsonOps: [
1165
+ "equals",
1166
+ "string_contains",
1167
+ "string_starts_with",
1168
+ "string_ends_with",
1169
+ "array_contains",
1170
+ "array_starts_with",
1171
+ "array_ends_with"
1172
+ ],
1173
+ jsonParamCast: "",
1174
+ lastInsertIdSql: "SELECT LAST_INSERT_ID() AS `id`",
1175
+ rowLockSyntax: {
1176
+ strengths: Object.freeze({ update: "FOR UPDATE", share: "FOR SHARE" }),
1177
+ wait: Object.freeze({ wait: "", nowait: " NOWAIT", skipLocked: " SKIP LOCKED" })
1178
+ },
1179
+ advisoryLockFunctions: null,
1180
+ rowDefaultKeyword: true,
1181
+ paramBudget: 1e4,
1182
+ booleanLiteral: { true: "1", false: "0" },
1183
+ quoteIdent({ name }) {
1184
+ return `\`${name.replaceAll("`", "``")}\``;
1185
+ },
1186
+ quoteStringLiteral({ value }) {
1187
+ return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "''")}'`;
1188
+ },
1189
+ placeholder() {
1190
+ return "?";
1191
+ },
1192
+ renderDbNow({ offsetSeconds, collector }) {
1193
+ if (offsetSeconds === 0)
1194
+ return "NOW(6)";
1195
+ return `DATE_ADD(NOW(6), INTERVAL ${collector.add(offsetSeconds)} SECOND)`;
1196
+ }
376
1197
  };
377
- var DIALECT_CODECS = {
378
- postgres: POSTGRES_CODECS,
379
- sqlite: SQLITE_CODECS,
380
- mysql: MYSQL_CODECS
1198
+ // packages/sql/src/dialects/registry.ts
1199
+ var SQL_DIALECTS = {
1200
+ postgres: postgresDialect,
1201
+ sqlite: sqliteDialect,
1202
+ mysql: mysqlDialect
381
1203
  };
1204
+ function getSqlDialect(params) {
1205
+ return SQL_DIALECTS[params.dialect];
1206
+ }
382
1207
  // packages/sql/src/dialects/diagnostics.ts
383
- import { unsupportedCapability } from "@vibeorm/schema";
1208
+ import { unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
384
1209
  var QUERIES = Object.freeze({
385
1210
  postgresJsonWire: { dialect: "postgres", text: `SELECT '{"__vibeorm":1}'::jsonb AS "probe"` },
386
1211
  sqliteTriggers: { dialect: "sqlite", text: "SELECT name, tbl_name, sql FROM sqlite_master WHERE type = 'trigger'" }
@@ -388,7 +1213,7 @@ var QUERIES = Object.freeze({
388
1213
  function renderDiagnostic(params) {
389
1214
  const query = QUERIES[params.query];
390
1215
  if (params.dialect.name !== query.dialect) {
391
- throw unsupportedCapability({ dialect: params.dialect.name, feature: params.query, hint: `this diagnostic requires ${query.dialect}` });
1216
+ throw unsupportedCapability4({ dialect: params.dialect.name, feature: params.query, hint: `this diagnostic requires ${query.dialect}` });
392
1217
  }
393
1218
  return { text: query.text, values: [], returning: "none" };
394
1219
  }
@@ -397,26 +1222,7 @@ function isFixedDiagnostic(params) {
397
1222
  }
398
1223
 
399
1224
  // packages/sql/src/dialects/postgres-diagnostics.ts
400
- import { VibeError as VibeError2, unsupportedCapability as unsupportedCapability2 } from "@vibeorm/schema";
401
-
402
- // packages/sql/src/params.ts
403
- class ParamCollector {
404
- dialect;
405
- values;
406
- constructor(dialect) {
407
- this.dialect = dialect;
408
- this.values = [];
409
- }
410
- add(value) {
411
- this.values.push(value);
412
- return this.dialect.placeholder({ index: this.values.length });
413
- }
414
- addMany(values) {
415
- return values.map((value) => this.add(value));
416
- }
417
- }
418
-
419
- // packages/sql/src/dialects/postgres-diagnostics.ts
1225
+ import { VibeError as VibeError6, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
420
1226
  function renderPostgresExplain(params) {
421
1227
  const { dialect, query, options } = params;
422
1228
  requirePostgres({ dialect, feature: "query plan inspection (EXPLAIN)" });
@@ -451,7 +1257,7 @@ var POSTGRES_WORKLOAD_LIMITS = Object.freeze({
451
1257
  });
452
1258
  function requirePostgres(params) {
453
1259
  if (params.dialect.name !== "postgres") {
454
- throw unsupportedCapability2({
1260
+ throw unsupportedCapability5({
455
1261
  dialect: params.dialect.name,
456
1262
  feature: params.feature,
457
1263
  hint: "plan inspection and workload statistics are PostgreSQL-shaped; portable operation tracing works on every dialect"
@@ -469,7 +1275,7 @@ function renderPostgresWorkload(params) {
469
1275
  if (query === "statementSnapshot") {
470
1276
  const bounded = limit ?? 20;
471
1277
  if (!Number.isInteger(bounded) || bounded < POSTGRES_WORKLOAD_LIMITS.minLimit || bounded > POSTGRES_WORKLOAD_LIMITS.maxLimit) {
472
- throw new VibeError2({
1278
+ throw new VibeError6({
473
1279
  code: "VIBE_CONFIG",
474
1280
  message: `workload snapshot limit must be an integer between ${POSTGRES_WORKLOAD_LIMITS.minLimit} and ${POSTGRES_WORKLOAD_LIMITS.maxLimit}, got ${String(limit)}`,
475
1281
  meta: { limit }
@@ -488,7 +1294,7 @@ function renderPostgresWorkload(params) {
488
1294
  function requireArg(params) {
489
1295
  const { value, name, query } = params;
490
1296
  if (value === undefined || value.length === 0) {
491
- throw new VibeError2({
1297
+ throw new VibeError6({
492
1298
  code: "VIBE_CONFIG",
493
1299
  message: `the "${query}" diagnostic read requires a ${name}`,
494
1300
  meta: { query, argument: name }
@@ -498,10 +1304,10 @@ function requireArg(params) {
498
1304
  }
499
1305
 
500
1306
  // packages/sql/src/dialects/postgres-rls-readiness.ts
501
- import { unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
1307
+ import { unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
502
1308
 
503
1309
  // packages/sql/src/dialects/postgres-rls.ts
504
- import { RlsContextError, VibeError as VibeError3, assertValidSchemaIR, unsupportedCapability as unsupportedCapability3, validateRlsContextIR } from "@vibeorm/schema";
1310
+ import { RlsContextError, VibeError as VibeError7, assertValidSchemaIR, unsupportedCapability as unsupportedCapability6, validateRlsContextIR } from "@vibeorm/schema";
505
1311
  var NATIVE_RLS = Object.freeze({ policyName: "vibeorm_managed", tableSchema: "public", settingPrefix: "vibeorm.", parentAlias: "parent" });
506
1312
  var COLUMN_TYPES = {
507
1313
  String: { default: "text", native: { text: "text", varchar: "varchar", charactervarying: "varchar", uuid: "uuid" } },
@@ -514,20 +1320,20 @@ var COLUMN_TYPES = {
514
1320
  };
515
1321
  function requireRls(params) {
516
1322
  if (!params.dialect.capabilities.nativeRowLevelSecurity) {
517
- throw unsupportedCapability3({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
1323
+ throw unsupportedCapability6({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
518
1324
  }
519
1325
  }
520
- function identifier(params) {
1326
+ function identifier2(params) {
521
1327
  if (typeof params.name !== "string" || params.name.length === 0 || params.name.includes("\x00") || new TextEncoder().encode(params.name).length > 63) {
522
- throw new VibeError3({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS identifiers must be nonempty PostgreSQL identifiers of at most 63 bytes" });
1328
+ throw new VibeError7({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS identifiers must be nonempty PostgreSQL identifiers of at most 63 bytes" });
523
1329
  }
524
1330
  return params.dialect.quoteIdent({ name: params.name });
525
1331
  }
526
1332
  function tableRef(params) {
527
1333
  if (params.schema !== undefined && params.schema !== "public" && params.schema !== "pg_temp") {
528
- throw unsupportedCapability3({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: "Only public tables and temporary policy probes are supported" });
1334
+ throw unsupportedCapability6({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: "Only public tables and temporary policy probes are supported" });
529
1335
  }
530
- return `${identifier({ dialect: params.dialect, name: params.schema ?? NATIVE_RLS.tableSchema })}.${identifier({ dialect: params.dialect, name: params.table })}`;
1336
+ return `${identifier2({ dialect: params.dialect, name: params.schema ?? NATIVE_RLS.tableSchema })}.${identifier2({ dialect: params.dialect, name: params.table })}`;
531
1337
  }
532
1338
  function query(params) {
533
1339
  return { text: params.text, values: params.values ?? [], returning: "none" };
@@ -550,7 +1356,7 @@ function renderRlsNoForce({ dialect, table }) {
550
1356
  }
551
1357
  function renderRlsDropPolicy({ dialect, table, policyName }) {
552
1358
  requireRls({ dialect });
553
- const name = identifier({ dialect, name: policyName ?? NATIVE_RLS.policyName });
1359
+ const name = identifier2({ dialect, name: policyName ?? NATIVE_RLS.policyName });
554
1360
  return query({ text: `DROP POLICY ${name} ON ${tableRef({ dialect, table })}` });
555
1361
  }
556
1362
  function renderRlsColumnType(params) {
@@ -566,14 +1372,14 @@ function renderRlsColumnType(params) {
566
1372
  if (native !== undefined)
567
1373
  return native;
568
1374
  }
569
- throw unsupportedCapability3({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: `Unsupported physical ownership type on field ${field.name}` });
1375
+ throw unsupportedCapability6({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity", hint: `Unsupported physical ownership type on field ${field.name}` });
570
1376
  }
571
1377
  function protectedModel(params) {
572
1378
  requireRls(params);
573
1379
  assertValidSchemaIR({ schema: params.schema });
574
1380
  const model = params.schema.models.find((entry) => entry.name === params.model);
575
1381
  if (model === undefined || model.rls === undefined || model.rls === "unprotected") {
576
- throw new VibeError3({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS policy rendering requires a protected model", meta: { model: params.model } });
1382
+ throw new VibeError7({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS policy rendering requires a protected model", meta: { model: params.model } });
577
1383
  }
578
1384
  return model;
579
1385
  }
@@ -589,7 +1395,7 @@ function predicate(params) {
589
1395
  if (typeof rule === "object" && "where" in rule) {
590
1396
  return Object.entries(rule.where).map(([name, ref]) => {
591
1397
  const field = model.fields.find((entry) => entry.name === name);
592
- const column = identifier({ dialect, name: field.dbName ?? field.name });
1398
+ const column = identifier2({ dialect, name: field.dbName ?? field.name });
593
1399
  const physicalType = renderRlsColumnType({ dialect, field });
594
1400
  return `(${column} = NULLIF(current_setting('${NATIVE_RLS.settingPrefix}${ref.context}', true), '')::${physicalType})`;
595
1401
  }).join(" AND ");
@@ -597,21 +1403,21 @@ function predicate(params) {
597
1403
  if (typeof rule === "object" && "through" in rule) {
598
1404
  const relation = model.relations.find((entry) => entry.name === rule.through);
599
1405
  const parent = schema.models.find((entry) => entry.name === relation.targetModel);
600
- const alias = identifier({ dialect, name: NATIVE_RLS.parentAlias });
601
- const child = identifier({ dialect, name: model.dbName ?? model.name });
1406
+ const alias = identifier2({ dialect, name: NATIVE_RLS.parentAlias });
1407
+ const child = identifier2({ dialect, name: model.dbName ?? model.name });
602
1408
  const join = relation.fields.map((name, index) => {
603
1409
  const childField = model.fields.find((field) => field.name === name);
604
1410
  const parentField = parent.fields.find((field) => field.name === relation.references[index]);
605
- return `(${alias}.${identifier({ dialect, name: parentField.dbName ?? parentField.name })} = ${child}.${identifier({ dialect, name: childField.dbName ?? childField.name })})`;
1411
+ return `(${alias}.${identifier2({ dialect, name: parentField.dbName ?? parentField.name })} = ${child}.${identifier2({ dialect, name: childField.dbName ?? childField.name })})`;
606
1412
  }).join(" AND ");
607
1413
  return `EXISTS (SELECT 1 FROM ${tableRef({ dialect, table: parent.dbName ?? parent.name })} AS ${alias} WHERE ${join})`;
608
1414
  }
609
- throw new VibeError3({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS requires a protected policy rule" });
1415
+ throw new VibeError7({ code: "VIBE_SCHEMA_INVALID", message: "Native RLS requires a protected policy rule" });
610
1416
  }
611
1417
  function renderRlsPolicy(params) {
612
1418
  const model = protectedModel(params);
613
1419
  const expression = predicate({ dialect: params.dialect, schema: params.schema, model });
614
- const name = identifier({ dialect: params.dialect, name: params.policyName ?? NATIVE_RLS.policyName });
1420
+ const name = identifier2({ dialect: params.dialect, name: params.policyName ?? NATIVE_RLS.policyName });
615
1421
  const table = tableRef({ dialect: params.dialect, table: model.dbName ?? model.name, schema: params.targetSchema });
616
1422
  return query({ text: `CREATE POLICY ${name} ON ${table} AS PERMISSIVE FOR ALL TO PUBLIC USING (${expression}) WITH CHECK (${expression})` });
617
1423
  }
@@ -640,7 +1446,7 @@ function renderRlsContext(params) {
640
1446
  function renderRlsRole(params) {
641
1447
  requireRls(params);
642
1448
  if (typeof params.role !== "string" || params.role.trim().length === 0 || params.role.includes("\x00")) {
643
- throw new VibeError3({ code: "VIBE_CONFIG", message: "PGlite native RLS requires a trusted nonempty runtime role name" });
1449
+ throw new VibeError7({ code: "VIBE_CONFIG", message: "PGlite native RLS requires a trusted nonempty runtime role name" });
644
1450
  }
645
1451
  const collector = new ParamCollector(params.dialect);
646
1452
  return query({ text: `SELECT set_config('role', ${collector.add(params.role)}, true)`, values: collector.values });
@@ -648,7 +1454,7 @@ function renderRlsRole(params) {
648
1454
 
649
1455
  // packages/sql/src/dialects/postgres-rls-readiness.ts
650
1456
  var NATIVE_RLS_PROBE_POLICY = "vibeorm_probe";
651
- var RLS_READINESS_SQL = Object.freeze({
1457
+ var CATALOG_READS = Object.freeze({
652
1458
  identity: `SELECT current_user::text AS "currentUser",
653
1459
  session_user::text AS "sessionUser",
654
1460
  r.rolsuper AS "super",
@@ -711,17 +1517,6 @@ FROM pg_catalog.pg_policy p
711
1517
  JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
712
1518
  JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
713
1519
  WHERE n.nspname = $1
714
- ORDER BY c.relname, p.polname`,
715
- expressions: `SELECT c.relname::text AS "table",
716
- p.polname::text AS "name",
717
- (n.nspname <> $1) AS "probe",
718
- pg_catalog.pg_get_expr(p.polqual, p.polrelid) AS "using",
719
- pg_catalog.pg_get_expr(p.polwithcheck, p.polrelid) AS "withCheck"
720
- FROM pg_catalog.pg_policy p
721
- JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
722
- JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
723
- WHERE (n.nspname = $1 AND p.polname = $2)
724
- OR (c.relnamespace = pg_catalog.pg_my_temp_schema() AND p.polname = $3)
725
1520
  ORDER BY c.relname, p.polname`,
726
1521
  views: `SELECT n.nspname::text AS "schema",
727
1522
  c.relname::text AS "name",
@@ -769,13 +1564,41 @@ JOIN pg_catalog.pg_proc f ON f.oid = t.tgfoid
769
1564
  WHERE n.nspname = $1
770
1565
  AND NOT t.tgisinternal
771
1566
  AND f.prosecdef
772
- ORDER BY c.relname, t.tgname`,
1567
+ ORDER BY c.relname, t.tgname`
1568
+ });
1569
+ var RLS_READINESS_CATALOG_KEYS = Object.freeze(["identity", "elevatedRoles", "schemaControl", "tables", "policies", "views", "routines", "triggers"]);
1570
+ var COMPOSITE_CATALOG = `SELECT
1571
+ ${RLS_READINESS_CATALOG_KEYS.map((key) => ` (SELECT json_agg(t)::text FROM (
1572
+ ${CATALOG_READS[key]}
1573
+ ) t) AS "${key}"`).join(`,
1574
+ `)}`;
1575
+ var RLS_READINESS_SQL = Object.freeze({
1576
+ identity: CATALOG_READS.identity,
1577
+ elevatedRoles: CATALOG_READS.elevatedRoles,
1578
+ schemaControl: CATALOG_READS.schemaControl,
1579
+ tables: CATALOG_READS.tables,
1580
+ policies: CATALOG_READS.policies,
1581
+ expressions: `SELECT c.relname::text AS "table",
1582
+ p.polname::text AS "name",
1583
+ (n.nspname <> $1) AS "probe",
1584
+ pg_catalog.pg_get_expr(p.polqual, p.polrelid) AS "using",
1585
+ pg_catalog.pg_get_expr(p.polwithcheck, p.polrelid) AS "withCheck"
1586
+ FROM pg_catalog.pg_policy p
1587
+ JOIN pg_catalog.pg_class c ON c.oid = p.polrelid
1588
+ JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
1589
+ WHERE (n.nspname = $1 AND p.polname = $2)
1590
+ OR (c.relnamespace = pg_catalog.pg_my_temp_schema() AND p.polname = $3)
1591
+ ORDER BY c.relname, p.polname`,
1592
+ views: CATALOG_READS.views,
1593
+ routines: CATALOG_READS.routines,
1594
+ triggers: CATALOG_READS.triggers,
1595
+ catalog: COMPOSITE_CATALOG,
773
1596
  readSearchPath: `SELECT pg_catalog.current_setting('search_path') AS "searchPath"`,
774
1597
  setSearchPath: `SELECT pg_catalog.set_config('search_path', $1, true)`
775
1598
  });
776
1599
  function requireRls2(params) {
777
1600
  if (!params.dialect.capabilities.nativeRowLevelSecurity) {
778
- throw unsupportedCapability4({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
1601
+ throw unsupportedCapability7({ dialect: params.dialect.name, feature: "nativeRowLevelSecurity" });
779
1602
  }
780
1603
  }
781
1604
  function renderRlsReadinessQuery(params) {
@@ -807,7 +1630,7 @@ function renderRlsPolicyPath(params) {
807
1630
  }
808
1631
 
809
1632
  // packages/sql/src/render.ts
810
- import { internalError, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
1633
+ import { internalError as internalError2, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
811
1634
 
812
1635
  // packages/sql/src/like.ts
813
1636
  function escapeLikePattern(params) {
@@ -853,6 +1676,8 @@ function renderStatement(params) {
853
1676
  }
854
1677
  case "select":
855
1678
  return renderSelect({ dialect, statement, collector });
1679
+ case "advisoryLock":
1680
+ return renderAdvisoryLock({ dialect, statement, collector });
856
1681
  case "insert":
857
1682
  return renderInsert({ dialect, statement, collector });
858
1683
  case "update":
@@ -888,7 +1713,7 @@ function quoteCol(dialect, column) {
888
1713
  const ref = column.table === undefined ? name : `${dialect.quoteIdent({ name: column.table })}.${name}`;
889
1714
  if (column.castReal === true) {
890
1715
  if (dialect.name !== "sqlite") {
891
- throw internalError({ message: "ColRef.castReal is a sqlite Decimal construct" });
1716
+ throw internalError2({ message: "ColRef.castReal is a sqlite Decimal construct" });
892
1717
  }
893
1718
  return `CAST(${ref} AS REAL)`;
894
1719
  }
@@ -902,7 +1727,7 @@ function quoteProjection(dialect, column) {
902
1727
  return `${base} AS ${dialect.quoteIdent({ name: column.alias })}`;
903
1728
  }
904
1729
  if (dialect.name !== "postgres") {
905
- throw internalError({ message: "ColRef.transform is a postgres lateral-join construct" });
1730
+ throw internalError2({ message: "ColRef.transform is a postgres lateral-join construct" });
906
1731
  }
907
1732
  const ref = quoteCol(dialect, column);
908
1733
  const alias = dialect.quoteIdent({ name: column.name });
@@ -918,10 +1743,10 @@ function renderTable(dialect, table) {
918
1743
  }
919
1744
  function assertCount(value, what) {
920
1745
  if (!Number.isSafeInteger(value) || value < 0) {
921
- throw internalError({ message: `${what} must be a non-negative integer, got ${value}` });
1746
+ throw internalError2({ message: `${what} must be a non-negative integer, got ${value}` });
922
1747
  }
923
1748
  }
924
- var COMPARISON_SQL = {
1749
+ var COMPARISON_SQL2 = {
925
1750
  eq: "=",
926
1751
  ne: "<>",
927
1752
  gt: ">",
@@ -950,7 +1775,7 @@ function renderAggRef(dialect, agg) {
950
1775
  function assertScalarArrays(dialect, feature) {
951
1776
  if (dialect.capabilities.scalarArrays)
952
1777
  return;
953
- throw unsupportedCapability5({
1778
+ throw unsupportedCapability8({
954
1779
  dialect: dialect.name,
955
1780
  feature,
956
1781
  hint: "only postgres has native array columns \u2014 model the list as a related table instead"
@@ -960,9 +1785,9 @@ function renderExpr(params) {
960
1785
  const { dialect, expr, collector } = params;
961
1786
  switch (expr.kind) {
962
1787
  case "cmp": {
963
- const op = COMPARISON_SQL[expr.op];
1788
+ const op = COMPARISON_SQL2[expr.op];
964
1789
  if (op === undefined) {
965
- throw internalError({ message: `unknown comparison operator "${expr.op}"` });
1790
+ throw internalError2({ message: `unknown comparison operator "${expr.op}"` });
966
1791
  }
967
1792
  if (isDbNowMarker(expr.value)) {
968
1793
  return `${quoteCol(dialect, expr.column)} ${op} ${dialect.renderDbNow({ offsetSeconds: expr.value.offsetSeconds, collector })}`;
@@ -970,9 +1795,9 @@ function renderExpr(params) {
970
1795
  return `${quoteCol(dialect, expr.column)} ${op} ${collector.add(expr.value)}`;
971
1796
  }
972
1797
  case "cmpCol": {
973
- const op = COMPARISON_SQL[expr.op];
1798
+ const op = COMPARISON_SQL2[expr.op];
974
1799
  if (op === undefined) {
975
- throw internalError({ message: `unknown comparison operator "${expr.op}"` });
1800
+ throw internalError2({ message: `unknown comparison operator "${expr.op}"` });
976
1801
  }
977
1802
  return `${quoteCol(dialect, expr.left)} ${op} ${quoteCol(dialect, expr.right)}`;
978
1803
  }
@@ -992,11 +1817,11 @@ function renderExpr(params) {
992
1817
  }
993
1818
  case "tupleIn": {
994
1819
  if (expr.columns.length === 0) {
995
- throw internalError({ message: "tupleIn needs at least one column" });
1820
+ throw internalError2({ message: "tupleIn needs at least one column" });
996
1821
  }
997
1822
  for (const row of expr.rows) {
998
1823
  if (row.length !== expr.columns.length) {
999
- throw internalError({
1824
+ throw internalError2({
1000
1825
  message: `tupleIn row has ${row.length} values for ${expr.columns.length} columns`
1001
1826
  });
1002
1827
  }
@@ -1068,9 +1893,9 @@ function renderExpr(params) {
1068
1893
  case "not":
1069
1894
  return `NOT (${renderExpr({ dialect, expr: expr.operand, collector })})`;
1070
1895
  case "aggCmp": {
1071
- const op = COMPARISON_SQL[expr.op];
1896
+ const op = COMPARISON_SQL2[expr.op];
1072
1897
  if (op === undefined) {
1073
- throw internalError({ message: `unknown comparison operator "${expr.op}"` });
1898
+ throw internalError2({ message: `unknown comparison operator "${expr.op}"` });
1074
1899
  }
1075
1900
  return `${renderAggRef(dialect, expr.agg)} ${op} ${collector.add(expr.value)}`;
1076
1901
  }
@@ -1098,6 +1923,8 @@ function renderExpr(params) {
1098
1923
  const sub = renderSelect({ dialect, statement: expr.select, collector });
1099
1924
  return `${expr.negate === true ? "NOT " : ""}EXISTS (${sub.text})`;
1100
1925
  }
1926
+ case "composed":
1927
+ return `(${renderSqlFragment({ dialect, fragment: expr.fragment, collector })})`;
1101
1928
  case "fragment":
1102
1929
  return renderFragment({ dialect, fragment: expr.fragment, collector });
1103
1930
  case "raw":
@@ -1134,7 +1961,7 @@ function jsonPathString(path) {
1134
1961
  function jsonStringPattern(params) {
1135
1962
  const { expr } = params;
1136
1963
  if (typeof expr.value !== "string") {
1137
- throw internalError({ message: `json ${expr.op} expects a string operand` });
1964
+ throw internalError2({ message: `json ${expr.op} expects a string operand` });
1138
1965
  }
1139
1966
  if (expr.op === "string_contains")
1140
1967
  return containsPattern({ raw: expr.value });
@@ -1158,7 +1985,7 @@ function renderJsonLike(params) {
1158
1985
  function renderJsonFilter(params) {
1159
1986
  const { dialect, expr, collector } = params;
1160
1987
  if (!dialect.supportedJsonOps.includes(expr.op)) {
1161
- throw unsupportedCapability5({
1988
+ throw unsupportedCapability8({
1162
1989
  dialect: dialect.name,
1163
1990
  feature: `the json filter "${expr.op}"`,
1164
1991
  hint: `this dialect can express: ${dialect.supportedJsonOps.join(", ")}`
@@ -1213,7 +2040,7 @@ function renderJsonFilter(params) {
1213
2040
  const elements = Array.isArray(expr.value) ? expr.value : [expr.value];
1214
2041
  const tests = elements.map((element) => {
1215
2042
  if (element === null || typeof element === "object" && element !== null) {
1216
- throw unsupportedCapability5({
2043
+ throw unsupportedCapability8({
1217
2044
  dialect: dialect.name,
1218
2045
  feature: "json array_contains with object/array/null elements",
1219
2046
  hint: "sqlite expresses scalar-element containment only \u2014 deep structural containment needs postgres or mysql"
@@ -1225,7 +2052,7 @@ function renderJsonFilter(params) {
1225
2052
  return tests.length === 0 ? guard : `(${[guard, ...tests].join(" AND ")})`;
1226
2053
  }
1227
2054
  default:
1228
- throw internalError({ message: `json op "${expr.op}" leaked past supportedJsonOps on sqlite` });
2055
+ throw internalError2({ message: `json op "${expr.op}" leaked past supportedJsonOps on sqlite` });
1229
2056
  }
1230
2057
  }
1231
2058
  const column = quoteCol(dialect, expr.column);
@@ -1280,11 +2107,11 @@ function renderSelectExpr(params) {
1280
2107
  function renderPositionalRow(params) {
1281
2108
  const { dialect, join, subAlias } = params;
1282
2109
  if (join.select.columns.length === 0 || join.select.selectExpr !== undefined || (join.select.aggregates?.length ?? 0) > 0 || join.select.rowNumber !== undefined) {
1283
- throw internalError({ message: "positional lateral rows require an explicit column-only projection" });
2110
+ throw internalError2({ message: "positional lateral rows require an explicit column-only projection" });
1284
2111
  }
1285
2112
  const names = join.select.columns.map((column) => projectionOutputName({ column }));
1286
2113
  if (new Set(names).size !== names.length) {
1287
- throw internalError({ message: "positional lateral projection has duplicate output names" });
2114
+ throw internalError2({ message: "positional lateral projection has duplicate output names" });
1288
2115
  }
1289
2116
  const values = names.map((name) => `${subAlias}.${dialect.quoteIdent({ name })}`);
1290
2117
  const chunks = [];
@@ -1292,7 +2119,7 @@ function renderPositionalRow(params) {
1292
2119
  chunks.push(`json_build_array(${values.slice(index, index + JSON_TRANSPORT.chunkSize).join(", ")})`);
1293
2120
  }
1294
2121
  if (chunks.length > JSON_TRANSPORT.chunkSize) {
1295
- throw internalError({ message: "positional lateral projection exceeds the transport width limit" });
2122
+ throw internalError2({ message: "positional lateral projection exceeds the transport width limit" });
1296
2123
  }
1297
2124
  return chunks.length === 1 ? chunks[0] : `json_build_array(${chunks.join(", ")})`;
1298
2125
  }
@@ -1301,7 +2128,7 @@ function renderLateralJoin(params) {
1301
2128
  const inner = renderSelect({ dialect, statement: join.select, collector });
1302
2129
  if (join.agg === "count") {
1303
2130
  if (join.rowFormat === "positional" || join.select.columns.length !== 0 || join.select.selectExpr?.kind !== "countAll" || join.select.selectExpr.alias !== join.columnAlias || join.select.groupBy !== undefined || join.select.having !== undefined || join.select.limit !== undefined || join.select.offset !== undefined || join.select.distinctOn !== undefined) {
1304
- throw internalError({ message: "count lateral must return one ungrouped COUNT(*) under its column alias" });
2131
+ throw internalError2({ message: "count lateral must return one ungrouped COUNT(*) under its column alias" });
1305
2132
  }
1306
2133
  return `LEFT JOIN LATERAL (${inner.text}) AS ${dialect.quoteIdent({ name: join.alias })} ON true`;
1307
2134
  }
@@ -1336,10 +2163,10 @@ function applyReturning(params) {
1336
2163
  function renderSelect(params) {
1337
2164
  const { dialect, statement, collector } = params;
1338
2165
  if (statement.selectExpr !== undefined && statement.columns.length > 0 && statement.selectExpr.kind !== "countAll") {
1339
- throw internalError({ message: "only countAll can combine with a column list" });
2166
+ throw internalError2({ message: "only countAll can combine with a column list" });
1340
2167
  }
1341
2168
  if (statement.selectExpr !== undefined && statement.aggregates !== undefined && statement.aggregates.length > 0) {
1342
- throw internalError({ message: "selectExpr and aggregates cannot combine" });
2169
+ throw internalError2({ message: "selectExpr and aggregates cannot combine" });
1343
2170
  }
1344
2171
  const columnList = statement.columns.map((column) => quoteProjection(dialect, column));
1345
2172
  if (statement.selectExpr !== undefined) {
@@ -1353,7 +2180,7 @@ function renderSelect(params) {
1353
2180
  if (statement.rowNumber !== undefined) {
1354
2181
  const rowNumber = statement.rowNumber;
1355
2182
  if (rowNumber.partitionBy.length === 0) {
1356
- throw internalError({ message: "rowNumber needs at least one partition column" });
2183
+ throw internalError2({ message: "rowNumber needs at least one partition column" });
1357
2184
  }
1358
2185
  const partition = rowNumber.partitionBy.map((column) => quoteCol(dialect, column)).join(", ");
1359
2186
  const order = rowNumber.orderBy.length === 0 ? "" : ` ORDER BY ${rowNumber.orderBy.map((term) => renderOrderTerm({ dialect, term, collector })).join(", ")}`;
@@ -1362,7 +2189,7 @@ function renderSelect(params) {
1362
2189
  let distinctPrefix = "";
1363
2190
  if (statement.distinctOn !== undefined && statement.distinctOn.length > 0) {
1364
2191
  if (!dialect.capabilities.distinctOn) {
1365
- throw unsupportedCapability5({
2192
+ throw unsupportedCapability8({
1366
2193
  dialect: dialect.name,
1367
2194
  feature: "SELECT DISTINCT ON",
1368
2195
  hint: "postgres-only \u2014 the runtime emulates distinct client-side on this dialect"
@@ -1374,7 +2201,7 @@ function renderSelect(params) {
1374
2201
  let from;
1375
2202
  if (statement.fromSelect !== undefined) {
1376
2203
  if (statement.table.alias !== undefined) {
1377
- throw internalError({ message: "fromSelect uses table.name as the subquery alias \u2014 table.alias must be unset" });
2204
+ throw internalError2({ message: "fromSelect uses table.name as the subquery alias \u2014 table.alias must be unset" });
1378
2205
  }
1379
2206
  const inner = renderSelect({ dialect, statement: statement.fromSelect, collector });
1380
2207
  from = `(${inner.text}) AS ${dialect.quoteIdent({ name: statement.table.name })}`;
@@ -1385,7 +2212,7 @@ function renderSelect(params) {
1385
2212
  if (statement.innerJoins !== undefined && statement.innerJoins.length > 0) {
1386
2213
  for (const join of statement.innerJoins) {
1387
2214
  if (join.on.length === 0) {
1388
- throw internalError({ message: "inner join needs at least one ON pair" });
2215
+ throw internalError2({ message: "inner join needs at least one ON pair" });
1389
2216
  }
1390
2217
  const on = join.on.map((pair) => `${quoteCol(dialect, pair.left)} = ${quoteCol(dialect, pair.right)}`).join(" AND ");
1391
2218
  text += ` INNER JOIN ${renderTable(dialect, join.table)} ON ${on}`;
@@ -1393,7 +2220,7 @@ function renderSelect(params) {
1393
2220
  }
1394
2221
  if (statement.lateralJoins !== undefined && statement.lateralJoins.length > 0) {
1395
2222
  if (!dialect.capabilities.lateralJoin) {
1396
- throw unsupportedCapability5({
2223
+ throw unsupportedCapability8({
1397
2224
  dialect: dialect.name,
1398
2225
  feature: "LATERAL JOIN relation loading",
1399
2226
  hint: 'use the portable "query" relation strategy on this dialect'
@@ -1427,22 +2254,24 @@ function renderSelect(params) {
1427
2254
  }
1428
2255
  text += ` OFFSET ${statement.offset}`;
1429
2256
  }
1430
- if (statement.lockForUpdate === true && dialect.selectForUpdate !== null) {
1431
- text += dialect.selectForUpdate;
2257
+ if (statement.rowLock !== undefined) {
2258
+ const clause = renderRowLockClause({ dialect, lock: statement.rowLock });
2259
+ if (clause !== null)
2260
+ text += ` ${clause}`;
1432
2261
  }
1433
2262
  return { text, values: collector.values, returning: "none" };
1434
2263
  }
1435
2264
  function renderInsert(params) {
1436
2265
  const { dialect, statement, collector } = params;
1437
2266
  if (statement.columns.length === 0) {
1438
- throw internalError({ message: "insert requires at least one column" });
2267
+ throw internalError2({ message: "insert requires at least one column" });
1439
2268
  }
1440
2269
  if (statement.rows.length === 0) {
1441
- throw internalError({ message: "insert requires at least one row" });
2270
+ throw internalError2({ message: "insert requires at least one row" });
1442
2271
  }
1443
2272
  for (const row of statement.rows) {
1444
2273
  if (row.length !== statement.columns.length) {
1445
- throw internalError({
2274
+ throw internalError2({
1446
2275
  message: `insert row has ${row.length} values but ${statement.columns.length} columns`
1447
2276
  });
1448
2277
  }
@@ -1460,14 +2289,14 @@ function renderInsert(params) {
1460
2289
  if (!isSqlDefaultCell(value))
1461
2290
  return collector.add(value);
1462
2291
  if (!dialect.rowDefaultKeyword) {
1463
- throw internalError({
2292
+ throw internalError2({
1464
2293
  message: `${dialect.name} cannot render a per-row DEFAULT cell \u2014 rows must be grouped by column set`
1465
2294
  });
1466
2295
  }
1467
2296
  return "DEFAULT";
1468
2297
  }).join(", ")})`).join(", ");
1469
2298
  let text = `${insertKeyword} ${renderTable(dialect, statement.table)} (${columnList}) VALUES ${rowsSql}`;
1470
- if (onConflict !== undefined && !("doNothing" in onConflict) && dialect.excludedRowRef.form === "rowAlias" && Object.values(onConflict.update).some((value) => isExcludedRef(value))) {
2299
+ if (onConflict !== undefined && !("doNothing" in onConflict) && dialect.excludedRowRef.form === "rowAlias" && Object.values(onConflict.update).some((value) => isExcludedRef(value) || isSqlFragment(value) && sqlUsesIncoming({ fragment: value }))) {
1471
2300
  text += ` AS ${dialect.quoteIdent({ name: dialect.excludedRowRef.alias })}`;
1472
2301
  }
1473
2302
  if (onConflict !== undefined) {
@@ -1476,7 +2305,7 @@ function renderInsert(params) {
1476
2305
  let target = "";
1477
2306
  if (onConflict.constraint !== undefined) {
1478
2307
  if (dialect.name !== "postgres") {
1479
- throw unsupportedCapability5({
2308
+ throw unsupportedCapability8({
1480
2309
  dialect: dialect.name,
1481
2310
  feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
1482
2311
  hint: "only postgres names constraints in conflict targets \u2014 use a column-list target"
@@ -1491,7 +2320,7 @@ function renderInsert(params) {
1491
2320
  }
1492
2321
  text += ` ON CONFLICT${target} DO NOTHING`;
1493
2322
  } else if (onConflict.constraint !== undefined || onConflict.conflictWhere !== undefined) {
1494
- throw unsupportedCapability5({
2323
+ throw unsupportedCapability8({
1495
2324
  dialect: dialect.name,
1496
2325
  feature: "a refined conflict target (constraint / partial-index predicate) on INSERT IGNORE",
1497
2326
  hint: "mysql skips on any duplicate key \u2014 drop the refinement or gate the call per dialect"
@@ -1500,23 +2329,23 @@ function renderInsert(params) {
1500
2329
  } else {
1501
2330
  const updates = Object.entries(onConflict.update);
1502
2331
  if (updates.length === 0) {
1503
- throw internalError({ message: "upsert update must set at least one column" });
2332
+ throw internalError2({ message: "upsert update must set at least one column" });
1504
2333
  }
1505
2334
  const selfRef = dialect.quoteIdent({ name: statement.table.name });
1506
- const assignments = renderAssignments({ dialect, entries: updates, collector, selfRef, allowExcluded: true });
2335
+ const assignments = renderAssignments({ dialect, entries: updates, collector, selfRef, allowExcluded: true, tableName: statement.table.name });
1507
2336
  if (dialect.upsertForm === "onConflict") {
1508
2337
  if (onConflict.lastInsertIdColumn !== undefined) {
1509
- throw internalError({ message: "lastInsertIdColumn is a mysql (onDuplicateKey) construct" });
2338
+ throw internalError2({ message: "lastInsertIdColumn is a mysql (onDuplicateKey) construct" });
1510
2339
  }
1511
2340
  if (onConflict.constraint !== undefined && dialect.name !== "postgres") {
1512
- throw unsupportedCapability5({
2341
+ throw unsupportedCapability8({
1513
2342
  dialect: dialect.name,
1514
2343
  feature: "a named-constraint conflict target (ON CONFLICT ON CONSTRAINT)",
1515
2344
  hint: "sqlite conflict targets are column lists \u2014 name the indexed columns instead"
1516
2345
  });
1517
2346
  }
1518
2347
  if (onConflict.constraint !== undefined && onConflict.conflictWhere !== undefined) {
1519
- throw internalError({
2348
+ throw internalError2({
1520
2349
  message: "a named-constraint conflict target already identifies the index \u2014 it cannot carry a partial predicate too"
1521
2350
  });
1522
2351
  }
@@ -1525,14 +2354,14 @@ function renderInsert(params) {
1525
2354
  text += ` ON CONFLICT${target} DO UPDATE SET ${assignments}`;
1526
2355
  } else {
1527
2356
  if (onConflict.constraint !== undefined) {
1528
- throw unsupportedCapability5({
2357
+ throw unsupportedCapability8({
1529
2358
  dialect: dialect.name,
1530
2359
  feature: "a named-constraint conflict target on ON DUPLICATE KEY UPDATE",
1531
2360
  hint: "mysql's ODKU fires on any duplicate key \u2014 no target can be named"
1532
2361
  });
1533
2362
  }
1534
2363
  if (onConflict.conflictWhere !== undefined) {
1535
- throw unsupportedCapability5({
2364
+ throw unsupportedCapability8({
1536
2365
  dialect: dialect.name,
1537
2366
  feature: "a partial-index conflict target on ON DUPLICATE KEY UPDATE",
1538
2367
  hint: "mysql's ODKU fires on any duplicate key \u2014 a partial arbiter cannot be selected; gate the call per dialect"
@@ -1550,7 +2379,7 @@ function renderUpdate(params) {
1550
2379
  const { dialect, statement, collector } = params;
1551
2380
  const assignments = Object.entries(statement.set);
1552
2381
  if (assignments.length === 0) {
1553
- throw internalError({ message: "update must set at least one column" });
2382
+ throw internalError2({ message: "update must set at least one column" });
1554
2383
  }
1555
2384
  const setSql = renderAssignments({ dialect, entries: assignments, collector });
1556
2385
  let text = `UPDATE ${renderTable(dialect, statement.table)} SET ${setSql}`;
@@ -1571,9 +2400,14 @@ function renderAssignments(params) {
1571
2400
  return entries.map(([name, value]) => {
1572
2401
  const column = dialect.quoteIdent({ name });
1573
2402
  const read = selfRef === undefined ? column : `${selfRef}.${column}`;
2403
+ if (isSqlFragment(value)) {
2404
+ if (params.allowExcluded !== true || selfRef === undefined)
2405
+ throw internalError2({ message: "SQL assignment fragments require a conflict update" });
2406
+ return `${column} = ${renderSqlFragment({ dialect, fragment: value, collector, conflict: { table: params.tableName } })}`;
2407
+ }
1574
2408
  if (isExcludedRef(value)) {
1575
2409
  if (params.allowExcluded !== true) {
1576
- throw internalError({
2410
+ throw internalError2({
1577
2411
  message: `an incoming-row reference (${value.column}) is only meaningful inside an upsert's update arm`
1578
2412
  });
1579
2413
  }
@@ -1607,12 +2441,377 @@ function renderDelete(params) {
1607
2441
  const returning = applyReturning({ dialect, requested: statement.returning });
1608
2442
  return { text: text + returning.suffix, values: collector.values, returning: returning.status };
1609
2443
  }
2444
+ // packages/sql/src/dialects/sqlite-table-definition.ts
2445
+ import { VibeError as VibeError8 } from "@vibeorm/schema";
2446
+ function tableDefinitionParts(params) {
2447
+ const sql2 = params.sql;
2448
+ if (!/^\s*CREATE\s+(?:TEMP(?:ORARY)?\s+)?TABLE\b/i.test(sql2))
2449
+ throw unavailable();
2450
+ const parts = [];
2451
+ let start = -1;
2452
+ let depth = 0;
2453
+ let quote;
2454
+ for (let index = 0;index < sql2.length; index++) {
2455
+ const char = sql2[index];
2456
+ if (quote !== undefined) {
2457
+ if (char === quote) {
2458
+ if (quote !== "]" && sql2[index + 1] === quote)
2459
+ index++;
2460
+ else
2461
+ quote = undefined;
2462
+ }
2463
+ continue;
2464
+ }
2465
+ if (char === "'" || char === '"' || char === "`") {
2466
+ quote = char;
2467
+ continue;
2468
+ }
2469
+ if (char === "[") {
2470
+ quote = "]";
2471
+ continue;
2472
+ }
2473
+ if (char === "-" && sql2[index + 1] === "-") {
2474
+ const end = sql2.indexOf(`
2475
+ `, index + 2);
2476
+ if (end < 0)
2477
+ break;
2478
+ index = end;
2479
+ continue;
2480
+ }
2481
+ if (char === "/" && sql2[index + 1] === "*") {
2482
+ const end = sql2.indexOf("*/", index + 2);
2483
+ if (end < 0)
2484
+ break;
2485
+ index = end + 1;
2486
+ continue;
2487
+ }
2488
+ if (char === "(") {
2489
+ if (depth === 0)
2490
+ start = index + 1;
2491
+ depth++;
2492
+ } else if (char === ")") {
2493
+ depth--;
2494
+ if (depth === 0 && start >= 0) {
2495
+ parts.push(sql2.slice(start, index).trim());
2496
+ return { clauses: parts, suffix: sql2.slice(index + 1) };
2497
+ }
2498
+ } else if (char === "," && depth === 1) {
2499
+ parts.push(sql2.slice(start, index).trim());
2500
+ start = index + 1;
2501
+ }
2502
+ }
2503
+ throw unavailable();
2504
+ }
2505
+ function unavailable() {
2506
+ return new VibeError8({ code: "VIBE_MIGRATION", message: "Cannot preserve table definition", meta: { reason: "table-definition-unavailable" } });
2507
+ }
2508
+ function sqliteColumnClauses(params) {
2509
+ const columns = [];
2510
+ for (const part of tableDefinitionParts(params).clauses) {
2511
+ const token = /^(?:"((?:[^"]|"")+)"|`((?:[^`]|``)+)`|\[([^\]]+)\]|([A-Za-z_][A-Za-z_0-9]*))/.exec(part);
2512
+ if (token === null)
2513
+ throw unavailable();
2514
+ if (token[4] !== undefined && /^(?:CONSTRAINT|PRIMARY|UNIQUE|CHECK|FOREIGN)$/i.test(token[4]))
2515
+ continue;
2516
+ const name = token[1]?.replaceAll('""', '"') ?? token[2]?.replaceAll("``", "`") ?? token[3] ?? token[4];
2517
+ columns.push({ name, sql: part });
2518
+ }
2519
+ return columns;
2520
+ }
2521
+ // packages/sql/src/dialects/constraint-owned-index.ts
2522
+ import { unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
2523
+ function renderConstraintOwnedIndexDrop(params) {
2524
+ if (params.dialect.name !== "postgres")
2525
+ throw unsupportedCapability9({ dialect: params.dialect.name, feature: "constraintOwnedIndexDrop" });
2526
+ const quote = (name) => params.dialect.quoteIdent({ name });
2527
+ return { text: `ALTER TABLE ${quote(params.table)} DROP CONSTRAINT ${quote(params.constraint)};`, values: [], returning: "none" };
2528
+ }
2529
+ // packages/sql/src/dialects/mysql-check-probe.ts
2530
+ import { unsupportedCapability as unsupportedCapability10 } from "@vibeorm/schema";
2531
+ function renderMysqlCheckProbe(params) {
2532
+ if (params.dialect.name !== "mysql")
2533
+ throw unsupportedCapability10({ dialect: params.dialect.name, feature: "temporaryCheckProbe" });
2534
+ const q = (name) => params.dialect.quoteIdent({ name });
2535
+ const probe = q(params.probe);
2536
+ switch (params.operation) {
2537
+ case "clone":
2538
+ if (params.table === undefined)
2539
+ throw unsupportedCapability10({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "A source table is required" });
2540
+ return { text: `CREATE TEMPORARY TABLE ${probe} LIKE ${q(params.table.namespace)}.${q(params.table.name)}`, values: [], returning: "none" };
2541
+ case "add": {
2542
+ if (params.expression === undefined || params.definition === undefined)
2543
+ throw unsupportedCapability10({ dialect: "mysql", feature: "temporaryCheckProbe", hint: "An authored expression and temporary clone definition are required" });
2544
+ const parts = tableDefinitionParts({ sql: params.definition });
2545
+ return { text: `CREATE TEMPORARY TABLE ${probe} (
2546
+ ${[...parts.clauses, `CONSTRAINT ${probe} CHECK (${params.expression})`].join(`,
2547
+ `)}
2548
+ )${parts.suffix}`, values: [], returning: "none" };
2549
+ }
2550
+ case "read":
2551
+ return { text: `SHOW CREATE TABLE ${probe}`, values: [], returning: "none" };
2552
+ case "drop":
2553
+ return { text: `DROP TEMPORARY TABLE ${probe}`, values: [], returning: "none" };
2554
+ }
2555
+ }
2556
+ // packages/sql/src/dialects/migration-history.ts
2557
+ function renderMigrationHistoryQuery(params) {
2558
+ const q = (name) => params.dialect.quoteIdent({ name });
2559
+ return { text: `SELECT ${q("name")}, ${q("checksum")}, ${q("statement_index")}, ${q("error")} FROM ${q(params.namespace)}.${q("_vibe_migrations")} ORDER BY ${q("id")}`, values: [], returning: "none" };
2560
+ }
2561
+ // packages/sql/src/dialects/sqlite-constraints.ts
2562
+ var IDENTIFIER = '(?:"(?:[^" ]| |"")+"|`(?:[^`]|``)+`|\\[[^\\]]+\\]|[A-Za-z_][A-Za-z_0-9]*)';
2563
+ function identifier3(value) {
2564
+ const text = value.trim();
2565
+ if (text.startsWith('"'))
2566
+ return text.slice(1, -1).replaceAll('""', '"');
2567
+ if (text.startsWith("`"))
2568
+ return text.slice(1, -1).replaceAll("``", "`");
2569
+ if (text.startsWith("["))
2570
+ return text.slice(1, -1);
2571
+ return text;
2572
+ }
2573
+ function sqliteTableConstraints(params) {
2574
+ const result = [];
2575
+ for (const clause of tableDefinitionParts(params).clauses) {
2576
+ const named = new RegExp(`^CONSTRAINT\\s+(${IDENTIFIER})\\s+`, "i").exec(clause);
2577
+ const body = named === null ? clause : clause.slice(named[0].length);
2578
+ const kind = /^(CHECK|FOREIGN\s+KEY|UNIQUE|PRIMARY\s+KEY)\s*\(/i.exec(body);
2579
+ if (kind === null)
2580
+ continue;
2581
+ const type = /^CHECK$/i.test(kind[1]) ? "check" : /^FOREIGN/i.test(kind[1]) ? "foreignKey" : /^PRIMARY/i.test(kind[1]) ? "primaryKey" : "unique";
2582
+ const parts = tableDefinitionParts({ sql: `CREATE TABLE x ${body.slice(kind[0].indexOf("("))}` });
2583
+ const columns = type === "check" ? [] : parts.clauses.map(identifier3);
2584
+ result.push({ name: named === null ? `@sqlite:${type}:${result.length}` : identifier3(named[1]), named: named !== null, type, sql: body, columns });
2585
+ }
2586
+ return result;
2587
+ }
2588
+ // packages/sql/src/dialects/migration-visibility.ts
2589
+ import { unsupportedCapability as unsupportedCapability11 } from "@vibeorm/schema";
2590
+ function renderMigrationVisibility(params) {
2591
+ if (params.dialect.name !== "mysql")
2592
+ throw unsupportedCapability11({ dialect: params.dialect.name, feature: "mysqlCatalogVisibility" });
2593
+ const collector = new ParamCollector(params.dialect);
2594
+ const grantee = "CONCAT(QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)), '@', QUOTE(SUBSTRING_INDEX(CURRENT_USER(), '@', -1)))";
2595
+ return { text: `SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.USER_PRIVILEGES WHERE GRANTEE = ${grantee} UNION SELECT PRIVILEGE_TYPE AS privilege FROM information_schema.SCHEMA_PRIVILEGES WHERE GRANTEE = ${grantee} AND ${collector.add(params.namespace)} LIKE TABLE_SCHEMA`, values: collector.values, returning: "none" };
2596
+ }
2597
+ // packages/sql/src/dialects/migration-inventory.ts
2598
+ import { unsupportedCapability as unsupportedCapability12 } from "@vibeorm/schema";
2599
+ function renderSqliteColumnInventory(params) {
2600
+ if (params.dialect.name !== "sqlite")
2601
+ throw unsupportedCapability12({ dialect: params.dialect.name, feature: "sqliteColumnInventory" });
2602
+ const collector = new ParamCollector(params.dialect);
2603
+ return { text: `SELECT name, hidden, pk, dflt_value AS definition FROM pragma_table_xinfo(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY cid`, values: collector.values, returning: "none" };
2604
+ }
2605
+ function renderSqliteForeignKeyInventory(params) {
2606
+ if (params.dialect.name !== "sqlite")
2607
+ throw unsupportedCapability12({ dialect: params.dialect.name, feature: "sqliteForeignKeyInventory" });
2608
+ const collector = new ParamCollector(params.dialect);
2609
+ return { text: `SELECT id, seq, "from", "to", "table", on_update, on_delete, match FROM pragma_foreign_key_list(${collector.add(params.table)}, ${collector.add(params.namespace)}) ORDER BY id, seq`, values: collector.values, returning: "none" };
2610
+ }
2611
+ function renderSqliteRebuildObjects(params) {
2612
+ if (params.dialect.name !== "sqlite")
2613
+ throw unsupportedCapability12({ dialect: params.dialect.name, feature: "sqliteRebuildObjects" });
2614
+ return { text: "SELECT name, tbl_name, type, sql FROM main.sqlite_schema WHERE type IN ('index', 'trigger') AND sql IS NOT NULL ORDER BY type, name", values: [], returning: "none" };
2615
+ }
2616
+ function renderMigrationInventory(params) {
2617
+ const collector = new ParamCollector(params.dialect);
2618
+ const namespace = collector.add(params.namespace);
2619
+ if (params.dialect.name === "postgres") {
2620
+ return { text: `WITH relations AS (
2621
+ SELECT c.oid, c.relname, c.relkind FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
2622
+ WHERE n.nspname = ${namespace} AND c.relname <> '_vibe_migrations'
2623
+ AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend jd JOIN pg_catalog.pg_class jt ON jt.oid = jd.refobjid WHERE jd.classid = 'pg_class'::regclass AND jd.objid = c.oid AND jd.refclassid = 'pg_class'::regclass AND jt.relname = '_vibe_migrations' AND jt.relnamespace = c.relnamespace)
2624
+ AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_class'::regclass AND d.objid = c.oid AND d.deptype = 'e')
2625
+ )
2626
+ SELECT CASE WHEN r.relkind IN ('v','m') THEN 'view' WHEN r.relkind = 'S' THEN 'sequence' ELSE 'table' END AS kind, r.relname::text AS name, NULL::text AS parent, NULL::text AS subtype, NULL::text AS signature, NULL::text AS backing FROM relations r WHERE r.relkind IN ('r','p','v','m','S')
2627
+ UNION ALL SELECT 'constraint', con.conname::text, r.relname::text, con.contype::text, NULL, NULL FROM relations r JOIN pg_catalog.pg_constraint con ON con.conrelid = r.oid WHERE con.contype IN ('c','f','x','u','p')
2628
+ UNION ALL SELECT 'index', ix.relname::text, r.relname::text, NULL, NULL, con.conname::text FROM relations r JOIN pg_catalog.pg_index i ON i.indrelid = r.oid JOIN pg_catalog.pg_class ix ON ix.oid = i.indexrelid LEFT JOIN pg_catalog.pg_constraint con ON con.conindid = i.indexrelid AND con.contype IN ('p','u','x')
2629
+ UNION ALL SELECT 'trigger', t.tgname::text, r.relname::text, NULL, NULL, NULL FROM relations r JOIN pg_catalog.pg_trigger t ON t.tgrelid = r.oid WHERE NOT t.tgisinternal
2630
+ UNION ALL SELECT 'column', a.attname::text, r.relname::text, NULL, NULL, NULL FROM relations r JOIN pg_catalog.pg_attribute a ON a.attrelid = r.oid WHERE a.attnum > 0 AND NOT a.attisdropped AND r.relkind IN ('r','p')
2631
+ UNION ALL SELECT CASE WHEN a.attgenerated <> '' THEN 'generatedColumn' ELSE 'columnDefault' END, a.attname::text, r.relname::text, NULL, NULL, NULL FROM relations r JOIN pg_catalog.pg_attribute a ON a.attrelid = r.oid JOIN pg_catalog.pg_attrdef d ON d.adrelid = r.oid AND d.adnum = a.attnum WHERE a.attnum > 0 AND NOT a.attisdropped
2632
+ UNION ALL SELECT 'function', p.proname::text, NULL, NULL, COALESCE((SELECT json_agg(json_build_object('namespace', tn.nspname, 'name', t.typname) ORDER BY a.ord)::text FROM unnest(p.proargtypes) WITH ORDINALITY a(oid, ord) JOIN pg_catalog.pg_type t ON t.oid = a.oid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace), '[]'), NULL FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.prokind = 'f' AND NOT EXISTS (SELECT 1 FROM pg_catalog.pg_depend d WHERE d.classid = 'pg_proc'::regclass AND d.objid = p.oid AND d.deptype = 'e')
2633
+ ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
2634
+ }
2635
+ if (params.dialect.name === "mysql") {
2636
+ const n = () => collector.add(params.namespace);
2637
+ return { text: `SELECT CASE WHEN TABLE_TYPE = 'VIEW' THEN 'view' ELSE 'table' END AS kind, TABLE_NAME AS name, NULL AS parent, NULL AS subtype, NULL AS signature, NULL AS backing FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME <> '_vibe_migrations'
2638
+ UNION ALL SELECT 'constraint', CONSTRAINT_NAME, TABLE_NAME, CONSTRAINT_TYPE, NULL, NULL FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = ${n()} AND TABLE_NAME <> '_vibe_migrations'
2639
+ UNION ALL SELECT 'index', s.INDEX_NAME, s.TABLE_NAME, NULL, NULL, tc.CONSTRAINT_NAME FROM information_schema.STATISTICS s LEFT JOIN information_schema.TABLE_CONSTRAINTS tc ON tc.TABLE_SCHEMA = s.TABLE_SCHEMA AND tc.TABLE_NAME = s.TABLE_NAME AND tc.CONSTRAINT_NAME = s.INDEX_NAME AND tc.CONSTRAINT_TYPE IN ('UNIQUE', 'PRIMARY KEY') WHERE s.TABLE_SCHEMA = ${n()} AND s.TABLE_NAME <> '_vibe_migrations' GROUP BY s.INDEX_NAME, s.TABLE_NAME, tc.CONSTRAINT_NAME
2640
+ UNION ALL SELECT 'trigger', TRIGGER_NAME, EVENT_OBJECT_TABLE, NULL, NULL, NULL FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = ${n()}
2641
+ UNION ALL SELECT 'column', COLUMN_NAME, TABLE_NAME, NULL, NULL, NULL FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${n()} AND TABLE_NAME <> '_vibe_migrations'
2642
+ UNION ALL SELECT CASE WHEN GENERATION_EXPRESSION <> '' THEN 'generatedColumn' ELSE 'columnDefault' END, COLUMN_NAME, TABLE_NAME, NULL, NULL, NULL FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${n()} AND TABLE_NAME <> '_vibe_migrations' AND (COLUMN_DEFAULT IS NOT NULL OR GENERATION_EXPRESSION <> '')
2643
+ UNION ALL SELECT 'function', ROUTINE_NAME, NULL, NULL, '[]', NULL FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${n()} AND ROUTINE_TYPE = 'FUNCTION'
2644
+ ORDER BY kind, parent, name`, values: collector.values, returning: "none" };
2645
+ }
2646
+ const schema = params.dialect.quoteIdent({ name: params.namespace });
2647
+ return { text: `SELECT type AS kind, name, tbl_name AS parent, sql AS definition FROM ${schema}.sqlite_schema WHERE name NOT LIKE 'sqlite_%' AND name <> '_vibe_migrations' ORDER BY type, tbl_name, name`, values: [], returning: "none" };
2648
+ }
2649
+ // packages/sql/src/dialects/migration-objects.ts
2650
+ import { unsupportedCapability as unsupportedCapability13 } from "@vibeorm/schema";
2651
+ function renderMigrationObjectQuery(params) {
2652
+ const { dialect, identity: object } = params;
2653
+ const collector = new ParamCollector(dialect);
2654
+ const physical = "table" in object ? object.table : object.name;
2655
+ const namespace = collector.add(physical.namespace);
2656
+ const name = collector.add(physical.name);
2657
+ let text;
2658
+ if (dialect.name === "postgres") {
2659
+ const relation = `FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace`;
2660
+ const where = `n.nspname = ${namespace} AND c.relname = ${name}`;
2661
+ switch (object.kind) {
2662
+ case "constraint": {
2663
+ const enforcement = object.constraintType === "foreignKey" ? `, (SELECT bool_and(t.tgenabled IN ('O', 'A')) FROM pg_catalog.pg_trigger t WHERE t.tgconstraint = con.oid) AS "triggersEnabled"` : "";
2664
+ text = `SELECT con.contype::text AS "type", pg_catalog.pg_get_constraintdef(con.oid, false) AS "definition", con.convalidated AS "validated", con.condeferrable AS "deferrable", con.condeferred AS "deferred"${enforcement} ${relation} JOIN pg_catalog.pg_constraint con ON con.conrelid = c.oid WHERE ${where} AND con.conname = ${collector.add(object.name)}`;
2665
+ break;
2666
+ }
2667
+ case "trigger":
2668
+ text = `SELECT pg_catalog.pg_get_triggerdef(t.oid, false) AS "definition", t.tgenabled::text AS "enabled", pn.nspname::text AS "functionNamespace", p.proname::text AS "functionName", pg_catalog.pg_get_function_identity_arguments(p.oid) AS "functionArguments" ${relation} JOIN pg_catalog.pg_trigger t ON t.tgrelid = c.oid JOIN pg_catalog.pg_proc p ON p.oid = t.tgfoid JOIN pg_catalog.pg_namespace pn ON pn.oid = p.pronamespace WHERE ${where} AND t.tgname = ${collector.add(object.name)} AND NOT t.tgisinternal`;
2669
+ break;
2670
+ case "function":
2671
+ text = `SELECT pg_catalog.pg_get_functiondef(p.oid) AS "definition", p.provolatile::text AS "volatility", p.prosecdef AS "securityDefiner", p.proisstrict AS "strict", p.proconfig::text AS "config", pg_catalog.pg_get_function_result(p.oid) AS "result" FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.proname = ${name} AND p.prokind = 'f' AND ARRAY(SELECT tn.nspname || '.' || t.typname FROM unnest(p.proargtypes) WITH ORDINALITY a(oid, ord) JOIN pg_catalog.pg_type t ON t.oid = a.oid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace ORDER BY a.ord) = ${collector.add(object.argumentTypes.map((type) => `${type.namespace}.${type.name}`))}::text[]`;
2672
+ break;
2673
+ case "view":
2674
+ text = `SELECT pg_catalog.pg_get_viewdef(c.oid, false) AS "definition", c.relkind::text AS "type", c.reloptions::text AS "options" ${relation} WHERE ${where} AND c.relkind IN ('v', 'm')`;
2675
+ break;
2676
+ case "sequence":
2677
+ text = `SELECT pg_catalog.format_type(s.seqtypid, NULL) AS "type", s.seqstart::text AS "start", s.seqincrement::text AS "increment", s.seqmax::text AS "max", s.seqmin::text AS "min", s.seqcache::text AS "cache", s.seqcycle AS "cycle" ${relation} JOIN pg_catalog.pg_sequence s ON s.seqrelid = c.oid WHERE ${where}`;
2678
+ break;
2679
+ case "column":
2680
+ case "columnDefault":
2681
+ case "generatedColumn":
2682
+ text = `SELECT pg_catalog.format_type(a.atttypid, a.atttypmod) AS "type", a.attnotnull AS "notNull", a.attgenerated::text AS "generated", a.attidentity::text AS "identity", pg_catalog.pg_get_expr(d.adbin, d.adrelid, false) AS "definition" ${relation} JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid LEFT JOIN pg_catalog.pg_attrdef d ON d.adrelid = c.oid AND d.adnum = a.attnum WHERE ${where} AND a.attname = ${collector.add(object.column)} AND a.attnum > 0 AND NOT a.attisdropped`;
2683
+ break;
2684
+ case "index":
2685
+ text = `SELECT pg_catalog.pg_get_indexdef(i.indexrelid, 0, false) AS "definition", i.indisunique AS "unique", i.indisvalid AS "valid", i.indisready AS "ready", con.conname::text AS "constraint", con.contype::text AS "constraintType" ${relation} JOIN pg_catalog.pg_index i ON i.indrelid = c.oid JOIN pg_catalog.pg_class ix ON ix.oid = i.indexrelid LEFT JOIN pg_catalog.pg_constraint con ON con.conindid = i.indexrelid AND con.contype IN ('p', 'u', 'x') WHERE ${where} AND ix.relname = ${collector.add(object.name)}`;
2686
+ break;
2687
+ case "table":
2688
+ text = `SELECT c.relkind::text AS "type", c.relrowsecurity AS "rls", c.relforcerowsecurity AS "forceRls" ${relation} WHERE ${where} AND c.relkind IN ('r', 'p')`;
2689
+ break;
2690
+ case "postgresExtension":
2691
+ text = `SELECT e.extversion::text AS "version", e.extrelocatable AS "relocatable" FROM pg_catalog.pg_extension e JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace WHERE n.nspname = ${namespace} AND e.extname = ${name}`;
2692
+ break;
2693
+ }
2694
+ } else if (dialect.name === "mysql") {
2695
+ switch (object.kind) {
2696
+ case "view":
2697
+ text = `SELECT VIEW_DEFINITION AS definition, CHECK_OPTION AS checkOption, SECURITY_TYPE AS securityType, DEFINER AS definer FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
2698
+ break;
2699
+ case "trigger":
2700
+ text = `SELECT ACTION_STATEMENT AS definition, ACTION_TIMING AS timing, EVENT_MANIPULATION AS event, ACTION_ORDER AS actionOrder, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = ${namespace} AND EVENT_OBJECT_TABLE = ${name} AND TRIGGER_NAME = ${collector.add(object.name)}`;
2701
+ break;
2702
+ case "function":
2703
+ text = `SELECT ROUTINE_DEFINITION AS definition, DTD_IDENTIFIER AS result, IS_DETERMINISTIC AS deterministic, SQL_DATA_ACCESS AS dataAccess, SECURITY_TYPE AS securityType, SQL_MODE AS sqlMode, DEFINER AS definer FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ${namespace} AND ROUTINE_NAME = ${name} AND ROUTINE_TYPE = 'FUNCTION'`;
2704
+ break;
2705
+ case "column":
2706
+ case "columnDefault":
2707
+ case "generatedColumn":
2708
+ text = `SELECT COLUMN_TYPE AS type, IS_NULLABLE AS nullable, COLUMN_DEFAULT AS definition, GENERATION_EXPRESSION AS generated, EXTRA AS extra, COLLATION_NAME AS collation FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND COLUMN_NAME = ${collector.add(object.column)}`;
2709
+ break;
2710
+ case "constraint":
2711
+ if (object.constraintType === "exclusion")
2712
+ throw unsupportedCapability13({ dialect: "mysql", feature: "exclusionConstraints" });
2713
+ text = `SELECT tc.CONSTRAINT_TYPE AS type, tc.ENFORCED AS enforced, cc.CHECK_CLAUSE AS definition, rc.UPDATE_RULE AS onUpdate, rc.DELETE_RULE AS onDelete, rc.MATCH_OPTION AS matchOption FROM information_schema.TABLE_CONSTRAINTS tc LEFT JOIN information_schema.CHECK_CONSTRAINTS cc ON cc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND cc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS rc ON rc.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA AND rc.TABLE_NAME = tc.TABLE_NAME AND rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME WHERE tc.TABLE_SCHEMA = ${namespace} AND tc.TABLE_NAME = ${name} AND tc.CONSTRAINT_NAME = ${collector.add(object.name)}`;
2714
+ break;
2715
+ case "index":
2716
+ text = `SELECT INDEX_NAME AS name, NON_UNIQUE AS nonUnique, INDEX_TYPE AS method, IS_VISIBLE AS visible FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)} GROUP BY INDEX_NAME, NON_UNIQUE, INDEX_TYPE, IS_VISIBLE`;
2717
+ break;
2718
+ case "table":
2719
+ text = `SELECT TABLE_TYPE AS type, ENGINE AS engine, TABLE_COLLATION AS collation FROM information_schema.TABLES WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name}`;
2720
+ break;
2721
+ default:
2722
+ throw unsupportedCapability13({ dialect: "mysql", feature: `inspect:${object.kind}` });
2723
+ }
2724
+ } else {
2725
+ if (physical.namespace !== "main" && physical.namespace !== "temp")
2726
+ throw unsupportedCapability13({ dialect: "sqlite", feature: "attachedSchemaInspection" });
2727
+ const catalog = `${dialect.quoteIdent({ name: physical.namespace })}.sqlite_schema`;
2728
+ const kind = object.kind === "table" || object.kind === "view" ? object.kind : object.kind === "trigger" ? "trigger" : object.kind === "index" ? "index" : "table";
2729
+ if (["function", "sequence", "postgresExtension"].includes(object.kind) || object.kind === "constraint" && object.constraintType === "exclusion")
2730
+ throw unsupportedCapability13({ dialect: "sqlite", feature: `inspect:${object.kind}` });
2731
+ const sqliteParams = new ParamCollector(dialect);
2732
+ if (object.kind === "column" || object.kind === "columnDefault" || object.kind === "generatedColumn") {
2733
+ text = `SELECT x.type AS type, x."notnull" AS "notNull", x.pk AS primaryKeyPosition, x.hidden AS generated, x.dflt_value AS definition, (SELECT sql FROM ${catalog} WHERE name = ${sqliteParams.add(physical.name)} AND type = 'table') AS tableDefinition FROM pragma_table_xinfo(${sqliteParams.add(physical.name)}, ${sqliteParams.add(physical.namespace)}) x WHERE x.name = ${sqliteParams.add(object.column)}`;
2734
+ return { text, values: sqliteParams.values, returning: "none" };
2735
+ }
2736
+ const objectName = object.kind === "trigger" || object.kind === "index" ? object.name : physical.name;
2737
+ text = `SELECT sql AS definition, type AS type FROM ${catalog} WHERE name = ${sqliteParams.add(objectName)} AND type = ${sqliteParams.add(kind)}`;
2738
+ return { text, values: sqliteParams.values, returning: "none" };
2739
+ }
2740
+ return { text, values: collector.values, returning: "none" };
2741
+ }
2742
+ function renderMysqlObjectMembers(params) {
2743
+ if (params.dialect.name !== "mysql")
2744
+ return;
2745
+ const object = params.identity;
2746
+ if (object.kind !== "function" && object.kind !== "index" && object.kind !== "constraint")
2747
+ return;
2748
+ const collector = new ParamCollector(params.dialect);
2749
+ const physical = "table" in object ? object.table : object.name;
2750
+ const namespace = collector.add(physical.namespace);
2751
+ const name = collector.add(physical.name);
2752
+ const text = object.kind === "function" ? `SELECT PARAMETER_MODE AS mode, PARAMETER_NAME AS name, DTD_IDENTIFIER AS type, CHARACTER_SET_NAME AS characterSet, COLLATION_NAME AS collation FROM information_schema.PARAMETERS WHERE SPECIFIC_SCHEMA = ${namespace} AND SPECIFIC_NAME = ${name} ORDER BY ORDINAL_POSITION` : object.kind === "index" ? `SELECT COLUMN_NAME AS name, EXPRESSION AS expression, SUB_PART AS prefixLength, COLLATION AS collation FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND INDEX_NAME = ${collector.add(object.name)} ORDER BY SEQ_IN_INDEX` : `SELECT COLUMN_NAME AS name, REFERENCED_TABLE_SCHEMA AS referenceNamespace, REFERENCED_TABLE_NAME AS referenceTable, REFERENCED_COLUMN_NAME AS referenceColumn FROM information_schema.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA = ${namespace} AND TABLE_NAME = ${name} AND CONSTRAINT_NAME = ${collector.add(object.name)} ORDER BY ORDINAL_POSITION`;
2753
+ return { text, values: collector.values, returning: "none" };
2754
+ }
2755
+ function renderMigrationDependencies(params) {
2756
+ if (params.dialect.name !== "postgres")
2757
+ throw unsupportedCapability13({ dialect: params.dialect.name, feature: "catalogDependencies" });
2758
+ const object = params.identity;
2759
+ const physical = "table" in object ? object.table : object.name;
2760
+ const collector = new ParamCollector(params.dialect);
2761
+ const namespace = collector.add(physical.namespace);
2762
+ const name = collector.add(physical.name);
2763
+ const relation = `SELECT c.oid FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ${namespace} AND c.relname = ${name}`;
2764
+ let source;
2765
+ switch (object.kind) {
2766
+ case "constraint":
2767
+ source = `SELECT 'pg_constraint'::regclass AS classid, con.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_constraint con WHERE con.conrelid = (${relation}) AND con.conname = ${collector.add(object.name)}`;
2768
+ break;
2769
+ case "trigger":
2770
+ source = `SELECT 'pg_trigger'::regclass AS classid, t.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_trigger t WHERE t.tgrelid = (${relation}) AND t.tgname = ${collector.add(object.name)}`;
2771
+ break;
2772
+ case "columnDefault":
2773
+ case "generatedColumn":
2774
+ source = `SELECT 'pg_attrdef'::regclass AS classid, d.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_attrdef d JOIN pg_catalog.pg_attribute a ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = (${relation}) AND a.attname = ${collector.add(object.column)}`;
2775
+ break;
2776
+ case "column":
2777
+ source = `SELECT 'pg_class'::regclass AS classid, a.attrelid AS objid, a.attnum AS objsubid FROM pg_catalog.pg_attribute a WHERE a.attrelid = (${relation}) AND a.attname = ${collector.add(object.column)}`;
2778
+ break;
2779
+ case "view":
2780
+ source = `SELECT 'pg_rewrite'::regclass AS classid, r.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_rewrite r WHERE r.ev_class = (${relation})`;
2781
+ break;
2782
+ case "index":
2783
+ source = `SELECT 'pg_class'::regclass AS classid, i.indexrelid AS objid, 0 AS objsubid FROM pg_catalog.pg_index i JOIN pg_catalog.pg_class c ON c.oid = i.indexrelid WHERE i.indrelid = (${relation}) AND c.relname = ${collector.add(object.name)}`;
2784
+ break;
2785
+ case "function":
2786
+ source = `SELECT 'pg_proc'::regclass AS classid, p.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = ${namespace} AND p.proname = ${name} AND ARRAY(SELECT tn.nspname || '.' || t.typname FROM unnest(p.proargtypes) WITH ORDINALITY a(oid, ord) JOIN pg_catalog.pg_type t ON t.oid = a.oid JOIN pg_catalog.pg_namespace tn ON tn.oid = t.typnamespace ORDER BY a.ord) = ${collector.add(object.argumentTypes.map((type) => `${type.namespace}.${type.name}`))}::text[]`;
2787
+ break;
2788
+ case "postgresExtension":
2789
+ source = `SELECT 'pg_extension'::regclass AS classid, e.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_extension e JOIN pg_catalog.pg_namespace n ON n.oid = e.extnamespace WHERE n.nspname = ${namespace} AND e.extname = ${name}`;
2790
+ break;
2791
+ default:
2792
+ source = `SELECT 'pg_class'::regclass AS classid, c.oid AS objid, 0 AS objsubid FROM pg_catalog.pg_class c WHERE c.oid = (${relation})`;
2793
+ break;
2794
+ }
2795
+ return { text: `SELECT DISTINCT json_build_array(d.deptype, a.type, a.object_names, a.object_args)::text AS address FROM (${source}) s JOIN pg_catalog.pg_depend d ON d.classid = s.classid AND d.objid = s.objid AND d.objsubid = s.objsubid CROSS JOIN LATERAL pg_catalog.pg_identify_object_as_address(d.refclassid, d.refobjid, d.refobjsubid) a ORDER BY address`, values: collector.values, returning: "none" };
2796
+ }
2797
+ function renderMigrationServerVersion(params) {
2798
+ return { text: params.dialect.name === "sqlite" ? "SELECT sqlite_version() AS version" : "SELECT version() AS version", values: [], returning: "none" };
2799
+ }
2800
+ function renderMigrationNamespace(params) {
2801
+ return { text: params.dialect.name === "mysql" ? "SELECT DATABASE() AS namespace" : params.dialect.name === "sqlite" ? "SELECT 'main' AS namespace" : "SELECT 'public' AS namespace", values: [], returning: "none" };
2802
+ }
2803
+ function renderCheckProbe(params) {
2804
+ if (params.dialect.name !== "postgres")
2805
+ throw unsupportedCapability13({ dialect: params.dialect.name, feature: "rollbackCheckProbe" });
2806
+ const q = (name) => params.dialect.quoteIdent({ name });
2807
+ return { text: `ALTER TABLE ${q(params.table.namespace)}.${q(params.table.name)} ADD CONSTRAINT ${q(params.name)} CHECK (${params.expression}) NOT VALID`, values: [], returning: "none" };
2808
+ }
1610
2809
  // packages/sql/src/dialects/postgres-migration.ts
1611
- import { VibeError as VibeError4, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
2810
+ import { VibeError as VibeError9, unsupportedCapability as unsupportedCapability14 } from "@vibeorm/schema";
1612
2811
  var SETTING_VALUE = /^[0-9]+(?:\.[0-9]+)?\s*(?:us|ms|s|min|h|d)?$/;
1613
2812
  function requirePostgres2(params) {
1614
2813
  if (params.dialect.name !== "postgres") {
1615
- throw unsupportedCapability6({ dialect: params.dialect.name, feature: params.feature });
2814
+ throw unsupportedCapability14({ dialect: params.dialect.name, feature: params.feature });
1616
2815
  }
1617
2816
  }
1618
2817
  function renderMigrationSessionRead(params) {
@@ -1627,7 +2826,7 @@ function renderMigrationSessionSet(params) {
1627
2826
  requirePostgres2({ dialect: params.dialect, feature: "migrationSessionSettings" });
1628
2827
  const { milliseconds, setting } = params;
1629
2828
  if (!Number.isSafeInteger(milliseconds) || milliseconds < 0) {
1630
- throw new VibeError4({
2829
+ throw new VibeError9({
1631
2830
  code: "VIBE_MIGRATION",
1632
2831
  message: `${setting} must be a non-negative integer number of milliseconds (got ${String(milliseconds)})`,
1633
2832
  meta: { reason: "execution-metadata-invalid", setting, value: milliseconds }
@@ -1714,63 +2913,21 @@ WHERE n.nspname = pg_catalog.current_schema() AND c.relname = ${table} AND a.att
1714
2913
  returning: "none"
1715
2914
  };
1716
2915
  }
1717
- // packages/sql/src/pg-array.ts
1718
- var PG_ARRAY_QUOTE = /^$|^NULL$|[{},"\\\s]/i;
1719
- function toPgArrayLiteral(params) {
1720
- const { values } = params;
1721
- const parts = values.map((value) => {
1722
- if (value === null || value === undefined)
1723
- return "NULL";
1724
- const text = String(value);
1725
- return PG_ARRAY_QUOTE.test(text) ? `"${text.replace(/["\\]/g, (char) => `\\${char}`)}"` : text;
1726
- });
1727
- return `{${parts.join(",")}}`;
1728
- }
1729
- function parsePgArrayLiteral(params) {
1730
- const { literal } = params;
1731
- if (literal.length < 2 || !literal.startsWith("{") || !literal.endsWith("}"))
1732
- return null;
1733
- const inner = literal.slice(1, -1);
1734
- if (inner.length === 0)
1735
- return [];
1736
- const out = [];
1737
- let index = 0;
1738
- while (index < inner.length) {
1739
- if (inner[index] === '"') {
1740
- let text = "";
1741
- index++;
1742
- while (index < inner.length) {
1743
- const char = inner[index];
1744
- if (char === "\\") {
1745
- text += inner[index + 1] ?? "";
1746
- index += 2;
1747
- continue;
1748
- }
1749
- index++;
1750
- if (char === '"')
1751
- break;
1752
- text += char;
1753
- }
1754
- out.push(text);
1755
- } else {
1756
- let text = "";
1757
- while (index < inner.length && inner[index] !== ",") {
1758
- text += inner[index];
1759
- index++;
1760
- }
1761
- out.push(text === "NULL" ? null : text);
1762
- }
1763
- if (inner[index] === ",")
1764
- index++;
1765
- }
1766
- return out;
1767
- }
1768
2916
  export {
1769
2917
  toPgArrayLiteral,
1770
2918
  strictMatchPattern,
1771
2919
  startsWithPattern,
2920
+ sqliteTableConstraints,
1772
2921
  sqliteDialect,
2922
+ sqliteColumnClauses,
2923
+ sqlUsesIncoming,
2924
+ sql,
1773
2925
  renderStatement,
2926
+ renderSqliteRebuildObjects,
2927
+ renderSqliteForeignKeyInventory,
2928
+ renderSqliteColumnInventory,
2929
+ renderSqlFragment,
2930
+ renderRowLockClause,
1774
2931
  renderRlsRole,
1775
2932
  renderRlsReadinessQuery,
1776
2933
  renderRlsProbeTable,
@@ -1785,23 +2942,42 @@ export {
1785
2942
  renderRlsContext,
1786
2943
  renderRlsColumnType,
1787
2944
  renderRelationStateQuery,
2945
+ renderPredicate,
1788
2946
  renderPostgresWorkload,
1789
2947
  renderPostgresExplain,
2948
+ renderMysqlObjectMembers,
2949
+ renderMysqlCheckProbe,
2950
+ renderMigrationVisibility,
1790
2951
  renderMigrationSessionSet,
1791
2952
  renderMigrationSessionRestore,
1792
2953
  renderMigrationSessionRead,
2954
+ renderMigrationServerVersion,
2955
+ renderMigrationObjectQuery,
2956
+ renderMigrationNamespace,
2957
+ renderMigrationInventory,
2958
+ renderMigrationHistoryQuery,
2959
+ renderMigrationDependencies,
1793
2960
  renderIndexStateQuery,
1794
2961
  renderFragment,
1795
2962
  renderExpr,
2963
+ renderExclusionSetup,
2964
+ renderExclusionProbe,
2965
+ renderExclusionDdl,
2966
+ renderExclusionCatalog,
1796
2967
  renderDiagnostic,
1797
2968
  renderConstraintStateQuery,
2969
+ renderConstraintOwnedIndexDrop,
1798
2970
  renderColumnStateQuery,
2971
+ renderCheckProbe,
2972
+ renderAdvisoryLock,
1799
2973
  projectionOutputName,
1800
2974
  postgresDialect,
1801
2975
  parsePgArrayLiteral,
1802
2976
  parseDateTimeText,
1803
2977
  mysqlDialect,
2978
+ mapConflictColumns,
1804
2979
  jsonParamCell,
2980
+ isSqlFragment,
1805
2981
  isSqlDefaultCell,
1806
2982
  isSetOperation,
1807
2983
  isListSetOperation,
@@ -1815,9 +2991,13 @@ export {
1815
2991
  escapeGlobPattern,
1816
2992
  enumMembershipCodec,
1817
2993
  endsWithPattern,
2994
+ describeRowLock,
1818
2995
  decodeIsNoop,
2996
+ decode,
1819
2997
  dbNowMarker,
1820
2998
  containsPattern,
2999
+ compileSql,
3000
+ compileExclusion,
1821
3001
  SQL_DIALECTS,
1822
3002
  SQL_DEFAULT_CELL,
1823
3003
  SQLITE_CODECS,
@@ -1834,7 +3014,9 @@ export {
1834
3014
  MYSQL_CAPABILITIES,
1835
3015
  JSON_TRANSPORT,
1836
3016
  DIALECT_CODECS,
1837
- DIALECT_CAPABILITIES
3017
+ DIALECT_CAPABILITIES,
3018
+ ADVISORY_LOCK_RESULT_COLUMN,
3019
+ ADVISORY_KEY_BOUNDS
1838
3020
  };
1839
3021
 
1840
- //# debugId=2783254C4B92111564756E2164756E21
3022
+ //# debugId=FBA51FB46584D1C064756E2164756E21