kern-orm 0.14.0 → 0.16.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,3575 +1,13 @@
1
- import { A as valuesQueryNode, B as oneNode, C as defineType, D as equalityOperators, E as Column, F as falseNode, I as noFilters, L as noJoins, M as createList, N as createNode, P as createSelectNode, R as noOrder, S as getBooleanType, T as isType$1, V as trueNode, _ as toCastValueNode, b as toNode, c as compare, d as getType, f as isExpression, g as toBooleanExpression, h as rejectSqlQueryOperand, i as textOperators, j as defineGenericOperator, k as isEqualityCompatible, l as compareNodes, m as operandNode, n as text, p as isOperandSource, s as orderingOperators, u as createIsNullNode, v as toExpression, w as describeRejectedDbType, x as toValueNode, y as toFunctionOperandNode, z as noProjections } from "./text-ucmJCsCN.mjs";
2
- import { SqlFragment, SqlQuery, assertUntypedValue, bindParameter, createFieldDecodeError, createResultDecodeError, encodeParameter, isRecordKey, quoteIdentifier, renderFragment, startSqlQuery, takeOnlyRow, toMissingResult, toValueRows } from "kern-db/builder";
3
- import { ConnectionError, NotFoundError, NotFoundError as NotFoundError$1, QueryError, ResultDecodeError, ResultDecodeError as ResultDecodeError$1, TransactionConnectionError, createDatabase, createStatement, createStatement as createStatement$1, identifier as identifier$1, isOutcomeUnknown, isQueryError, toDriverError } from "kern-db";
4
- import { types } from "node:util";
5
- // src/ast/boolean.ts
6
- /** Combines predicate nodes with `AND` or `OR`, flattening nested groups of the same kind. */
7
- function combineNodes(kind, operands) {
8
- const neutral = kind === "and";
9
- const flat = [];
10
- for (const operand of operands) if (operand.kind === "boolean") {
11
- if (operand.value !== neutral) return operand;
12
- } else if (operand.kind === kind) flat.push(...operand.operands);
13
- else flat.push(operand);
14
- if (flat.length === 0) return neutral ? trueNode : falseNode;
15
- return flat.length === 1 ? flat[0] : createNode({
16
- kind,
17
- operands: flat
18
- });
19
- }
20
- /** Negates a predicate node, simplifying constants and double negation. */
21
- function negateNode(operand) {
22
- if (operand.kind === "boolean") return operand.value ? falseNode : trueNode;
23
- if (operand.kind === "not") return operand.operand;
24
- return createNode({
25
- kind: "not",
26
- operand
27
- });
28
- }
29
- /** Combines the filters of a query into its effective predicate, `relation AND scope AND user`, which is `TRUE` when they restrict no row. */
30
- function combineFilters(filters) {
31
- const operands = [];
32
- if (filters.relation !== void 0) operands.push(filters.relation);
33
- if (filters.scope !== void 0) operands.push(filters.scope);
34
- if (filters.user !== void 0) operands.push(filters.user);
35
- return combineNodes("and", operands);
36
- }
37
- // src/expression/predicates.ts
38
- /** 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. */
39
- function toConditionNode(operand) {
40
- if (isOperandSource(operand)) return operand[operandNode]();
41
- if (operand instanceof SqlQuery) rejectSqlQueryOperand();
42
- 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");
43
- return createNode({
44
- kind: "values",
45
- values: operand
46
- });
47
- }
48
- /** Tells whether `value` can be an object of column values: a plain object, of this or another realm, or an object that has keys. */
49
- function isColumnValues(value) {
50
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
51
- const prototype = Object.getPrototypeOf(value);
52
- return prototype === null || Object.getPrototypeOf(prototype) === null || Object.keys(value).length > 0;
53
- }
54
- function and(...operands) {
55
- return combineConditions("and", operands);
56
- }
57
- function or(...operands) {
58
- return combineConditions("or", operands);
59
- }
60
- function not(operand) {
61
- return toBooleanExpression(negateNode(toConditionNode(operand)));
62
- }
63
- function combineConditions(kind, operands) {
64
- const nodes = [];
65
- for (const operand of operands) nodes.push(toConditionNode(operand));
66
- return toBooleanExpression(combineNodes(kind, nodes));
67
- }
68
- // src/expression/constants.ts
69
- /** Condition that always holds, such as for a branch of `and` built in code: `and(check, isAdmin ? TRUE : other)`. */
70
- const TRUE = /* @__PURE__ */ toExpression(trueNode, /* @__PURE__ */ getBooleanType());
71
- /** Condition that never holds, such as for a branch of `or` built in code: `or(check, isAdmin ? other : FALSE)`. */
72
- const FALSE = /* @__PURE__ */ toExpression(falseNode, /* @__PURE__ */ getBooleanType());
73
- // src/query/literal.ts
74
- /**
75
- * Field of a selection whose value is `T`, made by `literal`.
76
- *
77
- * It is not an expression: it has no SQL, so only a selection takes it.
78
- */
79
- var Literal = class {
80
- literal;
81
- constructor(literal) {
82
- this.literal = literal;
83
- Object.freeze(this);
84
- }
85
- /** Rejects the literal as an operand of an expression: a statement has no SQL of it. */
86
- [operandNode]() {
87
- throw new TypeError("A literal is only a selected field and has no SQL; pass a value to an expression through param");
88
- }
89
- };
90
- /**
91
- * 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.
92
- *
93
- * It lets a branch of a selection skip a column or a nested query, such as `withHint ? field.hint : literal(null)`.
94
- * To use a value in SQL, such as in a condition, pass it through `param` instead.
95
- */
96
- function literal(value) {
97
- return new Literal(value);
98
- }
99
- // src/query/exists.ts
100
- let existsProjection;
101
- /** Returns the projection of whether a query has a row, the only projection of a query made by `exists`. */
102
- function getExistsProjection() {
103
- existsProjection ??= Object.freeze({
104
- key: "exists",
105
- expression: trueNode,
106
- type: getBooleanType()
107
- });
108
- return existsProjection;
109
- }
110
- /** Tells whether `node` is a query of `exists`, whose value is whether the rows that its filters, limit, and offset choose exist. */
111
- function isExistsQuery(node) {
112
- return node.value && isExistsProjection(node.projections[0]);
113
- }
114
- /** Tells whether a selected field is the projection of `exists`, which only `exists` selects. */
115
- function isExistsProjection(field) {
116
- return field === existsProjection;
117
- }
118
- // src/query/aggregate.ts
119
- /** Type of a count: a `bigint` of PostgreSQL decoded as a number, rejecting a count that a number cannot hold exactly. */
120
- const countType = /* @__PURE__ */ defineType({ sqlType: "bigint" }).transform({
121
- decode: (text) => decodeSafeInteger(text, "Count"),
122
- encode: (value) => String(value)
123
- }).withOperators(orderingOperators);
124
- /** Types of the sums of the values of `smallint` and `integer` types, by the type of the values, created once for each. */
125
- const sumTypes = /* @__PURE__ */ new WeakMap();
126
- const noFallbacks = /* @__PURE__ */ Object.freeze([]);
127
- /** Definitions of the aggregate methods that take a column or an expression. */
128
- const aggregateDefinitions = /* @__PURE__ */ Object.freeze({
129
- count: {
130
- name: "count",
131
- distinct: false,
132
- ordered: false,
133
- type: toCountType
134
- },
135
- countDistinct: {
136
- name: "count",
137
- distinct: true,
138
- ordered: false,
139
- type: toCountType
140
- },
141
- min: {
142
- name: "min",
143
- distinct: false,
144
- ordered: false,
145
- type: toArgumentType
146
- },
147
- max: {
148
- name: "max",
149
- distinct: false,
150
- ordered: false,
151
- type: toArgumentType
152
- },
153
- sum: {
154
- name: "sum",
155
- distinct: false,
156
- ordered: false,
157
- type: toSumType
158
- },
159
- avg: {
160
- name: "avg",
161
- distinct: false,
162
- ordered: false,
163
- type: toAverageType
164
- },
165
- every: {
166
- name: "bool_and",
167
- distinct: false,
168
- ordered: false,
169
- type: toArgumentType
170
- },
171
- some: {
172
- name: "bool_or",
173
- distinct: false,
174
- ordered: false,
175
- type: toArgumentType
176
- },
177
- stringAgg: {
178
- name: "string_agg",
179
- distinct: false,
180
- ordered: true,
181
- type: toArgumentType
182
- }
183
- });
184
- /** Argument `*` of `count(*)`. */
185
- const allRowsNode = /* @__PURE__ */ createNode({
186
- kind: "raw",
187
- fragments: ["*"],
188
- values: []
189
- });
190
- /** Projection of `count(*)`, which `count` without an argument selects; its value does not depend on the values or the order of the rows. */
191
- const countProjection = /* @__PURE__ */ Object.freeze({
192
- key: "count",
193
- expression: /* @__PURE__ */ createNode({
194
- kind: "aggregate",
195
- name: "count",
196
- distinct: false,
197
- arguments: [allRowsNode],
198
- orderBy: noOrder,
199
- filter: void 0
200
- }),
201
- type: countType,
202
- ordered: false,
203
- fallbacks: noFallbacks
204
- });
205
- /**
206
- * Creates the projection of the aggregate of `method` over the values of `argument`, the projection of a column or an expression of each row.
207
- *
208
- * `delimiter` is the delimiter of `stringAgg`, sent as a parameter.
209
- */
210
- function projectAggregate(method, argument, delimiter) {
211
- return Object.freeze({
212
- key: method,
213
- expression: createAggregateCall(method, argument.expression, delimiter),
214
- type: toAggregateType(method, argument.type),
215
- ordered: aggregateDefinitions[method].ordered,
216
- fallbacks: noFallbacks
217
- });
218
- }
219
- /**
220
- * Creates the call of the aggregate function of `method` over the values of `argument`.
221
- *
222
- * `delimiter` is the delimiter of `stringAgg`, sent as a parameter, `orderBy` the order of the rows that the function takes, and `filter` their condition.
223
- */
224
- function createAggregateCall(method, argument, delimiter, orderBy = noOrder, filter) {
225
- const definition = aggregateDefinitions[method];
226
- const args = [argument];
227
- if (delimiter !== void 0) args.push(createNode({
228
- kind: "param",
229
- value: delimiter,
230
- type: void 0
231
- }));
232
- return createNode({
233
- kind: "aggregate",
234
- name: definition.name,
235
- distinct: definition.distinct,
236
- arguments: args,
237
- orderBy,
238
- filter
239
- });
240
- }
241
- /** Creates the call of `count(*)` over the rows that `filter` takes. */
242
- function createCountCall(filter) {
243
- return createNode({
244
- kind: "aggregate",
245
- name: "count",
246
- distinct: false,
247
- arguments: [allRowsNode],
248
- orderBy: noOrder,
249
- filter
250
- });
251
- }
252
- /** Returns the type that decodes the value of the aggregate of `method` over the values of type `argument`, rejecting what `method` cannot decode, such as `avg` of a type of the SQL type `bigint`. */
253
- function toAggregateType(method, argument) {
254
- return aggregateDefinitions[method].type(argument);
255
- }
256
- /** Creates the projection of the aggregate of `field` whose `NULL` `fallback` replaces after its earlier fallbacks. */
257
- function addFallback(field, fallback) {
258
- const fallbacks = field.fallbacks.slice();
259
- fallbacks.push(fallback);
260
- return Object.freeze({
261
- key: field.key,
262
- expression: field.expression,
263
- type: field.type,
264
- ordered: field.ordered,
265
- fallbacks
266
- });
267
- }
268
- /** Tells whether `node` is an aggregate query, whose value is the aggregate over the rows that its filters, limit, and offset choose. */
269
- function isAggregateQuery(node) {
270
- return node.value && isAggregateProjection(node.projections[0]);
271
- }
272
- /** 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, unless `map` or `transform` converts its value. */
273
- function isSelectedAsValue(node) {
274
- return node.conversion === void 0 && (isAggregateQuery(node) || isExistsQuery(node));
275
- }
276
- /** Tells whether a selected field is the projection of an aggregate, which only the aggregate methods select. */
277
- function isAggregateProjection(field) {
278
- return "ordered" in field;
279
- }
280
- function toCountType() {
281
- return countType;
282
- }
283
- function toArgumentType(argument) {
284
- return argument;
285
- }
286
- /** 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. */
287
- function toSumType(argument) {
288
- if (argument.castType !== "smallint" && argument.castType !== "integer") return argument;
289
- let type = sumTypes.get(argument);
290
- if (type === void 0) {
291
- type = defineType({ sqlType: "bigint" }).transform({
292
- decode: (text) => {
293
- decodeSafeInteger(text, "Sum");
294
- return argument.decode(text);
295
- },
296
- encode: (value) => argument.encode(value)
297
- }).withOperators(argument.operators);
298
- sumTypes.set(argument, type);
299
- }
300
- return type;
301
- }
302
- /** 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`. */
303
- function toAverageType(argument) {
304
- 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");
305
- return argument;
306
- }
307
- /** Decodes `text` of a `bigint` as a number, rejecting one that a number cannot hold exactly; `subject` names it in the error. */
308
- function decodeSafeInteger(text, subject) {
309
- const number = Number(text);
310
- if (!Number.isSafeInteger(number)) throw new RangeError(`${subject} ${text} is outside the safe integer range of numbers`);
311
- return number;
312
- }
313
- // src/query/column-refs.ts
314
- /** Context of a query whose table has no relations, such as one of `from(table)`. */
315
- const noContext = /* @__PURE__ */ Object.freeze({ relations: /* @__PURE__ */ Object.freeze({}) });
316
- /** Creates the references of the callbacks of queries over `source`: expressions of its columns, each with the type of its column, and the relations of `context`. */
317
- function createSelectionRefs(source, context) {
318
- const refs = {};
319
- const { columns } = source.table;
320
- for (const key of Object.keys(columns)) refs[key] = toExpression(createNode({
321
- kind: "column",
322
- source,
323
- key
324
- }), columns[key].type);
325
- return Object.defineProperties(refs, context.relations);
326
- }
327
- // src/ast/projections.ts
328
- /**
329
- * Returns the position of the projection that has the value of `expression`, such as a sort expression or a key of a group: a projection of the same value, as `isSameValue` tells, or `-1`.
330
- */
331
- function findValueProjection(projections, expression) {
332
- return projections.findIndex((projection) => isSameValue(projection.expression, expression));
333
- }
334
- /**
335
- * Tells whether `left` and `right` are sure to have the same value: they are the same column of the same source or the same expression node.
336
- *
337
- * Only the same node or column guarantees one value: PostgreSQL may or may not evaluate equal expressions built apart once, and gives each its own parameters.
338
- */
339
- function isSameValue(left, right) {
340
- return left.kind === "column" && right.kind === "column" ? left.source === right.source && left.key === right.key : left === right;
341
- }
342
- // src/table/table.ts
343
- function defineTable(name, definitions, options) {
344
- return createTable(name, definitions, options, void 0);
345
- }
346
- /**
347
- * Creates a table-definition function with the given naming convention, for an application to define its tables with.
348
- *
349
- * Its tables have the same types as those of `defineTable`.
350
- */
351
- function createTableFactory(factoryOptions) {
352
- const deriveColumnName = factoryOptions.columnName;
353
- if (typeof deriveColumnName !== "function") throw new TypeError("The columnName option of createTableFactory must be a function");
354
- return ((name, definitions, options) => createTable(name, definitions, options, deriveColumnName));
355
- }
356
- /** Creates the table that `defineTable` defines, naming its columns by `deriveColumnName` if given. */
357
- function createTable(name, definitions, options, deriveColumnName) {
358
- const columns = {};
359
- for (const [key, definition] of Object.entries(definitions)) {
360
- if (key.startsWith("$")) throw new Error(`Column key "${key}" of table "${name}" must not start with "$"`);
361
- if (!isRecordKey(key)) throw new Error(`Column key "__proto__" of table "${name}" is not allowed; use columnName("__proto__")`);
362
- const column = toColumn(definition);
363
- if (!column) {
364
- const rejected = describeRejectedDbType(definition);
365
- throw new TypeError(`Column "${key}" of table "${name}" must be a type of kern-orm or a column${rejected ? `, not ${rejected}` : ""}`);
366
- }
367
- columns[key] = column;
368
- }
369
- if (deriveColumnName) nameColumns(name, columns, deriveColumnName);
370
- const singleton = options?.singleton;
371
- if (singleton !== void 0 && typeof singleton !== "boolean") throw new TypeError(`The singleton option of table "${name}" must be a boolean`);
372
- return Object.freeze({
373
- kind: "table",
374
- name,
375
- columns: Object.freeze(columns),
376
- keys: defineKeys(name, columns, options),
377
- singleton: singleton === true
378
- });
379
- }
380
- /**
381
- * Replaces unnamed columns of table `name` with copies whose physical names are derived from their keys, so that a column shared with other tables stays as it is.
382
- *
383
- * It calls `deriveColumnName`, which an application gives, once for each such column.
384
- * It rejects a derived name that is not a non-empty string, which PostgreSQL rejects only when a query runs, and a derived name that another column has, since two keys would silently read one column.
385
- * Duplicate names set with `columnName` are allowed, as in `defineTable`.
386
- */
387
- function nameColumns(name, columns, deriveColumnName) {
388
- const keys = Object.keys(columns);
389
- const derivedKeys = [];
390
- for (const key of keys) {
391
- const column = columns[key];
392
- if (column.attributes.name === void 0) {
393
- const columnName = deriveColumnName(key);
394
- if (typeof columnName !== "string" || columnName === "") throw new TypeError(`The name derived for column "${key}" of table "${name}" must be a non-empty string`);
395
- columns[key] = column.columnName(columnName);
396
- derivedKeys.push(key);
397
- }
398
- }
399
- for (const key of derivedKeys) {
400
- const columnName = columns[key].attributes.name;
401
- for (const other of keys) if (other !== key && columns[other].attributes.name === columnName) throw new Error(`Columns "${key}" and "${other}" of table "${name}" have one physical name "${columnName}"; set another name with columnName()`);
402
- }
403
- }
404
- /**
405
- * Defines the keys of table `name` of `columns` from the keys marked on the columns and those of `options`.
406
- *
407
- * The unique keys are those of the columns in their order, followed by those of the options.
408
- * It rejects a primary key declared twice, a key of the options with fewer than two columns, an unknown column or a column listed twice in such a key, a nullable column of the primary key, and two keys of the same columns.
409
- */
410
- function defineKeys(name, columns, options) {
411
- let primaryKey;
412
- const unique = [];
413
- for (const key of Object.keys(columns)) {
414
- const keyKind = columns[key].attributes.keyKind;
415
- if (keyKind === "primaryKey") {
416
- if (primaryKey !== void 0) throw new Error(`Table "${name}" marks columns "${primaryKey[0]}" and "${key}" with primaryKey(); list the columns of a primary key of several columns in the options`);
417
- primaryKey = Object.freeze([key]);
418
- } else if (keyKind === "unique") unique.push(Object.freeze([key]));
419
- }
420
- if (options?.primaryKey !== void 0) {
421
- if (primaryKey !== void 0) throw new Error(`Table "${name}" declares its primary key both on column "${primaryKey[0]}" and in the options`);
422
- primaryKey = toKeyColumns(name, columns, options.primaryKey);
423
- }
424
- if (options?.unique !== void 0) {
425
- if (!Array.isArray(options.unique)) throw new TypeError(`Unique keys in the options of table "${name}" must be an array`);
426
- for (const key of options.unique) unique.push(toKeyColumns(name, columns, key));
427
- }
428
- for (const key of primaryKey ?? []) if (columns[key].type.isNullable) throw new Error(`Primary key column "${key}" of table "${name}" must not be nullable`);
429
- const keys = primaryKey === void 0 ? unique : [primaryKey, ...unique];
430
- for (let index = 1; index < keys.length; index++) for (let other = 0; other < index; other++) if (hasSameColumns(keys[index], keys[other])) throw new Error(`Table "${name}" declares the key of columns ${keys[index].map((key) => `"${key}"`).join(", ")} twice`);
431
- return Object.freeze({
432
- primaryKey,
433
- unique: Object.freeze(unique)
434
- });
435
- }
436
- /** Returns the column keys of a key of several columns from the options of table `name`, frozen, rejecting what `defineKeys` rejects in such a key. */
437
- function toKeyColumns(name, columns, key) {
438
- if (!Array.isArray(key) || key.length < 2) throw new Error(`A key in the options of table "${name}" must list at least two columns; mark a key of one column with primaryKey() or unique()`);
439
- for (let index = 0; index < key.length; index++) {
440
- const column = key[index];
441
- if (typeof column !== "string" || !Object.hasOwn(columns, column)) throw new Error(`A key in the options of table "${name}" lists unknown column "${column}"`);
442
- if (key.indexOf(column) !== index) throw new Error(`A key in the options of table "${name}" lists column "${column}" twice`);
443
- }
444
- return Object.freeze(key.slice());
445
- }
446
- /** Tells whether keys `key` and `other` have the same columns, in any order; neither lists a column twice. */
447
- function hasSameColumns(key, other) {
448
- return key.length === other.length && key.every((column) => other.includes(column));
449
- }
450
- /** Finds the column of `table` under `key`, ignoring properties inherited from the object prototype, such as `toString`. */
451
- function findColumn(table, key) {
452
- return Object.hasOwn(table.columns, key) ? table.columns[key] : void 0;
453
- }
454
- /** Tells whether the columns of `table` under `columns` are exactly a key of it, primary or unique, in any order, as `IsKey` does in types. */
455
- function isKey(table, columns) {
456
- return findKey(table, columns) !== void 0;
457
- }
458
- /** Returns the key of `table`, primary or unique, whose columns are exactly those under `columns` in any order, as `isKey` tells, or `undefined`. */
459
- function findKey(table, columns) {
460
- const listed = new Set(columns);
461
- const isListed = (key) => key.length === listed.size && isKeyAmong(key, listed);
462
- const { primaryKey, unique } = table.keys;
463
- return primaryKey !== void 0 && isListed(primaryKey) ? primaryKey : unique.find(isListed);
464
- }
465
- /** Tells whether the columns of `table` under `columns` include a key of it, primary or unique, as `ContainsKey` does in types. */
466
- function containsKey(table, columns) {
467
- const listed = new Set(columns);
468
- return someKey(table, (key) => isKeyAmong(key, listed));
469
- }
470
- /** Tells whether `predicate` holds for a key of `table`, primary or unique. */
471
- function someKey(table, predicate) {
472
- const { primaryKey, unique } = table.keys;
473
- return primaryKey !== void 0 && predicate(primaryKey) || unique.some(predicate);
474
- }
475
- /** Tells whether every column of `key` is in `columns`. */
476
- function isKeyAmong(key, columns) {
477
- return key.every((column) => columns.has(column));
478
- }
479
- /** Returns the column of `table` under `key` as `findColumn` finds it, rejecting a key that is not a column. */
480
- function requireColumn(table, key) {
481
- const column = findColumn(table, key);
482
- if (!column) throw new Error(`Unknown column "${key}" of table "${table.name}"`);
483
- return column;
484
- }
485
- /** Creates a column from a column definition, or returns `undefined` for a value that is neither a type nor a column. */
486
- function toColumn(definition) {
487
- if (definition instanceof Column) return definition;
488
- return isType$1(definition) ? new Column(definition, {
489
- name: void 0,
490
- keyKind: void 0,
491
- hasDefault: false
492
- }) : void 0;
493
- }
494
- // src/compiler/postgres/identifier.ts
495
- /** 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)). */
496
- const maxCharacterBytes = 4;
497
- /**
498
- * Returns the longest prefix of `name` that takes at most `maxBytes` bytes in any server encoding.
499
- *
500
- * Every server encoding takes one byte for an ASCII character, and a character other than ASCII counts as the most bytes it can take.
501
- */
502
- function cutIdentifier(name, maxBytes) {
503
- if (name.length * maxCharacterBytes <= maxBytes) return name;
504
- let bytes = 0;
505
- for (let index = 0; index < name.length;) {
506
- const code = name.codePointAt(index);
507
- bytes += code < 128 ? 1 : maxCharacterBytes;
508
- if (bytes > maxBytes) return name.slice(0, index);
509
- index += code < 65536 ? 1 : 2;
510
- }
511
- return name;
512
- }
513
- /**
514
- * Returns the SQL name of the projection with `key` at `index` of its query.
515
- *
516
- * A key of up to 50 bytes is the name itself.
517
- * A longer key is named by its prefix of at most 54 bytes, which takes more than 50 since a character takes at most 4, and by its position, so the name differs from the names of the other projections.
518
- */
519
- function nameProjection(key, index) {
520
- if (cutIdentifier(key, 50).length === key.length) return key;
521
- return `${cutIdentifier(key, 54)}_${index + 1}`;
522
- }
523
- // src/compiler/postgres/context.ts
524
- /**
525
- * State of one compilation shared by all queries of the statement, never by reusable nodes: parameters and the aliases of all sources.
526
- *
527
- * It binds the parameters of the fragments of the database layer that the statement interpolates, numbering them with its own.
528
- */
529
- var CompileContext = class {
530
- schemaName;
531
- tables;
532
- db;
533
- parameters = [];
534
- /** Whether a select statement of the compilation locks rows. */
535
- locksRows = false;
536
- /** Whether the clauses being compiled belong to a query of groups, where `bindParam` binds the parameter of a cast once. */
537
- grouped = false;
538
- #aliases = /* @__PURE__ */ new Set();
539
- #placeholders;
540
- constructor(schemaName, tables = void 0, db = void 0) {
541
- this.schemaName = schemaName;
542
- this.tables = tables;
543
- this.db = db;
544
- }
545
- /**
546
- * Creates an alias based on `name` that is unique in the statement, so that no source shadows another one in SQL.
547
- *
548
- * The name is cut to 50 bytes and numbered when the statement already has it, so an alias fits an identifier and PostgreSQL compares aliases as created rather than truncated.
549
- */
550
- createAlias(name) {
551
- const base = cutIdentifier(name.toWellFormed(), 50);
552
- let alias = base;
553
- for (let index = 2; this.#aliases.has(alias); index++) alias = `${base}_${index}`;
554
- this.#aliases.add(alias);
555
- return alias;
556
- }
557
- /** Adds a parameter of the statement and returns its placeholder, rejecting more parameters than PostgreSQL takes. */
558
- bind(value) {
559
- return bindParameter(this.parameters, value);
560
- }
561
- /**
562
- * Binds `value` as the parameter of the cast that `key` identifies, such as its node, and returns its placeholder.
563
- *
564
- * In a query of groups, it binds the parameter unless it has bound it for `key` before.
565
- */
566
- bindParam(key, value) {
567
- if (!this.grouped) return this.bind(value);
568
- this.#placeholders ??= /* @__PURE__ */ new Map();
569
- let placeholder = this.#placeholders.get(key);
570
- if (placeholder === void 0) {
571
- placeholder = this.bind(value);
572
- this.#placeholders.set(key, placeholder);
573
- }
574
- return placeholder;
575
- }
576
- };
577
- // src/compiler/postgres/parentheses.ts
578
- /** Tells whether an operand of `kind` needs parentheses at `position`, so that the SQL keeps the structure of the tree. */
579
- function needsParentheses(kind, position) {
580
- switch (kind) {
581
- case "column":
582
- case "param":
583
- case "boolean":
584
- case "values":
585
- case "nestedQuery":
586
- case "tableName":
587
- case "subquery":
588
- case "exists":
589
- case "textSubquery":
590
- case "aggregate": return false;
591
- case "cast": return position === "interpolation";
592
- case "raw":
593
- case "fragment": return position !== "interpolation";
594
- case "and":
595
- case "or": return true;
596
- case "not":
597
- case "comparison":
598
- case "in":
599
- case "inQuery":
600
- case "isNull": return position !== "condition";
601
- default: return kind;
602
- }
603
- }
604
- // src/compiler/postgres/scope.ts
605
- /**
606
- * Declares a source of `FROM` on top of `outer` with a new alias.
607
- *
608
- * It rejects a source already visible there, such as a query nested in itself: a column reference could not tell its occurrences apart.
609
- */
610
- function declareSource(context, outer, source) {
611
- if (findSource(outer, source) !== void 0 || source.kind === "derived" && source.replaces !== void 0 && findSource(outer, source.replaces) !== void 0) throw new Error(`An occurrence of ${describeSource(source)} appears where it is already visible, so its column references would be ambiguous`);
612
- const name = source.kind === "table" ? source.table.name : source.replaces?.table.name ?? "subquery";
613
- return {
614
- source,
615
- alias: context.createAlias(name),
616
- outer
617
- };
618
- }
619
- /**
620
- * Returns the declared source that a column reference reads in `scope`: its source, or a derived source that replaces it; rejects a source that is not visible there.
621
- */
622
- function resolveSource(scope, column) {
623
- const declared = findSource(scope, column.source);
624
- if (declared === void 0) throw new Error(`Column "${column.key}" of ${describeSource(column.source)} refers to a source that is not visible where it is used`);
625
- return declared;
626
- }
627
- /** Returns the declared source of `scope` that is `source` or replaces it, or `undefined` when the source is not visible there. */
628
- function findSource(scope, source) {
629
- for (let current = scope; current; current = current.outer) {
630
- const declared = current.source;
631
- if (declared === source || declared.kind === "derived" && declared.replaces === source) return current;
632
- }
633
- }
634
- function describeSource(source) {
635
- return source.kind === "table" ? `table "${source.table.name}"` : "a subquery";
636
- }
637
- // src/compiler/postgres/compile.ts
638
- const noFields = /* @__PURE__ */ Object.freeze([]);
639
- /**
640
- * Compiles a statement for PostgreSQL with the result plan that decodes its result: a select statement or a mutation.
641
- *
642
- * With `tables`, such as the tables of the schema of a `Db`, an occurrence or an interpolated name of any other table at any depth of the statement is rejected.
643
- * `db` is the `Db` that runs the statement: a table interpolated from a query bound to another `Db`, or to any `Db` without it, is rejected.
644
- */
645
- function compileStatement(node, options = {}, tables, db) {
646
- const context = new CompileContext(options.schemaName, tables, db);
647
- switch (node.kind) {
648
- case "select": return {
649
- text: compileQuery(context, void 0, node),
650
- parameters: context.parameters,
651
- fields: node.projections,
652
- recordTemplate: node.recordTemplate,
653
- conversion: node.conversion,
654
- rows: node.rows,
655
- value: node.value,
656
- counted: void 0,
657
- locksRows: context.locksRows
658
- };
659
- default: {
660
- const { returning } = node;
661
- return {
662
- text: compileMutation(context, node),
663
- parameters: context.parameters,
664
- fields: returning ?? noFields,
665
- recordTemplate: node.recordTemplate,
666
- conversion: node.conversion,
667
- rows: node.rows,
668
- value: node.value,
669
- counted: returning === void 0 ? "number" : returning.length === 0 ? "records" : void 0,
670
- locksRows: false
671
- };
672
- }
673
- }
674
- }
675
- /**
676
- * Compiles the SQL text of a statement, such as of `$query`, with the checks of `compileStatement` of the tables that it names.
677
- *
678
- * It has no result plan: the query of SQL text that runs it holds its own.
679
- */
680
- function compileTextStatement(node, options = {}, tables, db) {
681
- const context = new CompileContext(options.schemaName, tables, db);
682
- const text = compileExpression(context, void 0, node);
683
- return createStatement$1(text, context.parameters);
684
- }
685
- /** Compiles a mutation, whose expressions see the occurrence of its table, apart from the values of an insert, which see no source, and the values of `DO UPDATE SET`, which also see the row proposed for insertion as `excluded`. */
686
- function compileMutation(context, node) {
687
- if (node.kind === "insert" && node.conflict?.update !== void 0) context.createAlias(excludedAlias);
688
- const scope = declareSource(context, void 0, node.target);
689
- const target = compileSource(context, void 0, scope);
690
- let text;
691
- switch (node.kind) {
692
- case "insert":
693
- text = `INSERT INTO ${target}${compileValues(context, node)}${compileConflict(context, scope, node)}`;
694
- break;
695
- case "update":
696
- text = `UPDATE ${target} SET${compileAssignments(context, scope, node.target, node.set)}`;
697
- text += compileWhere(context, scope, node.filters);
698
- break;
699
- case "delete":
700
- text = `DELETE FROM ${target}${compileWhere(context, scope, node.filters)}`;
701
- break;
702
- default: return node;
703
- }
704
- const { returning } = node;
705
- if (returning !== void 0 && returning.length > 0) text += ` RETURNING${compileProjections(context, scope, returning)}`;
706
- return text;
707
- }
708
- /** Compiles the columns and the rows of `VALUES` of an insert, or `DEFAULT VALUES` for one row of the defaults of every column. */
709
- function compileValues(context, node) {
710
- const { columns, values } = node;
711
- if (columns.length === 0) {
712
- if (values.length !== 1) throw new Error("An insert of several rows must list a column");
713
- return " DEFAULT VALUES";
714
- }
715
- let text = " (";
716
- for (let index = 0; index < columns.length; index++) text += `${index === 0 ? "" : ", "}${compileColumnName(node.target, columns[index])}`;
717
- text += ") VALUES";
718
- for (let row = 0; row < values.length; row++) {
719
- const items = values[row];
720
- text += row === 0 ? " (" : ", (";
721
- for (let index = 0; index < items.length; index++) {
722
- const item = items[index];
723
- text += `${index === 0 ? "" : ", "}${item === void 0 ? "DEFAULT" : compileExpression(context, void 0, item)}`;
724
- }
725
- text += ")";
726
- }
727
- return text;
728
- }
729
- /** Alias of the row proposed for insertion in `DO UPDATE` of `ON CONFLICT`, which PostgreSQL names `EXCLUDED`. */
730
- const excludedAlias = "excluded";
731
- /**
732
- * Compiles `ON CONFLICT` of an insert, which names the physical columns of its key, or the expression `(true)` of the unique index of a singleton table, or nothing for an insert without it.
733
- *
734
- * The values of `DO UPDATE SET` see the existing row in `scope`, the occurrence of the table of the insert, and the row proposed for insertion as `excluded`.
735
- */
736
- function compileConflict(context, scope, node) {
737
- const { conflict } = node;
738
- if (conflict === void 0) return "";
739
- const { target, update } = conflict;
740
- let text = " ON CONFLICT";
741
- if (target === "singleton") text += " ((true))";
742
- else {
743
- for (let index = 0; index < target.length; index++) text += `${index === 0 ? " (" : ", "}${compileColumnName(node.target, target[index])}`;
744
- if (target.length > 0) text += ")";
745
- }
746
- if (update === void 0) return `${text} DO NOTHING`;
747
- const excluded = {
748
- source: update.excluded,
749
- alias: excludedAlias,
750
- outer: scope
751
- };
752
- return `${text} DO UPDATE SET${compileAssignments(context, excluded, node.target, update.set)}`;
753
- }
754
- /** Compiles the assignments of `SET` of an update or of `DO UPDATE` to the columns of the table of `target`, whose values see the sources of `scope`. */
755
- function compileAssignments(context, scope, target, set) {
756
- let text = "";
757
- for (let index = 0; index < set.length; index++) {
758
- const { key, value } = set[index];
759
- text += `${index === 0 ? " " : ", "}${compileColumnName(target, key)} = ${compileExpression(context, scope, value)}`;
760
- }
761
- return text;
762
- }
763
- /** Compiles the physical name of the column of the table of `target` under `key`, as `SET`, the column list of an insert, and the target of `ON CONFLICT` name it, without an alias. */
764
- function compileColumnName(target, key) {
765
- return quoteIdentifier(requireColumn(target.table, key).attributes.name ?? key);
766
- }
767
- /** Compiles a query at a position of the statement where the sources of `outer` are visible. */
768
- function compileQuery(context, outer, node) {
769
- const { from } = node;
770
- if (from === void 0 && node.joins.length > 0) throw new Error("A query without FROM cannot join sources");
771
- const fromScope = from === void 0 ? void 0 : declareSource(context, outer, from);
772
- let scope = fromScope ?? outer;
773
- const joinScopes = [];
774
- for (const join of node.joins) {
775
- scope = declareSource(context, scope, join.source);
776
- joinScopes.push(scope);
777
- }
778
- const { groupBy, having } = node;
779
- const { grouped } = context;
780
- context.grouped = groupBy !== void 0;
781
- let text = "SELECT";
782
- if (node.distinct) text += " DISTINCT";
783
- const { distinctOn } = node;
784
- if (distinctOn !== void 0) text += ` DISTINCT ON (${compileKeys(context, scope, distinctOn, node.projections)})`;
785
- text += compileProjections(context, scope, node.projections);
786
- if (fromScope !== void 0) {
787
- text += ` FROM ${compileSource(context, outer, fromScope)}`;
788
- for (let index = 0; index < node.joins.length; index++) {
789
- const joinScope = joinScopes[index];
790
- text += ` LEFT JOIN ${compileSource(context, outer, joinScope)} ON ${compileExpression(context, joinScope, node.joins[index].on)}`;
791
- }
792
- }
793
- text += compileWhere(context, scope, node.filters);
794
- if (groupBy !== void 0) text += ` GROUP BY ${compileKeys(context, scope, groupBy, node.projections)}`;
795
- if (having !== void 0) text += ` HAVING ${compileExpression(context, scope, having)}`;
796
- if (node.orderBy.length > 0) text += ` ${compileOrderBy(context, scope, node.orderBy)}`;
797
- if (node.limit) text += ` LIMIT ${compileExpression(context, outer, node.limit)}`;
798
- if (node.offset) text += ` OFFSET ${compileExpression(context, outer, node.offset)}`;
799
- const { lock } = node;
800
- if (lock !== void 0) {
801
- context.locksRows = true;
802
- text += ` FOR ${lock.strength}`;
803
- if (lock.onLocked !== void 0) text += ` ${lock.onLocked}`;
804
- }
805
- context.grouped = grouped;
806
- return text;
807
- }
808
- /** Compiles the projections of a select list or of `RETURNING`, each after a space or a comma. */
809
- function compileProjections(context, scope, projections) {
810
- let text = "";
811
- for (let index = 0; index < projections.length; index++) {
812
- const projection = projections[index];
813
- text += `${index === 0 ? " " : ", "}${compileExpression(context, scope, projection.expression)} AS ${quoteIdentifier(nameProjection(projection.key, index))}`;
814
- }
815
- return text;
816
- }
817
- /** Compiles the `WHERE` clause of the effective predicate of `filters` after a space, or nothing when they restrict no row. */
818
- function compileWhere(context, scope, filters) {
819
- const where = combineFilters(filters);
820
- return where.kind === "boolean" && where.value ? "" : ` WHERE ${compileExpression(context, scope, where)}`;
821
- }
822
- /** Compiles the keys of `GROUP BY` or `DISTINCT ON` of a query of `projections`, its final select list, also with those that lowering adds, such as of a sort key of packed rows: each key is the position of the projection that has its value, or its expression without one. */
823
- function compileKeys(context, scope, keys, projections) {
824
- let text = "";
825
- for (let index = 0; index < keys.length; index++) {
826
- const key = keys[index];
827
- const position = findValueProjection(projections, key);
828
- text += `${index === 0 ? "" : ", "}${position === -1 ? compileExpression(context, scope, key) : String(position + 1)}`;
829
- }
830
- return text;
831
- }
832
- /** Compiles the `ORDER BY` clause of a query or an aggregate, which has at least one sort key. */
833
- function compileOrderBy(context, scope, orderBy) {
834
- let text = "ORDER BY";
835
- for (let index = 0; index < orderBy.length; index++) {
836
- const order = orderBy[index];
837
- text += `${index === 0 ? " " : ", "}${compileExpression(context, scope, order.expression)}`;
838
- if (order.direction === "desc") text += " DESC";
839
- if (order.nulls !== void 0) text += order.nulls === "first" ? " NULLS FIRST" : " NULLS LAST";
840
- }
841
- return text;
842
- }
843
- /** Compiles a declared source of a query at a position of the statement where the sources of `outer` are visible. */
844
- function compileSource(context, outer, declared) {
845
- const { source, alias } = declared;
846
- if (source.kind === "table") return `${compileTableName(context, source.table)} AS ${quoteIdentifier(alias)}`;
847
- const query = compileQuery(context, source.lateral ? declared.outer : outer, source.query);
848
- return `${source.lateral ? "LATERAL " : ""}(${query}) AS ${quoteIdentifier(alias)}`;
849
- }
850
- /** Compiles the name of `table`, qualified by the PostgreSQL schema of the statement, rejecting a table outside the tables of the statement. */
851
- function compileTableName(context, table) {
852
- if (context.tables !== void 0 && !context.tables.has(table)) throw new Error(`Table "${table.name}" is not part of the schema`);
853
- return context.schemaName === void 0 ? quoteIdentifier(table.name) : `${quoteIdentifier(context.schemaName)}.${quoteIdentifier(table.name)}`;
854
- }
855
- /** Compiles the name of a table interpolated into a SQL fragment, rejecting a table of a query bound to a `Db` other than the one that runs the statement. */
856
- function compileInterpolatedTable(context, node) {
857
- const { db, table } = node;
858
- if (db !== void 0 && db !== context.db) throw new Error(context.db === void 0 ? `Table "${table.name}" interpolated into SQL is bound to a Db, so only that Db can compile the query` : `Table "${table.name}" interpolated into SQL is bound to another Db`);
859
- return compileTableName(context, table);
860
- }
861
- function compileColumn(scope, node) {
862
- const { key } = node;
863
- const declared = resolveSource(scope, node);
864
- const { source } = declared;
865
- let name;
866
- if (source.kind === "table") name = requireColumn(source.table, key).attributes.name ?? key;
867
- else {
868
- const index = source.query.projections.findIndex((projection) => projection.key === key);
869
- if (index === -1) throw new Error(`Unknown field "${key}" of a subquery`);
870
- name = nameProjection(key, index);
871
- }
872
- return `${quoteIdentifier(declared.alias)}.${quoteIdentifier(name)}`;
873
- }
874
- function compileExpression(context, scope, node) {
875
- switch (node.kind) {
876
- case "column": return compileColumn(scope, node);
877
- case "param": return context.bind(encodeParameter(node.value, node.type));
878
- case "cast": {
879
- const { operand } = node;
880
- return `${operand.kind === "param" ? context.bindParam(node, encodeParameter(operand.value, operand.type)) : compileOperand(context, scope, operand, "value")}::${node.type.castType}`;
881
- }
882
- case "boolean": return node.value ? "TRUE" : "FALSE";
883
- case "and":
884
- case "or": return node.operands.map((operand) => compileOperand(context, scope, operand, "condition")).join(node.kind === "and" ? " AND " : " OR ");
885
- case "not": return `NOT ${compileOperand(context, scope, node.operand, "condition")}`;
886
- case "values": throw new Error("An object condition can only be used in `where`");
887
- case "nestedQuery": throw new Error("A query in an expression must be lowered before compilation");
888
- case "comparison": return `${compileOperand(context, scope, node.left, "value")} ${node.operator} ${compileOperand(context, scope, node.right, "value")}`;
889
- case "in": {
890
- let text = `${compileOperand(context, scope, node.operand, "value")} IN (${compileOperand(context, scope, node.list[0], "value")}`;
891
- for (let index = 1; index < node.list.length; index++) text += `, ${compileOperand(context, scope, node.list[index], "value")}`;
892
- return `${text})`;
893
- }
894
- case "inQuery": {
895
- const { query } = node;
896
- if (query.kind === "nestedQuery") throw new Error("A query in an expression must be lowered before compilation");
897
- return `${compileOperand(context, scope, node.operand, "value")} IN ${compileSubquery(context, scope, query, "A subquery of IN")}`;
898
- }
899
- case "isNull": return `${compileOperand(context, scope, node.operand, "value")} IS NULL`;
900
- case "raw": {
901
- let text = node.fragments[0];
902
- for (let index = 0; index < node.values.length; index++) text += compileOperand(context, scope, node.values[index], "interpolation") + node.fragments[index + 1];
903
- return text;
904
- }
905
- case "fragment": return renderFragment(node.fragment, context);
906
- case "tableName": return compileInterpolatedTable(context, node);
907
- case "subquery": return compileSubquery(context, scope, node.query, "A scalar subquery");
908
- case "exists": return `EXISTS (${compileQuery(context, scope, node.query)})`;
909
- case "textSubquery": return `(${compileQuery(context, scope, node.query)})`;
910
- case "aggregate": {
911
- let text = `${node.name}(${node.distinct ? "DISTINCT " : ""}`;
912
- for (let index = 0; index < node.arguments.length; index++) text += `${index === 0 ? "" : ", "}${compileExpression(context, scope, node.arguments[index])}`;
913
- if (node.orderBy.length > 0) text += ` ${compileOrderBy(context, scope, node.orderBy)}`;
914
- text += ")";
915
- if (node.filter !== void 0) text += ` FILTER (WHERE ${compileExpression(context, scope, node.filter)})`;
916
- return text;
917
- }
918
- default: return node;
919
- }
920
- }
921
- /** Compiles `query` in parentheses as a subquery of one field, and rejects a query of another number of fields, naming the subquery as `subject`. */
922
- function compileSubquery(context, scope, query, subject) {
923
- const { length } = query.projections;
924
- if (length !== 1) throw new Error(`${subject} must select one field, not ${length}`);
925
- return `(${compileQuery(context, scope, query)})`;
926
- }
927
- /** Compiles an operand at `position` of its parent, parenthesizing it where its own operators could regroup with the parent. */
928
- function compileOperand(context, scope, node, position) {
929
- const sql = compileExpression(context, scope, node);
930
- return needsParentheses(node.kind, position) ? `(${sql})` : sql;
931
- }
932
- // src/schema/relation.ts
933
- /** Runtime mark of the declarations of `many` and `one`. */
934
- const declarationBrand = Symbol("kern-orm.relation");
935
- /** Returns the name of relation `name` of the table under key `key` in messages and errors, such as `field.form`. */
936
- function formatRelationName(key, name) {
937
- return `${key}.${name}`;
938
- }
939
- /**
940
- * Declares a relation of a table to the records of `target` whose columns `to` equal its columns `from`, for `$relations` of a schema.
941
- *
942
- * A composite key lists its columns in arrays of the same length.
943
- */
944
- function many(target, keys) {
945
- return declareRelation("many", target, keys, false);
946
- }
947
- /**
948
- * Declares a relation of a table to the record of `target` whose columns `to` equal its columns `from`, for `$relations` of a schema.
949
- *
950
- * A composite key lists its columns in arrays of the same length.
951
- * The columns `to` must include a key of `target`, primary or unique, so that they match at most one record.
952
- * Without the record, a query of the relation gives `null`, and a query of a relation declared with `required: true` rejects unless it filters the record.
953
- * Set `required: true` only where the database guarantees the record, such as by a foreign key on columns `from` that are not nullable.
954
- */
955
- function one(target, keys) {
956
- return declareRelation("one", target, keys, keys.required === true);
957
- }
958
- function declareRelation(kind, target, keys, required) {
959
- return Object.freeze({
960
- [declarationBrand]: true,
961
- kind,
962
- target,
963
- from: toKeyList(keys.from),
964
- to: toKeyList(keys.to),
965
- required
966
- });
967
- }
968
- function toKeyList(key) {
969
- return Object.freeze(Array.isArray(key) ? key.slice() : [key]);
970
- }
971
- /**
972
- * Defines relation `name` of table `source`, declared under its key `key` in a schema, checking its target and its keys.
973
- *
974
- * `findKey` returns the key of a table in the schema, or `undefined` for a table outside it.
975
- * Each pair of columns of the keys must satisfy `isEqualityCompatible`, the columns `to` of a relation `one` must include a key of the target, and the columns `from` of a required relation must not be nullable by `isNullable` of their types.
976
- */
977
- function defineRelation(source, key, name, declaration, findKey) {
978
- const subject = `Relation "${formatRelationName(key, name)}"`;
979
- if (!isRelationDeclaration(declaration)) throw new TypeError(`${subject} must be declared with many or one`);
980
- if (name.startsWith("$")) throw new Error(`${subject}: a relation name must not start with "$"`);
981
- if (findColumn(source, name)) throw new Error(`${subject}: a relation name must differ from the column keys of table "${source.name}"`);
982
- const { kind, target, from, to, required } = declaration;
983
- const targetKey = findKey(target);
984
- if (targetKey === void 0) throw new Error(`${subject} refers to table "${target.name}", which is not part of the schema`);
985
- if (from.length === 0 || from.length !== to.length) throw new Error(`${subject} must list as many columns in "to" as in "from", at least one`);
986
- for (let index = 0; index < from.length; index++) {
987
- const fromColumn = findColumn(source, from[index]);
988
- if (!fromColumn) throw new Error(`${subject}: unknown column "${from[index]}" of table "${source.name}"`);
989
- if (required && fromColumn.type.isNullable) throw new Error(`${subject} cannot be required: column "${from[index]}" of table "${source.name}" is nullable`);
990
- const toColumn = findColumn(target, to[index]);
991
- if (!toColumn) throw new Error(`${subject}: unknown column "${to[index]}" of table "${target.name}"`);
992
- if (!isEqualityCompatible(fromColumn.type, toColumn.type)) throw new Error(`${subject} cannot compare column "${from[index]}" (${fromColumn.type.sqlType}) with column "${to[index]}" (${toColumn.type.sqlType}) of table "${target.name}" by SQL =`);
993
- }
994
- if (kind === "one" && !containsKey(target, to)) throw new Error(`${subject}: columns "to" must include a key of table "${target.name}", primary or unique`);
995
- return Object.freeze({
996
- kind,
997
- name,
998
- key,
999
- source,
1000
- target,
1001
- targetKey,
1002
- from,
1003
- to,
1004
- required
1005
- });
1006
- }
1007
- /** Adds `definition` of relation `name` of the table under `key` to `relations`, rejecting another definition of the relation there. */
1008
- function addRelation(relations, key, name, definition) {
1009
- let named = relations.get(key);
1010
- if (named === void 0) {
1011
- named = /* @__PURE__ */ new Map();
1012
- relations.set(key, named);
1013
- }
1014
- const existing = named.get(name);
1015
- if (existing !== void 0 && existing !== definition) throw new Error(`Relation "${formatRelationName(key, name)}" has two different definitions`);
1016
- named.set(name, definition);
1017
- }
1018
- /** Adds the relation definitions of a schema to `relations`, rejecting another definition of a relation there. */
1019
- function addRelations(relations, added) {
1020
- for (const key of Object.keys(added)) {
1021
- const named = added[key];
1022
- for (const name of Object.keys(named)) addRelation(relations, key, name, named[name]);
1023
- }
1024
- }
1025
- /** Collects the relation definitions of a schema, which a `Db` of the schema accepts in its queries. */
1026
- function collectDefinitions(relations) {
1027
- const definitions = /* @__PURE__ */ new Set();
1028
- for (const key of Object.keys(relations)) {
1029
- const named = relations[key];
1030
- for (const name of Object.keys(named)) definitions.add(named[name]);
1031
- }
1032
- return definitions;
1033
- }
1034
- /** Creates frozen relations of a schema from `relations`; objects without a prototype keep any key, such as `__proto__`, an own property. */
1035
- function freezeRelations(relations) {
1036
- const result = Object.create(null);
1037
- for (const [key, named] of relations) {
1038
- const table = Object.create(null);
1039
- for (const [name, definition] of named) table[name] = definition;
1040
- result[key] = Object.freeze(table);
1041
- }
1042
- return Object.freeze(result);
1043
- }
1044
- function isRelationDeclaration(value) {
1045
- return typeof value === "object" && value !== null && declarationBrand in value;
1046
- }
1047
- // src/query/rows.ts
1048
- /** Returns the rows mode of a query that starts from `table`, as `TableQueryState` gives it in types: `optional` of the one row of a singleton table, and `many` of the rows of another table. */
1049
- function getTableRows(table) {
1050
- return table.singleton ? "optional" : "many";
1051
- }
1052
- /** Returns the rows mode of a query of the records of `relation`, as `RelationRows` gives it in types. */
1053
- function getRelationRows(relation) {
1054
- if (relation.kind === "many") return "many";
1055
- return relation.required ? "one" : "nullable";
1056
- }
1057
- /** 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. */
1058
- function toFilteredRows(rows, value, guaranteed) {
1059
- if (!guaranteed || rows !== "one") return rows;
1060
- return value ? "optional" : "nullable";
1061
- }
1062
- /** 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. */
1063
- function limitToOne(limit) {
1064
- return limit?.kind === "param" && limit.value === 0 ? limit : oneNode;
1065
- }
1066
- // src/query/node.ts
1067
- /** Empty values of the key without columns of a query that starts from a singleton table. */
1068
- const singletonKey = /* @__PURE__ */ Object.freeze({});
1069
- /**
1070
- * Creates a query of all rows of `from`, or of the records of `relation` with `filters` in the rows mode of the relation.
1071
- *
1072
- * A query of a singleton table without `relation` is a query of its one row, as of `find` of a key without columns, which `upsert` applies to.
1073
- */
1074
- function createQueryNode(from, relation, filters = noFilters) {
1075
- const singleton = relation === void 0 && from.table.singleton;
1076
- return Object.freeze({
1077
- kind: "query",
1078
- from,
1079
- relation,
1080
- projections: [],
1081
- filters,
1082
- groupBy: [],
1083
- having: void 0,
1084
- orderBy: [],
1085
- limit: void 0,
1086
- offset: void 0,
1087
- distinct: false,
1088
- distinctOn: [],
1089
- distinctFields: void 0,
1090
- lock: void 0,
1091
- rows: relation === void 0 ? getTableRows(from.table) : getRelationRows(relation),
1092
- value: false,
1093
- guaranteed: relation?.required ?? false,
1094
- all: false,
1095
- conversion: void 0,
1096
- foundKey: singleton ? singletonKey : void 0
1097
- });
1098
- }
1099
- /** Tells whether `node` is a query of a table without clauses, such as a table of a `Db`: no relation, filters, selected fields, keys of groups, order, limit, offset, `distinct`, keys of `distinctOn`, row lock, rows other than those that the table starts with, `many` or `optional` of a singleton table, `all`, or conversion. */
1100
- function isTableQuery(node) {
1101
- 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.groupBy.length === 0 && node.orderBy.length === 0 && node.limit === void 0 && node.offset === void 0 && !node.distinct && node.distinctOn.length === 0 && node.lock === void 0 && node.rows === getTableRows(node.from.table) && !node.all && node.conversion === void 0;
1102
- }
1103
- /** Tells whether a selected field is the rows of a nested query. */
1104
- function isNestedSelection(node) {
1105
- return "query" in node;
1106
- }
1107
- /** Tells whether a selected field is a literal. */
1108
- function isLiteralSelection(node) {
1109
- return "literal" in node;
1110
- }
1111
- // src/lowering/context.ts
1112
- /** Rejects a query of a relation outside the definitions of `context`. */
1113
- function checkRelation(node, context) {
1114
- const { relation } = node;
1115
- const { definitions } = context;
1116
- if (relation !== void 0 && definitions !== void 0 && !definitions.has(relation)) throw new Error(`Relation "${formatRelationName(relation.key, relation.name)}" is not part of the schema`);
1117
- }
1118
- /** Rejects a nested query bound to `db`, which the error names as `subject`, unless `db` is the `Db` of `context` or `undefined`. */
1119
- function checkDb(db, context, subject) {
1120
- if (db !== void 0 && db !== context.db) throw new Error(context.db === void 0 ? `${subject} is bound to a Db, so only that Db can compile the query` : `${subject} is bound to another Db`);
1121
- }
1122
- // src/lowering/expression.ts
1123
- /**
1124
- * Lowers an expression, replacing each query in it and checking the query as a nested query.
1125
- * A query of `exists`, such as in a condition, becomes `EXISTS` of its rows, another query of one value a scalar subquery of its value, the query of the values of `IN` its statement, and another query in SQL text its statement in parentheses.
1126
- *
1127
- * It returns `node` itself when it holds no query, and creates only the nodes that hold one.
1128
- */
1129
- function lowerExpression(node, context) {
1130
- switch (node.kind) {
1131
- case "column":
1132
- case "param":
1133
- case "boolean":
1134
- case "values":
1135
- case "fragment":
1136
- case "tableName":
1137
- case "subquery":
1138
- case "exists":
1139
- case "textSubquery": return node;
1140
- case "nestedQuery": return lowerNestedQuery(node, context);
1141
- case "cast": {
1142
- const operand = lowerExpression(node.operand, context);
1143
- return operand === node.operand ? node : createNode({
1144
- kind: "cast",
1145
- operand,
1146
- type: node.type
1147
- });
1148
- }
1149
- case "not": {
1150
- const operand = lowerExpression(node.operand, context);
1151
- return operand === node.operand ? node : createNode({
1152
- kind: "not",
1153
- operand
1154
- });
1155
- }
1156
- case "isNull": {
1157
- const operand = lowerExpression(node.operand, context);
1158
- return operand === node.operand ? node : createNode({
1159
- kind: "isNull",
1160
- operand
1161
- });
1162
- }
1163
- case "and":
1164
- case "or": {
1165
- const operands = lowerEach(node.operands, context, lowerExpression);
1166
- return operands === node.operands ? node : createNode({
1167
- kind: node.kind,
1168
- operands
1169
- });
1170
- }
1171
- case "comparison": {
1172
- const left = lowerExpression(node.left, context);
1173
- const right = lowerExpression(node.right, context);
1174
- return left === node.left && right === node.right ? node : createNode({
1175
- kind: "comparison",
1176
- operator: node.operator,
1177
- left,
1178
- right
1179
- });
1180
- }
1181
- case "in": {
1182
- const operand = lowerExpression(node.operand, context);
1183
- const list = lowerEach(node.list, context, lowerExpression);
1184
- return operand === node.operand && list === node.list ? node : createNode({
1185
- kind: "in",
1186
- operand,
1187
- list
1188
- });
1189
- }
1190
- case "inQuery": {
1191
- const operand = lowerExpression(node.operand, context);
1192
- const query = node.query.kind === "nestedQuery" ? lowerQueryOfValues(node.query, context) : node.query;
1193
- return operand === node.operand && query === node.query ? node : createNode({
1194
- kind: "inQuery",
1195
- operand,
1196
- query
1197
- });
1198
- }
1199
- case "raw": {
1200
- const values = lowerEach(node.values, context, lowerExpression);
1201
- return values === node.values ? node : createNode({
1202
- kind: "raw",
1203
- fragments: node.fragments,
1204
- values
1205
- });
1206
- }
1207
- case "aggregate": {
1208
- const args = lowerEach(node.arguments, context, lowerExpression);
1209
- const orderBy = lowerOrder(node.orderBy, context);
1210
- const filter = lowerValue(node.filter, context);
1211
- return args === node.arguments && orderBy === node.orderBy && filter === node.filter ? node : createNode({
1212
- kind: "aggregate",
1213
- name: node.name,
1214
- distinct: node.distinct,
1215
- arguments: args,
1216
- orderBy,
1217
- filter
1218
- });
1219
- }
1220
- default: return node;
1221
- }
1222
- }
1223
- /** Lowers an optional expression, such as `having` of a query or a value of a row of an insert, as `lowerExpression` does. */
1224
- function lowerValue(node, context) {
1225
- return node === void 0 ? void 0 : lowerExpression(node, context);
1226
- }
1227
- /**
1228
- * Lowers a query in an expression to `EXISTS` of the rows of a query of `exists`, to a scalar subquery of the value of another query of one value, or to its statement in parentheses for a query of records or of rows `many`, which only SQL text holds.
1229
- *
1230
- * In SQL text, a query of `exists` stays `EXISTS` rather than a subquery of its value, so that PostgreSQL can join its rows in a condition, as a semi-join.
1231
- */
1232
- function lowerNestedQuery(node, context) {
1233
- checkDb(node.db, context, "A query in an expression");
1234
- const { query } = node;
1235
- if (isExistsQuery(query)) return context.lowerExists(query);
1236
- return createNode({
1237
- kind: query.value && query.rows !== "many" ? "subquery" : "textSubquery",
1238
- query: context.lowerSelect(query, sortsByPositions(query))
1239
- });
1240
- }
1241
- /** Lowers the query of the values of `IN` to its statement, whatever its rows; it tells positions as `sortsByPositions` does. */
1242
- function lowerQueryOfValues(node, context) {
1243
- checkDb(node.db, context, "A query in an expression");
1244
- return context.lowerSelect(node.query, sortsByPositions(node.query));
1245
- }
1246
- /** Tells whether the statement of `node` in a subquery sorts by the positions of its projections: PostgreSQL finds a sort expression of `SELECT DISTINCT` or `GROUP BY` only when it is equal to a selected one or a key, and the keys of `DISTINCT ON` with the order only when they are equal, while a repeated expression has aliases of its own and, apart from the parameters of casts in a query of groups, parameters of its own. */
1247
- function sortsByPositions(node) {
1248
- return node.distinct || node.distinctOn.length > 0 || node.groupBy.length > 0;
1249
- }
1250
- /** Lowers the filters of a query, replacing the queries in their expressions; without queries, it returns `filters` itself. */
1251
- function lowerFilters(filters, context) {
1252
- const { relation, scope, user } = filters;
1253
- const loweredRelation = relation === void 0 ? void 0 : lowerExpression(relation, context);
1254
- const loweredScope = scope === void 0 ? void 0 : lowerExpression(scope, context);
1255
- const loweredUser = user === void 0 ? void 0 : lowerExpression(user, context);
1256
- if (loweredRelation === relation && loweredScope === scope && loweredUser === user) return filters;
1257
- const lowered = {};
1258
- if (loweredRelation !== void 0) lowered.relation = loweredRelation;
1259
- if (loweredScope !== void 0) lowered.scope = loweredScope;
1260
- if (loweredUser !== void 0) lowered.user = loweredUser;
1261
- return Object.freeze(lowered);
1262
- }
1263
- /**
1264
- * Lowers the sort keys of a query, replacing the queries in their expressions; without queries, it returns `orderBy` itself.
1265
- *
1266
- * Each sort key is lowered by `lowerSelectedValue` over `selected`, the fields of the query, and `projections`, their lowered projections.
1267
- */
1268
- function lowerOrder(orderBy, context, selected, projections) {
1269
- let lowered;
1270
- for (let index = 0; index < orderBy.length; index++) {
1271
- const order = orderBy[index];
1272
- const { expression } = order;
1273
- const sorted = lowerSelectedValue(expression, context, selected, projections);
1274
- if (lowered === void 0 && sorted === expression) continue;
1275
- lowered ??= orderBy.slice(0, index);
1276
- lowered.push(sorted === expression ? order : Object.freeze({
1277
- expression: sorted,
1278
- direction: order.direction,
1279
- nulls: order.nulls
1280
- }));
1281
- }
1282
- return lowered ?? orderBy;
1283
- }
1284
- /**
1285
- * Lowers the keys of `groupBy` or `distinctOn` of a query, or `undefined` for a query without them.
1286
- *
1287
- * Each key is lowered by `lowerSelectedValue` over `selected`, the fields of the query, and `projections`, their lowered projections.
1288
- */
1289
- function lowerKeys(keys, context, selected, projections) {
1290
- return keys.length === 0 ? void 0 : lowerEach(keys, context, (key, keyContext) => lowerSelectedValue(key, keyContext, selected, projections));
1291
- }
1292
- /**
1293
- * Lowers `expression`, a sort key, a key of a group, or the argument of an aggregate: the value of a field of `selected` gets the expression of its lowered projection among `projections`, and another expression is lowered as it is.
1294
- *
1295
- * Lowering a field that holds a query gives its projection a new node, so reusing that node keeps the projection identifiable by its position.
1296
- * A field of an aggregate or of `exists` is identified by the node of its reference, which holds the field.
1297
- */
1298
- function lowerSelectedValue(expression, context, selected, projections) {
1299
- const position = selected === void 0 || projections === void 0 || projections === selected ? -1 : selected.findIndex((field) => isFieldValue(field, expression));
1300
- return position === -1 ? lowerExpression(expression, context) : projections[position].expression;
1301
- }
1302
- /** Tells whether `expression`, a sort key, a key of a group, or the argument of an aggregate, is the value of `field`: its expression, or for a field of an aggregate or of `exists`, the node of its reference in the callback of `orderBy` or `groupBy`. */
1303
- function isFieldValue(field, expression) {
1304
- return isNestedSelection(field) ? expression.kind === "nestedQuery" && expression.field === field : field.expression === expression;
1305
- }
1306
- /** Lowers each of `items` with `lower`; when none changes, it returns `items` itself. */
1307
- function lowerEach(items, context, lower) {
1308
- let lowered;
1309
- for (let index = 0; index < items.length; index++) {
1310
- const item = items[index];
1311
- const result = lower(item, context);
1312
- if (lowered !== void 0) lowered.push(result);
1313
- else if (result !== item) {
1314
- lowered = items.slice(0, index);
1315
- lowered.push(result);
1316
- }
1317
- }
1318
- return lowered ?? items;
1319
- }
1320
- // src/lowering/order.ts
1321
- /** Creates the number of the projection at `position`, by which `ORDER BY` sorts by its value instead of evaluating an expression again. */
1322
- function createPositionNode(position) {
1323
- return createNode({
1324
- kind: "raw",
1325
- fragments: [String(position + 1)],
1326
- values: []
1327
- });
1328
- }
1329
- /** Creates the order of a statement that sorts by the positions of the projections among `projections` that have the values of its sort expressions, and by the other expressions as they are. */
1330
- function sortByPositions(orderBy, projections) {
1331
- const result = [];
1332
- for (const order of orderBy) {
1333
- const position = findValueProjection(projections, order.expression);
1334
- result.push(position === -1 ? order : Object.freeze({
1335
- expression: createPositionNode(position),
1336
- direction: order.direction,
1337
- nulls: order.nulls
1338
- }));
1339
- }
1340
- return result;
1341
- }
1342
- /**
1343
- * Creates the derived source of the rows of `query`, and, when `ordered`, the order of the query over the projections of the source, in which its reader takes the rows, such as an aggregate.
1344
- *
1345
- * The order of a derived source does not carry into the query that reads it, so the reader sorts by sort keys: the projections that have the values of the sort expressions, as for an executed query, or projections of the sort expressions added to the source.
1346
- * With a limit or an offset, the source sorts by the positions of the sort keys, so that the rows it chooses, their values, and their order in the reader come from one evaluation; so it does with `DISTINCT ON`, whose order chooses the first row of each group, and with a row lock, which takes the rows in the order of its query.
1347
- * Without them, it has no order.
1348
- * `offset` replaces the offset of `query` in the source, such as `OFFSET 0` that keeps PostgreSQL from merging it, and the source replaces the occurrence of a table `replaces` for its reader.
1349
- */
1350
- function deriveOrderedSource(query, ordered, offset = query.offset, replaces) {
1351
- const { orderBy } = query;
1352
- const projections = query.projections.slice();
1353
- const sorted = query.limit !== void 0 || query.offset !== void 0 || query.distinctOn !== void 0 || query.lock !== void 0;
1354
- const sortKeys = [];
1355
- const positions = [];
1356
- if (orderBy.length > 0 && (ordered || sorted)) for (let index = 0; index < orderBy.length; index++) {
1357
- const { expression, direction, nulls } = orderBy[index];
1358
- const position = projectSortKey(projections, expression, index);
1359
- if (ordered) sortKeys.push({
1360
- key: projections[position].key,
1361
- direction,
1362
- nulls
1363
- });
1364
- if (sorted) positions.push(Object.freeze({
1365
- expression: createPositionNode(position),
1366
- direction,
1367
- nulls
1368
- }));
1369
- }
1370
- const derivedQuery = Object.freeze({
1371
- ...query,
1372
- projections,
1373
- orderBy: positions,
1374
- offset
1375
- });
1376
- const source = Object.freeze(replaces === void 0 ? {
1377
- kind: "derived",
1378
- query: derivedQuery,
1379
- lateral: false
1380
- } : {
1381
- kind: "derived",
1382
- query: derivedQuery,
1383
- lateral: false,
1384
- replaces
1385
- });
1386
- const order = [];
1387
- for (const { key, direction, nulls } of sortKeys) order.push(Object.freeze({
1388
- expression: createNode({
1389
- kind: "column",
1390
- source,
1391
- key
1392
- }),
1393
- direction,
1394
- nulls
1395
- }));
1396
- return {
1397
- source,
1398
- order
1399
- };
1400
- }
1401
- /**
1402
- * Returns the position of the projection that sorts by `expression`: the projection of `findValueProjection`, or one added to `projections`.
1403
- *
1404
- * `index` is the position of the expression in the order.
1405
- */
1406
- function projectSortKey(projections, expression, index) {
1407
- const position = findValueProjection(projections, expression);
1408
- if (position !== -1) return position;
1409
- projections.push(Object.freeze({
1410
- key: createSortProjectionKey(projections, index),
1411
- expression,
1412
- type: text
1413
- }));
1414
- return projections.length - 1;
1415
- }
1416
- /** Creates the key of the sort key projection at `index` of the sort keys, which no other projection has. */
1417
- function createSortProjectionKey(projections, index) {
1418
- const base = `$order${index + 1}`;
1419
- let key = base;
1420
- for (let number = 2; projections.some((projection) => projection.key === key); number++) key = `${base}_${number}`;
1421
- return key;
1422
- }
1423
- // src/lowering/nested.ts
1424
- /** Maximum number of arguments of a PostgreSQL function, `FUNC_MAX_ARGS` of its default build. */
1425
- const maxFunctionArguments = 100;
1426
- /** Number `0`, the offset that keeps PostgreSQL from merging a derived source into its query. */
1427
- const zeroNode = /* @__PURE__ */ createNode({
1428
- kind: "raw",
1429
- fragments: ["0"],
1430
- values: []
1431
- });
1432
- /**
1433
- * Creates the projection of the rows of `query` packed as JSON under `key`, selected as a scalar subquery and decoded by the result plan of `query`.
1434
- *
1435
- * Rows `many` are one array, and the other rows modes are one packed row or `NULL` without a row; a scalar subquery fails with several rows.
1436
- */
1437
- function projectRows(key, query) {
1438
- const packed = packRows(query);
1439
- const { nested } = packed.projections[0];
1440
- return Object.freeze({
1441
- key,
1442
- expression: createNode({
1443
- kind: "subquery",
1444
- query: packed
1445
- }),
1446
- nested
1447
- });
1448
- }
1449
- /**
1450
- * Creates a query whose only projection is the rows of `query` packed as JSON, a field decoded by the result plan of `query`.
1451
- *
1452
- * Rows `many` are packed as an array in the order of `query`, and the created query returns one row.
1453
- * Otherwise the created query returns a packed row for each row of `query`, so a scalar subquery of it gives the packed row, `NULL` without a row, and fails with several rows.
1454
- */
1455
- function packRows(query) {
1456
- const { projections } = query;
1457
- const many = query.rows === "many";
1458
- const { source, order } = deriveOrderedSource(query, many, !query.distinct && query.distinctOn === void 0 && query.groupBy === void 0 && query.lock === void 0 && query.limit === void 0 && query.offset === void 0 && projections.some((projection) => projection.nested === void 0 && !isTableColumn(projection.expression)) ? zeroNode : query.offset);
1459
- const wide = projections.length > maxFunctionArguments;
1460
- const values = [];
1461
- for (const projection of projections) {
1462
- const value = createRef(source, projection.key);
1463
- if (projection.nested !== void 0) values.push(value);
1464
- else values.push(wide ? createList("to_json(", [packScalar(value)], ")") : packScalar(value));
1465
- }
1466
- const row = wide ? createList("array_to_json(ARRAY[", values, "])") : createList("json_build_array(", values, ")");
1467
- let packed = row;
1468
- if (many) packed = createNode({
1469
- kind: "raw",
1470
- fragments: ["coalesce(", ", '[]'::json)"],
1471
- values: [createNode({
1472
- kind: "aggregate",
1473
- name: "json_agg",
1474
- distinct: false,
1475
- arguments: [row],
1476
- orderBy: order,
1477
- filter: void 0
1478
- })]
1479
- });
1480
- const plan = Object.freeze({
1481
- fields: projections,
1482
- rows: query.rows,
1483
- value: query.value,
1484
- guaranteedBy: query.guaranteedBy,
1485
- recordTemplate: query.recordTemplate,
1486
- conversion: query.conversion
1487
- });
1488
- const projection = Object.freeze({
1489
- key: "rows",
1490
- expression: packed,
1491
- nested: plan
1492
- });
1493
- return createSelectNode(source, [projection]);
1494
- }
1495
- /** Tells whether `node` is a column of a table, which PostgreSQL reads rather than evaluates, so it can be repeated. */
1496
- function isTableColumn(node) {
1497
- return node.kind === "column" && node.source.kind === "table";
1498
- }
1499
- /**
1500
- * Packs a scalar as its PostgreSQL text representation, or `NULL`.
1501
- *
1502
- * `format` uses the output function of the type, as the driver receives the values of a row; a cast to `text` differs from it for types such as `boolean`, `inet`, and `char`.
1503
- */
1504
- function packScalar(value) {
1505
- return createNode({
1506
- kind: "raw",
1507
- fragments: [
1508
- "CASE WHEN ",
1509
- " IS NOT DISTINCT FROM NULL THEN NULL ELSE format('%s', ",
1510
- ") END"
1511
- ],
1512
- values: [value, value]
1513
- });
1514
- }
1515
- function createRef(source, key) {
1516
- return createNode({
1517
- kind: "column",
1518
- source,
1519
- key
1520
- });
1521
- }
1522
- // src/lowering/projection.ts
1523
- /**
1524
- * Lowers the fields of a query to projections, packing the rows of each nested query into the value of its field, or selecting the value of an aggregate query or `EXISTS` of a query of `exists`, and replacing the queries in the expressions of the other fields; checks them as `lowerQuery` does.
1525
- *
1526
- * Without queries, it returns `selected` itself.
1527
- */
1528
- function lowerProjections(selected, context) {
1529
- let lowered;
1530
- for (let index = 0; index < selected.length; index++) {
1531
- const field = selected[index];
1532
- let projection;
1533
- if (isNestedSelection(field)) {
1534
- checkDb(field.db, context, `Selected field "${field.key}"`);
1535
- projection = projectQuery(field.key, field.query, context);
1536
- } else {
1537
- const expression = lowerExpression(field.expression, context);
1538
- projection = expression === field.expression ? field : Object.freeze({
1539
- key: field.key,
1540
- expression,
1541
- type: field.type
1542
- });
1543
- }
1544
- if (lowered !== void 0) lowered.push(projection);
1545
- else if (projection !== field) {
1546
- lowered = selected.slice(0, index);
1547
- lowered.push(projection);
1548
- }
1549
- }
1550
- return lowered ?? selected;
1551
- }
1552
- /** Creates the projection of the value of `node`, a nested query, under `key`: `EXISTS` of a query of `exists`, the value of an aggregate query, or the packed rows of another query or of one whose result code converts. */
1553
- function projectQuery(key, node, context) {
1554
- if (!isSelectedAsValue(node)) return projectRows(key, context.lowerSelect(node, false));
1555
- return isExistsQuery(node) ? projectExists(key, node, context) : projectAggregateValue(key, context.lowerSelect(node, false));
1556
- }
1557
- /** Creates the projection of `EXISTS` of the rows of `node`, a query of `exists`, under `key`, decoded by the type of the projection of `exists`. */
1558
- function projectExists(key, node, context) {
1559
- return Object.freeze({
1560
- key,
1561
- expression: context.lowerExists(node),
1562
- type: node.projections[0].type
1563
- });
1564
- }
1565
- /** Creates the projection of the value of `query`, the statement of an aggregate query, under `key`, selected as a scalar subquery and decoded by the type of the aggregate. */
1566
- function projectAggregateValue(key, query) {
1567
- return Object.freeze({
1568
- key,
1569
- expression: createNode({
1570
- kind: "subquery",
1571
- query
1572
- }),
1573
- type: query.projections[0].type
1574
- });
1575
- }
1576
- /** Returns the fields of `selected` that a statement selects, or `selected` itself without literals. */
1577
- function dropLiterals(selected) {
1578
- if (!selected.some(isLiteralSelection)) return selected;
1579
- const fields = [];
1580
- for (const field of selected) if (!isLiteralSelection(field)) fields.push(field);
1581
- return fields;
1582
- }
1583
- /** Creates the template of the records of `selected`: every field in its order with the value of a literal, or `undefined` without literals. */
1584
- function createRecordTemplate(selected) {
1585
- if (!selected.some(isLiteralSelection)) return;
1586
- const template = [];
1587
- for (const field of selected) template.push(Object.freeze({
1588
- key: field.key,
1589
- value: isLiteralSelection(field) ? field.literal : void 0
1590
- }));
1591
- return template;
1592
- }
1593
- // src/lowering/distinct.ts
1594
- /**
1595
- * Rejects a query of `distinct` of the lowered `projections` and `orderBy` that `SELECT DISTINCT` cannot give the rows of, with an error that does not depend on where the query is:
1596
- *
1597
- * - A query without projections, such as of only literals, has nothing to compare, and PostgreSQL has no syntax for it.
1598
- * - Nested rows are JSON, which PostgreSQL cannot compare.
1599
- * - PostgreSQL rejects a sort key that is not a projection, since duplicates can differ in its value, whereas a packed query would add it to the projections of its derived source and compare it too.
1600
- * Only a projection of the same column or of the same expression node is sure to have its value, as in `findValueProjection`.
1601
- */
1602
- function checkDistinct(projections, orderBy) {
1603
- if (projections.length === 0) throw new Error("distinct requires at least one selected column or SQL expression; literal fields are not compared");
1604
- for (const { key, nested } of projections) if (nested !== void 0) throw new Error(`distinct cannot compare the nested rows of the selected field "${key}"`);
1605
- for (const { expression } of orderBy) if (findValueProjection(projections, expression) === -1) throw new Error("A query of distinct sorts only by its selected fields, since duplicates can differ in any other value; select the value to sort by it");
1606
- }
1607
- /**
1608
- * Rejects a query of `distinctOn` of the lowered `projections`, `keys`, and `orderBy` that `SELECT DISTINCT ON` cannot give the rows of, with an error that does not depend on where the query is: a query without projections, such as of only literals, since PostgreSQL requires a select list with `DISTINCT ON`, and an order that `checkDistinctOnOrder` rejects.
1609
- */
1610
- function checkDistinctOn(projections, keys, orderBy) {
1611
- if (projections.length === 0) throw new Error("distinctOn requires at least one selected column or SQL expression; literal fields are not selected");
1612
- checkDistinctOnOrder(projections, keys, orderBy);
1613
- }
1614
- /**
1615
- * Rejects an order of a query of `distinctOn` of the lowered `projections`, `keys`, and `orderBy` that sorts by a value other than the keys before it sorts by all of them, in any order and direction, which PostgreSQL rejects, since the order sorts the groups apart and then chooses the first row of each; an order of only keys may omit some, which PostgreSQL adds.
1616
- *
1617
- * A sort key is a key when it is the same column, or the same expression node that a projection of the query has, as `findValueProjection` tells, so that both compile to the same column or position.
1618
- * Another expression may compile at each place with parameters and aliases of its own, so PostgreSQL may find the two unequal; the check runs before packing, which would add the expression to the projections of its derived source and make both positions, so that it counts as another value wherever the query is.
1619
- */
1620
- function checkDistinctOnOrder(projections, keys, orderBy) {
1621
- const isKey = (key, expression) => isSameValue(key, expression) && (key.kind === "column" || findValueProjection(projections, key) !== -1);
1622
- let leading = 0;
1623
- while (leading < orderBy.length && keys.some((key) => isKey(key, orderBy[leading].expression))) leading++;
1624
- if (leading === orderBy.length) return;
1625
- for (const key of keys) {
1626
- let sorted = false;
1627
- for (let index = 0; index < leading && !sorted; index++) sorted = isKey(key, orderBy[index].expression);
1628
- if (!sorted) throw new Error("A query of distinctOn must sort by all its keys before any other value; sort by a key of an expression through its selected field");
1629
- }
1630
- }
1631
- /**
1632
- * Lowers the rows of `node`, a query of `distinct` or `distinctOn` made by an aggregate method or `exists`, to the statement that gives them, which an aggregate reads from a derived source and `EXISTS` reads as it is.
1633
- *
1634
- * It lowers the fields that the query kept, its keys, its order, and `argument`, the first argument of the aggregate, through those fields, as `lowerSelectedValue` does, so that each value of a selected field is its projection, and checks the query as the statement of the query of those fields is checked, except that a query of `distinctOn` needs no selected field, since the statement selects its keys.
1635
- *
1636
- * - The statement of `distinct` selects the fields, which `DISTINCT` compares, and `argument` must be one of them, as a sort key must be, since duplicates can differ in any other value.
1637
- * - The statement of `distinctOn` selects `argument` and each key that it does not select otherwise, so that it has a select list, which PostgreSQL requires with `DISTINCT ON`.
1638
- * It selects no other field, since an aggregate reads the rows of the source rather than of the select list, as for a query without `distinctOn`, so it does not lower the fields of nested rows, which neither a key nor a sort key reads.
1639
- *
1640
- * The statement has the order of the query when `sorted` is set; the number of the rows, which `count(*)` and `EXISTS` read, does not depend on it.
1641
- */
1642
- function lowerDistinctRows(node, context, argument, sorted) {
1643
- const fields = dropLiterals(node.distinctFields);
1644
- let selected = fields;
1645
- if (!node.distinct) {
1646
- const scalars = [];
1647
- for (const field of fields) if (!isNestedSelection(field) || isSelectedAsValue(field.query)) scalars.push(field);
1648
- selected = scalars;
1649
- }
1650
- const projections = lowerProjections(selected, context);
1651
- const orderBy = lowerOrder(node.orderBy, context, selected, projections);
1652
- const groupBy = lowerKeys(node.groupBy, context, selected, projections);
1653
- const keys = lowerKeys(node.distinctOn, context, selected, projections);
1654
- const value = argument === void 0 ? void 0 : lowerSelectedValue(argument, context, selected, projections);
1655
- let sourced;
1656
- let valueKey;
1657
- if (keys === void 0) {
1658
- checkDistinct(projections, orderBy);
1659
- sourced = projections;
1660
- if (value !== void 0) {
1661
- const position = findValueProjection(projections, value);
1662
- if (position === -1) throw new Error("An aggregate of a query of distinct reads only its selected fields, since duplicates can differ in any other value; select the value to aggregate it");
1663
- valueKey = projections[position].key;
1664
- }
1665
- } else {
1666
- checkDistinctOnOrder(projections, keys, orderBy);
1667
- const keyed = [];
1668
- if (value !== void 0) {
1669
- valueKey = "value";
1670
- keyed.push(Object.freeze({
1671
- key: valueKey,
1672
- expression: value,
1673
- type: text
1674
- }));
1675
- }
1676
- for (let index = 0; index < keys.length; index++) {
1677
- const key = keys[index];
1678
- if (findValueProjection(keyed, key) === -1) keyed.push(Object.freeze({
1679
- key: `$key${index + 1}`,
1680
- expression: key,
1681
- type: text
1682
- }));
1683
- }
1684
- sourced = keyed;
1685
- }
1686
- return {
1687
- query: Object.freeze({
1688
- kind: "select",
1689
- from: node.from,
1690
- joins: noJoins,
1691
- projections: sourced,
1692
- filters: lowerFilters(node.filters, context),
1693
- groupBy,
1694
- having: lowerValue(node.having, context),
1695
- orderBy: sorted ? orderBy : noOrder,
1696
- limit: node.limit,
1697
- offset: node.offset,
1698
- distinct: node.distinct,
1699
- distinctOn: keys,
1700
- rows: "many",
1701
- value: false,
1702
- guaranteedBy: void 0
1703
- }),
1704
- valueKey
1705
- };
1706
- }
1707
- // src/lowering/aggregate.ts
1708
- /** Lowers an aggregate query to a statement of the value of its aggregate over the rows that its filters, limit, and offset choose, also the distinct rows of `distinct` and the first rows of `distinctOn`. */
1709
- function lowerAggregate(node, context) {
1710
- const field = node.projections[0];
1711
- const aggregate = field.expression;
1712
- const counted = aggregate === countProjection.expression;
1713
- let from = node.from;
1714
- let filters = noFilters;
1715
- let args = aggregate.arguments;
1716
- let order = noOrder;
1717
- let rows;
1718
- let valueKey;
1719
- if (node.distinctFields !== void 0) {
1720
- const distinctRows = lowerDistinctRows(node, context, counted ? void 0 : aggregate.arguments[0], !counted);
1721
- rows = distinctRows.query;
1722
- valueKey = distinctRows.valueKey;
1723
- } else {
1724
- const orderBy = lowerOrder(node.orderBy, context);
1725
- const groupBy = lowerKeys(node.groupBy, context);
1726
- filters = lowerFilters(node.filters, context);
1727
- args = lowerEach(aggregate.arguments, context, lowerExpression);
1728
- order = field.ordered ? orderBy : noOrder;
1729
- if (groupBy !== void 0 || node.limit !== void 0 || node.offset !== void 0 || !counted && !refersToSource(args[0], node.from)) {
1730
- const projections = [];
1731
- if (!counted) {
1732
- valueKey = "value";
1733
- projections.push(Object.freeze({
1734
- key: valueKey,
1735
- expression: args[0],
1736
- type: field.type
1737
- }));
1738
- }
1739
- rows = {
1740
- kind: "select",
1741
- from: node.from,
1742
- joins: noJoins,
1743
- projections,
1744
- filters,
1745
- groupBy,
1746
- having: lowerValue(node.having, context),
1747
- orderBy: counted ? noOrder : orderBy,
1748
- limit: node.limit,
1749
- offset: node.offset,
1750
- rows: "many",
1751
- value: false,
1752
- guaranteedBy: void 0
1753
- };
1754
- }
1755
- }
1756
- if (rows !== void 0) {
1757
- const derived = deriveOrderedSource(rows, field.ordered);
1758
- from = derived.source;
1759
- filters = noFilters;
1760
- if (valueKey !== void 0) {
1761
- const sourceArgs = [createNode({
1762
- kind: "column",
1763
- source: from,
1764
- key: valueKey
1765
- })];
1766
- for (let index = 1; index < args.length; index++) sourceArgs.push(args[index]);
1767
- args = sourceArgs;
1768
- }
1769
- order = derived.order;
1770
- }
1771
- const call = args === aggregate.arguments && order.length === 0 ? aggregate : createNode({
1772
- kind: "aggregate",
1773
- name: aggregate.name,
1774
- distinct: aggregate.distinct,
1775
- arguments: args,
1776
- orderBy: order,
1777
- filter: aggregate.filter
1778
- });
1779
- const fallbacks = lowerEach(field.fallbacks, context, lowerExpression);
1780
- let value = call;
1781
- if (fallbacks.length > 0) {
1782
- const values = [call];
1783
- for (const fallback of fallbacks) values.push(fallback);
1784
- value = createList("coalesce(", values, ")");
1785
- }
1786
- return Object.freeze({
1787
- kind: "select",
1788
- from,
1789
- joins: noJoins,
1790
- projections: [value === aggregate ? field : Object.freeze({
1791
- key: field.key,
1792
- expression: value,
1793
- type: field.type
1794
- })],
1795
- filters,
1796
- orderBy: noOrder,
1797
- limit: void 0,
1798
- offset: void 0,
1799
- rows: node.rows,
1800
- value: true,
1801
- guaranteedBy: void 0
1802
- });
1803
- }
1804
- /**
1805
- * Tells whether `node` refers to `source` outside the queries nested in it.
1806
- *
1807
- * A reference inside a nested query is not counted, so an argument that refers to the source only there is read from a derived source, which is correct either way.
1808
- */
1809
- function refersToSource(node, source) {
1810
- switch (node.kind) {
1811
- case "column": return node.source === source;
1812
- case "param":
1813
- case "boolean":
1814
- case "values":
1815
- case "nestedQuery":
1816
- case "fragment":
1817
- case "tableName":
1818
- case "subquery":
1819
- case "exists":
1820
- case "textSubquery": return false;
1821
- case "cast":
1822
- case "not":
1823
- case "isNull":
1824
- case "inQuery": return refersToSource(node.operand, source);
1825
- case "and":
1826
- case "or": return node.operands.some((operand) => refersToSource(operand, source));
1827
- case "comparison": return refersToSource(node.left, source) || refersToSource(node.right, source);
1828
- case "in": return refersToSource(node.operand, source) || node.list.some((item) => refersToSource(item, source));
1829
- case "raw": return node.values.some((value) => refersToSource(value, source));
1830
- case "aggregate": return node.arguments.some((argument) => refersToSource(argument, source)) || node.filter !== void 0 && refersToSource(node.filter, source);
1831
- default: return node;
1832
- }
1833
- }
1834
- // src/lowering/exists.ts
1835
- /** Lowers a query of `exists` to `EXISTS` of the rows that its filters, limit, and offset choose, also the distinct rows of `distinct` and the first rows of `distinctOn`. */
1836
- function lowerExists(node, context) {
1837
- checkRelation(node, context);
1838
- return createNode({
1839
- kind: "exists",
1840
- query: node.distinctFields === void 0 ? Object.freeze({
1841
- kind: "select",
1842
- from: node.from,
1843
- joins: noJoins,
1844
- projections: noProjections,
1845
- filters: lowerFilters(node.filters, context),
1846
- groupBy: lowerKeys(node.groupBy, context),
1847
- having: lowerValue(node.having, context),
1848
- orderBy: noOrder,
1849
- limit: node.limit,
1850
- offset: node.offset,
1851
- rows: "many",
1852
- value: false,
1853
- guaranteedBy: void 0
1854
- }) : lowerDistinctRows(node, context, void 0, false).query
1855
- });
1856
- }
1857
- // src/ast/references.ts
1858
- /** Adds to `keys` the key of each column reference to `source` in `node` at any depth, including the queries nested in it. */
1859
- function collectColumnKeys(node, source, keys) {
1860
- visitNodes(node, (child) => {
1861
- if (child.kind === "column" && child.source === source) keys.add(child.key);
1862
- });
1863
- }
1864
- /**
1865
- * Tells whether `node` holds, at any depth, what may aggregate the rows of the query of `source`: an `aggregate` node or a SQL fragment that refers to a column of `source` at any depth, also in the queries nested in it.
1866
- *
1867
- * PostgreSQL assigns an aggregate whose arguments and filter refer only to the sources of an enclosing query to that query, also through a query nested in them ([PostgreSQL](https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-AGGREGATES)), so such a call in a nested query, such as `sum` of a column of the parent row, aggregates the rows of the query of `source`.
1868
- * Lowering does not parse SQL fragments to identify their aggregates, so a fragment counts as such a call.
1869
- *
1870
- * It is conservative: an aggregate whose arguments read both `source` and its own query belongs to its own query, yet it counts, since this walk cannot tell a source of the query that holds the aggregate from one of an enclosing query.
1871
- * So does a scalar fragment, also one that reads `source` only through a query correlated with it, such as of a relation.
1872
- */
1873
- function mayAggregateSource(node, source) {
1874
- let found = false;
1875
- const check = (value) => {
1876
- if (value.kind === "column" && value.source === source) found = true;
1877
- };
1878
- visitNodes(node, (child) => {
1879
- if (!found && (child.kind === "aggregate" || child.kind === "raw")) visitNodes(child, check);
1880
- });
1881
- return found;
1882
- }
1883
- /**
1884
- * Tells whether an aggregate belongs to an enclosing query rather than the query of `source`.
1885
- *
1886
- * Only references free in its arguments, order, and filter decide its owner: columns bound by a subquery do not count, but references through that subquery to its enclosing queries do.
1887
- * Without such references, an aggregate of constants belongs to the query that contains it.
1888
- * The node must have been lowered, so that subqueries expose their sources.
1889
- */
1890
- function aggregatesOuterSource(node, source) {
1891
- let local = false;
1892
- let outer = false;
1893
- const queries = [];
1894
- visitNodes(node, (child) => {
1895
- if (child.kind !== "column" || local) return;
1896
- for (const query of queries) {
1897
- if (bindsSource(query.from, child.source)) return;
1898
- for (const join of query.joins) if (bindsSource(join.source, child.source)) return;
1899
- }
1900
- if (child.source === source) local = true;
1901
- else outer = true;
1902
- }, queries);
1903
- return outer && !local;
1904
- }
1905
- /** Tells whether a declared source binds a reference, including the table occurrence a derived source replaces. */
1906
- function bindsSource(declared, source) {
1907
- return declared === source || declared?.kind === "derived" && declared.replaces === source;
1908
- }
1909
- /**
1910
- * Calls `visit` for `node` and each expression node in it at any depth, including the queries nested in it.
1911
- * When supplied, `queries` holds the nested queries enclosing each node passed to `visit`.
1912
- */
1913
- function visitNodes(node, visit, queries) {
1914
- visit(node);
1915
- switch (node.kind) {
1916
- case "column":
1917
- case "param":
1918
- case "boolean":
1919
- case "fragment":
1920
- case "tableName":
1921
- case "values":
1922
- case "nestedQuery": return;
1923
- case "cast":
1924
- case "not":
1925
- case "isNull":
1926
- visitNodes(node.operand, visit, queries);
1927
- return;
1928
- case "and":
1929
- case "or":
1930
- for (const operand of node.operands) visitNodes(operand, visit, queries);
1931
- return;
1932
- case "comparison":
1933
- visitNodes(node.left, visit, queries);
1934
- visitNodes(node.right, visit, queries);
1935
- return;
1936
- case "in":
1937
- visitNodes(node.operand, visit, queries);
1938
- for (const item of node.list) visitNodes(item, visit, queries);
1939
- return;
1940
- case "inQuery":
1941
- visitNodes(node.operand, visit, queries);
1942
- if (node.query.kind === "select") visitQuery(node.query, visit, queries);
1943
- return;
1944
- case "raw":
1945
- for (const value of node.values) visitNodes(value, visit, queries);
1946
- return;
1947
- case "subquery":
1948
- case "exists":
1949
- case "textSubquery":
1950
- visitQuery(node.query, visit, queries);
1951
- return;
1952
- case "aggregate":
1953
- for (const argument of node.arguments) visitNodes(argument, visit, queries);
1954
- for (const order of node.orderBy) visitNodes(order.expression, visit, queries);
1955
- if (node.filter !== void 0) visitNodes(node.filter, visit, queries);
1956
- return;
1957
- }
1958
- }
1959
- /**
1960
- * Calls `visit` for each expression node in the clauses and the derived sources of `query` at any depth.
1961
- * When supplied, `queries` holds the nested queries enclosing each node passed to `visit`; this call adds `query` for its duration.
1962
- */
1963
- function visitQuery(query, visit, queries) {
1964
- queries?.push(query);
1965
- const { from, filters } = query;
1966
- if (from?.kind === "derived") visitQuery(from.query, visit, queries);
1967
- for (const join of query.joins) {
1968
- if (join.source.kind === "derived") visitQuery(join.source.query, visit, queries);
1969
- visitNodes(join.on, visit, queries);
1970
- }
1971
- if (query.distinctOn !== void 0) for (const key of query.distinctOn) visitNodes(key, visit, queries);
1972
- for (const projection of query.projections) visitNodes(projection.expression, visit, queries);
1973
- if (filters.relation !== void 0) visitNodes(filters.relation, visit, queries);
1974
- if (filters.scope !== void 0) visitNodes(filters.scope, visit, queries);
1975
- if (filters.user !== void 0) visitNodes(filters.user, visit, queries);
1976
- if (query.groupBy !== void 0) for (const key of query.groupBy) visitNodes(key, visit, queries);
1977
- if (query.having !== void 0) visitNodes(query.having, visit, queries);
1978
- for (const order of query.orderBy) visitNodes(order.expression, visit, queries);
1979
- if (query.limit !== void 0) visitNodes(query.limit, visit, queries);
1980
- if (query.offset !== void 0) visitNodes(query.offset, visit, queries);
1981
- queries?.pop();
1982
- }
1983
- // src/lowering/group.ts
1984
- /**
1985
- * Rejects directly selected, unfiltered aggregates of an enclosing query in a query of groups.
1986
- *
1987
- * Types give these aggregates the nullability of their arguments in a nonempty group, but an enclosing query can have no rows.
1988
- * A typed SQL fragment keeps its declared nullability and is the explicit escape hatch for an outer aggregate.
1989
- */
1990
- function checkGroupAggregates(projections, query) {
1991
- for (const field of projections) {
1992
- const expression = field.expression;
1993
- if (expression.kind === "aggregate" && expression.name !== "count" && expression.filter === void 0 && aggregatesOuterSource(expression, query.from)) throw new Error(`An aggregate function of ${query.value ? "the grouped value" : `grouped field ${JSON.stringify(field.key)}`} refers only to enclosing queries; use an explicitly nullable sql expression for an outer aggregate`);
1994
- }
1995
- }
1996
- // src/lowering/mutation.ts
1997
- /** 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. */
1998
- function lowerMutation(node, context) {
1999
- const { target, returning, rows, value, conversion } = node;
2000
- const recordTemplate = returning === void 0 ? void 0 : createRecordTemplate(returning);
2001
- const lowered = returning === void 0 ? void 0 : lowerProjections(dropLiterals(returning), context);
2002
- switch (node.kind) {
2003
- case "insert": {
2004
- const values = lowerEach(node.values, context, lowerRow);
2005
- const conflict = lowerConflict(node.conflict, context);
2006
- if (lowered === returning && values === node.values && conflict === node.conflict) return node;
2007
- return Object.freeze({
2008
- kind: "insert",
2009
- target,
2010
- columns: node.columns,
2011
- values,
2012
- conflict,
2013
- returning: lowered,
2014
- recordTemplate,
2015
- conversion,
2016
- rows,
2017
- value
2018
- });
2019
- }
2020
- case "update": {
2021
- const set = lowerEach(node.set, context, lowerAssignment);
2022
- const filters = lowerFilters(node.filters, context);
2023
- if (lowered === returning && set === node.set && filters === node.filters) return node;
2024
- return Object.freeze({
2025
- kind: "update",
2026
- target,
2027
- set,
2028
- filters,
2029
- returning: lowered,
2030
- recordTemplate,
2031
- conversion,
2032
- rows,
2033
- value
2034
- });
2035
- }
2036
- case "delete": {
2037
- const filters = lowerFilters(node.filters, context);
2038
- if (lowered === returning && filters === node.filters) return node;
2039
- return Object.freeze({
2040
- kind: "delete",
2041
- target,
2042
- filters,
2043
- returning: lowered,
2044
- recordTemplate,
2045
- conversion,
2046
- rows,
2047
- value
2048
- });
2049
- }
2050
- default: return node;
2051
- }
2052
- }
2053
- /** Lowers a row of `VALUES` of an insert, whose `undefined` stands for `DEFAULT`. */
2054
- function lowerRow(row, context) {
2055
- return lowerEach(row, context, lowerValue);
2056
- }
2057
- /** Lowers the values of `DO UPDATE` of `ON CONFLICT` of an insert, keeping a conflict without queries in them as it is. */
2058
- function lowerConflict(conflict, context) {
2059
- if (conflict?.update === void 0) return conflict;
2060
- const { target, update } = conflict;
2061
- const set = lowerEach(update.set, context, lowerAssignment);
2062
- return set === update.set ? conflict : Object.freeze({
2063
- target,
2064
- update: Object.freeze({
2065
- set,
2066
- excluded: update.excluded
2067
- })
2068
- });
2069
- }
2070
- function lowerAssignment(assignment, context) {
2071
- const value = lowerExpression(assignment.value, context);
2072
- return value === assignment.value ? assignment : Object.freeze({
2073
- key: assignment.key,
2074
- value
2075
- });
2076
- }
2077
- // src/lowering/page.ts
2078
- /**
2079
- * Lowers `query`, the statement of a query on its table that sorts by its sort expressions, to a statement that evaluates its nested queries, apart from those that it sorts by, groups by, or compares, over the rows of a derived page, or returns `undefined` for a query that keeps its page on its table.
2080
- * `queryFields` are the fields of the query without literals, whose lowered projections the statement has in the same order.
2081
- * The derived source applies `DISTINCT ON`, the filters, the keys and the condition of the groups, the order, the limit, and the offset, and replaces the occurrence of the table.
2082
- * It selects each key of `distinctOn` that it does not select otherwise, so that it has a select list, which PostgreSQL requires with `DISTINCT ON`, and evaluates each key once; a key of `groupBy` needs no projection of its own, since it compiles as the position of a projection that has its value or as its expression.
2083
- *
2084
- * A query keeps its page on its table without an offset and `distinctOn`, without nested queries that the page would evaluate over its rows, or when `mayAggregateSource` tells that such a nested query may aggregate the rows of the query, which the limit and the offset apply after.
2085
- *
2086
- * The source selects the columns of the table that the fields and the nested queries of the query read, under their keys, and the other scalar fields of the query, which it evaluates before the limit and the offset as the query would, such as a window function over all its rows or an aggregate of a group.
2087
- * A field of an aggregate or of `exists` that the query sorts by or that is a key is such a scalar field: the order and the keys need its value for every row.
2088
- * 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(*)`.
2089
- * 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.
2090
- */
2091
- function lowerPage(query, queryFields, positions) {
2092
- const { from, projections, orderBy, groupBy, distinctOn, offset } = query;
2093
- if (offset === void 0 && distinctOn === void 0 || query.distinct || query.lock !== void 0 || !queryFields.some((field, index) => isPagedField(field, projections[index], orderBy, groupBy, distinctOn))) return;
2094
- const columnKeys = /* @__PURE__ */ new Set();
2095
- const fields = [];
2096
- const fieldKeys = [];
2097
- for (let index = 0; index < projections.length; index++) {
2098
- const { expression } = projections[index];
2099
- let key;
2100
- if (isPagedField(queryFields[index], projections[index], orderBy, groupBy, distinctOn)) {
2101
- if (mayAggregateSource(expression, from)) return;
2102
- collectColumnKeys(expression, from, columnKeys);
2103
- } else if (expression.kind === "column" && expression.source === from) columnKeys.add(expression.key);
2104
- else {
2105
- key = `$field${index + 1}`;
2106
- fields.push(Object.freeze({
2107
- key,
2108
- expression,
2109
- type: text
2110
- }));
2111
- }
2112
- fieldKeys.push(key);
2113
- }
2114
- const sourced = [];
2115
- for (const key of columnKeys) sourced.push(Object.freeze({
2116
- key,
2117
- expression: createNode({
2118
- kind: "column",
2119
- source: from,
2120
- key
2121
- }),
2122
- type: text
2123
- }));
2124
- for (const field of fields) sourced.push(field);
2125
- if (distinctOn !== void 0) for (let index = 0; index < distinctOn.length; index++) {
2126
- const key = distinctOn[index];
2127
- if (findValueProjection(sourced, key) === -1) sourced.push(Object.freeze({
2128
- key: `$key${index + 1}`,
2129
- expression: key,
2130
- type: text
2131
- }));
2132
- }
2133
- const page = deriveOrderedSource({
2134
- kind: "select",
2135
- from,
2136
- joins: noJoins,
2137
- projections: sourced,
2138
- filters: query.filters,
2139
- groupBy,
2140
- having: query.having,
2141
- orderBy,
2142
- limit: query.limit,
2143
- offset,
2144
- distinctOn,
2145
- rows: "many",
2146
- value: false,
2147
- guaranteedBy: void 0
2148
- }, true, offset, from);
2149
- const selected = [];
2150
- for (let index = 0; index < projections.length; index++) {
2151
- const projection = projections[index];
2152
- const key = fieldKeys[index];
2153
- selected.push(key === void 0 ? projection : Object.freeze({
2154
- key: projection.key,
2155
- expression: createNode({
2156
- kind: "column",
2157
- source: page.source,
2158
- key
2159
- }),
2160
- type: projection.type
2161
- }));
2162
- }
2163
- return Object.freeze({
2164
- kind: "select",
2165
- from: page.source,
2166
- joins: noJoins,
2167
- projections: selected,
2168
- filters: noFilters,
2169
- orderBy: positions ? sortByPositions(page.order, selected) : page.order,
2170
- limit: void 0,
2171
- offset: void 0,
2172
- rows: query.rows,
2173
- value: query.value,
2174
- guaranteedBy: query.guaranteedBy,
2175
- recordTemplate: query.recordTemplate
2176
- });
2177
- }
2178
- /**
2179
- * Tells whether `field`, a field of a query lowered to `projection`, is a nested query that a derived page evaluates only over its rows: one that no sort key of `orderBy`, the lowered order, sorts by, and that is none of `groupBy` and `distinctOn`, the lowered keys of the query.
2180
- *
2181
- * The query evaluates a field that it sorts by, groups by, or compares, of an aggregate or of `exists`, for every row anyway.
2182
- */
2183
- function isPagedField(field, projection, orderBy, groupBy, distinctOn) {
2184
- if (!isNestedSelection(field)) return false;
2185
- const { expression } = projection;
2186
- return !orderBy.some((order) => order.expression === expression) && (groupBy === void 0 || !groupBy.includes(expression)) && (distinctOn === void 0 || !distinctOn.includes(expression));
2187
- }
2188
- // src/lowering/lower.ts
2189
- function lowerStatement(node, definitions, db) {
2190
- const context = createContext(definitions, db);
2191
- switch (node.kind) {
2192
- case "query": return lowerSelect(node, context, true);
2193
- case "record": return lowerRecord(node, context);
2194
- default: return lowerMutation(node, context);
2195
- }
2196
- }
2197
- /** Lowers the SQL text of a statement, such as of `$query`, replacing the queries in the expressions interpolated into it, and checking them as `lowerStatement` does. */
2198
- function lowerTextStatement(node, definitions, db) {
2199
- return lowerExpression(node, createContext(definitions, db));
2200
- }
2201
- /** Creates the context of lowering a statement with `definitions` and `db`, whose nested queries `lowerSelect` lowers. */
2202
- function createContext(definitions, db) {
2203
- const context = {
2204
- definitions,
2205
- db,
2206
- lowerSelect: (node, positions) => lowerSelect(node, context, positions),
2207
- lowerExists: (node) => lowerExists(node, context)
2208
- };
2209
- return context;
2210
- }
2211
- /** Lowers a query as `lowerQuery` does, or as `lowerStatement` does when `positions` is set, with the conversion of its result. */
2212
- function lowerSelect(node, context, positions) {
2213
- const statement = lowerSelectStatement(node, context, positions);
2214
- const { conversion } = node;
2215
- return conversion === void 0 ? statement : Object.freeze({
2216
- ...statement,
2217
- conversion
2218
- });
2219
- }
2220
- /** Lowers a query to its statement, whichever it is: of `exists`, of an aggregate, of a page that evaluates its nested queries only over its rows, or of the rows of its source. */
2221
- function lowerSelectStatement(node, context, positions) {
2222
- if (isExistsQuery(node)) return selectExists(node, context);
2223
- checkRelation(node, context);
2224
- if (isAggregateQuery(node)) return lowerAggregate(node, context);
2225
- const recordTemplate = createRecordTemplate(node.projections);
2226
- const selected = dropLiterals(node.projections);
2227
- const projections = lowerProjections(selected, context);
2228
- if (node.groupBy.length > 0) checkGroupAggregates(projections, node);
2229
- const filters = lowerFilters(node.filters, context);
2230
- const orderBy = lowerOrder(node.orderBy, context, selected, projections);
2231
- const groupBy = lowerKeys(node.groupBy, context, selected, projections);
2232
- const having = lowerValue(node.having, context);
2233
- const distinctOn = lowerKeys(node.distinctOn, context, selected, projections);
2234
- if (node.distinct) checkDistinct(projections, orderBy);
2235
- if (distinctOn !== void 0) checkDistinctOn(projections, distinctOn, orderBy);
2236
- const { relation } = node;
2237
- const guaranteedBy = node.guaranteed && relation !== void 0 ? formatRelationName(relation.key, relation.name) : void 0;
2238
- const statement = {
2239
- kind: "select",
2240
- from: node.from,
2241
- joins: noJoins,
2242
- projections,
2243
- filters,
2244
- groupBy,
2245
- having,
2246
- orderBy,
2247
- limit: node.limit,
2248
- offset: node.offset,
2249
- distinct: node.distinct,
2250
- distinctOn,
2251
- lock: node.lock,
2252
- rows: node.rows,
2253
- value: node.value,
2254
- guaranteedBy,
2255
- recordTemplate
2256
- };
2257
- const page = lowerPage(statement, selected, positions);
2258
- if (page !== void 0) return page;
2259
- if (positions && orderBy.length > 0) statement.orderBy = sortByPositions(orderBy, projections);
2260
- return Object.freeze(statement);
2261
- }
2262
- /** Lowers a query of `exists` to a statement without a source of one row of `EXISTS` of its rows. */
2263
- function selectExists(node, context) {
2264
- return Object.freeze({
2265
- kind: "select",
2266
- from: void 0,
2267
- joins: noJoins,
2268
- projections: [projectExists(node.projections[0].key, node, context)],
2269
- filters: noFilters,
2270
- orderBy: noOrder,
2271
- limit: void 0,
2272
- offset: void 0,
2273
- rows: node.rows,
2274
- value: true,
2275
- guaranteedBy: void 0
2276
- });
2277
- }
2278
- /** Lowers a query of `$select` to a statement without a source, which returns one row of its fields. */
2279
- function lowerRecord(node, context) {
2280
- return Object.freeze({
2281
- kind: "select",
2282
- from: void 0,
2283
- joins: noJoins,
2284
- projections: lowerProjections(dropLiterals(node.projections), context),
2285
- filters: noFilters,
2286
- orderBy: noOrder,
2287
- limit: void 0,
2288
- offset: void 0,
2289
- rows: "one",
2290
- value: false,
2291
- guaranteedBy: void 0,
2292
- recordTemplate: createRecordTemplate(node.projections)
2293
- });
2294
- }
2295
- // src/query/kind.ts
2296
- /** `then` of every bound query, which executes the query on its `Db`. */
2297
- function executeOnAwait(onFulfilled, onRejected) {
2298
- return this.db.$execute(this).then(onFulfilled, onRejected);
2299
- }
2300
- /** Compiles `query` as its `toSQL` does: an unbound query with `options`, and a bound query as its `Db` executes it, which takes no options. */
2301
- function compileToSQL(query, options) {
2302
- const { db } = query;
2303
- if (db === void 0) {
2304
- const { text, parameters } = compileStatement(lowerStatement(query.node), options);
2305
- return createStatement$1(text, parameters);
2306
- }
2307
- if (options !== void 0) throw new Error("A query bound to a Db compiles with the options of its Db");
2308
- return db.$compile(query);
2309
- }
2310
- // src/query/conversion.ts
2311
- /**
2312
- * Immutable query of a table of state `S` whose whole result `transform` converts after decoding, unbound or bound to a `Db`.
2313
- *
2314
- * It executes and nests in a selection as the query it comes from, with the same SQL, so it has only `transform`, which converts the result further: another method would change what the callback receives, and an expression does not take it, since SQL does not see the conversion.
2315
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2316
- * A bound query executes on its `Db` when awaited.
2317
- */
2318
- var TransformedQuery = class {
2319
- node;
2320
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2321
- db;
2322
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2323
- then;
2324
- constructor(node, db) {
2325
- this.node = node;
2326
- this.db = db;
2327
- this.then = db === void 0 ? void 0 : executeOnAwait;
2328
- Object.freeze(this);
2329
- }
2330
- transform(callback) {
2331
- return transformQuery(this.node, this.db, callback);
2332
- }
2333
- toSQL(options) {
2334
- return compileToSQL(this, options);
2335
- }
2336
- /** Rejects the query as an operand of an expression, whose value SQL reads without its conversion. */
2337
- [operandNode]() {
2338
- 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 transform");
2339
- }
2340
- };
2341
- /** Creates the query of `transform` of `node`, a query of a table bound to `db` when given, whose whole result `callback` converts after the earlier conversions. */
2342
- function transformQuery(node, db, callback) {
2343
- return new TransformedQuery(Object.freeze({
2344
- ...node,
2345
- conversion: addTransform(node.conversion, callback),
2346
- foundKey: void 0
2347
- }), db);
2348
- }
2349
- /**
2350
- * Returns `conversion` of a query with `callback` of `map` after its earlier one.
2351
- *
2352
- * It rejects a conversion of `transform`, whose result has no rows to convert.
2353
- */
2354
- function addMap(conversion, callback) {
2355
- if (conversion?.transform !== void 0) throw new Error("map cannot be used after transform; convert the rows in its callback instead");
2356
- return Object.freeze({
2357
- map: chainConversions(conversion?.map, createConversion(callback, "map")),
2358
- transform: void 0
2359
- });
2360
- }
2361
- /** Returns `conversion` of a query with `callback` of `transform` after its earlier one. */
2362
- function addTransform(conversion, callback) {
2363
- return Object.freeze({
2364
- map: conversion?.map,
2365
- transform: chainConversions(conversion?.transform, createConversion(callback, "transform"))
2366
- });
2367
- }
2368
- /** Returns the conversion that applies `next` after `previous`, if any. */
2369
- function chainConversions(previous, next) {
2370
- return previous === void 0 ? next : (value) => next(previous(value));
2371
- }
2372
- /**
2373
- * Creates the conversion of `callback` of `method`, which rejects a Promise or another thenable returned by the callback: `SynchronousResult` rejects it in types, and a callback may still return one through `any`.
2374
- *
2375
- * It rejects a `callback` that is not a function when it is called, since decoding calls it long after, where its error would read as a failure of a row.
2376
- */
2377
- function createConversion(callback, method) {
2378
- if (typeof callback !== "function") throw new TypeError(`${method} takes a callback`);
2379
- return (value) => {
2380
- const result = callback(value);
2381
- if (typeof result?.then === "function") {
2382
- if (types.isPromise(result)) result.catch(ignoreRejection);
2383
- throw new TypeError(`The callback of ${method} must return its result synchronously, not a Promise or a query`);
2384
- }
2385
- return result;
2386
- };
2387
- }
2388
- /** Handles the rejection of a Promise that a callback returned, whose query has failed already. */
2389
- function ignoreRejection() {}
2390
- // src/query/resolve-values.ts
2391
- /**
2392
- * Replaces objects of column values in a predicate with conditions on the columns of `source`.
2393
- *
2394
- * Groups are rebuilt, so constants that appear after resolution, such as an empty object, are simplified.
2395
- */
2396
- function resolveValues(node, source) {
2397
- switch (node.kind) {
2398
- case "values": {
2399
- const conditions = [];
2400
- for (const key of Object.keys(node.values)) conditions.push(matchColumn(source, key, node.values[key]));
2401
- return combineNodes("and", conditions);
2402
- }
2403
- case "and":
2404
- case "or": {
2405
- const operands = [];
2406
- for (const operand of node.operands) operands.push(resolveValues(operand, source));
2407
- return combineNodes(node.kind, operands);
2408
- }
2409
- case "not": return negateNode(resolveValues(node.operand, source));
2410
- case "raw": return createNode({
2411
- ...node,
2412
- values: node.values.map((value) => resolveValues(value, source))
2413
- });
2414
- default: return node;
2415
- }
2416
- }
2417
- /** Creates the condition of column `key` of `source` in an object of column values: `IS NULL` of `null`, or the `eq` operator of its type for another value. */
2418
- function matchColumn(source, key, value) {
2419
- const type = findColumn(source.table, key)?.type;
2420
- const column = createNode({
2421
- kind: "column",
2422
- source,
2423
- key
2424
- });
2425
- if (value === null) return createIsNullNode(column);
2426
- if (type) return matchValue(source, column, type, value);
2427
- return compareNodes("=", column, value, void 0);
2428
- }
2429
- /** Matches a column with a value of an object condition by calling the `eq` operator of its type, whichever operator it is. */
2430
- function matchValue(source, column, type, value) {
2431
- const expression = toExpression(column, type);
2432
- 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`);
2433
- const predicate = expression.eq(value);
2434
- if (!isExpression(predicate)) throw new TypeError(`The eq operator of column "${column.key}" of table "${source.table.name}" must return an expression`);
2435
- return toNode(predicate);
2436
- }
2437
- // src/query/filters.ts
2438
- /** Creates query filters with the filter of `where` over `source` with the relations of `context` combined with `AND` with the user filters of `filters`. */
2439
- function addUserFilter(filters, filter, source, context) {
2440
- const predicate = toFilterNode(filter, source, context);
2441
- const { user } = filters;
2442
- return Object.freeze({
2443
- ...filters,
2444
- user: user ? combineNodes("and", [user, predicate]) : predicate
2445
- });
2446
- }
2447
- /**
2448
- * Converts a filter of `where` or `having` over `source` with the relations of `context` into the node of its condition, whose objects of column values it resolves.
2449
- *
2450
- * A callback receives the columns with the relations, and what `readSelected` returns, such as the selected fields for `having`.
2451
- */
2452
- function toFilterNode(filter, source, context, readSelected) {
2453
- return resolveValues(toConditionNode(typeof filter === "function" ? filter(createSelectionRefs(source, context), readSelected?.()) : filter), source);
2454
- }
2455
- // src/query/find.ts
2456
- /**
2457
- * 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.
2458
- *
2459
- * It rejects a table without a primary key, a number of values other than the number of its columns, and `null` and `undefined`.
2460
- */
2461
- function toPrimaryKeyValues(table, values) {
2462
- const { primaryKey } = table.keys;
2463
- 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`);
2464
- 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}`);
2465
- const filter = {};
2466
- for (let index = 0; index < primaryKey.length; index++) {
2467
- const column = primaryKey[index];
2468
- filter[column] = requireKeyValue(table, column, values[index], "find");
2469
- }
2470
- return filter;
2471
- }
2472
- /**
2473
- * Returns the object of column values that `findBy` filters a query of `table` by: a copy of `values`, read once.
2474
- *
2475
- * It rejects columns that are not exactly a key of `table`, primary or unique, as `isKey` tells, and `null` and `undefined`.
2476
- */
2477
- function toKeyValues(table, values) {
2478
- if (typeof values !== "object" || values === null) throw new TypeError(`findBy takes an object of the columns of a key of table "${table.name}"`);
2479
- const columns = Object.keys(values);
2480
- if (!isKey(table, columns)) {
2481
- const listed = columns.length === 0 ? "an object without columns" : `columns ${quoteColumns(columns)}`;
2482
- throw new Error(`findBy takes the columns of one key of table "${table.name}", primary or unique, not ${listed}`);
2483
- }
2484
- const filter = {};
2485
- for (const column of columns) {
2486
- const value = values[column];
2487
- filter[column] = requireKeyValue(table, column, value, "findBy");
2488
- }
2489
- return filter;
2490
- }
2491
- /**
2492
- * Returns the target of `onConflict` of `columns`: the key of `table` of exactly these columns, primary or unique, in the order of the key, or none for a conflict on any key when there are no columns.
2493
- *
2494
- * It rejects columns that are not exactly a key of `table`, as `isKey` tells.
2495
- */
2496
- function toConflictTarget(table, columns) {
2497
- if (columns.length === 0) return noColumns;
2498
- const key = findKey(table, columns);
2499
- if (key === void 0) throw new Error(`onConflict takes the columns of one key of table "${table.name}", primary or unique, or none for any key, not columns ${quoteColumns(columns)}`);
2500
- return key;
2501
- }
2502
- /** Columns of the target of a conflict on any key. */
2503
- const noColumns = /* @__PURE__ */ Object.freeze([]);
2504
- /** Returns `value` of column `column` of a key of `table` that `method` takes, rejecting `null` and `undefined`. */
2505
- function requireKeyValue(table, column, value, method) {
2506
- 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`);
2507
- return value;
2508
- }
2509
- /** Lists `columns` in quotes, separated by commas. */
2510
- function quoteColumns(columns) {
2511
- return columns.map((column) => `"${column}"`).join(", ");
2512
- }
2513
- // src/query/order.ts
2514
- /** Direction and placement of `NULL` of a sort key node, by `OrderDirection`. */
2515
- const directions = /* @__PURE__ */ Object.freeze({
2516
- asc: {
2517
- direction: "asc",
2518
- nulls: void 0
2519
- },
2520
- desc: {
2521
- direction: "desc",
2522
- nulls: void 0
2523
- },
2524
- "asc nulls first": {
2525
- direction: "asc",
2526
- nulls: "first"
2527
- },
2528
- "asc nulls last": {
2529
- direction: "asc",
2530
- nulls: "last"
2531
- },
2532
- "desc nulls first": {
2533
- direction: "desc",
2534
- nulls: "first"
2535
- },
2536
- "desc nulls last": {
2537
- direction: "desc",
2538
- nulls: "last"
2539
- }
2540
- });
2541
- const orderingNode = Symbol("kern-orm.ordering.node");
2542
- /** Runtime class of an expression with a direction, which holds its sort key node. */
2543
- var OrderingObject = class {
2544
- [orderingNode];
2545
- constructor(node) {
2546
- this[orderingNode] = node;
2547
- Object.freeze(this);
2548
- }
2549
- };
2550
- /** Sorts by `value`, an expression or a query of one value, in ascending order, in the callback of `orderBy`. */
2551
- function asc(value) {
2552
- return orderBy(value, "asc");
2553
- }
2554
- /** Sorts by `value`, an expression or a query of one value, in descending order, in the callback of `orderBy`. */
2555
- function desc(value) {
2556
- return orderBy(value, "desc");
2557
- }
2558
- /** Sorts by `value`, an expression or a query of one value, in `direction`, such as `"desc nulls last"`, in the callback of `orderBy`. */
2559
- function orderBy(value, direction) {
2560
- if (!isOperandSource(value)) throw new TypeError("A sort key must be an expression or a query of one value");
2561
- return new OrderingObject(createOrderNode(value[operandNode](), direction));
2562
- }
2563
- /**
2564
- * Creates the order of `node` with the sort keys of the arguments of `orderBy` after its own.
2565
- *
2566
- * `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.
2567
- */
2568
- function addOrder(node, context, args) {
2569
- const order = node.orderBy.slice();
2570
- const first = args[0];
2571
- if (typeof first === "function") {
2572
- addTerms(order, first(createSelectionRefs(node.from, context), createSelectedRefs(node, "sorted by")), "The callback of orderBy must return");
2573
- return order;
2574
- }
2575
- for (const arg of args) if (typeof arg === "string") order.push(createOrderNode(createColumnNode(node.from, arg), "asc"));
2576
- else if (typeof arg === "object" && arg !== null && !Array.isArray(arg)) {
2577
- const columns = arg;
2578
- for (const key of Object.keys(columns)) order.push(createOrderNode(createColumnNode(node.from, key), columns[key]));
2579
- } else throw new TypeError("orderBy takes column keys and objects of columns with directions, or a callback");
2580
- return order;
2581
- }
2582
- /** Adds to `order` the sort key nodes of `terms`, `OrderTerms` checked at runtime; `subject` starts the error of another value, such as `The callback of orderBy must return`. */
2583
- function addTerms(order, terms, subject) {
2584
- if (Array.isArray(terms)) for (const term of terms) order.push(readTerm$1(term, subject));
2585
- else order.push(readTerm$1(terms, subject));
2586
- }
2587
- /**
2588
- * Creates the sort key node of a sort key, `OrderTerm` checked at runtime, whose error starts with `subject`.
2589
- *
2590
- * A query is converted by the method of `operandNode`, which rejects a query other than of one value.
2591
- */
2592
- function readTerm$1(term, subject) {
2593
- if (term instanceof OrderingObject) return term[orderingNode];
2594
- if (isOperandSource(term)) return createOrderNode(term[operandNode](), "asc");
2595
- throw new TypeError(`${subject} expressions, queries of one value, or sort keys of asc, desc, and orderBy`);
2596
- }
2597
- /** Creates the sort key node of `expression` in `direction`, an `OrderDirection` checked at runtime. */
2598
- function createOrderNode(expression, direction) {
2599
- const placement = typeof direction === "string" && Object.hasOwn(directions, direction) ? directions[direction] : void 0;
2600
- if (placement === void 0) throw new TypeError(`Unknown sort direction ${JSON.stringify(direction)}`);
2601
- return Object.freeze({
2602
- expression,
2603
- direction: placement.direction,
2604
- nulls: placement.nulls
2605
- });
2606
- }
2607
- /** Creates a reference to the column `key` of the table of `source`. */
2608
- function createColumnNode(source, key) {
2609
- requireColumn(source.table, key);
2610
- return createNode({
2611
- kind: "column",
2612
- source,
2613
- key
2614
- });
2615
- }
2616
- /**
2617
- * Creates the references of the callback of `orderBy`, `groupBy`, `distinctOn`, or `having` to the fields selected by `node`; `purpose` completes the error of a field that cannot be read, such as `sorted by`.
2618
- *
2619
- * Each is an expression over the node of its projection, so that a sort key or a key of a group of it is the projection itself; `HAVING` compiles the expression again, since it cannot refer to a projection.
2620
- * 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.
2621
- */
2622
- function createSelectedRefs(node, purpose) {
2623
- const { projections } = node;
2624
- if (node.value) return toSelectedExpression(projections[0]);
2625
- const refs = {};
2626
- for (const projection of projections) {
2627
- const { key } = projection;
2628
- if (isLiteralSelection(projection)) Object.defineProperty(refs, key, {
2629
- get() {
2630
- throw new Error(`Field "${key}" holds a literal and cannot be ${purpose}`);
2631
- },
2632
- enumerable: true
2633
- });
2634
- else if (isNestedSelection(projection)) {
2635
- if (isSelectedAsValue(projection.query)) refs[key] = toQueryExpression(projection);
2636
- else Object.defineProperty(refs, key, {
2637
- get() {
2638
- throw new Error(`Field "${key}" holds nested rows and cannot be ${purpose}`);
2639
- },
2640
- enumerable: true
2641
- });
2642
- } else refs[key] = toSelectedExpression(projection);
2643
- }
2644
- return refs;
2645
- }
2646
- /** Creates an expression over the node of a projection of a query, which has a type: only lowering adds projections of nested queries. */
2647
- function toSelectedExpression(projection) {
2648
- return toExpression(projection.expression, projection.type);
2649
- }
2650
- /** Creates an expression of the value of `field`, a selected aggregate query or query of `exists`, with the type of its value. */
2651
- function toQueryExpression(field) {
2652
- const { query } = field;
2653
- return toExpression(createNode({
2654
- kind: "nestedQuery",
2655
- query,
2656
- db: field.db,
2657
- field
2658
- }), query.projections[0].type);
2659
- }
2660
- // src/query/group.ts
2661
- /** Method that takes the keys of groups, and the phrase of what it does with a field that cannot be a key, for its errors. */
2662
- const keyMethods = {
2663
- groupBy: "grouped by",
2664
- distinctOn: "a key of distinctOn"
2665
- };
2666
- /**
2667
- * Creates the keys of `method`, `groupBy` or `distinctOn`, of `node` with the keys of the arguments of the call after its own.
2668
- *
2669
- * `args` are column keys, or a callback that receives the columns with the relations of `context` and the selected fields, and returns one key or an array of them.
2670
- * A string names a column, never a selected field, whose key names only the field of a record.
2671
- * It rejects a call without keys, which would leave the rows of a query ungrouped, or keep all of them, when a list built in code is empty.
2672
- */
2673
- function addGroupKeys(method, node, context, args) {
2674
- const existing = node[method];
2675
- const keys = existing.slice();
2676
- const first = args[0];
2677
- if (typeof first === "function") {
2678
- const terms = first(createSelectionRefs(node.from, context), createSelectedRefs(node, keyMethods[method]));
2679
- if (Array.isArray(terms)) for (const term of terms) keys.push(readTerm(term, method));
2680
- else keys.push(readTerm(terms, method));
2681
- } else for (const arg of args) {
2682
- if (typeof arg !== "string") throw new TypeError(`${method} takes column keys or a callback`);
2683
- keys.push(createColumnNode(node.from, arg));
2684
- }
2685
- if (keys.length === existing.length) throw new TypeError(`${method} requires at least one key`);
2686
- return keys;
2687
- }
2688
- /**
2689
- * Creates the condition of the groups of `node` with `filter`, what `where` takes, combined with `AND` with its earlier condition.
2690
- *
2691
- * A callback also receives the fields selected so far, as `HavingFields` tells, so that a condition reads an aggregate or a key of an expression by its field.
2692
- * The condition stands apart from the filters of the rows, so it requires keys: without them, `having` would read as a filter of rows while PostgreSQL takes the whole query for one group.
2693
- */
2694
- function addHaving(node, filter, context) {
2695
- if (node.groupBy.length === 0) throw new Error("having requires an earlier groupBy; filter the rows with where");
2696
- const predicate = toFilterNode(filter, node.from, context, () => node.conversion !== void 0 || isAggregateQuery(node) || isExistsQuery(node) ? void 0 : createSelectedRefs(node, "read in having"));
2697
- return node.having === void 0 ? predicate : combineNodes("and", [node.having, predicate]);
2698
- }
2699
- /**
2700
- * Creates the node of a key returned by the callback of `method`.
2701
- *
2702
- * A query is converted by the method of `operandNode`, which rejects a query other than of one value.
2703
- */
2704
- function readTerm(term, method) {
2705
- if (isOperandSource(term)) return term[operandNode]();
2706
- throw new TypeError(`The callback of ${method} must return expressions or queries of one value`);
2707
- }
2708
- // src/query/lock.ts
2709
- /** Creates the row lock of `strength` for `method`, rejecting a query whose rows it cannot lock and options that contradict each other. */
2710
- function createRowLock(node, method, strength, options = {}) {
2711
- if (isAggregateQuery(node)) throw new Error(`${method} cannot be used after an aggregate`);
2712
- if (isExistsQuery(node)) throw new Error(`${method} cannot be used after exists`);
2713
- if (node.distinct) throw new Error(`${method} cannot be used after distinct, since a row without duplicates comes from several rows of the table`);
2714
- if (node.distinctOn.length > 0) throw new Error(`${method} cannot be used after distinctOn; PostgreSQL does not allow row locks with DISTINCT ON`);
2715
- if (node.groupBy.length > 0) throw new Error(`${method} cannot be used after groupBy, since a group comes from several rows of the table`);
2716
- const { noWait, skipLocked } = options;
2717
- if (noWait && skipLocked) throw new Error(`${method} takes either noWait or skipLocked, not both`);
2718
- return Object.freeze({
2719
- strength,
2720
- onLocked: noWait ? "NOWAIT" : skipLocked ? "SKIP LOCKED" : void 0
2721
- });
2722
- }
2723
- // src/query/record.ts
2724
- /**
2725
- * 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.
2726
- *
2727
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2728
- * A bound query executes on its `Db` when awaited.
2729
- */
2730
- var RecordQuery = class {
2731
- node;
2732
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2733
- db;
2734
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2735
- then;
2736
- constructor(node, db) {
2737
- this.node = node;
2738
- this.db = db;
2739
- this.then = db === void 0 ? void 0 : executeOnAwait;
2740
- Object.freeze(this);
2741
- }
2742
- toSQL(options) {
2743
- return compileToSQL(this, options);
2744
- }
2745
- /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2746
- [operandNode]() {
2747
- 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");
2748
- }
2749
- };
2750
- /**
2751
- * Starts the query of `$select` of `selection`, an object of expressions, queries, and literals by key, bound to `db` when given.
2752
- *
2753
- * It reads the keys and values of `selection` when it is called.
2754
- */
2755
- function startRecordQuery(selection, db) {
2756
- const projections = [];
2757
- addSelection(projections, selection);
2758
- return new RecordQuery(Object.freeze({
2759
- kind: "record",
2760
- projections
2761
- }), db);
2762
- }
2763
- // src/query/projections.ts
2764
- /**
2765
- * Creates the fields of `select` over `source`, appending new keys and replacing existing ones in place.
2766
- *
2767
- * `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.
2768
- */
2769
- function mergeProjections(projections, source, args, context) {
2770
- const result = projections.slice();
2771
- const first = args[0];
2772
- if (typeof first === "function") addSelection(result, first(createSelectionRefs(source, context)));
2773
- else {
2774
- const keys = first === "*" ? Object.keys(source.table.columns) : args;
2775
- for (const key of keys) setProjection(result, projectColumn(source, key));
2776
- }
2777
- return result;
2778
- }
2779
- /** Adds the fields of `selection`, expressions, queries, and literals by key, to `projections`, replacing existing keys in place. */
2780
- function addSelection(projections, selection) {
2781
- for (const key of Reflect.ownKeys(selection)) {
2782
- if (typeof key === "symbol") throw new TypeError("A selected field must have a string key");
2783
- setProjection(projections, selectValue(key, selection[key]));
2784
- }
2785
- }
2786
- /**
2787
- * Creates the projection of the value of `get` or `pluck`, or of the argument of an aggregate method, such as `max`, over `source`.
2788
- *
2789
- * `arg` is the argument of `method`: a column key, or a callback that receives the references of `source` with the relations of `context` and returns an expression or a query of one value.
2790
- * The value of such a query is that of `expr`, `NULL` without its row, since the projection holds one scalar rather than nested rows.
2791
- */
2792
- function projectValue(source, arg, method, context) {
2793
- if (typeof arg !== "function") return projectColumn(source, arg);
2794
- const result = arg(createSelectionRefs(source, context));
2795
- const value = result instanceof SelectQuery ? result.expr() : result;
2796
- if (!isExpression(value)) throw new TypeError(`The callback of ${method} must return an expression or a query of one value`);
2797
- const type = getType(value);
2798
- 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)`);
2799
- return projectExpression("value", value, type);
2800
- }
2801
- /**
2802
- * 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.
2803
- *
2804
- * The projection of an aggregate keeps its call, which lowering builds, and adds the fallback after its earlier ones.
2805
- * The projection of `exists` stays as it is, since `EXISTS` is never `NULL`.
2806
- */
2807
- function coalesceValue(field, fallback) {
2808
- const value = toFunctionOperandNode(fallback, field.type, "coalesce");
2809
- if (isExistsProjection(field)) return field;
2810
- if (isAggregateProjection(field)) return addFallback(field, value);
2811
- return Object.freeze({
2812
- key: field.key,
2813
- expression: createList("coalesce(", [field.expression, value], ")"),
2814
- type: field.type
2815
- });
2816
- }
2817
- /** 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. */
2818
- function selectValue(key, value) {
2819
- if (value instanceof Literal) return Object.freeze({
2820
- key,
2821
- literal: value.literal
2822
- });
2823
- if (value instanceof SelectQuery || value instanceof TransformedQuery) return Object.freeze({
2824
- key,
2825
- query: value.node,
2826
- db: value.db
2827
- });
2828
- if (value instanceof RecordQuery) throw new TypeError(`Selected field "${key}" is a query of $select, which cannot be nested; select its fields directly instead`);
2829
- if (value instanceof MutationQuery) throw new TypeError(`Selected field "${key}" is a query of insert, update, or delete, which cannot be nested`);
2830
- if (value instanceof SqlQuery) throw new TypeError(`Selected field "${key}" is a query of SQL text, which cannot be nested`);
2831
- if (!isExpression(value)) throw new TypeError(`Selected field "${key}" must be an expression, a query, or a literal`);
2832
- const type = getType(value);
2833
- 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)`);
2834
- return projectExpression(key, value, type);
2835
- }
2836
- /** Creates the projection of a column of the table of `source` under its key. */
2837
- function projectColumn(source, key) {
2838
- const { type } = requireColumn(source.table, key);
2839
- return Object.freeze({
2840
- key,
2841
- expression: createNode({
2842
- kind: "column",
2843
- source,
2844
- key
2845
- }),
2846
- type
2847
- });
2848
- }
2849
- /** Creates the projection of an expression under `key`, decoded with `type`, the type of the expression. */
2850
- function projectExpression(key, value, type) {
2851
- return Object.freeze({
2852
- key,
2853
- expression: toNode(value),
2854
- type
2855
- });
2856
- }
2857
- /** Adds or replaces a field by key, rejecting a key that a record cannot have. */
2858
- function setProjection(projections, projection) {
2859
- const { key } = projection;
2860
- if (!isRecordKey(key)) throw new Error(`Field "${key}" cannot be selected: it is not a valid record key`);
2861
- for (let index = 0; index < projections.length; index++) if (projections[index].key === key) {
2862
- projections[index] = projection;
2863
- return;
2864
- }
2865
- projections.push(projection);
2866
- }
2867
- // src/query/values.ts
2868
- /**
2869
- * 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.
2870
- *
2871
- * The columns are those that some record gives a value other than `undefined`, in the order that the records first give them, and a record that omits one inserts its `DEFAULT`.
2872
- * Several records without values insert the `DEFAULT` of the first column of the table, since `DEFAULT VALUES` inserts one row.
2873
- * It rejects a key that is not a column of `table`, and a query other than of one value.
2874
- */
2875
- function toInsertRows(table, records, method) {
2876
- if (records.length === 0) throw new Error(`${method} takes at least one record`);
2877
- const columns = [];
2878
- const rows = [];
2879
- for (const record of records) {
2880
- if (typeof record !== "object" || record === null) throw new TypeError(`${method} takes records of the values of the columns of table "${table.name}"`);
2881
- const row = [];
2882
- for (const key of Object.keys(record)) {
2883
- const value = record[key];
2884
- if (value === void 0) continue;
2885
- let index = columns.indexOf(key);
2886
- if (index === -1) index = columns.push(key) - 1;
2887
- row[index] = resolveValue(table, key, value);
2888
- }
2889
- rows.push(row);
2890
- }
2891
- if (columns.length === 0 && rows.length > 1) {
2892
- const first = Object.keys(table.columns)[0];
2893
- if (first !== void 0) columns.push(first);
2894
- }
2895
- for (const row of rows) while (row.length < columns.length) row.push(void 0);
2896
- return {
2897
- columns,
2898
- values: rows
2899
- };
2900
- }
2901
- /**
2902
- * 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 references of `source` with the relations of `context`, and those of `excluded` for `DO UPDATE` of a conflict, and returns them, read when it is called.
2903
- *
2904
- * A value of `undefined` keeps its column, and an update must set at least one column.
2905
- * It rejects a key that is not a column of the table of `source`, and a query other than of one value.
2906
- */
2907
- function toAssignments(source, set, context, excluded) {
2908
- const { table } = source;
2909
- const values = typeof set !== "function" ? set : excluded === void 0 ? set(createSelectionRefs(source, context)) : set(createSelectionRefs(source, context), createSelectionRefs(excluded, noContext));
2910
- 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`);
2911
- const assignments = [];
2912
- for (const key of Object.keys(values)) {
2913
- const value = values[key];
2914
- if (value !== void 0) assignments.push(Object.freeze({
2915
- key,
2916
- value: resolveValue(table, key, value)
2917
- }));
2918
- }
2919
- 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`);
2920
- return assignments;
2921
- }
2922
- /** Returns the node of `value` of the column of `table` under `key`: an expression or a query of one value, which lowering replaces with a scalar subquery, or a parameter encoded with the type of the column. */
2923
- function resolveValue(table, key, value) {
2924
- return toValueNode(value, requireColumn(table, key).type);
2925
- }
2926
- // src/query/mutation.ts
2927
- /**
2928
- * Immutable query of state `S` that inserts, updates, or deletes rows, unbound or bound to a `Db`.
2929
- *
2930
- * Without a selection, it resolves to the number of the rows it changes; `select`, `get`, and `pluck` return the fields of those rows instead, and `map` and `transform` convert them in code.
2931
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
2932
- * A bound query executes on its `Db` when awaited.
2933
- */
2934
- var MutationQuery = class MutationQuery {
2935
- table;
2936
- node;
2937
- context;
2938
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
2939
- db;
2940
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
2941
- then;
2942
- constructor(table, node, context, db) {
2943
- this.table = table;
2944
- this.node = node;
2945
- this.context = context;
2946
- this.db = db;
2947
- this.then = db === void 0 ? void 0 : executeOnAwait;
2948
- Object.freeze(this);
2949
- }
2950
- select(...args) {
2951
- this.rejectConverted("select");
2952
- const { node } = this;
2953
- const { returning } = node;
2954
- 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");
2955
- return this.derive({
2956
- returning: mergeProjections(returning ?? [], node.target, args, this.context),
2957
- value: false
2958
- });
2959
- }
2960
- get(arg) {
2961
- 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");
2962
- return this.deriveValue(arg, "get");
2963
- }
2964
- pluck(arg) {
2965
- return this.deriveValue(arg, "pluck");
2966
- }
2967
- map(callback) {
2968
- const { node } = this;
2969
- if (node.returning === void 0) throw new Error("map applies only to a mutation that returns the fields of its rows; select them before map, or call transform to convert the number of the rows");
2970
- return this.derive({ conversion: addMap(node.conversion, callback) });
2971
- }
2972
- transform(callback) {
2973
- return this.derive({ conversion: addTransform(this.node.conversion, callback) });
2974
- }
2975
- use(callback, ...args) {
2976
- const result = requireDerived(this, callback(this, ...args), "The callback of use");
2977
- if (this.node.returning === void 0 && result.node.returning?.length === 0) throw new Error("The callback of use must select at least one field, or not call select to return the number of the rows");
2978
- return result;
2979
- }
2980
- onConflict(...columns) {
2981
- const { node } = this;
2982
- if (node.kind !== "insert") throw new Error("onConflict applies only to insert and insertMany");
2983
- if (node.returning !== void 0 || node.conversion !== void 0 || node.conflict !== void 0) throw new Error("onConflict applies right after insert or insertMany, once; call select, get, pluck, map, and transform after its action");
2984
- return new ConflictTarget(this, toConflictTarget(this.table, columns));
2985
- }
2986
- toSQL(options) {
2987
- return compileToSQL(this, options);
2988
- }
2989
- /** Rejects the query as an operand of an expression, which takes a query of one value of a table. */
2990
- [operandNode]() {
2991
- 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");
2992
- }
2993
- /** Creates a mutation of the same kind and `Db` with the node changes applied. */
2994
- derive(changes) {
2995
- return new MutationQuery(this.table, Object.freeze({
2996
- ...this.node,
2997
- ...changes
2998
- }), this.context, this.db);
2999
- }
3000
- /** Creates the mutation that returns the value of `arg` of `method`, a column key or a callback that receives the columns and the relations and returns an expression or a query of one value, of each changed row. */
3001
- deriveValue(arg, method) {
3002
- this.rejectConverted(method);
3003
- const { node } = this;
3004
- return this.derive({
3005
- returning: [projectValue(node.target, arg, method, this.context)],
3006
- value: true,
3007
- rows: toValueRows(node.rows)
3008
- });
3009
- }
3010
- /** Rejects `method`, which changes the fields that the mutation returns, on a mutation that `map` or `transform` converts. */
3011
- rejectConverted(method) {
3012
- if (this.node.conversion !== void 0) throw new Error(`${method} cannot be used after map or transform; call it before them`);
3013
- }
3014
- };
3015
- /**
3016
- * Conflict target of an insert of state `S` on the key of columns `K`, or without columns for `never`, with methods that choose the action and return the mutation: without columns, `doNothing` takes any key, and `merge` and `update` the row of a singleton table.
3017
- *
3018
- * It is no query: awaiting it is a type error and rejects, so that an insert without an action does not resolve without running.
3019
- */
3020
- var ConflictTarget = class {
3021
- insert;
3022
- target;
3023
- constructor(insert, target) {
3024
- this.insert = insert;
3025
- this.target = target;
3026
- Object.freeze(this);
3027
- }
3028
- doNothing() {
3029
- const rows = this.insert.node.rows;
3030
- return this.derive(Object.freeze({ target: this.target }), rows === "one" ? "optional" : rows);
3031
- }
3032
- merge(...columns) {
3033
- const { insert } = this;
3034
- const target = this.target;
3035
- const updateTarget = toUpdateTarget(insert.table, target, "merge");
3036
- const node = this.insertNode();
3037
- const merged = columns.length === 0 ? node.columns.filter((key) => !target.includes(key)) : columns;
3038
- if (merged.length === 0) throw new Error("merge has no column to set, since the insert gives no column apart from the key of onConflict; use doNothing");
3039
- const excluded = createExcluded(insert.table);
3040
- const set = [];
3041
- for (const key of merged) {
3042
- requireColumn(insert.table, key);
3043
- if (target.includes(key)) throw new Error(`merge cannot set "${key}", a column of the key of onConflict`);
3044
- if (set.some((assignment) => assignment.key === key)) throw new Error(`merge takes each column once, not "${key}" twice`);
3045
- const index = node.columns.indexOf(key);
3046
- if (index === -1 || node.values.some((row) => row[index] === void 0)) throw new Error(`merge cannot set "${key}", which a record does not give, so that its default would replace the value of the record; give it in every record or leave it out of merge`);
3047
- set.push(Object.freeze({
3048
- key,
3049
- value: createNode({
3050
- kind: "column",
3051
- source: excluded,
3052
- key
3053
- })
3054
- }));
3055
- }
3056
- return this.derive(Object.freeze({
3057
- target: updateTarget,
3058
- update: Object.freeze({
3059
- set,
3060
- excluded
3061
- })
3062
- }), node.rows);
3063
- }
3064
- update(set) {
3065
- const { insert } = this;
3066
- const target = toUpdateTarget(insert.table, this.target, "update");
3067
- const node = this.insertNode();
3068
- const excluded = createExcluded(insert.table);
3069
- const assignments = toAssignments(node.target, set, insert.context, excluded);
3070
- return this.derive(Object.freeze({
3071
- target,
3072
- update: Object.freeze({
3073
- set: assignments,
3074
- excluded
3075
- })
3076
- }), node.rows);
3077
- }
3078
- /** Rejects awaiting the conflict target, which needs an action, such as `doNothing()`. */
3079
- then(_action) {
3080
- throw new Error("onConflict needs an action before the mutation runs, such as doNothing()");
3081
- }
3082
- /** Returns the node of the insert, which `onConflict` takes only of an insert. */
3083
- insertNode() {
3084
- return this.insert.node;
3085
- }
3086
- /** Creates the insert of the same kind and `Db` with `conflict`, changing rows `rows`. */
3087
- derive(conflict, rows) {
3088
- const { insert } = this;
3089
- const node = this.insertNode();
3090
- return new MutationQuery(insert.table, Object.freeze({
3091
- kind: "insert",
3092
- target: node.target,
3093
- columns: node.columns,
3094
- values: node.values,
3095
- conflict,
3096
- returning: void 0,
3097
- rows,
3098
- value: false
3099
- }), insert.context, insert.db);
3100
- }
3101
- };
3102
- /**
3103
- * Returns the target of `DO UPDATE` of `method` of a conflict on the columns `target` of a key of `table`: the columns, or without them the unique index of `(true)` of a singleton table.
3104
- *
3105
- * It rejects a target without columns of another table, since PostgreSQL requires an explicit conflict target for `DO UPDATE`.
3106
- */
3107
- function toUpdateTarget(table, target, method) {
3108
- if (target.length > 0) return target;
3109
- if (table.singleton) return "singleton";
3110
- throw new Error(`${method} needs the columns of a key in onConflict, since PostgreSQL updates a record only on a conflict of a named key`);
3111
- }
3112
- /** Creates the occurrence of `table` that stands for the row proposed for insertion in `DO UPDATE`, `EXCLUDED` of PostgreSQL. */
3113
- function createExcluded(table) {
3114
- return Object.freeze({
3115
- kind: "table",
3116
- table
3117
- });
3118
- }
3119
- /**
3120
- * 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`.
3121
- *
3122
- * It returns the number of the inserted rows, until a selection returns their fields.
3123
- * It rejects an insert of rows `many` into a singleton table, which holds one row.
3124
- */
3125
- function createInsert(query, records, rows, method) {
3126
- if (!isTableQuery(query.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`);
3127
- const { table } = query;
3128
- if (rows === "many" && table.singleton) throw new Error(`${method} cannot insert into singleton table "${table.name}", which holds one row; use insert or upsert`);
3129
- return createInsertInto(query, records, rows, method);
3130
- }
3131
- /**
3132
- * Creates the upsert of `values` by `query`, a query of `find` or `findBy` of a table without other clauses, or of a singleton table without clauses.
3133
- *
3134
- * It inserts the values of the key of `query` with `values`, and on a conflict on that key, or on the row of a singleton table, sets the columns of `values` of the existing record, as `merge` of `onConflict` does.
3135
- * It rejects another query, values that are not an object, a value of a column of the key, and values without a value other than `undefined`.
3136
- */
3137
- function createUpsert(query, values) {
3138
- const { table } = query;
3139
- const { foundKey } = query.node;
3140
- if (foundKey === void 0) throw new Error("upsert applies only to a query of a singleton table or right after find or findBy of a query of a table, without clauses such as filters, optional, or selected fields; select the fields that it returns after it");
3141
- if (typeof values !== "object" || values === null) throw new TypeError(`upsert takes the values of the columns of table "${table.name}"`);
3142
- const key = Object.keys(foundKey);
3143
- const record = {};
3144
- for (const column of key) record[column] = foundKey[column];
3145
- let hasValues = false;
3146
- for (const column of Object.keys(values)) {
3147
- const value = values[column];
3148
- if (value === void 0) continue;
3149
- if (Object.hasOwn(foundKey, column)) throw new Error(`upsert takes the values of the columns other than the key of find or findBy, not of "${column}"`);
3150
- record[column] = value;
3151
- hasValues = true;
3152
- }
3153
- if (!hasValues) throw new Error(key.length === 0 ? "upsert takes the value of at least one column; to insert the row unless it exists, use insert(...).onConflict().doNothing()" : "upsert takes the value of at least one column other than the key; to insert the record of the key unless it exists, use insert(...).onConflict(...).doNothing()");
3154
- return new ConflictTarget(createInsertInto(query, [record], "one", "upsert"), key.length === 0 ? key : findKey(table, key)).merge();
3155
- }
3156
- /** Creates the insert of `records` into the occurrence of the table of `query`, whose clauses it does not read, in rows mode `rows` of the method named by `method`. */
3157
- function createInsertInto(query, records, rows, method) {
3158
- const { node } = query;
3159
- const { columns, values } = toInsertRows(node.from.table, records, method);
3160
- return new MutationQuery(query.table, Object.freeze({
3161
- kind: "insert",
3162
- target: node.from,
3163
- columns,
3164
- values,
3165
- returning: void 0,
3166
- rows,
3167
- value: false
3168
- }), query.context, query.db);
3169
- }
3170
- /** Creates the update of the rows of `query` that `set` gives, as `update` takes it, in the rows mode of the query. */
3171
- function createUpdate(query, set) {
3172
- const { node } = query;
3173
- checkChangedRows(node, "update");
3174
- return new MutationQuery(query.table, Object.freeze({
3175
- kind: "update",
3176
- target: node.from,
3177
- set: toAssignments(node.from, set, query.context),
3178
- filters: node.filters,
3179
- returning: void 0,
3180
- rows: node.rows,
3181
- value: false
3182
- }), query.context, query.db);
3183
- }
3184
- /** Creates the delete of the rows of `query`, in the rows mode of the query. */
3185
- function createDelete(query) {
3186
- const { node } = query;
3187
- checkChangedRows(node, "delete");
3188
- return new MutationQuery(query.table, Object.freeze({
3189
- kind: "delete",
3190
- target: node.from,
3191
- filters: node.filters,
3192
- returning: void 0,
3193
- rows: node.rows,
3194
- value: false
3195
- }), query.context, query.db);
3196
- }
3197
- /**
3198
- * 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 a conversion of `map`, which a mutation takes after it too, with keys of groups, whose rows SQL does not give, with an order, a limit, an offset, `distinct`, or `distinctOn`, with a row lock, which a mutation takes on its rows itself, or without a filter that restricts its rows unless `all` allows it or the table is a singleton table.
3199
- *
3200
- * A filter simplified to `TRUE`, such as `where({})`, restricts no row.
3201
- */
3202
- function checkChangedRows(node, method) {
3203
- if (node.relation !== void 0) throw new Error(`${method} applies only to a query of a table, not of a relation`);
3204
- if (node.projections.length > 0) throw new Error(`${method} returns the fields selected after it, not before; call select, get, or pluck after ${method}`);
3205
- if (node.conversion !== void 0) throw new Error(`${method} returns what map converts after it, not before; call map after ${method}`);
3206
- if (node.groupBy.length > 0) throw new Error(`${method} changes rows rather than groups; choose them with where, find, or findBy instead of groupBy`);
3207
- if (node.orderBy.length > 0 || node.limit !== void 0 || node.offset !== void 0 || node.distinct || node.distinctOn.length > 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, orderBy, distinct, or distinctOn`);
3208
- if (node.lock !== void 0) throw new Error(`${method} locks the rows it changes itself, so its query takes no row lock`);
3209
- if (node.all || node.from.table.singleton) return;
3210
- const predicate = combineFilters(node.filters);
3211
- if (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`);
3212
- }
3213
- // src/query/pagination.ts
3214
- /** 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. */
3215
- function createPageCount(node, method, count) {
3216
- if (node.rows !== "many") throw new Error(`${method} applies only to a query of many rows${createPaginationHint(node)}`);
3217
- if (!Number.isSafeInteger(count) || count < 0) throw new RangeError(`${method} takes a non-negative integer, not ${count}`);
3218
- return createNode({
3219
- kind: "param",
3220
- value: count,
3221
- type: void 0
3222
- });
3223
- }
3224
- /** Creates the hint of the error of `limit` or `offset` of query `node` of one row: the method to call them before, if any. */
3225
- function createPaginationHint(node) {
3226
- if (node.relation === void 0 ? node.from.table.singleton : node.relation.kind === "one") return "";
3227
- if (isAggregateQuery(node)) return "; call it before count or another aggregate to aggregate the rows of a page";
3228
- if (isExistsQuery(node)) return "; call it before exists to check the rows of a page";
3229
- return "; call it before take or get";
3230
- }
3231
- // src/query/select.ts
3232
- /**
3233
- * Immutable select query of state `S`, unbound or bound to a `Db`.
3234
- *
3235
- * Every method returns a query of the same kind and leaves this query unchanged.
3236
- * An unbound query is not thenable, so it can be returned from async functions; it is compiled with `toSQL` or executed by a `Db`.
3237
- * A bound query executes on its `Db` when awaited.
3238
- */
3239
- var SelectQuery = class SelectQuery {
3240
- table;
3241
- node;
3242
- context;
3243
- /** `Db` that executes the query when it is awaited; `undefined` for an unbound query. */
3244
- db;
3245
- /** Executes a bound query on its `Db`; `undefined` for an unbound query, so that it is not thenable. */
3246
- then;
3247
- constructor(table, node, context, db) {
3248
- this.table = table;
3249
- this.node = node;
3250
- this.context = context;
3251
- this.db = db;
3252
- this.then = db === void 0 ? void 0 : executeOnAwait;
3253
- Object.freeze(this);
3254
- }
3255
- where(filter) {
3256
- return this.derive(this.addFilter(filter));
3257
- }
3258
- select(...args) {
3259
- this.rejectValue("select");
3260
- return this.derive({ projections: mergeProjections(this.node.projections, this.node.from, args, this.context) });
3261
- }
3262
- clearSelect() {
3263
- this.rejectValue("clearSelect");
3264
- return this.derive({ projections: [] });
3265
- }
3266
- take() {
3267
- return this.deriveTaken({});
3268
- }
3269
- find(...values) {
3270
- return this.takeWhere(toPrimaryKeyValues(this.table, values));
3271
- }
3272
- findBy(values) {
3273
- return this.takeWhere(toKeyValues(this.table, values));
3274
- }
3275
- get(arg) {
3276
- this.rejectAggregate("get");
3277
- return this.deriveTaken({
3278
- projections: [projectValue(this.node.from, arg, "get", this.context)],
3279
- value: true,
3280
- rows: toValueRows(this.node.rows)
3281
- });
3282
- }
3283
- pluck(arg) {
3284
- this.rejectAggregate("pluck");
3285
- return this.derive({
3286
- projections: [projectValue(this.node.from, arg, "pluck", this.context)],
3287
- value: true,
3288
- rows: toValueRows(this.node.rows)
3289
- });
3290
- }
3291
- count(arg) {
3292
- if (arg !== void 0) return this.aggregateBy("count", arg);
3293
- this.rejectAggregation("count");
3294
- return this.deriveAggregate(countProjection);
3295
- }
3296
- countDistinct(arg) {
3297
- return this.aggregateBy("countDistinct", arg);
3298
- }
3299
- min(arg) {
3300
- return this.aggregateBy("min", arg);
3301
- }
3302
- max(arg) {
3303
- return this.aggregateBy("max", arg);
3304
- }
3305
- sum(arg) {
3306
- return this.aggregateBy("sum", arg);
3307
- }
3308
- avg(arg) {
3309
- return this.aggregateBy("avg", arg);
3310
- }
3311
- every(arg) {
3312
- return this.aggregateBy("every", arg);
3313
- }
3314
- some(arg) {
3315
- return this.aggregateBy("some", arg);
3316
- }
3317
- stringAgg(arg, delimiter) {
3318
- return this.aggregateBy("stringAgg", arg, delimiter);
3319
- }
3320
- exists() {
3321
- this.rejectAggregation("exists");
3322
- return this.deriveAggregate(getExistsProjection());
3323
- }
3324
- coalesce(fallback) {
3325
- this.rejectMapped("coalesce");
3326
- const { node } = this;
3327
- if (!node.value) throw new Error("coalesce applies only to a query of values, such as one made by get, pluck, or an aggregate");
3328
- return this.derive({ projections: [coalesceValue(node.projections[0], fallback)] });
3329
- }
3330
- expr() {
3331
- const value = this[operandNode]();
3332
- return toExpression(value, this.node.projections[0].type);
3333
- }
3334
- groupBy(...args) {
3335
- this.rejectAggregate("groupBy");
3336
- if (this.node.lock !== void 0) throw new Error("groupBy cannot be used after a row lock, since a group comes from several rows of the table");
3337
- return this.derive({ groupBy: addGroupKeys("groupBy", this.node, this.context, args) });
3338
- }
3339
- having(filter) {
3340
- return this.derive({
3341
- having: addHaving(this.node, filter, this.context),
3342
- rows: this.getFilteredRows(),
3343
- guaranteed: false
3344
- });
3345
- }
3346
- orderBy(...args) {
3347
- return this.derive({ orderBy: addOrder(this.node, this.context, args) });
3348
- }
3349
- limit(count) {
3350
- return this.derive({ limit: createPageCount(this.node, "limit", count) });
3351
- }
3352
- offset(count) {
3353
- return this.derive({ offset: createPageCount(this.node, "offset", count) });
3354
- }
3355
- distinct() {
3356
- if (this.node.rows !== "many") throw new Error("distinct applies only to a query of many rows");
3357
- if (this.node.distinctOn.length > 0) throw new Error("distinct cannot be used after distinctOn, which compares only its keys");
3358
- if (this.node.lock !== void 0) throw new Error("distinct cannot be used after a row lock, since a row without duplicates comes from several rows of the table");
3359
- return this.derive({ distinct: true });
3360
- }
3361
- distinctOn(...args) {
3362
- const { node } = this;
3363
- if (node.rows !== "many") throw new Error("distinctOn applies only to a query of many rows");
3364
- if (node.distinct) throw new Error("distinctOn cannot be used after distinct, which compares every selected field");
3365
- if (node.lock !== void 0) throw new Error("distinctOn cannot be used after a row lock; PostgreSQL does not allow row locks with DISTINCT ON");
3366
- return this.derive({ distinctOn: addGroupKeys("distinctOn", node, this.context, args) });
3367
- }
3368
- forUpdate(options) {
3369
- return this.derive({ lock: createRowLock(this.node, "forUpdate", "UPDATE", options) });
3370
- }
3371
- forNoKeyUpdate(options) {
3372
- return this.derive({ lock: createRowLock(this.node, "forNoKeyUpdate", "NO KEY UPDATE", options) });
3373
- }
3374
- forShare(options) {
3375
- return this.derive({ lock: createRowLock(this.node, "forShare", "SHARE", options) });
3376
- }
3377
- forKeyShare(options) {
3378
- return this.derive({ lock: createRowLock(this.node, "forKeyShare", "KEY SHARE", options) });
3379
- }
3380
- optional() {
3381
- return this.changeOneRow("optional", "optional");
3382
- }
3383
- nullable() {
3384
- if (this.node.value && this.node.conversion === void 0) throw new Error("nullable applies only to a query of records; use optional after get, pluck, or an aggregate");
3385
- return this.changeOneRow("nullable", "nullable");
3386
- }
3387
- required() {
3388
- return this.changeOneRow("required", "one");
3389
- }
3390
- insert(values) {
3391
- return createInsert(this, [values], "one", "insert");
3392
- }
3393
- insertMany(records) {
3394
- if (!Array.isArray(records)) throw new TypeError("insertMany takes an array of records");
3395
- return createInsert(this, records, "many", "insertMany");
3396
- }
3397
- upsert(values) {
3398
- return createUpsert(this, values);
3399
- }
3400
- update(set) {
3401
- return createUpdate(this, set);
3402
- }
3403
- delete() {
3404
- return createDelete(this);
3405
- }
3406
- all() {
3407
- if (this.node.rows !== "many") throw new Error("all applies only to a query of many rows");
3408
- return this.derive({ all: true });
3409
- }
3410
- map(callback) {
3411
- return this.derive({ conversion: addMap(this.node.conversion, callback) });
3412
- }
3413
- transform(callback) {
3414
- return transformQuery(this.node, this.db, callback);
3415
- }
3416
- use(callback, ...args) {
3417
- return requireDerived(this, callback(this, ...args), "The callback of use");
3418
- }
3419
- toSQL(options) {
3420
- return compileToSQL(this, options);
3421
- }
3422
- /**
3423
- * 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`.
3424
- *
3425
- * It rejects a query of records or of rows `many`, which `ScalarQuery` rejects in types.
3426
- */
3427
- [operandNode]() {
3428
- const { node } = this;
3429
- 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");
3430
- if (node.conversion !== void 0) throw new TypeError("An expression takes a query of one value, such as of get, an aggregate, or exists, not a query of map");
3431
- return createNode({
3432
- kind: "nestedQuery",
3433
- query: node,
3434
- db: this.db
3435
- });
3436
- }
3437
- /**
3438
- * Returns the node of the query as the values of `in`, which lowering replaces with its statement.
3439
- *
3440
- * It rejects a query of records, which `ValuesQuery` rejects in types.
3441
- */
3442
- [valuesQueryNode]() {
3443
- const { node } = this;
3444
- if (!node.value) throw new TypeError("in takes a query of values, such as of pluck, not a query of records");
3445
- if (node.conversion !== void 0) throw new TypeError("in takes a query of values, such as of pluck, not a query of map");
3446
- return createNode({
3447
- kind: "nestedQuery",
3448
- query: node,
3449
- db: this.db
3450
- });
3451
- }
3452
- /** Creates a query of the same kind and `Db` with the node changes applied, dropping the key of `find` and `findBy` unless the changes give it. */
3453
- derive(changes) {
3454
- return new SelectQuery(this.table, Object.freeze({
3455
- ...this.node,
3456
- foundKey: void 0,
3457
- ...changes
3458
- }), this.context, this.db);
3459
- }
3460
- /**
3461
- * Creates a query of the same kind and `Db` with the node changes applied and then those of `take`, in one derived query.
3462
- *
3463
- * It adds the changes of `take` to `changes`, which must leave the limit as it is.
3464
- */
3465
- deriveTaken(changes) {
3466
- if ((changes.rows ?? this.node.rows) === "many") {
3467
- changes.limit = limitToOne(this.node.limit);
3468
- changes.rows = "one";
3469
- }
3470
- return this.derive(changes);
3471
- }
3472
- /**
3473
- * 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.
3474
- *
3475
- * A query of `distinct` or `distinctOn` keeps the fields that `projection` replaces: `distinct` compares them, and the keys, the order, and the argument of an aggregate read a selected field through its projection.
3476
- */
3477
- deriveAggregate(projection) {
3478
- const { node } = this;
3479
- const changes = {
3480
- projections: [projection],
3481
- rows: "one",
3482
- value: true,
3483
- guaranteed: false
3484
- };
3485
- if (node.distinct || node.distinctOn.length > 0) changes.distinctFields = node.projections;
3486
- return this.derive(changes);
3487
- }
3488
- /** Creates the query of the aggregate of `method` over `arg`, a column key or a callback that receives the columns and the relations and returns an expression or a query of one value; `delimiter` is the delimiter of `stringAgg`. */
3489
- aggregateBy(method, arg, delimiter) {
3490
- this.rejectAggregation(method);
3491
- return this.deriveAggregate(projectAggregate(method, projectValue(this.node.from, arg, method, this.context), delimiter));
3492
- }
3493
- /** Returns the changes of the node that add `filter` with `AND`, ending the guarantee of the row as `FilteredState` does in types. */
3494
- addFilter(filter) {
3495
- const { node } = this;
3496
- return {
3497
- filters: addUserFilter(node.filters, filter, node.from, this.context),
3498
- rows: this.getFilteredRows(),
3499
- guaranteed: false
3500
- };
3501
- }
3502
- /** Returns the rows mode of this query after a filter, as `FilteredStateRows` gives it in types. */
3503
- getFilteredRows() {
3504
- const { node } = this;
3505
- return toFilteredRows(node.rows, node.value && node.conversion === void 0, node.guaranteed);
3506
- }
3507
- /**
3508
- * Creates the query of `find` and `findBy`: `where` of `values`, an object of the values of the columns of a key, returning one row like `take`.
3509
- *
3510
- * On a query of a table without clauses, it keeps `values` as the key that `upsert` inserts.
3511
- */
3512
- takeWhere(values) {
3513
- const changes = this.addFilter(values);
3514
- if (changes.rows === "many") changes.rows = "one";
3515
- if (isTableQuery(this.node)) changes.foundKey = Object.freeze(values);
3516
- return this.derive(changes);
3517
- }
3518
- /** Creates the query of one row with rows mode `rows` that `method` returns, rejecting a query of many rows. */
3519
- changeOneRow(method, rows) {
3520
- if (this.node.rows === "many") throw new Error(`${method} applies only to a query of one row, such as one made by take`);
3521
- return this.derive({
3522
- rows,
3523
- guaranteed: false
3524
- });
3525
- }
3526
- /** Rejects `method`, which reads or changes the fields of the query, on a query that `map` converts. */
3527
- rejectMapped(method) {
3528
- if (this.node.conversion !== void 0) throw new Error(`${method} cannot be used after map; call it before map`);
3529
- }
3530
- /** Rejects a change of the selection by `method` of a query made by `get`, `pluck`, or an aggregate method. */
3531
- rejectValue(method) {
3532
- this.rejectMapped(method);
3533
- if (!this.node.value) return;
3534
- this.rejectAggregate(method);
3535
- throw new Error(`${method} cannot be used after get or pluck; call get or pluck to replace the value`);
3536
- }
3537
- /** Rejects `method`, which replaces the value or the selection, on a query made by an aggregate method or `exists`. */
3538
- rejectAggregate(method) {
3539
- this.rejectMapped(method);
3540
- const { node } = this;
3541
- if (isAggregateQuery(node)) throw new Error(`${method} cannot be used after an aggregate`);
3542
- if (isExistsQuery(node)) throw new Error(`${method} cannot be used after exists`);
3543
- }
3544
- /** Rejects `method`, an aggregate method or `exists`, on a query made by one of them or with a row lock. */
3545
- rejectAggregation(method) {
3546
- this.rejectAggregate(method);
3547
- if (this.node.lock !== void 0) throw new Error(`${method} cannot be used after a row lock, since it returns no rows of the table to lock`);
3548
- }
3549
- };
3550
- /**
3551
- * Returns `result`, which a callback named by `subject` returned for `query`, a query of a table or a mutation, after checking that it is `query` or a query of the same class derived from it.
3552
- *
3553
- * An ancestor of `query` also passes, since only the source occurrence is compared.
3554
- */
3555
- function requireDerived(query, result, subject) {
3556
- if (!(query instanceof SelectQuery ? result instanceof SelectQuery && result.node.from === query.node.from : result instanceof MutationQuery && result.node.target === query.node.target)) throw new Error(`${subject} must return the query it receives or one derived from it`);
3557
- return result;
3558
- }
3559
- /** Binds a query to `db`, so that awaiting it executes it there. */
3560
- function bindQuery(query, db) {
3561
- return new SelectQuery(query.table, query.node, query.context, db);
3562
- }
3563
- function from(table) {
3564
- return startQuery(table, noContext);
3565
- }
3566
- /** 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. */
3567
- function startQuery(table, context) {
3568
- return new SelectQuery(table, createQueryNode(Object.freeze({
3569
- kind: "table",
3570
- table
3571
- })), context);
3572
- }
1
+ import { C as defineType, D as equalityOperators, F as falseNode, M as createList, N as createNode, R as noOrder, S as getBooleanType, T as isType$1, V as trueNode, _ as toCastValueNode, b as toNode, c as compare, d as getType, f as isExpression, g as toBooleanExpression, i as textOperators, j as defineGenericOperator, m as operandNode, p as isOperandSource, s as orderingOperators, v as toExpression, w as describeRejectedDbType, x as toValueNode, y as toFunctionOperandNode } from "./text-ucmJCsCN.mjs";
2
+ import { A as countProjection, B as combineNodes, D as compileTextStatement, E as compileStatement, F as literal, I as and, L as isColumnValues, M as createAggregateCall, N as createCountCall, O as createTableFactory, P as toAggregateType, R as not, S as collectDefinitions, T as one, _ as matchColumn, a as SelectQuery, b as lowerTextStatement, c as requireDerived, d as RecordQuery, f as startRecordQuery, g as orderBy, h as desc, i as createQueryContexts, j as countType, k as defineTable, l as startQuery, m as asc, n as defineSchema, o as bindQuery, p as addTerms, r as schemaRelations, s as from, t as defineEntries, u as MutationQuery, v as TransformedQuery, w as many, x as isTableQuery, y as lowerStatement, z as or } from "./schema-lVpsWpEF.mjs";
3
+ import { SqlFragment, SqlQuery, assertUntypedValue, createFieldDecodeError, createResultDecodeError, startSqlQuery, takeOnlyRow, toMissingResult } from "kern-db/builder";
4
+ import { ConnectionError, NotFoundError, NotFoundError as NotFoundError$1, QueryError, ResultDecodeError, ResultDecodeError as ResultDecodeError$1, TransactionConnectionError, createDatabase, createStatement, createStatement as createStatement$1, identifier as identifier$1, isDatabase, isOutcomeUnknown, isQueryError, toDriverError } from "kern-db";
5
+ import { AsyncLocalStorage } from "node:async_hooks";
6
+ // src/expression/constants.ts
7
+ /** Condition that always holds, such as for a branch of `and` built in code: `and(check, isAdmin ? TRUE : other)`. */
8
+ const TRUE = /* @__PURE__ */ toExpression(trueNode, /* @__PURE__ */ getBooleanType());
9
+ /** Condition that never holds, such as for a branch of `or` built in code: `or(check, isAdmin ? other : FALSE)`. */
10
+ const FALSE = /* @__PURE__ */ toExpression(falseNode, /* @__PURE__ */ getBooleanType());
3573
11
  // src/expression/functions.ts
3574
12
  function coalesce(first, ...rest) {
3575
13
  return callFunction("coalesce", first, rest);
@@ -4012,122 +450,13 @@ function toInterpolatedNode(value) {
4012
450
  if (!isOperandSource(value)) assertUntypedValue(value);
4013
451
  return toValueNode(value);
4014
452
  }
4015
- // src/query/relations.ts
4016
- /** Creates the contexts of the queries of the tables under `keys` in a schema of relations `relations`, by table key. */
4017
- function createQueryContexts(keys, relations) {
4018
- const contexts = Object.create(null);
4019
- for (const key of keys) {
4020
- const named = relations[key];
4021
- if (named === void 0) {
4022
- contexts[key] = noContext;
4023
- continue;
4024
- }
4025
- const getters = Object.create(null);
4026
- for (const name of Object.keys(named)) {
4027
- const definition = named[name];
4028
- getters[name] = Object.freeze({
4029
- get() {
4030
- return startRelated(this, definition, contexts[definition.targetKey]);
4031
- },
4032
- enumerable: true
4033
- });
4034
- }
4035
- contexts[key] = Object.freeze({ relations: Object.freeze(getters) });
4036
- }
4037
- return Object.freeze(contexts);
4038
- }
4039
- /**
4040
- * Starts the query of the records of relation `definition` of the row of `parent`, the references of the callback of a query, in the context of the target table.
4041
- *
4042
- * The relation filter compares the key columns of the target with those of `parent` with SQL `=` directly rather than with the `eq` operators of their types, which a custom type can replace.
4043
- */
4044
- function startRelated(parent, definition, context) {
4045
- const { target, from, to } = definition;
4046
- const source = Object.freeze({
4047
- kind: "table",
4048
- table: target
4049
- });
4050
- const conditions = [];
4051
- for (let index = 0; index < from.length; index++) conditions.push(createNode({
4052
- kind: "comparison",
4053
- operator: "=",
4054
- left: createNode({
4055
- kind: "column",
4056
- source,
4057
- key: to[index]
4058
- }),
4059
- right: toNode(parent[from[index]])
4060
- }));
4061
- return new SelectQuery(target, createQueryNode(source, definition, Object.freeze({ relation: combineNodes("and", conditions) })), context);
4062
- }
4063
- // src/schema/schema.ts
4064
- const schemaBrand = Symbol("kern-orm.schema");
4065
- /** Key of the relation definitions of a schema, which composition reads. */
4066
- const schemaRelations = Symbol("kern-orm.schema.relations");
4067
- /**
4068
- * Defines a schema of the tables of `parts`, keyed by their names in queries.
4069
- *
4070
- * A part is an object of tables by their keys or another schema, whose tables and relations the new schema includes as they are, so queries built from that schema run on the new one.
4071
- * A key of two different tables, a table under two keys, and two different definitions of a relation of a table are rejected; the same table under the same key or the same relation in several parts is one.
4072
- */
4073
- function defineSchema(...parts) {
4074
- const tables = /* @__PURE__ */ new Map();
4075
- const keys = /* @__PURE__ */ new Map();
4076
- const relations = /* @__PURE__ */ new Map();
4077
- for (const part of parts) {
4078
- const partTables = isSchema(part) ? part.$tables : part;
4079
- for (const key of Object.keys(partTables)) {
4080
- if (key.startsWith("$")) throw new Error(`Table key "${key}" must not start with "$"`);
4081
- const table = partTables[key];
4082
- const keyTable = tables.get(key);
4083
- if (keyTable !== void 0 && keyTable !== table) throw new Error(`Table key "${key}" refers to two different tables`);
4084
- const tableKey = keys.get(table);
4085
- if (tableKey !== void 0 && tableKey !== key) throw new Error(`Table "${table.name}" is included under two keys, "${tableKey}" and "${key}"`);
4086
- tables.set(key, table);
4087
- keys.set(table, key);
4088
- }
4089
- if (isSchema(part)) addRelations(relations, part[schemaRelations]);
4090
- }
4091
- return createSchema(Object.freeze(Object.fromEntries(tables)), keys, freezeRelations(relations));
4092
- }
4093
- /** Creates a schema of tables and relation definitions that are already checked; `keys` gives the key of each table. */
4094
- function createSchema(tables, keys, relations) {
4095
- const methods = {
4096
- [schemaBrand]: true,
4097
- $tables: tables,
4098
- [schemaRelations]: relations,
4099
- $relations(declarations) {
4100
- const added = /* @__PURE__ */ new Map();
4101
- addRelations(added, relations);
4102
- for (const key of Object.keys(declarations)) {
4103
- if (!Object.hasOwn(tables, key)) throw new Error(`Relations are declared for table key "${key}", which is not part of the schema`);
4104
- const named = declarations[key];
4105
- if (named === void 0) continue;
4106
- for (const name of Object.keys(named)) addRelation(added, key, name, defineRelation(tables[key], key, name, named[name], (table) => keys.get(table)));
4107
- }
4108
- return createSchema(tables, keys, freezeRelations(added));
4109
- },
4110
- $select: (selection) => startRecordQuery(selection)
4111
- };
4112
- const contexts = createQueryContexts(Object.keys(tables), relations);
4113
- return defineEntries(methods, tables, (key) => startQuery(tables[key], contexts[key]));
4114
- }
4115
- function isSchema(part) {
4116
- return schemaBrand in part;
4117
- }
4118
- /** Adds a getter per table key to `methods` that starts a query with `start`, and freezes the result. */
4119
- function defineEntries(methods, tables, start) {
4120
- const result = Object.defineProperties(methods, Object.fromEntries(Object.keys(tables).map((key) => [key, {
4121
- get: () => start(key),
4122
- enumerable: true
4123
- }])));
4124
- return Object.freeze(result);
4125
- }
4126
453
  // src/execution/db.ts
4127
454
  /**
4128
455
  * Binds a schema to a database, placing its tables in a PostgreSQL schema.
4129
456
  *
4130
457
  * Schemas bound to the same database, such as tenant and SaaS schemas, share its connections and transactions.
458
+ * Given a function instead of a database, such as one that reads it from dependency injection, the `Db` calls it for each statement and at the start of each transaction, session, and lock, in the async context of the caller.
459
+ * The function must return the same database within a transaction or session; in the callback of a transaction or session of the `Db`, a statement for which it returns another database rejects.
4131
460
  */
4132
461
  function bindSchema(schema, database, options = {}) {
4133
462
  const tables = new Set(Object.values(schema.$tables));
@@ -4135,6 +464,7 @@ function bindSchema(schema, database, options = {}) {
4135
464
  const definitions = collectDefinitions(relations);
4136
465
  const { schemaName } = options;
4137
466
  const resolveSchemaName = () => typeof schemaName === "function" ? schemaName() : schemaName;
467
+ const { resolveDatabase, executor, track } = createDatabaseResolver(database);
4138
468
  function compile(query) {
4139
469
  if (query instanceof SqlQuery) throw new TypeError("A query of SQL text executes when it is awaited and compiles with its toSQL, not with $execute or $compile");
4140
470
  if (query.db !== void 0 && query.db !== db) throw new Error("Cannot run a query bound to another Db");
@@ -4146,7 +476,9 @@ function bindSchema(schema, database, options = {}) {
4146
476
  }
4147
477
  const methods = {
4148
478
  $schema: schema,
4149
- $database: database,
479
+ get $database() {
480
+ return resolveDatabase();
481
+ },
4150
482
  get $schemaName() {
4151
483
  return resolveSchemaName();
4152
484
  },
@@ -4156,33 +488,69 @@ function bindSchema(schema, database, options = {}) {
4156
488
  },
4157
489
  async $execute(query) {
4158
490
  const compiled = compile(query);
491
+ const database = resolveDatabase();
4159
492
  if (compiled.locksRows && !database.isInTransaction()) throw new Error("Cannot lock the rows of a query outside a transaction, where the locks would end with its statement; a test transaction alone does not count");
4160
493
  return decodeStatement(compiled, await database.execute(compiled));
4161
494
  },
4162
495
  $select: (selection) => startRecordQuery(selection, db),
4163
496
  $query(strings, ...values) {
4164
497
  const node = toRawSqlNode(strings, values);
4165
- return startSqlQuery(() => compileText(node), database);
498
+ return startSqlQuery(() => compileText(node), executor);
4166
499
  },
4167
500
  async $script(script, ...values) {
4168
- if (typeof script === "string") return database.script(script);
501
+ if (typeof script === "string") return resolveDatabase().script(script);
4169
502
  const { text, parameters } = compileText(toRawSqlNode(script, values));
4170
503
  if (parameters.length > 0) throw new Error("A script has no parameters, so it takes no values, also in the queries and sql fragments that it interpolates");
4171
- return database.script(text);
504
+ return resolveDatabase().script(text);
505
+ },
506
+ async $transaction(callback, options) {
507
+ const database = resolveDatabase();
508
+ return database.transaction(track(database, callback), options);
509
+ },
510
+ async $ensureTransaction(callback) {
511
+ const database = resolveDatabase();
512
+ return database.ensureTransaction(track(database, callback));
513
+ },
514
+ $isInTransaction: () => resolveDatabase().isInTransaction(),
515
+ $isInTransactionBlock: () => resolveDatabase().isInTransactionBlock(),
516
+ async $session(callback, options) {
517
+ const database = resolveDatabase();
518
+ return database.session(track(database, callback), options);
4172
519
  },
4173
- $transaction: (callback, options) => database.transaction(callback, options),
4174
- $ensureTransaction: (callback) => database.ensureTransaction(callback),
4175
- $isInTransaction: () => database.isInTransaction(),
4176
- $isInTransactionBlock: () => database.isInTransactionBlock(),
4177
- $session: (callback, options) => database.session(callback, options),
4178
- $lock: (key) => database.lock(key),
4179
- $tryLock: (key) => database.tryLock(key),
4180
- $pollLock: (key, options) => database.pollLock(key, options)
520
+ $lock: async (key) => resolveDatabase().lock(key),
521
+ $tryLock: async (key) => resolveDatabase().tryLock(key),
522
+ $pollLock: async (key, options) => resolveDatabase().pollLock(key, options)
4181
523
  };
4182
524
  const contexts = createQueryContexts(Object.keys(schema.$tables), relations);
4183
525
  const db = defineEntries(methods, schema.$tables, (key) => bindQuery(startQuery(schema.$tables[key], contexts[key]), db));
4184
526
  return db;
4185
527
  }
528
+ /**
529
+ * Creates the resolver of `database`, the database given to `bindSchema` or a function that returns it.
530
+ *
531
+ * Only the callbacks of the transactions and sessions of the `Db` are checked: a transaction of its database or of another `Db` is not known here, and checking it would require kern-db to expose the transactions of every database in the async context.
532
+ */
533
+ function createDatabaseResolver(database) {
534
+ if (typeof database !== "function") return {
535
+ resolveDatabase: () => database,
536
+ executor: database,
537
+ track: (_, callback) => callback
538
+ };
539
+ const getDatabase = database;
540
+ const started = new AsyncLocalStorage();
541
+ function resolveDatabase() {
542
+ const resolved = getDatabase();
543
+ if (!isDatabase(resolved)) throw new TypeError("The function passed to bindSchema must return a database");
544
+ const current = started.getStore();
545
+ if (current !== void 0 && current !== resolved) throw new Error("The function passed to bindSchema returned another database inside the callback of a transaction or session of the Db; it must return the same database there");
546
+ return resolved;
547
+ }
548
+ return {
549
+ resolveDatabase,
550
+ executor: { execute: (statement) => resolveDatabase().execute(statement) },
551
+ track: (resolved, callback) => started.getStore() === resolved ? callback : () => started.run(resolved, callback)
552
+ };
553
+ }
4186
554
  // src/table/snake-case.ts
4187
555
  const wordStart = /(?<=[\p{Ll}\p{N}])(?=\p{Lu})|(?<=\p{Lu})(?=\p{Lu}(?!s$)\p{Ll})/gu;
4188
556
  /**