qubu 0.6.1 → 0.6.2

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 (84) hide show
  1. package/dist/{complete-DP7pliuY.mjs → canonical-B5_ouh-c.mjs} +466 -241
  2. package/dist/codegen.d.mts +2 -2
  3. package/dist/codegen.mjs +180 -90
  4. package/dist/column-Cyc2CMnG.mjs +116 -0
  5. package/dist/column-DDRvD7SF.mjs +721 -0
  6. package/dist/{constraints-DM_tarXc.mjs → constraints-CAmi18Uk.mjs} +8 -3
  7. package/dist/core.d.mts +3 -3
  8. package/dist/core.mjs +4 -4
  9. package/dist/diff.d.mts +9 -9
  10. package/dist/diff.mjs +152 -102
  11. package/dist/{explain-CkIK13L_.mjs → explain-BIqEmZha.mjs} +1 -1
  12. package/dist/{expressions-BCjc08zw.mjs → expressions-_6JF_J77.mjs} +2 -1
  13. package/dist/index-CaxrMD1A.d.mts +1 -0
  14. package/dist/index.d.mts +2 -2
  15. package/dist/index.mjs +368 -74
  16. package/dist/introspection/mysql.d.mts +1 -1
  17. package/dist/introspection/mysql.mjs +156 -23
  18. package/dist/introspection/postgres.d.mts +6 -3
  19. package/dist/introspection/postgres.mjs +388 -53
  20. package/dist/introspection/sqlite.d.mts +1 -1
  21. package/dist/introspection/sqlite.mjs +198 -12
  22. package/dist/introspection.d.mts +26 -12
  23. package/dist/introspection.mjs +2 -672
  24. package/dist/mysql.d.mts +3 -3
  25. package/dist/mysql.mjs +6 -5
  26. package/dist/{errors-Dxv73YJu.mjs → omit-VEr9Ydux.mjs} +5 -1
  27. package/dist/{on-conflict-CnaY5qso.mjs → on-conflict-B2rFyHGF.mjs} +6 -8
  28. package/dist/on-duplicate-key-update-Czsw1Yq-.mjs +95 -0
  29. package/dist/{postgres-Dey7QXPL.mjs → postgres-hFhd0I9n.mjs} +4 -5
  30. package/dist/postgres.d.mts +2 -2
  31. package/dist/postgres.mjs +2 -2
  32. package/dist/{registry-oWDiqD7i.mjs → registry-BXE_4M9P.mjs} +1 -1
  33. package/dist/{relational-DSAJ-l58.mjs → relational-CoPBETjI.mjs} +3 -2
  34. package/dist/schema.d.mts +2 -2
  35. package/dist/schema.mjs +8 -8
  36. package/dist/{serialize-CE-gw5_s.mjs → serialize-CyobNEx-.mjs} +174 -30
  37. package/dist/serialize-Du2UPZMt.d.mts +92 -0
  38. package/dist/snapshot/mysql.d.mts +5 -5
  39. package/dist/snapshot/mysql.mjs +8 -8
  40. package/dist/snapshot/postgres.d.mts +3 -3
  41. package/dist/snapshot/postgres.mjs +9 -9
  42. package/dist/snapshot/sqlite.d.mts +3 -3
  43. package/dist/snapshot/sqlite.mjs +7 -7
  44. package/dist/snapshot-mIb-Zzb5.mjs +1489 -0
  45. package/dist/snapshot.d.mts +4 -5
  46. package/dist/snapshot.mjs +3 -4
  47. package/dist/{source-BDuUXmAk.mjs → source-DYSUqzvb.mjs} +2 -2
  48. package/dist/sqlite.d.mts +2 -2
  49. package/dist/sqlite.mjs +6 -6
  50. package/dist/{table-C1QGNe4P.mjs → table-B8zEq0az.mjs} +4 -4
  51. package/dist/{types-BLNRatG_.mjs → types-CYHpSPwj.mjs} +10 -5
  52. package/dist/{types-BEn0N_al.d.mts → types-CiMvKi5V.d.mts} +14 -4
  53. package/dist/{types-DUe6eeI0.d.mts → types-Dqr4o2I1.d.mts} +590 -168
  54. package/dist/value-CpaUFtjw.mjs +45 -0
  55. package/dist/vite/ambient.d.ts +2 -0
  56. package/dist/vite.d.mts +1 -1
  57. package/dist/vite.mjs +2 -0
  58. package/docs/dialects-and-execution.md +61 -11
  59. package/docs/getting-started.md +1 -1
  60. package/docs/guides/extensions/typed-expressions.md +5 -3
  61. package/docs/guides/json.md +95 -2
  62. package/docs/guides/mutations.md +36 -0
  63. package/docs/index.md +1 -1
  64. package/docs/migrations/adapters.md +58 -21
  65. package/docs/migrations/recovery.md +7 -1
  66. package/docs/query-model/fragments.md +21 -1
  67. package/docs/reference/introspection-support.md +16 -18
  68. package/docs/reference/supported-surface.md +8 -7
  69. package/docs/schema/catalog-model.md +20 -7
  70. package/docs/schema/code-generation.md +1 -1
  71. package/docs/schema/diff.md +2 -2
  72. package/docs/schema/introspection.md +21 -14
  73. package/docs/schema/snapshots.md +18 -8
  74. package/docs/schema/storage-and-schema-sql.md +7 -2
  75. package/package.json +2 -1
  76. package/dist/canonical-DMvR9yBe.mjs +0 -972
  77. package/dist/column-BzN8KFJa.mjs +0 -364
  78. package/dist/column-CFvSbil0.mjs +0 -309
  79. package/dist/complete-types-CNMWBWap.d.mts +0 -371
  80. package/dist/index-CGui70hi.d.mts +0 -32
  81. package/dist/json-Db7XRD91.mjs +0 -169
  82. package/dist/omit-OxV58AwX.mjs +0 -5
  83. package/dist/serialize-OvXCLzjm.d.mts +0 -66
  84. package/dist/snapshot-DgsOhf_8.mjs +0 -354
package/dist/index.mjs CHANGED
@@ -1,58 +1,47 @@
1
- import { a as assertDialectCapability } from "./json-Db7XRD91.mjs";
2
- import { A as parenthesize, B as resultValueOf, C as makeExpression, E as markSchemaExpression, F as dateResultDecoder, I as decodeResultRow, L as jsonTextResultDecoder, M as ResultDecodingError, N as booleanResultDecoder, O as fragment, P as createResultShape, R as resultShapeValue, S as isSchemaExpression, T as markExpressionCategory, V as timestampResultDecoder, b as snakeCaseIdentifier, i as identifier, k as isFragment, l as value, o as asValue, t as createColumnReference, w as makeSchemaExpression, x as isExpression, y as resolveSqlNames, z as resultValue } from "./column-BzN8KFJa.mjs";
3
- import { c as render, n as call, o as cast, r as schemaCall, t as createClause } from "./types-BLNRatG_.mjs";
4
- import { n as queryValidationError, t as QueryValidationError } from "./errors-Dxv73YJu.mjs";
5
- import { C as identityColumn, S as generatedColumn, _ as uuid, b as externalDefault, c as integer, d as nativeStorage, f as nullable, g as timestamp, h as text, i as column, l as json, m as portableStorage, n as binary, o as date, p as numeric, r as boolean, s as encodeColumnParameter, t as bigint, u as nativeColumn, x as externalGeneratedColumn } from "./column-CFvSbil0.mjs";
6
- import { a as isDistinctFrom, c as lt, d as notLike, f as expressionOperand, i as gte, l as lte, m as renderOperands, n as eq, o as isNotDistinctFrom, p as isNullOperand, r as gt, s as like, u as ne } from "./relational-DSAJ-l58.mjs";
7
- import { t as omit } from "./omit-OxV58AwX.mjs";
8
- import { r as exposeColumns, t as createSource } from "./source-BDuUXmAk.mjs";
9
- import { n as alias, r as lateral, t as table } from "./table-C1QGNe4P.mjs";
10
- import { a as primaryKey, c as uniqueConstraint, i as foreignKey, n as catalogForeignKey, o as references, r as check, s as unique, t as catalogCheck, u as index } from "./constraints-DM_tarXc.mjs";
11
- import { c as unsafeSchemaSql } from "./expressions-BCjc08zw.mjs";
12
- import { i as schema } from "./registry-oWDiqD7i.mjs";
1
+ import { A as fragment, B as decodeResultRow, C as isExpression, D as markExpressionCategory, E as makeSchemaExpression, F as attachResultValue, G as timestampResultDecoder, H as resultShapeValue, I as bigintResultDecoder, L as booleanResultDecoder, M as parenthesize, O as markSchemaExpression, P as ResultDecodingError, R as createResultShape, S as snakeCaseIdentifier, T as makeExpression, U as resultValue, V as jsonTextResultDecoder, W as resultValueOf, X as assertDialectCapability, c as externalDefault, d as identityColumn, i as identifier, j as isFragment, l as externalGeneratedColumn, t as createColumnReference, u as generatedColumn, w as isSchemaExpression, x as resolveSqlNames, z as dateResultDecoder } from "./column-DDRvD7SF.mjs";
2
+ import { i as value, t as asValue } from "./value-CpaUFtjw.mjs";
3
+ import { c as render, n as call, o as cast, r as schemaCall, t as createClause } from "./types-CYHpSPwj.mjs";
4
+ import { n as QueryValidationError, r as queryValidationError, t as omit } from "./omit-VEr9Ydux.mjs";
5
+ import { _ as timestamp, c as encodeColumnParameter, d as nativeColumn, f as nativeStorage, g as text, h as portableStorage, i as column, l as integer, m as numeric, n as binary, o as columnSqlType, p as nullable, r as boolean, s as date, t as bigint, u as json, v as uuid } from "./column-Cyc2CMnG.mjs";
6
+ import { a as isDistinctFrom, c as lt, d as notLike, f as expressionOperand, i as gte, l as lte, m as renderOperands, n as eq, o as isNotDistinctFrom, p as isNullOperand, r as gt, s as like, u as ne } from "./relational-CoPBETjI.mjs";
7
+ import { r as exposeColumns, t as createSource } from "./source-DYSUqzvb.mjs";
8
+ import { n as alias, r as lateral, t as table } from "./table-B8zEq0az.mjs";
9
+ import { a as primaryKey, c as uniqueConstraint, i as foreignKey, n as catalogForeignKey, o as references, r as check, s as unique, t as catalogCheck, u as index } from "./constraints-CAmi18Uk.mjs";
10
+ import { c as unsafeSchemaSql } from "./expressions-_6JF_J77.mjs";
11
+ import { i as schema } from "./registry-BXE_4M9P.mjs";
12
+ import { i as renderDuplicateKeyUpdate, n as incomingAlias } from "./on-duplicate-key-update-Czsw1Yq-.mjs";
13
13
  //#region src/execution.ts
14
14
  function qubu(adapter, options = {}) {
15
- const observation = createObservation(options.hooks);
16
- const client = createClient(adapter, observation);
17
- if (!isTransactionalQueryAdapter(adapter)) return client;
18
- return Object.freeze({
19
- ...client,
20
- async transaction(callback, transactionOptions) {
21
- const active = startTransactionOperation(observation, transactionOptions?.hookMetadata);
22
- try {
23
- const result = await adapter.transaction(async (transactionAdapter) => callback(createClient(transactionAdapter, observation, active?.operation.id)), adapterTransactionOptions(transactionOptions));
24
- active?.finish({ status: "success" });
25
- return result;
26
- } catch (error) {
27
- active?.finish({
28
- status: "error",
29
- error
30
- });
31
- throw error;
32
- }
33
- }
34
- });
15
+ return createClient(adapter, createObservation(options.hooks));
35
16
  }
36
17
  function createClient(adapter, observation, parentId) {
37
- const client = {
18
+ return Object.freeze({
38
19
  adapter,
39
20
  execute(query, options) {
40
21
  return executeInternal(query, adapter, options ?? {}, observation, parentId);
41
22
  },
42
23
  rows(query, options) {
43
24
  return executeRowsInternal(query, adapter, options ?? {}, observation, parentId);
44
- }
45
- };
46
- const streaming = isStreamingQueryAdapter(adapter);
47
- const explainable = isExplainableQueryAdapter(adapter);
48
- if (!streaming && !explainable) return Object.freeze(client);
49
- return Object.freeze({
50
- ...client,
51
- ...streaming ? { stream(query, options) {
25
+ },
26
+ ...isStreamingQueryAdapter(adapter) ? { stream(query, options) {
52
27
  return streamInternal(query, adapter, options ?? {}, observation, parentId);
53
28
  } } : {},
54
- ...explainable ? { explain(query, options) {
29
+ ...isExplainableQueryAdapter(adapter) ? { explain(query, options) {
55
30
  return explainInternal(query, adapter, options ?? {}, observation, parentId);
31
+ } } : {},
32
+ ...isTransactionalQueryAdapter(adapter) ? { async transaction(callback, options) {
33
+ const active = startTransactionOperation(observation, options?.hookMetadata, parentId);
34
+ try {
35
+ const result = await adapter.transaction(async (scoped) => callback(createClient(scoped, observation, active?.operation.id)), adapterTransactionOptions(options));
36
+ active?.finish({ status: "success" });
37
+ return result;
38
+ } catch (error) {
39
+ active?.finish({
40
+ status: "error",
41
+ error
42
+ });
43
+ throw error;
44
+ }
56
45
  } } : {}
57
46
  });
58
47
  }
@@ -83,11 +72,11 @@ function startQueryOperation(observation, kind, request, dialect, metadata, pare
83
72
  parentId
84
73
  });
85
74
  }
86
- function startTransactionOperation(observation, metadata) {
75
+ function startTransactionOperation(observation, metadata, parentId) {
87
76
  return startOperation(observation, {
88
77
  kind: "transaction",
89
78
  metadata,
90
- parentId: void 0
79
+ parentId
91
80
  });
92
81
  }
93
82
  function startOperation(observation, input) {
@@ -278,7 +267,8 @@ function createExplainRequest(query, adapter, options) {
278
267
  });
279
268
  const statement = Object.freeze({
280
269
  text: dialect.explain.render(request.statement.text, query.queryKind, explainRenderOptions(options)),
281
- parameters: request.statement.parameters
270
+ parameters: request.statement.parameters,
271
+ ...request.statement.parameterSqlTypes === void 0 ? {} : { parameterSqlTypes: request.statement.parameterSqlTypes }
282
272
  });
283
273
  return Object.freeze({
284
274
  ...request,
@@ -307,7 +297,8 @@ function isQuery(value) {
307
297
  //#region src/expressions/map-result.ts
308
298
  /** Attach an application decoder to an expression without changing its SQL. */
309
299
  function mapResult(expression, decoder) {
310
- const mapped = makeExpression(expression.expressionKind, (context) => context.render(expression), expression.expressionCategory, resultValue(resultValueOf(expression)?.type, decoder));
300
+ const metadata = resultValueOf(expression);
301
+ const mapped = makeExpression(expression.expressionKind, (context) => context.render(expression), expression.expressionCategory, resultValue(metadata?.type, decoder, metadata?.sqlType));
311
302
  return isSchemaExpression(expression) ? markSchemaExpression(mapped) : mapped;
312
303
  }
313
304
  //#endregion
@@ -315,6 +306,7 @@ function mapResult(expression, decoder) {
315
306
  function caseWhen(condition, thenValue, elseValue) {
316
307
  const thenExpression = asValue(thenValue);
317
308
  const elseExpression = asValue(elseValue);
309
+ const domain = resultValueOf(thenExpression)?.sqlType ?? resultValueOf(elseExpression)?.sqlType;
318
310
  return makeSchemaExpression("operator", (context) => {
319
311
  context.append("CASE WHEN ");
320
312
  context.render(condition);
@@ -323,7 +315,7 @@ function caseWhen(condition, thenValue, elseValue) {
323
315
  context.append(" ELSE ");
324
316
  context.render(elseExpression);
325
317
  context.append(" END");
326
- });
318
+ }, resultValue(void 0, void 0, domain === "integer" ? "decimal" : domain));
327
319
  }
328
320
  //#endregion
329
321
  //#region src/expressions/sql.ts
@@ -368,40 +360,40 @@ function count(expression) {
368
360
  if (expression) context.render(expression);
369
361
  else context.append("*");
370
362
  context.append(")");
371
- }, "aggregate");
363
+ }, "aggregate", resultValue(void 0, void 0, "integer"));
372
364
  }
373
365
  function countDistinct(expression) {
374
366
  return makeExpression("function", (context) => {
375
367
  context.append("COUNT(DISTINCT ");
376
368
  context.render(expression);
377
369
  context.append(")");
378
- }, "aggregate");
370
+ }, "aggregate", resultValue(void 0, void 0, "integer"));
379
371
  }
380
372
  function sum(expression) {
381
- return markExpressionCategory(call("SUM", expression), "aggregate");
373
+ return markExpressionCategory(attachResultValue(call("SUM", expression), resultValueOf(expression)), "aggregate");
382
374
  }
383
375
  function avg(expression) {
384
- return markExpressionCategory(call("AVG", expression), "aggregate");
376
+ return markExpressionCategory(attachResultValue(call("AVG", expression), resultValue(void 0, void 0, "decimal")), "aggregate");
385
377
  }
386
378
  function min(expression) {
387
- return markExpressionCategory(call("MIN", expression), "aggregate");
379
+ return markExpressionCategory(attachResultValue(call("MIN", expression), resultValueOf(expression)), "aggregate");
388
380
  }
389
381
  function max(expression) {
390
- return markExpressionCategory(call("MAX", expression), "aggregate");
382
+ return markExpressionCategory(attachResultValue(call("MAX", expression), resultValueOf(expression)), "aggregate");
391
383
  }
392
384
  //#endregion
393
385
  //#region src/expressions/functions/string.ts
394
386
  function lower(input) {
395
- return schemaCall("LOWER", input);
387
+ return attachResultValue(schemaCall("LOWER", input), resultValue(void 0, void 0, "text"));
396
388
  }
397
389
  function upper(input) {
398
- return schemaCall("UPPER", input);
390
+ return attachResultValue(schemaCall("UPPER", input), resultValue(void 0, void 0, "text"));
399
391
  }
400
392
  function coalesce(first, ...rest) {
401
- return schemaCall("COALESCE", first, ...rest);
393
+ return attachResultValue(schemaCall("COALESCE", first, ...rest), resultValueOf(first));
402
394
  }
403
395
  function concat(...argumentsToConcat) {
404
- return schemaCall("CONCAT", ...argumentsToConcat);
396
+ return attachResultValue(schemaCall("CONCAT", ...argumentsToConcat), resultValue(void 0, void 0, "text"));
405
397
  }
406
398
  //#endregion
407
399
  //#region src/expressions/functions/window.ts
@@ -427,16 +419,16 @@ function over(expression, window) {
427
419
  });
428
420
  }
429
421
  context.append(")");
430
- }, "window");
422
+ }, "window", resultValueOf(expression));
431
423
  }
432
424
  function rowNumber() {
433
- return markExpressionCategory(call("ROW_NUMBER"), "window");
425
+ return markExpressionCategory(attachResultValue(call("ROW_NUMBER"), resultValue(void 0, void 0, "integer")), "window");
434
426
  }
435
427
  function rank() {
436
- return markExpressionCategory(call("RANK"), "window");
428
+ return markExpressionCategory(attachResultValue(call("RANK"), resultValue(void 0, void 0, "integer")), "window");
437
429
  }
438
430
  function denseRank() {
439
- return markExpressionCategory(call("DENSE_RANK"), "window");
431
+ return markExpressionCategory(attachResultValue(call("DENSE_RANK"), resultValue(void 0, void 0, "integer")), "window");
440
432
  }
441
433
  //#endregion
442
434
  //#region src/expressions/subquery.ts
@@ -481,7 +473,7 @@ function jsonScalar(document, path, kind) {
481
473
  assertDialectCapability(context.dialect, "json");
482
474
  if (!context.dialect.json) throw new Error(`Dialect "${context.dialect.name}" advertises JSON support without a JSON renderer`);
483
475
  context.dialect.json.renderScalar(context, document, path.segments, kind);
484
- }, kind === "boolean" ? resultValue("boolean") : void 0);
476
+ }, kind === "boolean" ? resultValue("boolean") : resultValue(void 0, void 0, kind === "number" ? "decimal" : "text"));
485
477
  }
486
478
  /** Extract a JSON string, returning SQL NULL for missing, null, or non-string values. */
487
479
  function jsonText(document, path) {
@@ -513,7 +505,7 @@ function arithmetic(operator, left, right) {
513
505
  context.append(` ${operator} `);
514
506
  context.render(rightExpression);
515
507
  context.append(")");
516
- });
508
+ }, resultValue(void 0, void 0, resultValueOf(left)?.sqlType === "integer" ? "decimal" : resultValueOf(left)?.sqlType));
517
509
  }
518
510
  const add = (left, right) => arithmetic("+", left, right);
519
511
  const subtract = (left, right) => arithmetic("-", left, right);
@@ -686,11 +678,11 @@ function renderPagination(context, clauses) {
686
678
  if (index > 0) context.append(" ");
687
679
  if (part.kind === "offset") {
688
680
  context.append("OFFSET ");
689
- context.parameter(part.rows);
681
+ context.parameter(part.rows, "integer");
690
682
  context.append(" ROWS");
691
683
  } else {
692
684
  context.append(`FETCH ${part.direction} `);
693
- context.parameter(part.rows);
685
+ context.parameter(part.rows, "integer");
694
686
  context.append(" ROWS ONLY");
695
687
  }
696
688
  });
@@ -824,7 +816,9 @@ function select(selection, ...parts) {
824
816
  clause,
825
817
  index
826
818
  })).sort((left, right) => left.clause.order - right.clause.order || left.index - right.index).map(({ clause }) => clause);
827
- return createQuery("select", selectionRow(selection), selectionResultShape(selection), (context) => {
819
+ const row = selectionRow(selection);
820
+ const query = createQuery("select", row, selectionResultShape(selection), renderBody);
821
+ function renderBody(context, extraOrdering) {
828
822
  const beforeSelect = orderedClauses.filter((clause) => clause.placement === "before-select");
829
823
  const afterSelect = orderedClauses.filter((clause) => clause.placement === "after-select");
830
824
  const paginationClauses = afterSelect.filter((clause) => clause.clauseKind === "offset" || clause.clauseKind === "fetch");
@@ -841,6 +835,12 @@ function select(selection, ...parts) {
841
835
  context.append(" ");
842
836
  }
843
837
  renderSelection(selection, context);
838
+ extraOrdering?.terms.forEach((term, index) => {
839
+ if (!extraOrdering.hidden[index]) return;
840
+ context.append(", ");
841
+ context.render(term.expression);
842
+ context.append(" AS " + context.dialect.quoteIdentifier(extraOrdering.names[index]));
843
+ });
844
844
  for (const clause of afterSelect) {
845
845
  if (clause.clauseKind === "correlate") continue;
846
846
  if (clause === distinctClause) continue;
@@ -852,7 +852,56 @@ function select(selection, ...parts) {
852
852
  continue;
853
853
  }
854
854
  context.append(" ");
855
- context.render(clause);
855
+ if (clause.clauseKind === "order-by" && extraOrdering) {
856
+ context.append("ORDER BY ");
857
+ extraOrdering.terms.forEach((term, index) => {
858
+ if (index) context.append(", ");
859
+ context.append(context.dialect.quoteIdentifier(extraOrdering.names[index]));
860
+ if (term.direction) context.append(` ${term.direction}`);
861
+ if (term.nulls) context.append(` NULLS ${term.nulls}`);
862
+ });
863
+ } else context.render(clause);
864
+ }
865
+ }
866
+ return Object.freeze({
867
+ ...query,
868
+ cardinality: normalizedClauses.some((clause) => clause.clauseKind === "fetch" && clause.rows <= 1) ? "zero-or-one" : normalizedClauses.every((clause) => [
869
+ "distinct",
870
+ "order-by",
871
+ "row-lock",
872
+ "with"
873
+ ].includes(clause.clauseKind)) ? "exactly-one" : "many",
874
+ renderJsonRows(context, ordinal) {
875
+ const terms = orderedClauses.find((clause) => clause.clauseKind === "order-by")?.terms ?? [];
876
+ if (orderedClauses.some((clause) => clause.clauseKind === "distinct") && terms.some((term) => !Object.values(selection).includes(term.expression))) throw new TypeError("Nested JSON DISTINCT ordering must use selected expressions");
877
+ const occupied = new Set(Object.keys(row).map(snakeCaseIdentifier));
878
+ occupied.add(ordinal);
879
+ const hidden = [];
880
+ const names = terms.map((term, index) => {
881
+ const selected = Object.entries(selection).find(([, expression]) => expression === term.expression);
882
+ hidden.push(selected === void 0);
883
+ if (selected) return snakeCaseIdentifier(selected[0]);
884
+ let name = `__qubu_json_sort_${index}`;
885
+ while (occupied.has(name)) name += "_";
886
+ occupied.add(name);
887
+ return name;
888
+ });
889
+ const quote = context.dialect.quoteIdentifier;
890
+ context.append(`SELECT ${quote("__qubu_ordered")}.*, DENSE_RANK() OVER (`);
891
+ if (terms.length) context.append("ORDER BY ");
892
+ terms.forEach((term, index) => {
893
+ if (index) context.append(", ");
894
+ context.append(`${quote("__qubu_ordered")}.${quote(names[index])}`);
895
+ if (term.direction) context.append(` ${term.direction}`);
896
+ if (term.nulls) context.append(` NULLS ${term.nulls}`);
897
+ });
898
+ context.append(`) AS ${quote(ordinal)} FROM (`);
899
+ renderBody(context, {
900
+ terms,
901
+ names,
902
+ hidden
903
+ });
904
+ context.append(`) AS ${quote("__qubu_ordered")}`);
856
905
  }
857
906
  });
858
907
  }
@@ -864,8 +913,10 @@ function setOperation(operator, left, right) {
864
913
  row: left.row,
865
914
  resultShape: left.resultShape,
866
915
  render: (context) => {
916
+ if (context.dialect.name === "sqlite") context.append("SELECT * FROM ");
867
917
  context.render(parenthesize(left));
868
918
  context.append(` ${operator} `);
919
+ if (context.dialect.name === "sqlite") context.append("SELECT * FROM ");
869
920
  context.render(parenthesize(right));
870
921
  }
871
922
  };
@@ -1241,6 +1292,30 @@ function insertSelect(query, columns) {
1241
1292
  function insertInto(table, source, ...clauses) {
1242
1293
  validateInsert(table, source);
1243
1294
  const insertClauses = clauses;
1295
+ const duplicate = insertClauses.find((clause) => clause.clauseKind === "on-duplicate-key-update");
1296
+ if (duplicate) {
1297
+ if (insertClauses.some((clause) => clause.clauseKind === "returning")) throw queryValidationError({
1298
+ code: "invalid-mutation",
1299
+ context: "insert.duplicate-key",
1300
+ path: ["returning"],
1301
+ message: "MySQL duplicate-key updates do not support RETURNING",
1302
+ hint: "Read the row in a separate query."
1303
+ });
1304
+ if (duplicate.table !== table) throw queryValidationError({
1305
+ code: "invalid-mutation",
1306
+ context: "insert.duplicate-key",
1307
+ path: ["onDuplicateKeyUpdate"],
1308
+ message: "Duplicate-key updates require the same INSERT target table",
1309
+ hint: "Pass the INSERT table to onDuplicateKeyUpdate()."
1310
+ });
1311
+ if (insertClauses.filter((clause) => clause.clauseKind === "on-duplicate-key-update" || clause.clauseKind === "on-conflict").length !== 1) throw queryValidationError({
1312
+ code: "duplicate-clause",
1313
+ context: "insert.duplicate-key",
1314
+ path: ["clauses"],
1315
+ message: "INSERT accepts one conflict clause",
1316
+ hint: "Use one onDuplicateKeyUpdate() clause."
1317
+ });
1318
+ }
1244
1319
  validateMutationWithClauses("INSERT", insertClauses);
1245
1320
  const withClause = insertClauses.find((clause) => clause.clauseKind === "with");
1246
1321
  return createMutation("insert", insertClauses.find((clause) => clause.clauseKind === "returning")?.row ?? {}, insertClauses.find((clause) => clause.clauseKind === "returning")?.resultShape ?? { fields: [] }, (context) => {
@@ -1255,7 +1330,7 @@ function insertInto(table, source, ...clauses) {
1255
1330
  const explicitColumns = Object.keys(rows[0] ?? {});
1256
1331
  const runtimeDefaultColumns = Object.entries(table.definitions).filter(([columnName, definition]) => !explicitColumns.includes(columnName) && definition.defaultFn !== void 0).map(([columnName]) => columnName);
1257
1332
  const columns = [...explicitColumns, ...runtimeDefaultColumns];
1258
- if (columns.length === 0) context.append(" DEFAULT VALUES");
1333
+ if (columns.length === 0) context.append(context.dialect.name === "mysql" ? ` () VALUES ${rows.map(() => "()").join(", ")}` : " DEFAULT VALUES");
1259
1334
  else {
1260
1335
  renderTargetColumns(context, table, columns);
1261
1336
  context.append(" VALUES ");
@@ -1272,7 +1347,7 @@ function insertInto(table, source, ...clauses) {
1272
1347
  }
1273
1348
  } else if (source.insertKind === "default-values") {
1274
1349
  const runtimeDefaults = Object.entries(table.definitions).filter(([, definition]) => definition.defaultFn !== void 0);
1275
- if (runtimeDefaults.length === 0) context.append(" DEFAULT VALUES");
1350
+ if (runtimeDefaults.length === 0) context.append(context.dialect.name === "mysql" ? " () VALUES ()" : " DEFAULT VALUES");
1276
1351
  else {
1277
1352
  renderTargetColumns(context, table, runtimeDefaults.map(([columnName]) => columnName));
1278
1353
  context.append(" VALUES (");
@@ -1285,12 +1360,41 @@ function insertInto(table, source, ...clauses) {
1285
1360
  } else {
1286
1361
  renderTargetColumns(context, table, source.columns);
1287
1362
  context.append(" ");
1288
- context.renderRelation(source.query);
1363
+ if (duplicate) {
1364
+ const fields = Object.keys(source.query.row);
1365
+ if (fields.length !== source.columns.length) throw queryValidationError({
1366
+ code: "invalid-insert",
1367
+ context: "insert.select.columns",
1368
+ path: ["insertSelect", "columns"],
1369
+ message: "INSERT SELECT target and projection lengths must match",
1370
+ hint: "Map every projected field to one insert column."
1371
+ });
1372
+ context.append("SELECT * FROM (SELECT ");
1373
+ fields.forEach((field, index) => {
1374
+ if (index) context.append(", ");
1375
+ context.render(identifier("__qubu_insert_source"));
1376
+ context.append(".");
1377
+ context.render(identifier(snakeCaseIdentifier(field)));
1378
+ context.append(" AS ");
1379
+ context.render(identifier(table.sqlNames[source.columns[index]] ?? source.columns[index]));
1380
+ });
1381
+ context.append(" FROM (");
1382
+ context.renderRelation(source.query);
1383
+ context.append(") AS ");
1384
+ context.render(identifier("__qubu_insert_source"));
1385
+ context.append(") AS ");
1386
+ context.render(identifier(incomingAlias(table)));
1387
+ } else context.renderRelation(source.query);
1388
+ }
1389
+ if (duplicate && source.insertKind !== "select") {
1390
+ context.append(" AS ");
1391
+ context.render(identifier(incomingAlias(table)));
1289
1392
  }
1290
1393
  for (const clause of insertClauses) {
1291
1394
  if (clause.clauseKind === "with") continue;
1292
1395
  context.append(" ");
1293
- context.render(clause);
1396
+ if (clause.clauseKind === "on-duplicate-key-update") renderDuplicateKeyUpdate(context, clause, source.insertKind === "select" ? source.columns : void 0);
1397
+ else context.render(clause);
1294
1398
  }
1295
1399
  });
1296
1400
  }
@@ -1304,7 +1408,7 @@ function renderTargetColumns(context, table, columns) {
1304
1408
  }
1305
1409
  function renderInsertValue(context, input, definition) {
1306
1410
  if (isExpression(input)) context.render(input);
1307
- else context.parameter(encodeColumnParameter(definition, input));
1411
+ else context.parameter(encodeColumnParameter(definition, input), columnSqlType(definition));
1308
1412
  }
1309
1413
  function validateInsert(table, source) {
1310
1414
  const definitions = table.definitions;
@@ -1457,7 +1561,7 @@ function update(table, assignments, ...clauses) {
1457
1561
  }
1458
1562
  function renderAssignmentValue(context, value, definition) {
1459
1563
  if (isExpression(value)) context.render(value);
1460
- else context.parameter(encodeColumnParameter(definition, value));
1564
+ else context.parameter(encodeColumnParameter(definition, value), columnSqlType(definition));
1461
1565
  }
1462
1566
  function validateUpdate(table, assignments) {
1463
1567
  const definitions = table.definitions;
@@ -1529,4 +1633,194 @@ function returning(selection) {
1529
1633
  });
1530
1634
  }
1531
1635
  //#endregion
1532
- export { QueryValidationError, ResultDecodingError, add, alias, all, allowAll, and, asValue, asc, avg, between, bigint, binary, boolean, booleanResultDecoder, call, caseWhen, cast, catalogCheck, catalogForeignKey, check, coalesce, column, concat, correlate, count, countDistinct, crossJoin, cte, date, dateResultDecoder, defaultValues, deleteFrom, denseRank, desc, distinct, divide, eq, except, execute, executeRows, exists, explain, externalDefault, externalGeneratedColumn, fetchFirst, fetchNext, foreignKey, from, fullJoin, generatedColumn, groupBy, gt, gte, having, identityColumn, inList, inQuery, index, innerJoin, insertInto, insertSelect, integer, intersect, isDistinctFrom, isNotDistinctFrom, isNotNull, isNull, isTrue, json, jsonBoolean, jsonExists, jsonNumber, jsonPath, jsonText, jsonTextResultDecoder, lateral, leftJoin, like, lower, lt, lte, mapResult, max, min, modulo, multiply, nativeColumn, nativeStorage, naturalJoin, ne, not, notExists, notIn, notLike, nullable, nullsFirst, nullsLast, numeric, offset, omit, or, order, orderBy, over, portableStorage, primaryKey, qubu, rank, recursiveCte, references, render, returning, rightJoin, rowLock, rowNumber, scalar, schema, schemaCall, select, sql, stream, subtract, sum, table, text, timestamp, timestampResultDecoder, union, unionAll, unique, uniqueConstraint, unsafeSchemaSql, update, upper, uuid, value, values, where, withCte };
1636
+ //#region src/expressions/nested-json.ts
1637
+ /**
1638
+ * Turn a SELECT or set query into an inferred array expression; empty queries return [].
1639
+ *
1640
+ * Preserves correlation, explicit ordering and pagination on PostgreSQL, MySQL 8.0.21+, and SQLite
1641
+ * 3.45+. Without ORDER BY, element order is unspecified. DISTINCT ordering must use expressions
1642
+ * present in the projection.
1643
+ *
1644
+ * Nested fields require supported runtime SQL domains. Bigints, binary values and serialized JSON
1645
+ * use exact text transport; dates and booleans are normalized without adapter-specific decoders.
1646
+ * Unsupported domains or lossy numeric representations throw. Custom result decoders receive the
1647
+ * transport value (including strings for bigint, decimal, binary hex and JSON), consistent with
1648
+ * their unknown-input contract.
1649
+ */
1650
+ function jsonArrayFrom(query) {
1651
+ return nestedJson(query, true);
1652
+ }
1653
+ /**
1654
+ * Turn a query proven to return at most one row into an inferred object.
1655
+ *
1656
+ * Empty queries return null; exactly-one queries retain a non-null result type. Use an
1657
+ * unconditional fetchFirst(1) to prove the row bound for a table query. Shares dialect, projection
1658
+ * and exact-decoding rules with {@link jsonArrayFrom}.
1659
+ *
1660
+ * @throws {TypeError} When the query lacks a runtime at-most-one-row proof.
1661
+ */
1662
+ function jsonObjectFrom(query) {
1663
+ if (query.cardinality !== "exactly-one" && query.cardinality !== "zero-or-one") throw new TypeError("jsonObjectFrom() requires a query proven to return at most one row");
1664
+ return nestedJson(query, false);
1665
+ }
1666
+ function nestedJson(query, array) {
1667
+ if (query.queryKind !== "select" && query.queryKind !== "set") throw new TypeError("Nested JSON requires a SELECT or set query");
1668
+ return makeExpression("subquery", (context) => renderNestedJson(context, query, array), "subquery", resultValue("json", (value, context) => {
1669
+ const parsed = typeof value === "string" ? parseExactJson(value) : value;
1670
+ if (array) {
1671
+ if (!Array.isArray(parsed)) throw new TypeError("Expected a nested JSON array");
1672
+ return parsed.map((row) => decodeNestedRow(row, query.resultShape, context));
1673
+ }
1674
+ return parsed === null ? null : decodeNestedRow(parsed, query.resultShape, context);
1675
+ }, "json"));
1676
+ }
1677
+ function renderNestedJson(context, query, array) {
1678
+ const dialect = context.dialect.name;
1679
+ if (dialect !== "postgresql" && dialect !== "sqlite" && dialect !== "mysql") throw new TypeError(`Nested JSON queries are not supported by dialect "${dialect}"`);
1680
+ const q = context.dialect.quoteIdentifier;
1681
+ const names = new Set(query.resultShape.fields.map((field) => snakeCaseIdentifier(field.name)));
1682
+ let ordinal = "__qubu_json_order";
1683
+ while (names.has(ordinal)) ordinal += "_";
1684
+ const ordered = array && query.renderJsonRows !== void 0;
1685
+ const reference = (name) => context.append(`${q("__qubu_json")}.${q(name)}`);
1686
+ const renderObject = () => {
1687
+ context.append(dialect === "postgresql" ? "json_build_object(" : "json_object(");
1688
+ query.resultShape.fields.forEach((field, index) => {
1689
+ if (index) context.append(", ");
1690
+ context.parameter(field.name, "text");
1691
+ if (dialect === "postgresql") context.append("::text");
1692
+ context.append(", ");
1693
+ const type = field.sqlType ?? field.type;
1694
+ const ref = () => reference(snakeCaseIdentifier(field.name));
1695
+ if (type === "decimal" && dialect === "sqlite") {
1696
+ context.append("CASE typeof(");
1697
+ ref();
1698
+ context.append(") WHEN 'real' THEN printf('%!.17g', ");
1699
+ ref();
1700
+ context.append(") WHEN 'integer' THEN CAST(");
1701
+ ref();
1702
+ context.append(" AS TEXT) WHEN 'null' THEN NULL ELSE json('invalid numeric storage') END");
1703
+ } else if (type === "bigint" || type === "decimal" || type === "json") {
1704
+ context.append("CAST(");
1705
+ ref();
1706
+ context.append(dialect === "mysql" ? " AS CHAR)" : " AS TEXT)");
1707
+ } else if (type === "binary") {
1708
+ if (dialect === "sqlite") {
1709
+ context.append("CASE WHEN ");
1710
+ ref();
1711
+ context.append(" IS NULL THEN NULL ELSE ");
1712
+ }
1713
+ context.append(dialect === "postgresql" ? "encode(" : "hex(");
1714
+ ref();
1715
+ context.append(dialect === "postgresql" ? ", 'hex')" : ")");
1716
+ if (dialect === "sqlite") context.append(" END");
1717
+ } else if (type === void 0 || type === "unknown" || ![
1718
+ "text",
1719
+ "uuid",
1720
+ "integer",
1721
+ "decimal",
1722
+ "boolean",
1723
+ "date",
1724
+ "timestamp",
1725
+ "json"
1726
+ ].includes(type)) throw new TypeError(`Nested JSON field "${field.name}" requires a supported declared SQL domain`);
1727
+ else ref();
1728
+ });
1729
+ context.append(")");
1730
+ };
1731
+ context.append(array ? "COALESCE((SELECT " : "(SELECT ");
1732
+ if (array) context.append(dialect === "postgresql" ? "json_agg(" : dialect === "sqlite" ? "json_group_array(" : "JSON_ARRAYAGG(");
1733
+ renderObject();
1734
+ if (array) {
1735
+ if (ordered && dialect !== "mysql") {
1736
+ context.append(" ORDER BY ");
1737
+ reference(ordinal);
1738
+ }
1739
+ context.append(")");
1740
+ if (dialect === "mysql") {
1741
+ context.append(" OVER (");
1742
+ if (ordered) {
1743
+ context.append("ORDER BY ");
1744
+ reference(ordinal);
1745
+ context.append(" ");
1746
+ }
1747
+ context.append("ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)");
1748
+ }
1749
+ }
1750
+ context.append(" FROM (");
1751
+ context.renderRelation(fragment((inner) => {
1752
+ if (ordered) query.renderJsonRows(inner, ordinal);
1753
+ else inner.render(query);
1754
+ }));
1755
+ context.append(`) AS ${q("__qubu_json")}`);
1756
+ if (array && dialect === "mysql") context.append(" LIMIT 1");
1757
+ context.append(")");
1758
+ if (array) context.append(dialect === "postgresql" ? ", '[]'::json)" : dialect === "mysql" ? ", JSON_ARRAY())" : ", json('[]'))");
1759
+ }
1760
+ function decodeNestedRow(value, shape, context) {
1761
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("Expected a nested JSON object");
1762
+ const row = value;
1763
+ const entries = shape.fields.map((field) => {
1764
+ if (!Object.hasOwn(row, field.name)) throw new TypeError(`Missing nested JSON field "${field.name}"`);
1765
+ return [field.name, decodeNestedField(row[field.name], field, context)];
1766
+ });
1767
+ return Object.fromEntries(entries);
1768
+ }
1769
+ function decodeNestedField(value, field, context) {
1770
+ if (value === null) return null;
1771
+ if (field.decoder) return field.decoder(value, {
1772
+ ...context,
1773
+ field: `${context.field}.${field.name}`
1774
+ });
1775
+ switch (field.type ?? field.sqlType) {
1776
+ case "bigint": return bigintResultDecoder(value, context);
1777
+ case "boolean": return booleanResultDecoder(value, context);
1778
+ case "date": return dateResultDecoder(value, context);
1779
+ case "timestamp": return timestampResultDecoder(value, context);
1780
+ case "json": return typeof value === "string" ? parseExactJson(value) : value;
1781
+ case "binary":
1782
+ if (typeof value !== "string" || !/^(?:[\da-f]{2})*$/iu.test(value)) throw new TypeError("Expected hexadecimal binary result");
1783
+ return Uint8Array.from(value.match(/../gu) ?? [], (byte) => parseInt(byte, 16));
1784
+ case "integer":
1785
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) throw new TypeError("Expected a safe integer result");
1786
+ return value;
1787
+ case "decimal":
1788
+ if (typeof value !== "string" && typeof value !== "number") throw new TypeError("Expected a numeric result");
1789
+ if (context.dialect.name === "sqlite") {
1790
+ canonicalDecimal(String(value));
1791
+ const number = Number(value);
1792
+ if (!Number.isFinite(number) || Number.isInteger(number) && !Number.isSafeInteger(number)) throw new TypeError("Expected a finite, safely represented SQLite number");
1793
+ return number;
1794
+ }
1795
+ return exactNumber(String(value));
1796
+ case "text":
1797
+ case "uuid":
1798
+ if (typeof value !== "string") throw new TypeError("Expected a text result");
1799
+ return value;
1800
+ default: throw new TypeError(`Unsupported nested JSON field "${field.name}"`);
1801
+ }
1802
+ }
1803
+ function exactNumber(value) {
1804
+ const number = Number(value);
1805
+ if (!Number.isFinite(number) || canonicalDecimal(value) !== canonicalDecimal(String(number))) throw new TypeError("Nested JSON numeric value cannot be represented exactly as a JavaScript number");
1806
+ if (Number.isInteger(number) && !Number.isSafeInteger(number)) throw new TypeError("Nested JSON integer exceeds JavaScript's safe integer range");
1807
+ return number;
1808
+ }
1809
+ function canonicalDecimal(value) {
1810
+ const match = /^([+-]?)(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$/u.exec(value);
1811
+ if (!match) throw new TypeError("Expected a decimal number");
1812
+ let digits = (match[2] + (match[3] ?? "")).replace(/^0+/u, "");
1813
+ if (!digits) return "0";
1814
+ let exponent = Number(match[4] ?? 0) - (match[3]?.length ?? 0);
1815
+ if (!Number.isSafeInteger(exponent)) throw new TypeError("Unsupported decimal exponent");
1816
+ const zeros = /0+$/u.exec(digits)?.[0].length ?? 0;
1817
+ digits = digits.slice(0, digits.length - zeros);
1818
+ exponent += zeros;
1819
+ return `${match[1] === "-" ? "-" : ""}${digits}e${exponent}`;
1820
+ }
1821
+ function parseExactJson(value) {
1822
+ for (const token of value.matchAll(/"(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/gu)) if (token[0][0] !== "\"") exactNumber(token[0]);
1823
+ return JSON.parse(value);
1824
+ }
1825
+ //#endregion
1826
+ export { QueryValidationError, ResultDecodingError, add, alias, all, allowAll, and, asValue, asc, avg, between, bigint, bigintResultDecoder, binary, boolean, booleanResultDecoder, call, caseWhen, cast, catalogCheck, catalogForeignKey, check, coalesce, column, concat, correlate, count, countDistinct, crossJoin, cte, date, dateResultDecoder, defaultValues, deleteFrom, denseRank, desc, distinct, divide, eq, except, execute, executeRows, exists, explain, externalDefault, externalGeneratedColumn, fetchFirst, fetchNext, foreignKey, from, fullJoin, generatedColumn, groupBy, gt, gte, having, identityColumn, inList, inQuery, index, innerJoin, insertInto, insertSelect, integer, intersect, isDistinctFrom, isNotDistinctFrom, isNotNull, isNull, isTrue, json, jsonArrayFrom, jsonBoolean, jsonExists, jsonNumber, jsonObjectFrom, jsonPath, jsonText, jsonTextResultDecoder, lateral, leftJoin, like, lower, lt, lte, mapResult, max, min, modulo, multiply, nativeColumn, nativeStorage, naturalJoin, ne, not, notExists, notIn, notLike, nullable, nullsFirst, nullsLast, numeric, offset, omit, or, order, orderBy, over, portableStorage, primaryKey, qubu, rank, recursiveCte, references, render, returning, rightJoin, rowLock, rowNumber, scalar, schema, schemaCall, select, sql, stream, subtract, sum, table, text, timestamp, timestampResultDecoder, union, unionAll, unique, uniqueConstraint, unsafeSchemaSql, update, upper, uuid, value, values, where, withCte };
@@ -1,4 +1,4 @@
1
- import { kt as CatalogConnection, st as IntrospectionCatalog, ut as IntrospectionOptions } from "../types-BEn0N_al.mjs";
1
+ import { ft as IntrospectionOptions, jt as CatalogConnection, lt as IntrospectionCatalog } from "../types-CiMvKi5V.mjs";
2
2
  //#region src/introspection/mysql.d.ts
3
3
  declare const mysqlServerQuery = "SELECT VERSION() AS version, @@version_comment AS version_comment";
4
4
  declare const mysqlTablesQuery = "\n SELECT TABLE_NAME AS table_name, TABLE_TYPE AS table_type,\n ENGINE AS engine, TABLE_COLLATION AS table_collation,\n CREATE_OPTIONS AS create_options, TABLE_COMMENT AS table_comment\n FROM INFORMATION_SCHEMA.TABLES\n WHERE TABLE_SCHEMA = ?\n ORDER BY TABLE_NAME\n";