kern-orm 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as createList, C as isType, D as isEqualityCompatible, F as oneNode, I as trueNode, M as createSelectNode, N as falseNode, O as valuesQueryNode, P as noFilters, S as defineType, T as equalityOperators, _ as toBooleanExpression, a as stringifyJson, b as toValueNode, c as textOperators, d as compareNodes, f as createIsNullNode, g as operandNode, h as isOperandSource, j as createNode, k as defineGenericOperator, l as orderingOperators, m as isExpression, n as text, p as getType, s as encodeBytea, u as compare, v as toExpression, w as Column, x as getBooleanType, y as toNode } from "./text-BUNl8wpl.mjs";
1
+ import { B as trueNode, C as toNode, D as isType, E as defineType, F as createNode, I as createSelectNode, L as falseNode, M as valuesQueryNode, N as defineGenericOperator, O as Column, P as createList, R as noFilters, S as toFunctionOperandNode, T as getBooleanType, _ as isOperandSource, a as stringifyJson, b as toCastValueNode, c as textOperators, d as orderingOperators, f as compare, g as isExpression, h as getType, j as isEqualityCompatible, k as equalityOperators, m as createIsNullNode, n as text, p as compareNodes, s as encodeBytea, v as operandNode, w as toValueNode, x as toExpression, y as toBooleanExpression, z as oneNode } from "./text-BTFErHIi.mjs";
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
3
  // src/ast/boolean.ts
4
4
  /** Combines predicate nodes with `AND` or `OR`, flattening nested groups of the same kind. */
@@ -33,14 +33,21 @@ function combineFilters(filters) {
33
33
  return combineNodes("and", operands);
34
34
  }
35
35
  // src/expression/predicates.ts
36
- /** Converts a condition operand into a node: a query nests in it, and an object of column values stays unresolved until `where`. */
36
+ /** Converts a condition operand into a node: a query nests in it, and an object of column values stays unresolved until `where`; it rejects any other value. */
37
37
  function toConditionNode(operand) {
38
38
  if (isOperandSource(operand)) return operand[operandNode]();
39
+ if (!isColumnValues(operand)) throw new TypeError("A condition must be an expression, such as TRUE or FALSE, a query of one Boolean value, or an object of column values");
39
40
  return createNode({
40
41
  kind: "values",
41
42
  values: operand
42
43
  });
43
44
  }
45
+ /** Tells whether `value` can be an object of column values: a plain object, of this or another realm, or an object that has keys. */
46
+ function isColumnValues(value) {
47
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
48
+ const prototype = Object.getPrototypeOf(value);
49
+ return prototype === null || Object.getPrototypeOf(prototype) === null || Object.keys(value).length > 0;
50
+ }
44
51
  function and(...operands) {
45
52
  return combineConditions("and", operands);
46
53
  }
@@ -55,6 +62,244 @@ function combineConditions(kind, operands) {
55
62
  for (const operand of operands) nodes.push(toConditionNode(operand));
56
63
  return toBooleanExpression(combineNodes(kind, nodes));
57
64
  }
65
+ // src/expression/constants.ts
66
+ /** Condition that always holds, such as for a branch of `and` built in code: `and(check, isAdmin ? TRUE : other)`. */
67
+ const TRUE = /* @__PURE__ */ toExpression(trueNode, /* @__PURE__ */ getBooleanType());
68
+ /** Condition that never holds, such as for a branch of `or` built in code: `or(check, isAdmin ? other : FALSE)`. */
69
+ const FALSE = /* @__PURE__ */ toExpression(falseNode, /* @__PURE__ */ getBooleanType());
70
+ // src/query/literal.ts
71
+ /**
72
+ * Field of a selection whose value is `T`, made by `literal`.
73
+ *
74
+ * It is not an expression: it has no SQL, so only a selection takes it.
75
+ */
76
+ var Literal = class {
77
+ literal;
78
+ constructor(literal) {
79
+ this.literal = literal;
80
+ Object.freeze(this);
81
+ }
82
+ /** Rejects the literal as an operand of an expression: a statement has no SQL of it. */
83
+ [operandNode]() {
84
+ throw new TypeError("A literal is only a selected field and has no SQL; pass a value to an expression through param");
85
+ }
86
+ };
87
+ /**
88
+ * Creates a field of a selection with `value` in every record, without selecting anything in SQL: the query returns the value itself, not a copy of it, whatever it is.
89
+ *
90
+ * It lets a branch of a selection skip a column or a nested query, such as `withHint ? field.hint : literal(null)`.
91
+ * To use a value in SQL, such as in a condition, pass it through `param` instead.
92
+ */
93
+ function literal(value) {
94
+ return new Literal(value);
95
+ }
96
+ // src/query/exists.ts
97
+ let existsProjection;
98
+ /** Returns the projection of whether a query has a row, the only projection of a query made by `exists`. */
99
+ function getExistsProjection() {
100
+ existsProjection ??= Object.freeze({
101
+ key: "exists",
102
+ expression: trueNode,
103
+ type: getBooleanType()
104
+ });
105
+ return existsProjection;
106
+ }
107
+ /** Tells whether `node` is a query of `exists`, whose value is whether the rows that its filters, limit, and offset choose exist. */
108
+ function isExistsQuery(node) {
109
+ return node.value && isExistsProjection(node.projections[0]);
110
+ }
111
+ /** Tells whether a selected field is the projection of `exists`, which only `exists` selects. */
112
+ function isExistsProjection(field) {
113
+ return field === existsProjection;
114
+ }
115
+ // src/query/aggregate.ts
116
+ /** Type of a count: a `bigint` of PostgreSQL decoded as a number, rejecting a count that a number cannot hold exactly. */
117
+ const countType = /* @__PURE__ */ defineType({ sqlType: "bigint" }).transform({
118
+ decode: (text) => decodeSafeInteger(text, "Count"),
119
+ encode: (value) => String(value)
120
+ }).withOperators(orderingOperators);
121
+ /** Types of the sums of the values of `smallint` and `integer` types, by the type of the values, created once for each. */
122
+ const sumTypes = /* @__PURE__ */ new WeakMap();
123
+ const noFallbacks = /* @__PURE__ */ Object.freeze([]);
124
+ /** Definitions of the aggregate methods that take a column or an expression. */
125
+ const aggregateDefinitions = /* @__PURE__ */ Object.freeze({
126
+ count: {
127
+ name: "count",
128
+ distinct: false,
129
+ ordered: false,
130
+ type: toCountType
131
+ },
132
+ countDistinct: {
133
+ name: "count",
134
+ distinct: true,
135
+ ordered: false,
136
+ type: toCountType
137
+ },
138
+ min: {
139
+ name: "min",
140
+ distinct: false,
141
+ ordered: false,
142
+ type: toArgumentType
143
+ },
144
+ max: {
145
+ name: "max",
146
+ distinct: false,
147
+ ordered: false,
148
+ type: toArgumentType
149
+ },
150
+ sum: {
151
+ name: "sum",
152
+ distinct: false,
153
+ ordered: false,
154
+ type: toSumType
155
+ },
156
+ avg: {
157
+ name: "avg",
158
+ distinct: false,
159
+ ordered: false,
160
+ type: toAverageType
161
+ },
162
+ every: {
163
+ name: "bool_and",
164
+ distinct: false,
165
+ ordered: false,
166
+ type: toArgumentType
167
+ },
168
+ some: {
169
+ name: "bool_or",
170
+ distinct: false,
171
+ ordered: false,
172
+ type: toArgumentType
173
+ },
174
+ stringAgg: {
175
+ name: "string_agg",
176
+ distinct: false,
177
+ ordered: true,
178
+ type: toArgumentType
179
+ }
180
+ });
181
+ /** Projection of `count(*)`, which `count` without an argument selects; its value does not depend on the values or the order of the rows. */
182
+ const countProjection = /* @__PURE__ */ Object.freeze({
183
+ key: "count",
184
+ expression: /* @__PURE__ */ createNode({
185
+ kind: "aggregate",
186
+ name: "count",
187
+ distinct: false,
188
+ arguments: [/* @__PURE__ */ createNode({
189
+ kind: "raw",
190
+ fragments: ["*"],
191
+ values: []
192
+ })],
193
+ orderBy: []
194
+ }),
195
+ type: countType,
196
+ ordered: false,
197
+ fallbacks: noFallbacks
198
+ });
199
+ /**
200
+ * Creates the projection of the aggregate of `method` over the values of `argument`, the projection of a column or an expression of each row.
201
+ *
202
+ * `delimiter` is the delimiter of `stringAgg`, sent as a parameter.
203
+ */
204
+ function projectAggregate(method, argument, delimiter) {
205
+ const definition = aggregateDefinitions[method];
206
+ const args = [argument.expression];
207
+ if (delimiter !== void 0) args.push(createNode({
208
+ kind: "param",
209
+ value: delimiter,
210
+ type: void 0
211
+ }));
212
+ return Object.freeze({
213
+ key: method,
214
+ expression: createNode({
215
+ kind: "aggregate",
216
+ name: definition.name,
217
+ distinct: definition.distinct,
218
+ arguments: args,
219
+ orderBy: []
220
+ }),
221
+ type: definition.type(argument.type),
222
+ ordered: definition.ordered,
223
+ fallbacks: noFallbacks
224
+ });
225
+ }
226
+ /** Creates the projection of the aggregate of `field` whose `NULL` `fallback` replaces after its earlier fallbacks. */
227
+ function addFallback(field, fallback) {
228
+ const fallbacks = field.fallbacks.slice();
229
+ fallbacks.push(fallback);
230
+ return Object.freeze({
231
+ key: field.key,
232
+ expression: field.expression,
233
+ type: field.type,
234
+ ordered: field.ordered,
235
+ fallbacks
236
+ });
237
+ }
238
+ /** Tells whether `node` is an aggregate query, whose value is the aggregate over the rows that its filters, limit, and offset choose. */
239
+ function isAggregateQuery(node) {
240
+ return node.value && isAggregateProjection(node.projections[0]);
241
+ }
242
+ /** Tells whether `node`, a nested query, is selected as its value rather than as packed rows: an aggregate query as a scalar subquery of its statement, and a query of `exists` as `EXISTS` of its rows. */
243
+ function isSelectedAsValue(node) {
244
+ return isAggregateQuery(node) || isExistsQuery(node);
245
+ }
246
+ /** Tells whether a selected field is the projection of an aggregate, which only the aggregate methods select. */
247
+ function isAggregateProjection(field) {
248
+ return "ordered" in field;
249
+ }
250
+ function toCountType() {
251
+ return countType;
252
+ }
253
+ function toArgumentType(argument) {
254
+ return argument;
255
+ }
256
+ /** Returns the type of the sum of the values of type `argument`: for `smallint` and `integer` values, a `bigint` with the operators of `argument` that rejects a sum that a number cannot hold exactly, and `argument` for others. */
257
+ function toSumType(argument) {
258
+ if (argument.castType !== "smallint" && argument.castType !== "integer") return argument;
259
+ let type = sumTypes.get(argument);
260
+ if (type === void 0) {
261
+ type = defineType({ sqlType: "bigint" }).transform({
262
+ decode: (text) => {
263
+ decodeSafeInteger(text, "Sum");
264
+ return argument.decode(text);
265
+ },
266
+ encode: (value) => argument.encode(value)
267
+ }).withOperators(argument.operators);
268
+ sumTypes.set(argument, type);
269
+ }
270
+ return type;
271
+ }
272
+ /** Returns the type of the average of the values of type `argument`, which decodes a fractional value where PostgreSQL gives one, such as `Number` of `integer`; rejects a type of the SQL type `bigint`. */
273
+ function toAverageType(argument) {
274
+ if (argument.castType === "bigint") throw new TypeError("avg of bigint values requires a type that can represent fractional values; average a sql fragment of the column with t.doublePrecision or t.numeric");
275
+ return argument;
276
+ }
277
+ /** Decodes `text` of a `bigint` as a number, rejecting one that a number cannot hold exactly; `subject` names it in the error. */
278
+ function decodeSafeInteger(text, subject) {
279
+ const number = Number(text);
280
+ if (!Number.isSafeInteger(number)) throw new RangeError(`${subject} ${text} is outside the safe integer range of numbers`);
281
+ return number;
282
+ }
283
+ // src/query/column-refs.ts
284
+ /** Context of a query whose table has no relations, such as one of `from(table)`. */
285
+ const noContext = /* @__PURE__ */ Object.freeze({ relations: /* @__PURE__ */ Object.freeze({}) });
286
+ /** Creates expressions of the columns of `source`, each with the type of its column. */
287
+ function createColumnRefs(source) {
288
+ return addColumns({}, source);
289
+ }
290
+ /** Creates the references of the callbacks of `select`, `where`, and `orderBy` over `source`: its columns, and the relations of `context`. */
291
+ function createSelectionRefs(source, context) {
292
+ return Object.defineProperties(addColumns({}, source), context.relations);
293
+ }
294
+ function addColumns(refs, source) {
295
+ const { columns } = source.table;
296
+ for (const key of Object.keys(columns)) refs[key] = toExpression(createNode({
297
+ kind: "column",
298
+ source,
299
+ key
300
+ }), columns[key].type);
301
+ return refs;
302
+ }
58
303
  // src/result/result.ts
59
304
  /** Error thrown when a query of one row finds no row, executed or nested, unless a required relation guarantees the row. */
60
305
  var NotFoundError = class extends Error {
@@ -111,9 +356,9 @@ function decodeStatement(plan, result) {
111
356
  }
112
357
  }
113
358
  if (counted === "number") return count;
114
- if (plan.rows !== "many") return {};
359
+ if (plan.rows !== "many") return createRecord(plan);
115
360
  const records = [];
116
- for (let index = 0; index < count; index++) records.push({});
361
+ for (let index = 0; index < count; index++) records.push(createRecord(plan));
117
362
  return records;
118
363
  }
119
364
  /**
@@ -232,7 +477,7 @@ function decodeRow(plan, row, packed) {
232
477
  let index = 0;
233
478
  try {
234
479
  if (plan.value) return packed ? decodePackedValue(fields[0], row[0]) : decodeDriverValue(fields[0], row[0]);
235
- const record = {};
480
+ const record = createRecord(plan);
236
481
  for (; index < fields.length; index++) {
237
482
  const field = fields[index];
238
483
  record[field.key] = packed ? decodePackedValue(field, row[index]) : decodeDriverValue(field, row[index]);
@@ -243,6 +488,16 @@ function decodeRow(plan, row, packed) {
243
488
  throw prefixPath(packed ? `.${key}` : key, error);
244
489
  }
245
490
  }
491
+ /** Creates a record of `plan` before the values of a row are assigned: empty, or with the fields of its template. */
492
+ function createRecord(plan) {
493
+ const record = {};
494
+ const { recordTemplate } = plan;
495
+ if (recordTemplate !== void 0) for (let index = 0; index < recordTemplate.length; index++) {
496
+ const { key, value } = recordTemplate[index];
497
+ record[key] = value;
498
+ }
499
+ return record;
500
+ }
246
501
  /** Decodes the value of a field in a row of the driver: a scalar from its text, keeping `NULL` as `null`, or nested rows from JSON text. */
247
502
  function decodeDriverValue(field, value) {
248
503
  if (value === void 0) throw new Error("Driver returned no value");
@@ -387,40 +642,144 @@ function toColumn(definition) {
387
642
  hasDefault: false
388
643
  }) : void 0;
389
644
  }
390
- // src/type/untyped.ts
391
- /** Encodes a parameter without a type, such as a value interpolated into `sql`, by its JavaScript type. */
392
- function encodeUntyped(value) {
393
- if (typeof value === "string") return value;
394
- if (typeof value === "number" || typeof value === "bigint") return String(value);
395
- if (typeof value === "boolean") return value ? "t" : "f";
396
- if (value instanceof Date) return value.toISOString();
397
- if (value instanceof Uint8Array) return encodeBytea(value);
398
- if (Array.isArray(value)) throw new TypeError("Pass an array with param(type, value), so that its elements are encoded by type");
399
- return stringifyJson(value);
400
- }
401
- // src/compiler/postgres/identifier.ts
402
- /** Most bytes a character other than ASCII takes in a server encoding, such as UTF-8 and EUC_TW ([PostgreSQL](https://www.postgresql.org/docs/current/multibyte.html)). */
403
- const maxCharacterBytes = 4;
404
- function quoteIdentifier(name) {
405
- return `"${name.replaceAll("\"", "\"\"")}"`;
406
- }
645
+ // src/query/resolve-values.ts
407
646
  /**
408
- * Returns the longest prefix of `name` that takes at most `maxBytes` bytes in any server encoding.
647
+ * Replaces objects of column values in a predicate with conditions on the columns of `source`.
409
648
  *
410
- * Every server encoding takes one byte for an ASCII character, and a character other than ASCII counts as the most bytes it can take.
649
+ * Groups are rebuilt, so constants that appear after resolution, such as an empty object, are simplified.
411
650
  */
412
- function cutIdentifier(name, maxBytes) {
413
- if (name.length * maxCharacterBytes <= maxBytes) return name;
414
- let bytes = 0;
415
- for (let index = 0; index < name.length;) {
416
- const code = name.codePointAt(index);
417
- bytes += code < 128 ? 1 : maxCharacterBytes;
418
- if (bytes > maxBytes) return name.slice(0, index);
419
- index += code < 65536 ? 1 : 2;
420
- }
421
- return name;
422
- }
423
- /**
651
+ function resolveValues(node, source) {
652
+ switch (node.kind) {
653
+ case "values": {
654
+ const conditions = [];
655
+ for (const key of Object.keys(node.values)) {
656
+ const value = node.values[key];
657
+ const type = findColumn(source.table, key)?.type;
658
+ const column = createNode({
659
+ kind: "column",
660
+ source,
661
+ key
662
+ });
663
+ if (value === null) conditions.push(createIsNullNode(column));
664
+ else if (type) conditions.push(matchValue(source, column, type, value));
665
+ else conditions.push(compareNodes("=", column, value, void 0));
666
+ }
667
+ return combineNodes("and", conditions);
668
+ }
669
+ case "and":
670
+ case "or": {
671
+ const operands = [];
672
+ for (const operand of node.operands) operands.push(resolveValues(operand, source));
673
+ return combineNodes(node.kind, operands);
674
+ }
675
+ case "not": return negateNode(resolveValues(node.operand, source));
676
+ case "raw": return createNode({
677
+ ...node,
678
+ values: node.values.map((value) => resolveValues(value, source))
679
+ });
680
+ default: return node;
681
+ }
682
+ }
683
+ /** Matches a column with a value of an object condition by calling the `eq` operator of its type, whichever operator it is. */
684
+ function matchValue(source, column, type, value) {
685
+ const expression = toExpression(column, type);
686
+ if (typeof expression.eq !== "function") throw new TypeError(`Column "${column.key}" of table "${source.table.name}" has no eq operator; an object condition can only match it with null`);
687
+ const predicate = expression.eq(value);
688
+ if (!isExpression(predicate)) throw new TypeError(`The eq operator of column "${column.key}" of table "${source.table.name}" must return an expression`);
689
+ return toNode(predicate);
690
+ }
691
+ // src/query/filters.ts
692
+ /** Creates query filters with the filter of `where` over `source` with the relations of `context` combined with `AND` with the user filters of `filters`. */
693
+ function addUserFilter(filters, filter, source, context) {
694
+ const predicate = resolveValues(toConditionNode(typeof filter === "function" ? filter(createSelectionRefs(source, context)) : filter), source);
695
+ const { user } = filters;
696
+ return Object.freeze({
697
+ ...filters,
698
+ user: user ? combineNodes("and", [user, predicate]) : predicate
699
+ });
700
+ }
701
+ function defineFilter(_table, filter) {
702
+ return filter;
703
+ }
704
+ // src/query/find.ts
705
+ /**
706
+ * Returns the object of column values that `find` filters a query of `table` by: `values` of the columns of its primary key, in their order.
707
+ *
708
+ * It rejects a table without a primary key, a number of values other than the number of its columns, and `null` and `undefined`.
709
+ */
710
+ function toPrimaryKeyValues(table, values) {
711
+ const { primaryKey } = table.keys;
712
+ if (primaryKey === void 0) throw new Error(`find takes the values of a primary key, which table "${table.name}" does not have; use findBy with a unique key`);
713
+ if (values.length !== primaryKey.length) throw new Error(`find takes one value for each column of the primary key of table "${table.name}", ${quoteColumns(primaryKey)}, not ${values.length}`);
714
+ const filter = {};
715
+ for (let index = 0; index < primaryKey.length; index++) {
716
+ const column = primaryKey[index];
717
+ filter[column] = requireKeyValue(table, column, values[index], "find");
718
+ }
719
+ return filter;
720
+ }
721
+ /**
722
+ * Returns the object of column values that `findBy` filters a query of `table` by: a copy of `values`, read once.
723
+ *
724
+ * It rejects columns that are not exactly a key of `table`, primary or unique, as `isKey` tells, and `null` and `undefined`.
725
+ */
726
+ function toKeyValues(table, values) {
727
+ if (typeof values !== "object" || values === null) throw new TypeError(`findBy takes an object of the columns of a key of table "${table.name}"`);
728
+ const columns = Object.keys(values);
729
+ if (!isKey(table, columns)) {
730
+ const listed = columns.length === 0 ? "an object without columns" : `columns ${quoteColumns(columns)}`;
731
+ throw new Error(`findBy takes the columns of one key of table "${table.name}", primary or unique, not ${listed}`);
732
+ }
733
+ const filter = {};
734
+ for (const column of columns) {
735
+ const value = values[column];
736
+ filter[column] = requireKeyValue(table, column, value, "findBy");
737
+ }
738
+ return filter;
739
+ }
740
+ /** Returns `value` of column `column` of a key of `table` that `method` takes, rejecting `null` and `undefined`. */
741
+ function requireKeyValue(table, column, value, method) {
742
+ if (value === null || value === void 0) throw new TypeError(`${method} got ${value} for column "${column}" of table "${table.name}"; a value of a key is never null or undefined`);
743
+ return value;
744
+ }
745
+ /** Lists `columns` in quotes, separated by commas. */
746
+ function quoteColumns(columns) {
747
+ return columns.map((column) => `"${column}"`).join(", ");
748
+ }
749
+ // src/type/untyped.ts
750
+ /** Encodes a parameter without a type, such as a value interpolated into `sql`, by its JavaScript type. */
751
+ function encodeUntyped(value) {
752
+ if (typeof value === "string") return value;
753
+ if (typeof value === "number" || typeof value === "bigint") return String(value);
754
+ if (typeof value === "boolean") return value ? "t" : "f";
755
+ if (value instanceof Date) return value.toISOString();
756
+ if (value instanceof Uint8Array) return encodeBytea(value);
757
+ if (Array.isArray(value)) throw new TypeError("Pass an array with param(type, value), so that its elements are encoded by type");
758
+ return stringifyJson(value);
759
+ }
760
+ // src/compiler/postgres/identifier.ts
761
+ /** Most bytes a character other than ASCII takes in a server encoding, such as UTF-8 and EUC_TW ([PostgreSQL](https://www.postgresql.org/docs/current/multibyte.html)). */
762
+ const maxCharacterBytes = 4;
763
+ function quoteIdentifier(name) {
764
+ return `"${name.replaceAll("\"", "\"\"")}"`;
765
+ }
766
+ /**
767
+ * Returns the longest prefix of `name` that takes at most `maxBytes` bytes in any server encoding.
768
+ *
769
+ * Every server encoding takes one byte for an ASCII character, and a character other than ASCII counts as the most bytes it can take.
770
+ */
771
+ function cutIdentifier(name, maxBytes) {
772
+ if (name.length * maxCharacterBytes <= maxBytes) return name;
773
+ let bytes = 0;
774
+ for (let index = 0; index < name.length;) {
775
+ const code = name.codePointAt(index);
776
+ bytes += code < 128 ? 1 : maxCharacterBytes;
777
+ if (bytes > maxBytes) return name.slice(0, index);
778
+ index += code < 65536 ? 1 : 2;
779
+ }
780
+ return name;
781
+ }
782
+ /**
424
783
  * Returns the SQL name of the projection with `key` at `index` of its query.
425
784
  *
426
785
  * A key of up to 50 bytes is the name itself.
@@ -538,6 +897,7 @@ function compileStatement(node, options = {}, tables, db) {
538
897
  text: compileQuery(context, void 0, node),
539
898
  parameters: context.parameters,
540
899
  fields: node.projections,
900
+ recordTemplate: node.recordTemplate,
541
901
  rows: node.rows,
542
902
  value: node.value,
543
903
  counted: void 0,
@@ -561,6 +921,7 @@ function compileStatement(node, options = {}, tables, db) {
561
921
  text: compileMutation(context, node),
562
922
  parameters: context.parameters,
563
923
  fields: returning ?? noFields,
924
+ recordTemplate: node.recordTemplate,
564
925
  rows: node.rows,
565
926
  value: node.value,
566
927
  counted: returning === void 0 ? "number" : returning.length === 0 ? "records" : void 0,
@@ -853,237 +1214,54 @@ function visitQuery(query, visit) {
853
1214
  if (query.limit !== void 0) visitNodes(query.limit, true, visit);
854
1215
  if (query.offset !== void 0) visitNodes(query.offset, true, visit);
855
1216
  }
856
- // src/query/exists.ts
857
- let existsProjection;
858
- /** Returns the projection of whether a query has a row, the only projection of a query made by `exists`. */
859
- function getExistsProjection() {
860
- existsProjection ??= Object.freeze({
861
- key: "exists",
862
- expression: trueNode,
863
- type: getBooleanType()
1217
+ // src/query/rows.ts
1218
+ /** Returns the rows mode of a query of the records of `relation`, as `RelationRows` gives it in types. */
1219
+ function getRelationRows(relation) {
1220
+ if (relation.kind === "many") return "many";
1221
+ return relation.required ? "one" : "nullable";
1222
+ }
1223
+ /** Returns the rows mode after a filter of a query of rows mode `rows`, of values when `value`, whose row is `guaranteed`, as `FilteredStateRows` gives it in types. */
1224
+ function toFilteredRows(rows, value, guaranteed) {
1225
+ if (!guaranteed || rows !== "one") return rows;
1226
+ return value ? "optional" : "nullable";
1227
+ }
1228
+ /** Returns the limit of a query of many rows that becomes a query of one row, given its limit `limit`: one row, or none under a limit of zero. */
1229
+ function limitToOne(limit) {
1230
+ return limit?.kind === "param" && limit.value === 0 ? limit : oneNode;
1231
+ }
1232
+ /** Returns the rows mode after `pluck` of a query of rows mode `rows`, as `ValueRows` gives it in types. */
1233
+ function toValueRows(rows) {
1234
+ return rows === "nullable" ? "optional" : rows;
1235
+ }
1236
+ // src/query/node.ts
1237
+ /** Creates a query of all rows of `from`, or of the records of `relation` with `filters` in the rows mode of the relation. */
1238
+ function createQueryNode(from, relation, filters = noFilters) {
1239
+ return Object.freeze({
1240
+ kind: "query",
1241
+ from,
1242
+ relation,
1243
+ projections: [],
1244
+ filters,
1245
+ orderBy: [],
1246
+ limit: void 0,
1247
+ offset: void 0,
1248
+ rows: relation === void 0 ? "many" : getRelationRows(relation),
1249
+ value: false,
1250
+ guaranteed: relation?.required ?? false,
1251
+ all: false
864
1252
  });
865
- return existsProjection;
866
1253
  }
867
- /** Tells whether `node` is a query of `exists`, whose value is whether the rows that its filters, limit, and offset choose exist. */
868
- function isExistsQuery(node) {
869
- return node.value && isExistsProjection(node.projections[0]);
1254
+ /** Tells whether `node` is a query of a table without clauses, such as a table of a `Db`: no relation, filters, selected fields, order, limit, offset, rows other than `many`, or `all`. */
1255
+ function isTableQuery(node) {
1256
+ return node.relation === void 0 && node.projections.length === 0 && node.filters.relation === void 0 && node.filters.scope === void 0 && node.filters.user === void 0 && node.orderBy.length === 0 && node.limit === void 0 && node.offset === void 0 && node.rows === "many" && !node.all;
870
1257
  }
871
- /** Tells whether a selected field is the projection of `exists`, which only `exists` selects. */
872
- function isExistsProjection(field) {
873
- return field === existsProjection;
1258
+ /** Tells whether a selected field is the rows of a nested query. */
1259
+ function isNestedSelection(node) {
1260
+ return "query" in node;
874
1261
  }
875
- // src/query/aggregate.ts
876
- /** Type of a count: a `bigint` of PostgreSQL decoded as a number, rejecting a count that a number cannot hold exactly. */
877
- const countType = /* @__PURE__ */ defineType({ sqlType: "bigint" }).transform({
878
- decode: (text) => decodeSafeInteger(text, "Count"),
879
- encode: (value) => String(value)
880
- }).withOperators(orderingOperators);
881
- /** Types of the sums of the values of `smallint` and `integer` types, by the type of the values, created once for each. */
882
- const sumTypes = /* @__PURE__ */ new WeakMap();
883
- const noFallbacks = /* @__PURE__ */ Object.freeze([]);
884
- /** Definitions of the aggregate methods that take a column or an expression. */
885
- const aggregateDefinitions = /* @__PURE__ */ Object.freeze({
886
- count: {
887
- name: "count",
888
- distinct: false,
889
- ordered: false,
890
- type: toCountType
891
- },
892
- countDistinct: {
893
- name: "count",
894
- distinct: true,
895
- ordered: false,
896
- type: toCountType
897
- },
898
- min: {
899
- name: "min",
900
- distinct: false,
901
- ordered: false,
902
- type: toArgumentType
903
- },
904
- max: {
905
- name: "max",
906
- distinct: false,
907
- ordered: false,
908
- type: toArgumentType
909
- },
910
- sum: {
911
- name: "sum",
912
- distinct: false,
913
- ordered: false,
914
- type: toSumType
915
- },
916
- avg: {
917
- name: "avg",
918
- distinct: false,
919
- ordered: false,
920
- type: toAverageType
921
- },
922
- every: {
923
- name: "bool_and",
924
- distinct: false,
925
- ordered: false,
926
- type: toArgumentType
927
- },
928
- some: {
929
- name: "bool_or",
930
- distinct: false,
931
- ordered: false,
932
- type: toArgumentType
933
- },
934
- stringAgg: {
935
- name: "string_agg",
936
- distinct: false,
937
- ordered: true,
938
- type: toArgumentType
939
- }
940
- });
941
- /** Projection of `count(*)`, which `count` without an argument selects; its value does not depend on the values or the order of the rows. */
942
- const countProjection = /* @__PURE__ */ Object.freeze({
943
- key: "count",
944
- expression: /* @__PURE__ */ createNode({
945
- kind: "aggregate",
946
- name: "count",
947
- distinct: false,
948
- arguments: [/* @__PURE__ */ createNode({
949
- kind: "raw",
950
- fragments: ["*"],
951
- values: []
952
- })],
953
- orderBy: []
954
- }),
955
- type: countType,
956
- ordered: false,
957
- fallbacks: noFallbacks
958
- });
959
- /**
960
- * Creates the projection of the aggregate of `method` over the values of `argument`, the projection of a column or an expression of each row.
961
- *
962
- * `delimiter` is the delimiter of `stringAgg`, sent as a parameter.
963
- */
964
- function projectAggregate(method, argument, delimiter) {
965
- const definition = aggregateDefinitions[method];
966
- const args = [argument.expression];
967
- if (delimiter !== void 0) args.push(createNode({
968
- kind: "param",
969
- value: delimiter,
970
- type: void 0
971
- }));
972
- return Object.freeze({
973
- key: method,
974
- expression: createNode({
975
- kind: "aggregate",
976
- name: definition.name,
977
- distinct: definition.distinct,
978
- arguments: args,
979
- orderBy: []
980
- }),
981
- type: definition.type(argument.type),
982
- ordered: definition.ordered,
983
- fallbacks: noFallbacks
984
- });
985
- }
986
- /** Creates the projection of the aggregate of `field` whose `NULL` `fallback` replaces after its earlier fallbacks. */
987
- function addFallback(field, fallback) {
988
- const fallbacks = field.fallbacks.slice();
989
- fallbacks.push(fallback);
990
- return Object.freeze({
991
- key: field.key,
992
- expression: field.expression,
993
- type: field.type,
994
- ordered: field.ordered,
995
- fallbacks
996
- });
997
- }
998
- /** Tells whether `node` is an aggregate query, whose value is the aggregate over the rows that its filters, limit, and offset choose. */
999
- function isAggregateQuery(node) {
1000
- return node.value && isAggregateProjection(node.projections[0]);
1001
- }
1002
- /** Tells whether `node`, a nested query, is selected as its value rather than as packed rows: an aggregate query as a scalar subquery of its statement, and a query of `exists` as `EXISTS` of its rows. */
1003
- function isSelectedAsValue(node) {
1004
- return isAggregateQuery(node) || isExistsQuery(node);
1005
- }
1006
- /** Tells whether a selected field is the projection of an aggregate, which only the aggregate methods select. */
1007
- function isAggregateProjection(field) {
1008
- return "ordered" in field;
1009
- }
1010
- function toCountType() {
1011
- return countType;
1012
- }
1013
- function toArgumentType(argument) {
1014
- return argument;
1015
- }
1016
- /** Returns the type of the sum of the values of type `argument`: for `smallint` and `integer` values, a `bigint` with the operators of `argument` that rejects a sum that a number cannot hold exactly, and `argument` for others. */
1017
- function toSumType(argument) {
1018
- if (argument.castType !== "smallint" && argument.castType !== "integer") return argument;
1019
- let type = sumTypes.get(argument);
1020
- if (type === void 0) {
1021
- type = defineType({ sqlType: "bigint" }).transform({
1022
- decode: (text) => {
1023
- decodeSafeInteger(text, "Sum");
1024
- return argument.decode(text);
1025
- },
1026
- encode: (value) => argument.encode(value)
1027
- }).withOperators(argument.operators);
1028
- sumTypes.set(argument, type);
1029
- }
1030
- return type;
1031
- }
1032
- /** Returns the type of the average of the values of type `argument`, which decodes a fractional value where PostgreSQL gives one, such as `Number` of `integer`; rejects a type of the SQL type `bigint`. */
1033
- function toAverageType(argument) {
1034
- if (argument.castType === "bigint") throw new TypeError("avg of bigint values requires a type that can represent fractional values; average a sql fragment of the column with t.doublePrecision or t.numeric");
1035
- return argument;
1036
- }
1037
- /** Decodes `text` of a `bigint` as a number, rejecting one that a number cannot hold exactly; `subject` names it in the error. */
1038
- function decodeSafeInteger(text, subject) {
1039
- const number = Number(text);
1040
- if (!Number.isSafeInteger(number)) throw new RangeError(`${subject} ${text} is outside the safe integer range of numbers`);
1041
- return number;
1042
- }
1043
- // src/query/rows.ts
1044
- /** Returns the rows mode of a query of the records of `relation`, as `RelationRows` gives it in types. */
1045
- function getRelationRows(relation) {
1046
- if (relation.kind === "many") return "many";
1047
- return relation.required ? "one" : "nullable";
1048
- }
1049
- /** Returns the rows mode after a filter of a query of rows mode `rows`, of values when `value`, whose row is `guaranteed`, as `FilteredStateRows` gives it in types. */
1050
- function toFilteredRows(rows, value, guaranteed) {
1051
- if (!guaranteed || rows !== "one") return rows;
1052
- return value ? "optional" : "nullable";
1053
- }
1054
- /** Returns the limit of a query of many rows that becomes a query of one row, given its limit `limit`: one row, or none under a limit of zero. */
1055
- function limitToOne(limit) {
1056
- return limit?.kind === "param" && limit.value === 0 ? limit : oneNode;
1057
- }
1058
- /** Returns the rows mode after `pluck` of a query of rows mode `rows`, as `ValueRows` gives it in types. */
1059
- function toValueRows(rows) {
1060
- return rows === "nullable" ? "optional" : rows;
1061
- }
1062
- // src/query/node.ts
1063
- /** Creates a query of all rows of `from`, or of the records of `relation` with `filters` in the rows mode of the relation. */
1064
- function createQueryNode(from, relation, filters = noFilters) {
1065
- return Object.freeze({
1066
- kind: "query",
1067
- from,
1068
- relation,
1069
- projections: [],
1070
- filters,
1071
- orderBy: [],
1072
- limit: void 0,
1073
- offset: void 0,
1074
- rows: relation === void 0 ? "many" : getRelationRows(relation),
1075
- value: false,
1076
- guaranteed: relation?.required ?? false,
1077
- all: false
1078
- });
1079
- }
1080
- /** Tells whether `node` is a query of a table without clauses, such as a table of a `Db`: no relation, filters, selected fields, order, limit, offset, rows other than `many`, or `all`. */
1081
- function isTableQuery(node) {
1082
- return node.relation === void 0 && node.projections.length === 0 && node.filters.relation === void 0 && node.filters.scope === void 0 && node.filters.user === void 0 && node.orderBy.length === 0 && node.limit === void 0 && node.offset === void 0 && node.rows === "many" && !node.all;
1083
- }
1084
- /** Tells whether a selected field is the rows of a nested query. */
1085
- function isNestedSelection(node) {
1086
- return "query" in node;
1262
+ /** Tells whether a selected field is a literal. */
1263
+ function isLiteralSelection(node) {
1264
+ return "literal" in node;
1087
1265
  }
1088
1266
  // src/schema/relation.ts
1089
1267
  /** Runtime mark of the declarations of `many` and `one`. */
@@ -1373,7 +1551,8 @@ function packRows(query) {
1373
1551
  fields: projections,
1374
1552
  rows: query.rows,
1375
1553
  value: query.value,
1376
- guaranteedBy: query.guaranteedBy
1554
+ guaranteedBy: query.guaranteedBy,
1555
+ recordTemplate: query.recordTemplate
1377
1556
  });
1378
1557
  const projection = Object.freeze({
1379
1558
  key: "rows",
@@ -1440,7 +1619,8 @@ function lowerText(node, context) {
1440
1619
  /** Lowers a mutation to its statement, replacing the queries in its expressions, and packing the rows of each nested query of `RETURNING` into the value of its field, or selecting the value of a nested aggregate query, as a select list does. */
1441
1620
  function lowerMutation(node, context) {
1442
1621
  const { target, returning, rows, value } = node;
1443
- const lowered = returning === void 0 ? void 0 : lowerProjections(returning, context);
1622
+ const recordTemplate = returning === void 0 ? void 0 : createRecordTemplate(returning);
1623
+ const lowered = returning === void 0 ? void 0 : lowerProjections(dropLiterals(returning), context);
1444
1624
  switch (node.kind) {
1445
1625
  case "insert": {
1446
1626
  const values = lowerEach(node.values, context, lowerRow);
@@ -1451,6 +1631,7 @@ function lowerMutation(node, context) {
1451
1631
  columns: node.columns,
1452
1632
  values,
1453
1633
  returning: lowered,
1634
+ recordTemplate,
1454
1635
  rows,
1455
1636
  value
1456
1637
  });
@@ -1465,6 +1646,7 @@ function lowerMutation(node, context) {
1465
1646
  set,
1466
1647
  filters,
1467
1648
  returning: lowered,
1649
+ recordTemplate,
1468
1650
  rows,
1469
1651
  value
1470
1652
  });
@@ -1477,6 +1659,7 @@ function lowerMutation(node, context) {
1477
1659
  target,
1478
1660
  filters,
1479
1661
  returning: lowered,
1662
+ recordTemplate,
1480
1663
  rows,
1481
1664
  value
1482
1665
  });
@@ -1503,13 +1686,14 @@ function lowerSelect(node, context, positions) {
1503
1686
  if (isExistsQuery(node)) return selectExists(node, context);
1504
1687
  checkRelation(node, context);
1505
1688
  if (isAggregateQuery(node)) return lowerAggregate(node, context);
1506
- const selected = node.projections;
1689
+ const recordTemplate = createRecordTemplate(node.projections);
1690
+ const selected = dropLiterals(node.projections);
1507
1691
  const projections = lowerProjections(selected, context);
1508
1692
  const filters = lowerFilters(node.filters, context);
1509
1693
  const orderBy = lowerOrder(node.orderBy, context, selected, projections);
1510
1694
  const { relation } = node;
1511
1695
  const guaranteedBy = node.guaranteed && relation !== void 0 ? formatRelationName(relation.key, relation.name) : void 0;
1512
- const page = node.offset !== void 0 && selected.some((field, index) => isPagedField(field, projections[index], orderBy)) ? lowerPage(node, projections, filters, orderBy, positions, guaranteedBy) : void 0;
1696
+ const page = node.offset !== void 0 && selected.some((field, index) => isPagedField(field, projections[index], orderBy)) ? lowerPage(node, selected, projections, filters, orderBy, positions, guaranteedBy, recordTemplate) : void 0;
1513
1697
  if (page !== void 0) return page;
1514
1698
  return Object.freeze({
1515
1699
  kind: "select",
@@ -1522,9 +1706,27 @@ function lowerSelect(node, context, positions) {
1522
1706
  offset: node.offset,
1523
1707
  rows: node.rows,
1524
1708
  value: node.value,
1525
- guaranteedBy
1709
+ guaranteedBy,
1710
+ recordTemplate
1526
1711
  });
1527
1712
  }
1713
+ /** Returns the fields of `selected` that a statement selects, or `selected` itself without literals. */
1714
+ function dropLiterals(selected) {
1715
+ if (!selected.some(isLiteralSelection)) return selected;
1716
+ const fields = [];
1717
+ for (const field of selected) if (!isLiteralSelection(field)) fields.push(field);
1718
+ return fields;
1719
+ }
1720
+ /** Creates the template of the records of `selected`: every field in its order with the value of a literal, or `undefined` without literals. */
1721
+ function createRecordTemplate(selected) {
1722
+ if (!selected.some(isLiteralSelection)) return;
1723
+ const template = [];
1724
+ for (const field of selected) template.push(Object.freeze({
1725
+ key: field.key,
1726
+ value: isLiteralSelection(field) ? field.literal : void 0
1727
+ }));
1728
+ return template;
1729
+ }
1528
1730
  /**
1529
1731
  * Tells whether `field`, a field of a query lowered to `projection`, is a nested query that a page after an offset evaluates only over its rows: one that no sort key of `orderBy`, the lowered order, sorts by.
1530
1732
  *
@@ -1547,6 +1749,7 @@ function checkDb(db, context, subject) {
1547
1749
  }
1548
1750
  /**
1549
1751
  * Lowers `node` with `projections`, `filters`, and `orderBy`, the lowered parts of the node, to a statement that evaluates its nested queries, apart from those that it sorts by, over the rows of a derived page.
1752
+ * `queryFields` are the fields of the query without literals, and `projections` their lowered projections in the same order.
1550
1753
  * The derived source applies the filters, the order, the limit, and the offset, and replaces the occurrence of the table.
1551
1754
  *
1552
1755
  * It returns `undefined` when a nested query that it evaluates over the rows of the page holds a SQL fragment that refers to a column of the table outside the queries nested in the fragment.
@@ -1557,7 +1760,7 @@ function checkDb(db, context, subject) {
1557
1760
  * A column that no field reads stays out of the source, which could not select it beside an aggregate of a SQL fragment, such as `count(*)`.
1558
1761
  * The order of a derived source does not carry into the query that reads it, so the statement sorts the rows of the page again by the sort keys of the source, by positions when `positions` is set.
1559
1762
  */
1560
- function lowerPage(node, projections, filters, orderBy, positions, guaranteedBy) {
1763
+ function lowerPage(node, queryFields, projections, filters, orderBy, positions, guaranteedBy, recordTemplate) {
1561
1764
  const { from } = node;
1562
1765
  const columnKeys = /* @__PURE__ */ new Set();
1563
1766
  const fields = [];
@@ -1565,7 +1768,7 @@ function lowerPage(node, projections, filters, orderBy, positions, guaranteedBy)
1565
1768
  for (let index = 0; index < projections.length; index++) {
1566
1769
  const { expression } = projections[index];
1567
1770
  let key;
1568
- if (isPagedField(node.projections[index], projections[index], orderBy)) {
1771
+ if (isPagedField(queryFields[index], projections[index], orderBy)) {
1569
1772
  if (holdsFragmentOfSource(expression, from)) return;
1570
1773
  collectColumnKeys(expression, from, columnKeys);
1571
1774
  } else if (expression.kind === "column" && expression.source === from) columnKeys.add(expression.key);
@@ -1628,7 +1831,8 @@ function lowerPage(node, projections, filters, orderBy, positions, guaranteedBy)
1628
1831
  offset: void 0,
1629
1832
  rows: node.rows,
1630
1833
  value: node.value,
1631
- guaranteedBy
1834
+ guaranteedBy,
1835
+ recordTemplate
1632
1836
  });
1633
1837
  }
1634
1838
  /** Lowers an aggregate query to a statement of the value of its aggregate over the rows that its filters, limit, and offset choose. */
@@ -1785,14 +1989,15 @@ function lowerRecord(node, context) {
1785
1989
  kind: "select",
1786
1990
  from: void 0,
1787
1991
  joins: noJoins,
1788
- projections: lowerProjections(node.projections, context),
1992
+ projections: lowerProjections(dropLiterals(node.projections), context),
1789
1993
  filters: noFilters,
1790
1994
  orderBy: noOrder,
1791
1995
  limit: void 0,
1792
1996
  offset: void 0,
1793
1997
  rows: "one",
1794
1998
  value: false,
1795
- guaranteedBy: void 0
1999
+ guaranteedBy: void 0,
2000
+ recordTemplate: createRecordTemplate(node.projections)
1796
2001
  });
1797
2002
  }
1798
2003
  /**
@@ -2026,550 +2231,45 @@ function compileToSQL(query, options) {
2026
2231
  if (options !== void 0) throw new Error("A query bound to a Db compiles with the options of its Db");
2027
2232
  return db.$compile(query);
2028
2233
  }
2029
- // src/query/column-refs.ts
2030
- /** Context of a query whose table has no relations, such as one of `from(table)`. */
2031
- const noContext = /* @__PURE__ */ Object.freeze({ relations: /* @__PURE__ */ Object.freeze({}) });
2032
- /** Creates expressions of the columns of `source`, each with the type of its column. */
2033
- function createColumnRefs(source) {
2034
- return addColumns({}, source);
2035
- }
2036
- /** Creates the references of the callbacks of `select`, `where`, and `orderBy` over `source`: its columns, and the relations of `context`. */
2037
- function createSelectionRefs(source, context) {
2038
- return Object.defineProperties(addColumns({}, source), context.relations);
2039
- }
2040
- function addColumns(refs, source) {
2041
- const { columns } = source.table;
2042
- for (const key of Object.keys(columns)) refs[key] = toExpression(createNode({
2043
- kind: "column",
2044
- source,
2045
- key
2046
- }), columns[key].type);
2047
- return refs;
2048
- }
2049
- // src/query/resolve-values.ts
2234
+ // src/query/record.ts
2050
2235
  /**
2051
- * Replaces objects of column values in a predicate with conditions on the columns of `source`.
2236
+ * Immutable query of `$select` of state `S`, unbound or bound to a `Db`: one record whose fields are the values of expressions and of literals and the results of independent queries, selected in one statement.
2052
2237
  *
2053
- * Groups are rebuilt, so constants that appear after resolution, such as an empty object, are simplified.
2238
+ * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2239
+ * A bound query executes on its `Db` when awaited.
2054
2240
  */
2055
- function resolveValues(node, source) {
2056
- switch (node.kind) {
2057
- case "values": {
2058
- const conditions = [];
2059
- for (const key of Object.keys(node.values)) {
2060
- const value = node.values[key];
2061
- const type = findColumn(source.table, key)?.type;
2062
- const column = createNode({
2063
- kind: "column",
2064
- source,
2065
- key
2066
- });
2067
- if (value === null) conditions.push(createIsNullNode(column));
2068
- else if (type) conditions.push(matchValue(source, column, type, value));
2069
- else conditions.push(compareNodes("=", column, value, void 0));
2070
- }
2071
- return combineNodes("and", conditions);
2072
- }
2073
- case "and":
2074
- case "or": {
2075
- const operands = [];
2076
- for (const operand of node.operands) operands.push(resolveValues(operand, source));
2077
- return combineNodes(node.kind, operands);
2078
- }
2079
- case "not": return negateNode(resolveValues(node.operand, source));
2080
- case "raw": return createNode({
2081
- ...node,
2082
- values: node.values.map((value) => resolveValues(value, source))
2083
- });
2084
- default: return node;
2241
+ var RecordQuery = class {
2242
+ node;
2243
+ /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2244
+ db;
2245
+ /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2246
+ then;
2247
+ constructor(node, db) {
2248
+ this.node = node;
2249
+ this.db = db;
2250
+ this.then = db === void 0 ? void 0 : executeOnAwait;
2251
+ Object.freeze(this);
2085
2252
  }
2086
- }
2087
- /** Matches a column with a value of an object condition by calling the `eq` operator of its type, whichever operator it is. */
2088
- function matchValue(source, column, type, value) {
2089
- const expression = toExpression(column, type);
2090
- if (typeof expression.eq !== "function") throw new TypeError(`Column "${column.key}" of table "${source.table.name}" has no eq operator; an object condition can only match it with null`);
2091
- const predicate = expression.eq(value);
2092
- if (!isExpression(predicate)) throw new TypeError(`The eq operator of column "${column.key}" of table "${source.table.name}" must return an expression`);
2093
- return toNode(predicate);
2094
- }
2095
- // src/query/filters.ts
2096
- /** Creates query filters with the filter of `where` over `source` with the relations of `context` combined with `AND` with the user filters of `filters`. */
2097
- function addUserFilter(filters, filter, source, context) {
2098
- const predicate = resolveValues(toConditionNode(typeof filter === "function" ? filter(createSelectionRefs(source, context)) : filter), source);
2099
- const { user } = filters;
2100
- return Object.freeze({
2101
- ...filters,
2102
- user: user ? combineNodes("and", [user, predicate]) : predicate
2103
- });
2104
- }
2105
- function defineFilter(_table, filter) {
2106
- return filter;
2107
- }
2108
- // src/query/find.ts
2253
+ toSQL(options) {
2254
+ return compileToSQL(this, options);
2255
+ }
2256
+ /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2257
+ [operandNode]() {
2258
+ throw new TypeError("An expression takes a query of one value of a table, such as of get, an aggregate, or exists, not a query of $select");
2259
+ }
2260
+ };
2109
2261
  /**
2110
- * Returns the object of column values that `find` filters a query of `table` by: `values` of the columns of its primary key, in their order.
2262
+ * Starts the query of `$select` of `selection`, an object of expressions, queries, and literals by key, bound to `db` when given.
2111
2263
  *
2112
- * It rejects a table without a primary key, a number of values other than the number of its columns, and `null` and `undefined`.
2264
+ * It reads the keys and values of `selection` when it is called.
2113
2265
  */
2114
- function toPrimaryKeyValues(table, values) {
2115
- const { primaryKey } = table.keys;
2116
- if (primaryKey === void 0) throw new Error(`find takes the values of a primary key, which table "${table.name}" does not have; use findBy with a unique key`);
2117
- if (values.length !== primaryKey.length) throw new Error(`find takes one value for each column of the primary key of table "${table.name}", ${quoteColumns(primaryKey)}, not ${values.length}`);
2118
- const filter = {};
2119
- for (let index = 0; index < primaryKey.length; index++) {
2120
- const column = primaryKey[index];
2121
- filter[column] = requireKeyValue(table, column, values[index], "find");
2122
- }
2123
- return filter;
2124
- }
2125
- /**
2126
- * Returns the object of column values that `findBy` filters a query of `table` by: a copy of `values`, read once.
2127
- *
2128
- * It rejects columns that are not exactly a key of `table`, primary or unique, as `isKey` tells, and `null` and `undefined`.
2129
- */
2130
- function toKeyValues(table, values) {
2131
- if (typeof values !== "object" || values === null) throw new TypeError(`findBy takes an object of the columns of a key of table "${table.name}"`);
2132
- const columns = Object.keys(values);
2133
- if (!isKey(table, columns)) {
2134
- const listed = columns.length === 0 ? "an object without columns" : `columns ${quoteColumns(columns)}`;
2135
- throw new Error(`findBy takes the columns of one key of table "${table.name}", primary or unique, not ${listed}`);
2136
- }
2137
- const filter = {};
2138
- for (const column of columns) {
2139
- const value = values[column];
2140
- filter[column] = requireKeyValue(table, column, value, "findBy");
2141
- }
2142
- return filter;
2143
- }
2144
- /** Returns `value` of column `column` of a key of `table` that `method` takes, rejecting `null` and `undefined`. */
2145
- function requireKeyValue(table, column, value, method) {
2146
- if (value === null || value === void 0) throw new TypeError(`${method} got ${value} for column "${column}" of table "${table.name}"; a value of a key is never null or undefined`);
2147
- return value;
2148
- }
2149
- /** Lists `columns` in quotes, separated by commas. */
2150
- function quoteColumns(columns) {
2151
- return columns.map((column) => `"${column}"`).join(", ");
2152
- }
2153
- // src/query/order.ts
2154
- /** Direction and placement of `NULL` of a sort key node, by `OrderDirection`. */
2155
- const directions = /* @__PURE__ */ Object.freeze({
2156
- asc: {
2157
- direction: "asc",
2158
- nulls: void 0
2159
- },
2160
- desc: {
2161
- direction: "desc",
2162
- nulls: void 0
2163
- },
2164
- "asc nulls first": {
2165
- direction: "asc",
2166
- nulls: "first"
2167
- },
2168
- "asc nulls last": {
2169
- direction: "asc",
2170
- nulls: "last"
2171
- },
2172
- "desc nulls first": {
2173
- direction: "desc",
2174
- nulls: "first"
2175
- },
2176
- "desc nulls last": {
2177
- direction: "desc",
2178
- nulls: "last"
2179
- }
2180
- });
2181
- const orderingNode = Symbol("kern-orm.ordering.node");
2182
- /** Runtime class of an expression with a direction, which holds its sort key node. */
2183
- var OrderingObject = class {
2184
- [orderingNode];
2185
- constructor(node) {
2186
- this[orderingNode] = node;
2187
- Object.freeze(this);
2188
- }
2189
- };
2190
- /** Sorts by `value`, an expression or a query of one value, in ascending order, in the callback of `orderBy`. */
2191
- function asc(value) {
2192
- return orderBy(value, "asc");
2193
- }
2194
- /** Sorts by `value`, an expression or a query of one value, in descending order, in the callback of `orderBy`. */
2195
- function desc(value) {
2196
- return orderBy(value, "desc");
2197
- }
2198
- /** Sorts by `value`, an expression or a query of one value, in `direction`, such as `"desc nulls last"`, in the callback of `orderBy`. */
2199
- function orderBy(value, direction) {
2200
- if (!isOperandSource(value)) throw new TypeError("A sort key must be an expression or a query of one value");
2201
- return new OrderingObject(createOrderNode(value[operandNode](), direction));
2202
- }
2203
- /**
2204
- * Creates the order of `node` with the sort keys of the arguments of `orderBy` after its own.
2205
- *
2206
- * `args` are column keys and objects of columns with directions, or a callback that receives the columns with the relations of `context` and the selected fields, and returns one sort key or an array of them.
2207
- */
2208
- function addOrder(node, context, args) {
2209
- const order = node.orderBy.slice();
2210
- const first = args[0];
2211
- if (typeof first === "function") {
2212
- const terms = first(createSelectionRefs(node.from, context), createSelectedRefs(node));
2213
- if (Array.isArray(terms)) for (const term of terms) order.push(readTerm(term));
2214
- else order.push(readTerm(terms));
2215
- return order;
2216
- }
2217
- for (const arg of args) if (typeof arg === "string") order.push(createOrderNode(createColumnNode(node.from, arg), "asc"));
2218
- else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
2219
- const columns = arg;
2220
- for (const key of Object.keys(columns)) order.push(createOrderNode(createColumnNode(node.from, key), columns[key]));
2221
- } else throw new TypeError("orderBy takes column keys and objects of columns with directions, or a callback");
2222
- return order;
2223
- }
2224
- /**
2225
- * Creates the sort key node of a sort key returned by the callback of `orderBy`.
2226
- *
2227
- * A query is converted by the method of `operandNode`, which rejects a query other than of one value.
2228
- */
2229
- function readTerm(term) {
2230
- if (term instanceof OrderingObject) return term[orderingNode];
2231
- if (isOperandSource(term)) return createOrderNode(term[operandNode](), "asc");
2232
- throw new TypeError("The callback of orderBy must return expressions, queries of one value, or sort keys of asc, desc, and orderBy");
2233
- }
2234
- /** Creates the sort key node of `expression` in `direction`, an `OrderDirection` checked at runtime. */
2235
- function createOrderNode(expression, direction) {
2236
- const placement = typeof direction === "string" && Object.hasOwn(directions, direction) ? directions[direction] : void 0;
2237
- if (placement === void 0) throw new TypeError(`Unknown sort direction ${JSON.stringify(direction)}`);
2238
- return Object.freeze({
2239
- expression,
2240
- direction: placement.direction,
2241
- nulls: placement.nulls
2242
- });
2243
- }
2244
- /** Creates a reference to the column `key` of the table of `source`. */
2245
- function createColumnNode(source, key) {
2246
- requireColumn(source.table, key);
2247
- return createNode({
2248
- kind: "column",
2249
- source,
2250
- key
2251
- });
2252
- }
2253
- /**
2254
- * Creates the references of the callback of `orderBy` to the fields selected by `node`.
2255
- *
2256
- * Each is an expression over the node of its projection, so that a sort key of it is the projection itself.
2257
- * A field of an aggregate or of `exists` is an expression of its query that holds the field, by which lowering finds the projection of the field.
2258
- */
2259
- function createSelectedRefs(node) {
2260
- const { projections } = node;
2261
- if (node.value) return toSelectedExpression(projections[0]);
2262
- const refs = {};
2263
- for (const projection of projections) {
2264
- const { key } = projection;
2265
- if (isNestedSelection(projection)) {
2266
- if (isSelectedAsValue(projection.query)) refs[key] = toQueryExpression(projection);
2267
- else Object.defineProperty(refs, key, {
2268
- get() {
2269
- throw new Error(`Field "${key}" holds nested rows and cannot be sorted by`);
2270
- },
2271
- enumerable: true
2272
- });
2273
- } else refs[key] = toSelectedExpression(projection);
2274
- }
2275
- return refs;
2276
- }
2277
- /** Creates an expression over the node of a projection of a query, which has a type: only lowering adds projections of nested queries. */
2278
- function toSelectedExpression(projection) {
2279
- return toExpression(projection.expression, projection.type);
2280
- }
2281
- /** Creates an expression of the value of `field`, a selected aggregate query or query of `exists`, with the type of its value. */
2282
- function toQueryExpression(field) {
2283
- const { query } = field;
2284
- return toExpression(createNode({
2285
- kind: "nestedQuery",
2286
- query,
2287
- db: field.db,
2288
- field
2289
- }), query.projections[0].type);
2290
- }
2291
- // src/query/pagination.ts
2292
- /** Creates the parameter of the number of rows of `limit` or `offset`, named by `method`, of query `node`, rejecting a query of one row and a count that is not a non-negative safe integer. */
2293
- function createPageCount(node, method, count) {
2294
- if (node.rows !== "many") throw new Error(`${method} applies only to a query of many rows${createPaginationHint(node)}`);
2295
- if (!Number.isSafeInteger(count) || count < 0) throw new RangeError(`${method} takes a non-negative integer, not ${count}`);
2296
- return createNode({
2297
- kind: "param",
2298
- value: count,
2299
- type: void 0
2300
- });
2301
- }
2302
- /** Creates the hint of the error of `limit` or `offset` of query `node` of one row: the method to call them before, if any. */
2303
- function createPaginationHint(node) {
2304
- if (node.relation?.kind === "one") return "";
2305
- if (isAggregateQuery(node)) return "; call it before count or another aggregate to aggregate the rows of a page";
2306
- if (isExistsQuery(node)) return "; call it before exists to check the rows of a page";
2307
- return "; call it before take or get";
2308
- }
2309
- // src/query/select.ts
2310
- /**
2311
- * Immutable select query of state `S`, unbound or bound to a `Db`.
2312
- *
2313
- * Every method returns a query of the same kind and leaves this query unchanged.
2314
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2315
- * A bound query executes on its `Db` when awaited.
2316
- */
2317
- var SelectQuery = class SelectQuery {
2318
- table;
2319
- node;
2320
- context;
2321
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2322
- db;
2323
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2324
- then;
2325
- constructor(table, node, context, db) {
2326
- this.table = table;
2327
- this.node = node;
2328
- this.context = context;
2329
- this.db = db;
2330
- this.then = db === void 0 ? void 0 : executeOnAwait;
2331
- Object.freeze(this);
2332
- }
2333
- where(filter) {
2334
- return this.derive(this.addFilter(filter));
2335
- }
2336
- select(...args) {
2337
- this.rejectValue("select");
2338
- return this.derive({ projections: mergeProjections(this.node.projections, this.node.from, args, this.context) });
2339
- }
2340
- clearSelect() {
2341
- this.rejectValue("clearSelect");
2342
- return this.derive({ projections: [] });
2343
- }
2344
- take() {
2345
- return this.deriveTaken({});
2346
- }
2347
- find(...values) {
2348
- return this.takeWhere(toPrimaryKeyValues(this.table, values));
2349
- }
2350
- findBy(values) {
2351
- return this.takeWhere(toKeyValues(this.table, values));
2352
- }
2353
- get(arg) {
2354
- this.rejectAggregate("get");
2355
- return this.deriveTaken({
2356
- projections: [projectValue(this.node.from, arg, "get")],
2357
- value: true,
2358
- rows: toValueRows(this.node.rows)
2359
- });
2360
- }
2361
- pluck(arg) {
2362
- this.rejectAggregate("pluck");
2363
- return this.derive({
2364
- projections: [projectValue(this.node.from, arg, "pluck")],
2365
- value: true,
2366
- rows: toValueRows(this.node.rows)
2367
- });
2368
- }
2369
- count(arg) {
2370
- if (arg !== void 0) return this.aggregateBy("count", arg);
2371
- this.rejectAggregate("count");
2372
- return this.deriveAggregate(countProjection);
2373
- }
2374
- countDistinct(arg) {
2375
- return this.aggregateBy("countDistinct", arg);
2376
- }
2377
- min(arg) {
2378
- return this.aggregateBy("min", arg);
2379
- }
2380
- max(arg) {
2381
- return this.aggregateBy("max", arg);
2382
- }
2383
- sum(arg) {
2384
- return this.aggregateBy("sum", arg);
2385
- }
2386
- avg(arg) {
2387
- return this.aggregateBy("avg", arg);
2388
- }
2389
- every(arg) {
2390
- return this.aggregateBy("every", arg);
2391
- }
2392
- some(arg) {
2393
- return this.aggregateBy("some", arg);
2394
- }
2395
- stringAgg(arg, delimiter) {
2396
- return this.aggregateBy("stringAgg", arg, delimiter);
2397
- }
2398
- exists() {
2399
- this.rejectAggregate("exists");
2400
- return this.deriveAggregate(getExistsProjection());
2401
- }
2402
- coalesce(fallback) {
2403
- const { node } = this;
2404
- if (!node.value) throw new Error("coalesce applies only to a query of values, such as one made by get, pluck, or an aggregate");
2405
- return this.derive({ projections: [coalesceValue(node.projections[0], fallback)] });
2406
- }
2407
- expr() {
2408
- const value = this[operandNode]();
2409
- return toExpression(value, this.node.projections[0].type);
2410
- }
2411
- orderBy(...args) {
2412
- return this.derive({ orderBy: addOrder(this.node, this.context, args) });
2413
- }
2414
- limit(count) {
2415
- return this.derive({ limit: createPageCount(this.node, "limit", count) });
2416
- }
2417
- offset(count) {
2418
- return this.derive({ offset: createPageCount(this.node, "offset", count) });
2419
- }
2420
- optional() {
2421
- return this.changeOneRow("optional", "optional");
2422
- }
2423
- nullable() {
2424
- if (this.node.value) throw new Error("nullable applies only to a query of records; use optional after get, pluck, or an aggregate");
2425
- return this.changeOneRow("nullable", "nullable");
2426
- }
2427
- required() {
2428
- return this.changeOneRow("required", "one");
2429
- }
2430
- insert(values) {
2431
- return createInsert(this, [values], "one", "insert");
2432
- }
2433
- insertMany(records) {
2434
- if (!Array.isArray(records)) throw new TypeError("insertMany takes an array of records");
2435
- return createInsert(this, records, "many", "insertMany");
2436
- }
2437
- update(set) {
2438
- return createUpdate(this, set);
2439
- }
2440
- delete() {
2441
- return createDelete(this);
2442
- }
2443
- all() {
2444
- if (this.node.rows !== "many") throw new Error("all applies only to a query of many rows");
2445
- return this.derive({ all: true });
2446
- }
2447
- use(callback, ...args) {
2448
- return requireDerived(this, callback(this, ...args), "The callback of use");
2449
- }
2450
- toSQL(options) {
2451
- return compileToSQL(this, options);
2452
- }
2453
- /**
2454
- * Returns the node of the query as an operand of an expression, which lowering replaces with a scalar subquery of its value, or with `EXISTS` of its rows for a query of `exists`.
2455
- *
2456
- * It rejects a query of records or of rows `many`, which `ScalarQuery` rejects in types.
2457
- */
2458
- [operandNode]() {
2459
- const { node } = this;
2460
- if (!node.value || node.rows === "many") throw new TypeError("An expression takes a query of one value, such as of get, an aggregate, or exists, not a query of records or of an array");
2461
- return createNode({
2462
- kind: "nestedQuery",
2463
- query: node,
2464
- db: this.db
2465
- });
2466
- }
2467
- /**
2468
- * Returns the node of the query as the values of `in`, which lowering replaces with its statement.
2469
- *
2470
- * It rejects a query of records, which `ValuesQuery` rejects in types.
2471
- */
2472
- [valuesQueryNode]() {
2473
- const { node } = this;
2474
- if (!node.value) throw new TypeError("in takes a query of values, such as of pluck, not a query of records");
2475
- return createNode({
2476
- kind: "nestedQuery",
2477
- query: node,
2478
- db: this.db
2479
- });
2480
- }
2481
- /** Creates a query of the same kind and `Db` with the node changes applied. */
2482
- derive(changes) {
2483
- return new SelectQuery(this.table, Object.freeze({
2484
- ...this.node,
2485
- ...changes
2486
- }), this.context, this.db);
2487
- }
2488
- /**
2489
- * Creates a query of the same kind and `Db` with the node changes applied and then those of `take`, in one derived query.
2490
- *
2491
- * It adds the changes of `take` to `changes`, which must leave the limit as it is.
2492
- */
2493
- deriveTaken(changes) {
2494
- if ((changes.rows ?? this.node.rows) === "many") {
2495
- changes.limit = limitToOne(this.node.limit);
2496
- changes.rows = "one";
2497
- }
2498
- return this.derive(changes);
2499
- }
2500
- /** Creates the query of the value of `projection`, of an aggregate or of `exists` over the rows of this query, which always returns one row. */
2501
- deriveAggregate(projection) {
2502
- return this.derive({
2503
- projections: [projection],
2504
- rows: "one",
2505
- value: true,
2506
- guaranteed: false
2507
- });
2508
- }
2509
- /** Creates the query of the aggregate of `method` over `arg`, a column key or a callback that receives the columns and returns an expression; `delimiter` is the delimiter of `stringAgg`. */
2510
- aggregateBy(method, arg, delimiter) {
2511
- this.rejectAggregate(method);
2512
- return this.deriveAggregate(projectAggregate(method, projectValue(this.node.from, arg, method), delimiter));
2513
- }
2514
- /** Returns the changes of the node that add `filter` with `AND`, ending the guarantee of the row as `FilteredState` does in types. */
2515
- addFilter(filter) {
2516
- const { node } = this;
2517
- return {
2518
- filters: addUserFilter(node.filters, filter, node.from, this.context),
2519
- rows: toFilteredRows(node.rows, node.value, node.guaranteed),
2520
- guaranteed: false
2521
- };
2522
- }
2523
- /** Creates the query of `find` and `findBy`: `where` of `values`, an object of column values, returning one row like `take`. */
2524
- takeWhere(values) {
2525
- const changes = this.addFilter(values);
2526
- if (changes.rows === "many") changes.rows = "one";
2527
- return this.derive(changes);
2528
- }
2529
- /** Creates the query of one row with rows mode `rows` that `method` returns, rejecting a query of many rows. */
2530
- changeOneRow(method, rows) {
2531
- if (this.node.rows === "many") throw new Error(`${method} applies only to a query of one row, such as one made by take`);
2532
- return this.derive({
2533
- rows,
2534
- guaranteed: false
2535
- });
2536
- }
2537
- /** Rejects a change of the selection by `method` of a query made by `get`, `pluck`, or an aggregate method. */
2538
- rejectValue(method) {
2539
- if (!this.node.value) return;
2540
- this.rejectAggregate(method);
2541
- throw new Error(`${method} cannot be used after get or pluck; call get or pluck to replace the value`);
2542
- }
2543
- /** Rejects `method`, which replaces the value or the selection, on a query made by an aggregate method or `exists`. */
2544
- rejectAggregate(method) {
2545
- const { node } = this;
2546
- if (isAggregateQuery(node)) throw new Error(`${method} cannot be used after an aggregate`);
2547
- if (isExistsQuery(node)) throw new Error(`${method} cannot be used after exists`);
2548
- }
2549
- };
2550
- /**
2551
- * Returns `result`, which a callback named by `subject` returned for `query`, after checking that it is `query` or a query derived from it.
2552
- *
2553
- * An ancestor of `query` also passes, since only the source occurrence is compared.
2554
- */
2555
- function requireDerived(query, result, subject) {
2556
- if (!(result instanceof SelectQuery) || result.node.from !== query.node.from) throw new Error(`${subject} must return the query it receives or one derived from it`);
2557
- return result;
2558
- }
2559
- /** Binds a query to `db`, so that awaiting it executes it there. */
2560
- function bindQuery(query, db) {
2561
- return new SelectQuery(query.table, query.node, query.context, db);
2562
- }
2563
- /** Starts a query over a new occurrence of the table. */
2564
- function from(table) {
2565
- return startQuery(table, noContext);
2566
- }
2567
- /** Starts a query over a new occurrence of the table with the relations of `context`, such as a query of a table of a schema. */
2568
- function startQuery(table, context) {
2569
- return new SelectQuery(table, createQueryNode(Object.freeze({
2570
- kind: "table",
2571
- table
2572
- })), context);
2266
+ function startRecordQuery(selection, db) {
2267
+ const projections = [];
2268
+ addSelection(projections, selection);
2269
+ return new RecordQuery(Object.freeze({
2270
+ kind: "record",
2271
+ projections
2272
+ }), db);
2573
2273
  }
2574
2274
  // src/query/sql-query.ts
2575
2275
  /**
@@ -2675,6 +2375,108 @@ function requireType(value, what) {
2675
2375
  if (!isType(value)) throw new TypeError(`${what} takes a type, such as t.integer, not a column or another value`);
2676
2376
  return value;
2677
2377
  }
2378
+ // src/query/projections.ts
2379
+ /**
2380
+ * Creates the fields of `select` over `source`, appending new keys and replacing existing ones in place.
2381
+ *
2382
+ * `args` are the arguments of `select`: `"*"`, column keys, or a callback that receives the references of `source` with the relations of `context` and returns a selection.
2383
+ */
2384
+ function mergeProjections(projections, source, args, context) {
2385
+ const result = projections.slice();
2386
+ const first = args[0];
2387
+ if (typeof first === "function") addSelection(result, first(createSelectionRefs(source, context)));
2388
+ else {
2389
+ const keys = first === "*" ? Object.keys(source.table.columns) : args;
2390
+ for (const key of keys) setProjection(result, projectColumn(source, key));
2391
+ }
2392
+ return result;
2393
+ }
2394
+ /** Adds the fields of `selection`, expressions, queries, and literals by key, to `projections`, replacing existing keys in place. */
2395
+ function addSelection(projections, selection) {
2396
+ for (const key of Reflect.ownKeys(selection)) {
2397
+ if (typeof key === "symbol") throw new TypeError("A selected field must have a string key");
2398
+ setProjection(projections, selectValue(key, selection[key]));
2399
+ }
2400
+ }
2401
+ /**
2402
+ * Creates the projection of the value of `get` or `pluck`, or of the argument of an aggregate method, such as `max`, over `source`.
2403
+ *
2404
+ * `arg` is the argument of `method`: a column key, or a callback that receives the columns and returns an expression.
2405
+ */
2406
+ function projectValue(source, arg, method) {
2407
+ if (typeof arg !== "function") return projectColumn(source, arg);
2408
+ const value = arg(createColumnRefs(source));
2409
+ if (!isExpression(value)) throw new TypeError(`The callback of ${method} must return an expression`);
2410
+ const type = getType(value);
2411
+ if (!type) throw new TypeError(`The expression of ${method} has no type to decode its values; build a sql fragment with a type, such as sql(t.integer)`);
2412
+ return projectExpression("value", value, type);
2413
+ }
2414
+ /**
2415
+ * Creates the projection of the value of `field`, the only projection of a query of values, whose `NULL` `fallback` replaces: a value that the type of the field encodes, an expression, or a query of one value.
2416
+ *
2417
+ * The projection of an aggregate keeps its call, which lowering builds, and adds the fallback after its earlier ones.
2418
+ * The projection of `exists` stays as it is, since `EXISTS` is never `NULL`.
2419
+ */
2420
+ function coalesceValue(field, fallback) {
2421
+ const value = toFunctionOperandNode(fallback, field.type, "coalesce");
2422
+ if (isExistsProjection(field)) return field;
2423
+ if (isAggregateProjection(field)) return addFallback(field, value);
2424
+ return Object.freeze({
2425
+ key: field.key,
2426
+ expression: createList("coalesce(", [field.expression, value], ")"),
2427
+ type: field.type
2428
+ });
2429
+ }
2430
+ /** Creates the field of a value of a selection under `key`: an expression with a type, a query whose rows become its value, or a literal. */
2431
+ function selectValue(key, value) {
2432
+ if (value instanceof Literal) return Object.freeze({
2433
+ key,
2434
+ literal: value.literal
2435
+ });
2436
+ if (value instanceof SelectQuery) return Object.freeze({
2437
+ key,
2438
+ query: value.node,
2439
+ db: value.db
2440
+ });
2441
+ if (value instanceof RecordQuery) throw new TypeError(`Selected field "${key}" is a query of $select, which cannot be nested; select its fields directly instead`);
2442
+ if (value instanceof MutationQuery) throw new TypeError(`Selected field "${key}" is a query of insert, update, or delete, which cannot be nested`);
2443
+ if (value instanceof SqlQuery) throw new TypeError(`Selected field "${key}" is a query of $query, which cannot be nested`);
2444
+ if (!isExpression(value)) throw new TypeError(`Selected field "${key}" must be an expression, a query, or a literal`);
2445
+ const type = getType(value);
2446
+ if (!type) throw new TypeError(`Selected field "${key}" has no type to decode its values; build a sql fragment with a type, such as sql(t.integer)`);
2447
+ return projectExpression(key, value, type);
2448
+ }
2449
+ /** Creates the projection of a column of the table of `source` under its key. */
2450
+ function projectColumn(source, key) {
2451
+ const { type } = requireColumn(source.table, key);
2452
+ return Object.freeze({
2453
+ key,
2454
+ expression: createNode({
2455
+ kind: "column",
2456
+ source,
2457
+ key
2458
+ }),
2459
+ type
2460
+ });
2461
+ }
2462
+ /** Creates the projection of an expression under `key`, decoded with `type`, the type of the expression. */
2463
+ function projectExpression(key, value, type) {
2464
+ return Object.freeze({
2465
+ key,
2466
+ expression: toNode(value),
2467
+ type
2468
+ });
2469
+ }
2470
+ /** Adds or replaces a field by key, rejecting a key that a record cannot have. */
2471
+ function setProjection(projections, projection) {
2472
+ const { key } = projection;
2473
+ if (!isRecordKey(key)) throw new Error(`Field "${key}" cannot be selected: it is not a valid record key`);
2474
+ for (let index = 0; index < projections.length; index++) if (projections[index].key === key) {
2475
+ projections[index] = projection;
2476
+ return;
2477
+ }
2478
+ projections.push(projection);
2479
+ }
2678
2480
  // src/query/values.ts
2679
2481
  /**
2680
2482
  * Returns the columns and the rows of `VALUES` of an insert of `records`, at least one, into `table`, reading the keys and values of each record when it is called.
@@ -2710,41 +2512,325 @@ function toInsertRows(table, records, method) {
2710
2512
  };
2711
2513
  }
2712
2514
  /**
2713
- * Returns the assignments of an update of the rows of `source` that `set` gives: the values of its columns, or a callback that receives the columns and returns them, read when it is called.
2515
+ * Returns the assignments of an update of the rows of `source` that `set` gives: the values of its columns, or a callback that receives the columns and returns them, read when it is called.
2516
+ *
2517
+ * A value of `undefined` keeps its column, and an update must set at least one column.
2518
+ * It rejects a key that is not a column of the table of `source`, and a query as a value.
2519
+ */
2520
+ function toAssignments(source, set) {
2521
+ const { table } = source;
2522
+ const values = typeof set === "function" ? set(createColumnRefs(source)) : set;
2523
+ if (typeof values !== "object" || values === null) throw new TypeError(`update takes the values of the columns of table "${table.name}" or a callback that returns them`);
2524
+ const assignments = [];
2525
+ for (const key of Object.keys(values)) {
2526
+ const value = values[key];
2527
+ if (value !== void 0) assignments.push(Object.freeze({
2528
+ key,
2529
+ value: resolveValue(table, key, value)
2530
+ }));
2531
+ }
2532
+ if (assignments.length === 0) throw new Error(`update takes the value of at least one column of table "${table.name}"; a column given as undefined keeps its value`);
2533
+ return assignments;
2534
+ }
2535
+ /** Returns the node of `value` of the column of `table` under `key`: an expression, or a parameter encoded with the type of the column. */
2536
+ function resolveValue(table, key, value) {
2537
+ const column = requireColumn(table, key);
2538
+ if (value instanceof SelectQuery || value instanceof RecordQuery || value instanceof MutationQuery || value instanceof SqlQuery) throw new TypeError(`Column "${key}" of table "${table.name}" takes a value or an expression, not a query`);
2539
+ return toValueNode(value, column.type);
2540
+ }
2541
+ // src/query/mutation.ts
2542
+ /**
2543
+ * Immutable query of state `S` that inserts, updates, or deletes rows, unbound or bound to a `Db`.
2544
+ *
2545
+ * Without a selection, it resolves to the number of the rows it changes; `select`, `get`, and `pluck` return the fields of those rows instead.
2546
+ * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2547
+ * A bound query executes on its `Db` when awaited.
2548
+ */
2549
+ var MutationQuery = class MutationQuery {
2550
+ table;
2551
+ node;
2552
+ context;
2553
+ /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2554
+ db;
2555
+ /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2556
+ then;
2557
+ constructor(table, node, context, db) {
2558
+ this.table = table;
2559
+ this.node = node;
2560
+ this.context = context;
2561
+ this.db = db;
2562
+ this.then = db === void 0 ? void 0 : executeOnAwait;
2563
+ Object.freeze(this);
2564
+ }
2565
+ select(...args) {
2566
+ const { node } = this;
2567
+ const { returning } = node;
2568
+ if (returning !== void 0 && node.value) throw new Error("select cannot be used after get or pluck; call get or pluck to replace the value");
2569
+ return this.derive({
2570
+ returning: mergeProjections(returning ?? [], node.target, args, this.context),
2571
+ value: false
2572
+ });
2573
+ }
2574
+ get(arg) {
2575
+ if (this.node.rows === "many") throw new Error("get applies only to a query that changes one row, such as of insert or find; use pluck to return the values of several rows");
2576
+ return this.deriveValue(arg, "get");
2577
+ }
2578
+ pluck(arg) {
2579
+ return this.deriveValue(arg, "pluck");
2580
+ }
2581
+ toSQL(options) {
2582
+ return compileToSQL(this, options);
2583
+ }
2584
+ /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2585
+ [operandNode]() {
2586
+ throw new TypeError("An expression takes a query of one value of a table, such as of get, an aggregate, or exists, not a query of insert, update, or delete");
2587
+ }
2588
+ /** Creates a mutation of the same kind and `Db` with the node changes applied. */
2589
+ derive(changes) {
2590
+ return new MutationQuery(this.table, Object.freeze({
2591
+ ...this.node,
2592
+ ...changes
2593
+ }), this.context, this.db);
2594
+ }
2595
+ /** Creates the mutation that returns the value of `arg` of `method`, a column key or a callback that receives the columns and returns an expression, of each changed row. */
2596
+ deriveValue(arg, method) {
2597
+ const { node } = this;
2598
+ return this.derive({
2599
+ returning: [projectValue(node.target, arg, method)],
2600
+ value: true,
2601
+ rows: toValueRows(node.rows)
2602
+ });
2603
+ }
2604
+ };
2605
+ /**
2606
+ * Creates the insert of `records` into the table of `query`, which must have no clauses, in rows mode `rows`: `one` for `insert` and `many` for `insertMany`, named by `method`.
2607
+ *
2608
+ * It returns the number of the inserted rows, until a selection returns their fields.
2609
+ */
2610
+ function createInsert(query, records, rows, method) {
2611
+ const { node } = query;
2612
+ if (!isTableQuery(node)) throw new Error(`${method} applies only to a query of a table without clauses, such as filters or selected fields; select the fields that it returns after it`);
2613
+ const { columns, values } = toInsertRows(node.from.table, records, method);
2614
+ return new MutationQuery(query.table, Object.freeze({
2615
+ kind: "insert",
2616
+ target: node.from,
2617
+ columns,
2618
+ values,
2619
+ returning: void 0,
2620
+ rows,
2621
+ value: false
2622
+ }), query.context, query.db);
2623
+ }
2624
+ /** Creates the update of the rows of `query` that `set` gives, as `update` takes it, in the rows mode of the query. */
2625
+ function createUpdate(query, set) {
2626
+ const { node } = query;
2627
+ checkChangedRows(node, "update");
2628
+ return new MutationQuery(query.table, Object.freeze({
2629
+ kind: "update",
2630
+ target: node.from,
2631
+ set: toAssignments(node.from, set),
2632
+ filters: node.filters,
2633
+ returning: void 0,
2634
+ rows: node.rows,
2635
+ value: false
2636
+ }), query.context, query.db);
2637
+ }
2638
+ /** Creates the delete of the rows of `query`, in the rows mode of the query. */
2639
+ function createDelete(query) {
2640
+ const { node } = query;
2641
+ checkChangedRows(node, "delete");
2642
+ return new MutationQuery(query.table, Object.freeze({
2643
+ kind: "delete",
2644
+ target: node.from,
2645
+ filters: node.filters,
2646
+ returning: void 0,
2647
+ rows: node.rows,
2648
+ value: false
2649
+ }), query.context, query.db);
2650
+ }
2651
+ /**
2652
+ * Rejects a query whose rows `method`, `update` or `delete`, cannot change: one of a relation, with selected fields, which a mutation selects after it, with an order, a limit, or an offset, or without a filter that restricts its rows unless `all` allows it.
2653
+ *
2654
+ * A filter simplified to `TRUE`, such as `where({})`, restricts no row.
2655
+ */
2656
+ function checkChangedRows(node, method) {
2657
+ if (node.relation !== void 0) throw new Error(`${method} applies only to a query of a table, not of a relation`);
2658
+ if (node.projections.length > 0) throw new Error(`${method} returns the fields selected after it, not before; call select, get, or pluck after ${method}`);
2659
+ if (node.orderBy.length > 0 || node.limit !== void 0 || node.offset !== void 0) throw new Error(`${method} cannot sort or limit the rows it changes; choose them with where, find, or findBy instead of take, limit, offset, or orderBy`);
2660
+ const predicate = combineFilters(node.filters);
2661
+ if (!node.all && predicate.kind === "boolean" && predicate.value) throw new Error(`${method} requires a filter that restricts the rows, such as of where or find; call all() to ${method} every row`);
2662
+ }
2663
+ // src/query/order.ts
2664
+ /** Direction and placement of `NULL` of a sort key node, by `OrderDirection`. */
2665
+ const directions = /* @__PURE__ */ Object.freeze({
2666
+ asc: {
2667
+ direction: "asc",
2668
+ nulls: void 0
2669
+ },
2670
+ desc: {
2671
+ direction: "desc",
2672
+ nulls: void 0
2673
+ },
2674
+ "asc nulls first": {
2675
+ direction: "asc",
2676
+ nulls: "first"
2677
+ },
2678
+ "asc nulls last": {
2679
+ direction: "asc",
2680
+ nulls: "last"
2681
+ },
2682
+ "desc nulls first": {
2683
+ direction: "desc",
2684
+ nulls: "first"
2685
+ },
2686
+ "desc nulls last": {
2687
+ direction: "desc",
2688
+ nulls: "last"
2689
+ }
2690
+ });
2691
+ const orderingNode = Symbol("kern-orm.ordering.node");
2692
+ /** Runtime class of an expression with a direction, which holds its sort key node. */
2693
+ var OrderingObject = class {
2694
+ [orderingNode];
2695
+ constructor(node) {
2696
+ this[orderingNode] = node;
2697
+ Object.freeze(this);
2698
+ }
2699
+ };
2700
+ /** Sorts by `value`, an expression or a query of one value, in ascending order, in the callback of `orderBy`. */
2701
+ function asc(value) {
2702
+ return orderBy(value, "asc");
2703
+ }
2704
+ /** Sorts by `value`, an expression or a query of one value, in descending order, in the callback of `orderBy`. */
2705
+ function desc(value) {
2706
+ return orderBy(value, "desc");
2707
+ }
2708
+ /** Sorts by `value`, an expression or a query of one value, in `direction`, such as `"desc nulls last"`, in the callback of `orderBy`. */
2709
+ function orderBy(value, direction) {
2710
+ if (!isOperandSource(value)) throw new TypeError("A sort key must be an expression or a query of one value");
2711
+ return new OrderingObject(createOrderNode(value[operandNode](), direction));
2712
+ }
2713
+ /**
2714
+ * Creates the order of `node` with the sort keys of the arguments of `orderBy` after its own.
2715
+ *
2716
+ * `args` are column keys and objects of columns with directions, or a callback that receives the columns with the relations of `context` and the selected fields, and returns one sort key or an array of them.
2717
+ */
2718
+ function addOrder(node, context, args) {
2719
+ const order = node.orderBy.slice();
2720
+ const first = args[0];
2721
+ if (typeof first === "function") {
2722
+ const terms = first(createSelectionRefs(node.from, context), createSelectedRefs(node));
2723
+ if (Array.isArray(terms)) for (const term of terms) order.push(readTerm(term));
2724
+ else order.push(readTerm(terms));
2725
+ return order;
2726
+ }
2727
+ for (const arg of args) if (typeof arg === "string") order.push(createOrderNode(createColumnNode(node.from, arg), "asc"));
2728
+ else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
2729
+ const columns = arg;
2730
+ for (const key of Object.keys(columns)) order.push(createOrderNode(createColumnNode(node.from, key), columns[key]));
2731
+ } else throw new TypeError("orderBy takes column keys and objects of columns with directions, or a callback");
2732
+ return order;
2733
+ }
2734
+ /**
2735
+ * Creates the sort key node of a sort key returned by the callback of `orderBy`.
2736
+ *
2737
+ * A query is converted by the method of `operandNode`, which rejects a query other than of one value.
2738
+ */
2739
+ function readTerm(term) {
2740
+ if (term instanceof OrderingObject) return term[orderingNode];
2741
+ if (isOperandSource(term)) return createOrderNode(term[operandNode](), "asc");
2742
+ throw new TypeError("The callback of orderBy must return expressions, queries of one value, or sort keys of asc, desc, and orderBy");
2743
+ }
2744
+ /** Creates the sort key node of `expression` in `direction`, an `OrderDirection` checked at runtime. */
2745
+ function createOrderNode(expression, direction) {
2746
+ const placement = typeof direction === "string" && Object.hasOwn(directions, direction) ? directions[direction] : void 0;
2747
+ if (placement === void 0) throw new TypeError(`Unknown sort direction ${JSON.stringify(direction)}`);
2748
+ return Object.freeze({
2749
+ expression,
2750
+ direction: placement.direction,
2751
+ nulls: placement.nulls
2752
+ });
2753
+ }
2754
+ /** Creates a reference to the column `key` of the table of `source`. */
2755
+ function createColumnNode(source, key) {
2756
+ requireColumn(source.table, key);
2757
+ return createNode({
2758
+ kind: "column",
2759
+ source,
2760
+ key
2761
+ });
2762
+ }
2763
+ /**
2764
+ * Creates the references of the callback of `orderBy` to the fields selected by `node`.
2714
2765
  *
2715
- * A value of `undefined` keeps its column, and an update must set at least one column.
2716
- * It rejects a key that is not a column of the table of `source`, and a query as a value.
2766
+ * Each is an expression over the node of its projection, so that a sort key of it is the projection itself.
2767
+ * A field of an aggregate or of `exists` is an expression of its query that holds the field, by which lowering finds the projection of the field.
2717
2768
  */
2718
- function toAssignments(source, set) {
2719
- const { table } = source;
2720
- const values = typeof set === "function" ? set(createColumnRefs(source)) : set;
2721
- if (typeof values !== "object" || values === null) throw new TypeError(`update takes the values of the columns of table "${table.name}" or a callback that returns them`);
2722
- const assignments = [];
2723
- for (const key of Object.keys(values)) {
2724
- const value = values[key];
2725
- if (value !== void 0) assignments.push(Object.freeze({
2726
- key,
2727
- value: resolveValue(table, key, value)
2728
- }));
2769
+ function createSelectedRefs(node) {
2770
+ const { projections } = node;
2771
+ if (node.value) return toSelectedExpression(projections[0]);
2772
+ const refs = {};
2773
+ for (const projection of projections) {
2774
+ const { key } = projection;
2775
+ if (isLiteralSelection(projection)) Object.defineProperty(refs, key, {
2776
+ get() {
2777
+ throw new Error(`Field "${key}" holds a literal and cannot be sorted by`);
2778
+ },
2779
+ enumerable: true
2780
+ });
2781
+ else if (isNestedSelection(projection)) {
2782
+ if (isSelectedAsValue(projection.query)) refs[key] = toQueryExpression(projection);
2783
+ else Object.defineProperty(refs, key, {
2784
+ get() {
2785
+ throw new Error(`Field "${key}" holds nested rows and cannot be sorted by`);
2786
+ },
2787
+ enumerable: true
2788
+ });
2789
+ } else refs[key] = toSelectedExpression(projection);
2729
2790
  }
2730
- if (assignments.length === 0) throw new Error(`update takes the value of at least one column of table "${table.name}"; a column given as undefined keeps its value`);
2731
- return assignments;
2791
+ return refs;
2732
2792
  }
2733
- /** Returns the node of `value` of the column of `table` under `key`: an expression, or a parameter encoded with the type of the column. */
2734
- function resolveValue(table, key, value) {
2735
- const column = requireColumn(table, key);
2736
- if (value instanceof SelectQuery || value instanceof RecordQuery || value instanceof MutationQuery || value instanceof SqlQuery) throw new TypeError(`Column "${key}" of table "${table.name}" takes a value or an expression, not a query`);
2737
- return toValueNode(value, column.type);
2793
+ /** Creates an expression over the node of a projection of a query, which has a type: only lowering adds projections of nested queries. */
2794
+ function toSelectedExpression(projection) {
2795
+ return toExpression(projection.expression, projection.type);
2738
2796
  }
2739
- // src/query/mutation.ts
2797
+ /** Creates an expression of the value of `field`, a selected aggregate query or query of `exists`, with the type of its value. */
2798
+ function toQueryExpression(field) {
2799
+ const { query } = field;
2800
+ return toExpression(createNode({
2801
+ kind: "nestedQuery",
2802
+ query,
2803
+ db: field.db,
2804
+ field
2805
+ }), query.projections[0].type);
2806
+ }
2807
+ // src/query/pagination.ts
2808
+ /** Creates the parameter of the number of rows of `limit` or `offset`, named by `method`, of query `node`, rejecting a query of one row and a count that is not a non-negative safe integer. */
2809
+ function createPageCount(node, method, count) {
2810
+ if (node.rows !== "many") throw new Error(`${method} applies only to a query of many rows${createPaginationHint(node)}`);
2811
+ if (!Number.isSafeInteger(count) || count < 0) throw new RangeError(`${method} takes a non-negative integer, not ${count}`);
2812
+ return createNode({
2813
+ kind: "param",
2814
+ value: count,
2815
+ type: void 0
2816
+ });
2817
+ }
2818
+ /** Creates the hint of the error of `limit` or `offset` of query `node` of one row: the method to call them before, if any. */
2819
+ function createPaginationHint(node) {
2820
+ if (node.relation?.kind === "one") return "";
2821
+ if (isAggregateQuery(node)) return "; call it before count or another aggregate to aggregate the rows of a page";
2822
+ if (isExistsQuery(node)) return "; call it before exists to check the rows of a page";
2823
+ return "; call it before take or get";
2824
+ }
2825
+ // src/query/select.ts
2740
2826
  /**
2741
- * Immutable query of state `S` that inserts, updates, or deletes rows, unbound or bound to a `Db`.
2827
+ * Immutable select query of state `S`, unbound or bound to a `Db`.
2742
2828
  *
2743
- * Without a selection, it resolves to the number of the rows it changes; `select`, `get`, and `pluck` return the fields of those rows instead.
2829
+ * Every method returns a query of the same kind and leaves this query unchanged.
2744
2830
  * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2745
2831
  * A bound query executes on its `Db` when awaited.
2746
2832
  */
2747
- var MutationQuery = class MutationQuery {
2833
+ var SelectQuery = class SelectQuery {
2748
2834
  table;
2749
2835
  node;
2750
2836
  context;
@@ -2760,242 +2846,295 @@ var MutationQuery = class MutationQuery {
2760
2846
  this.then = db === void 0 ? void 0 : executeOnAwait;
2761
2847
  Object.freeze(this);
2762
2848
  }
2849
+ where(filter) {
2850
+ return this.derive(this.addFilter(filter));
2851
+ }
2763
2852
  select(...args) {
2853
+ this.rejectValue("select");
2854
+ return this.derive({ projections: mergeProjections(this.node.projections, this.node.from, args, this.context) });
2855
+ }
2856
+ clearSelect() {
2857
+ this.rejectValue("clearSelect");
2858
+ return this.derive({ projections: [] });
2859
+ }
2860
+ take() {
2861
+ return this.deriveTaken({});
2862
+ }
2863
+ find(...values) {
2864
+ return this.takeWhere(toPrimaryKeyValues(this.table, values));
2865
+ }
2866
+ findBy(values) {
2867
+ return this.takeWhere(toKeyValues(this.table, values));
2868
+ }
2869
+ get(arg) {
2870
+ this.rejectAggregate("get");
2871
+ return this.deriveTaken({
2872
+ projections: [projectValue(this.node.from, arg, "get")],
2873
+ value: true,
2874
+ rows: toValueRows(this.node.rows)
2875
+ });
2876
+ }
2877
+ pluck(arg) {
2878
+ this.rejectAggregate("pluck");
2879
+ return this.derive({
2880
+ projections: [projectValue(this.node.from, arg, "pluck")],
2881
+ value: true,
2882
+ rows: toValueRows(this.node.rows)
2883
+ });
2884
+ }
2885
+ count(arg) {
2886
+ if (arg !== void 0) return this.aggregateBy("count", arg);
2887
+ this.rejectAggregate("count");
2888
+ return this.deriveAggregate(countProjection);
2889
+ }
2890
+ countDistinct(arg) {
2891
+ return this.aggregateBy("countDistinct", arg);
2892
+ }
2893
+ min(arg) {
2894
+ return this.aggregateBy("min", arg);
2895
+ }
2896
+ max(arg) {
2897
+ return this.aggregateBy("max", arg);
2898
+ }
2899
+ sum(arg) {
2900
+ return this.aggregateBy("sum", arg);
2901
+ }
2902
+ avg(arg) {
2903
+ return this.aggregateBy("avg", arg);
2904
+ }
2905
+ every(arg) {
2906
+ return this.aggregateBy("every", arg);
2907
+ }
2908
+ some(arg) {
2909
+ return this.aggregateBy("some", arg);
2910
+ }
2911
+ stringAgg(arg, delimiter) {
2912
+ return this.aggregateBy("stringAgg", arg, delimiter);
2913
+ }
2914
+ exists() {
2915
+ this.rejectAggregate("exists");
2916
+ return this.deriveAggregate(getExistsProjection());
2917
+ }
2918
+ coalesce(fallback) {
2764
2919
  const { node } = this;
2765
- const { returning } = node;
2766
- if (returning !== void 0 && node.value) throw new Error("select cannot be used after get or pluck; call get or pluck to replace the value");
2920
+ if (!node.value) throw new Error("coalesce applies only to a query of values, such as one made by get, pluck, or an aggregate");
2921
+ return this.derive({ projections: [coalesceValue(node.projections[0], fallback)] });
2922
+ }
2923
+ expr() {
2924
+ const value = this[operandNode]();
2925
+ return toExpression(value, this.node.projections[0].type);
2926
+ }
2927
+ orderBy(...args) {
2928
+ return this.derive({ orderBy: addOrder(this.node, this.context, args) });
2929
+ }
2930
+ limit(count) {
2931
+ return this.derive({ limit: createPageCount(this.node, "limit", count) });
2932
+ }
2933
+ offset(count) {
2934
+ return this.derive({ offset: createPageCount(this.node, "offset", count) });
2935
+ }
2936
+ optional() {
2937
+ return this.changeOneRow("optional", "optional");
2938
+ }
2939
+ nullable() {
2940
+ if (this.node.value) throw new Error("nullable applies only to a query of records; use optional after get, pluck, or an aggregate");
2941
+ return this.changeOneRow("nullable", "nullable");
2942
+ }
2943
+ required() {
2944
+ return this.changeOneRow("required", "one");
2945
+ }
2946
+ insert(values) {
2947
+ return createInsert(this, [values], "one", "insert");
2948
+ }
2949
+ insertMany(records) {
2950
+ if (!Array.isArray(records)) throw new TypeError("insertMany takes an array of records");
2951
+ return createInsert(this, records, "many", "insertMany");
2952
+ }
2953
+ update(set) {
2954
+ return createUpdate(this, set);
2955
+ }
2956
+ delete() {
2957
+ return createDelete(this);
2958
+ }
2959
+ all() {
2960
+ if (this.node.rows !== "many") throw new Error("all applies only to a query of many rows");
2961
+ return this.derive({ all: true });
2962
+ }
2963
+ use(callback, ...args) {
2964
+ return requireDerived(this, callback(this, ...args), "The callback of use");
2965
+ }
2966
+ toSQL(options) {
2967
+ return compileToSQL(this, options);
2968
+ }
2969
+ /**
2970
+ * Returns the node of the query as an operand of an expression, which lowering replaces with a scalar subquery of its value, or with `EXISTS` of its rows for a query of `exists`.
2971
+ *
2972
+ * It rejects a query of records or of rows `many`, which `ScalarQuery` rejects in types.
2973
+ */
2974
+ [operandNode]() {
2975
+ const { node } = this;
2976
+ if (!node.value || node.rows === "many") throw new TypeError("An expression takes a query of one value, such as of get, an aggregate, or exists, not a query of records or of an array");
2977
+ return createNode({
2978
+ kind: "nestedQuery",
2979
+ query: node,
2980
+ db: this.db
2981
+ });
2982
+ }
2983
+ /**
2984
+ * Returns the node of the query as the values of `in`, which lowering replaces with its statement.
2985
+ *
2986
+ * It rejects a query of records, which `ValuesQuery` rejects in types.
2987
+ */
2988
+ [valuesQueryNode]() {
2989
+ const { node } = this;
2990
+ if (!node.value) throw new TypeError("in takes a query of values, such as of pluck, not a query of records");
2991
+ return createNode({
2992
+ kind: "nestedQuery",
2993
+ query: node,
2994
+ db: this.db
2995
+ });
2996
+ }
2997
+ /** Creates a query of the same kind and `Db` with the node changes applied. */
2998
+ derive(changes) {
2999
+ return new SelectQuery(this.table, Object.freeze({
3000
+ ...this.node,
3001
+ ...changes
3002
+ }), this.context, this.db);
3003
+ }
3004
+ /**
3005
+ * Creates a query of the same kind and `Db` with the node changes applied and then those of `take`, in one derived query.
3006
+ *
3007
+ * It adds the changes of `take` to `changes`, which must leave the limit as it is.
3008
+ */
3009
+ deriveTaken(changes) {
3010
+ if ((changes.rows ?? this.node.rows) === "many") {
3011
+ changes.limit = limitToOne(this.node.limit);
3012
+ changes.rows = "one";
3013
+ }
3014
+ return this.derive(changes);
3015
+ }
3016
+ /** Creates the query of the value of `projection`, of an aggregate or of `exists` over the rows of this query, which always returns one row. */
3017
+ deriveAggregate(projection) {
2767
3018
  return this.derive({
2768
- returning: mergeProjections(returning ?? [], node.target, args, this.context),
2769
- value: false
3019
+ projections: [projection],
3020
+ rows: "one",
3021
+ value: true,
3022
+ guaranteed: false
2770
3023
  });
2771
3024
  }
2772
- get(arg) {
2773
- if (this.node.rows === "many") throw new Error("get applies only to a query that changes one row, such as of insert or find; use pluck to return the values of several rows");
2774
- return this.deriveValue(arg, "get");
3025
+ /** Creates the query of the aggregate of `method` over `arg`, a column key or a callback that receives the columns and returns an expression; `delimiter` is the delimiter of `stringAgg`. */
3026
+ aggregateBy(method, arg, delimiter) {
3027
+ this.rejectAggregate(method);
3028
+ return this.deriveAggregate(projectAggregate(method, projectValue(this.node.from, arg, method), delimiter));
2775
3029
  }
2776
- pluck(arg) {
2777
- return this.deriveValue(arg, "pluck");
3030
+ /** Returns the changes of the node that add `filter` with `AND`, ending the guarantee of the row as `FilteredState` does in types. */
3031
+ addFilter(filter) {
3032
+ const { node } = this;
3033
+ return {
3034
+ filters: addUserFilter(node.filters, filter, node.from, this.context),
3035
+ rows: toFilteredRows(node.rows, node.value, node.guaranteed),
3036
+ guaranteed: false
3037
+ };
2778
3038
  }
2779
- toSQL(options) {
2780
- return compileToSQL(this, options);
3039
+ /** Creates the query of `find` and `findBy`: `where` of `values`, an object of column values, returning one row like `take`. */
3040
+ takeWhere(values) {
3041
+ const changes = this.addFilter(values);
3042
+ if (changes.rows === "many") changes.rows = "one";
3043
+ return this.derive(changes);
2781
3044
  }
2782
- /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2783
- [operandNode]() {
2784
- throw new TypeError("An expression takes a query of one value of a table, such as of get, an aggregate, or exists, not a query of insert, update, or delete");
3045
+ /** Creates the query of one row with rows mode `rows` that `method` returns, rejecting a query of many rows. */
3046
+ changeOneRow(method, rows) {
3047
+ if (this.node.rows === "many") throw new Error(`${method} applies only to a query of one row, such as one made by take`);
3048
+ return this.derive({
3049
+ rows,
3050
+ guaranteed: false
3051
+ });
2785
3052
  }
2786
- /** Creates a mutation of the same kind and `Db` with the node changes applied. */
2787
- derive(changes) {
2788
- return new MutationQuery(this.table, Object.freeze({
2789
- ...this.node,
2790
- ...changes
2791
- }), this.context, this.db);
3053
+ /** Rejects a change of the selection by `method` of a query made by `get`, `pluck`, or an aggregate method. */
3054
+ rejectValue(method) {
3055
+ if (!this.node.value) return;
3056
+ this.rejectAggregate(method);
3057
+ throw new Error(`${method} cannot be used after get or pluck; call get or pluck to replace the value`);
2792
3058
  }
2793
- /** Creates the mutation that returns the value of `arg` of `method`, a column key or a callback that receives the columns and returns an expression, of each changed row. */
2794
- deriveValue(arg, method) {
3059
+ /** Rejects `method`, which replaces the value or the selection, on a query made by an aggregate method or `exists`. */
3060
+ rejectAggregate(method) {
2795
3061
  const { node } = this;
2796
- return this.derive({
2797
- returning: [projectValue(node.target, arg, method)],
2798
- value: true,
2799
- rows: toValueRows(node.rows)
2800
- });
3062
+ if (isAggregateQuery(node)) throw new Error(`${method} cannot be used after an aggregate`);
3063
+ if (isExistsQuery(node)) throw new Error(`${method} cannot be used after exists`);
2801
3064
  }
2802
3065
  };
2803
3066
  /**
2804
- * Creates the insert of `records` into the table of `query`, which must have no clauses, in rows mode `rows`: `one` for `insert` and `many` for `insertMany`, named by `method`.
2805
- *
2806
- * It returns the number of the inserted rows, until a selection returns their fields.
2807
- */
2808
- function createInsert(query, records, rows, method) {
2809
- const { node } = query;
2810
- if (!isTableQuery(node)) throw new Error(`${method} applies only to a query of a table without clauses, such as filters or selected fields; select the fields that it returns after it`);
2811
- const { columns, values } = toInsertRows(node.from.table, records, method);
2812
- return new MutationQuery(query.table, Object.freeze({
2813
- kind: "insert",
2814
- target: node.from,
2815
- columns,
2816
- values,
2817
- returning: void 0,
2818
- rows,
2819
- value: false
2820
- }), query.context, query.db);
2821
- }
2822
- /** Creates the update of the rows of `query` that `set` gives, as `update` takes it, in the rows mode of the query. */
2823
- function createUpdate(query, set) {
2824
- const { node } = query;
2825
- checkChangedRows(node, "update");
2826
- return new MutationQuery(query.table, Object.freeze({
2827
- kind: "update",
2828
- target: node.from,
2829
- set: toAssignments(node.from, set),
2830
- filters: node.filters,
2831
- returning: void 0,
2832
- rows: node.rows,
2833
- value: false
2834
- }), query.context, query.db);
2835
- }
2836
- /** Creates the delete of the rows of `query`, in the rows mode of the query. */
2837
- function createDelete(query) {
2838
- const { node } = query;
2839
- checkChangedRows(node, "delete");
2840
- return new MutationQuery(query.table, Object.freeze({
2841
- kind: "delete",
2842
- target: node.from,
2843
- filters: node.filters,
2844
- returning: void 0,
2845
- rows: node.rows,
2846
- value: false
2847
- }), query.context, query.db);
2848
- }
2849
- /**
2850
- * Rejects a query whose rows `method`, `update` or `delete`, cannot change: one of a relation, with selected fields, which a mutation selects after it, with an order, a limit, or an offset, or without a filter that restricts its rows unless `all` allows it.
2851
- *
2852
- * A filter simplified to `TRUE`, such as `where({})`, restricts no row.
2853
- */
2854
- function checkChangedRows(node, method) {
2855
- if (node.relation !== void 0) throw new Error(`${method} applies only to a query of a table, not of a relation`);
2856
- if (node.projections.length > 0) throw new Error(`${method} returns the fields selected after it, not before; call select, get, or pluck after ${method}`);
2857
- if (node.orderBy.length > 0 || node.limit !== void 0 || node.offset !== void 0) throw new Error(`${method} cannot sort or limit the rows it changes; choose them with where, find, or findBy instead of take, limit, offset, or orderBy`);
2858
- const predicate = combineFilters(node.filters);
2859
- if (!node.all && predicate.kind === "boolean" && predicate.value) throw new Error(`${method} requires a filter that restricts the rows, such as of where or find; call all() to ${method} every row`);
2860
- }
2861
- // src/query/projections.ts
2862
- /**
2863
- * Creates the fields of `select` over `source`, appending new keys and replacing existing ones in place.
3067
+ * Returns `result`, which a callback named by `subject` returned for `query`, after checking that it is `query` or a query derived from it.
2864
3068
  *
2865
- * `args` are the arguments of `select`: `"*"`, column keys, or a callback that receives the references of `source` with the relations of `context` and returns a selection.
3069
+ * An ancestor of `query` also passes, since only the source occurrence is compared.
2866
3070
  */
2867
- function mergeProjections(projections, source, args, context) {
2868
- const result = projections.slice();
2869
- const first = args[0];
2870
- if (typeof first === "function") addSelection(result, first(createSelectionRefs(source, context)));
2871
- else {
2872
- const keys = first === "*" ? Object.keys(source.table.columns) : args;
2873
- for (const key of keys) setProjection(result, projectColumn(source, key));
2874
- }
3071
+ function requireDerived(query, result, subject) {
3072
+ if (!(result instanceof SelectQuery) || result.node.from !== query.node.from) throw new Error(`${subject} must return the query it receives or one derived from it`);
2875
3073
  return result;
2876
3074
  }
2877
- /** Adds the fields of `selection`, expressions and queries by key, to `projections`, replacing existing keys in place. */
2878
- function addSelection(projections, selection) {
2879
- for (const key of Reflect.ownKeys(selection)) {
2880
- if (typeof key === "symbol") throw new TypeError("A selected field must have a string key");
2881
- setProjection(projections, selectValue(key, selection[key]));
2882
- }
2883
- }
2884
- /**
2885
- * Creates the projection of the value of `get` or `pluck`, or of the argument of an aggregate method, such as `max`, over `source`.
2886
- *
2887
- * `arg` is the argument of `method`: a column key, or a callback that receives the columns and returns an expression.
2888
- */
2889
- function projectValue(source, arg, method) {
2890
- if (typeof arg !== "function") return projectColumn(source, arg);
2891
- const value = arg(createColumnRefs(source));
2892
- if (!isExpression(value)) throw new TypeError(`The callback of ${method} must return an expression`);
2893
- const type = getType(value);
2894
- if (!type) throw new TypeError(`The expression of ${method} has no type to decode its values; build a sql fragment with a type, such as sql(t.integer)`);
2895
- return projectExpression("value", value, type);
3075
+ /** Binds a query to `db`, so that awaiting it executes it there. */
3076
+ function bindQuery(query, db) {
3077
+ return new SelectQuery(query.table, query.node, query.context, db);
2896
3078
  }
2897
- /**
2898
- * Creates the projection of the value of `field`, the only projection of a query of values, whose `NULL` `fallback` replaces: a value that the type of the field encodes, an expression, or a query of one value.
2899
- *
2900
- * The projection of an aggregate keeps its call, which lowering builds, and adds the fallback after its earlier ones.
2901
- * The projection of `exists` stays as it is, since `EXISTS` is never `NULL`.
2902
- */
2903
- function coalesceValue(field, fallback) {
2904
- if (fallback === null || fallback === void 0) throw new TypeError(`coalesce takes a value other than ${String(fallback)}`);
2905
- if (isExistsProjection(field)) return field;
2906
- const value = toValueNode(fallback, field.type);
2907
- if (isAggregateProjection(field)) return addFallback(field, value);
2908
- return Object.freeze({
2909
- key: field.key,
2910
- expression: createList("coalesce(", [field.expression, value], ")"),
2911
- type: field.type
2912
- });
3079
+ /** Starts a query over a new occurrence of the table. */
3080
+ function from(table) {
3081
+ return startQuery(table, noContext);
2913
3082
  }
2914
- /** Creates the field of a value of a selection under `key`: an expression with a type, or a query whose rows become its value. */
2915
- function selectValue(key, value) {
2916
- if (value instanceof SelectQuery) return Object.freeze({
2917
- key,
2918
- query: value.node,
2919
- db: value.db
2920
- });
2921
- if (value instanceof RecordQuery) throw new TypeError(`Selected field "${key}" is a query of $select, which cannot be nested; select its fields directly instead`);
2922
- if (value instanceof MutationQuery) throw new TypeError(`Selected field "${key}" is a query of insert, update, or delete, which cannot be nested`);
2923
- if (value instanceof SqlQuery) throw new TypeError(`Selected field "${key}" is a query of $query, which cannot be nested`);
2924
- if (!isExpression(value)) throw new TypeError(`Selected field "${key}" must be an expression or a query`);
2925
- const type = getType(value);
2926
- if (!type) throw new TypeError(`Selected field "${key}" has no type to decode its values; build a sql fragment with a type, such as sql(t.integer)`);
2927
- return projectExpression(key, value, type);
3083
+ /** Starts a query over a new occurrence of the table with the relations of `context`, such as a query of a table of a schema. */
3084
+ function startQuery(table, context) {
3085
+ return new SelectQuery(table, createQueryNode(Object.freeze({
3086
+ kind: "table",
3087
+ table
3088
+ })), context);
2928
3089
  }
2929
- /** Creates the projection of a column of the table of `source` under its key. */
2930
- function projectColumn(source, key) {
2931
- const { type } = requireColumn(source.table, key);
2932
- return Object.freeze({
2933
- key,
2934
- expression: createNode({
2935
- kind: "column",
2936
- source,
2937
- key
2938
- }),
2939
- type
2940
- });
3090
+ // src/expression/functions.ts
3091
+ function coalesce(first, ...rest) {
3092
+ return callFunction("coalesce", first, rest);
2941
3093
  }
2942
- /** Creates the projection of an expression under `key`, decoded with `type`, the type of the expression. */
2943
- function projectExpression(key, value, type) {
2944
- return Object.freeze({
2945
- key,
2946
- expression: toNode(value),
2947
- type
2948
- });
3094
+ function greatest(first, ...rest) {
3095
+ return callFunction("greatest", first, rest);
2949
3096
  }
2950
- /** Adds or replaces a field by key, rejecting a key that a record cannot have. */
2951
- function setProjection(projections, projection) {
2952
- const { key } = projection;
2953
- if (!isRecordKey(key)) throw new Error(`Field "${key}" cannot be selected: it is not a valid record key`);
2954
- for (let index = 0; index < projections.length; index++) if (projections[index].key === key) {
2955
- projections[index] = projection;
2956
- return;
2957
- }
2958
- projections.push(projection);
3097
+ function least(first, ...rest) {
3098
+ return callFunction("least", first, rest);
2959
3099
  }
2960
- // src/query/record.ts
2961
- /**
2962
- * Immutable query of `$select` of state `S`, unbound or bound to a `Db`: one record whose fields are the values of expressions and the results of independent queries, selected in one statement.
2963
- *
2964
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2965
- * A bound query executes on its `Db` when awaited.
2966
- */
2967
- var RecordQuery = class {
2968
- node;
2969
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2970
- db;
2971
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2972
- then;
2973
- constructor(node, db) {
2974
- this.node = node;
2975
- this.db = db;
2976
- this.then = db === void 0 ? void 0 : executeOnAwait;
2977
- Object.freeze(this);
2978
- }
2979
- toSQL(options) {
2980
- return compileToSQL(this, options);
3100
+ function caseWhen(type, branches, otherwise) {
3101
+ if (!isType(type)) throw new TypeError("caseWhen() accepts a type, not a column");
3102
+ if (branches.length === 0) return toExpression(toCastValueNode(otherwise === void 0 ? null : otherwise, type), type);
3103
+ const fragments = [];
3104
+ const values = [];
3105
+ for (const branch of branches) {
3106
+ fragments.push(values.length === 0 ? "CASE WHEN " : " WHEN ", " THEN ");
3107
+ values.push(toCaseConditionNode(branch[0]), toCastValueNode(branch[1], type));
2981
3108
  }
2982
- /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2983
- [operandNode]() {
2984
- throw new TypeError("An expression takes a query of one value of a table, such as of get, an aggregate, or exists, not a query of $select");
3109
+ if (otherwise !== void 0) {
3110
+ fragments.push(" ELSE ");
3111
+ values.push(toCastValueNode(otherwise, type));
2985
3112
  }
2986
- };
2987
- /**
2988
- * Starts the query of `$select` of `selection`, an object of expressions and queries by key, bound to `db` when given.
2989
- *
2990
- * It reads the keys and values of `selection` when it is called.
2991
- */
2992
- function startRecordQuery(selection, db) {
2993
- const projections = [];
2994
- addSelection(projections, selection);
2995
- return new RecordQuery(Object.freeze({
2996
- kind: "record",
2997
- projections
2998
- }), db);
3113
+ fragments.push(" END");
3114
+ return toExpression(createNode({
3115
+ kind: "raw",
3116
+ fragments,
3117
+ values
3118
+ }), type);
3119
+ }
3120
+ /** Converts a condition of `caseWhen` into a node, rejecting a value other than an expression or a query, such as an object of column values, which has no table here. */
3121
+ function toCaseConditionNode(condition) {
3122
+ if (!isOperandSource(condition)) throw new TypeError("A condition of caseWhen must be an expression or a query of one value");
3123
+ return condition[operandNode]();
3124
+ }
3125
+ /** Creates the expression of the call of the SQL function `name`, of the type of its first operand. */
3126
+ function callFunction(name, first, rest) {
3127
+ const expression = toTypedExpression(first, name);
3128
+ const type = getType(expression);
3129
+ const operands = [toNode(expression)];
3130
+ for (const value of rest) operands.push(toFunctionOperandNode(value, type, name));
3131
+ return toExpression(createList(`${name}(`, operands, ")"), type);
3132
+ }
3133
+ /** Converts the first operand of the function `name` into an expression with a type, rejecting any other value. */
3134
+ function toTypedExpression(value, name) {
3135
+ const expression = value instanceof SelectQuery ? value.expr() : value;
3136
+ if (!isExpression(expression) || getType(expression) === void 0) throw new TypeError(`The first operand of ${name} must be a query of one value of a table or an expression with a type to decode the result; build a sql fragment with a type, such as sql(t.integer)`);
3137
+ return expression;
2999
3138
  }
3000
3139
  // src/query/relations.ts
3001
3140
  /** Creates the contexts of the queries of the tables under `keys` in a schema of relations `relations`, by table key. */
@@ -3141,12 +3280,7 @@ function param(type, value) {
3141
3280
  const valueType = getType(type);
3142
3281
  return toExpression(toValueNode(value, valueType), valueType);
3143
3282
  }
3144
- const node = toValueNode(value, type);
3145
- return toExpression(node.kind === "param" ? createNode({
3146
- kind: "cast",
3147
- operand: node,
3148
- type
3149
- }) : node, type);
3283
+ return toExpression(toCastValueNode(value, type), type);
3150
3284
  }
3151
3285
  function isTemplateStrings(value) {
3152
3286
  return Array.isArray(value);
@@ -3897,4 +4031,4 @@ function createLockStatement(key) {
3897
4031
  function defineHelper(_table, helper) {
3898
4032
  return (query, ...args) => requireDerived(query, helper(query, ...args), "The callback of a helper");
3899
4033
  }
3900
- export { NotFoundError, RequiredRelationError, ResultDecodeError, and, asc, compare, createDatabase, createStatement, defineFilter, defineGenericOperator, defineHelper, defineSchema, defineTable, defineType, desc, equalityOperators, from, identifier, many, not, one, or, orderBy, orderingOperators, param, sql, textOperators };
4034
+ export { FALSE, NotFoundError, RequiredRelationError, ResultDecodeError, TRUE, and, asc, caseWhen, coalesce, compare, createDatabase, createStatement, defineFilter, defineGenericOperator, defineHelper, defineSchema, defineTable, defineType, desc, equalityOperators, from, greatest, identifier, least, literal, many, not, one, or, orderBy, orderingOperators, param, sql, textOperators };