effect-qb 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/mysql.js +1661 -591
  2. package/dist/postgres/metadata.js +1930 -135
  3. package/dist/postgres.js +7808 -6718
  4. package/dist/sqlite.js +8360 -0
  5. package/package.json +6 -1
  6. package/src/internal/derived-table.ts +29 -3
  7. package/src/internal/dialect.ts +2 -0
  8. package/src/internal/dsl-mutation-runtime.ts +173 -4
  9. package/src/internal/dsl-plan-runtime.ts +165 -20
  10. package/src/internal/dsl-query-runtime.ts +60 -6
  11. package/src/internal/dsl-transaction-ddl-runtime.ts +72 -2
  12. package/src/internal/executor.ts +47 -9
  13. package/src/internal/expression-ast.ts +3 -2
  14. package/src/internal/grouping-key.ts +141 -1
  15. package/src/internal/implication-runtime.ts +2 -1
  16. package/src/internal/json/types.ts +155 -40
  17. package/src/internal/predicate/context.ts +14 -1
  18. package/src/internal/predicate/key.ts +19 -2
  19. package/src/internal/predicate/runtime.ts +27 -3
  20. package/src/internal/query.ts +252 -30
  21. package/src/internal/renderer.ts +35 -2
  22. package/src/internal/runtime/driver-value-mapping.ts +58 -0
  23. package/src/internal/runtime/normalize.ts +62 -38
  24. package/src/internal/runtime/schema.ts +5 -3
  25. package/src/internal/runtime/value.ts +153 -30
  26. package/src/internal/table-options.ts +108 -1
  27. package/src/internal/table.ts +87 -29
  28. package/src/mysql/column.ts +18 -2
  29. package/src/mysql/datatypes/index.ts +21 -0
  30. package/src/mysql/errors/catalog.ts +5 -5
  31. package/src/mysql/errors/normalize.ts +2 -2
  32. package/src/mysql/internal/dsl.ts +736 -218
  33. package/src/mysql/internal/renderer.ts +2 -1
  34. package/src/mysql/internal/sql-expression-renderer.ts +486 -130
  35. package/src/mysql/query.ts +9 -2
  36. package/src/mysql/table.ts +38 -12
  37. package/src/postgres/column.ts +4 -2
  38. package/src/postgres/errors/normalize.ts +2 -2
  39. package/src/postgres/executor.ts +48 -5
  40. package/src/postgres/function/core.ts +19 -1
  41. package/src/postgres/internal/dsl.ts +683 -240
  42. package/src/postgres/internal/renderer.ts +2 -1
  43. package/src/postgres/internal/schema-ddl.ts +2 -1
  44. package/src/postgres/internal/schema-model.ts +6 -3
  45. package/src/postgres/internal/sql-expression-renderer.ts +420 -91
  46. package/src/postgres/json.ts +57 -17
  47. package/src/postgres/query.ts +9 -2
  48. package/src/postgres/schema-management.ts +91 -4
  49. package/src/postgres/schema.ts +1 -1
  50. package/src/postgres/table.ts +189 -53
  51. package/src/sqlite/column.ts +128 -0
  52. package/src/sqlite/datatypes/index.ts +79 -0
  53. package/src/sqlite/datatypes/spec.ts +98 -0
  54. package/src/sqlite/errors/catalog.ts +103 -0
  55. package/src/sqlite/errors/fields.ts +19 -0
  56. package/src/sqlite/errors/index.ts +19 -0
  57. package/src/sqlite/errors/normalize.ts +229 -0
  58. package/src/sqlite/errors/requirements.ts +71 -0
  59. package/src/sqlite/errors/types.ts +29 -0
  60. package/src/sqlite/executor.ts +227 -0
  61. package/src/sqlite/function/aggregate.ts +2 -0
  62. package/src/sqlite/function/core.ts +2 -0
  63. package/src/sqlite/function/index.ts +19 -0
  64. package/src/sqlite/function/string.ts +2 -0
  65. package/src/sqlite/function/temporal.ts +100 -0
  66. package/src/sqlite/function/window.ts +2 -0
  67. package/src/sqlite/internal/dialect.ts +37 -0
  68. package/src/sqlite/internal/dsl.ts +6926 -0
  69. package/src/sqlite/internal/renderer.ts +47 -0
  70. package/src/sqlite/internal/sql-expression-renderer.ts +1821 -0
  71. package/src/sqlite/json.ts +2 -0
  72. package/src/sqlite/query.ts +196 -0
  73. package/src/sqlite/renderer.ts +24 -0
  74. package/src/sqlite/table.ts +183 -0
  75. package/src/sqlite.ts +22 -0
package/dist/mysql.js CHANGED
@@ -312,19 +312,109 @@ var references = (target) => foreignKey(target);
312
312
  // src/internal/runtime/value.ts
313
313
  import * as Schema3 from "effect/Schema";
314
314
  var brandString = (pattern2, brand5) => Schema3.String.pipe(Schema3.pattern(pattern2), Schema3.brand(brand5));
315
- var LocalDateStringSchema = brandString(/^\d{4}-\d{2}-\d{2}$/, "LocalDateString");
316
- var LocalTimeStringSchema = brandString(/^\d{2}:\d{2}:\d{2}(?:\.\d+)?$/, "LocalTimeString");
317
- var OffsetTimeStringSchema = brandString(/^\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/, "OffsetTimeString");
318
- var LocalDateTimeStringSchema = brandString(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?$/, "LocalDateTimeString");
319
- var InstantStringSchema = brandString(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/, "InstantString");
315
+ var localDatePattern = /^(\d{4})-(\d{2})-(\d{2})$/;
316
+ var isValidLocalDateString = (value) => {
317
+ const match = localDatePattern.exec(value);
318
+ if (match === null) {
319
+ return false;
320
+ }
321
+ const year = Number(match[1]);
322
+ const month = Number(match[2]);
323
+ const day = Number(match[3]);
324
+ const parsed = new Date(Date.UTC(year, month - 1, day));
325
+ parsed.setUTCFullYear(year);
326
+ return parsed.getUTCFullYear() === year && parsed.getUTCMonth() === month - 1 && parsed.getUTCDate() === day;
327
+ };
328
+ var localTimePattern = /^(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?$/;
329
+ var isValidLocalTimeString = (value) => {
330
+ const match = localTimePattern.exec(value);
331
+ if (match === null) {
332
+ return false;
333
+ }
334
+ const hour = Number(match[1]);
335
+ const minute = Number(match[2]);
336
+ const second = Number(match[3]);
337
+ return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
338
+ };
339
+ var offsetPattern = /^(?:Z|[+-](\d{2}):(\d{2}))$/;
340
+ var isValidOffset = (value) => {
341
+ const match = offsetPattern.exec(value);
342
+ if (match === null) {
343
+ return false;
344
+ }
345
+ if (value === "Z") {
346
+ return true;
347
+ }
348
+ const hour = Number(match[1]);
349
+ const minute = Number(match[2]);
350
+ return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59;
351
+ };
352
+ var offsetTimePattern = /^(\d{2}:\d{2}:\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:\d{2})$/;
353
+ var isValidOffsetTimeString = (value) => {
354
+ const match = offsetTimePattern.exec(value);
355
+ return match !== null && isValidLocalTimeString(match[1]) && isValidOffset(match[2]);
356
+ };
357
+ var localDateTimePattern = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?)$/;
358
+ var isValidLocalDateTimeString = (value) => {
359
+ const match = localDateTimePattern.exec(value);
360
+ return match !== null && isValidLocalDateString(match[1]) && isValidLocalTimeString(match[2]);
361
+ };
362
+ var instantPattern = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:\d{2})$/;
363
+ var isValidInstantString = (value) => {
364
+ const match = instantPattern.exec(value);
365
+ return match !== null && isValidLocalDateString(match[1]) && isValidLocalTimeString(match[2]) && isValidOffset(match[3]);
366
+ };
367
+ var LocalDateStringSchema = Schema3.String.pipe(Schema3.pattern(localDatePattern), Schema3.filter(isValidLocalDateString), Schema3.brand("LocalDateString"));
368
+ var LocalTimeStringSchema = Schema3.String.pipe(Schema3.pattern(localTimePattern), Schema3.filter(isValidLocalTimeString), Schema3.brand("LocalTimeString"));
369
+ var OffsetTimeStringSchema = Schema3.String.pipe(Schema3.pattern(offsetTimePattern), Schema3.filter(isValidOffsetTimeString), Schema3.brand("OffsetTimeString"));
370
+ var LocalDateTimeStringSchema = Schema3.String.pipe(Schema3.pattern(localDateTimePattern), Schema3.filter(isValidLocalDateTimeString), Schema3.brand("LocalDateTimeString"));
371
+ var InstantStringSchema = Schema3.String.pipe(Schema3.pattern(instantPattern), Schema3.filter(isValidInstantString), Schema3.brand("InstantString"));
320
372
  var YearStringSchema = brandString(/^\d{4}$/, "YearString");
321
- var BigIntStringSchema = brandString(/^-?\d+$/, "BigIntString");
322
- var DecimalStringSchema = brandString(/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/, "DecimalString");
323
- var JsonValueSchema = Schema3.suspend(() => Schema3.Union(Schema3.String, Schema3.Number, Schema3.Boolean, Schema3.Null, Schema3.Array(JsonValueSchema), Schema3.Record({
373
+ var canonicalizeBigIntString = (input) => {
374
+ const trimmed = input.trim();
375
+ if (!/^-?\d+$/.test(trimmed)) {
376
+ throw new Error("Expected an integer-like bigint value");
377
+ }
378
+ return BigInt(trimmed).toString();
379
+ };
380
+ var isCanonicalBigIntString = (value) => {
381
+ try {
382
+ return canonicalizeBigIntString(value) === value;
383
+ } catch {
384
+ return false;
385
+ }
386
+ };
387
+ var canonicalizeDecimalString = (input) => {
388
+ const trimmed = input.trim();
389
+ const match = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(trimmed);
390
+ if (match === null) {
391
+ throw new Error("Expected a decimal string");
392
+ }
393
+ const sign = match[1] === "-" ? "-" : "";
394
+ const integer = match[2].replace(/^0+(?=\d)/, "") || "0";
395
+ const fraction = (match[3] ?? "").replace(/0+$/, "");
396
+ if (fraction.length === 0) {
397
+ if (integer === "0") {
398
+ return "0";
399
+ }
400
+ return `${sign}${integer}`;
401
+ }
402
+ return `${sign}${integer}.${fraction}`;
403
+ };
404
+ var isCanonicalDecimalString = (value) => {
405
+ try {
406
+ return canonicalizeDecimalString(value) === value;
407
+ } catch {
408
+ return false;
409
+ }
410
+ };
411
+ var BigIntStringSchema = Schema3.String.pipe(Schema3.filter(isCanonicalBigIntString), Schema3.brand("BigIntString"));
412
+ var DecimalStringSchema = Schema3.String.pipe(Schema3.filter(isCanonicalDecimalString), Schema3.brand("DecimalString"));
413
+ var JsonValueSchema = Schema3.suspend(() => Schema3.Union(Schema3.String, Schema3.Number.pipe(Schema3.finite()), Schema3.Boolean, Schema3.Null, Schema3.Array(JsonValueSchema), Schema3.Record({
324
414
  key: Schema3.String,
325
415
  value: JsonValueSchema
326
416
  })));
327
- var JsonPrimitiveSchema = Schema3.Union(Schema3.String, Schema3.Number, Schema3.Boolean, Schema3.Null);
417
+ var JsonPrimitiveSchema = Schema3.Union(Schema3.String, Schema3.Number.pipe(Schema3.finite()), Schema3.Boolean, Schema3.Null);
328
418
 
329
419
  // src/mysql/datatypes/index.ts
330
420
  var exports_datatypes = {};
@@ -542,6 +632,12 @@ var mysqlDatatypeModule = {
542
632
  for (const kind of Object.keys(mysqlDatatypeKinds)) {
543
633
  mysqlDatatypeModule[kind] = () => withMetadata(kind);
544
634
  }
635
+ mysqlDatatypeModule.json = () => ({
636
+ ...withMetadata("json"),
637
+ driverValueMapping: {
638
+ toDriver: (value) => value !== null && typeof value === "object" ? JSON.stringify(value) : value
639
+ }
640
+ });
545
641
  var mysqlDatatypes = mysqlDatatypeModule;
546
642
 
547
643
  // src/mysql/column.ts
@@ -52238,10 +52334,8 @@ var mysqlErrorCatalogByNumber = {
52238
52334
  "MY-015152": [mysqlErrorCatalogBySymbol["ER_AUDIT_LOG_JSON_INVALID_FILTER_CANNOT_BE_USED"]],
52239
52335
  "MY-015153": [mysqlErrorCatalogBySymbol["ER_WARN_AUDIT_LOG_FILTER_RECOVERY_LOGGING_DISABLED_LOG"]]
52240
52336
  };
52241
- var mysqlSymbolPattern = /^(?:[A-Z][A-Z0-9_]*|MY-\d+)$/;
52242
- var mysqlNumberPattern = /^(?:\d+|MY-\d+)$/;
52243
- var isMysqlErrorSymbol = (value) => mysqlSymbolPattern.test(value);
52244
- var isMysqlErrorNumber = (value) => mysqlNumberPattern.test(value);
52337
+ var isMysqlErrorSymbol = (value) => (value in mysqlErrorCatalogBySymbol);
52338
+ var isMysqlErrorNumber = (value) => (value in mysqlErrorCatalogByNumber);
52245
52339
  var getMysqlErrorDescriptor = (symbol) => mysqlErrorCatalogBySymbol[symbol];
52246
52340
  var findMysqlErrorDescriptorsByNumber = (value) => mysqlErrorCatalogByNumber[value];
52247
52341
  var findMysqlErrorDescriptorsByNumberLoose = (value) => mysqlErrorCatalogByNumber[String(value)];
@@ -109613,8 +109707,8 @@ var asNumber = (value) => {
109613
109707
  if (typeof value === "number" && Number.isFinite(value)) {
109614
109708
  return value;
109615
109709
  }
109616
- if (typeof value === "string" && value.trim() !== "") {
109617
- const parsed = Number(value);
109710
+ if (typeof value === "string" && /^[+-]?\d+$/.test(value.trim())) {
109711
+ const parsed = Number(value.trim());
109618
109712
  return Number.isFinite(parsed) ? parsed : undefined;
109619
109713
  }
109620
109714
  return;
@@ -109797,6 +109891,27 @@ var TypeId3 = Symbol.for("effect-qb/Plan");
109797
109891
  import { pipeArguments as pipeArguments2 } from "effect/Pipeable";
109798
109892
 
109799
109893
  // src/internal/table-options.ts
109894
+ var referentialActionError = "Foreign key action must be noAction, restrict, cascade, setNull, or setDefault";
109895
+ var renderReferentialAction = (action) => {
109896
+ switch (action) {
109897
+ case "noAction":
109898
+ return "no action";
109899
+ case "restrict":
109900
+ return "restrict";
109901
+ case "cascade":
109902
+ return "cascade";
109903
+ case "setNull":
109904
+ return "set null";
109905
+ case "setDefault":
109906
+ return "set default";
109907
+ }
109908
+ throw new Error(referentialActionError);
109909
+ };
109910
+ var validateReferentialAction = (action) => {
109911
+ if (action !== undefined) {
109912
+ renderReferentialAction(action);
109913
+ }
109914
+ };
109800
109915
  var normalizeColumnList = (columns) => {
109801
109916
  const normalized = Array.isArray(columns) ? [...columns] : [columns];
109802
109917
  if (normalized.length === 0) {
@@ -109824,6 +109939,8 @@ var collectInlineOptions = (fields2) => {
109824
109939
  });
109825
109940
  }
109826
109941
  if (column.metadata.references) {
109942
+ validateReferentialAction(column.metadata.references.onUpdate);
109943
+ validateReferentialAction(column.metadata.references.onDelete);
109827
109944
  const local = [columnName];
109828
109945
  options.push({
109829
109946
  kind: "foreignKey",
@@ -109900,6 +110017,8 @@ var validateOptions = (tableName, fields2, options) => {
109900
110017
  }
109901
110018
  }
109902
110019
  if (option.kind === "foreignKey") {
110020
+ validateReferentialAction(option.onUpdate);
110021
+ validateReferentialAction(option.onDelete);
109903
110022
  const reference = option.references();
109904
110023
  if (reference.columns.length !== columns.length) {
109905
110024
  throw new Error(`Foreign key on table '${tableName}' must reference the same number of columns`);
@@ -109924,7 +110043,7 @@ var validateOptions = (tableName, fields2, options) => {
109924
110043
  throw new Error(`Unknown index key column '${key.column}' on table '${tableName}'`);
109925
110044
  }
109926
110045
  }
109927
- if (option.columns === undefined && (option.keys === undefined || option.keys.length === 0)) {
110046
+ if (columns.length === 0 && (option.keys === undefined || option.keys.length === 0)) {
109928
110047
  throw new Error(`Index on table '${tableName}' requires at least one column or key`);
109929
110048
  }
109930
110049
  }
@@ -110138,10 +110257,13 @@ function make2(name, fields2, schemaName) {
110138
110257
  const resolvedSchemaName = arguments.length >= 3 ? schemaName : "public";
110139
110258
  return makeTable(name, fields2, [], name, "schema", resolvedSchemaName, arguments.length >= 3 ? "explicit" : "default");
110140
110259
  }
110141
- var schema3 = (schemaName) => ({
110142
- schemaName,
110143
- table: (name, fields2, ...options2) => applyDeclaredOptions(makeTable(name, fields2, [], name, "schema", schemaName, "explicit"), options2)
110144
- });
110260
+ var schema3 = (schemaName) => {
110261
+ const table = (name, fields2, ...options2) => applyDeclaredOptions(makeTable(name, fields2, [], name, "schema", schemaName, "explicit"), options2);
110262
+ return {
110263
+ schemaName,
110264
+ table
110265
+ };
110266
+ };
110145
110267
  var alias = (table, aliasName) => {
110146
110268
  const state = table[TypeId4];
110147
110269
  const columns = Object.fromEntries(Object.entries(state.fields).map(([key, column]) => [key, bindColumn(aliasName, key, column, state.baseName, state.schemaName)]));
@@ -110265,6 +110387,309 @@ var check = (name, predicate) => makeOption({
110265
110387
  predicate
110266
110388
  });
110267
110389
 
110390
+ // src/internal/runtime/normalize.ts
110391
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
110392
+ var isPlainRecord = (value) => {
110393
+ if (!isRecord2(value)) {
110394
+ return false;
110395
+ }
110396
+ const prototype = Object.getPrototypeOf(value);
110397
+ return prototype === Object.prototype || prototype === null;
110398
+ };
110399
+ var pad = (value, width = 2) => value.toString().padStart(width, "0");
110400
+ var formatLocalDate = (value) => `${pad(value.getUTCFullYear(), 4)}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}`;
110401
+ var formatLocalTime = (value) => {
110402
+ const milliseconds = value.getUTCMilliseconds();
110403
+ const base = `${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}`;
110404
+ return milliseconds === 0 ? base : `${base}.${pad(milliseconds, 3)}`;
110405
+ };
110406
+ var formatLocalDateTime = (value) => {
110407
+ const milliseconds = value.getUTCMilliseconds();
110408
+ const base = `${formatLocalDate(value)}T${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}`;
110409
+ return milliseconds === 0 ? base : `${base}.${pad(milliseconds, 3)}`;
110410
+ };
110411
+ var runtimeTagOfBaseDbType = (dbType) => {
110412
+ return dbType.runtime;
110413
+ };
110414
+ var expectString = (value, label) => {
110415
+ if (typeof value === "string") {
110416
+ return value;
110417
+ }
110418
+ throw new Error(`Expected ${label} as string`);
110419
+ };
110420
+ var finiteNumberStringPattern = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:[eE][+-]?\d+)?$/;
110421
+ var normalizeNumber = (value) => {
110422
+ if (typeof value === "number" && Number.isFinite(value)) {
110423
+ return value;
110424
+ }
110425
+ if (typeof value === "string") {
110426
+ const trimmed = value.trim();
110427
+ const parsed = finiteNumberStringPattern.test(trimmed) ? Number(trimmed) : Number.NaN;
110428
+ if (Number.isFinite(parsed)) {
110429
+ return parsed;
110430
+ }
110431
+ }
110432
+ if (typeof value === "bigint" && Number.isSafeInteger(Number(value))) {
110433
+ return Number(value);
110434
+ }
110435
+ throw new Error("Expected a finite numeric value");
110436
+ };
110437
+ var normalizeBoolean = (value) => {
110438
+ if (typeof value === "boolean") {
110439
+ return value;
110440
+ }
110441
+ if (typeof value === "number") {
110442
+ if (value === 1) {
110443
+ return true;
110444
+ }
110445
+ if (value === 0) {
110446
+ return false;
110447
+ }
110448
+ }
110449
+ if (typeof value === "string") {
110450
+ const normalized = value.trim().toLowerCase();
110451
+ if (normalized === "true" || normalized === "t" || normalized === "1") {
110452
+ return true;
110453
+ }
110454
+ if (normalized === "false" || normalized === "f" || normalized === "0") {
110455
+ return false;
110456
+ }
110457
+ }
110458
+ throw new Error("Expected a boolean-like value");
110459
+ };
110460
+ var normalizeBigIntString = (value) => {
110461
+ if (typeof value === "bigint") {
110462
+ return value.toString();
110463
+ }
110464
+ if (typeof value === "number" && Number.isSafeInteger(value)) {
110465
+ return BigInt(value).toString();
110466
+ }
110467
+ if (typeof value === "string") {
110468
+ return canonicalizeBigIntString(value);
110469
+ }
110470
+ throw new Error("Expected an integer-like bigint value");
110471
+ };
110472
+ var normalizeDecimalString = (value) => {
110473
+ if (typeof value === "string") {
110474
+ return canonicalizeDecimalString(value);
110475
+ }
110476
+ if (typeof value === "number" && Number.isFinite(value)) {
110477
+ const rendered = String(value);
110478
+ if (/[eE]/.test(rendered)) {
110479
+ throw new Error("Scientific notation is not a supported decimal runtime");
110480
+ }
110481
+ return canonicalizeDecimalString(rendered);
110482
+ }
110483
+ throw new Error("Expected a decimal-like value");
110484
+ };
110485
+ var normalizeLocalDate = (value) => {
110486
+ if (value instanceof Date) {
110487
+ return formatLocalDate(value);
110488
+ }
110489
+ const raw = expectString(value, "local date").trim();
110490
+ if (isValidLocalDateString(raw)) {
110491
+ return raw;
110492
+ }
110493
+ const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
110494
+ if (isValidInstantString(canonicalInstant)) {
110495
+ const parsed = new Date(canonicalInstant);
110496
+ if (!Number.isNaN(parsed.getTime())) {
110497
+ return formatLocalDate(parsed);
110498
+ }
110499
+ }
110500
+ throw new Error("Expected a local-date value");
110501
+ };
110502
+ var normalizeLocalTime = (value) => {
110503
+ if (value instanceof Date) {
110504
+ return formatLocalTime(value);
110505
+ }
110506
+ const raw = expectString(value, "local time").trim();
110507
+ if (isValidLocalTimeString(raw)) {
110508
+ return raw;
110509
+ }
110510
+ throw new Error("Expected a local-time value");
110511
+ };
110512
+ var normalizeOffsetTime = (value) => {
110513
+ if (value instanceof Date) {
110514
+ return `${formatLocalTime(value)}Z`;
110515
+ }
110516
+ const raw = expectString(value, "offset time").trim();
110517
+ if (isValidOffsetTimeString(raw)) {
110518
+ return raw;
110519
+ }
110520
+ throw new Error("Expected an offset-time value");
110521
+ };
110522
+ var normalizeLocalDateTime = (value) => {
110523
+ if (value instanceof Date) {
110524
+ return formatLocalDateTime(value);
110525
+ }
110526
+ const raw = expectString(value, "local datetime").trim();
110527
+ const canonicalLocalDateTime = raw.replace(" ", "T");
110528
+ if (isValidLocalDateTimeString(canonicalLocalDateTime)) {
110529
+ return canonicalLocalDateTime;
110530
+ }
110531
+ const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
110532
+ if (isValidInstantString(canonicalInstant)) {
110533
+ const parsed = new Date(canonicalInstant);
110534
+ if (!Number.isNaN(parsed.getTime())) {
110535
+ return formatLocalDateTime(parsed);
110536
+ }
110537
+ }
110538
+ throw new Error("Expected a local-datetime value");
110539
+ };
110540
+ var normalizeInstant = (value) => {
110541
+ if (value instanceof Date) {
110542
+ return value.toISOString();
110543
+ }
110544
+ const raw = expectString(value, "instant").trim();
110545
+ if (!/[zZ]|[+-]\d{2}:\d{2}$/.test(raw)) {
110546
+ throw new Error("Instant values require a timezone offset");
110547
+ }
110548
+ const canonicalInstant = raw.replace(" ", "T").replace(/z$/, "Z");
110549
+ if (!isValidInstantString(canonicalInstant)) {
110550
+ throw new Error("Expected an ISO instant value");
110551
+ }
110552
+ const parsed = new Date(canonicalInstant);
110553
+ if (Number.isNaN(parsed.getTime())) {
110554
+ throw new Error("Expected an ISO instant value");
110555
+ }
110556
+ return parsed.toISOString();
110557
+ };
110558
+ var normalizeYear = (value) => {
110559
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 9999) {
110560
+ return pad(value, 4);
110561
+ }
110562
+ const raw = expectString(value, "year").trim();
110563
+ if (/^\d{4}$/.test(raw)) {
110564
+ return raw;
110565
+ }
110566
+ throw new Error("Expected a four-digit year");
110567
+ };
110568
+ var normalizeBytes = (value) => {
110569
+ if (value instanceof Uint8Array) {
110570
+ return new Uint8Array(value);
110571
+ }
110572
+ const BufferConstructor = globalThis.Buffer;
110573
+ if (BufferConstructor !== undefined && value instanceof BufferConstructor) {
110574
+ return new Uint8Array(value);
110575
+ }
110576
+ throw new Error("Expected a byte array value");
110577
+ };
110578
+ var isJsonValue = (value) => {
110579
+ if (value === null) {
110580
+ return true;
110581
+ }
110582
+ switch (typeof value) {
110583
+ case "string":
110584
+ case "boolean":
110585
+ return true;
110586
+ case "number":
110587
+ return Number.isFinite(value);
110588
+ case "object":
110589
+ if (Array.isArray(value)) {
110590
+ return value.every(isJsonValue);
110591
+ }
110592
+ return isPlainRecord(value) && Object.values(value).every(isJsonValue);
110593
+ default:
110594
+ return false;
110595
+ }
110596
+ };
110597
+ var normalizeJson = (value) => {
110598
+ if (typeof value === "string") {
110599
+ try {
110600
+ const parsed = JSON.parse(value);
110601
+ if (isJsonValue(parsed)) {
110602
+ return parsed;
110603
+ }
110604
+ throw new Error("Parsed JSON value is not a valid JSON runtime");
110605
+ } catch (error) {
110606
+ if (error instanceof SyntaxError) {
110607
+ return value;
110608
+ }
110609
+ throw error;
110610
+ }
110611
+ }
110612
+ if (isJsonValue(value)) {
110613
+ return value;
110614
+ }
110615
+ throw new Error("Expected a JSON value");
110616
+ };
110617
+ var normalizeDbValue = (dbType, value) => {
110618
+ if (value === null) {
110619
+ return null;
110620
+ }
110621
+ if ("base" in dbType) {
110622
+ return normalizeDbValue(dbType.base, value);
110623
+ }
110624
+ if ("element" in dbType) {
110625
+ if (!Array.isArray(value)) {
110626
+ throw new Error("Expected an array value");
110627
+ }
110628
+ return value.map((entry) => normalizeDbValue(dbType.element, entry));
110629
+ }
110630
+ if ("fields" in dbType) {
110631
+ if (!isRecord2(value)) {
110632
+ throw new Error("Expected a record value");
110633
+ }
110634
+ const normalized = {};
110635
+ for (const [key, fieldDbType] of Object.entries(dbType.fields)) {
110636
+ if (key in value) {
110637
+ normalized[key] = normalizeDbValue(fieldDbType, value[key]);
110638
+ }
110639
+ }
110640
+ return normalized;
110641
+ }
110642
+ if ("variant" in dbType && dbType.variant === "json") {
110643
+ return normalizeJson(value);
110644
+ }
110645
+ if ("variant" in dbType && (dbType.variant === "enum" || dbType.variant === "set")) {
110646
+ return expectString(value, "text");
110647
+ }
110648
+ switch (runtimeTagOfBaseDbType(dbType)) {
110649
+ case "string":
110650
+ return expectString(value, "text");
110651
+ case "number":
110652
+ return normalizeNumber(value);
110653
+ case "bigintString":
110654
+ return normalizeBigIntString(value);
110655
+ case "boolean":
110656
+ return normalizeBoolean(value);
110657
+ case "json":
110658
+ return normalizeJson(value);
110659
+ case "localDate":
110660
+ return normalizeLocalDate(value);
110661
+ case "localTime":
110662
+ return normalizeLocalTime(value);
110663
+ case "offsetTime":
110664
+ return normalizeOffsetTime(value);
110665
+ case "localDateTime":
110666
+ return normalizeLocalDateTime(value);
110667
+ case "instant":
110668
+ return normalizeInstant(value);
110669
+ case "year":
110670
+ return normalizeYear(value);
110671
+ case "decimalString":
110672
+ return normalizeDecimalString(value);
110673
+ case "bytes":
110674
+ return normalizeBytes(value);
110675
+ case "array":
110676
+ if (!Array.isArray(value)) {
110677
+ throw new Error("Expected an array value");
110678
+ }
110679
+ return value;
110680
+ case "record":
110681
+ if (!isRecord2(value)) {
110682
+ throw new Error("Expected a record value");
110683
+ }
110684
+ return value;
110685
+ case "null":
110686
+ return null;
110687
+ case "unknown":
110688
+ case undefined:
110689
+ return value;
110690
+ }
110691
+ };
110692
+
110268
110693
  // src/internal/query.ts
110269
110694
  import { pipeArguments as pipeArguments3 } from "effect/Pipeable";
110270
110695
 
@@ -110301,7 +110726,18 @@ var cloneContext = (context) => ({
110301
110726
  unknown: context.unknown
110302
110727
  });
110303
110728
  var freezeContext = (context) => context;
110304
- var sourceNameOfKey = (key) => key.split(".", 1)[0] ?? key;
110729
+ var columnPredicateKey = (tableName, columnName) => JSON.stringify([tableName, columnName]);
110730
+ var columnPredicateKeyParts = (key) => {
110731
+ const jsonSeparator = key.indexOf("#json:");
110732
+ const columnKey = jsonSeparator === -1 ? key : key.slice(0, jsonSeparator);
110733
+ try {
110734
+ const parsed = JSON.parse(columnKey);
110735
+ return Array.isArray(parsed) && parsed.length === 2 && typeof parsed[0] === "string" && typeof parsed[1] === "string" ? [parsed[0], parsed[1]] : undefined;
110736
+ } catch {
110737
+ return;
110738
+ }
110739
+ };
110740
+ var sourceNameOfKey = (key) => columnPredicateKeyParts(key)?.[0] ?? key.split(".", 1)[0] ?? key;
110305
110741
  var addSourceName = (context, key) => {
110306
110742
  context.sourceNames.add(sourceNameOfKey(key));
110307
110743
  };
@@ -110551,9 +110987,10 @@ var analyzeFormula = (formula) => freezeContext(analyzeStack(emptyContext(), [{
110551
110987
  var astOf = (value) => value[TypeId2];
110552
110988
  var columnKeyOfExpression = (value) => {
110553
110989
  const ast = astOf(value);
110554
- return ast.kind === "column" ? `${ast.tableName}.${ast.columnName}` : undefined;
110990
+ return ast.kind === "column" ? columnPredicateKey(ast.tableName, ast.columnName) : undefined;
110555
110991
  };
110556
110992
  var sameDbType = (left, right) => left.dialect === right.dialect && left.kind === right.kind;
110993
+ var escapeJsonPathPredicateKeySegment = (value) => value.replaceAll("\\", "\\\\").replaceAll(".", "\\.");
110557
110994
  var jsonPathPredicateKeyOfExpression = (value) => {
110558
110995
  const ast = astOf(value);
110559
110996
  switch (ast.kind) {
@@ -110577,7 +111014,7 @@ var jsonPathPredicateKeyOfExpression = (value) => {
110577
111014
  return;
110578
111015
  }
110579
111016
  const baseKey = columnKeyOfExpression(jsonAst.base);
110580
- return baseKey === undefined ? undefined : `${baseKey}#json:${path.join(".")}`;
111017
+ return baseKey === undefined ? undefined : `${baseKey}#json:${path.map(escapeJsonPathPredicateKeySegment).join(".")}`;
110581
111018
  }
110582
111019
  default:
110583
111020
  return;
@@ -110993,7 +111430,7 @@ var collectPresenceWitnesses = (selection, output) => {
110993
111430
  const expression = selection;
110994
111431
  const ast = expression[TypeId2];
110995
111432
  if (ast.kind === "column" && expression[TypeId].nullability === "never") {
110996
- output.add(`${ast.tableName}.${ast.columnName}`);
111433
+ output.add(columnPredicateKey(ast.tableName, ast.columnName));
110997
111434
  }
110998
111435
  return;
110999
111436
  }
@@ -111142,6 +111579,20 @@ var path = (...segments) => ({
111142
111579
  });
111143
111580
 
111144
111581
  // src/internal/grouping-key.ts
111582
+ var subqueryPlanIds = new WeakMap;
111583
+ var nextSubqueryPlanId = 0;
111584
+ var subqueryPlanGroupingKey = (plan) => {
111585
+ if (plan === null || typeof plan !== "object") {
111586
+ return "unknown";
111587
+ }
111588
+ const existing = subqueryPlanIds.get(plan);
111589
+ if (existing !== undefined) {
111590
+ return existing;
111591
+ }
111592
+ const next = `${nextSubqueryPlanId++}`;
111593
+ subqueryPlanIds.set(plan, next);
111594
+ return next;
111595
+ };
111145
111596
  var literalGroupingKey = (value) => {
111146
111597
  if (value instanceof Date) {
111147
111598
  return `date:${value.toISOString()}`;
@@ -111160,15 +111611,62 @@ var literalGroupingKey = (value) => {
111160
111611
  return `literal:${JSON.stringify(value)}`;
111161
111612
  }
111162
111613
  };
111614
+ var isExpression = (value) => value !== null && typeof value === "object" && (TypeId in value);
111615
+ var expressionGroupingKey = (value) => isExpression(value) ? groupingKeyOfExpression(value) : "missing";
111616
+ var escapeGroupingText = (value) => value.replace(/\\/g, "\\\\").replace(/,/g, "\\,").replace(/\|/g, "\\|").replace(/=/g, "\\=").replace(/>/g, "\\>");
111617
+ var jsonSegmentGroupingKey = (segment) => {
111618
+ if (segment !== null && typeof segment === "object" && "kind" in segment) {
111619
+ switch (segment.kind) {
111620
+ case "key":
111621
+ return `key:${escapeGroupingText(segment.key)}`;
111622
+ case "index":
111623
+ return `index:${segment.index}`;
111624
+ case "wildcard":
111625
+ return "wildcard";
111626
+ case "slice": {
111627
+ const slice2 = segment;
111628
+ return `slice:${slice2.start ?? ""}:${slice2.end ?? ""}`;
111629
+ }
111630
+ case "descend":
111631
+ return "descend";
111632
+ }
111633
+ }
111634
+ if (typeof segment === "string") {
111635
+ return `key:${escapeGroupingText(segment)}`;
111636
+ }
111637
+ if (typeof segment === "number") {
111638
+ return `index:${segment}`;
111639
+ }
111640
+ return "unknown";
111641
+ };
111642
+ var jsonPathGroupingKey = (segments) => (segments ?? []).map(jsonSegmentGroupingKey).join(",");
111643
+ var isJsonPath = (value) => value !== null && typeof value === "object" && (TypeId6 in value);
111644
+ var jsonOpaquePathGroupingKey = (value) => {
111645
+ if (isJsonPath(value)) {
111646
+ return `jsonpath:${jsonPathGroupingKey(value.segments)}`;
111647
+ }
111648
+ if (typeof value === "string") {
111649
+ return `jsonpath:${escapeGroupingText(value)}`;
111650
+ }
111651
+ if (isExpression(value)) {
111652
+ return `jsonpath:${groupingKeyOfExpression(value)}`;
111653
+ }
111654
+ return "jsonpath:unknown";
111655
+ };
111656
+ var jsonEntryGroupingKey = (entry) => `${escapeGroupingText(entry.key)}=>${groupingKeyOfExpression(entry.value)}`;
111163
111657
  var groupingKeyOfExpression = (expression) => {
111164
111658
  const ast = expression[TypeId2];
111165
111659
  switch (ast.kind) {
111166
111660
  case "column":
111167
- return `column:${ast.tableName}.${ast.columnName}`;
111661
+ return `column:${columnPredicateKey(ast.tableName, ast.columnName)}`;
111168
111662
  case "literal":
111169
111663
  return `literal:${literalGroupingKey(ast.value)}`;
111170
111664
  case "cast":
111171
111665
  return `cast(${groupingKeyOfExpression(ast.value)} as ${ast.target.dialect}:${ast.target.kind})`;
111666
+ case "collate":
111667
+ return `collate(${groupingKeyOfExpression(ast.value)},${ast.collation.map(escapeGroupingText).join(",")})`;
111668
+ case "function":
111669
+ return `function(${escapeGroupingText(ast.name)},${ast.args.map(groupingKeyOfExpression).join(",")})`;
111172
111670
  case "isNull":
111173
111671
  case "isNotNull":
111174
111672
  case "not":
@@ -111186,8 +111684,15 @@ var groupingKeyOfExpression = (expression) => {
111186
111684
  case "gte":
111187
111685
  case "like":
111188
111686
  case "ilike":
111687
+ case "regexMatch":
111688
+ case "regexIMatch":
111689
+ case "regexNotMatch":
111690
+ case "regexNotIMatch":
111189
111691
  case "isDistinctFrom":
111190
111692
  case "isNotDistinctFrom":
111693
+ case "contains":
111694
+ case "containedBy":
111695
+ case "overlaps":
111191
111696
  return `${ast.kind}(${groupingKeyOfExpression(ast.left)},${groupingKeyOfExpression(ast.right)})`;
111192
111697
  case "and":
111193
111698
  case "or":
@@ -111199,6 +111704,54 @@ var groupingKeyOfExpression = (expression) => {
111199
111704
  return `${ast.kind}(${ast.values.map(groupingKeyOfExpression).join(",")})`;
111200
111705
  case "case":
111201
111706
  return `case(${ast.branches.map((branch) => `when:${groupingKeyOfExpression(branch.when)}=>${groupingKeyOfExpression(branch.then)}`).join("|")};else:${groupingKeyOfExpression(ast.else)})`;
111707
+ case "exists":
111708
+ return `exists(${subqueryPlanGroupingKey(ast.plan)})`;
111709
+ case "scalarSubquery":
111710
+ return `scalarSubquery(${subqueryPlanGroupingKey(ast.plan)})`;
111711
+ case "inSubquery":
111712
+ return `inSubquery(${groupingKeyOfExpression(ast.left)},${subqueryPlanGroupingKey(ast.plan)})`;
111713
+ case "comparisonAny":
111714
+ case "comparisonAll":
111715
+ return `${ast.kind}(${ast.operator},${groupingKeyOfExpression(ast.left)},${subqueryPlanGroupingKey(ast.plan)})`;
111716
+ case "jsonGet":
111717
+ case "jsonPath":
111718
+ case "jsonAccess":
111719
+ case "jsonTraverse":
111720
+ case "jsonGetText":
111721
+ case "jsonPathText":
111722
+ case "jsonAccessText":
111723
+ case "jsonTraverseText":
111724
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${jsonPathGroupingKey(ast.segments)})`;
111725
+ case "jsonHasKey":
111726
+ case "jsonKeyExists":
111727
+ case "jsonHasAnyKeys":
111728
+ case "jsonHasAllKeys":
111729
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${(ast.keys ?? []).map(escapeGroupingText).join(",")})`;
111730
+ case "jsonConcat":
111731
+ case "jsonMerge":
111732
+ return `json(${ast.kind},${expressionGroupingKey(ast.left)},${expressionGroupingKey(ast.right)},)`;
111733
+ case "jsonDelete":
111734
+ case "jsonDeletePath":
111735
+ case "jsonRemove":
111736
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(undefined)},${jsonPathGroupingKey(ast.segments)})`;
111737
+ case "jsonSet":
111738
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(ast.newValue)},${jsonPathGroupingKey(ast.segments)})`;
111739
+ case "jsonInsert":
111740
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${expressionGroupingKey(ast.insert)},${jsonPathGroupingKey(ast.segments)})`;
111741
+ case "jsonPathExists":
111742
+ case "jsonPathMatch":
111743
+ return `json(${ast.kind},${expressionGroupingKey(ast.base)},${jsonOpaquePathGroupingKey(ast.query)})`;
111744
+ case "jsonBuildObject":
111745
+ return `json(${ast.kind},${(ast.entries ?? []).map(jsonEntryGroupingKey).join("|")})`;
111746
+ case "jsonBuildArray":
111747
+ return `json(${ast.kind},${(ast.values ?? []).map(groupingKeyOfExpression).join(",")})`;
111748
+ case "jsonToJson":
111749
+ case "jsonToJsonb":
111750
+ case "jsonTypeOf":
111751
+ case "jsonLength":
111752
+ case "jsonKeys":
111753
+ case "jsonStripNulls":
111754
+ return `json(${ast.kind},${expressionGroupingKey(ast.value)})`;
111202
111755
  default:
111203
111756
  throw new Error("Unsupported expression for grouping key generation");
111204
111757
  }
@@ -111216,8 +111769,112 @@ var dedupeGroupedExpressions = (values) => {
111216
111769
  };
111217
111770
 
111218
111771
  // src/internal/dsl-mutation-runtime.ts
111772
+ var expectInsertSourceKind = (source) => {
111773
+ if (source !== undefined && source.kind !== "values" && source.kind !== "query" && source.kind !== "unnest") {
111774
+ throw new Error("Unsupported insert source kind");
111775
+ }
111776
+ return source;
111777
+ };
111778
+ var expectConflictClause = (conflict) => {
111779
+ if (conflict === undefined) {
111780
+ return conflict;
111781
+ }
111782
+ if (conflict.kind !== "conflict") {
111783
+ throw new Error("Unsupported conflict clause kind");
111784
+ }
111785
+ if (conflict.action !== "doNothing" && conflict.action !== "doUpdate") {
111786
+ throw new Error("Unsupported conflict action");
111787
+ }
111788
+ if (conflict.target !== undefined && conflict.target.kind !== "columns" && conflict.target.kind !== "constraint") {
111789
+ throw new Error("Unsupported conflict target kind");
111790
+ }
111791
+ return conflict;
111792
+ };
111219
111793
  var makeDslMutationRuntime = (ctx) => {
111794
+ const aliasedSourceKinds = new Set(["derived", "cte", "lateral", "values", "unnest", "tableFunction"]);
111795
+ const isRecord3 = (value) => typeof value === "object" && value !== null;
111796
+ const isTableTarget = (target) => typeof target === "object" && target !== null && (TypeId4 in target) && (TypeId3 in target);
111797
+ const hasColumnRecord = (value) => isRecord3(value.columns);
111798
+ const isAliasedSource = (source) => {
111799
+ if (!isRecord3(source)) {
111800
+ return false;
111801
+ }
111802
+ if (isTableTarget(source)) {
111803
+ return true;
111804
+ }
111805
+ if (!("kind" in source) || !("name" in source) || !("baseName" in source)) {
111806
+ return false;
111807
+ }
111808
+ if (typeof source.kind !== "string" || !aliasedSourceKinds.has(source.kind)) {
111809
+ return false;
111810
+ }
111811
+ if (typeof source.name !== "string" || typeof source.baseName !== "string") {
111812
+ return false;
111813
+ }
111814
+ switch (source.kind) {
111815
+ case "derived":
111816
+ case "cte":
111817
+ case "lateral":
111818
+ return isRecord3(source.plan) && TypeId3 in source.plan && hasColumnRecord(source);
111819
+ case "values":
111820
+ return Array.isArray(source.rows) && hasColumnRecord(source);
111821
+ case "unnest":
111822
+ return isRecord3(source.arrays) && hasColumnRecord(source);
111823
+ case "tableFunction":
111824
+ return typeof source.functionName === "string" && Array.isArray(source.args) && hasColumnRecord(source);
111825
+ }
111826
+ return false;
111827
+ };
111828
+ const assertMutationTarget = (target, apiName) => {
111829
+ if (!isTableTarget(target)) {
111830
+ throw new Error(`${apiName}(...) requires table targets`);
111831
+ }
111832
+ };
111833
+ const assertAliasedSource = (source, apiName) => {
111834
+ if (!isAliasedSource(source)) {
111835
+ throw new Error(`${apiName}(...) requires an aliased source`);
111836
+ }
111837
+ };
111838
+ const assertMutationTargets = (target, apiName, options2 = {}) => {
111839
+ const targets = Array.isArray(target) ? target : [target];
111840
+ if (targets.length === 0) {
111841
+ throw new Error(`${apiName}(...) requires at least one table target`);
111842
+ }
111843
+ if (Array.isArray(target) && targets.length === 1) {
111844
+ throw new Error(`${apiName}(...) requires a table target, not a single-element target tuple`);
111845
+ }
111846
+ for (const entry of targets) {
111847
+ assertMutationTarget(entry, apiName);
111848
+ }
111849
+ if (targets.length > 1 && options2.allowMultiple !== true) {
111850
+ throw new Error(`${apiName}(...) requires a single table target`);
111851
+ }
111852
+ if (targets.length > 1 && ctx.profile.dialect !== "mysql" && ctx.profile.dialect !== "sqlite") {
111853
+ throw new Error(`${apiName}(...) only supports multiple mutation targets for mysql`);
111854
+ }
111855
+ };
111856
+ const assertUniqueTargetNames = (targets) => {
111857
+ const seen = new Set;
111858
+ for (const target of targets) {
111859
+ if (seen.has(target.tableName)) {
111860
+ throw new Error(`mutation target source names must be unique: ${target.tableName}`);
111861
+ }
111862
+ seen.add(target.tableName);
111863
+ }
111864
+ };
111865
+ const assertInsertSelectSource = (sourcePlan, selection) => {
111866
+ const statement = ctx.getQueryState(sourcePlan).statement;
111867
+ if (statement !== "select" && statement !== "set") {
111868
+ throw new Error("insert sources only accept select-like query plans");
111869
+ }
111870
+ for (const value of Object.values(selection)) {
111871
+ if (value === null || typeof value !== "object" || !(TypeId in value)) {
111872
+ throw new Error("insert sources require a flat selection object");
111873
+ }
111874
+ }
111875
+ };
111220
111876
  const insert = (target, values) => {
111877
+ assertMutationTargets(target, "insert");
111221
111878
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
111222
111879
  const assignments = values === undefined ? [] : ctx.buildMutationAssignments(target, values);
111223
111880
  const required = assignments.flatMap((entry) => Object.keys(entry.value[TypeId].dependencies));
@@ -111293,10 +111950,11 @@ var makeDslMutationRuntime = (ctx) => {
111293
111950
  }
111294
111951
  const sourcePlan = source;
111295
111952
  const selection = sourcePlan[TypeId3].selection;
111953
+ assertInsertSelectSource(sourcePlan, selection);
111296
111954
  const columns = ctx.normalizeInsertSelectColumns(selection);
111297
111955
  return ctx.makePlan({
111298
111956
  selection: current.selection,
111299
- required: ctx.currentRequiredList(sourcePlan[TypeId3].required).filter((name) => name !== sourceName),
111957
+ required: ctx.currentRequiredList(sourcePlan[TypeId3].required),
111300
111958
  available: current.available,
111301
111959
  dialect: current.dialect
111302
111960
  }, {
@@ -111313,14 +111971,22 @@ var makeDslMutationRuntime = (ctx) => {
111313
111971
  const current = plan[TypeId3];
111314
111972
  const currentAst = ctx.getAst(plan);
111315
111973
  const currentQuery = ctx.getQueryState(plan);
111974
+ if (currentQuery.statement !== "insert") {
111975
+ throw new Error(`onConflict(...) is not supported for ${currentQuery.statement} statements`);
111976
+ }
111316
111977
  const insertTarget = currentAst.into.source;
111317
111978
  const conflictTarget = ctx.buildConflictTarget(insertTarget, target);
111318
111979
  const updateAssignments = options2.update ? ctx.buildMutationAssignments(insertTarget, options2.update) : [];
111980
+ if (options2.update !== undefined && updateAssignments.length === 0) {
111981
+ throw new Error("conflict update assignments require at least one assignment");
111982
+ }
111319
111983
  const updateWhere = options2.where === undefined ? undefined : ctx.toDialectExpression(options2.where);
111984
+ const targetWhere = conflictTarget.kind === "columns" ? conflictTarget.where : undefined;
111320
111985
  const required = [
111321
111986
  ...ctx.currentRequiredList(current.required),
111322
111987
  ...updateAssignments.flatMap((entry) => Object.keys(entry.value[TypeId].dependencies)),
111323
- ...updateWhere ? Object.keys(updateWhere[TypeId].dependencies) : []
111988
+ ...updateWhere ? Object.keys(updateWhere[TypeId].dependencies) : [],
111989
+ ...targetWhere ? Object.keys(targetWhere[TypeId].dependencies) : []
111324
111990
  ].filter((name, index4, list) => !(name in current.available) && list.indexOf(name) === index4);
111325
111991
  return ctx.makePlan({
111326
111992
  selection: current.selection,
@@ -111339,7 +112005,9 @@ var makeDslMutationRuntime = (ctx) => {
111339
112005
  }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, currentQuery.insertSource);
111340
112006
  };
111341
112007
  const update = (target, values) => {
112008
+ assertMutationTargets(target, "update", { allowMultiple: true });
111342
112009
  const targets = ctx.mutationTargetClauses(target);
112010
+ assertUniqueTargetNames(targets);
111343
112011
  const primaryTarget = targets[0];
111344
112012
  const assignments = ctx.buildMutationAssignments(target, values);
111345
112013
  const targetNames = new Set(targets.map((entry) => entry.tableName));
@@ -111363,9 +112031,13 @@ var makeDslMutationRuntime = (ctx) => {
111363
112031
  }, undefined, "write", "update");
111364
112032
  };
111365
112033
  const upsert = (target, values, conflictColumns, updateValues) => {
112034
+ assertMutationTargets(target, "upsert");
111366
112035
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
111367
112036
  const assignments = ctx.buildMutationAssignments(target, values);
111368
112037
  const updateAssignments = updateValues ? ctx.buildMutationAssignments(target, updateValues) : [];
112038
+ if (updateValues !== undefined && updateAssignments.length === 0) {
112039
+ throw new Error("upsert update assignments require at least one assignment");
112040
+ }
111369
112041
  const required = [
111370
112042
  ...assignments.flatMap((entry) => Object.keys(entry.value[TypeId].dependencies)),
111371
112043
  ...updateAssignments.flatMap((entry) => Object.keys(entry.value[TypeId].dependencies))
@@ -111395,7 +112067,7 @@ var makeDslMutationRuntime = (ctx) => {
111395
112067
  kind: "conflict",
111396
112068
  target: {
111397
112069
  kind: "columns",
111398
- columns: ctx.normalizeColumnList(conflictColumns)
112070
+ columns: ctx.normalizeConflictColumns(target, conflictColumns)
111399
112071
  },
111400
112072
  action: updateAssignments.length > 0 ? "doUpdate" : "doNothing",
111401
112073
  values: updateAssignments.length > 0 ? updateAssignments : undefined
@@ -111408,7 +112080,9 @@ var makeDslMutationRuntime = (ctx) => {
111408
112080
  }, undefined, "write", "insert", target, "ready");
111409
112081
  };
111410
112082
  const delete_ = (target) => {
112083
+ assertMutationTargets(target, "delete", { allowMultiple: true });
111411
112084
  const targets = ctx.mutationTargetClauses(target);
112085
+ assertUniqueTargetNames(targets);
111412
112086
  const primaryTarget = targets[0];
111413
112087
  return ctx.makePlan({
111414
112088
  selection: {},
@@ -111428,6 +112102,7 @@ var makeDslMutationRuntime = (ctx) => {
111428
112102
  }, undefined, "write", "delete");
111429
112103
  };
111430
112104
  const truncate = (target, options2 = {}) => {
112105
+ assertMutationTargets(target, "truncate");
111431
112106
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
111432
112107
  return ctx.makePlan({
111433
112108
  selection: {},
@@ -111456,8 +112131,13 @@ var makeDslMutationRuntime = (ctx) => {
111456
112131
  }, undefined, "write", "truncate");
111457
112132
  };
111458
112133
  const merge = (target, source, on, options2 = {}) => {
112134
+ assertMutationTargets(target, "merge");
112135
+ assertAliasedSource(source, "merge");
111459
112136
  const { sourceName: targetName, sourceBaseName: targetBaseName } = ctx.targetSourceDetails(target);
111460
112137
  const { sourceName: usingName, sourceBaseName: usingBaseName } = ctx.sourceDetails(source);
112138
+ if (targetName === usingName) {
112139
+ throw new Error(`merge(...) source name must differ from target source name: ${targetName}`);
112140
+ }
111461
112141
  const onExpression = ctx.toDialectExpression(on);
111462
112142
  const matched = options2.whenMatched;
111463
112143
  const notMatched = options2.whenNotMatched;
@@ -111543,8 +112223,98 @@ var makeDslMutationRuntime = (ctx) => {
111543
112223
  };
111544
112224
 
111545
112225
  // src/internal/dsl-plan-runtime.ts
112226
+ var renderSelectLockMode = (mode) => {
112227
+ switch (mode) {
112228
+ case "update":
112229
+ return "for update";
112230
+ case "share":
112231
+ return "for share";
112232
+ }
112233
+ throw new Error("lock(...) mode must be update or share for select statements");
112234
+ };
112235
+ var renderMysqlMutationLockMode = (mode, statement) => {
112236
+ switch (mode) {
112237
+ case "lowPriority":
112238
+ return " low_priority";
112239
+ case "ignore":
112240
+ return " ignore";
112241
+ case "quick":
112242
+ if (statement === "delete") {
112243
+ return " quick";
112244
+ }
112245
+ break;
112246
+ }
112247
+ throw new Error(statement === "update" ? "lock(...) mode must be lowPriority or ignore for update statements" : "lock(...) mode must be lowPriority, quick, or ignore for delete statements");
112248
+ };
111546
112249
  var makeDslPlanRuntime = (ctx) => {
112250
+ const aliasedSourceKinds = new Set(["derived", "cte", "lateral", "values", "unnest", "tableFunction"]);
112251
+ const isRecord3 = (value) => typeof value === "object" && value !== null;
112252
+ const isPlan = (value) => isRecord3(value) && (TypeId3 in value);
112253
+ const hasColumnRecord = (value) => isRecord3(value.columns);
112254
+ const sourceRequiredList = (source) => typeof source === "object" && source !== null && ("required" in source) ? ctx.currentRequiredList(source.required) : [];
112255
+ const isAliasedSource = (source) => {
112256
+ if (!isRecord3(source)) {
112257
+ return false;
112258
+ }
112259
+ if (TypeId4 in source) {
112260
+ return true;
112261
+ }
112262
+ if (!("kind" in source) || !("name" in source) || !("baseName" in source)) {
112263
+ return false;
112264
+ }
112265
+ if (typeof source.kind !== "string" || !aliasedSourceKinds.has(source.kind)) {
112266
+ return false;
112267
+ }
112268
+ if (typeof source.name !== "string" || typeof source.baseName !== "string") {
112269
+ return false;
112270
+ }
112271
+ switch (source.kind) {
112272
+ case "derived":
112273
+ case "cte":
112274
+ case "lateral":
112275
+ return isPlan(source.plan) && hasColumnRecord(source);
112276
+ case "values":
112277
+ return Array.isArray(source.rows) && hasColumnRecord(source);
112278
+ case "unnest":
112279
+ return isRecord3(source.arrays) && hasColumnRecord(source);
112280
+ case "tableFunction":
112281
+ return typeof source.functionName === "string" && Array.isArray(source.args) && hasColumnRecord(source);
112282
+ }
112283
+ return false;
112284
+ };
112285
+ const assertAliasedSource = (source, message) => {
112286
+ if (!isAliasedSource(source)) {
112287
+ throw new Error(message);
112288
+ }
112289
+ };
112290
+ const assertPlanComplete = (plan) => {
112291
+ const required = ctx.currentRequiredList(plan[TypeId3].required);
112292
+ if (required.length > 0) {
112293
+ throw new Error(`query references sources that are not yet in scope: ${required.join(", ")}`);
112294
+ }
112295
+ };
112296
+ const assertSourceNameAvailable = (available, sourceName) => {
112297
+ if (sourceName in available) {
112298
+ throw new Error(`query source name is already in scope: ${sourceName}`);
112299
+ }
112300
+ };
112301
+ const assertSelectHasBaseSourceForJoin = (statement, available) => {
112302
+ if (statement === "select" && Object.keys(available).length === 0) {
112303
+ throw new Error("select joins require a from(...) source before joining");
112304
+ }
112305
+ };
112306
+ const supportsJoinSources = (statement) => statement === "select" || statement === "update" || statement === "delete";
112307
+ const assertSetOperandStatement = (plan) => {
112308
+ const statement = ctx.getQueryState(plan).statement;
112309
+ if (statement !== "select" && statement !== "set") {
112310
+ throw new Error("set operator operands only accept select-like query plans");
112311
+ }
112312
+ };
111547
112313
  const buildSetOperation = (kind, all, left, right) => {
112314
+ assertSetOperandStatement(left);
112315
+ assertSetOperandStatement(right);
112316
+ assertPlanComplete(left);
112317
+ assertPlanComplete(right);
111548
112318
  const leftState = left[TypeId3];
111549
112319
  const leftAst = ctx.getAst(left);
111550
112320
  const basePlan = leftAst.kind === "set" ? leftAst.setBase ?? left : left;
@@ -111599,25 +112369,29 @@ var makeDslPlanRuntime = (ctx) => {
111599
112369
  if (currentQuery.statement === "insert") {
111600
112370
  return ctx.attachInsertSource(plan, source);
111601
112371
  }
111602
- if (typeof source !== "object" || source === null || "kind" in source && source.kind === "values" && !("name" in source) || !(TypeId4 in source) && !(("name" in source) && ("baseName" in source))) {
111603
- throw new Error("from(...) requires an aliased source in select/update statements");
112372
+ assertAliasedSource(source, "from(...) requires an aliased source in select/update statements");
112373
+ if (currentQuery.statement === "select" && currentAst.from !== undefined) {
112374
+ throw new Error("select statements accept only one from(...) source; use joins for additional sources");
111604
112375
  }
111605
112376
  const sourceLike = source;
111606
112377
  const { sourceName, sourceBaseName } = ctx.sourceDetails(sourceLike);
111607
112378
  const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(sourceLike);
112379
+ const sourceRequired = sourceRequiredList(sourceLike);
112380
+ assertSourceNameAvailable(current.available, sourceName);
111608
112381
  if (currentQuery.statement === "select") {
112382
+ const nextAvailable = {
112383
+ [sourceName]: {
112384
+ name: sourceName,
112385
+ mode: "required",
112386
+ baseName: sourceBaseName,
112387
+ _presentFormula: ctx.trueFormula(),
112388
+ _presenceWitnesses: presenceWitnesses
112389
+ }
112390
+ };
111609
112391
  return ctx.makePlan({
111610
112392
  selection: current.selection,
111611
- required: ctx.currentRequiredList(current.required).filter((name) => name !== sourceName),
111612
- available: {
111613
- [sourceName]: {
111614
- name: sourceName,
111615
- mode: "required",
111616
- baseName: sourceBaseName,
111617
- _presentFormula: ctx.trueFormula(),
111618
- _presenceWitnesses: presenceWitnesses
111619
- }
111620
- },
112393
+ required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index4, values) => !(name in nextAvailable) && values.indexOf(name) === index4),
112394
+ available: nextAvailable,
111621
112395
  dialect: current.dialect
111622
112396
  }, {
111623
112397
  ...currentAst,
@@ -111642,7 +112416,7 @@ var makeDslPlanRuntime = (ctx) => {
111642
112416
  };
111643
112417
  return ctx.makePlan({
111644
112418
  selection: current.selection,
111645
- required: ctx.currentRequiredList(current.required).filter((name) => !(name in nextAvailable)),
112419
+ required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index4, values) => !(name in nextAvailable) && values.indexOf(name) === index4),
111646
112420
  available: nextAvailable,
111647
112421
  dialect: current.dialect
111648
112422
  }, {
@@ -111683,8 +112457,16 @@ var makeDslPlanRuntime = (ctx) => {
111683
112457
  const current = plan[TypeId3];
111684
112458
  const currentAst = ctx.getAst(plan);
111685
112459
  const currentQuery = ctx.getQueryState(plan);
112460
+ if (supportsJoinSources(currentQuery.statement)) {
112461
+ assertAliasedSource(table, "join(...) requires an aliased source in select/update/delete statements");
112462
+ assertSelectHasBaseSourceForJoin(currentQuery.statement, current.available);
112463
+ }
111686
112464
  const { sourceName, sourceBaseName } = ctx.sourceDetails(table);
111687
112465
  const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table);
112466
+ const sourceRequired = sourceRequiredList(table);
112467
+ if (supportsJoinSources(currentQuery.statement)) {
112468
+ assertSourceNameAvailable(current.available, sourceName);
112469
+ }
111688
112470
  const nextAvailable = {
111689
112471
  ...current.available,
111690
112472
  [sourceName]: {
@@ -111697,7 +112479,7 @@ var makeDslPlanRuntime = (ctx) => {
111697
112479
  };
111698
112480
  return ctx.makePlan({
111699
112481
  selection: current.selection,
111700
- required: ctx.currentRequiredList(current.required).filter((name) => !(name in nextAvailable)),
112482
+ required: [...ctx.currentRequiredList(current.required), ...sourceRequired].filter((name, index4, values) => !(name in nextAvailable) && values.indexOf(name) === index4),
111701
112483
  available: nextAvailable,
111702
112484
  dialect: current.dialect ?? table[TypeId3]?.dialect ?? table.dialect
111703
112485
  }, {
@@ -111716,8 +112498,16 @@ var makeDslPlanRuntime = (ctx) => {
111716
112498
  const currentQuery = ctx.getQueryState(plan);
111717
112499
  const onExpression = ctx.toDialectExpression(on);
111718
112500
  const onFormula = ctx.formulaOfExpressionRuntime(onExpression);
112501
+ if (supportsJoinSources(currentQuery.statement)) {
112502
+ assertAliasedSource(table, "join(...) requires an aliased source in select/update/delete statements");
112503
+ assertSelectHasBaseSourceForJoin(currentQuery.statement, current.available);
112504
+ }
111719
112505
  const { sourceName, sourceBaseName } = ctx.sourceDetails(table);
111720
112506
  const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table);
112507
+ const sourceRequired = sourceRequiredList(table);
112508
+ if (supportsJoinSources(currentQuery.statement)) {
112509
+ assertSourceNameAvailable(current.available, sourceName);
112510
+ }
111721
112511
  const baseAvailable = kind === "right" || kind === "full" ? Object.fromEntries(Object.entries(current.available).map(([name, source]) => [name, {
111722
112512
  name: source.name,
111723
112513
  mode: "optional",
@@ -111737,7 +112527,7 @@ var makeDslPlanRuntime = (ctx) => {
111737
112527
  };
111738
112528
  return ctx.makePlan({
111739
112529
  selection: current.selection,
111740
- required: [...ctx.currentRequiredList(current.required), ...ctx.extractRequiredFromDialectInputRuntime(on)].filter((name, index4, values) => !(name in nextAvailable) && values.indexOf(name) === index4),
112530
+ required: [...ctx.currentRequiredList(current.required), ...sourceRequired, ...ctx.extractRequiredFromDialectInputRuntime(on)].filter((name, index4, values) => !(name in nextAvailable) && values.indexOf(name) === index4),
111741
112531
  available: nextAvailable,
111742
112532
  dialect: current.dialect ?? table.dialect ?? onExpression[TypeId].dialect
111743
112533
  }, {
@@ -111752,6 +112542,9 @@ var makeDslPlanRuntime = (ctx) => {
111752
112542
  }, kind === "inner" ? ctx.assumeFormulaTrue(currentQuery.assumptions, onFormula) : currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
111753
112543
  };
111754
112544
  const orderBy = (value, direction = "asc") => (plan) => {
112545
+ if (direction !== "asc" && direction !== "desc") {
112546
+ throw new Error("orderBy(...) direction must be asc or desc");
112547
+ }
111755
112548
  const current = plan[TypeId3];
111756
112549
  const currentAst = ctx.getAst(plan);
111757
112550
  const currentQuery = ctx.getQueryState(plan);
@@ -111775,6 +112568,15 @@ var makeDslPlanRuntime = (ctx) => {
111775
112568
  const current = plan[TypeId3];
111776
112569
  const currentAst = ctx.getAst(plan);
111777
112570
  const currentQuery = ctx.getQueryState(plan);
112571
+ if (currentQuery.statement === "select") {
112572
+ renderSelectLockMode(mode);
112573
+ }
112574
+ if (ctx.profile.dialect === "mysql" && currentQuery.statement === "update") {
112575
+ renderMysqlMutationLockMode(mode, "update");
112576
+ }
112577
+ if (ctx.profile.dialect === "mysql" && currentQuery.statement === "delete") {
112578
+ renderMysqlMutationLockMode(mode, "delete");
112579
+ }
111778
112580
  return ctx.makePlan({
111779
112581
  selection: current.selection,
111780
112582
  required: current.required,
@@ -111851,18 +112653,96 @@ var makeDslPlanRuntime = (ctx) => {
111851
112653
  };
111852
112654
  };
111853
112655
 
112656
+ // src/internal/projection-alias.ts
112657
+ var TypeId7 = Symbol.for("effect-qb/ProjectionAlias");
112658
+
112659
+ // src/internal/projections.ts
112660
+ var aliasFromPath = (path2) => path2.join("__");
112661
+ var isExpression2 = (value) => typeof value === "object" && value !== null && (TypeId in value);
112662
+ var projectionAliasOf = (expression) => (TypeId7 in expression) ? expression[TypeId7].alias : undefined;
112663
+ var pathKeyOf = (path2) => JSON.stringify(path2);
112664
+ var formatProjectionPath = (path2) => path2.join(".");
112665
+ var isPrefixPath = (left, right) => left.length < right.length && left.every((segment, index4) => segment === right[index4]);
112666
+ var flattenSelection = (selection, path2 = []) => {
112667
+ const fields2 = [];
112668
+ for (const [key2, value] of Object.entries(selection)) {
112669
+ const nextPath = [...path2, key2];
112670
+ if (isExpression2(value)) {
112671
+ fields2.push({
112672
+ path: nextPath,
112673
+ expression: value,
112674
+ alias: projectionAliasOf(value) ?? aliasFromPath(nextPath)
112675
+ });
112676
+ continue;
112677
+ }
112678
+ fields2.push(...flattenSelection(value, nextPath));
112679
+ }
112680
+ return fields2;
112681
+ };
112682
+ var validateProjections = (projections) => {
112683
+ const seen = new Set;
112684
+ const pathKeys = new Set;
112685
+ for (const projection of projections) {
112686
+ if (seen.has(projection.alias)) {
112687
+ throw new Error(`Duplicate projection alias: ${projection.alias}`);
112688
+ }
112689
+ seen.add(projection.alias);
112690
+ const pathKey = pathKeyOf(projection.path);
112691
+ if (pathKeys.has(pathKey)) {
112692
+ throw new Error(`Duplicate projection path: ${formatProjectionPath(projection.path)}`);
112693
+ }
112694
+ pathKeys.add(pathKey);
112695
+ }
112696
+ for (let index4 = 0;index4 < projections.length; index4++) {
112697
+ const current = projections[index4];
112698
+ for (let compareIndex = index4 + 1;compareIndex < projections.length; compareIndex++) {
112699
+ const other = projections[compareIndex];
112700
+ if (isPrefixPath(current.path, other.path) || isPrefixPath(other.path, current.path)) {
112701
+ throw new Error(`Conflicting projection paths: ${formatProjectionPath(current.path)} conflicts with ${formatProjectionPath(other.path)}`);
112702
+ }
112703
+ }
112704
+ }
112705
+ };
112706
+
111854
112707
  // src/internal/dsl-query-runtime.ts
111855
112708
  var makeDslQueryRuntime = (ctx) => {
112709
+ const assertSelectionObject = (apiName, selection) => {
112710
+ if (selection === null || typeof selection !== "object" || Array.isArray(selection) || TypeId in selection) {
112711
+ throw new Error(`${apiName}(...) expects a projection object`);
112712
+ }
112713
+ };
112714
+ const assertSelectionTree = (apiName, selection) => {
112715
+ const visit = (value, isRoot) => {
112716
+ if (value !== null && typeof value === "object" && TypeId in value) {
112717
+ return;
112718
+ }
112719
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
112720
+ throw new Error(`${apiName}(...) selection leaves must be expressions`);
112721
+ }
112722
+ const nested = Object.values(value);
112723
+ if (!isRoot && nested.length === 0) {
112724
+ throw new Error(`${apiName}(...) projection objects cannot contain empty nested selections`);
112725
+ }
112726
+ for (const item of nested) {
112727
+ visit(item, false);
112728
+ }
112729
+ };
112730
+ visit(selection, true);
112731
+ };
111856
112732
  const values = (rows) => {
111857
112733
  if (rows.length === 0) {
111858
112734
  throw new Error("values(...) requires at least one row");
111859
112735
  }
111860
112736
  const normalizedRows = rows.map((row) => ctx.normalizeValuesRow(row));
111861
112737
  const columnNames = Object.keys(normalizedRows[0]);
112738
+ if (columnNames.length === 0) {
112739
+ throw new Error("values(...) rows must specify at least one column");
112740
+ }
112741
+ const columnNameSet = new Set(columnNames);
111862
112742
  for (const row of normalizedRows) {
111863
112743
  const rowKeys = Object.keys(row);
111864
- if (rowKeys.length !== columnNames.length || !rowKeys.every((key2, index4) => key2 === columnNames[index4])) {
111865
- throw new Error("values(...) rows must project the same columns in the same order");
112744
+ if (rowKeys.length !== columnNames.length || !rowKeys.every((key2) => columnNameSet.has(key2))) {
112745
+ throw new Error("values(...) rows must project the same columns");
111866
112746
  }
111867
112747
  }
111868
112748
  return Object.assign(Object.create(ctx.ValuesInputProto), {
@@ -111921,21 +112801,28 @@ var makeDslQueryRuntime = (ctx) => {
111921
112801
  };
111922
112802
  return Object.assign(source, columns);
111923
112803
  };
111924
- const select = (selection) => ctx.makePlan({
111925
- selection,
111926
- required: ctx.extractRequiredRuntime(selection),
111927
- available: {},
111928
- dialect: ctx.profile.dialect
111929
- }, {
111930
- kind: "select",
111931
- select: selection,
111932
- where: [],
111933
- having: [],
111934
- joins: [],
111935
- groupBy: [],
111936
- orderBy: []
111937
- }, undefined, "read", "select");
112804
+ const select = (selection = {}) => {
112805
+ assertSelectionObject("select", selection);
112806
+ assertSelectionTree("select", selection);
112807
+ return ctx.makePlan({
112808
+ selection,
112809
+ required: ctx.extractRequiredRuntime(selection),
112810
+ available: {},
112811
+ dialect: ctx.profile.dialect
112812
+ }, {
112813
+ kind: "select",
112814
+ select: selection,
112815
+ where: [],
112816
+ having: [],
112817
+ joins: [],
112818
+ groupBy: [],
112819
+ orderBy: []
112820
+ }, undefined, "read", "select");
112821
+ };
111938
112822
  const groupBy = (...values2) => (plan) => {
112823
+ if (values2.length === 0) {
112824
+ throw new Error("groupBy(...) requires at least one expression");
112825
+ }
111939
112826
  const current = plan[TypeId3];
111940
112827
  const currentAst = ctx.getAst(plan);
111941
112828
  const currentQuery = ctx.getQueryState(plan);
@@ -111950,19 +112837,29 @@ var makeDslQueryRuntime = (ctx) => {
111950
112837
  groupBy: ctx.dedupeGroupedExpressions([...currentAst.groupBy, ...values2])
111951
112838
  }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement);
111952
112839
  };
111953
- const returning = (selection) => (plan) => {
111954
- const current = plan[TypeId3];
111955
- const currentAst = ctx.getAst(plan);
111956
- const currentQuery = ctx.getQueryState(plan);
111957
- return ctx.makePlan({
111958
- selection,
111959
- required: [...ctx.currentRequiredList(current.required), ...ctx.extractRequiredRuntime(selection)].filter((name, index4, list) => !(name in current.available) && list.indexOf(name) === index4),
111960
- available: current.available,
111961
- dialect: current.dialect
111962
- }, {
111963
- ...currentAst,
111964
- select: selection
111965
- }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, currentQuery.insertSource);
112840
+ const returning = (selection) => {
112841
+ assertSelectionObject("returning", selection);
112842
+ assertSelectionTree("returning", selection);
112843
+ if (flattenSelection(selection).length === 0) {
112844
+ throw new Error("returning(...) requires at least one selected expression");
112845
+ }
112846
+ return (plan) => {
112847
+ const current = plan[TypeId3];
112848
+ const currentAst = ctx.getAst(plan);
112849
+ const currentQuery = ctx.getQueryState(plan);
112850
+ if (currentQuery.statement !== "insert" && currentQuery.statement !== "update" && currentQuery.statement !== "delete") {
112851
+ throw new Error(`returning(...) is not supported for ${currentQuery.statement} statements`);
112852
+ }
112853
+ return ctx.makePlan({
112854
+ selection,
112855
+ required: [...ctx.currentRequiredList(current.required), ...ctx.extractRequiredRuntime(selection)].filter((name, index4, list) => !(name in current.available) && list.indexOf(name) === index4),
112856
+ available: current.available,
112857
+ dialect: current.dialect
112858
+ }, {
112859
+ ...currentAst,
112860
+ select: selection
112861
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, currentQuery.insertSource);
112862
+ };
111966
112863
  };
111967
112864
  return {
111968
112865
  values,
@@ -111975,26 +112872,71 @@ var makeDslQueryRuntime = (ctx) => {
111975
112872
  };
111976
112873
 
111977
112874
  // src/internal/dsl-transaction-ddl-runtime.ts
112875
+ var allowedIsolationLevels = new Set(["read committed", "repeatable read", "serializable"]);
112876
+ var renderTransactionIsolationLevel = (isolationLevel) => {
112877
+ if (isolationLevel === undefined) {
112878
+ return "";
112879
+ }
112880
+ if (typeof isolationLevel !== "string" || !allowedIsolationLevels.has(isolationLevel)) {
112881
+ throw new Error("Unsupported transaction isolation level");
112882
+ }
112883
+ return `isolation level ${isolationLevel}`;
112884
+ };
112885
+ var expectDdlClauseKind = (ddl, kind) => {
112886
+ if (ddl === undefined || ddl.kind !== kind) {
112887
+ throw new Error("Unsupported DDL statement kind");
112888
+ }
112889
+ return ddl;
112890
+ };
112891
+ var expectTruncateClause = (truncate) => {
112892
+ if (truncate === undefined || truncate.kind !== "truncate") {
112893
+ throw new Error("Unsupported truncate statement kind");
112894
+ }
112895
+ return truncate;
112896
+ };
112897
+ var validateIsolationLevel = (isolationLevel) => {
112898
+ renderTransactionIsolationLevel(isolationLevel);
112899
+ };
111978
112900
  var makeDslTransactionDdlRuntime = (ctx) => {
111979
- const transaction = (options2 = {}) => ctx.makePlan({
111980
- selection: {},
111981
- required: [],
111982
- available: {},
111983
- dialect: ctx.profile.dialect
111984
- }, {
111985
- kind: "transaction",
111986
- select: {},
111987
- transaction: {
112901
+ const isRecord3 = (value) => typeof value === "object" && value !== null;
112902
+ const assertTableTarget = (target, apiName) => {
112903
+ if (!isRecord3(target) || !(TypeId4 in target) || !(TypeId3 in target)) {
112904
+ throw new Error(`${apiName}(...) requires a table target`);
112905
+ }
112906
+ };
112907
+ const validateIndexColumns = (target, columns) => {
112908
+ const fields2 = target[TypeId4]?.fields;
112909
+ if (fields2 === undefined) {
112910
+ return;
112911
+ }
112912
+ for (const columnName of columns) {
112913
+ if (!(columnName in fields2)) {
112914
+ throw new Error(`effect-qb: unknown index column '${columnName}'`);
112915
+ }
112916
+ }
112917
+ };
112918
+ const transaction = (options2 = {}) => {
112919
+ validateIsolationLevel(options2.isolationLevel);
112920
+ return ctx.makePlan({
112921
+ selection: {},
112922
+ required: [],
112923
+ available: {},
112924
+ dialect: ctx.profile.dialect
112925
+ }, {
111988
112926
  kind: "transaction",
111989
- isolationLevel: options2.isolationLevel,
111990
- readOnly: options2.readOnly
111991
- },
111992
- where: [],
111993
- having: [],
111994
- joins: [],
111995
- groupBy: [],
111996
- orderBy: []
111997
- }, undefined, "transaction", "transaction");
112927
+ select: {},
112928
+ transaction: {
112929
+ kind: "transaction",
112930
+ isolationLevel: options2.isolationLevel,
112931
+ readOnly: options2.readOnly
112932
+ },
112933
+ where: [],
112934
+ having: [],
112935
+ joins: [],
112936
+ groupBy: [],
112937
+ orderBy: []
112938
+ }, undefined, "transaction", "transaction");
112939
+ };
111998
112940
  const commit = () => ctx.makePlan({
111999
112941
  selection: {},
112000
112942
  required: [],
@@ -112084,6 +113026,7 @@ var makeDslTransactionDdlRuntime = (ctx) => {
112084
113026
  orderBy: []
112085
113027
  }, undefined, "transaction", "releaseSavepoint");
112086
113028
  const createTable = (target, options2 = {}) => {
113029
+ assertTableTarget(target, "createTable");
112087
113030
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
112088
113031
  return ctx.makePlan({
112089
113032
  selection: {},
@@ -112111,6 +113054,7 @@ var makeDslTransactionDdlRuntime = (ctx) => {
112111
113054
  }, undefined, "ddl", "createTable");
112112
113055
  };
112113
113056
  const dropTable = (target, options2 = {}) => {
113057
+ assertTableTarget(target, "dropTable");
112114
113058
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
112115
113059
  return ctx.makePlan({
112116
113060
  selection: {},
@@ -112138,7 +113082,9 @@ var makeDslTransactionDdlRuntime = (ctx) => {
112138
113082
  }, undefined, "ddl", "dropTable");
112139
113083
  };
112140
113084
  const createIndex = (target, columns, options2 = {}) => {
113085
+ assertTableTarget(target, "createIndex");
112141
113086
  const normalizedColumns = ctx.normalizeColumnList(columns);
113087
+ validateIndexColumns(target, normalizedColumns);
112142
113088
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
112143
113089
  return ctx.makePlan({
112144
113090
  selection: {},
@@ -112169,7 +113115,9 @@ var makeDslTransactionDdlRuntime = (ctx) => {
112169
113115
  }, undefined, "ddl", "createIndex");
112170
113116
  };
112171
113117
  const dropIndex = (target, columns, options2 = {}) => {
113118
+ assertTableTarget(target, "dropIndex");
112172
113119
  const normalizedColumns = ctx.normalizeColumnList(columns);
113120
+ validateIndexColumns(target, normalizedColumns);
112173
113121
  const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target);
112174
113122
  return ctx.makePlan({
112175
113123
  selection: {},
@@ -112213,59 +113161,6 @@ var makeDslTransactionDdlRuntime = (ctx) => {
112213
113161
 
112214
113162
  // src/internal/derived-table.ts
112215
113163
  import { pipeArguments as pipeArguments4 } from "effect/Pipeable";
112216
-
112217
- // src/internal/projection-alias.ts
112218
- var TypeId7 = Symbol.for("effect-qb/ProjectionAlias");
112219
-
112220
- // src/internal/projections.ts
112221
- var aliasFromPath = (path2) => path2.join("__");
112222
- var isExpression = (value) => typeof value === "object" && value !== null && (TypeId in value);
112223
- var projectionAliasOf = (expression) => (TypeId7 in expression) ? expression[TypeId7].alias : undefined;
112224
- var pathKeyOf = (path2) => JSON.stringify(path2);
112225
- var formatProjectionPath = (path2) => path2.join(".");
112226
- var isPrefixPath = (left, right) => left.length < right.length && left.every((segment, index4) => segment === right[index4]);
112227
- var flattenSelection = (selection, path2 = []) => {
112228
- const fields2 = [];
112229
- for (const [key2, value] of Object.entries(selection)) {
112230
- const nextPath = [...path2, key2];
112231
- if (isExpression(value)) {
112232
- fields2.push({
112233
- path: nextPath,
112234
- expression: value,
112235
- alias: projectionAliasOf(value) ?? aliasFromPath(nextPath)
112236
- });
112237
- continue;
112238
- }
112239
- fields2.push(...flattenSelection(value, nextPath));
112240
- }
112241
- return fields2;
112242
- };
112243
- var validateProjections = (projections) => {
112244
- const seen = new Set;
112245
- const pathKeys = new Set;
112246
- for (const projection of projections) {
112247
- if (seen.has(projection.alias)) {
112248
- throw new Error(`Duplicate projection alias: ${projection.alias}`);
112249
- }
112250
- seen.add(projection.alias);
112251
- const pathKey = pathKeyOf(projection.path);
112252
- if (pathKeys.has(pathKey)) {
112253
- throw new Error(`Duplicate projection path: ${formatProjectionPath(projection.path)}`);
112254
- }
112255
- pathKeys.add(pathKey);
112256
- }
112257
- for (let index4 = 0;index4 < projections.length; index4++) {
112258
- const current = projections[index4];
112259
- for (let compareIndex = index4 + 1;compareIndex < projections.length; compareIndex++) {
112260
- const other = projections[compareIndex];
112261
- if (isPrefixPath(current.path, other.path) || isPrefixPath(other.path, current.path)) {
112262
- throw new Error(`Conflicting projection paths: ${formatProjectionPath(current.path)} conflicts with ${formatProjectionPath(other.path)}`);
112263
- }
112264
- }
112265
- }
112266
- };
112267
-
112268
- // src/internal/derived-table.ts
112269
113164
  var DerivedProto = {
112270
113165
  pipe() {
112271
113166
  return pipeArguments4(this, arguments);
@@ -112297,10 +113192,24 @@ var setPath = (target, path2, value) => {
112297
113192
  current[path2[path2.length - 1]] = value;
112298
113193
  };
112299
113194
  var pathAlias = (path2) => path2.join("__");
113195
+ var assertSourceComplete = (plan) => {
113196
+ const required = currentRequiredList(plan[TypeId3].required);
113197
+ if (required.length > 0) {
113198
+ throw new Error(`query references sources that are not yet in scope: ${required.join(", ")}`);
113199
+ }
113200
+ };
113201
+ var assertInlineSourceStatement = (plan) => {
113202
+ const statement = getQueryState(plan).statement;
113203
+ if (statement !== "select" && statement !== "set") {
113204
+ throw new Error("inline derived sources only accept select-like query plans");
113205
+ }
113206
+ };
112300
113207
  var reboundedColumns = (plan, alias2) => {
112301
113208
  const ast = getAst(plan);
112302
113209
  const selection = {};
112303
- for (const projection of flattenSelection(ast.select)) {
113210
+ const projections = flattenSelection(ast.select);
113211
+ validateProjections(projections);
113212
+ for (const projection of projections) {
112304
113213
  const expectedAlias = pathAlias(projection.path);
112305
113214
  if (projection.alias !== expectedAlias) {
112306
113215
  throw new Error(`Derived subqueries currently require path-based output aliases; expected '${expectedAlias}' for path '${projection.path.join(".")}'`);
@@ -112325,6 +113234,8 @@ var reboundedColumns = (plan, alias2) => {
112325
113234
  return selection;
112326
113235
  };
112327
113236
  var makeDerivedSource = (plan, alias2) => {
113237
+ assertInlineSourceStatement(plan);
113238
+ assertSourceComplete(plan);
112328
113239
  const columns = reboundedColumns(plan, alias2);
112329
113240
  const derived = attachPipe3(Object.create(DerivedProto));
112330
113241
  Object.assign(derived, columns);
@@ -112338,6 +113249,7 @@ var makeDerivedSource = (plan, alias2) => {
112338
113249
  return derived;
112339
113250
  };
112340
113251
  var makeCteSource = (plan, alias2, recursive = false) => {
113252
+ assertSourceComplete(plan);
112341
113253
  const columns = reboundedColumns(plan, alias2);
112342
113254
  const cte = attachPipe3(Object.create(DerivedProto));
112343
113255
  Object.assign(cte, columns);
@@ -112352,6 +113264,7 @@ var makeCteSource = (plan, alias2, recursive = false) => {
112352
113264
  return cte;
112353
113265
  };
112354
113266
  var makeLateralSource = (plan, alias2) => {
113267
+ assertInlineSourceStatement(plan);
112355
113268
  const columns = reboundedColumns(plan, alias2);
112356
113269
  const lateral = attachPipe3(Object.create(DerivedProto));
112357
113270
  Object.assign(lateral, columns);
@@ -112360,7 +113273,7 @@ var makeLateralSource = (plan, alias2) => {
112360
113273
  lateral.baseName = alias2;
112361
113274
  lateral.dialect = plan[TypeId3].dialect;
112362
113275
  lateral.plan = plan;
112363
- lateral.required = undefined;
113276
+ lateral.required = currentRequiredList(plan[TypeId3].required);
112364
113277
  lateral.columns = columns;
112365
113278
  return lateral;
112366
113279
  };
@@ -112504,10 +113417,16 @@ var extractRequiredFromDialectInputRuntime = (value) => {
112504
113417
  };
112505
113418
  var normalizeWindowSpec = (spec) => {
112506
113419
  const partitionBy = [...spec?.partitionBy ?? []];
112507
- const orderBy = (spec?.orderBy ?? []).map((term) => ({
112508
- value: term.value,
112509
- direction: term.direction ?? "asc"
112510
- }));
113420
+ const orderBy = (spec?.orderBy ?? []).map((term) => {
113421
+ const direction = term.direction ?? "asc";
113422
+ if (direction !== "asc" && direction !== "desc") {
113423
+ throw new Error("window order direction must be asc or desc");
113424
+ }
113425
+ return {
113426
+ value: term.value,
113427
+ direction
113428
+ };
113429
+ });
112511
113430
  return {
112512
113431
  partitionBy,
112513
113432
  orderBy
@@ -113485,21 +114404,52 @@ var excluded = (value) => {
113485
114404
  });
113486
114405
  };
113487
114406
  var toMutationValueExpression = (value, column2) => {
114407
+ const columnState = column2[TypeId];
114408
+ const normalizeMutationValue = (candidate) => {
114409
+ if (candidate === null && columnState.nullability !== "never") {
114410
+ return null;
114411
+ }
114412
+ const runtimeSchemaAccepts = columnState.runtimeSchema !== undefined && Schema6.is(columnState.runtimeSchema)(candidate);
114413
+ if (runtimeSchemaAccepts) {
114414
+ return candidate;
114415
+ }
114416
+ const normalized = normalizeDbValue(columnState.dbType, candidate);
114417
+ return columnState.runtimeSchema === undefined ? normalized : Schema6.decodeUnknownSync(columnState.runtimeSchema)(normalized);
114418
+ };
113488
114419
  if (value !== null && typeof value === "object" && TypeId in value) {
114420
+ const expression = value;
114421
+ const ast = expression[TypeId2];
114422
+ if (ast.kind === "literal") {
114423
+ const normalizedValue2 = normalizeMutationValue(ast.value);
114424
+ return makeExpression({
114425
+ runtime: normalizedValue2,
114426
+ dbType: columnState.dbType,
114427
+ runtimeSchema: columnState.runtimeSchema,
114428
+ driverValueMapping: columnState.driverValueMapping,
114429
+ nullability: normalizedValue2 === null ? "always" : "never",
114430
+ dialect: columnState.dialect,
114431
+ kind: "scalar",
114432
+ dependencies: {}
114433
+ }, {
114434
+ kind: "literal",
114435
+ value: normalizedValue2
114436
+ });
114437
+ }
113489
114438
  return retargetLiteralExpression(value, column2);
113490
114439
  }
114440
+ const normalizedValue = normalizeMutationValue(value);
113491
114441
  return makeExpression({
113492
- runtime: value,
113493
- dbType: column2[TypeId].dbType,
113494
- runtimeSchema: column2[TypeId].runtimeSchema,
113495
- driverValueMapping: column2[TypeId].driverValueMapping,
113496
- nullability: value === null ? "always" : "never",
113497
- dialect: column2[TypeId].dialect,
114442
+ runtime: normalizedValue,
114443
+ dbType: columnState.dbType,
114444
+ runtimeSchema: columnState.runtimeSchema,
114445
+ driverValueMapping: columnState.driverValueMapping,
114446
+ nullability: normalizedValue === null ? "always" : "never",
114447
+ dialect: columnState.dialect,
113498
114448
  kind: "scalar",
113499
114449
  dependencies: {}
113500
114450
  }, {
113501
114451
  kind: "literal",
113502
- value
114452
+ value: normalizedValue
113503
114453
  });
113504
114454
  };
113505
114455
  var renderQuantifiedComparisonAst = (left, plan, operator, quantifier) => ({
@@ -113562,7 +114512,12 @@ var makeAliasedValuesSource = (rows, selection, alias2) => {
113562
114512
  return Object.assign(source, columns);
113563
114513
  };
113564
114514
  var normalizeValuesRow = (row) => Object.fromEntries(Object.entries(row).map(([key2, value]) => [key2, toDialectExpression(value)]));
113565
- var normalizeUnnestColumns = (columns) => Object.fromEntries(Object.entries(columns).map(([key2, values]) => [key2, values.map((value) => toDialectExpression(value))]));
114515
+ var normalizeUnnestColumns = (columns) => Object.fromEntries(Object.entries(columns).map(([key2, values]) => {
114516
+ if (!Array.isArray(values)) {
114517
+ throw new Error("unnest(...) expects every value to be an array");
114518
+ }
114519
+ return [key2, values.map((value) => toDialectExpression(value))];
114520
+ }));
113566
114521
  var normalizeMutationTargets = (target) => Array.isArray(target) ? target : [target];
113567
114522
  var mutationTargetClauses = (target) => normalizeMutationTargets(target).map((table) => {
113568
114523
  const { sourceName, sourceBaseName } = targetSourceDetails(table);
@@ -113584,13 +114539,20 @@ var mutationAvailableSources = (target, mode = "required") => Object.fromEntries
113584
114539
  }
113585
114540
  ];
113586
114541
  }));
114542
+ var getMutationColumn = (columns, columnName) => {
114543
+ const column2 = columns[columnName];
114544
+ if (column2 === undefined || column2 === null || typeof column2 !== "object" || !(TypeId in column2)) {
114545
+ throw new Error("effect-qb: unknown mutation column");
114546
+ }
114547
+ return column2;
114548
+ };
113587
114549
  var buildMutationAssignments = (target, values) => {
113588
114550
  const targets = normalizeMutationTargets(target);
113589
114551
  if (targets.length === 1 && !Array.isArray(target)) {
113590
114552
  const columns = target;
113591
114553
  return Object.entries(values).map(([columnName, value]) => ({
113592
114554
  columnName,
113593
- value: toMutationValueExpression(value, columns[columnName])
114555
+ value: toMutationValueExpression(value, getMutationColumn(columns, columnName))
113594
114556
  }));
113595
114557
  }
113596
114558
  const valueMap = values;
@@ -113601,7 +114563,7 @@ var buildMutationAssignments = (target, values) => {
113601
114563
  return Object.entries(scopedValues).map(([columnName, value]) => ({
113602
114564
  tableName: targetName,
113603
114565
  columnName,
113604
- value: toMutationValueExpression(value, columns[columnName])
114566
+ value: toMutationValueExpression(value, getMutationColumn(columns, columnName))
113605
114567
  }));
113606
114568
  });
113607
114569
  };
@@ -113664,25 +114626,22 @@ var normalizeInsertUnnestValues = (target, values) => {
113664
114626
  values: normalized
113665
114627
  };
113666
114628
  };
114629
+ var normalizeConflictColumns = (target, columnsInput) => {
114630
+ const columns = normalizeColumnList(columnsInput);
114631
+ const knownColumns = new Set(Object.keys(target[TypeId4].fields));
114632
+ if (columns.some((columnName) => !knownColumns.has(columnName))) {
114633
+ throw new Error("effect-qb: unknown conflict target column");
114634
+ }
114635
+ return columns;
114636
+ };
113667
114637
  var buildConflictTarget = (target, input) => {
113668
- if (Array.isArray(input)) {
114638
+ if (typeof input === "string" || Array.isArray(input)) {
113669
114639
  return {
113670
114640
  kind: "columns",
113671
- columns: normalizeColumnList(input)
113672
- };
113673
- }
113674
- if (!Array.isArray(input) && "constraint" in input) {
113675
- return {
113676
- kind: "constraint",
113677
- name: input.constraint
114641
+ columns: normalizeConflictColumns(target, input)
113678
114642
  };
113679
114643
  }
113680
- const columnTarget = input;
113681
- return {
113682
- kind: "columns",
113683
- columns: normalizeColumnList(columnTarget.columns),
113684
- where: columnTarget.where === undefined ? undefined : toDialectExpression(columnTarget.where)
113685
- };
114644
+ throw new Error("Unsupported mysql conflict target");
113686
114645
  };
113687
114646
  var defaultIndexName = (tableName, columns, unique4) => `${tableName}_${columns.join("_")}_${unique4 ? "uniq" : "idx"}`;
113688
114647
  function as(valueOrAlias, alias2) {
@@ -113795,6 +114754,7 @@ var distinctOn = {
113795
114754
  __effect_qb_hint__: "Use postgres.Query.distinctOn(...) or regular distinct()/grouping logic"
113796
114755
  };
113797
114756
  var mutationRuntime = makeDslMutationRuntime({
114757
+ profile,
113798
114758
  makePlan,
113799
114759
  getAst,
113800
114760
  getQueryState,
@@ -113807,7 +114767,7 @@ var mutationRuntime = makeDslMutationRuntime({
113807
114767
  buildConflictTarget,
113808
114768
  mutationTargetClauses,
113809
114769
  mutationAvailableSources,
113810
- normalizeColumnList,
114770
+ normalizeConflictColumns,
113811
114771
  targetSourceDetails,
113812
114772
  sourceDetails
113813
114773
  });
@@ -113818,7 +114778,7 @@ var update = (target, values2) => mutationRuntime.update(target, values2);
113818
114778
  var upsert = (target, values2, conflictColumns, updateValues) => mutationRuntime.upsert(target, values2, conflictColumns, updateValues);
113819
114779
  var delete_ = (target) => mutationRuntime.delete_(target);
113820
114780
  var truncate = (target, options2 = {}) => mutationRuntime.truncate(target, options2);
113821
- var merge = (target, source, on, options2 = {}) => mutationRuntime.merge(target, source, on, options2);
114781
+ var merge = (target, source, on, options2) => mutationRuntime.merge(target, source, on, options2);
113822
114782
  var {
113823
114783
  transaction,
113824
114784
  commit,
@@ -113929,299 +114889,6 @@ import * as Stream from "effect/Stream";
113929
114889
 
113930
114890
  // src/internal/runtime/driver-value-mapping.ts
113931
114891
  import * as Schema7 from "effect/Schema";
113932
-
113933
- // src/internal/runtime/normalize.ts
113934
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
113935
- var pad = (value, width = 2) => value.toString().padStart(width, "0");
113936
- var formatLocalDate = (value) => `${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}`;
113937
- var formatLocalTime = (value) => {
113938
- const milliseconds = value.getUTCMilliseconds();
113939
- const base = `${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}`;
113940
- return milliseconds === 0 ? base : `${base}.${pad(milliseconds, 3)}`;
113941
- };
113942
- var formatLocalDateTime = (value) => {
113943
- const milliseconds = value.getUTCMilliseconds();
113944
- const base = `${formatLocalDate(value)}T${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}`;
113945
- return milliseconds === 0 ? base : `${base}.${pad(milliseconds, 3)}`;
113946
- };
113947
- var runtimeTagOfBaseDbType = (dbType) => {
113948
- return dbType.runtime;
113949
- };
113950
- var expectString = (value, label) => {
113951
- if (typeof value === "string") {
113952
- return value;
113953
- }
113954
- throw new Error(`Expected ${label} as string`);
113955
- };
113956
- var normalizeNumber = (value) => {
113957
- if (typeof value === "number" && Number.isFinite(value)) {
113958
- return value;
113959
- }
113960
- if (typeof value === "string" && value.trim() !== "") {
113961
- const parsed = Number(value);
113962
- if (Number.isFinite(parsed)) {
113963
- return parsed;
113964
- }
113965
- }
113966
- if (typeof value === "bigint" && Number.isSafeInteger(Number(value))) {
113967
- return Number(value);
113968
- }
113969
- throw new Error("Expected a finite numeric value");
113970
- };
113971
- var normalizeBoolean = (value) => {
113972
- if (typeof value === "boolean") {
113973
- return value;
113974
- }
113975
- if (typeof value === "number") {
113976
- if (value === 1) {
113977
- return true;
113978
- }
113979
- if (value === 0) {
113980
- return false;
113981
- }
113982
- }
113983
- if (typeof value === "string") {
113984
- const normalized = value.trim().toLowerCase();
113985
- if (normalized === "true" || normalized === "t" || normalized === "1") {
113986
- return true;
113987
- }
113988
- if (normalized === "false" || normalized === "f" || normalized === "0") {
113989
- return false;
113990
- }
113991
- }
113992
- throw new Error("Expected a boolean-like value");
113993
- };
113994
- var normalizeBigIntString = (value) => {
113995
- if (typeof value === "bigint") {
113996
- return value.toString();
113997
- }
113998
- if (typeof value === "number" && Number.isSafeInteger(value)) {
113999
- return BigInt(value).toString();
114000
- }
114001
- if (typeof value === "string" && /^-?\d+$/.test(value.trim())) {
114002
- return BigInt(value.trim()).toString();
114003
- }
114004
- throw new Error("Expected an integer-like bigint value");
114005
- };
114006
- var canonicalizeDecimalString = (input) => {
114007
- const trimmed = input.trim();
114008
- const match2 = /^([+-]?)(\d+)(?:\.(\d+))?$/.exec(trimmed);
114009
- if (match2 === null) {
114010
- throw new Error("Expected a decimal string");
114011
- }
114012
- const sign = match2[1] === "-" ? "-" : "";
114013
- const integer = match2[2].replace(/^0+(?=\d)/, "") || "0";
114014
- const fraction = (match2[3] ?? "").replace(/0+$/, "");
114015
- if (fraction.length === 0) {
114016
- return `${sign}${integer}`;
114017
- }
114018
- return `${sign}${integer}.${fraction}`;
114019
- };
114020
- var normalizeDecimalString = (value) => {
114021
- if (typeof value === "string") {
114022
- return canonicalizeDecimalString(value);
114023
- }
114024
- if (typeof value === "number" && Number.isFinite(value)) {
114025
- const rendered = String(value);
114026
- if (/[eE]/.test(rendered)) {
114027
- throw new Error("Scientific notation is not a supported decimal runtime");
114028
- }
114029
- return canonicalizeDecimalString(rendered);
114030
- }
114031
- throw new Error("Expected a decimal-like value");
114032
- };
114033
- var normalizeLocalDate = (value) => {
114034
- if (value instanceof Date) {
114035
- return formatLocalDate(value);
114036
- }
114037
- const raw = expectString(value, "local date").trim();
114038
- if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
114039
- return raw;
114040
- }
114041
- const parsed = new Date(raw);
114042
- if (!Number.isNaN(parsed.getTime())) {
114043
- return formatLocalDate(parsed);
114044
- }
114045
- throw new Error("Expected a local-date value");
114046
- };
114047
- var normalizeLocalTime = (value) => {
114048
- if (value instanceof Date) {
114049
- return formatLocalTime(value);
114050
- }
114051
- const raw = expectString(value, "local time").trim();
114052
- if (/^\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(raw)) {
114053
- return raw;
114054
- }
114055
- throw new Error("Expected a local-time value");
114056
- };
114057
- var normalizeOffsetTime = (value) => {
114058
- if (value instanceof Date) {
114059
- return `${formatLocalTime(value)}Z`;
114060
- }
114061
- const raw = expectString(value, "offset time").trim();
114062
- if (/^\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(raw)) {
114063
- return raw;
114064
- }
114065
- throw new Error("Expected an offset-time value");
114066
- };
114067
- var normalizeLocalDateTime = (value) => {
114068
- if (value instanceof Date) {
114069
- return formatLocalDateTime(value);
114070
- }
114071
- const raw = expectString(value, "local datetime").trim();
114072
- if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(raw)) {
114073
- return raw.replace(" ", "T");
114074
- }
114075
- if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(raw)) {
114076
- const parsed = new Date(raw);
114077
- if (!Number.isNaN(parsed.getTime())) {
114078
- return formatLocalDateTime(parsed);
114079
- }
114080
- }
114081
- throw new Error("Expected a local-datetime value");
114082
- };
114083
- var normalizeInstant = (value) => {
114084
- if (value instanceof Date) {
114085
- return value.toISOString();
114086
- }
114087
- const raw = expectString(value, "instant").trim();
114088
- if (!/[zZ]|[+-]\d{2}:\d{2}$/.test(raw)) {
114089
- throw new Error("Instant values require a timezone offset");
114090
- }
114091
- const parsed = new Date(raw);
114092
- if (Number.isNaN(parsed.getTime())) {
114093
- throw new Error("Expected an ISO instant value");
114094
- }
114095
- return parsed.toISOString();
114096
- };
114097
- var normalizeYear = (value) => {
114098
- if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 9999) {
114099
- return pad(value, 4);
114100
- }
114101
- const raw = expectString(value, "year").trim();
114102
- if (/^\d{4}$/.test(raw)) {
114103
- return raw;
114104
- }
114105
- throw new Error("Expected a four-digit year");
114106
- };
114107
- var normalizeBytes = (value) => {
114108
- if (value instanceof Uint8Array) {
114109
- return new Uint8Array(value);
114110
- }
114111
- const BufferConstructor = globalThis.Buffer;
114112
- if (BufferConstructor !== undefined && value instanceof BufferConstructor) {
114113
- return new Uint8Array(value);
114114
- }
114115
- throw new Error("Expected a byte array value");
114116
- };
114117
- var isJsonValue = (value) => {
114118
- if (value === null) {
114119
- return true;
114120
- }
114121
- switch (typeof value) {
114122
- case "string":
114123
- case "number":
114124
- case "boolean":
114125
- return true;
114126
- case "object":
114127
- if (Array.isArray(value)) {
114128
- return value.every(isJsonValue);
114129
- }
114130
- return isRecord2(value) && Object.values(value).every(isJsonValue);
114131
- default:
114132
- return false;
114133
- }
114134
- };
114135
- var normalizeJson = (value) => {
114136
- if (typeof value === "string") {
114137
- const parsed = JSON.parse(value);
114138
- if (isJsonValue(parsed)) {
114139
- return parsed;
114140
- }
114141
- throw new Error("Parsed JSON value is not a valid JSON runtime");
114142
- }
114143
- if (isJsonValue(value)) {
114144
- return value;
114145
- }
114146
- throw new Error("Expected a JSON value");
114147
- };
114148
- var normalizeDbValue = (dbType, value) => {
114149
- if (value === null) {
114150
- return null;
114151
- }
114152
- if ("base" in dbType) {
114153
- return normalizeDbValue(dbType.base, value);
114154
- }
114155
- if ("element" in dbType) {
114156
- if (!Array.isArray(value)) {
114157
- throw new Error("Expected an array value");
114158
- }
114159
- return value.map((entry) => normalizeDbValue(dbType.element, entry));
114160
- }
114161
- if ("fields" in dbType) {
114162
- if (!isRecord2(value)) {
114163
- throw new Error("Expected a record value");
114164
- }
114165
- const normalized = {};
114166
- for (const [key2, fieldDbType] of Object.entries(dbType.fields)) {
114167
- if (key2 in value) {
114168
- normalized[key2] = normalizeDbValue(fieldDbType, value[key2]);
114169
- }
114170
- }
114171
- return normalized;
114172
- }
114173
- if ("variant" in dbType && dbType.variant === "json") {
114174
- return normalizeJson(value);
114175
- }
114176
- if ("variant" in dbType && (dbType.variant === "enum" || dbType.variant === "set")) {
114177
- return expectString(value, "text");
114178
- }
114179
- switch (runtimeTagOfBaseDbType(dbType)) {
114180
- case "string":
114181
- return expectString(value, "text");
114182
- case "number":
114183
- return normalizeNumber(value);
114184
- case "bigintString":
114185
- return normalizeBigIntString(value);
114186
- case "boolean":
114187
- return normalizeBoolean(value);
114188
- case "json":
114189
- return normalizeJson(value);
114190
- case "localDate":
114191
- return normalizeLocalDate(value);
114192
- case "localTime":
114193
- return normalizeLocalTime(value);
114194
- case "offsetTime":
114195
- return normalizeOffsetTime(value);
114196
- case "localDateTime":
114197
- return normalizeLocalDateTime(value);
114198
- case "instant":
114199
- return normalizeInstant(value);
114200
- case "year":
114201
- return normalizeYear(value);
114202
- case "decimalString":
114203
- return normalizeDecimalString(value);
114204
- case "bytes":
114205
- return normalizeBytes(value);
114206
- case "array":
114207
- if (!Array.isArray(value)) {
114208
- throw new Error("Expected an array value");
114209
- }
114210
- return value;
114211
- case "record":
114212
- if (!isRecord2(value)) {
114213
- throw new Error("Expected a record value");
114214
- }
114215
- return value;
114216
- case "null":
114217
- return null;
114218
- case "unknown":
114219
- case undefined:
114220
- return value;
114221
- }
114222
- };
114223
-
114224
- // src/internal/runtime/driver-value-mapping.ts
114225
114892
  var runtimeTagOfDbType = (dbType) => {
114226
114893
  if (dbType === undefined) {
114227
114894
  return;
@@ -114273,6 +114940,20 @@ var findMapping = (context, key2) => {
114273
114940
  }
114274
114941
  return;
114275
114942
  };
114943
+ var isJsonDbType = (dbType) => {
114944
+ if (dbType === undefined) {
114945
+ return false;
114946
+ }
114947
+ if ("base" in dbType) {
114948
+ return isJsonDbType(dbType.base);
114949
+ }
114950
+ if (!("variant" in dbType)) {
114951
+ return false;
114952
+ }
114953
+ const variant = dbType.variant;
114954
+ return variant === "json" || variant === "jsonb";
114955
+ };
114956
+ var schemaAccepts = (schema4, value) => schema4 !== undefined && Schema7.is(schema4)(value);
114276
114957
  var encodeWithSchema = (schema4, value) => {
114277
114958
  if (schema4 === undefined) {
114278
114959
  return { value, encoded: false };
@@ -114285,10 +114966,35 @@ var encodeWithSchema = (schema4, value) => {
114285
114966
  encoded: true
114286
114967
  };
114287
114968
  };
114969
+ var normalizeJsonDriverString = (value, context) => {
114970
+ if (!isJsonDbType(context.dbType) || context.runtimeSchema === undefined) {
114971
+ return;
114972
+ }
114973
+ try {
114974
+ const parsed = JSON.parse(value);
114975
+ if (value.trimStart().startsWith('"') && schemaAccepts(context.runtimeSchema, parsed)) {
114976
+ return parsed;
114977
+ }
114978
+ if (schemaAccepts(context.runtimeSchema, value) && !schemaAccepts(context.runtimeSchema, parsed)) {
114979
+ return value;
114980
+ }
114981
+ } catch (error) {
114982
+ if (error instanceof SyntaxError && schemaAccepts(context.runtimeSchema, value)) {
114983
+ return value;
114984
+ }
114985
+ if (!(error instanceof SyntaxError)) {
114986
+ throw error;
114987
+ }
114988
+ }
114989
+ return;
114990
+ };
114288
114991
  var toDriverValue = (value, context) => {
114289
114992
  if (value === null) {
114290
114993
  return null;
114291
114994
  }
114995
+ if (value instanceof Date && Number.isNaN(value.getTime())) {
114996
+ throw new Error("Expected a valid Date value");
114997
+ }
114292
114998
  const dbType = context.dbType;
114293
114999
  const encoded = encodeWithSchema(context.runtimeSchema, value);
114294
115000
  let current = encoded.value;
@@ -114296,6 +115002,9 @@ var toDriverValue = (value, context) => {
114296
115002
  if (custom3 !== undefined && dbType !== undefined) {
114297
115003
  return custom3(current, dbType);
114298
115004
  }
115005
+ if (encoded.encoded && typeof current === "string" && isJsonDbType(dbType)) {
115006
+ return current;
115007
+ }
114299
115008
  return dbType === undefined || !encoded.encoded ? current : normalizeDbValue(dbType, current);
114300
115009
  };
114301
115010
  var fromDriverValue = (value, context) => {
@@ -114307,6 +115016,12 @@ var fromDriverValue = (value, context) => {
114307
115016
  if (custom3 !== undefined && dbType !== undefined) {
114308
115017
  return custom3(value, dbType);
114309
115018
  }
115019
+ if (typeof value === "string") {
115020
+ const normalizedJsonString = normalizeJsonDriverString(value, context);
115021
+ if (normalizedJsonString !== undefined) {
115022
+ return normalizedJsonString;
115023
+ }
115024
+ }
114310
115025
  return dbType === undefined ? value : normalizeDbValue(dbType, value);
114311
115026
  };
114312
115027
  var textCast = (sql) => `(${sql})::text`;
@@ -114346,12 +115061,13 @@ var renderJsonSelectSql = (sql, context) => {
114346
115061
  import * as Schema8 from "effect/Schema";
114347
115062
  import * as SchemaAST from "effect/SchemaAST";
114348
115063
  var schemaCache = new WeakMap;
115064
+ var FiniteNumberSchema = Schema8.Number.pipe(Schema8.finite());
114349
115065
  var runtimeSchemaForTag = (tag) => {
114350
115066
  switch (tag) {
114351
115067
  case "string":
114352
115068
  return Schema8.String;
114353
115069
  case "number":
114354
- return Schema8.Number;
115070
+ return FiniteNumberSchema;
114355
115071
  case "bigintString":
114356
115072
  return BigIntStringSchema;
114357
115073
  case "boolean":
@@ -114636,7 +115352,7 @@ var deriveRuntimeSchema = (expression, context) => {
114636
115352
  return Schema8.String;
114637
115353
  case "count":
114638
115354
  case "jsonLength":
114639
- return Schema8.Number;
115355
+ return FiniteNumberSchema;
114640
115356
  case "max":
114641
115357
  case "min":
114642
115358
  return expressionRuntimeSchema(ast.value, context);
@@ -114649,7 +115365,7 @@ var deriveRuntimeSchema = (expression, context) => {
114649
115365
  return selection === undefined ? undefined : expressionRuntimeSchema(selection, context);
114650
115366
  }
114651
115367
  case "window":
114652
- return ast.function === "over" && ast.value !== undefined ? expressionRuntimeSchema(ast.value, context) : Schema8.Number;
115368
+ return ast.function === "over" && ast.value !== undefined ? expressionRuntimeSchema(ast.value, context) : FiniteNumberSchema;
114653
115369
  case "jsonGet":
114654
115370
  case "jsonPath":
114655
115371
  case "jsonAccess":
@@ -114771,7 +115487,7 @@ var effectiveRuntimeNullability = (expression, scope) => {
114771
115487
  return "always";
114772
115488
  }
114773
115489
  if (ast.kind === "column") {
114774
- const key2 = `${ast.tableName}.${ast.columnName}`;
115490
+ const key2 = columnPredicateKey(ast.tableName, ast.columnName);
114775
115491
  if (scope.absentSourceNames.has(ast.tableName) || scope.nullKeys.has(key2)) {
114776
115492
  return "always";
114777
115493
  }
@@ -114784,6 +115500,13 @@ var effectiveRuntimeNullability = (expression, scope) => {
114784
115500
  }
114785
115501
  return hasOptionalSourceDependency(expression, scope) ? "maybe" : nullability;
114786
115502
  };
115503
+ var dbTypeAllowsTopLevelJsonNull = (dbType) => {
115504
+ if ("base" in dbType) {
115505
+ return dbTypeAllowsTopLevelJsonNull(dbType.base);
115506
+ }
115507
+ return "variant" in dbType && dbType.variant === "json" || dbType.runtime === "json";
115508
+ };
115509
+ var schemaAcceptsNull = (schema4) => schema4 !== undefined && Schema9.is(schema4)(null);
114787
115510
  var decodeProjectionValue = (rendered, projection, expression, raw, scope, driverMode, valueMappings) => {
114788
115511
  let normalized = raw;
114789
115512
  if (driverMode === "raw") {
@@ -114800,8 +115523,12 @@ var decodeProjectionValue = (rendered, projection, expression, raw, scope, drive
114800
115523
  }
114801
115524
  }
114802
115525
  const nullability = effectiveRuntimeNullability(expression, scope);
115526
+ const schema4 = expressionRuntimeSchema(expression, { assumptions: scope.assumptions });
114803
115527
  if (normalized === null) {
114804
115528
  if (nullability === "never") {
115529
+ if (dbTypeAllowsTopLevelJsonNull(expression[TypeId].dbType) && schemaAcceptsNull(schema4)) {
115530
+ return null;
115531
+ }
114805
115532
  throw makeRowDecodeError(rendered, projection, expression, raw, "schema", new Error("Received null for a non-null projection"), normalized);
114806
115533
  }
114807
115534
  return null;
@@ -114809,7 +115536,9 @@ var decodeProjectionValue = (rendered, projection, expression, raw, scope, drive
114809
115536
  if (nullability === "always") {
114810
115537
  throw makeRowDecodeError(rendered, projection, expression, raw, "schema", new Error("Received non-null for an always-null projection"), normalized);
114811
115538
  }
114812
- const schema4 = expressionRuntimeSchema(expression, { assumptions: scope.assumptions });
115539
+ if (dbTypeAllowsTopLevelJsonNull(expression[TypeId].dbType) && !isJsonValue(normalized)) {
115540
+ throw makeRowDecodeError(rendered, projection, expression, raw, "schema", new Error("Expected a JSON value"), normalized);
115541
+ }
114813
115542
  if (schema4 === undefined) {
114814
115543
  return normalized;
114815
115544
  }
@@ -114824,19 +115553,19 @@ var decodeProjectionValue = (rendered, projection, expression, raw, scope, drive
114824
115553
  };
114825
115554
  var makeRowDecoder = (rendered, plan, options2 = {}) => {
114826
115555
  const projections = flattenSelection(getAst(plan).select);
114827
- const byAlias = new Map(projections.map((projection) => [projection.alias, projection.expression]));
115556
+ const byPath = new Map(projections.map((projection) => [JSON.stringify(projection.path), projection.expression]));
114828
115557
  const driverMode = options2.driverMode ?? "raw";
114829
115558
  const valueMappings = options2.valueMappings ?? rendered.valueMappings;
114830
115559
  const scope = resolveImplicationScope(plan[TypeId3].available, getQueryState(plan).assumptions);
114831
115560
  return (row) => {
114832
115561
  const decoded = {};
114833
115562
  for (const projection of rendered.projections) {
114834
- if (!(projection.alias in row)) {
114835
- continue;
114836
- }
114837
- const expression = byAlias.get(projection.alias);
115563
+ const expression = byPath.get(JSON.stringify(projection.path));
114838
115564
  if (expression === undefined) {
114839
- continue;
115565
+ throw new Error(`Rendered projection path '${projection.path.join(".")}' does not exist in the query selection`);
115566
+ }
115567
+ if (!(projection.alias in row)) {
115568
+ throw makeRowDecodeError(rendered, projection, expression, undefined, "schema", new Error(`Missing required projection alias '${projection.alias}'`));
114840
115569
  }
114841
115570
  setPath2(decoded, projection.path, decodeProjectionValue(rendered, projection, expression, row[projection.alias], scope, driverMode, valueMappings));
114842
115571
  }
@@ -114883,6 +115612,23 @@ var withSavepoint = (effect) => Effect.flatMap(SqlClient.SqlClient, (sql) => sql
114883
115612
 
114884
115613
  // src/internal/renderer.ts
114885
115614
  var TypeId8 = Symbol.for("effect-qb/Renderer");
115615
+ var projectionPathKey = (path2) => JSON.stringify(path2);
115616
+ var formatProjectionPath2 = (path2) => path2.join(".");
115617
+ var validateProjectionPathsMatchSelection = (plan, projections) => {
115618
+ const expected = flattenSelection(getAst(plan).select);
115619
+ const expectedPaths = new Set(expected.map((projection) => projectionPathKey(projection.path)));
115620
+ const actualPaths = new Set(projections.map((projection) => projectionPathKey(projection.path)));
115621
+ for (const projection of projections) {
115622
+ if (!expectedPaths.has(projectionPathKey(projection.path))) {
115623
+ throw new Error(`Projection path ${formatProjectionPath2(projection.path)} does not exist in the query selection`);
115624
+ }
115625
+ }
115626
+ for (const projection of expected) {
115627
+ if (!actualPaths.has(projectionPathKey(projection.path))) {
115628
+ throw new Error(`Projection path ${formatProjectionPath2(projection.path)} is missing from rendered projections`);
115629
+ }
115630
+ }
115631
+ };
114886
115632
  function make5(dialect, render) {
114887
115633
  if (typeof render !== "function") {
114888
115634
  throw new Error(`Renderer.make requires an explicit render implementation for dialect: ${dialect}`);
@@ -114890,9 +115636,18 @@ function make5(dialect, render) {
114890
115636
  return {
114891
115637
  dialect,
114892
115638
  render(plan) {
115639
+ const required = currentRequiredList(plan[TypeId3].required);
115640
+ if (required.length > 0) {
115641
+ throw new Error(`query references sources that are not yet in scope: ${required.join(", ")}`);
115642
+ }
115643
+ const planDialect = plan[TypeId3].dialect;
115644
+ if (planDialect !== dialect) {
115645
+ throw new Error("effect-qb: plan dialect is not compatible with the target renderer or executor");
115646
+ }
114893
115647
  const rendered = render(plan);
114894
115648
  const projections = rendered.projections ?? [];
114895
115649
  validateProjections(projections);
115650
+ validateProjectionPathsMatchSelection(plan, projections);
114896
115651
  return {
114897
115652
  sql: rendered.sql,
114898
115653
  params: rendered.params ?? [],
@@ -114938,16 +115693,19 @@ var mysqlDialect = {
114938
115693
  }
114939
115694
  };
114940
115695
 
115696
+ // src/mysql/internal/sql-expression-renderer.ts
115697
+ import * as Schema10 from "effect/Schema";
115698
+
114941
115699
  // src/internal/aggregation-validation.ts
114942
- var isExpression2 = (value) => typeof value === "object" && value !== null && (TypeId in value);
115700
+ var isExpression3 = (value) => typeof value === "object" && value !== null && (TypeId in value);
114943
115701
  var selectionHasAggregate = (selection) => {
114944
- if (isExpression2(selection)) {
115702
+ if (isExpression3(selection)) {
114945
115703
  return selection[TypeId].kind === "aggregate";
114946
115704
  }
114947
115705
  return Object.values(selection).some((value) => selectionHasAggregate(value));
114948
115706
  };
114949
115707
  var isGroupedSelectionValid = (selection, groupedExpressions) => {
114950
- if (isExpression2(selection)) {
115708
+ if (isExpression3(selection)) {
114951
115709
  const aggregation = selection[TypeId].kind;
114952
115710
  if (aggregation === "aggregate") {
114953
115711
  return true;
@@ -115052,7 +115810,46 @@ var renderCastType = (dialect, dbType) => {
115052
115810
  return dbType.kind;
115053
115811
  }
115054
115812
  };
115055
- var renderDdlExpression = (expression, state, dialect) => isSchemaExpression(expression) ? render(expression) : renderExpression(expression, state, dialect);
115813
+ var renderMysqlDdlString = (value) => `'${value.replaceAll("'", "''")}'`;
115814
+ var renderMysqlDdlBytes = (value) => `x'${Array.from(value, (byte) => byte.toString(16).padStart(2, "0")).join("")}'`;
115815
+ var renderMysqlDdlLiteral = (value, state, context = {}) => {
115816
+ const driverValue = toDriverValue(value, {
115817
+ dialect: "mysql",
115818
+ valueMappings: state.valueMappings,
115819
+ ...context
115820
+ });
115821
+ if (driverValue === null) {
115822
+ return "null";
115823
+ }
115824
+ switch (typeof driverValue) {
115825
+ case "boolean":
115826
+ return driverValue ? "true" : "false";
115827
+ case "number":
115828
+ if (!Number.isFinite(driverValue)) {
115829
+ throw new Error("Expected a finite numeric value");
115830
+ }
115831
+ return String(driverValue);
115832
+ case "bigint":
115833
+ return driverValue.toString();
115834
+ case "string":
115835
+ return renderMysqlDdlString(driverValue);
115836
+ case "object":
115837
+ if (driverValue instanceof Uint8Array) {
115838
+ return renderMysqlDdlBytes(driverValue);
115839
+ }
115840
+ break;
115841
+ }
115842
+ throw new Error("Unsupported mysql DDL literal value");
115843
+ };
115844
+ var renderDdlExpression = (expression, state, dialect) => {
115845
+ if (isSchemaExpression(expression)) {
115846
+ return render(expression);
115847
+ }
115848
+ return renderExpression(expression, state, {
115849
+ ...dialect,
115850
+ renderLiteral: renderMysqlDdlLiteral
115851
+ });
115852
+ };
115056
115853
  var renderMysqlMutationLimit = (expression, state, dialect) => {
115057
115854
  const ast = expression[TypeId2];
115058
115855
  if (ast.kind === "literal" && typeof ast.value === "number" && Number.isInteger(ast.value) && ast.value >= 0) {
@@ -115087,30 +115884,52 @@ var renderCreateTableSql = (targetSource, state, dialect, ifNotExists) => {
115087
115884
  definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}primary key (${option2.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${option2.deferrable ? ` deferrable${option2.initiallyDeferred ? " initially deferred" : ""}` : ""}`);
115088
115885
  break;
115089
115886
  case "unique":
115887
+ if (option2.nullsNotDistinct || option2.deferrable || option2.initiallyDeferred) {
115888
+ throw new Error("Unsupported mysql unique constraint options");
115889
+ }
115090
115890
  definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}unique${option2.nullsNotDistinct ? " nulls not distinct" : ""} (${option2.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${option2.deferrable ? ` deferrable${option2.initiallyDeferred ? " initially deferred" : ""}` : ""}`);
115091
115891
  break;
115092
115892
  case "foreignKey": {
115093
115893
  const reference = option2.references();
115094
- definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}foreign key (${option2.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")}) references ${dialect.renderTableReference(reference.tableName, reference.tableName, reference.schemaName)} (${reference.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${option2.onDelete ? ` on delete ${option2.onDelete.replace(/[A-Z]/g, (value) => ` ${value.toLowerCase()}`).trim()}` : ""}${option2.onUpdate ? ` on update ${option2.onUpdate.replace(/[A-Z]/g, (value) => ` ${value.toLowerCase()}`).trim()}` : ""}${option2.deferrable ? ` deferrable${option2.initiallyDeferred ? " initially deferred" : ""}` : ""}`);
115894
+ definitions.push(`${option2.name ? `constraint ${dialect.quoteIdentifier(option2.name)} ` : ""}foreign key (${option2.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")}) references ${dialect.renderTableReference(reference.tableName, reference.tableName, reference.schemaName)} (${reference.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${option2.onDelete !== undefined ? ` on delete ${renderReferentialAction(option2.onDelete)}` : ""}${option2.onUpdate !== undefined ? ` on update ${renderReferentialAction(option2.onUpdate)}` : ""}${option2.deferrable ? ` deferrable${option2.initiallyDeferred ? " initially deferred" : ""}` : ""}`);
115095
115895
  break;
115096
115896
  }
115097
115897
  case "check":
115098
- definitions.push(`constraint ${dialect.quoteIdentifier(option2.name)} check (${renderDdlExpression(option2.predicate, state, dialect)})${option2.noInherit ? " no inherit" : ""}`);
115898
+ definitions.push(`constraint ${dialect.quoteIdentifier(option2.name)} check (${renderDdlExpression(option2.predicate, { ...state, rowLocalColumns: true }, dialect)})${option2.noInherit ? " no inherit" : ""}`);
115099
115899
  break;
115100
115900
  case "index":
115101
115901
  break;
115902
+ default:
115903
+ throw new Error("Unsupported table option kind");
115102
115904
  }
115103
115905
  }
115104
115906
  return `create table${ifNotExists ? " if not exists" : ""} ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} (${definitions.join(", ")})`;
115105
115907
  };
115106
115908
  var renderCreateIndexSql = (targetSource, ddl, state, dialect) => {
115909
+ if (ddl.ifNotExists) {
115910
+ throw new Error("Unsupported mysql create index options");
115911
+ }
115107
115912
  const maybeIfNotExists = dialect.name === "postgres" && ddl.ifNotExists ? " if not exists" : "";
115108
115913
  return `create${ddl.unique ? " unique" : ""} index${maybeIfNotExists} ${dialect.quoteIdentifier(ddl.name)} on ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} (${ddl.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})`;
115109
115914
  };
115110
- var renderDropIndexSql = (targetSource, ddl, state, dialect) => dialect.name === "postgres" ? `drop index${ddl.ifExists ? " if exists" : ""} ${dialect.quoteIdentifier(ddl.name)}` : `drop index ${dialect.quoteIdentifier(ddl.name)} on ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)}`;
115111
- var isExpression3 = (value) => value !== null && typeof value === "object" && (TypeId in value);
115112
- var isJsonDbType = (dbType) => dbType.kind === "jsonb" || dbType.kind === "json" || ("variant" in dbType) && dbType.variant === "json";
115113
- var isJsonExpression = (value) => isExpression3(value) && isJsonDbType(value[TypeId].dbType);
115915
+ var renderDropIndexSql = (targetSource, ddl, state, dialect) => {
115916
+ if (ddl.ifExists) {
115917
+ throw new Error("Unsupported mysql drop index options");
115918
+ }
115919
+ return dialect.name === "postgres" ? `drop index${ddl.ifExists ? " if exists" : ""} ${dialect.quoteIdentifier(ddl.name)}` : `drop index ${dialect.quoteIdentifier(ddl.name)} on ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)}`;
115920
+ };
115921
+ var isExpression4 = (value) => value !== null && typeof value === "object" && (TypeId in value);
115922
+ var isJsonDbType2 = (dbType) => {
115923
+ if (dbType.kind === "jsonb" || dbType.kind === "json") {
115924
+ return true;
115925
+ }
115926
+ if (!("variant" in dbType)) {
115927
+ return false;
115928
+ }
115929
+ const variant = dbType.variant;
115930
+ return variant === "json" || variant === "jsonb";
115931
+ };
115932
+ var isJsonExpression = (value) => isExpression4(value) && isJsonDbType2(value[TypeId].dbType);
115114
115933
  var unsupportedJsonFeature = (dialect, feature) => {
115115
115934
  const error = new Error(`Unsupported JSON feature for ${dialect.name}: ${feature}`);
115116
115935
  Object.assign(error, {
@@ -115153,15 +115972,16 @@ var extractJsonPathSegments = (node) => {
115153
115972
  };
115154
115973
  var extractJsonValue = (node) => node.newValue ?? node.insert ?? node.right;
115155
115974
  var renderJsonPathSegment = (segment) => {
115975
+ const renderKey = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) ? `.${value}` : `.${JSON.stringify(value)}`;
115156
115976
  if (typeof segment === "string") {
115157
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(segment) ? `.${segment}` : `."${segment.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
115977
+ return renderKey(segment);
115158
115978
  }
115159
115979
  if (typeof segment === "number") {
115160
115980
  return `[${segment}]`;
115161
115981
  }
115162
115982
  switch (segment.kind) {
115163
115983
  case "key":
115164
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(segment.key) ? `.${segment.key}` : `."${segment.key.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
115984
+ return renderKey(segment.key);
115165
115985
  case "index":
115166
115986
  return `[${segment.index}]`;
115167
115987
  case "wildcard":
@@ -115174,14 +115994,45 @@ var renderJsonPathSegment = (segment) => {
115174
115994
  throw new Error("Unsupported JSON path segment");
115175
115995
  }
115176
115996
  };
115177
- var renderJsonPathStringLiteral = (segments) => {
115997
+ var renderMySqlJsonIndex = (index4) => index4 >= 0 ? String(index4) : index4 === -1 ? "last" : `last-${Math.abs(index4) - 1}`;
115998
+ var renderMySqlJsonPathSegment = (segment) => {
115999
+ if (typeof segment === "number") {
116000
+ return `[${renderMySqlJsonIndex(segment)}]`;
116001
+ }
116002
+ if (typeof segment === "object" && segment !== null && segment.kind === "index") {
116003
+ return `[${renderMySqlJsonIndex(segment.index)}]`;
116004
+ }
116005
+ if (typeof segment === "object" && segment !== null && segment.kind === "slice") {
116006
+ return `[${renderMySqlJsonIndex(segment.start ?? 0)} to ${segment.end === undefined ? "last" : renderMySqlJsonIndex(segment.end)}]`;
116007
+ }
116008
+ if (typeof segment === "object" && segment !== null && segment.kind === "descend") {
116009
+ return "**";
116010
+ }
116011
+ return renderJsonPathSegment(segment);
116012
+ };
116013
+ var renderJsonPathStringLiteral = (segments, renderSegment = renderJsonPathSegment) => {
115178
116014
  let path2 = "$";
115179
116015
  for (const segment of segments) {
115180
- path2 += renderJsonPathSegment(segment);
116016
+ path2 += renderSegment(segment);
115181
116017
  }
115182
116018
  return path2;
115183
116019
  };
115184
- var renderMySqlJsonPath = (segments, state, dialect) => dialect.renderLiteral(renderJsonPathStringLiteral(segments), state);
116020
+ var renderMySqlJsonPath = (segments, state, dialect) => dialect.renderLiteral(renderJsonPathStringLiteral(segments, renderMySqlJsonPathSegment), state);
116021
+ var isJsonArrayIndexSegment = (segment) => typeof segment === "number" || typeof segment === "object" && segment !== null && segment.kind === "index";
116022
+ var renderMySqlJsonInsertPath = (segments, insertAfter, state, dialect) => {
116023
+ if (!insertAfter || segments.length === 0) {
116024
+ return renderMySqlJsonPath(segments, state, dialect);
116025
+ }
116026
+ const last = segments[segments.length - 1];
116027
+ const nextSegments = segments.slice(0, -1);
116028
+ if (typeof last === "number") {
116029
+ return renderMySqlJsonPath([...nextSegments, last + 1], state, dialect);
116030
+ }
116031
+ if (typeof last === "object" && last !== null && last.kind === "index") {
116032
+ return renderMySqlJsonPath([...nextSegments, { ...last, index: last.index + 1 }], state, dialect);
116033
+ }
116034
+ return renderMySqlJsonPath(segments, state, dialect);
116035
+ };
115185
116036
  var renderPostgresJsonPathArray = (segments, state, dialect) => `array[${segments.map((segment) => {
115186
116037
  if (typeof segment === "string") {
115187
116038
  return dialect.renderLiteral(segment, state);
@@ -115210,7 +116061,7 @@ var renderPostgresJsonAccessStep = (segment, textMode, state, dialect) => {
115210
116061
  }
115211
116062
  };
115212
116063
  var renderPostgresJsonValue = (value, state, dialect) => {
115213
- if (!isExpression3(value)) {
116064
+ if (!isExpression4(value)) {
115214
116065
  throw new Error("Expected a JSON expression");
115215
116066
  }
115216
116067
  const rendered = renderExpression(value, state, dialect);
@@ -115223,23 +116074,48 @@ var expressionDriverContext = (expression, state, dialect) => ({
115223
116074
  runtimeSchema: expression[TypeId].runtimeSchema,
115224
116075
  driverValueMapping: expression[TypeId].driverValueMapping
115225
116076
  });
115226
- var renderJsonInputExpression = (expression, state, dialect) => renderJsonSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect));
115227
- var encodeArrayValues = (values2, column2, state, dialect) => values2.map((value) => toDriverValue(value, {
115228
- dialect: dialect.name,
115229
- valueMappings: state.valueMappings,
115230
- dbType: column2.metadata.dbType,
115231
- runtimeSchema: column2.schema,
115232
- driverValueMapping: column2.metadata.driverValueMapping
115233
- }));
116077
+ var renderMySqlStructuredJsonLiteral = (expression, state) => {
116078
+ const ast = expression[TypeId2];
116079
+ if (ast.kind !== "literal" || ast.value === null || typeof ast.value !== "object") {
116080
+ return;
116081
+ }
116082
+ state.params.push(JSON.stringify(ast.value));
116083
+ return "cast(? as json)";
116084
+ };
116085
+ var renderJsonInputExpression = (expression, state, dialect) => {
116086
+ if (dialect.name === "mysql") {
116087
+ const jsonLiteral = renderMySqlStructuredJsonLiteral(expression, state);
116088
+ if (jsonLiteral !== undefined) {
116089
+ return jsonLiteral;
116090
+ }
116091
+ }
116092
+ return renderJsonSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect));
116093
+ };
116094
+ var encodeArrayValues = (values2, column2, state, dialect) => values2.map((value) => {
116095
+ if (value === null && column2.metadata.nullable) {
116096
+ return null;
116097
+ }
116098
+ const runtimeSchemaAccepts = column2.schema !== undefined && Schema10.is(column2.schema)(value);
116099
+ const normalizedValue = runtimeSchemaAccepts ? value : normalizeDbValue(column2.metadata.dbType, value);
116100
+ const encodedValue = column2.schema === undefined || runtimeSchemaAccepts ? normalizedValue : Schema10.decodeUnknownSync(column2.schema)(normalizedValue);
116101
+ return toDriverValue(encodedValue, {
116102
+ dialect: dialect.name,
116103
+ valueMappings: state.valueMappings,
116104
+ dbType: column2.metadata.dbType,
116105
+ runtimeSchema: column2.schema,
116106
+ driverValueMapping: column2.metadata.driverValueMapping
116107
+ });
116108
+ });
115234
116109
  var renderPostgresJsonKind = (value) => value[TypeId].dbType.kind === "jsonb" ? "jsonb" : "json";
115235
116110
  var renderJsonOpaquePath = (value, state, dialect) => {
115236
116111
  if (isJsonPathValue2(value)) {
115237
- return dialect.renderLiteral(renderJsonPathStringLiteral(value.segments), state);
116112
+ const renderSegment = dialect.name === "mysql" ? renderMySqlJsonPathSegment : renderJsonPathSegment;
116113
+ return dialect.renderLiteral(renderJsonPathStringLiteral(value.segments, renderSegment), state);
115238
116114
  }
115239
116115
  if (typeof value === "string") {
115240
116116
  return dialect.renderLiteral(value, state);
115241
116117
  }
115242
- if (isExpression3(value)) {
116118
+ if (isExpression4(value)) {
115243
116119
  return renderExpression(value, state, dialect);
115244
116120
  }
115245
116121
  throw new Error("Unsupported SQL/JSON path input");
@@ -115257,7 +116133,7 @@ var renderFunctionCall = (name, args, state, dialect) => {
115257
116133
  if (source === undefined) {
115258
116134
  throw new Error("Unsupported SQL extract expression");
115259
116135
  }
115260
- const fieldRuntime = isExpression3(field) && field[TypeId].dbType.kind === "text" && typeof field[TypeId].runtime === "string" ? field[TypeId].runtime : undefined;
116136
+ const fieldRuntime = isExpression4(field) && field[TypeId].dbType.kind === "text" && typeof field[TypeId].runtime === "string" ? field[TypeId].runtime : undefined;
115261
116137
  const renderedField = fieldRuntime ?? renderExpression(field, state, dialect);
115262
116138
  return `extract(${renderedField} from ${renderExpression(source, state, dialect)})`;
115263
116139
  }
@@ -115295,7 +116171,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115295
116171
  case "jsonPathText":
115296
116172
  case "jsonAccessText":
115297
116173
  case "jsonTraverseText": {
115298
- if (!isExpression3(base) || segments.length === 0) {
116174
+ if (!isExpression4(base) || segments.length === 0) {
115299
116175
  return;
115300
116176
  }
115301
116177
  const baseSql = renderExpression(base, state, dialect);
@@ -115318,7 +116194,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115318
116194
  case "jsonKeyExists":
115319
116195
  case "jsonHasAnyKeys":
115320
116196
  case "jsonHasAllKeys": {
115321
- if (!isExpression3(base)) {
116197
+ if (!isExpression4(base)) {
115322
116198
  return;
115323
116199
  }
115324
116200
  const baseSql = dialect.name === "postgres" ? renderPostgresJsonValue(base, state, dialect) : renderExpression(base, state, dialect);
@@ -115337,21 +116213,22 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115337
116213
  }
115338
116214
  if (dialect.name === "mysql") {
115339
116215
  const mode = kind === "jsonHasAllKeys" ? "all" : "one";
116216
+ const modeSql = dialect.renderLiteral(mode, state);
115340
116217
  const paths = keys.map((segment) => renderMySqlJsonPath([segment], state, dialect)).join(", ");
115341
- return `json_contains_path(${baseSql}, ${dialect.renderLiteral(mode, state)}, ${paths})`;
116218
+ return `json_contains_path(${baseSql}, ${modeSql}, ${paths})`;
115342
116219
  }
115343
116220
  return;
115344
116221
  }
115345
116222
  case "jsonConcat":
115346
116223
  case "jsonMerge": {
115347
- if (!isExpression3(ast.left) || !isExpression3(ast.right)) {
116224
+ if (!isExpression4(ast.left) || !isExpression4(ast.right)) {
115348
116225
  return;
115349
116226
  }
115350
116227
  if (dialect.name === "postgres") {
115351
116228
  return `(${renderPostgresJsonValue(ast.left, state, dialect)} || ${renderPostgresJsonValue(ast.right, state, dialect)})`;
115352
116229
  }
115353
116230
  if (dialect.name === "mysql") {
115354
- return `json_merge_preserve(${renderExpression(ast.left, state, dialect)}, ${renderExpression(ast.right, state, dialect)})`;
116231
+ return `json_merge_preserve(${renderJsonInputExpression(ast.left, state, dialect)}, ${renderJsonInputExpression(ast.right, state, dialect)})`;
115355
116232
  }
115356
116233
  return;
115357
116234
  }
@@ -115381,29 +116258,29 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115381
116258
  return;
115382
116259
  }
115383
116260
  case "jsonToJson":
115384
- if (!isExpression3(base)) {
116261
+ if (!isExpression4(base)) {
115385
116262
  return;
115386
116263
  }
115387
116264
  if (dialect.name === "postgres") {
115388
116265
  return `to_json(${renderJsonInputExpression(base, state, dialect)})`;
115389
116266
  }
115390
116267
  if (dialect.name === "mysql") {
115391
- return `cast(${renderExpression(base, state, dialect)} as json)`;
116268
+ return renderMySqlStructuredJsonLiteral(base, state) ?? `cast(${renderExpression(base, state, dialect)} as json)`;
115392
116269
  }
115393
116270
  return;
115394
116271
  case "jsonToJsonb":
115395
- if (!isExpression3(base)) {
116272
+ if (!isExpression4(base)) {
115396
116273
  return;
115397
116274
  }
115398
116275
  if (dialect.name === "postgres") {
115399
116276
  return `to_jsonb(${renderJsonInputExpression(base, state, dialect)})`;
115400
116277
  }
115401
116278
  if (dialect.name === "mysql") {
115402
- return `cast(${renderExpression(base, state, dialect)} as json)`;
116279
+ return renderMySqlStructuredJsonLiteral(base, state) ?? `cast(${renderExpression(base, state, dialect)} as json)`;
115403
116280
  }
115404
116281
  return;
115405
116282
  case "jsonTypeOf":
115406
- if (!isExpression3(base)) {
116283
+ if (!isExpression4(base)) {
115407
116284
  return;
115408
116285
  }
115409
116286
  if (dialect.name === "postgres") {
@@ -115415,7 +116292,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115415
116292
  }
115416
116293
  return;
115417
116294
  case "jsonLength":
115418
- if (!isExpression3(base)) {
116295
+ if (!isExpression4(base)) {
115419
116296
  return;
115420
116297
  }
115421
116298
  if (dialect.name === "postgres") {
@@ -115430,7 +116307,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115430
116307
  }
115431
116308
  return;
115432
116309
  case "jsonKeys":
115433
- if (!isExpression3(base)) {
116310
+ if (!isExpression4(base)) {
115434
116311
  return;
115435
116312
  }
115436
116313
  if (dialect.name === "postgres") {
@@ -115444,7 +116321,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115444
116321
  }
115445
116322
  return;
115446
116323
  case "jsonStripNulls":
115447
- if (!isExpression3(base)) {
116324
+ if (!isExpression4(base)) {
115448
116325
  return;
115449
116326
  }
115450
116327
  if (dialect.name === "postgres") {
@@ -115455,7 +116332,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115455
116332
  case "jsonDelete":
115456
116333
  case "jsonDeletePath":
115457
116334
  case "jsonRemove": {
115458
- if (!isExpression3(base) || segments.length === 0) {
116335
+ if (!isExpression4(base) || segments.length === 0) {
115459
116336
  return;
115460
116337
  }
115461
116338
  if (dialect.name === "postgres") {
@@ -115467,17 +116344,17 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115467
116344
  return `(${baseSql} #- ${renderPostgresJsonPathArray(segments, state, dialect)})`;
115468
116345
  }
115469
116346
  if (dialect.name === "mysql") {
115470
- return `json_remove(${renderExpression(base, state, dialect)}, ${segments.map((segment) => renderMySqlJsonPath([segment], state, dialect)).join(", ")})`;
116347
+ return `json_remove(${renderExpression(base, state, dialect)}, ${renderMySqlJsonPath(segments, state, dialect)})`;
115471
116348
  }
115472
116349
  return;
115473
116350
  }
115474
116351
  case "jsonSet":
115475
116352
  case "jsonInsert": {
115476
- if (!isExpression3(base) || segments.length === 0) {
116353
+ if (!isExpression4(base) || segments.length === 0) {
115477
116354
  return;
115478
116355
  }
115479
116356
  const nextValue = extractJsonValue(ast);
115480
- if (!isExpression3(nextValue)) {
116357
+ if (!isExpression4(nextValue)) {
115481
116358
  return;
115482
116359
  }
115483
116360
  const createMissing = ast.createMissing === true;
@@ -115488,13 +116365,21 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115488
116365
  return `${functionName}(${renderPostgresJsonValue(base, state, dialect)}, ${renderPostgresJsonPathArray(segments, state, dialect)}, ${renderPostgresJsonValue(nextValue, state, dialect)}${extra})`;
115489
116366
  }
115490
116367
  if (dialect.name === "mysql") {
115491
- const functionName = kind === "jsonInsert" ? "json_insert" : "json_set";
115492
- return `${functionName}(${renderExpression(base, state, dialect)}, ${renderMySqlJsonPath(segments, state, dialect)}, ${renderExpression(nextValue, state, dialect)})`;
116368
+ const renderedBase = renderExpression(base, state, dialect);
116369
+ if (kind === "jsonInsert" && isJsonArrayIndexSegment(segments[segments.length - 1])) {
116370
+ const renderedPath2 = renderMySqlJsonInsertPath(segments, insertAfter, state, dialect);
116371
+ const renderedValue2 = renderJsonInputExpression(nextValue, state, dialect);
116372
+ return `json_array_insert(${renderedBase}, ${renderedPath2}, ${renderedValue2})`;
116373
+ }
116374
+ const functionName = kind === "jsonInsert" ? "json_insert" : createMissing ? "json_set" : "json_replace";
116375
+ const renderedPath = renderMySqlJsonPath(segments, state, dialect);
116376
+ const renderedValue = renderJsonInputExpression(nextValue, state, dialect);
116377
+ return `${functionName}(${renderedBase}, ${renderedPath}, ${renderedValue})`;
115493
116378
  }
115494
116379
  return;
115495
116380
  }
115496
116381
  case "jsonPathExists": {
115497
- if (!isExpression3(base)) {
116382
+ if (!isExpression4(base)) {
115498
116383
  return;
115499
116384
  }
115500
116385
  const path2 = ast.path ?? ast.query ?? ast.right;
@@ -115510,7 +116395,7 @@ var renderJsonExpression = (expression, ast, state, dialect) => {
115510
116395
  return;
115511
116396
  }
115512
116397
  case "jsonPathMatch": {
115513
- if (!isExpression3(base)) {
116398
+ if (!isExpression4(base)) {
115514
116399
  return;
115515
116400
  }
115516
116401
  const path2 = ast.path ?? ast.query ?? ast.right;
@@ -115541,23 +116426,15 @@ var renderMysqlMutationLock = (lock2, statement) => {
115541
116426
  if (!lock2) {
115542
116427
  return "";
115543
116428
  }
115544
- switch (lock2.mode) {
115545
- case "lowPriority":
115546
- return " low_priority";
115547
- case "ignore":
115548
- return " ignore";
115549
- case "quick":
115550
- return statement === "delete" ? " quick" : "";
115551
- default:
115552
- return "";
115553
- }
116429
+ return renderMysqlMutationLockMode(lock2.mode, statement);
115554
116430
  };
115555
116431
  var renderTransactionClause = (clause, dialect) => {
115556
116432
  switch (clause.kind) {
115557
116433
  case "transaction": {
115558
116434
  const modes = [];
115559
- if (clause.isolationLevel) {
115560
- modes.push(`isolation level ${clause.isolationLevel}`);
116435
+ const isolationLevel = renderTransactionIsolationLevel(clause.isolationLevel);
116436
+ if (isolationLevel) {
116437
+ modes.push(isolationLevel);
115561
116438
  }
115562
116439
  if (clause.readOnly === true) {
115563
116440
  modes.push("read only");
@@ -115575,13 +116452,16 @@ var renderTransactionClause = (clause, dialect) => {
115575
116452
  case "releaseSavepoint":
115576
116453
  return `release savepoint ${dialect.quoteIdentifier(clause.name)}`;
115577
116454
  }
115578
- return "";
116455
+ throw new Error("Unsupported transaction statement kind");
115579
116456
  };
115580
116457
  var renderSelectionList = (selection, state, dialect, validateAggregation) => {
115581
116458
  if (validateAggregation) {
115582
116459
  validateAggregationSelection(selection, []);
115583
116460
  }
115584
116461
  const flattened = flattenSelection(selection);
116462
+ if (dialect.name === "mysql" && flattened.length === 0) {
116463
+ throw new Error("mysql select statements require at least one selected expression");
116464
+ }
115585
116465
  const projections = selectionProjections(selection);
115586
116466
  const sql = flattened.map(({ expression, alias: alias2 }) => `${renderSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect))} as ${dialect.quoteIdentifier(alias2)}`).join(", ");
115587
116467
  return {
@@ -115589,7 +116469,84 @@ var renderSelectionList = (selection, state, dialect, validateAggregation) => {
115589
116469
  projections
115590
116470
  };
115591
116471
  };
115592
- var renderQueryAst = (ast, state, dialect) => {
116472
+ var nestedRenderState = (state) => ({
116473
+ params: state.params,
116474
+ valueMappings: state.valueMappings,
116475
+ ctes: [],
116476
+ cteNames: new Set(state.cteNames),
116477
+ cteSources: new Map(state.cteSources)
116478
+ });
116479
+ var assertMatchingSetProjections = (left, right) => {
116480
+ const leftKeys = left.map((projection) => JSON.stringify(projection.path));
116481
+ const rightKeys = right.map((projection) => JSON.stringify(projection.path));
116482
+ if (leftKeys.length !== rightKeys.length || leftKeys.some((key2, index4) => key2 !== rightKeys[index4])) {
116483
+ throw new Error("set operator operands must have matching result rows");
116484
+ }
116485
+ };
116486
+ var assertNoGroupedMutationClauses = (ast, statement) => {
116487
+ if (ast.groupBy.length > 0) {
116488
+ throw new Error(`groupBy(...) is not supported for ${statement} statements`);
116489
+ }
116490
+ if (ast.having.length > 0) {
116491
+ throw new Error(`having(...) is not supported for ${statement} statements`);
116492
+ }
116493
+ };
116494
+ var assertNoInsertQueryClauses = (ast) => {
116495
+ if (ast.where.length > 0) {
116496
+ throw new Error("where(...) is not supported for insert statements");
116497
+ }
116498
+ if (ast.joins.length > 0) {
116499
+ throw new Error("join(...) is not supported for insert statements");
116500
+ }
116501
+ if (ast.orderBy.length > 0) {
116502
+ throw new Error("orderBy(...) is not supported for insert statements");
116503
+ }
116504
+ if (ast.limit) {
116505
+ throw new Error("limit(...) is not supported for insert statements");
116506
+ }
116507
+ if (ast.offset) {
116508
+ throw new Error("offset(...) is not supported for insert statements");
116509
+ }
116510
+ if (ast.lock) {
116511
+ throw new Error("lock(...) is not supported for insert statements");
116512
+ }
116513
+ };
116514
+ var assertNoStatementQueryClauses = (ast, statement, options2 = {}) => {
116515
+ if (ast.distinct) {
116516
+ throw new Error(`distinct(...) is not supported for ${statement} statements`);
116517
+ }
116518
+ if (ast.where.length > 0) {
116519
+ throw new Error(`where(...) is not supported for ${statement} statements`);
116520
+ }
116521
+ if ((ast.fromSources?.length ?? 0) > 0 || ast.from) {
116522
+ throw new Error(`from(...) is not supported for ${statement} statements`);
116523
+ }
116524
+ if (ast.joins.length > 0) {
116525
+ throw new Error(`join(...) is not supported for ${statement} statements`);
116526
+ }
116527
+ if (ast.groupBy.length > 0) {
116528
+ throw new Error(`groupBy(...) is not supported for ${statement} statements`);
116529
+ }
116530
+ if (ast.having.length > 0) {
116531
+ throw new Error(`having(...) is not supported for ${statement} statements`);
116532
+ }
116533
+ if (ast.orderBy.length > 0) {
116534
+ throw new Error(`orderBy(...) is not supported for ${statement} statements`);
116535
+ }
116536
+ if (ast.limit) {
116537
+ throw new Error(`limit(...) is not supported for ${statement} statements`);
116538
+ }
116539
+ if (ast.offset) {
116540
+ throw new Error(`offset(...) is not supported for ${statement} statements`);
116541
+ }
116542
+ if (ast.lock) {
116543
+ throw new Error(`lock(...) is not supported for ${statement} statements`);
116544
+ }
116545
+ if (options2.allowSelection !== true && Object.keys(ast.select).length > 0) {
116546
+ throw new Error(`returning(...) is not supported for ${statement} statements`);
116547
+ }
116548
+ };
116549
+ var renderQueryAst = (ast, state, dialect, options2 = {}) => {
115593
116550
  let sql = "";
115594
116551
  let projections = [];
115595
116552
  switch (ast.kind) {
@@ -115597,13 +116554,17 @@ var renderQueryAst = (ast, state, dialect) => {
115597
116554
  validateAggregationSelection(ast.select, ast.groupBy);
115598
116555
  const rendered = renderSelectionList(ast.select, state, dialect, false);
115599
116556
  projections = rendered.projections;
116557
+ const selectList = rendered.sql.length > 0 ? ` ${rendered.sql}` : "";
115600
116558
  const clauses = [
115601
- ast.distinctOn && ast.distinctOn.length > 0 ? `select distinct on (${ast.distinctOn.map((value) => renderExpression(value, state, dialect)).join(", ")}) ${rendered.sql}` : `select${ast.distinct ? " distinct" : ""} ${rendered.sql}`
116559
+ ast.distinctOn && ast.distinctOn.length > 0 ? `select distinct on (${ast.distinctOn.map((value) => renderExpression(value, state, dialect)).join(", ")})${selectList}` : `select${ast.distinct ? " distinct" : ""}${selectList}`
115602
116560
  ];
115603
116561
  if (ast.from) {
115604
116562
  clauses.push(`from ${renderSourceReference(ast.from.source, ast.from.tableName, ast.from.baseTableName, state, dialect)}`);
115605
116563
  }
115606
116564
  for (const join2 of ast.joins) {
116565
+ if (dialect.name === "mysql" && join2.kind === "full") {
116566
+ throw new Error("Unsupported mysql full join");
116567
+ }
115607
116568
  const source = renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect);
115608
116569
  clauses.push(join2.kind === "cross" ? `cross join ${source}` : `${join2.kind} join ${source} on ${renderExpression(join2.on, state, dialect)}`);
115609
116570
  }
@@ -115626,19 +116587,25 @@ var renderQueryAst = (ast, state, dialect) => {
115626
116587
  clauses.push(`offset ${renderExpression(ast.offset, state, dialect)}`);
115627
116588
  }
115628
116589
  if (ast.lock) {
115629
- clauses.push(`${ast.lock.mode === "update" ? "for update" : "for share"}${ast.lock.nowait ? " nowait" : ""}${ast.lock.skipLocked ? " skip locked" : ""}`);
116590
+ if (ast.lock.nowait && ast.lock.skipLocked) {
116591
+ throw new Error("lock(...) cannot specify both nowait and skipLocked");
116592
+ }
116593
+ clauses.push(`${renderSelectLockMode(ast.lock.mode)}${ast.lock.nowait ? " nowait" : ""}${ast.lock.skipLocked ? " skip locked" : ""}`);
115630
116594
  }
115631
116595
  sql = clauses.join(" ");
115632
116596
  break;
115633
116597
  }
115634
116598
  case "set": {
115635
116599
  const setAst = ast;
116600
+ assertNoStatementQueryClauses(setAst, "set", { allowSelection: true });
115636
116601
  const base = renderQueryAst(getAst(setAst.setBase), state, dialect);
115637
116602
  projections = selectionProjections(setAst.select);
116603
+ assertMatchingSetProjections(projections, base.projections);
115638
116604
  sql = [
115639
116605
  `(${base.sql})`,
115640
116606
  ...(setAst.setOperations ?? []).map((entry) => {
115641
116607
  const rendered = renderQueryAst(getAst(entry.query), state, dialect);
116608
+ assertMatchingSetProjections(projections, rendered.projections);
115642
116609
  return `${entry.kind}${entry.all ? " all" : ""} (${rendered.sql})`;
115643
116610
  })
115644
116611
  ].join(" ");
@@ -115646,28 +116613,40 @@ var renderQueryAst = (ast, state, dialect) => {
115646
116613
  }
115647
116614
  case "insert": {
115648
116615
  const insertAst = ast;
116616
+ if (insertAst.distinct) {
116617
+ throw new Error("distinct(...) is not supported for insert statements");
116618
+ }
116619
+ assertNoGroupedMutationClauses(insertAst, "insert");
116620
+ assertNoInsertQueryClauses(insertAst);
115649
116621
  const targetSource = insertAst.into;
115650
116622
  const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
116623
+ const insertSource = expectInsertSourceKind(insertAst.insertSource);
116624
+ const conflict = expectConflictClause(insertAst.conflict);
115651
116625
  sql = `insert into ${target}`;
115652
- if (insertAst.insertSource?.kind === "values") {
115653
- const columns = insertAst.insertSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
115654
- const rows = insertAst.insertSource.rows.map((row) => `(${row.values.map((entry) => renderExpression(entry.value, state, dialect)).join(", ")})`).join(", ");
116626
+ if (insertSource?.kind === "values") {
116627
+ const columns = insertSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
116628
+ const rows = insertSource.rows.map((row) => `(${row.values.map((entry) => renderExpression(entry.value, state, dialect)).join(", ")})`).join(", ");
115655
116629
  sql += ` (${columns}) values ${rows}`;
115656
- } else if (insertAst.insertSource?.kind === "query") {
115657
- const columns = insertAst.insertSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
115658
- const renderedQuery = renderQueryAst(getAst(insertAst.insertSource.query), state, dialect);
116630
+ } else if (insertSource?.kind === "query") {
116631
+ const columns = insertSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
116632
+ const renderedQuery = renderQueryAst(getAst(insertSource.query), state, dialect);
115659
116633
  sql += ` (${columns}) ${renderedQuery.sql}`;
115660
- } else if (insertAst.insertSource?.kind === "unnest") {
115661
- const unnestSource = insertAst.insertSource;
115662
- const columns = unnestSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
116634
+ } else if (insertSource?.kind === "unnest") {
116635
+ const columns = insertSource.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ");
115663
116636
  if (dialect.name === "postgres") {
115664
116637
  const table = targetSource.source;
115665
116638
  const fields2 = table[TypeId4].fields;
115666
- const rendered = unnestSource.values.map((entry) => `cast(${dialect.renderLiteral(encodeArrayValues(entry.values, fields2[entry.columnName], state, dialect), state)} as ${renderCastType(dialect, fields2[entry.columnName].metadata.dbType)}[])`).join(", ");
116639
+ const rendered = insertSource.values.map((entry) => `cast(${dialect.renderLiteral(encodeArrayValues(entry.values, fields2[entry.columnName], state, dialect), state)} as ${renderCastType(dialect, fields2[entry.columnName].metadata.dbType)}[])`).join(", ");
115667
116640
  sql += ` (${columns}) select * from unnest(${rendered})`;
115668
116641
  } else {
115669
- const rowCount = unnestSource.values[0]?.values.length ?? 0;
115670
- const rows = Array.from({ length: rowCount }, (_, index4) => `(${unnestSource.values.map((entry) => dialect.renderLiteral(entry.values[index4], state, targetSource.source[TypeId4].fields[entry.columnName][TypeId])).join(", ")})`).join(", ");
116642
+ const table = targetSource.source;
116643
+ const fields2 = table[TypeId4].fields;
116644
+ const encodedValues = insertSource.values.map((entry) => ({
116645
+ columnName: entry.columnName,
116646
+ values: encodeArrayValues(entry.values, fields2[entry.columnName], state, dialect)
116647
+ }));
116648
+ const rowCount = encodedValues[0]?.values.length ?? 0;
116649
+ const rows = Array.from({ length: rowCount }, (_, index4) => `(${encodedValues.map((entry) => dialect.renderLiteral(entry.values[index4], state)).join(", ")})`).join(", ");
115671
116650
  sql += ` (${columns}) values ${rows}`;
115672
116651
  }
115673
116652
  } else {
@@ -115676,22 +116655,29 @@ var renderQueryAst = (ast, state, dialect) => {
115676
116655
  if ((insertAst.values ?? []).length > 0) {
115677
116656
  sql += ` (${columns}) values (${values2})`;
115678
116657
  } else {
115679
- sql += " default values";
116658
+ sql += " () values ()";
115680
116659
  }
115681
116660
  }
115682
- if (insertAst.conflict) {
115683
- const updateValues = (insertAst.conflict.values ?? []).map((entry) => `${dialect.quoteIdentifier(entry.columnName)} = ${renderExpression(entry.value, state, dialect)}`).join(", ");
116661
+ if (conflict) {
116662
+ if (conflict.where) {
116663
+ throw new Error("Unsupported mysql conflict action predicates");
116664
+ }
116665
+ const updateValues = (conflict.values ?? []).map((entry) => `${dialect.quoteIdentifier(entry.columnName)} = ${renderExpression(entry.value, state, dialect)}`).join(", ");
115684
116666
  if (dialect.name === "postgres") {
115685
- const targetSql = insertAst.conflict.target?.kind === "constraint" ? ` on conflict on constraint ${dialect.quoteIdentifier(insertAst.conflict.target.name)}` : insertAst.conflict.target?.kind === "columns" ? ` on conflict (${insertAst.conflict.target.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${insertAst.conflict.target.where ? ` where ${renderExpression(insertAst.conflict.target.where, state, dialect)}` : ""}` : " on conflict";
116667
+ const targetSql = conflict.target?.kind === "constraint" ? ` on conflict on constraint ${dialect.quoteIdentifier(conflict.target.name)}` : conflict.target?.kind === "columns" ? ` on conflict (${conflict.target.columns.map((column2) => dialect.quoteIdentifier(column2)).join(", ")})${conflict.target.where ? ` where ${renderExpression(conflict.target.where, state, dialect)}` : ""}` : " on conflict";
115686
116668
  sql += targetSql;
115687
- sql += insertAst.conflict.action === "doNothing" ? " do nothing" : ` do update set ${updateValues}${insertAst.conflict.where ? ` where ${renderExpression(insertAst.conflict.where, state, dialect)}` : ""}`;
115688
- } else if (insertAst.conflict.action === "doNothing") {
116669
+ sql += conflict.action === "doNothing" ? " do nothing" : ` do update set ${updateValues}${conflict.where ? ` where ${renderExpression(conflict.where, state, dialect)}` : ""}`;
116670
+ } else if (conflict.action === "doNothing") {
115689
116671
  sql = sql.replace(/^insert/, "insert ignore");
115690
116672
  } else {
115691
116673
  sql += ` on duplicate key update ${updateValues}`;
115692
116674
  }
115693
116675
  }
115694
- const returning2 = renderSelectionList(insertAst.select, state, dialect, false);
116676
+ const hasReturning = Object.keys(insertAst.select).length > 0;
116677
+ const returning2 = hasReturning ? renderSelectionList(insertAst.select, state, dialect, false) : { sql: "", projections: [] };
116678
+ if (dialect.name === "mysql" && returning2.sql.length > 0) {
116679
+ throw new Error("Unsupported mysql returning");
116680
+ }
115695
116681
  projections = returning2.projections;
115696
116682
  if (returning2.sql.length > 0) {
115697
116683
  sql += ` returning ${returning2.sql}`;
@@ -115700,15 +116686,27 @@ var renderQueryAst = (ast, state, dialect) => {
115700
116686
  }
115701
116687
  case "update": {
115702
116688
  const updateAst = ast;
116689
+ if (updateAst.distinct) {
116690
+ throw new Error("distinct(...) is not supported for update statements");
116691
+ }
116692
+ assertNoGroupedMutationClauses(updateAst, "update");
116693
+ if (updateAst.offset) {
116694
+ throw new Error("offset(...) is not supported for update statements");
116695
+ }
115703
116696
  const targetSource = updateAst.target;
115704
116697
  const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
115705
116698
  const targets = updateAst.targets ?? [targetSource];
115706
116699
  const fromSources = updateAst.fromSources ?? [];
116700
+ if ((updateAst.set ?? []).length === 0) {
116701
+ throw new Error("update statements require at least one assignment");
116702
+ }
115707
116703
  const assignments = updateAst.set.map((entry) => renderMutationAssignment(entry, state, dialect)).join(", ");
115708
116704
  if (dialect.name === "mysql") {
115709
116705
  const modifiers = renderMysqlMutationLock(updateAst.lock, "update");
115710
116706
  const extraSources = renderFromSources(fromSources, state, dialect);
115711
- const joinSources = updateAst.joins.map((join2) => join2.kind === "cross" ? `cross join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)}` : `${join2.kind} join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)} on ${renderExpression(join2.on, state, dialect)}`).join(" ");
116707
+ const joinSources = updateAst.joins.map((join2) => join2.kind === "full" ? (() => {
116708
+ throw new Error("Unsupported mysql full join");
116709
+ })() : join2.kind === "cross" ? `cross join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)}` : `${join2.kind} join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)} on ${renderExpression(join2.on, state, dialect)}`).join(" ");
115712
116710
  const targetList = [
115713
116711
  ...targets.map((entry) => renderSourceReference(entry.source, entry.tableName, entry.baseTableName, state, dialect)),
115714
116712
  ...extraSources.length > 0 ? [extraSources] : []
@@ -115737,7 +116735,11 @@ var renderQueryAst = (ast, state, dialect) => {
115737
116735
  if (dialect.name === "mysql" && updateAst.limit) {
115738
116736
  sql += ` limit ${renderMysqlMutationLimit(updateAst.limit, state, dialect)}`;
115739
116737
  }
115740
- const returning2 = renderSelectionList(updateAst.select, state, dialect, false);
116738
+ const hasReturning = Object.keys(updateAst.select).length > 0;
116739
+ const returning2 = hasReturning ? renderSelectionList(updateAst.select, state, dialect, false) : { sql: "", projections: [] };
116740
+ if (dialect.name === "mysql" && returning2.sql.length > 0) {
116741
+ throw new Error("Unsupported mysql returning");
116742
+ }
115741
116743
  projections = returning2.projections;
115742
116744
  if (returning2.sql.length > 0) {
115743
116745
  sql += ` returning ${returning2.sql}`;
@@ -115746,6 +116748,13 @@ var renderQueryAst = (ast, state, dialect) => {
115746
116748
  }
115747
116749
  case "delete": {
115748
116750
  const deleteAst = ast;
116751
+ if (deleteAst.distinct) {
116752
+ throw new Error("distinct(...) is not supported for delete statements");
116753
+ }
116754
+ assertNoGroupedMutationClauses(deleteAst, "delete");
116755
+ if (deleteAst.offset) {
116756
+ throw new Error("offset(...) is not supported for delete statements");
116757
+ }
115749
116758
  const targetSource = deleteAst.target;
115750
116759
  const target = renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect);
115751
116760
  const targets = deleteAst.targets ?? [targetSource];
@@ -115754,7 +116763,9 @@ var renderQueryAst = (ast, state, dialect) => {
115754
116763
  const hasJoinedSources = deleteAst.joins.length > 0 || targets.length > 1;
115755
116764
  const targetList = renderDeleteTargets(targets, dialect);
115756
116765
  const fromSources = targets.map((entry) => renderSourceReference(entry.source, entry.tableName, entry.baseTableName, state, dialect)).join(", ");
115757
- const joinSources = deleteAst.joins.map((join2) => join2.kind === "cross" ? `cross join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)}` : `${join2.kind} join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)} on ${renderExpression(join2.on, state, dialect)}`).join(" ");
116766
+ const joinSources = deleteAst.joins.map((join2) => join2.kind === "full" ? (() => {
116767
+ throw new Error("Unsupported mysql full join");
116768
+ })() : join2.kind === "cross" ? `cross join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)}` : `${join2.kind} join ${renderSourceReference(join2.source, join2.tableName, join2.baseTableName, state, dialect)} on ${renderExpression(join2.on, state, dialect)}`).join(" ");
115758
116769
  sql = hasJoinedSources ? `delete${modifiers} ${targetList} from ${fromSources}${joinSources.length > 0 ? ` ${joinSources}` : ""}` : `delete${modifiers} from ${fromSources}`;
115759
116770
  } else {
115760
116771
  sql = `delete from ${target}`;
@@ -115775,7 +116786,11 @@ var renderQueryAst = (ast, state, dialect) => {
115775
116786
  if (dialect.name === "mysql" && deleteAst.limit) {
115776
116787
  sql += ` limit ${renderMysqlMutationLimit(deleteAst.limit, state, dialect)}`;
115777
116788
  }
115778
- const returning2 = renderSelectionList(deleteAst.select, state, dialect, false);
116789
+ const hasReturning = Object.keys(deleteAst.select).length > 0;
116790
+ const returning2 = hasReturning ? renderSelectionList(deleteAst.select, state, dialect, false) : { sql: "", projections: [] };
116791
+ if (dialect.name === "mysql" && returning2.sql.length > 0) {
116792
+ throw new Error("Unsupported mysql returning");
116793
+ }
115779
116794
  projections = returning2.projections;
115780
116795
  if (returning2.sql.length > 0) {
115781
116796
  sql += ` returning ${returning2.sql}`;
@@ -115784,12 +116799,17 @@ var renderQueryAst = (ast, state, dialect) => {
115784
116799
  }
115785
116800
  case "truncate": {
115786
116801
  const truncateAst = ast;
116802
+ assertNoStatementQueryClauses(truncateAst, "truncate");
116803
+ const truncate2 = expectTruncateClause(truncateAst.truncate);
115787
116804
  const targetSource = truncateAst.target;
116805
+ if (dialect.name === "mysql" && (truncate2.restartIdentity || truncate2.cascade)) {
116806
+ throw new Error("Unsupported mysql truncate options");
116807
+ }
115788
116808
  sql = `truncate table ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)}`;
115789
- if (truncateAst.truncate?.restartIdentity) {
116809
+ if (truncate2.restartIdentity) {
115790
116810
  sql += " restart identity";
115791
116811
  }
115792
- if (truncateAst.truncate?.cascade) {
116812
+ if (truncate2.cascade) {
115793
116813
  sql += " cascade";
115794
116814
  }
115795
116815
  break;
@@ -115802,6 +116822,9 @@ var renderQueryAst = (ast, state, dialect) => {
115802
116822
  const targetSource = mergeAst.target;
115803
116823
  const usingSource = mergeAst.using;
115804
116824
  const merge2 = mergeAst.merge;
116825
+ if (Object.keys(mergeAst.select).length > 0) {
116826
+ throw new Error("returning(...) is not supported for merge statements");
116827
+ }
115805
116828
  sql = `merge into ${renderSourceReference(targetSource.source, targetSource.tableName, targetSource.baseTableName, state, dialect)} using ${renderSourceReference(usingSource.source, usingSource.tableName, usingSource.baseTableName, state, dialect)} on ${renderExpression(merge2.on, state, dialect)}`;
115806
116829
  if (merge2.whenMatched) {
115807
116830
  sql += " when matched";
@@ -115829,32 +116852,40 @@ var renderQueryAst = (ast, state, dialect) => {
115829
116852
  case "savepoint":
115830
116853
  case "rollbackTo":
115831
116854
  case "releaseSavepoint": {
116855
+ assertNoStatementQueryClauses(ast, ast.kind);
115832
116856
  sql = renderTransactionClause(ast.transaction, dialect);
115833
116857
  break;
115834
116858
  }
115835
116859
  case "createTable": {
115836
116860
  const createTableAst = ast;
115837
- sql = renderCreateTableSql(createTableAst.target, state, dialect, createTableAst.ddl?.kind === "createTable" && createTableAst.ddl.ifNotExists);
116861
+ assertNoStatementQueryClauses(createTableAst, "createTable");
116862
+ const ddl = expectDdlClauseKind(createTableAst.ddl, "createTable");
116863
+ sql = renderCreateTableSql(createTableAst.target, state, dialect, ddl.ifNotExists);
115838
116864
  break;
115839
116865
  }
115840
116866
  case "dropTable": {
115841
116867
  const dropTableAst = ast;
115842
- const ifExists = dropTableAst.ddl?.kind === "dropTable" && dropTableAst.ddl.ifExists;
115843
- sql = `drop table${ifExists ? " if exists" : ""} ${renderSourceReference(dropTableAst.target.source, dropTableAst.target.tableName, dropTableAst.target.baseTableName, state, dialect)}`;
116868
+ assertNoStatementQueryClauses(dropTableAst, "dropTable");
116869
+ const ddl = expectDdlClauseKind(dropTableAst.ddl, "dropTable");
116870
+ sql = `drop table${ddl.ifExists ? " if exists" : ""} ${renderSourceReference(dropTableAst.target.source, dropTableAst.target.tableName, dropTableAst.target.baseTableName, state, dialect)}`;
115844
116871
  break;
115845
116872
  }
115846
116873
  case "createIndex": {
115847
116874
  const createIndexAst = ast;
115848
- sql = renderCreateIndexSql(createIndexAst.target, createIndexAst.ddl, state, dialect);
116875
+ assertNoStatementQueryClauses(createIndexAst, "createIndex");
116876
+ sql = renderCreateIndexSql(createIndexAst.target, expectDdlClauseKind(createIndexAst.ddl, "createIndex"), state, dialect);
115849
116877
  break;
115850
116878
  }
115851
116879
  case "dropIndex": {
115852
116880
  const dropIndexAst = ast;
115853
- sql = renderDropIndexSql(dropIndexAst.target, dropIndexAst.ddl, state, dialect);
116881
+ assertNoStatementQueryClauses(dropIndexAst, "dropIndex");
116882
+ sql = renderDropIndexSql(dropIndexAst.target, expectDdlClauseKind(dropIndexAst.ddl, "dropIndex"), state, dialect);
115854
116883
  break;
115855
116884
  }
116885
+ default:
116886
+ throw new Error("Unsupported query statement kind");
115856
116887
  }
115857
- if (state.ctes.length === 0) {
116888
+ if (state.ctes.length === 0 || options2.emitCtes === false) {
115858
116889
  return {
115859
116890
  sql,
115860
116891
  projections
@@ -115877,9 +116908,22 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
115877
116908
  };
115878
116909
  if (typeof source === "object" && source !== null && "kind" in source && source.kind === "cte") {
115879
116910
  const cte = source;
116911
+ const registeredCteSource = state.cteSources.get(cte.name);
116912
+ if (registeredCteSource !== undefined && registeredCteSource !== cte.plan) {
116913
+ throw new Error(`common table expression name is already registered with a different plan: ${cte.name}`);
116914
+ }
115880
116915
  if (!state.cteNames.has(cte.name)) {
115881
116916
  state.cteNames.add(cte.name);
115882
- const rendered = renderQueryAst(getAst(cte.plan), state, dialect);
116917
+ state.cteSources.set(cte.name, cte.plan);
116918
+ const statement = getQueryState(cte.plan).statement;
116919
+ if (statement !== "select" && statement !== "set") {
116920
+ const cteAst = getAst(cte.plan);
116921
+ if (Object.keys(cteAst.select ?? {}).length > 0) {
116922
+ throw new Error("Unsupported mysql returning");
116923
+ }
116924
+ throw new Error("Unsupported mysql data-modifying cte");
116925
+ }
116926
+ const rendered = renderQueryAst(getAst(cte.plan), state, dialect, { emitCtes: false });
115883
116927
  state.ctes.push({
115884
116928
  name: cte.name,
115885
116929
  sql: rendered.sql,
@@ -115891,11 +116935,11 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
115891
116935
  if (typeof source === "object" && source !== null && "kind" in source && source.kind === "derived") {
115892
116936
  const derived = source;
115893
116937
  if (!state.cteNames.has(derived.name)) {}
115894
- return `(${renderQueryAst(getAst(derived.plan), state, dialect).sql}) as ${dialect.quoteIdentifier(derived.name)}`;
116938
+ return `(${renderQueryAst(getAst(derived.plan), nestedRenderState(state), dialect).sql}) as ${dialect.quoteIdentifier(derived.name)}`;
115895
116939
  }
115896
116940
  if (typeof source === "object" && source !== null && "kind" in source && source.kind === "lateral") {
115897
116941
  const lateral2 = source;
115898
- return `lateral (${renderQueryAst(getAst(lateral2.plan), state, dialect).sql}) as ${dialect.quoteIdentifier(lateral2.name)}`;
116942
+ return `lateral (${renderQueryAst(getAst(lateral2.plan), nestedRenderState(state), dialect).sql}) as ${dialect.quoteIdentifier(lateral2.name)}`;
115899
116943
  }
115900
116944
  if (typeof source === "object" && source !== null && source.kind === "values") {
115901
116945
  const values2 = source;
@@ -115916,6 +116960,13 @@ var renderSourceReference = (source, tableName, baseTableName, state, dialect) =
115916
116960
  const schemaName = typeof source === "object" && source !== null && TypeId4 in source ? source[TypeId4].schemaName : undefined;
115917
116961
  return dialect.renderTableReference(tableName, baseTableName, schemaName);
115918
116962
  };
116963
+ var renderSubqueryExpressionPlan = (plan, state, dialect) => {
116964
+ const statement = getQueryState(plan).statement;
116965
+ if (statement !== "select" && statement !== "set") {
116966
+ throw new Error("subquery expressions only accept select-like query plans");
116967
+ }
116968
+ return renderQueryAst(getAst(plan), state, dialect).sql;
116969
+ };
115919
116970
  var renderExpression = (expression, state, dialect) => {
115920
116971
  const rawAst = expression[TypeId2];
115921
116972
  const jsonSql = renderJsonExpression(expression, rawAst, state, dialect);
@@ -115926,8 +116977,11 @@ var renderExpression = (expression, state, dialect) => {
115926
116977
  const renderComparisonOperator = (operator) => operator === "eq" ? "=" : operator === "neq" ? "<>" : operator === "lt" ? "<" : operator === "lte" ? "<=" : operator === "gt" ? ">" : ">=";
115927
116978
  switch (ast.kind) {
115928
116979
  case "column":
115929
- return ast.tableName.length === 0 ? dialect.quoteIdentifier(ast.columnName) : `${dialect.quoteIdentifier(ast.tableName)}.${dialect.quoteIdentifier(ast.columnName)}`;
116980
+ return state.rowLocalColumns || ast.tableName.length === 0 ? dialect.quoteIdentifier(ast.columnName) : `${dialect.quoteIdentifier(ast.tableName)}.${dialect.quoteIdentifier(ast.columnName)}`;
115930
116981
  case "literal":
116982
+ if (typeof ast.value === "number" && !Number.isFinite(ast.value)) {
116983
+ throw new Error("Expected a finite numeric value");
116984
+ }
115931
116985
  return dialect.renderLiteral(ast.value, state, expression[TypeId]);
115932
116986
  case "excluded":
115933
116987
  return dialect.name === "mysql" ? `values(${dialect.quoteIdentifier(ast.columnName)})` : `excluded.${dialect.quoteIdentifier(ast.columnName)}`;
@@ -115970,7 +117024,7 @@ var renderExpression = (expression, state, dialect) => {
115970
117024
  return `(${left} @> ${right})`;
115971
117025
  }
115972
117026
  if (dialect.name === "mysql" && isJsonExpression(ast.left) && isJsonExpression(ast.right)) {
115973
- return `json_contains(${renderExpression(ast.left, state, dialect)}, ${renderExpression(ast.right, state, dialect)})`;
117027
+ return `json_contains(${renderJsonInputExpression(ast.left, state, dialect)}, ${renderJsonInputExpression(ast.right, state, dialect)})`;
115974
117028
  }
115975
117029
  throw new Error("Unsupported container operator for SQL rendering");
115976
117030
  case "containedBy":
@@ -115980,7 +117034,7 @@ var renderExpression = (expression, state, dialect) => {
115980
117034
  return `(${left} <@ ${right})`;
115981
117035
  }
115982
117036
  if (dialect.name === "mysql" && isJsonExpression(ast.left) && isJsonExpression(ast.right)) {
115983
- return `json_contains(${renderExpression(ast.right, state, dialect)}, ${renderExpression(ast.left, state, dialect)})`;
117037
+ return `json_contains(${renderJsonInputExpression(ast.right, state, dialect)}, ${renderJsonInputExpression(ast.left, state, dialect)})`;
115984
117038
  }
115985
117039
  throw new Error("Unsupported container operator for SQL rendering");
115986
117040
  case "overlaps":
@@ -115990,7 +117044,7 @@ var renderExpression = (expression, state, dialect) => {
115990
117044
  return `(${left} && ${right})`;
115991
117045
  }
115992
117046
  if (dialect.name === "mysql" && isJsonExpression(ast.left) && isJsonExpression(ast.right)) {
115993
- return `json_overlaps(${renderExpression(ast.left, state, dialect)}, ${renderExpression(ast.right, state, dialect)})`;
117047
+ return `json_overlaps(${renderJsonInputExpression(ast.left, state, dialect)}, ${renderJsonInputExpression(ast.right, state, dialect)})`;
115994
117048
  }
115995
117049
  throw new Error("Unsupported container operator for SQL rendering");
115996
117050
  case "isNull":
@@ -116010,14 +117064,26 @@ var renderExpression = (expression, state, dialect) => {
116010
117064
  case "min":
116011
117065
  return `min(${renderExpression(ast.value, state, dialect)})`;
116012
117066
  case "and":
117067
+ if (ast.values.length === 0) {
117068
+ throw new Error("and(...) requires at least one predicate");
117069
+ }
116013
117070
  return `(${ast.values.map((value) => renderExpression(value, state, dialect)).join(" and ")})`;
116014
117071
  case "or":
117072
+ if (ast.values.length === 0) {
117073
+ throw new Error("or(...) requires at least one predicate");
117074
+ }
116015
117075
  return `(${ast.values.map((value) => renderExpression(value, state, dialect)).join(" or ")})`;
116016
117076
  case "coalesce":
116017
117077
  return `coalesce(${ast.values.map((value) => renderExpression(value, state, dialect)).join(", ")})`;
116018
117078
  case "in":
117079
+ if (ast.values.length < 2) {
117080
+ throw new Error("in(...) requires at least one candidate value");
117081
+ }
116019
117082
  return `(${renderExpression(ast.values[0], state, dialect)} in (${ast.values.slice(1).map((value) => renderExpression(value, state, dialect)).join(", ")}))`;
116020
117083
  case "notIn":
117084
+ if (ast.values.length < 2) {
117085
+ throw new Error("notIn(...) requires at least one candidate value");
117086
+ }
116021
117087
  return `(${renderExpression(ast.values[0], state, dialect)} not in (${ast.values.slice(1).map((value) => renderExpression(value, state, dialect)).join(", ")}))`;
116022
117088
  case "between":
116023
117089
  return `(${renderExpression(ast.values[0], state, dialect)} between ${renderExpression(ast.values[1], state, dialect)} and ${renderExpression(ast.values[2], state, dialect)})`;
@@ -116026,15 +117092,15 @@ var renderExpression = (expression, state, dialect) => {
116026
117092
  case "case":
116027
117093
  return `case ${ast.branches.map((branch) => `when ${renderExpression(branch.when, state, dialect)} then ${renderExpression(branch.then, state, dialect)}`).join(" ")} else ${renderExpression(ast.else, state, dialect)} end`;
116028
117094
  case "exists":
116029
- return `exists (${renderQueryAst(getAst(ast.plan), state, dialect).sql})`;
117095
+ return `exists (${renderSubqueryExpressionPlan(ast.plan, state, dialect)})`;
116030
117096
  case "scalarSubquery":
116031
- return `(${renderQueryAst(getAst(ast.plan), state, dialect).sql})`;
117097
+ return `(${renderSubqueryExpressionPlan(ast.plan, state, dialect)})`;
116032
117098
  case "inSubquery":
116033
- return `(${renderExpression(ast.left, state, dialect)} in (${renderQueryAst(getAst(ast.plan), state, dialect).sql}))`;
117099
+ return `(${renderExpression(ast.left, state, dialect)} in (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
116034
117100
  case "comparisonAny":
116035
- return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} any (${renderQueryAst(getAst(ast.plan), state, dialect).sql}))`;
117101
+ return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} any (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
116036
117102
  case "comparisonAll":
116037
- return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} all (${renderQueryAst(getAst(ast.plan), state, dialect).sql}))`;
117103
+ return `(${renderExpression(ast.left, state, dialect)} ${renderComparisonOperator(ast.operator)} all (${renderSubqueryExpressionPlan(ast.plan, state, dialect)}))`;
116038
117104
  case "window": {
116039
117105
  if (!Array.isArray(ast.partitionBy) || !Array.isArray(ast.orderBy) || typeof ast.function !== "string") {
116040
117106
  break;
@@ -116069,7 +117135,8 @@ var renderMysqlPlan = (plan, options2 = {}) => {
116069
117135
  params: [],
116070
117136
  valueMappings: options2.valueMappings,
116071
117137
  ctes: [],
116072
- cteNames: new Set
117138
+ cteNames: new Set,
117139
+ cteSources: new Map
116073
117140
  };
116074
117141
  const rendered = renderQueryAst(getAst(plan), state, mysqlDialect);
116075
117142
  return {
@@ -116238,10 +117305,13 @@ var TypeId10 = TypeId4;
116238
117305
  var OptionsSymbol2 = OptionsSymbol;
116239
117306
  var options2 = options;
116240
117307
  var make7 = (name, fields2, schemaName = undefined) => make2(name, fields2, schemaName);
116241
- var schema4 = (schemaName) => ({
116242
- schemaName,
116243
- table: (name, fields2, ...declaredOptions) => schema3(schemaName).table(name, fields2, ...declaredOptions)
116244
- });
117308
+ var schema4 = (schemaName) => {
117309
+ const table = (name, fields2, ...declaredOptions) => schema3(schemaName).table(name, fields2, ...declaredOptions);
117310
+ return {
117311
+ schemaName,
117312
+ table
117313
+ };
117314
+ };
116245
117315
  var alias2 = (table, aliasName) => alias(table, aliasName);
116246
117316
  var Class2 = (name, schemaName = undefined) => {
116247
117317
  const base = Class(name, schemaName);