qubu 0.3.5 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/{canonical-BbnqavJm.mjs → canonical-BXUguqfo.mjs} +23 -23
  2. package/dist/codegen.d.mts +25 -33
  3. package/dist/codegen.mjs +38 -45
  4. package/dist/column-hqKr7-1I.mjs +620 -0
  5. package/dist/{complete-D5Djh-zo.mjs → complete-WYyVozgK.mjs} +50 -50
  6. package/dist/{complete-types-B2PO6wQD.d.mts → complete-types-IjEn5VPN.d.mts} +56 -56
  7. package/dist/core.d.mts +2 -2
  8. package/dist/core.mjs +4 -4
  9. package/dist/ddl.d.mts +12 -12
  10. package/dist/ddl.mjs +13 -14
  11. package/dist/{dialect-b2-Z6uBF.mjs → dialect-wUKrnPMB.mjs} +2 -2
  12. package/dist/diff.d.mts +1 -1
  13. package/dist/diff.mjs +6 -7
  14. package/dist/{index-7qc6OcIC.d.mts → index-1DpA3mUh.d.mts} +20 -20
  15. package/dist/{index-CqWnouTK.d.mts → index-CPvfEheG.d.mts} +13 -15
  16. package/dist/index.d.mts +2 -2
  17. package/dist/index.mjs +148 -120
  18. package/dist/introspection.d.mts +8 -8
  19. package/dist/introspection.mjs +29 -30
  20. package/dist/{json-CUZlv4HT.mjs → json-Db7XRD91.mjs} +2 -2
  21. package/dist/migration.d.mts +20 -21
  22. package/dist/migration.mjs +5 -6
  23. package/dist/{mysql-DqkqXB6A.mjs → mysql-B_cYzzX2.mjs} +237 -7
  24. package/dist/mysql.d.mts +1 -1
  25. package/dist/mysql.mjs +3 -3
  26. package/dist/{on-conflict-BxnxubMb.mjs → on-conflict-hfPW0KmQ.mjs} +4 -4
  27. package/dist/postgres.d.mts +5 -5
  28. package/dist/postgres.mjs +6 -6
  29. package/dist/{registry-BufIskVN.mjs → registry-BRMLYwDp.mjs} +27 -135
  30. package/dist/{relational-DCZrrNia.mjs → relational-BZ3WDPzC.mjs} +4 -4
  31. package/dist/schema.d.mts +2 -2
  32. package/dist/schema.mjs +6 -6
  33. package/dist/{snapshot-CWPgzxNx.mjs → snapshot-C-W65HEd.mjs} +5 -5
  34. package/dist/snapshot.d.mts +3 -3
  35. package/dist/snapshot.mjs +5 -7
  36. package/dist/{source-DUoJVXmL.mjs → source-BcS2AsIg.mjs} +7 -9
  37. package/dist/{serialize-PF1cfH2P.mjs → sqlite-Cg0nwYEH.mjs} +326 -12
  38. package/dist/sqlite.d.mts +2 -2
  39. package/dist/sqlite.mjs +2 -2
  40. package/dist/{standard-BTVYKh_F.mjs → standard-DfcZEVOj.mjs} +1 -1
  41. package/dist/{table-CCUJ60rB.mjs → table-Bp5irMSj.mjs} +5 -7
  42. package/dist/{types-D8M1yZF4.d.mts → types-BK1COGZe.d.mts} +2661 -2150
  43. package/dist/{types-Cec0xzo4.mjs → types-JM3FcAnX.mjs} +8 -8
  44. package/dist/{types-LBt5rclR.d.mts → types-JSZHpUEj.d.mts} +83 -84
  45. package/dist/{value-BvilP0oz.mjs → value-Bi71Agyf.mjs} +1 -1
  46. package/dist/vite/ambient.d.ts +311 -390
  47. package/dist/vite.d.mts +5 -6
  48. package/dist/vite.mjs +3 -4
  49. package/docs/dialects-and-execution.md +121 -81
  50. package/docs/getting-started.md +4 -4
  51. package/docs/guides/better-auth.md +57 -0
  52. package/docs/guides/compose-queries.md +24 -67
  53. package/docs/guides/drizzle.md +23 -23
  54. package/docs/guides/extensions/dialects.md +4 -4
  55. package/docs/guides/extensions/sources-and-clauses.md +15 -15
  56. package/docs/guides/extensions/typed-expressions.md +13 -17
  57. package/docs/guides/extensions/unsafe-syntax.md +3 -3
  58. package/docs/guides/json.md +7 -7
  59. package/docs/guides/mutations.md +14 -21
  60. package/docs/guides/select/conditions.md +6 -8
  61. package/docs/guides/select/grouping-and-windows.md +4 -15
  62. package/docs/guides/select/ordering-and-pagination.md +6 -19
  63. package/docs/guides/select/overview.md +12 -26
  64. package/docs/guides/sql-templates.md +20 -24
  65. package/docs/guides/vite-plugin.md +9 -13
  66. package/docs/index.md +5 -7
  67. package/docs/query-model/fragments.md +4 -15
  68. package/docs/query-model/result-shapes.md +11 -14
  69. package/docs/query-model/source-scope.md +31 -49
  70. package/docs/reference/mysql-snapshot.md +2 -5
  71. package/docs/reference/postgres-snapshot.md +3 -3
  72. package/docs/reference/sqlite-snapshot.md +2 -5
  73. package/docs/reference/supported-surface.md +33 -33
  74. package/docs/schema/catalog-model.md +2 -5
  75. package/docs/schema/code-generation.md +18 -18
  76. package/docs/schema/columns-and-writes.md +17 -25
  77. package/docs/schema/constraints-and-indexes.md +36 -52
  78. package/docs/schema/ddl-emission.md +6 -6
  79. package/docs/schema/diff.md +5 -5
  80. package/docs/schema/introspection.md +7 -7
  81. package/docs/schema/migration-plans.md +9 -9
  82. package/docs/schema/snapshots.md +3 -3
  83. package/docs/schema/storage-and-schema-sql.md +11 -11
  84. package/docs/schema/tables-and-names.md +11 -14
  85. package/docs/sql-semantic-types.md +10 -10
  86. package/docs/troubleshooting.md +10 -10
  87. package/package.json +21 -33
  88. package/skills/qubu/agents/openai.yaml +3 -3
  89. package/dist/column-CXMxx8Hq.mjs +0 -118
  90. package/dist/column-CYMbKbOy.mjs +0 -290
  91. package/dist/drizzle-mysql.d.mts +0 -24
  92. package/dist/drizzle-mysql.mjs +0 -72
  93. package/dist/drizzle-postgres.d.mts +0 -24
  94. package/dist/drizzle-postgres.mjs +0 -73
  95. package/dist/drizzle-sqlite.d.mts +0 -50
  96. package/dist/drizzle-sqlite.mjs +0 -108
  97. package/dist/drizzle.d.mts +0 -13
  98. package/dist/drizzle.mjs +0 -2
  99. package/dist/errors-BGCoLe_r.mjs +0 -14
  100. package/dist/naming-QVCOnSj2.mjs +0 -20
  101. package/dist/postgres-DEBBeh52.mjs +0 -235
  102. package/dist/runtime-Cn_Xgzta.mjs +0 -193
  103. package/dist/sqlite-BU6DBxef.mjs +0 -320
  104. package/dist/types-Ctlxz1ip.d.mts +0 -45
package/dist/index.mjs CHANGED
@@ -1,15 +1,13 @@
1
- import { a as assertDialectCapability } from "./json-CUZlv4HT.mjs";
2
- import { c as render, n as call, o as cast, r as schemaCall, t as createClause } from "./types-Cec0xzo4.mjs";
1
+ import { a as assertDialectCapability } from "./json-Db7XRD91.mjs";
2
+ import { c as render, n as call, o as cast, r as schemaCall, t as createClause } from "./types-JM3FcAnX.mjs";
3
3
  import { n as queryValidationError, t as QueryValidationError } from "./errors-Dxv73YJu.mjs";
4
- import { c as makeExpression, h as parenthesize, i as identifier, l as makeSchemaExpression, m as isFragment, o as isExpression, p as fragment, t as createColumnReference, u as markExpressionCategory } from "./column-CXMxx8Hq.mjs";
5
- import { i as value, t as asValue } from "./value-BvilP0oz.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-DCZrrNia.mjs";
4
+ import { $ as dateResultDecoder, B as isSchemaExpression, D as identityColumn, E as generatedColumn, H as makeSchemaExpression, J as parenthesize, K as fragment, L as resolveSqlNames, Q as createResultShape, R as snakeCaseIdentifier, T as externalGeneratedColumn, U as markExpressionCategory, V as makeExpression, W as markSchemaExpression, X as ResultDecodingError, Z as booleanResultDecoder, _ as numeric, at as timestampResultDecoder, b as timestamp, c as boolean, d as date, et as decodeResultRow, f as integer, g as nullable, h as nativeStorage, i as identifier, it as resultValueOf, l as column, m as nativeColumn, nt as resultShapeValue, o as bigint, p as json, q as isFragment, rt as resultValue, s as binary, t as createColumnReference, tt as jsonTextResultDecoder, v as portableStorage, w as externalDefault, x as uuid, y as text, z as isExpression } from "./column-hqKr7-1I.mjs";
5
+ import { i as value, t as asValue } from "./value-Bi71Agyf.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-BZ3WDPzC.mjs";
7
7
  import { t as omit } from "./omit-OxV58AwX.mjs";
8
- import { n as snakeCaseIdentifier, t as resolveSqlNames } from "./naming-QVCOnSj2.mjs";
9
- import { r as exposeColumns, t as createSource } from "./source-DUoJVXmL.mjs";
10
- import { n as alias, r as lateral, t as table } from "./table-CCUJ60rB.mjs";
11
- import { C as index, S as unsafeSchemaSql, c as check, d as references, f as unique, i as schema, l as foreignKey, o as catalogCheck, p as uniqueConstraint, s as catalogForeignKey, u as primaryKey } from "./registry-BufIskVN.mjs";
12
- import { a as date, b as generatedColumn, c as nativeColumn, d as numeric, f as portableStorage, h as uuid, i as column, l as nativeStorage, m as timestamp, n as binary, o as integer, p as text, r as boolean, s as json, t as bigint, u as nullable, v as externalDefault, x as identityColumn, y as externalGeneratedColumn } from "./column-CYMbKbOy.mjs";
8
+ import { r as exposeColumns, t as createSource } from "./source-BcS2AsIg.mjs";
9
+ import { n as alias, r as lateral, t as table } from "./table-Bp5irMSj.mjs";
10
+ import { C as index, S as unsafeSchemaSql, c as check, d as references, f as unique, i as schema, l as foreignKey, o as catalogCheck, p as uniqueConstraint, s as catalogForeignKey, u as primaryKey } from "./registry-BRMLYwDp.mjs";
13
11
  //#region src/execution.ts
14
12
  function qubu(adapter) {
15
13
  const client = createClient(adapter);
@@ -68,22 +66,34 @@ function stream(first, second, options = {}) {
68
66
  const query = isQuery(first) ? first : second;
69
67
  const adapter = isQuery(first) ? second : first;
70
68
  assertStreamableQuery(query);
71
- return adapter.stream(createExecutionRequest(query, adapter, options));
69
+ const request = createExecutionRequest(query, adapter, options);
70
+ const dialect = options.dialect ?? adapter.dialect;
71
+ return decodeResultStream(adapter.stream(request), request, adapter, dialect);
72
72
  }
73
73
  async function executeInternal(first, second, options) {
74
74
  const query = isQuery(first) ? first : second;
75
75
  const adapter = isQuery(first) ? second : first;
76
76
  const request = createExecutionRequest(query, adapter, options);
77
- return adapter.execute(request);
77
+ const result = await adapter.execute(request);
78
+ const dialect = options.dialect ?? adapter.dialect;
79
+ return {
80
+ ...result,
81
+ rows: result.rows.map((row, rowIndex) => decodeResultRow(row, request.resultShape, adapter.decoders, dialect, rowIndex))
82
+ };
78
83
  }
79
84
  function createExecutionRequest(query, adapter, options) {
80
85
  const statement = render(query, { dialect: options.dialect ?? adapter.dialect });
81
86
  return Object.freeze({
82
87
  statement,
83
88
  queryKind: query.queryKind,
89
+ resultShape: query.resultShape,
84
90
  ...options.signal === void 0 ? {} : { signal: options.signal }
85
91
  });
86
92
  }
93
+ async function* decodeResultStream(rows, request, adapter, dialect) {
94
+ let rowIndex = 0;
95
+ for await (const row of rows) yield decodeResultRow(row, request.resultShape, adapter.decoders, dialect, rowIndex++);
96
+ }
87
97
  function createExplainRequest(query, adapter, options) {
88
98
  const request = createExecutionRequest(query, adapter, options);
89
99
  if (options.analyze === true && query.queryKind !== "select" && query.queryKind !== "set") throw queryValidationError({
@@ -124,6 +134,13 @@ function isQuery(value) {
124
134
  return "render" in value && typeof value.render === "function";
125
135
  }
126
136
  //#endregion
137
+ //#region src/expressions/map-result.ts
138
+ /** Attach an application decoder to an expression without changing its SQL. */
139
+ function mapResult(expression, decoder) {
140
+ const mapped = makeExpression(expression.expressionKind, (context) => context.render(expression), expression.expressionCategory, resultValue(resultValueOf(expression)?.type, decoder));
141
+ return isSchemaExpression(expression) ? markSchemaExpression(mapped) : mapped;
142
+ }
143
+ //#endregion
127
144
  //#region src/expressions/case.ts
128
145
  function caseWhen(condition, thenValue, elseValue) {
129
146
  const thenExpression = asValue(thenValue);
@@ -161,13 +178,13 @@ function createSqlTag() {
161
178
  const sqlTag = createSqlTag();
162
179
  sqlTag.type = createSqlTag;
163
180
  /**
164
- * Build trusted SQL syntax while binding every ordinary substitution as a
165
- * parameter. Qubu fragments remain composable substitutions.
181
+ * Build trusted SQL syntax while binding every ordinary substitution as a parameter. Qubu fragments
182
+ * remain composable substitutions.
166
183
  *
167
- * @remarks Template text is trusted and is not parsed. Use `identifier()` from
168
- * `qubu/core` for runtime identifiers and `unsafeExpression()` for deliberately
169
- * dynamic syntax. Use `sql.type<Output, SqlType>()` when the fragment's result
170
- * is known.
184
+ * @remarks
185
+ * Template text is trusted and is not parsed. Use `identifier()` from `qubu/core` for runtime
186
+ * identifiers and `unsafeExpression()` for deliberately dynamic syntax. Use `sql.type<Output,
187
+ * SqlType>()` when the fragment's result is known.
171
188
  */
172
189
  const sql = Object.freeze(sqlTag);
173
190
  function isQueryFragment(value) {
@@ -265,7 +282,7 @@ function scalar(query) {
265
282
  message: "scalar() requires a query with exactly one selected column",
266
283
  hint: "Select exactly one named field before wrapping the query in scalar()."
267
284
  });
268
- return makeExpression("subquery", (context) => context.renderRelation(parenthesize(query)));
285
+ return makeExpression("subquery", (context) => context.renderRelation(parenthesize(query)), "subquery", resultShapeValue(query.resultShape, Object.keys(query.row)[0]));
269
286
  }
270
287
  //#endregion
271
288
  //#region src/expressions/json.ts
@@ -294,7 +311,7 @@ function jsonScalar(document, path, kind) {
294
311
  assertDialectCapability(context.dialect, "json");
295
312
  if (!context.dialect.json) throw new Error(`Dialect "${context.dialect.name}" advertises JSON support without a JSON renderer`);
296
313
  context.dialect.json.renderScalar(context, document, path.segments, kind);
297
- });
314
+ }, kind === "boolean" ? resultValue("boolean") : void 0);
298
315
  }
299
316
  /** Extract a JSON string, returning SQL NULL for missing, null, or non-string values. */
300
317
  function jsonText(document, path) {
@@ -314,7 +331,7 @@ function jsonExists(document, path) {
314
331
  assertDialectCapability(context.dialect, "json");
315
332
  if (!context.dialect.json) throw new Error(`Dialect "${context.dialect.name}" advertises JSON support without a JSON renderer`);
316
333
  context.dialect.json.renderExists(context, document, path.segments);
317
- });
334
+ }, resultValue("boolean"));
318
335
  }
319
336
  //#endregion
320
337
  //#region src/expressions/operators/arithmetic.ts
@@ -349,7 +366,7 @@ function composeConditions(conditions, separator, name) {
349
366
  context.append("(");
350
367
  renderOperands(context, presentConditions, separator);
351
368
  context.append(")");
352
- });
369
+ }, resultValue("boolean"));
353
370
  }
354
371
  function and(...conditions) {
355
372
  return composeConditions(conditions, " AND ", "and");
@@ -362,7 +379,7 @@ function not(condition) {
362
379
  context.append("(NOT ");
363
380
  context.render(condition);
364
381
  context.append(")");
365
- });
382
+ }, resultValue("boolean"));
366
383
  }
367
384
  //#endregion
368
385
  //#region src/expressions/operators/comparison/range.ts
@@ -378,7 +395,7 @@ function between(expression, lower, upper) {
378
395
  context.append(" AND ");
379
396
  context.render(upperExpression);
380
397
  context.append(")");
381
- });
398
+ }, resultValue("boolean"));
382
399
  }
383
400
  function inList(expression, values) {
384
401
  const valueExpressions = values.map(expressionOperand);
@@ -395,7 +412,7 @@ function inList(expression, values) {
395
412
  context.render(value);
396
413
  });
397
414
  context.append("))");
398
- });
415
+ }, resultValue("boolean"));
399
416
  }
400
417
  function notIn(expression, values) {
401
418
  const valueExpressions = values.map(expressionOperand);
@@ -412,7 +429,7 @@ function notIn(expression, values) {
412
429
  context.render(value);
413
430
  });
414
431
  context.append("))");
415
- });
432
+ }, resultValue("boolean"));
416
433
  }
417
434
  //#endregion
418
435
  //#region src/expressions/operators/comparison/subquery.ts
@@ -423,19 +440,19 @@ function inQuery(expression, query) {
423
440
  context.append(" IN ");
424
441
  context.renderRelation(parenthesize(query));
425
442
  context.append(")");
426
- });
443
+ }, "subquery", resultValue("boolean"));
427
444
  }
428
445
  function exists(query) {
429
446
  return makeExpression("subquery", (context) => {
430
447
  context.append("EXISTS ");
431
448
  context.renderRelation(parenthesize(query));
432
- });
449
+ }, "subquery", resultValue("boolean"));
433
450
  }
434
451
  function notExists(query) {
435
452
  return makeExpression("subquery", (context) => {
436
453
  context.append("NOT EXISTS ");
437
454
  context.renderRelation(parenthesize(query));
438
- });
455
+ }, "subquery", resultValue("boolean"));
439
456
  }
440
457
  //#endregion
441
458
  //#region src/expressions/operators/comparison/null.ts
@@ -444,41 +461,110 @@ function isNull(expression) {
444
461
  context.append("(");
445
462
  context.render(expression);
446
463
  context.append(" IS NULL)");
447
- });
464
+ }, resultValue("boolean"));
448
465
  }
449
466
  function isNotNull(expression) {
450
467
  return makeSchemaExpression("operator", (context) => {
451
468
  context.append("(");
452
469
  context.render(expression);
453
470
  context.append(" IS NOT NULL)");
454
- });
471
+ }, resultValue("boolean"));
455
472
  }
456
473
  function isTrue(expression) {
457
474
  return makeSchemaExpression("operator", (context) => {
458
475
  context.render(expression);
459
476
  context.append(" IS TRUE");
460
- });
477
+ }, resultValue("boolean"));
461
478
  }
462
479
  //#endregion
463
480
  //#region src/query/selection.ts
464
481
  /**
465
482
  * Return every known source column as a named projection object.
466
483
  *
467
- * The result can be passed directly to `select()` or spread into a larger
468
- * projection, such as `{ ...all(users), displayName: upper(users.name) }`.
484
+ * The result can be passed directly to `select()` or spread into a larger projection, such as `{
485
+ * ...all(users), displayName: upper(users.name) }`.
469
486
  */
470
487
  function all(source) {
471
488
  return Object.freeze({ ...source.columns });
472
489
  }
490
+ /** Build the runtime field metadata for a named projection. */
491
+ function selectionResultShape(selection) {
492
+ return createResultShape(Object.entries(selection).filter(([, expression]) => expression !== omit).map(([name, expression]) => ({
493
+ name,
494
+ ...resultValueOf(expression)
495
+ })));
496
+ }
473
497
  //#endregion
474
- //#region src/query/types.ts
475
- function createQuery(queryKind, row, render) {
476
- return Object.freeze({
477
- queryKind,
478
- row,
479
- ...fragment(render)
498
+ //#region src/query/clauses/pagination.ts
499
+ function toPaginationPart(clause) {
500
+ return clause.clauseKind === "offset" ? {
501
+ kind: "offset",
502
+ rows: clause.rows
503
+ } : {
504
+ kind: "fetch",
505
+ rows: clause.rows,
506
+ direction: clause.direction
507
+ };
508
+ }
509
+ function renderPagination(context, clauses) {
510
+ const parts = clauses.map(toPaginationPart);
511
+ if (context.dialect.pagination) {
512
+ context.dialect.pagination.render(context, parts);
513
+ return;
514
+ }
515
+ parts.forEach((part, index) => {
516
+ if (index > 0) context.append(" ");
517
+ if (part.kind === "offset") {
518
+ context.append("OFFSET ");
519
+ context.parameter(part.rows);
520
+ context.append(" ROWS");
521
+ } else {
522
+ context.append(`FETCH ${part.direction} `);
523
+ context.parameter(part.rows);
524
+ context.append(" ROWS ONLY");
525
+ }
526
+ });
527
+ }
528
+ function offset(rows) {
529
+ if (!Number.isInteger(rows) || rows < 0) throw queryValidationError({
530
+ code: "invalid-pagination",
531
+ context: "select.pagination.offset",
532
+ path: ["offset"],
533
+ message: "offset() requires a non-negative integer",
534
+ hint: "Pass a non-negative integer row count."
535
+ });
536
+ return Object.assign(createClause("offset", "after-select", 90, (context) => renderPagination(context, [{
537
+ clauseKind: "offset",
538
+ rows
539
+ }])), {
540
+ clauseKind: "offset",
541
+ rows
542
+ });
543
+ }
544
+ function fetchRows(direction, rows) {
545
+ if (!Number.isInteger(rows) || rows < 0) throw queryValidationError({
546
+ code: "invalid-pagination",
547
+ context: `select.pagination.fetch${direction === "FIRST" ? "First" : "Next"}`,
548
+ path: ["fetch", direction],
549
+ message: "fetch rows require a non-negative integer",
550
+ hint: "Pass a non-negative integer row count."
551
+ });
552
+ return Object.assign(createClause("fetch", "after-select", 100, (context) => renderPagination(context, [{
553
+ clauseKind: "fetch",
554
+ direction,
555
+ rows
556
+ }])), {
557
+ clauseKind: "fetch",
558
+ direction,
559
+ rows
480
560
  });
481
561
  }
562
+ function fetchFirst(rows) {
563
+ return fetchRows("FIRST", rows);
564
+ }
565
+ function fetchNext(rows) {
566
+ return fetchRows("NEXT", rows);
567
+ }
482
568
  //#endregion
483
569
  //#region src/query/select/render.ts
484
570
  function renderSelection(selection, context) {
@@ -550,76 +636,15 @@ function validateClauses(clauses) {
550
636
  }
551
637
  }
552
638
  //#endregion
553
- //#region src/query/clauses/pagination.ts
554
- function toPaginationPart(clause) {
555
- return clause.clauseKind === "offset" ? {
556
- kind: "offset",
557
- rows: clause.rows
558
- } : {
559
- kind: "fetch",
560
- rows: clause.rows,
561
- direction: clause.direction
562
- };
563
- }
564
- function renderPagination(context, clauses) {
565
- const parts = clauses.map(toPaginationPart);
566
- if (context.dialect.pagination) {
567
- context.dialect.pagination.render(context, parts);
568
- return;
569
- }
570
- parts.forEach((part, index) => {
571
- if (index > 0) context.append(" ");
572
- if (part.kind === "offset") {
573
- context.append("OFFSET ");
574
- context.parameter(part.rows);
575
- context.append(" ROWS");
576
- } else {
577
- context.append(`FETCH ${part.direction} `);
578
- context.parameter(part.rows);
579
- context.append(" ROWS ONLY");
580
- }
581
- });
582
- }
583
- function offset(rows) {
584
- if (!Number.isInteger(rows) || rows < 0) throw queryValidationError({
585
- code: "invalid-pagination",
586
- context: "select.pagination.offset",
587
- path: ["offset"],
588
- message: "offset() requires a non-negative integer",
589
- hint: "Pass a non-negative integer row count."
590
- });
591
- return Object.assign(createClause("offset", "after-select", 90, (context) => renderPagination(context, [{
592
- clauseKind: "offset",
593
- rows
594
- }])), {
595
- clauseKind: "offset",
596
- rows
597
- });
598
- }
599
- function fetchRows(direction, rows) {
600
- if (!Number.isInteger(rows) || rows < 0) throw queryValidationError({
601
- code: "invalid-pagination",
602
- context: `select.pagination.fetch${direction === "FIRST" ? "First" : "Next"}`,
603
- path: ["fetch", direction],
604
- message: "fetch rows require a non-negative integer",
605
- hint: "Pass a non-negative integer row count."
606
- });
607
- return Object.assign(createClause("fetch", "after-select", 100, (context) => renderPagination(context, [{
608
- clauseKind: "fetch",
609
- direction,
610
- rows
611
- }])), {
612
- clauseKind: "fetch",
613
- direction,
614
- rows
639
+ //#region src/query/types.ts
640
+ function createQuery(queryKind, row, resultShape, render) {
641
+ return Object.freeze({
642
+ queryKind,
643
+ row,
644
+ resultShape,
645
+ ...fragment(render)
615
646
  });
616
647
  }
617
- function fetchFirst(rows) {
618
- return fetchRows("FIRST", rows);
619
- }
620
- function fetchNext(rows) {
621
- return fetchRows("NEXT", rows);
622
- }
623
648
  //#endregion
624
649
  //#region src/query/select.ts
625
650
  function select(selection, ...parts) {
@@ -629,7 +654,7 @@ function select(selection, ...parts) {
629
654
  clause,
630
655
  index
631
656
  })).sort((left, right) => left.clause.order - right.clause.order || left.index - right.index).map(({ clause }) => clause);
632
- return createQuery("select", selectionRow(selection), (context) => {
657
+ return createQuery("select", selectionRow(selection), selectionResultShape(selection), (context) => {
633
658
  const beforeSelect = orderedClauses.filter((clause) => clause.placement === "before-select");
634
659
  const afterSelect = orderedClauses.filter((clause) => clause.placement === "after-select");
635
660
  const paginationClauses = afterSelect.filter((clause) => clause.clauseKind === "offset" || clause.clauseKind === "fetch");
@@ -667,6 +692,7 @@ function setOperation(operator, left, right) {
667
692
  return {
668
693
  queryKind: "set",
669
694
  row: left.row,
695
+ resultShape: left.resultShape,
670
696
  render: (context) => {
671
697
  context.render(parenthesize(left));
672
698
  context.append(` ${operator} `);
@@ -889,7 +915,7 @@ function cte(name, query) {
889
915
  const reference = identifier(name);
890
916
  const source = createSource("cte", (context) => context.render(reference), reference);
891
917
  const sqlNames = resolveSqlNames(Object.keys(query.row).map((fieldName) => ({ fieldName })));
892
- const columns = Object.fromEntries(Object.keys(query.row).map((fieldName) => [fieldName, createColumnReference(sqlNames[fieldName], reference, fieldName)]));
918
+ const columns = Object.fromEntries(Object.keys(query.row).map((fieldName) => [fieldName, createColumnReference(sqlNames[fieldName], reference, fieldName, resultShapeValue(query.resultShape, fieldName))]));
893
919
  Object.assign(source, {
894
920
  cteName: name,
895
921
  query,
@@ -899,15 +925,15 @@ function cte(name, query) {
899
925
  return source;
900
926
  }
901
927
  /**
902
- * Define a typed recursive `WITH` source from an anchor and one recursive
903
- * member. The callback receives a forward reference that must be introduced
904
- * through the member query's normal FROM or JOIN scope.
928
+ * Define a typed recursive `WITH` source from an anchor and one recursive member. The callback
929
+ * receives a forward reference that must be introduced through the member query's normal FROM or
930
+ * JOIN scope.
905
931
  */
906
932
  function recursiveCte(name, anchor, member) {
907
933
  const reference = identifier(name);
908
934
  const source = createSource("cte", (context) => context.render(reference), reference);
909
935
  const sqlNames = resolveSqlNames(Object.keys(anchor.row).map((fieldName) => ({ fieldName })));
910
- const columns = Object.fromEntries(Object.keys(anchor.row).map((fieldName) => [fieldName, createColumnReference(sqlNames[fieldName], reference, fieldName)]));
936
+ const columns = Object.fromEntries(Object.keys(anchor.row).map((fieldName) => [fieldName, createColumnReference(sqlNames[fieldName], reference, fieldName, resultShapeValue(anchor.resultShape, fieldName))]));
911
937
  Object.assign(source, {
912
938
  cteName: name,
913
939
  query: anchor,
@@ -916,7 +942,7 @@ function recursiveCte(name, anchor, member) {
916
942
  exposeColumns(source, columns);
917
943
  const memberQuery = member(source);
918
944
  const query = Object.freeze({
919
- ...createQuery("set", anchor.row, (context) => {
945
+ ...createQuery("set", anchor.row, anchor.resultShape, (context) => {
920
946
  context.render(anchor);
921
947
  context.append(" UNION ALL ");
922
948
  context.render(memberQuery);
@@ -951,10 +977,11 @@ function withCte(...ctes) {
951
977
  }
952
978
  //#endregion
953
979
  //#region src/query/mutation/types.ts
954
- function createMutation(queryKind, row, render) {
980
+ function createMutation(queryKind, row, resultShape, render) {
955
981
  return {
956
982
  queryKind,
957
983
  row,
984
+ resultShape,
958
985
  render
959
986
  };
960
987
  }
@@ -1025,7 +1052,7 @@ function insertSelect(query, columns) {
1025
1052
  function insertInto(table, source, ...clauses) {
1026
1053
  validateInsert(table, source);
1027
1054
  const insertClauses = clauses;
1028
- return createMutation("insert", insertClauses.find((clause) => clause.clauseKind === "returning")?.row ?? {}, (context) => {
1055
+ return createMutation("insert", insertClauses.find((clause) => clause.clauseKind === "returning")?.row ?? {}, insertClauses.find((clause) => clause.clauseKind === "returning")?.resultShape ?? { fields: [] }, (context) => {
1029
1056
  context.append("INSERT INTO ");
1030
1057
  context.render(table.reference);
1031
1058
  if (source.insertKind === "values") {
@@ -1187,7 +1214,7 @@ function update(table, assignments, ...clauses) {
1187
1214
  const entries = validateUpdate(table, assignments);
1188
1215
  const whereClause = normalizedClauses.find((clause) => clause.clauseKind === "where");
1189
1216
  const returningClause = normalizedClauses.find((clause) => clause.clauseKind === "returning");
1190
- return createMutation("update", returningClause?.row ?? {}, (context) => {
1217
+ return createMutation("update", returningClause?.row ?? {}, returningClause?.resultShape ?? { fields: [] }, (context) => {
1191
1218
  context.append("UPDATE ");
1192
1219
  context.render(table.reference);
1193
1220
  context.append(" SET ");
@@ -1247,7 +1274,7 @@ function deleteFrom(table, ...clauses) {
1247
1274
  validateMutationClauses("DELETE", normalizedClauses);
1248
1275
  const whereClause = normalizedClauses.find((clause) => clause.clauseKind === "where");
1249
1276
  const returningClause = normalizedClauses.find((clause) => clause.clauseKind === "returning");
1250
- return createMutation("delete", returningClause?.row ?? {}, (context) => {
1277
+ return createMutation("delete", returningClause?.row ?? {}, returningClause?.resultShape ?? { fields: [] }, (context) => {
1251
1278
  context.append("DELETE FROM ");
1252
1279
  context.render(table.reference);
1253
1280
  if (whereClause) {
@@ -1267,6 +1294,7 @@ function returning(selection) {
1267
1294
  clauseKind: "returning",
1268
1295
  selection,
1269
1296
  row: selectionRow(selection),
1297
+ resultShape: selectionResultShape(selection),
1270
1298
  render(context) {
1271
1299
  context.append("RETURNING ");
1272
1300
  renderSelection(selection, context);
@@ -1274,4 +1302,4 @@ function returning(selection) {
1274
1302
  });
1275
1303
  }
1276
1304
  //#endregion
1277
- export { QueryValidationError, add, alias, all, allowAll, and, asValue, asc, avg, between, bigint, binary, boolean, call, caseWhen, cast, catalogCheck, catalogForeignKey, check, coalesce, column, concat, correlate, count, countDistinct, crossJoin, cte, date, 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, lateral, leftJoin, like, lower, lt, lte, 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, union, unionAll, unique, uniqueConstraint, unsafeSchemaSql, update, upper, uuid, value, values, where, withCte };
1305
+ 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 };
@@ -1,10 +1,10 @@
1
- import { $ as CatalogTrigger, A as CatalogNamespace, At as CatalogQuery, B as CatalogPrimaryKeyConstraint, C as CatalogForeignKeyTarget, Ct as IntrospectionDiagnosticCode, D as CatalogIndexTerm, Dt as createIntrospectionDiagnostic, E as CatalogIndex, Et as IntrospectionError, F as CatalogOpaqueObject, G as CatalogRoutine, H as CatalogProvenanceKind, I as CatalogOwnership, J as CatalogSequence, K as CatalogRoutineParameter, L as CatalogPartition, M as CatalogObjectBase, N as CatalogObjectMetadata, O as CatalogIntrospector, Ot as hasIntrospectionErrors, P as CatalogObjectReference, Q as CatalogTable, R as CatalogPolicy, S as CatalogForeignKeyConstraint, St as IntrospectionDiagnostic, T as CatalogIdentity, Tt as IntrospectionDiagnosticSeverity, U as CatalogQueryRow, V as CatalogProvenance, W as CatalogReference, X as CatalogSqlExpression, Y as CatalogServerInfo, Z as CatalogStorageType, _ as CatalogEntityReference, _t as CatalogIdentityPolicy, a as CatalogCollation, at as CatalogView, b as CatalogExpressionFact, bt as CatalogResolvedIdentity, c as CatalogCompleteObject, ct as IntrospectionFailure, d as CatalogDeferredObject, dt as IntrospectionResult, et as CatalogUniqueConstraint, f as CatalogDeferredObjectKind, ft as IntrospectionSuccess, g as CatalogEntityKind, gt as CatalogIdentityHints, h as CatalogDomain, ht as CatalogIdentityHint, i as CatalogClassificationConfidence, it as CatalogVersion, j as CatalogObject, jt as CatalogQueryOptions, k as CatalogLiteralFact, kt as CatalogConnection, l as CatalogConstraint, lt as IntrospectionMode, m as CatalogDialectExtension, mt as CatalogIdentityFallback, n as CatalogCatalogReference, nt as CatalogUnknownObject, o as CatalogColumn, ot as CompleteIntrospectionCatalog, p as CatalogDialect, pt as CatalogIdentityEntityKind, q as CatalogScalar, r as CatalogCheckConstraint, rt as CatalogValueFact, s as CatalogComment, st as IntrospectionCatalog, t as CatalogCapabilities, tt as CatalogUnknownField, u as CatalogData, ut as IntrospectionOptions, v as CatalogEnum, vt as CatalogIdentitySource, w as CatalogGeneratedColumn, wt as IntrospectionDiagnosticInput, x as CatalogExtensionObject, xt as introspectedPhysicalIdentityPolicy, y as CatalogEnumValue, yt as CatalogPreviousSnapshotIdentitySource, z as CatalogPortableStorageType } from "./types-LBt5rclR.mjs";
2
- import { t as CompleteSchemaSnapshot } from "./complete-types-B2PO6wQD.mjs";
1
+ import { $ as CatalogTrigger, A as CatalogNamespace, At as CatalogQuery, B as CatalogPrimaryKeyConstraint, C as CatalogForeignKeyTarget, Ct as IntrospectionDiagnosticCode, D as CatalogIndexTerm, Dt as createIntrospectionDiagnostic, E as CatalogIndex, Et as IntrospectionError, F as CatalogOpaqueObject, G as CatalogRoutine, H as CatalogProvenanceKind, I as CatalogOwnership, J as CatalogSequence, K as CatalogRoutineParameter, L as CatalogPartition, M as CatalogObjectBase, N as CatalogObjectMetadata, O as CatalogIntrospector, Ot as hasIntrospectionErrors, P as CatalogObjectReference, Q as CatalogTable, R as CatalogPolicy, S as CatalogForeignKeyConstraint, St as IntrospectionDiagnostic, T as CatalogIdentity, Tt as IntrospectionDiagnosticSeverity, U as CatalogQueryRow, V as CatalogProvenance, W as CatalogReference, X as CatalogSqlExpression, Y as CatalogServerInfo, Z as CatalogStorageType, _ as CatalogEntityReference, _t as CatalogIdentityPolicy, a as CatalogCollation, at as CatalogView, b as CatalogExpressionFact, bt as CatalogResolvedIdentity, c as CatalogCompleteObject, ct as IntrospectionFailure, d as CatalogDeferredObject, dt as IntrospectionResult, et as CatalogUniqueConstraint, f as CatalogDeferredObjectKind, ft as IntrospectionSuccess, g as CatalogEntityKind, gt as CatalogIdentityHints, h as CatalogDomain, ht as CatalogIdentityHint, i as CatalogClassificationConfidence, it as CatalogVersion, j as CatalogObject, jt as CatalogQueryOptions, k as CatalogLiteralFact, kt as CatalogConnection, l as CatalogConstraint, lt as IntrospectionMode, m as CatalogDialectExtension, mt as CatalogIdentityFallback, n as CatalogCatalogReference, nt as CatalogUnknownObject, o as CatalogColumn, ot as CompleteIntrospectionCatalog, p as CatalogDialect, pt as CatalogIdentityEntityKind, q as CatalogScalar, r as CatalogCheckConstraint, rt as CatalogValueFact, s as CatalogComment, st as IntrospectionCatalog, t as CatalogCapabilities, tt as CatalogUnknownField, u as CatalogData, ut as IntrospectionOptions, v as CatalogEnum, vt as CatalogIdentitySource, w as CatalogGeneratedColumn, wt as IntrospectionDiagnosticInput, x as CatalogExtensionObject, xt as introspectedPhysicalIdentityPolicy, y as CatalogEnumValue, yt as CatalogPreviousSnapshotIdentitySource, z as CatalogPortableStorageType } from "./types-JSZHpUEj.mjs";
2
+ import { t as CompleteSchemaSnapshot } from "./complete-types-IjEn5VPN.mjs";
3
3
  //#region src/introspection/catalog.d.ts
4
4
  /**
5
- * Materialize every optional object-family collection and deeply freeze the
6
- * normalized catalog. Catalog text and extension data remain values; this
7
- * helper never evaluates SQL or assigns persisted logical identities.
5
+ * Materialize every optional object-family collection and deeply freeze the normalized catalog.
6
+ * Catalog text and extension data remain values; this helper never evaluates SQL or assigns
7
+ * persisted logical identities.
8
8
  */
9
9
  declare function createCompleteIntrospectionCatalog(catalog: IntrospectionCatalog): CompleteIntrospectionCatalog;
10
10
  /** Alias for callers that already use the normalized-catalog terminology. */
@@ -27,9 +27,9 @@ type CompleteSnapshotMappingResult = {
27
27
  readonly lossy: false;
28
28
  };
29
29
  /**
30
- * Map a normalized catalog to strict Snapshot v2 data. This is intentionally
31
- * separate from the Snapshot v1 mapper: complete objects are never fabricated
32
- * as tables, and catalog references remain evidence rather than logical IDs.
30
+ * Map a normalized catalog to strict Snapshot v2 data. This is intentionally separate from the
31
+ * Snapshot v1 mapper: complete objects are never fabricated as tables, and catalog references
32
+ * remain evidence rather than logical IDs.
33
33
  */
34
34
  declare function mapCatalogToCompleteSnapshot(input: IntrospectionCatalog): CompleteSnapshotMappingResult;
35
35
  /** Numbered alias for callers that keep both snapshot mappers available. */