pqb 0.61.13 → 0.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import url from 'url';
2
2
  import path from 'node:path';
3
- import { setTimeout } from 'timers/promises';
4
- import { addTopCteSql as addTopCteSql$1, addTopCte as addTopCte$1, pushQueryValueImmutable as pushQueryValueImmutable$1, prepareSubQueryForSql as prepareSubQueryForSql$3 } from 'pqb';
3
+ import { addTopCteSql as addTopCteSql$1, addTopCte as addTopCte$1, emptyArray as emptyArray$1, pushQueryValueImmutable as pushQueryValueImmutable$1, prepareSubQueryForSql as prepareSubQueryForSql$3, _clone as _clone$1 } from 'pqb/internal';
5
4
  import { inspect } from 'node:util';
6
5
  import { AsyncLocalStorage } from 'node:async_hooks';
6
+ import { setTimeout } from 'timers/promises';
7
7
 
8
8
  function applyMixins(targetClass, mixinClasses) {
9
9
  const target = targetClass.prototype;
@@ -155,7 +155,7 @@ const getCallerFilePath = (stack = getStackTrace()) => {
155
155
  } else {
156
156
  try {
157
157
  file = new URL(file).pathname;
158
- } catch (_) {
158
+ } catch {
159
159
  }
160
160
  }
161
161
  return file;
@@ -230,32 +230,7 @@ const colors = {
230
230
  pale: (s) => `\x1B[2m${s}\x1B[0m`
231
231
  };
232
232
 
233
- const setConnectRetryConfig = (adapter, config) => {
234
- adapter.connectRetryConfig = {
235
- attempts: config.attempts ?? 10,
236
- strategy: typeof config.strategy === "function" ? config.strategy : defaultConnectRetryStrategy(config.strategy ?? emptyObject)
237
- };
238
- };
239
- const wrapAdapterFnWithConnectRetry = (adapter, fn) => {
240
- return async function(...args) {
241
- let attempt = 1;
242
- for (; ; ) {
243
- try {
244
- return await fn.call(this, ...args);
245
- } catch (err) {
246
- const config = adapter.connectRetryConfig;
247
- if (!err || typeof err !== "object" || err.code !== "ECONNREFUSED" || !config || attempt >= config.attempts) {
248
- throw err;
249
- }
250
- await config.strategy(attempt, config.attempts);
251
- attempt++;
252
- }
253
- }
254
- };
255
- };
256
- const defaultConnectRetryStrategy = (param) => {
257
- return (attempt) => setTimeout((param.factor ?? 1.5) ** (attempt - 1) * (param.delay ?? 50));
258
- };
233
+ const snakeCaseKey = Symbol("snakeCase");
259
234
 
260
235
  class Expression {
261
236
  // Produce SQL string by calling `makeSQL` and applying operators from the `q.chain`, push query variables into given `values` array.
@@ -468,6 +443,108 @@ class UnsafeSqlExpression extends Expression {
468
443
  }
469
444
  }
470
445
 
446
+ const makeIndex = (columns, first, second) => {
447
+ if (typeof first === "string") {
448
+ const options = { ...second, name: first };
449
+ return {
450
+ index: { columns, options }
451
+ };
452
+ } else {
453
+ const options = first ?? {};
454
+ return {
455
+ index: { columns, options }
456
+ };
457
+ }
458
+ };
459
+ const tableDataMethods = {
460
+ primaryKey(columns, name) {
461
+ return { primaryKey: { columns, name } };
462
+ },
463
+ unique(columns, ...args) {
464
+ const [first, second] = args;
465
+ const input = makeIndex(columns, first, second);
466
+ input.index.options.unique = true;
467
+ return input;
468
+ },
469
+ index: makeIndex,
470
+ searchIndex(columns, ...args) {
471
+ var _a;
472
+ const [first, second] = args;
473
+ const input = makeIndex(columns, first, second);
474
+ (_a = input.index.options).using ?? (_a.using = "gin");
475
+ input.index.options.tsVector = true;
476
+ return input;
477
+ },
478
+ exclude(columns, ...args) {
479
+ const [first, second] = args;
480
+ if (typeof first === "string") {
481
+ const options = second ?? {};
482
+ return {
483
+ exclude: { columns, options: { ...options, name: first } }
484
+ };
485
+ } else {
486
+ const options = first ?? {};
487
+ return {
488
+ exclude: { columns, options }
489
+ };
490
+ }
491
+ },
492
+ foreignKey(columns, fnOrTable, foreignColumns, options) {
493
+ return {
494
+ constraint: {
495
+ name: options?.name,
496
+ references: { columns, fnOrTable, foreignColumns, options }
497
+ }
498
+ };
499
+ },
500
+ check(check, name) {
501
+ return { constraint: { check, name } };
502
+ },
503
+ sql: sqlFn
504
+ };
505
+ const parseTableData = (dataFn) => {
506
+ const tableData = {};
507
+ if (dataFn) {
508
+ const input = dataFn(tableDataMethods);
509
+ if (Array.isArray(input)) {
510
+ for (const item of input) {
511
+ parseTableDataInput(tableData, item);
512
+ }
513
+ } else {
514
+ parseTableDataInput(tableData, input);
515
+ }
516
+ }
517
+ return tableData;
518
+ };
519
+ const parseTableDataInput = (tableData, item) => {
520
+ if (item.primaryKey) {
521
+ tableData.primaryKey = item.primaryKey;
522
+ } else if (item.index) {
523
+ (tableData.indexes ?? (tableData.indexes = [])).push(
524
+ parseIndexOrExclude(item.index)
525
+ );
526
+ } else if (item.exclude) {
527
+ (tableData.excludes ?? (tableData.excludes = [])).push(
528
+ parseIndexOrExclude(item.exclude)
529
+ );
530
+ } else if (item.constraint) {
531
+ (tableData.constraints ?? (tableData.constraints = [])).push(item.constraint);
532
+ if (item.constraint.references?.options?.dropMode) {
533
+ item.constraint.dropMode = item.constraint.references.options.dropMode;
534
+ }
535
+ }
536
+ };
537
+ const parseIndexOrExclude = (item) => {
538
+ for (let i = item.columns.length - 1; i >= 0; i--) {
539
+ if (typeof item.columns[i] === "string") {
540
+ item.columns[i] = {
541
+ column: item.columns[i]
542
+ };
543
+ }
544
+ }
545
+ return item;
546
+ };
547
+
471
548
  function makeColumnNullable(column, inputSchema, outputSchema, querySchema) {
472
549
  const c = setColumnData(column, "isNullable", true);
473
550
  c.inputSchema = inputSchema;
@@ -512,9 +589,6 @@ const setDefaultNowFn = (sql) => {
512
589
  currentNowFn = sql;
513
590
  };
514
591
  const getDefaultNowFn = () => currentNowFn;
515
- const resetDefaultNowFn = () => {
516
- currentNowFn = defaultNowFn;
517
- };
518
592
  let defaultLanguage = "english";
519
593
  const setDefaultLanguage = (lang) => {
520
594
  defaultLanguage = lang || "english";
@@ -1463,7 +1537,6 @@ const excludeInnerToCode = (item, t) => {
1463
1537
  const excludeToCode = indexOrExcludeToCode(excludeInnerToCode);
1464
1538
  const constraintToCode = (item, t, m, prefix) => {
1465
1539
  const code = constraintInnerToCode(item, t, m);
1466
- if (prefix) code[0] = prefix + code[0];
1467
1540
  const last = code[code.length - 1];
1468
1541
  if (typeof last === "string" && !last.endsWith(","))
1469
1542
  code[code.length - 1] += ",";
@@ -1845,7 +1918,7 @@ const make = (_op) => {
1845
1918
  // function to turn the operator expression into SQL
1846
1919
  _op
1847
1920
  }
1848
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1921
+ //
1849
1922
  );
1850
1923
  };
1851
1924
  const makeVarArg = (_op) => {
@@ -1867,7 +1940,7 @@ const makeVarArg = (_op) => {
1867
1940
  // function to turn the operator expression into SQL
1868
1941
  _op
1869
1942
  }
1870
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1943
+ //
1871
1944
  );
1872
1945
  };
1873
1946
  const prepareOpArg = (q, arg) => {
@@ -3189,10 +3262,6 @@ const typmodType = (typmod) => {
3189
3262
  const typmodSrid = (typmod) => {
3190
3263
  return typmod < 0 ? 0 : (typmod & 268435200) - (typmod & 268435456) >> 8;
3191
3264
  };
3192
- const postgisTypmodToSql = (typmod) => {
3193
- const srid = typmodSrid(typmod);
3194
- return typmodType(typmod) + (srid === defaultSrid ? "" : ", " + srid);
3195
- };
3196
3265
  let byteToHex;
3197
3266
  function uint8ArrToHex(arr) {
3198
3267
  if (!byteToHex) {
@@ -3418,8 +3487,6 @@ const anyShape = new Proxy(emptyObject, {
3418
3487
  }
3419
3488
  });
3420
3489
 
3421
- const snakeCaseKey = Symbol("snakeCase");
3422
-
3423
3490
  const pushQueryValueImmutable = (q, key, value) => {
3424
3491
  pushOrNewArrayToObjectImmutable(
3425
3492
  q.q,
@@ -3446,447 +3513,354 @@ class QueryClone {
3446
3513
  }
3447
3514
  }
3448
3515
 
3449
- const getQueryAs = (q) => {
3450
- return q.q.as || q.table;
3451
- };
3452
- const requireQueryAs = (q) => {
3453
- const as = getQueryAs(q);
3454
- if (!as) throw new Error(`Table name or alias is missing`);
3455
- return as;
3516
+ const before = (q, key, cb) => pushQueryValueImmutable(q, `before${key}`, cb);
3517
+ const after = (query, key, select, cb, commit) => {
3518
+ const q = query;
3519
+ pushQueryValueImmutable(
3520
+ q,
3521
+ `after${key}${commit ? "Commit" : ""}`,
3522
+ cb
3523
+ );
3524
+ if (key === "Save") {
3525
+ addSelect(q, "Create", select);
3526
+ addSelect(q, "Update", select);
3527
+ } else {
3528
+ addSelect(q, key, select);
3529
+ }
3530
+ return query;
3456
3531
  };
3457
- const _getQueryAs = (q) => q.q.as;
3458
- const _getQueryFreeAlias = (q, as) => q.aliases ? getFreeAlias(q.aliases, as) : as;
3459
- const _checkIfAliased = (q, as, name) => {
3460
- return q.q.aliases?.[as] === name;
3532
+ const addSelect = (q, key, select) => {
3533
+ const prop = `after${key}Select`;
3534
+ const set = q.q[prop] = new Set(q.q[prop]);
3535
+ for (const column of select) {
3536
+ set.add(column);
3537
+ }
3461
3538
  };
3462
- const _getQueryAliasOrName = (q, as) => {
3463
- return q.aliases?.[as] || as;
3539
+ const _queryHookBeforeQuery = (q, cb) => {
3540
+ return pushQueryValueImmutable(q, "before", cb);
3464
3541
  };
3465
- const _getQueryOuterAliases = (q) => {
3466
- return q.outerAliases;
3542
+ const _queryHookAfterQuery = (q, cb) => {
3543
+ return pushQueryValueImmutable(q, "after", cb);
3467
3544
  };
3468
- const _setQueryAs = (self, as) => {
3469
- const { q } = self;
3470
- q.as = as;
3471
- q.aliases = {
3472
- ...q.aliases,
3473
- [as]: _getQueryFreeAlias(q, as)
3545
+ const _hookSelectColumns = (query, columns, asFn) => {
3546
+ const hookSelect = query.q.hookSelect = new Map(
3547
+ query.q.hookSelect && [...query.q.hookSelect]
3548
+ );
3549
+ const aliases = [];
3550
+ const addAlias = (as) => {
3551
+ aliases.push(as);
3552
+ if (aliases.length === columns.length) {
3553
+ asFn(aliases);
3554
+ }
3474
3555
  };
3475
- return self;
3476
- };
3477
- const _setQueryAlias = (q, name, as) => {
3478
- q.q.aliases = { ...q.q.aliases, [as]: name };
3479
- };
3480
- const _setSubQueryAliases = (q) => {
3481
- q.q.outerAliases = q.q.aliases;
3482
- };
3483
- const _applyRelationAliases = (query, relQueryData) => {
3484
- const aliases = query.q.as ? { ...query.q.aliases } : { ...query.q.aliases, [query.table]: query.table };
3485
- const relAliases = relQueryData.aliases;
3486
- for (const as in relAliases) {
3487
- aliases[as] = getFreeAlias(aliases, as);
3488
- }
3489
- relQueryData.as = aliases[relQueryData.as];
3490
- relQueryData.aliases = aliases;
3491
- };
3492
- const _copyQueryAliasToQuery = (fromQuery, toQuery, key) => {
3493
- const name = _getQueryAliasOrName(fromQuery.q, key);
3494
- if (name !== key) {
3495
- _setQueryAlias(toQuery, name, key);
3556
+ for (const column of columns) {
3557
+ const item = hookSelect.get(column);
3558
+ hookSelect.set(column, {
3559
+ ...item,
3560
+ select: column,
3561
+ onAs: [...item?.onAs || emptyArray, addAlias]
3562
+ });
3496
3563
  }
3497
- return name;
3498
3564
  };
3499
- class QueryAsMethods {
3500
- /**
3501
- * Sets table alias:
3502
- *
3503
- * ```ts
3504
- * db.table.as('u').select('u.name');
3505
- *
3506
- * // Can be used in the join:
3507
- * db.table.join(db.profile.as('p'), 'p.userId', 'user.id');
3508
- * ```
3509
- *
3510
- * @param as - alias for the table of this query
3511
- */
3512
- as(as) {
3513
- return _setQueryAs(_clone(this), as);
3565
+ class QueryHookUtils {
3566
+ constructor(query, columns, key) {
3567
+ this.query = query;
3568
+ this.columns = columns;
3569
+ this.key = key;
3570
+ this.set = (data) => {
3571
+ const set = {};
3572
+ for (const key in data) {
3573
+ if (data[key] !== void 0) {
3574
+ set[key] = data[key];
3575
+ }
3576
+ }
3577
+ pushQueryValueImmutable(this.query, this.key, set);
3578
+ };
3514
3579
  }
3515
3580
  }
3516
-
3517
- const queryColumnNameToKey = (q, name) => {
3518
- let map = q.internal.columnNameToKeyMap;
3519
- if (!map) {
3520
- q.internal.columnNameToKeyMap = map = /* @__PURE__ */ new Map();
3521
- const { shape } = q;
3522
- for (const key in q.shape) {
3523
- const column = shape[key];
3524
- map.set(column.data.name ?? key, key);
3581
+ const finalizeNestedHookSelect = (batches, returnType, tempColumns, renames, key) => {
3582
+ if (renames) {
3583
+ for (const { data } of batches) {
3584
+ for (const record of data) {
3585
+ if (record) {
3586
+ for (const a in renames) {
3587
+ record[a] = record[renames[a]];
3588
+ }
3589
+ }
3590
+ }
3525
3591
  }
3526
3592
  }
3527
- return map.get(name);
3528
- };
3529
-
3530
- var __typeError = (msg) => {
3531
- throw TypeError(msg);
3532
- };
3533
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
3534
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
3535
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
3536
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
3537
- var _query, _query2, _columnsCache;
3538
- class OrchidOrmError extends Error {
3539
- }
3540
- class NotFoundError extends OrchidOrmError {
3541
- constructor(query, message = "Record is not found") {
3542
- super(message);
3543
- // `#query` is private to prevent it from serializing to not cause problems to test runner reports
3544
- // it is exposed with `getQuery` method which prevents this problem from both Vitest and Jest.
3545
- // Exposing it with `get query()` still leaves the issue in Vitest.
3546
- __privateAdd(this, _query);
3547
- __privateSet(this, _query, query);
3548
- }
3549
- getQuery() {
3550
- return __privateGet(this, _query);
3551
- }
3552
- }
3553
- _query = new WeakMap();
3554
- class OrchidOrmInternalError extends Error {
3555
- constructor(query, message, data) {
3556
- super(message);
3557
- this.data = data;
3558
- // `#query` is private to prevent it from serializing to not cause problems to test runner reports
3559
- // it is exposed with `getQuery` method which prevents this problem from both Vitest and Jest.
3560
- // Exposing it with `get query()` still leaves the issue in Vitest.
3561
- __privateAdd(this, _query2);
3562
- __privateSet(this, _query2, query);
3563
- }
3564
- getQuery() {
3565
- return __privateGet(this, _query2);
3566
- }
3567
- }
3568
- _query2 = new WeakMap();
3569
- class QueryError extends OrchidOrmInternalError {
3570
- constructor() {
3571
- super(...arguments);
3572
- __privateAdd(this, _columnsCache);
3573
- }
3574
- get isUnique() {
3575
- return this.code === "23505";
3576
- }
3577
- get columns() {
3578
- if (__privateGet(this, _columnsCache)) return __privateGet(this, _columnsCache);
3579
- const columns = {};
3580
- if (this.detail) {
3581
- const list = this.detail.match(/\((.*)\)=/)?.[1];
3582
- if (list) {
3583
- list.split(", ").forEach((item) => {
3584
- const column = item.startsWith('"') ? item.slice(1, -1) : item;
3585
- const key = queryColumnNameToKey(this.getQuery(), column) ?? column;
3586
- columns[key] = true;
3587
- });
3593
+ if (tempColumns?.size) {
3594
+ for (const { data } of batches) {
3595
+ for (const record of data) {
3596
+ if (record) {
3597
+ for (const key2 of tempColumns) {
3598
+ delete record[key2];
3599
+ }
3600
+ }
3588
3601
  }
3589
3602
  }
3590
- return __privateSet(this, _columnsCache, columns);
3591
- }
3592
- }
3593
- _columnsCache = new WeakMap();
3594
- class MoreThanOneRowError extends OrchidOrmInternalError {
3595
- constructor(query, message) {
3596
- super(query, message);
3597
3603
  }
3598
- }
3599
- class UnhandledTypeError extends OrchidOrmInternalError {
3600
- constructor(query, value) {
3601
- super(query, `Unhandled type: ${JSON.stringify(value)} received`);
3604
+ if (returnType === "one" || returnType === "oneOrThrow") {
3605
+ for (const batch of batches) {
3606
+ batch.data = batch.data[0];
3607
+ }
3608
+ } else if (returnType === "pluck") {
3609
+ for (const { data } of batches) {
3610
+ for (let i = 0; i < data.length; i++) {
3611
+ data[i] = data[i][key];
3612
+ }
3613
+ }
3614
+ } else if (returnType === "value" || returnType === "valueOrThrow") {
3615
+ for (const item of batches) {
3616
+ item.parent[item.key] = item.data[0]?.[key];
3617
+ }
3602
3618
  }
3603
- }
3604
-
3605
- const pushQueryArrayImmutable = (q, key, value) => {
3606
- const arr = q.q[key];
3607
- q.q[key] = arr ? [...arr, ...value] : value;
3608
- return q;
3609
3619
  };
3610
- const setQueryObjectValueImmutable = (q, object, key, value) => {
3611
- q.q[object] = {
3612
- ...q.q[object],
3613
- [key]: value
3614
- };
3615
- return q;
3620
+ const _queryHookBeforeCreate = (q, cb) => {
3621
+ return before(
3622
+ q,
3623
+ "Create",
3624
+ (q2) => cb(new QueryHookUtils(q2, q2.q.columns, "hookCreateSet"))
3625
+ );
3616
3626
  };
3617
- const throwIfNoWhere = (q, method) => {
3618
- if (!q.q.or && !q.q.and && !q.q.scopes && !q.q.all) {
3619
- throw new OrchidOrmInternalError(
3620
- q,
3621
- `Dangerous ${method} without conditions`
3622
- );
3623
- }
3627
+ const _queryHookAfterCreate = (q, select, cb) => {
3628
+ return after(q, "Create", select, cb);
3624
3629
  };
3625
- const throwIfJoinLateral = (q, method) => {
3626
- if (q.q.join?.some((x) => Array.isArray(x) || "s" in x.args && x.args.s)) {
3627
- throw new OrchidOrmInternalError(
3628
- q,
3629
- `Cannot join a complex query in ${method}`
3630
- );
3631
- }
3630
+ const _queryHookAfterCreateCommit = (q, select, cb) => {
3631
+ return after(q, "Create", select, cb, true);
3632
3632
  };
3633
- const throwOnReadOnlyUpdate = (query, column, key) => {
3634
- if (column.data.appReadOnly || column.data.readOnly) {
3635
- throw new OrchidOrmInternalError(
3636
- query,
3637
- "Trying to update a readonly column",
3638
- { column: key }
3639
- );
3640
- }
3633
+ const _queryHookBeforeUpdate = (q, cb) => {
3634
+ return before(q, "Update", (q2) => {
3635
+ const columns = /* @__PURE__ */ new Set();
3636
+ if (q2.q.updateData) {
3637
+ for (const item of q2.q.updateData) {
3638
+ if (typeof item === "object") {
3639
+ for (const key in item) {
3640
+ columns.add(key);
3641
+ }
3642
+ }
3643
+ }
3644
+ }
3645
+ if (q2.q.updateMany) {
3646
+ for (const key of q2.q.updateMany.setColumns) {
3647
+ columns.add(key);
3648
+ }
3649
+ }
3650
+ return cb(new QueryHookUtils(q2, [...columns], "hookUpdateSet"));
3651
+ });
3641
3652
  };
3642
- const saveAliasedShape = (q, as, key) => {
3643
- const shapes = q.q[key];
3644
- as = getFreeAlias(shapes, as);
3645
- setQueryObjectValueImmutable(q, key, as, emptyObject);
3646
- return as;
3653
+ const _queryHookAfterUpdate = (q, select, cb) => {
3654
+ return after(q, "Update", select, cb);
3647
3655
  };
3648
- const extendQuery = (q, methods) => {
3649
- const base = Object.create(q.baseQuery);
3650
- base.baseQuery = base;
3651
- Object.assign(base, methods);
3652
- const cloned = Object.create(base);
3653
- cloned.q = getClonedQueryData(q.q);
3654
- return cloned;
3656
+ const _queryHookAfterUpdateCommit = (q, select, cb) => {
3657
+ return after(q, "Update", select, cb, true);
3655
3658
  };
3656
- const _queryAll = (q) => {
3657
- q.q.returnType = "all";
3658
- q.q.all = true;
3659
- return q;
3659
+ const _queryHookBeforeSave = (q, cb) => {
3660
+ return _queryHookBeforeUpdate(_queryHookBeforeCreate(q, cb), cb);
3660
3661
  };
3661
- const _queryTake = (query) => {
3662
- const q = query.q;
3663
- switch (q.returnType) {
3664
- case "valueOrThrow":
3665
- case "pluck":
3666
- case "void":
3667
- break;
3668
- case "value": {
3669
- q.returnType = "valueOrThrow";
3670
- break;
3671
- }
3672
- default: {
3673
- q.returnType = "oneOrThrow";
3674
- }
3675
- }
3676
- return query;
3662
+ const _queryHookAfterSave = (q, select, cb) => {
3663
+ return after(q, "Save", select, cb);
3677
3664
  };
3678
- const _queryTakeOptional = (query) => {
3679
- const q = query.q;
3680
- switch (q.returnType) {
3681
- case "value":
3682
- case "pluck":
3683
- case "void":
3684
- break;
3685
- case "valueOrThrow": {
3686
- q.returnType = "value";
3687
- break;
3688
- }
3689
- default: {
3690
- q.returnType = "one";
3691
- }
3692
- }
3693
- return query;
3665
+ const _queryAfterSaveCommit = (q, select, cb) => {
3666
+ return after(q, "Save", select, cb, true);
3694
3667
  };
3695
- const _queryExec = (q) => {
3696
- q.q.returnType = "void";
3697
- return q;
3668
+ const _queryHookBeforeDelete = (q, cb) => {
3669
+ return before(q, "Delete", cb);
3698
3670
  };
3699
- const _queryRows = (q) => {
3700
- q.q.returnType = "rows";
3701
- return q;
3671
+ const _queryHookAfterDelete = (q, select, cb) => {
3672
+ return after(q, "Delete", select, cb);
3702
3673
  };
3703
- const getFullColumnTable = (q, column, index, as) => {
3704
- const table = column.slice(0, index);
3705
- return as && table !== as && _checkIfAliased(q, table, as) ? as : table;
3674
+ const _queryHookAfterDeleteCommit = (q, select, cb) => {
3675
+ return after(q, "Delete", select, cb, true);
3706
3676
  };
3707
-
3708
- const prepareSubQueryForSql = (mainQuery, subQuery) => {
3709
- if (subQuery.dynamicBefore) {
3710
- pushQueryValueImmutable(mainQuery, "dynamicBefore", subQuery.q);
3711
- return subQuery;
3677
+ class QueryHooks {
3678
+ /**
3679
+ * Run the function before any kind of query.
3680
+ *
3681
+ * @param cb - function to call, first argument is a query object
3682
+ */
3683
+ beforeQuery(cb) {
3684
+ return _queryHookBeforeQuery(_clone(this), cb);
3712
3685
  }
3713
- let beforeAction = subQuery.q.type ? subQuery.q.type === "insert" ? subQuery.q.beforeCreate : subQuery.q.type === "update" ? subQuery.q.beforeUpdate : subQuery.q.type === "upsert" ? subQuery.q.upsertUpdate && subQuery.q.updateData ? subQuery.q.beforeUpdate && subQuery.q.beforeCreate ? [...subQuery.q.beforeUpdate, ...subQuery.q.beforeCreate] : subQuery.q.beforeUpdate || subQuery.q.beforeCreate : subQuery.q.beforeCreate : subQuery.q.type === "delete" ? subQuery.q.beforeDelete : void 0 : void 0;
3714
- const { beforeSet } = subQuery.q;
3715
- beforeAction = beforeAction && beforeSet ? [...beforeAction, ...beforeSet] : beforeSet ? [...beforeSet] : beforeAction;
3716
- if (beforeAction) {
3717
- const newSet = new Set(mainQuery.q.beforeSet);
3718
- const filteredHooks = [];
3719
- for (const hook of beforeAction) {
3720
- if (!newSet.has(hook)) {
3721
- newSet.add(hook);
3722
- filteredHooks.push(hook);
3723
- }
3724
- }
3725
- mainQuery.q.beforeSet = newSet;
3726
- beforeAction = filteredHooks;
3727
- if (beforeAction.length) {
3728
- pushQueryArrayImmutable(
3729
- mainQuery,
3730
- "before",
3731
- beforeAction.map((fn) => () => fn(subQuery))
3732
- );
3733
- }
3734
- }
3735
- return subQuery;
3736
- };
3737
- setPrepareSubQueryForSql(prepareSubQueryForSql);
3738
- setRawSqlPrepareSubQueryForSql(prepareSubQueryForSql);
3739
-
3740
- const _queryUnion = (base, args, k, p, m) => {
3741
- const query = base.baseQuery.clone();
3742
- const u = args.map(
3743
- (a) => ({
3744
- a: prepareSubQueryForSql(
3745
- base,
3746
- typeof a === "function" ? a(query) : a
3747
- ),
3748
- k,
3749
- m
3750
- })
3751
- );
3752
- const { q } = query;
3753
- const baseQ = base.q;
3754
- q.union = baseQ.union ? {
3755
- ...baseQ.union,
3756
- u: [...baseQ.union.u, ...u]
3757
- } : {
3758
- b: base,
3759
- u,
3760
- p
3761
- };
3762
- return query;
3763
- };
3764
- class Union {
3765
3686
  /**
3766
- * Creates a union query, takes one or more queries or SQL expressions.
3767
- *
3768
- * ```ts
3769
- * import { sql } from './baseTable';
3770
- *
3771
- * // The first query of the union
3772
- * db.one
3773
- * .select('id', 'name')
3774
- * // add two more queries to the union
3775
- * .union(
3776
- * db.two.select('id', 'name'),
3777
- * (q = sql`SELECT id, name FROM "thirdTable"`),
3778
- * )
3779
- * // sub-sequent `union` is equivalent to passing multiple queries into a single `union`
3780
- * .union(db.three.select('id', 'name'));
3781
- * ```
3687
+ * Run the function after any kind of query.
3688
+ * Enforces wrapping the query into a transaction.
3689
+ * The function will run after the query is succeeded, but before the transaction commit.
3782
3690
  *
3783
- * `order`, `limit`, `offset` are special, it matters if you place them **before** or **after** the `union`, it also have a meaning to place them before and after.
3691
+ * @param cb - function to call, first argument is the query result of type `unknown`, second argument is a query object
3692
+ */
3693
+ afterQuery(cb) {
3694
+ return _queryHookAfterQuery(_clone(this), cb);
3695
+ }
3696
+ /**
3697
+ * Run the function before a `create` kind of query.
3784
3698
  *
3785
- * ```ts
3786
- * // order, limit, offset are applied ONLY to 'one'
3787
- * db.one
3788
- * .order('x')
3789
- * .limit(1)
3790
- * .offset(1)
3791
- * // 'two' also has order, limit, and offset
3792
- * .unionAll(db.two.order('y').limit(2).offset(2))
3793
- * // sets order, limit, offset for all records
3794
- * .order('z')
3795
- * .limit(3)
3796
- * .offset(3);
3797
- * ```
3699
+ * @param cb - function to call, first argument is a query object
3700
+ */
3701
+ beforeCreate(cb) {
3702
+ return _queryHookBeforeCreate(_clone(this), cb);
3703
+ }
3704
+ /**
3705
+ * Run the function after a `create` kind of query.
3706
+ * Enforces wrapping the query into a transaction.
3707
+ * The function will run after the query is succeeded, but before the transaction commit.
3708
+ * Queries inside the function will run in the same transaction as the target query.
3798
3709
  *
3799
- * Equivalent SQL:
3710
+ * @param select - list of columns to select for the hook
3711
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3712
+ */
3713
+ afterCreate(select, cb) {
3714
+ return _queryHookAfterCreate(_clone(this), select, cb);
3715
+ }
3716
+ /**
3717
+ * Run the function after transaction for a `create` kind of query will be committed.
3718
+ * If the query wasn't wrapped in a transaction, will run after the query.
3800
3719
  *
3801
- * ```sql
3802
- * -- both union parts have their own order, limit, offset
3803
- * ( SELECT * FROM one ORDER x ASC LIMIT 1 OFFSET 1 )
3804
- * UNION ALL
3805
- * ( SELECT * FROM two ORDER y ASC LIMIT 2 OFFSET 2 )
3806
- * -- order, limit, offset of the whole query
3807
- * ORDER BY z ASC LIMIT 3 OFFSET 3
3808
- * ```
3720
+ * @param select - list of columns to select for the hook
3721
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3722
+ */
3723
+ afterCreateCommit(select, cb) {
3724
+ return _queryHookAfterCreateCommit(
3725
+ _clone(this),
3726
+ select,
3727
+ cb
3728
+ );
3729
+ }
3730
+ /**
3731
+ * Run the function before an `update` kind of query.
3809
3732
  *
3810
- * All the listed methods have the same signature, they are only different by SQL keyword:
3733
+ * @param cb - function to call, first argument is a query object
3734
+ */
3735
+ beforeUpdate(cb) {
3736
+ return _queryHookBeforeUpdate(_clone(this), cb);
3737
+ }
3738
+ /**
3739
+ * Run the function after an `update` kind of query.
3740
+ * Enforces wrapping the query into a transaction.
3741
+ * The function will run after the query is succeeded, but before the transaction commit.
3742
+ * Queries inside the function will run in the same transaction as the target query.
3743
+ * If no records were updated, the hook *won't* run.
3811
3744
  *
3812
- * - `union` - union of all queries, performs deduplication
3813
- * - `unionAll` - `union` that allows duplicated rows
3814
- * - `intersect` - get only rows that are present in all queries
3815
- * - `intersectAll` - `intersect` that allows duplicated rows
3816
- * - `except` - get only rows that are in the first query but not in the second
3817
- * - `exceptAll` - `except` that allows duplicated rows
3745
+ * @param select - list of columns to select for the hook
3746
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3747
+ */
3748
+ afterUpdate(select, cb) {
3749
+ return _queryHookAfterUpdate(_clone(this), select, cb);
3750
+ }
3751
+ /**
3752
+ * Run the function after transaction for an `update` kind of query will be committed.
3753
+ * If the query wasn't wrapped in a transaction, will run after the query.
3754
+ * If no records were updated, the hook *won't* run.
3818
3755
  *
3819
- * @param args - array of queries or SQL expressions
3756
+ * @param select - list of columns to select for the hook
3757
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3820
3758
  */
3821
- union(...args) {
3822
- return _queryUnion(
3759
+ afterUpdateCommit(select, cb) {
3760
+ return _queryHookAfterUpdateCommit(
3823
3761
  _clone(this),
3824
- args,
3825
- "UNION"
3762
+ select,
3763
+ cb
3826
3764
  );
3827
3765
  }
3828
3766
  /**
3829
- * Same as {@link union}, but allows duplicated rows.
3767
+ * Run the function before a `create` or an `update` kind of query.
3830
3768
  *
3831
- * @param args - array of queries or SQL expressions
3769
+ * @param cb - function to call, first argument is a query object
3832
3770
  */
3833
- unionAll(...args) {
3834
- return _queryUnion(
3835
- _clone(this),
3836
- args,
3837
- "UNION ALL"
3838
- );
3771
+ beforeSave(cb) {
3772
+ return _queryHookBeforeSave(_clone(this), cb);
3839
3773
  }
3840
3774
  /**
3841
- * Same as {@link union}, but uses a `INTERSECT` SQL keyword instead
3775
+ * Run the function after a `create` or an `update` kind of query.
3776
+ * Enforces wrapping the query into a transaction.
3777
+ * The function will run after the query is succeeded, but before the transaction commit.
3778
+ * Queries inside the function will run in the same transaction as the target query.
3779
+ * For the `update` query, if no records were updated, the hook *won't* run.
3842
3780
  *
3843
- * @param args - array of queries or SQL expressions
3781
+ * @param select - list of columns to select for the hook
3782
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3844
3783
  */
3845
- intersect(...args) {
3846
- return _queryUnion(
3847
- _clone(this),
3848
- args,
3849
- "INTERSECT"
3850
- );
3784
+ afterSave(select, cb) {
3785
+ return _queryHookAfterSave(_clone(this), select, cb);
3851
3786
  }
3852
3787
  /**
3853
- * Same as {@link intersect}, but allows duplicated rows.
3788
+ * Run the function after transaction for a `create` or an `update` kind of query will be committed.
3789
+ * If the query wasn't wrapped in a transaction, will run after the query.
3790
+ * For the `update` query, if no records were updated, the hook *won't* run.
3854
3791
  *
3855
- * @param args - array of queries or SQL expressions
3792
+ * @param select - list of columns to select for the hook
3793
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3856
3794
  */
3857
- intersectAll(...args) {
3858
- return _queryUnion(
3859
- _clone(this),
3860
- args,
3861
- "INTERSECT ALL"
3862
- );
3795
+ afterSaveCommit(select, cb) {
3796
+ return _queryAfterSaveCommit(_clone(this), select, cb);
3863
3797
  }
3864
3798
  /**
3865
- * Same as {@link union}, but uses an `EXCEPT` SQL keyword instead
3799
+ * Run the function before a `delete` kind of query.
3866
3800
  *
3867
- * @param args - array of queries or SQL expressions
3801
+ * @param cb - function to call, first argument is a query object
3868
3802
  */
3869
- except(...args) {
3870
- return _queryUnion(
3871
- _clone(this),
3872
- args,
3873
- "EXCEPT"
3874
- );
3803
+ beforeDelete(cb) {
3804
+ return _queryHookBeforeDelete(_clone(this), cb);
3875
3805
  }
3876
3806
  /**
3877
- * Same as {@link except}, but allows duplicated rows.
3807
+ * Run the function after a `delete` kind of query.
3808
+ * Enforces wrapping the query into a transaction.
3809
+ * The function will run after the query is succeeded, but before the transaction commit.
3810
+ * Queries inside the function will run in the same transaction as the target query.
3811
+ * If no records were deleted, the hook *won't* run.
3878
3812
  *
3879
- * @param args - array of queries or SQL expressions
3813
+ * @param select - list of columns to select for the hook
3814
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3880
3815
  */
3881
- exceptAll(...args) {
3882
- return _queryUnion(
3816
+ afterDelete(select, cb) {
3817
+ return _queryHookAfterDelete(_clone(this), select, cb);
3818
+ }
3819
+ /**
3820
+ * Run the function after transaction for a `delete` kind of query will be committed.
3821
+ * If the query wasn't wrapped in a transaction, will run after the query.
3822
+ * If no records were deleted, the hook *won't* run.
3823
+ *
3824
+ * @param select - list of columns to select for the hook
3825
+ * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
3826
+ */
3827
+ afterDeleteCommit(select, cb) {
3828
+ return _queryHookAfterDeleteCommit(
3883
3829
  _clone(this),
3884
- args,
3885
- "EXCEPT ALL"
3830
+ select,
3831
+ cb
3886
3832
  );
3887
3833
  }
3888
- }
3889
-
3834
+ /**
3835
+ * Add `catchAfterCommitError` to the query to catch possible errors that are coming from after commit hooks.
3836
+ *
3837
+ * When it is used, the transaction will return its result disregarding of a failed hook.
3838
+ *
3839
+ * Without `catchAfterCommitError`, the transaction function throws and won't return result.
3840
+ * Result is still accessible from the error object [AfterCommitError](#AfterCommitError).
3841
+ *
3842
+ * ```ts
3843
+ * const result = await db
3844
+ * .$transaction(async () => {
3845
+ * return db.table.create(data);
3846
+ * })
3847
+ * .catchAfterCommitError((err) => {
3848
+ * // err is instance of AfterCommitError (see below)
3849
+ * })
3850
+ * // can be added multiple times, all catchers will be executed
3851
+ * .catchAfterCommitError((err) => {});
3852
+ *
3853
+ * // result is available even if an after commit hook has failed
3854
+ * result.id;
3855
+ * ```
3856
+ */
3857
+ catchAfterCommitError(fn) {
3858
+ const q = _clone(this);
3859
+ pushQueryValueImmutable(q, "catchAfterCommitErrors", fn);
3860
+ return q;
3861
+ }
3862
+ }
3863
+
3890
3864
  const setParserToQuery = (query, key, parser) => {
3891
3865
  if (parser) {
3892
3866
  if (query.parsers) query.parsers[key] = parser;
@@ -3912,6 +3886,94 @@ const getQueryParsers = (q, hookSelect) => {
3912
3886
  return q.q.select ? q.q.parsers : q.q.defaultParsers;
3913
3887
  };
3914
3888
 
3889
+ const queryColumnNameToKey = (q, name) => {
3890
+ let map = q.internal.columnNameToKeyMap;
3891
+ if (!map) {
3892
+ q.internal.columnNameToKeyMap = map = /* @__PURE__ */ new Map();
3893
+ const { shape } = q;
3894
+ for (const key in q.shape) {
3895
+ const column = shape[key];
3896
+ map.set(column.data.name ?? key, key);
3897
+ }
3898
+ }
3899
+ return map.get(name);
3900
+ };
3901
+
3902
+ var __typeError = (msg) => {
3903
+ throw TypeError(msg);
3904
+ };
3905
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
3906
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
3907
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
3908
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
3909
+ var _query, _query2, _columnsCache;
3910
+ class OrchidOrmError extends Error {
3911
+ }
3912
+ class NotFoundError extends OrchidOrmError {
3913
+ constructor(query, message = "Record is not found") {
3914
+ super(message);
3915
+ // `#query` is private to prevent it from serializing to not cause problems to test runner reports
3916
+ // it is exposed with `getQuery` method which prevents this problem from both Vitest and Jest.
3917
+ // Exposing it with `get query()` still leaves the issue in Vitest.
3918
+ __privateAdd(this, _query);
3919
+ __privateSet(this, _query, query);
3920
+ }
3921
+ getQuery() {
3922
+ return __privateGet(this, _query);
3923
+ }
3924
+ }
3925
+ _query = new WeakMap();
3926
+ class OrchidOrmInternalError extends Error {
3927
+ constructor(query, message, data) {
3928
+ super(message);
3929
+ this.data = data;
3930
+ // `#query` is private to prevent it from serializing to not cause problems to test runner reports
3931
+ // it is exposed with `getQuery` method which prevents this problem from both Vitest and Jest.
3932
+ // Exposing it with `get query()` still leaves the issue in Vitest.
3933
+ __privateAdd(this, _query2);
3934
+ __privateSet(this, _query2, query);
3935
+ }
3936
+ getQuery() {
3937
+ return __privateGet(this, _query2);
3938
+ }
3939
+ }
3940
+ _query2 = new WeakMap();
3941
+ class QueryError extends OrchidOrmInternalError {
3942
+ constructor() {
3943
+ super(...arguments);
3944
+ __privateAdd(this, _columnsCache);
3945
+ }
3946
+ get isUnique() {
3947
+ return this.code === "23505";
3948
+ }
3949
+ get columns() {
3950
+ if (__privateGet(this, _columnsCache)) return __privateGet(this, _columnsCache);
3951
+ const columns = {};
3952
+ if (this.detail) {
3953
+ const list = this.detail.match(/\((.*)\)=/)?.[1];
3954
+ if (list) {
3955
+ list.split(", ").forEach((item) => {
3956
+ const column = item.startsWith('"') ? item.slice(1, -1) : item;
3957
+ const key = queryColumnNameToKey(this.getQuery(), column) ?? column;
3958
+ columns[key] = true;
3959
+ });
3960
+ }
3961
+ }
3962
+ return __privateSet(this, _columnsCache, columns);
3963
+ }
3964
+ }
3965
+ _columnsCache = new WeakMap();
3966
+ class MoreThanOneRowError extends OrchidOrmInternalError {
3967
+ constructor(query, message) {
3968
+ super(query, message);
3969
+ }
3970
+ }
3971
+ class UnhandledTypeError extends OrchidOrmInternalError {
3972
+ constructor(query, value) {
3973
+ super(query, `Unhandled type: ${JSON.stringify(value)} received`);
3974
+ }
3975
+ }
3976
+
3915
3977
  const escape = (value, migration, nested) => {
3916
3978
  const type = typeof value;
3917
3979
  if (type === "number" || type === "bigint") return String(value);
@@ -4163,525 +4225,177 @@ class QueryTransaction {
4163
4225
  } finally {
4164
4226
  state.transactionId = transactionId - 1;
4165
4227
  }
4166
- }
4167
- }
4168
- /**
4169
- * Use the `$ensureTransaction` when you want to ensure the sequence of queries is running in a transaction, but there is no need for Postgres [savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html).
4170
- *
4171
- * ```ts
4172
- * async function updateUserBalance(userId: string, amount: number) {
4173
- * await db.$ensureTransaction(async () => {
4174
- * await db.transfer.create({ userId, amount })
4175
- * await db.user.find(userId).increment({ balance: amount })
4176
- * })
4177
- * }
4178
- *
4179
- * async function saveDeposit(userId: string, deposit: { ... }) {
4180
- * await db.$ensureTransaction(async () => {
4181
- * await db.deposit.create(deposit)
4182
- * // transaction in updateUserBalance won't be started
4183
- * await updateUserBalance(userId, deposit.amount)
4184
- * })
4185
- * }
4186
- * ```
4187
- */
4188
- ensureTransaction(cb) {
4189
- const trx = this.internal.asyncStorage.getStore();
4190
- if (trx) return cb();
4191
- return QueryTransaction.prototype.transaction.call(this, cb);
4192
- }
4193
- isInTransaction() {
4194
- const trx = this.internal.asyncStorage.getStore();
4195
- return isInUserTransaction(trx);
4196
- }
4197
- /**
4198
- * Schedules a hook to run after the outermost transaction commits:
4199
- *
4200
- * ```ts
4201
- * await db.$transaction(async () => {
4202
- * await db.table.create(data)
4203
- * await db.table.where({ ...conditions }).update({ key: 'value' })
4204
- *
4205
- * db.$afterCommit(() => { // can be sync or async
4206
- * console.log('after commit')
4207
- * })
4208
- * })
4209
- * ```
4210
- *
4211
- * If used outside the transaction, the hook will be executed almost immediately, on the next microtask:
4212
- *
4213
- * ```ts
4214
- * db.$afterCommit(async () => { // can be sync or async
4215
- * console.log('after commit')
4216
- * })
4217
- * ```
4218
- *
4219
- * If the callback has no `try/catch` and throws an error,
4220
- * this will cause `uncaughtException` if the callback is sync and `unhandledRejection` if it is async.
4221
- */
4222
- afterCommit(hook) {
4223
- const trx = this.internal.asyncStorage.getStore();
4224
- if (isInUserTransaction(trx)) {
4225
- (trx.afterCommit ?? (trx.afterCommit = [])).push(hook);
4226
- } else {
4227
- queueMicrotask(hook);
4228
- }
4229
- }
4230
- /**
4231
- * Whenever a query in a transaction fails, the transaction is transitioned to a failed state, no further queries are possible.
4232
- *
4233
- * Use [catchUniqueError](/guide/error-handling.html#catchuniqueerror) to handle uniqueness errors,
4234
- * the following examples do not use it to illustrate error handling.
4235
- *
4236
- * ```ts
4237
- * // This transaction is going to fail
4238
- * db.$transaction(async () => {
4239
- * try {
4240
- * // imagine it fails because the username is already taken
4241
- * await db.user.insert({ username: 'taken' });
4242
- * } catch (err) {
4243
- * // even though the query is wrapped in a try-catch, the transaction fails anyway
4244
- * }
4245
- * });
4246
- * ```
4247
- *
4248
- * You can use `catch` method on a query instead of `try-catch` to surpass the problem.
4249
- * The following transaction won't fail:
4250
- *
4251
- * ```ts
4252
- * // Transaction succeeds
4253
- * db.$transaction(async () => {
4254
- * const result = await db.user.insert({ username: 'taken' }).catch(() => 'failed');
4255
- *
4256
- * if (result === 'failed') {
4257
- * await db.user.insert({ username: 'another' });
4258
- * }
4259
- * });
4260
- * ```
4261
- *
4262
- * This is because when using `catch` method, `OrchidORM` will wrap the query with a savepoint.
4263
- *
4264
- * Alternatively, you can use the `recoverable()` method:
4265
- *
4266
- * ```ts
4267
- * // Transaction succeeds
4268
- * db.$transaction(async () => {
4269
- * try {
4270
- * await db.user.insert({ username: 'taken' }).recoverable();
4271
- * } catch (err) {
4272
- * await db.user.insert({ username: 'another' });
4273
- * }
4274
- * });
4275
- * ```
4276
- */
4277
- recoverable() {
4278
- const q = _clone(this);
4279
- q.q.catch = true;
4280
- return q;
4281
- }
4282
- }
4283
- const runAfterCommit = (afterCommit, result) => {
4284
- queueMicrotask(async () => {
4285
- if (afterCommit) {
4286
- const promises = [];
4287
- let catchAfterCommitErrors;
4288
- for (let i = 0, len = afterCommit.length; i < len; ) {
4289
- const first = afterCommit[i];
4290
- if (typeof first === "function") {
4291
- try {
4292
- promises.push(first());
4293
- } catch (err) {
4294
- promises.push(Promise.reject(err));
4295
- }
4296
- i++;
4297
- } else {
4298
- const q = afterCommit[i + 1];
4299
- if (q.q.catchAfterCommitErrors) {
4300
- (catchAfterCommitErrors ?? (catchAfterCommitErrors = [])).push(...q.q.catchAfterCommitErrors);
4301
- }
4302
- for (const fn of afterCommit[i + 2]) {
4303
- try {
4304
- promises.push(fn(first, q));
4305
- } catch (err) {
4306
- promises.push(Promise.reject(err));
4307
- }
4308
- }
4309
- i += 3;
4310
- }
4311
- }
4312
- const getHookNames = () => {
4313
- const hookNames = [];
4314
- for (let i = 0, len = afterCommit.length; i < len; ) {
4315
- const first = afterCommit[i];
4316
- if (typeof first === "function") {
4317
- hookNames.push(first.name);
4318
- i++;
4319
- } else {
4320
- for (const fn of afterCommit[i + 2]) {
4321
- hookNames.push(fn.name);
4322
- }
4323
- i += 3;
4324
- }
4325
- }
4326
- return hookNames;
4327
- };
4328
- await _runAfterCommitHooks(
4329
- result,
4330
- promises,
4331
- getHookNames,
4332
- catchAfterCommitErrors
4333
- );
4334
- }
4335
- });
4336
- };
4337
-
4338
- const before = (q, key, cb) => pushQueryValueImmutable(q, `before${key}`, cb);
4339
- const after = (query, key, select, cb, commit) => {
4340
- const q = query;
4341
- pushQueryValueImmutable(
4342
- q,
4343
- `after${key}${commit ? "Commit" : ""}`,
4344
- cb
4345
- );
4346
- if (key === "Save") {
4347
- addSelect(q, "Create", select);
4348
- addSelect(q, "Update", select);
4349
- } else {
4350
- addSelect(q, key, select);
4351
- }
4352
- return query;
4353
- };
4354
- const addSelect = (q, key, select) => {
4355
- const prop = `after${key}Select`;
4356
- const set = q.q[prop] = new Set(q.q[prop]);
4357
- for (const column of select) {
4358
- set.add(column);
4359
- }
4360
- };
4361
- const _queryHookBeforeQuery = (q, cb) => {
4362
- return pushQueryValueImmutable(q, "before", cb);
4363
- };
4364
- const _queryHookAfterQuery = (q, cb) => {
4365
- return pushQueryValueImmutable(q, "after", cb);
4366
- };
4367
- const _hookSelectColumns = (query, columns, asFn) => {
4368
- const hookSelect = query.q.hookSelect = new Map(
4369
- query.q.hookSelect && [...query.q.hookSelect]
4370
- );
4371
- const aliases = [];
4372
- const addAlias = (as) => {
4373
- aliases.push(as);
4374
- if (aliases.length === columns.length) {
4375
- asFn(aliases);
4376
- }
4377
- };
4378
- for (const column of columns) {
4379
- const item = hookSelect.get(column);
4380
- hookSelect.set(column, {
4381
- ...item,
4382
- select: column,
4383
- onAs: [...item?.onAs || emptyArray, addAlias]
4384
- });
4385
- }
4386
- };
4387
- class QueryHookUtils {
4388
- constructor(query, columns, key) {
4389
- this.query = query;
4390
- this.columns = columns;
4391
- this.key = key;
4392
- this.set = (data) => {
4393
- const set = {};
4394
- for (const key in data) {
4395
- if (data[key] !== void 0) {
4396
- set[key] = data[key];
4397
- }
4398
- }
4399
- pushQueryValueImmutable(this.query, this.key, set);
4400
- };
4401
- }
4402
- }
4403
- const finalizeNestedHookSelect = (batches, returnType, tempColumns, renames, key) => {
4404
- if (renames) {
4405
- for (const { data } of batches) {
4406
- for (const record of data) {
4407
- if (record) {
4408
- for (const a in renames) {
4409
- record[a] = record[renames[a]];
4410
- }
4411
- }
4412
- }
4413
- }
4414
- }
4415
- if (tempColumns?.size) {
4416
- for (const { data } of batches) {
4417
- for (const record of data) {
4418
- if (record) {
4419
- for (const key2 of tempColumns) {
4420
- delete record[key2];
4421
- }
4422
- }
4423
- }
4424
- }
4425
- }
4426
- if (returnType === "one" || returnType === "oneOrThrow") {
4427
- for (const batch of batches) {
4428
- batch.data = batch.data[0];
4429
- }
4430
- } else if (returnType === "pluck") {
4431
- for (const { data } of batches) {
4432
- for (let i = 0; i < data.length; i++) {
4433
- data[i] = data[i][key];
4434
- }
4435
- }
4436
- } else if (returnType === "value" || returnType === "valueOrThrow") {
4437
- for (const item of batches) {
4438
- item.parent[item.key] = item.data[0]?.[key];
4439
- }
4440
- }
4441
- };
4442
- const _queryHookBeforeCreate = (q, cb) => {
4443
- return before(
4444
- q,
4445
- "Create",
4446
- (q2) => cb(new QueryHookUtils(q2, q2.q.columns, "hookCreateSet"))
4447
- );
4448
- };
4449
- const _queryHookAfterCreate = (q, select, cb) => {
4450
- return after(q, "Create", select, cb);
4451
- };
4452
- const _queryHookAfterCreateCommit = (q, select, cb) => {
4453
- return after(q, "Create", select, cb, true);
4454
- };
4455
- const _queryHookBeforeUpdate = (q, cb) => {
4456
- return before(q, "Update", (q2) => {
4457
- const columns = /* @__PURE__ */ new Set();
4458
- if (q2.q.updateData) {
4459
- for (const item of q2.q.updateData) {
4460
- if (typeof item === "object") {
4461
- for (const key in item) {
4462
- columns.add(key);
4463
- }
4464
- }
4465
- }
4466
- }
4467
- if (q2.q.updateMany) {
4468
- for (const key of q2.q.updateMany.setColumns) {
4469
- columns.add(key);
4470
- }
4471
- }
4472
- return cb(new QueryHookUtils(q2, [...columns], "hookUpdateSet"));
4473
- });
4474
- };
4475
- const _queryHookAfterUpdate = (q, select, cb) => {
4476
- return after(q, "Update", select, cb);
4477
- };
4478
- const _queryHookAfterUpdateCommit = (q, select, cb) => {
4479
- return after(q, "Update", select, cb, true);
4480
- };
4481
- const _queryHookBeforeSave = (q, cb) => {
4482
- return _queryHookBeforeUpdate(_queryHookBeforeCreate(q, cb), cb);
4483
- };
4484
- const _queryHookAfterSave = (q, select, cb) => {
4485
- return after(q, "Save", select, cb);
4486
- };
4487
- const _queryAfterSaveCommit = (q, select, cb) => {
4488
- return after(q, "Save", select, cb, true);
4489
- };
4490
- const _queryHookBeforeDelete = (q, cb) => {
4491
- return before(q, "Delete", cb);
4492
- };
4493
- const _queryHookAfterDelete = (q, select, cb) => {
4494
- return after(q, "Delete", select, cb);
4495
- };
4496
- const _queryHookAfterDeleteCommit = (q, select, cb) => {
4497
- return after(q, "Delete", select, cb, true);
4498
- };
4499
- class QueryHooks {
4500
- /**
4501
- * Run the function before any kind of query.
4502
- *
4503
- * @param cb - function to call, first argument is a query object
4504
- */
4505
- beforeQuery(cb) {
4506
- return _queryHookBeforeQuery(_clone(this), cb);
4507
- }
4508
- /**
4509
- * Run the function after any kind of query.
4510
- * Enforces wrapping the query into a transaction.
4511
- * The function will run after the query is succeeded, but before the transaction commit.
4512
- *
4513
- * @param cb - function to call, first argument is the query result of type `unknown`, second argument is a query object
4514
- */
4515
- afterQuery(cb) {
4516
- return _queryHookAfterQuery(_clone(this), cb);
4517
- }
4518
- /**
4519
- * Run the function before a `create` kind of query.
4520
- *
4521
- * @param cb - function to call, first argument is a query object
4522
- */
4523
- beforeCreate(cb) {
4524
- return _queryHookBeforeCreate(_clone(this), cb);
4228
+ }
4525
4229
  }
4526
4230
  /**
4527
- * Run the function after a `create` kind of query.
4528
- * Enforces wrapping the query into a transaction.
4529
- * The function will run after the query is succeeded, but before the transaction commit.
4530
- * Queries inside the function will run in the same transaction as the target query.
4231
+ * Use the `$ensureTransaction` when you want to ensure the sequence of queries is running in a transaction, but there is no need for Postgres [savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html).
4531
4232
  *
4532
- * @param select - list of columns to select for the hook
4533
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4534
- */
4535
- afterCreate(select, cb) {
4536
- return _queryHookAfterCreate(_clone(this), select, cb);
4537
- }
4538
- /**
4539
- * Run the function after transaction for a `create` kind of query will be committed.
4540
- * If the query wasn't wrapped in a transaction, will run after the query.
4233
+ * ```ts
4234
+ * async function updateUserBalance(userId: string, amount: number) {
4235
+ * await db.$ensureTransaction(async () => {
4236
+ * await db.transfer.create({ userId, amount })
4237
+ * await db.user.find(userId).increment({ balance: amount })
4238
+ * })
4239
+ * }
4541
4240
  *
4542
- * @param select - list of columns to select for the hook
4543
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4241
+ * async function saveDeposit(userId: string, deposit: { ... }) {
4242
+ * await db.$ensureTransaction(async () => {
4243
+ * await db.deposit.create(deposit)
4244
+ * // transaction in updateUserBalance won't be started
4245
+ * await updateUserBalance(userId, deposit.amount)
4246
+ * })
4247
+ * }
4248
+ * ```
4544
4249
  */
4545
- afterCreateCommit(select, cb) {
4546
- return _queryHookAfterCreateCommit(
4547
- _clone(this),
4548
- select,
4549
- cb
4550
- );
4250
+ ensureTransaction(cb) {
4251
+ const trx = this.internal.asyncStorage.getStore();
4252
+ if (trx) return cb();
4253
+ return QueryTransaction.prototype.transaction.call(this, cb);
4551
4254
  }
4552
- /**
4553
- * Run the function before an `update` kind of query.
4554
- *
4555
- * @param cb - function to call, first argument is a query object
4556
- */
4557
- beforeUpdate(cb) {
4558
- return _queryHookBeforeUpdate(_clone(this), cb);
4255
+ isInTransaction() {
4256
+ const trx = this.internal.asyncStorage.getStore();
4257
+ return isInUserTransaction(trx);
4559
4258
  }
4560
4259
  /**
4561
- * Run the function after an `update` kind of query.
4562
- * Enforces wrapping the query into a transaction.
4563
- * The function will run after the query is succeeded, but before the transaction commit.
4564
- * Queries inside the function will run in the same transaction as the target query.
4565
- * If no records were updated, the hook *won't* run.
4260
+ * Schedules a hook to run after the outermost transaction commits:
4566
4261
  *
4567
- * @param select - list of columns to select for the hook
4568
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4569
- */
4570
- afterUpdate(select, cb) {
4571
- return _queryHookAfterUpdate(_clone(this), select, cb);
4572
- }
4573
- /**
4574
- * Run the function after transaction for an `update` kind of query will be committed.
4575
- * If the query wasn't wrapped in a transaction, will run after the query.
4576
- * If no records were updated, the hook *won't* run.
4262
+ * ```ts
4263
+ * await db.$transaction(async () => {
4264
+ * await db.table.create(data)
4265
+ * await db.table.where({ ...conditions }).update({ key: 'value' })
4577
4266
  *
4578
- * @param select - list of columns to select for the hook
4579
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4580
- */
4581
- afterUpdateCommit(select, cb) {
4582
- return _queryHookAfterUpdateCommit(
4583
- _clone(this),
4584
- select,
4585
- cb
4586
- );
4587
- }
4588
- /**
4589
- * Run the function before a `create` or an `update` kind of query.
4267
+ * db.$afterCommit(() => { // can be sync or async
4268
+ * console.log('after commit')
4269
+ * })
4270
+ * })
4271
+ * ```
4590
4272
  *
4591
- * @param cb - function to call, first argument is a query object
4592
- */
4593
- beforeSave(cb) {
4594
- return _queryHookBeforeSave(_clone(this), cb);
4595
- }
4596
- /**
4597
- * Run the function after a `create` or an `update` kind of query.
4598
- * Enforces wrapping the query into a transaction.
4599
- * The function will run after the query is succeeded, but before the transaction commit.
4600
- * Queries inside the function will run in the same transaction as the target query.
4601
- * For the `update` query, if no records were updated, the hook *won't* run.
4273
+ * If used outside the transaction, the hook will be executed almost immediately, on the next microtask:
4602
4274
  *
4603
- * @param select - list of columns to select for the hook
4604
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4605
- */
4606
- afterSave(select, cb) {
4607
- return _queryHookAfterSave(_clone(this), select, cb);
4608
- }
4609
- /**
4610
- * Run the function after transaction for a `create` or an `update` kind of query will be committed.
4611
- * If the query wasn't wrapped in a transaction, will run after the query.
4612
- * For the `update` query, if no records were updated, the hook *won't* run.
4275
+ * ```ts
4276
+ * db.$afterCommit(async () => { // can be sync or async
4277
+ * console.log('after commit')
4278
+ * })
4279
+ * ```
4613
4280
  *
4614
- * @param select - list of columns to select for the hook
4615
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4281
+ * If the callback has no `try/catch` and throws an error,
4282
+ * this will cause `uncaughtException` if the callback is sync and `unhandledRejection` if it is async.
4616
4283
  */
4617
- afterSaveCommit(select, cb) {
4618
- return _queryAfterSaveCommit(_clone(this), select, cb);
4284
+ afterCommit(hook) {
4285
+ const trx = this.internal.asyncStorage.getStore();
4286
+ if (isInUserTransaction(trx)) {
4287
+ (trx.afterCommit ?? (trx.afterCommit = [])).push(hook);
4288
+ } else {
4289
+ queueMicrotask(hook);
4290
+ }
4619
4291
  }
4620
4292
  /**
4621
- * Run the function before a `delete` kind of query.
4293
+ * Whenever a query in a transaction fails, the transaction is transitioned to a failed state, no further queries are possible.
4622
4294
  *
4623
- * @param cb - function to call, first argument is a query object
4624
- */
4625
- beforeDelete(cb) {
4626
- return _queryHookBeforeDelete(_clone(this), cb);
4627
- }
4628
- /**
4629
- * Run the function after a `delete` kind of query.
4630
- * Enforces wrapping the query into a transaction.
4631
- * The function will run after the query is succeeded, but before the transaction commit.
4632
- * Queries inside the function will run in the same transaction as the target query.
4633
- * If no records were deleted, the hook *won't* run.
4295
+ * Use [catchUniqueError](/guide/error-handling.html#catchuniqueerror) to handle uniqueness errors,
4296
+ * the following examples do not use it to illustrate error handling.
4634
4297
  *
4635
- * @param select - list of columns to select for the hook
4636
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4637
- */
4638
- afterDelete(select, cb) {
4639
- return _queryHookAfterDelete(_clone(this), select, cb);
4640
- }
4641
- /**
4642
- * Run the function after transaction for a `delete` kind of query will be committed.
4643
- * If the query wasn't wrapped in a transaction, will run after the query.
4644
- * If no records were deleted, the hook *won't* run.
4298
+ * ```ts
4299
+ * // This transaction is going to fail
4300
+ * db.$transaction(async () => {
4301
+ * try {
4302
+ * // imagine it fails because the username is already taken
4303
+ * await db.user.insert({ username: 'taken' });
4304
+ * } catch (err) {
4305
+ * // even though the query is wrapped in a try-catch, the transaction fails anyway
4306
+ * }
4307
+ * });
4308
+ * ```
4645
4309
  *
4646
- * @param select - list of columns to select for the hook
4647
- * @param cb - function to call, first argument is the query result with selected columns, second argument is a query object
4648
- */
4649
- afterDeleteCommit(select, cb) {
4650
- return _queryHookAfterDeleteCommit(
4651
- _clone(this),
4652
- select,
4653
- cb
4654
- );
4655
- }
4656
- /**
4657
- * Add `catchAfterCommitError` to the query to catch possible errors that are coming from after commit hooks.
4310
+ * You can use `catch` method on a query instead of `try-catch` to surpass the problem.
4311
+ * The following transaction won't fail:
4658
4312
  *
4659
- * When it is used, the transaction will return its result disregarding of a failed hook.
4313
+ * ```ts
4314
+ * // Transaction succeeds
4315
+ * db.$transaction(async () => {
4316
+ * const result = await db.user.insert({ username: 'taken' }).catch(() => 'failed');
4660
4317
  *
4661
- * Without `catchAfterCommitError`, the transaction function throws and won't return result.
4662
- * Result is still accessible from the error object [AfterCommitError](#AfterCommitError).
4318
+ * if (result === 'failed') {
4319
+ * await db.user.insert({ username: 'another' });
4320
+ * }
4321
+ * });
4322
+ * ```
4663
4323
  *
4664
- * ```ts
4665
- * const result = await db
4666
- * .$transaction(async () => {
4667
- * return db.table.create(data);
4668
- * })
4669
- * .catchAfterCommitError((err) => {
4670
- * // err is instance of AfterCommitError (see below)
4671
- * })
4672
- * // can be added multiple times, all catchers will be executed
4673
- * .catchAfterCommitError((err) => {});
4324
+ * This is because when using `catch` method, `OrchidORM` will wrap the query with a savepoint.
4674
4325
  *
4675
- * // result is available even if an after commit hook has failed
4676
- * result.id;
4326
+ * Alternatively, you can use the `recoverable()` method:
4327
+ *
4328
+ * ```ts
4329
+ * // Transaction succeeds
4330
+ * db.$transaction(async () => {
4331
+ * try {
4332
+ * await db.user.insert({ username: 'taken' }).recoverable();
4333
+ * } catch (err) {
4334
+ * await db.user.insert({ username: 'another' });
4335
+ * }
4336
+ * });
4677
4337
  * ```
4678
4338
  */
4679
- catchAfterCommitError(fn) {
4339
+ recoverable() {
4680
4340
  const q = _clone(this);
4681
- pushQueryValueImmutable(q, "catchAfterCommitErrors", fn);
4341
+ q.q.catch = true;
4682
4342
  return q;
4683
4343
  }
4684
4344
  }
4345
+ const runAfterCommit = (afterCommit, result) => {
4346
+ queueMicrotask(async () => {
4347
+ if (afterCommit) {
4348
+ const promises = [];
4349
+ let catchAfterCommitErrors;
4350
+ for (let i = 0, len = afterCommit.length; i < len; ) {
4351
+ const first = afterCommit[i];
4352
+ if (typeof first === "function") {
4353
+ try {
4354
+ promises.push(first());
4355
+ } catch (err) {
4356
+ promises.push(Promise.reject(err));
4357
+ }
4358
+ i++;
4359
+ } else {
4360
+ const q = afterCommit[i + 1];
4361
+ if (q.q.catchAfterCommitErrors) {
4362
+ (catchAfterCommitErrors ?? (catchAfterCommitErrors = [])).push(...q.q.catchAfterCommitErrors);
4363
+ }
4364
+ for (const fn of afterCommit[i + 2]) {
4365
+ try {
4366
+ promises.push(fn(first, q));
4367
+ } catch (err) {
4368
+ promises.push(Promise.reject(err));
4369
+ }
4370
+ }
4371
+ i += 3;
4372
+ }
4373
+ }
4374
+ const getHookNames = () => {
4375
+ const hookNames = [];
4376
+ for (let i = 0, len = afterCommit.length; i < len; ) {
4377
+ const first = afterCommit[i];
4378
+ if (typeof first === "function") {
4379
+ hookNames.push(first.name);
4380
+ i++;
4381
+ } else {
4382
+ for (const fn of afterCommit[i + 2]) {
4383
+ hookNames.push(fn.name);
4384
+ }
4385
+ i += 3;
4386
+ }
4387
+ }
4388
+ return hookNames;
4389
+ };
4390
+ await _runAfterCommitHooks(
4391
+ result,
4392
+ promises,
4393
+ getHookNames,
4394
+ catchAfterCommitErrors
4395
+ );
4396
+ }
4397
+ });
4398
+ };
4685
4399
 
4686
4400
  const applyTransforms = (queryData, returnType, fns, result) => {
4687
4401
  for (const fn of fns) {
@@ -4938,6 +4652,127 @@ const collectPrimaryKeys = (q) => {
4938
4652
  return primaryKeys;
4939
4653
  };
4940
4654
 
4655
+ const _unscope = (q, scope) => {
4656
+ if (q.q.scopes) {
4657
+ q.q.scopes = { ...q.q.scopes };
4658
+ delete q.q.scopes[scope];
4659
+ for (const _ in q.q.scopes) {
4660
+ return q;
4661
+ }
4662
+ delete q.q.scopes;
4663
+ }
4664
+ return q;
4665
+ };
4666
+ class QueryScope {
4667
+ /**
4668
+ * See {@link QueryScope}
4669
+ *
4670
+ * Use the `scope` method to apply a pre-defined scope.
4671
+ *
4672
+ * ```ts
4673
+ * // use the `active` scope that is defined in the table:
4674
+ * await db.some.scope('active');
4675
+ * ```
4676
+ *
4677
+ * @param scope - name of the scope to apply
4678
+ */
4679
+ scope(scope) {
4680
+ const q = _clone(this);
4681
+ if (!q.q.scopes?.[scope]) {
4682
+ const s = q.internal.scopes[scope];
4683
+ if (!s) throw new Error(`Scope ${scope} is not defined`);
4684
+ setObjectValueImmutable(q.q, "scopes", scope, s);
4685
+ }
4686
+ return q;
4687
+ }
4688
+ /**
4689
+ * See {@link QueryScope}
4690
+ *
4691
+ * Remove conditions that were added by the scope from the query.
4692
+ *
4693
+ * ```ts
4694
+ * // SomeTable has a default scope, ignore it for this query:
4695
+ * await db.some.unscope('default');
4696
+ * ```
4697
+ *
4698
+ * @param scope - name of the scope to remove from the query
4699
+ */
4700
+ unscope(scope) {
4701
+ return _unscope(_clone(this), scope);
4702
+ }
4703
+ }
4704
+
4705
+ const checkIfNeedResultAllForMutativeQueriesSelectRelations = (sql) => {
4706
+ return sql.mutativeQueriesSelectRelationsState?.value;
4707
+ };
4708
+ const checkIfShouldReleaseSavepointForMutativeQueriesSelectRelations = (sql) => {
4709
+ return sql.mutativeQueriesSelectRelationsState?.value;
4710
+ };
4711
+ const loadMutativeQueriesSelectRelations = (sql, result, adapter, startingSavepoint, renames) => sql.mutativeQueriesSelectRelationsState?.value ? loadRelations(
4712
+ sql.mutativeQueriesSelectRelationsState,
4713
+ result,
4714
+ adapter,
4715
+ startingSavepoint,
4716
+ renames
4717
+ ) : void 0;
4718
+ const loadRelations = async (state, result, adapter, startingSavepoint, renames) => {
4719
+ var _a;
4720
+ const q = state.query;
4721
+ const primaryKeys = requirePrimaryKeys(
4722
+ q,
4723
+ "Cannot select a relation of a table that has no primary keys"
4724
+ );
4725
+ const selectQuery = _unscope(q, "nonDeleted");
4726
+ selectQuery.q.type = selectQuery.q.returnType = void 0;
4727
+ const matchSourceTableIds = {};
4728
+ for (const pkey of primaryKeys) {
4729
+ matchSourceTableIds[pkey] = {
4730
+ in: result.map((row) => row[pkey])
4731
+ };
4732
+ }
4733
+ ((_a = selectQuery.q).and ?? (_a.and = [])).push(matchSourceTableIds);
4734
+ const relationsSelect = state.value;
4735
+ const selectAs = { ...relationsSelect };
4736
+ const select = [{ selectAs }];
4737
+ const relationKeyAliases = primaryKeys.map((key) => {
4738
+ if (key in selectAs) {
4739
+ const as = getFreeAlias(selectAs, key);
4740
+ selectAs[as] = key;
4741
+ return as;
4742
+ } else {
4743
+ select.push(key);
4744
+ return key;
4745
+ }
4746
+ });
4747
+ selectQuery.q.select = select;
4748
+ const relationsResult = await maybeWrappedThen.call(
4749
+ selectQuery,
4750
+ void 0,
4751
+ async (err) => {
4752
+ await adapter.arrays(`ROLLBACK TO SAVEPOINT "${startingSavepoint}"`);
4753
+ throw err;
4754
+ },
4755
+ startingSavepoint
4756
+ );
4757
+ for (const row of result) {
4758
+ const relationRow = relationsResult.find((relationRow2) => {
4759
+ return !primaryKeys.some(
4760
+ (key, i) => relationRow2[relationKeyAliases[i]] !== row[key]
4761
+ );
4762
+ });
4763
+ if (relationRow) {
4764
+ Object.assign(row, relationRow);
4765
+ }
4766
+ }
4767
+ if (renames) {
4768
+ for (const key in relationsSelect) {
4769
+ if (key in renames) {
4770
+ delete renames[key];
4771
+ }
4772
+ }
4773
+ }
4774
+ };
4775
+
4941
4776
  const queryMethodByReturnType = {
4942
4777
  undefined: "query",
4943
4778
  all: "query",
@@ -4950,7 +4785,6 @@ const queryMethodByReturnType = {
4950
4785
  void: "arrays"
4951
4786
  };
4952
4787
  class Then {
4953
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4954
4788
  catch(fn) {
4955
4789
  const q = _clone(this);
4956
4790
  q.q.catch = true;
@@ -4982,7 +4816,7 @@ Object.defineProperty(Then.prototype, "then", {
4982
4816
  });
4983
4817
  }
4984
4818
  });
4985
- function maybeWrappedThen(resolve, reject) {
4819
+ function maybeWrappedThen(resolve, reject, parentSavepoint) {
4986
4820
  const { q } = this;
4987
4821
  const shouldCatch = q.catch;
4988
4822
  let beforeActionHooks;
@@ -5037,7 +4871,8 @@ function maybeWrappedThen(resolve, reject) {
5037
4871
  afterSaveCommitHooks,
5038
4872
  resolve2,
5039
4873
  reject2,
5040
- shouldCatch
4874
+ shouldCatch,
4875
+ parentSavepoint
5041
4876
  );
5042
4877
  })
5043
4878
  ).then(resolve, reject);
@@ -5053,7 +4888,8 @@ function maybeWrappedThen(resolve, reject) {
5053
4888
  afterSaveCommitHooks,
5054
4889
  resolve,
5055
4890
  reject,
5056
- shouldCatch
4891
+ shouldCatch,
4892
+ parentSavepoint
5057
4893
  );
5058
4894
  }
5059
4895
  }
@@ -5063,8 +4899,7 @@ const callAfterHook = function(cb) {
5063
4899
  return cb(this[0], this[1]);
5064
4900
  };
5065
4901
  const beginSql = { text: "BEGIN" };
5066
- const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks, afterCommitHooks, afterSaveCommitHooks, resolve, reject, shouldCatch) => {
5067
- var _a;
4902
+ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks, afterCommitHooks, afterSaveCommitHooks, resolve, reject, shouldCatch, parentSavepoint) => {
5068
4903
  const { q: query } = q;
5069
4904
  let sql;
5070
4905
  let logData;
@@ -5088,12 +4923,16 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5088
4923
  }
5089
4924
  if (promises) await Promise.all(promises);
5090
4925
  }
5091
- const { tableHook, cteHooks, delayedRelationSelect } = sql;
4926
+ const { tableHook, cteHooks } = sql;
5092
4927
  const { returnType = "all" } = query;
5093
- const tempReturnType = tableHook?.select || cteHooks?.hasSelect || returnType === "rows" && q.q.batchParsers || delayedRelationSelect?.value ? "all" : returnType;
4928
+ const tempReturnType = tableHook?.select || cteHooks?.hasSelect || returnType === "rows" && q.q.batchParsers || checkIfNeedResultAllForMutativeQueriesSelectRelations(sql) ? "all" : returnType;
5094
4929
  let result;
5095
4930
  let queryResult;
5096
4931
  let cteData;
4932
+ const startingSavepoint = setCatchingSavepoint(
4933
+ !parentSavepoint && shouldCatch && state
4934
+ );
4935
+ const releasingSavepoint = checkIfShouldReleaseSavepointForMutativeQueriesSelectRelations(sql) || parentSavepoint ? void 0 : startingSavepoint;
5097
4936
  if ("text" in sql) {
5098
4937
  if (query.autoPreparedStatements) {
5099
4938
  sql.name = queriesNames[sql.text] || (queriesNames[sql.text] = (nameI++).toString(36));
@@ -5102,7 +4941,13 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5102
4941
  logData = log.beforeQuery(sql);
5103
4942
  }
5104
4943
  const method = queryMethodByReturnType[tempReturnType];
5105
- queryResult = await execQuery(adapter, method, sql, shouldCatch && state);
4944
+ queryResult = await execQuery(
4945
+ adapter,
4946
+ method,
4947
+ sql,
4948
+ startingSavepoint,
4949
+ releasingSavepoint
4950
+ );
5106
4951
  const { runAfterQuery } = sql;
5107
4952
  if (log) {
5108
4953
  log.afterQuery(sql, logData);
@@ -5136,8 +4981,9 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5136
4981
  } else {
5137
4982
  const queryMethod = queryMethodByReturnType[tempReturnType];
5138
4983
  const queryBatch = async (batch) => {
5139
- for (const item of batch) {
5140
- sql = item;
4984
+ const last = batch.length - 1;
4985
+ for (let i = 0; i <= last; i++) {
4986
+ sql = batch[i];
5141
4987
  if (log) {
5142
4988
  logData = log.beforeQuery(sql);
5143
4989
  }
@@ -5145,7 +4991,8 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5145
4991
  adapter,
5146
4992
  queryMethod,
5147
4993
  sql,
5148
- shouldCatch && state
4994
+ i === 0 ? startingSavepoint : void 0,
4995
+ i === last ? releasingSavepoint : void 0
5149
4996
  );
5150
4997
  if (queryResult) {
5151
4998
  queryResult.rowCount += result2.rowCount;
@@ -5177,8 +5024,11 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5177
5024
  let tempColumns;
5178
5025
  let renames;
5179
5026
  if (tableHook?.select) {
5180
- for (const column of tableHook.select.keys()) {
5181
- const { as, temp } = tableHook.select.get(column);
5027
+ for (const [
5028
+ column,
5029
+ { as, temp, notLoaded }
5030
+ ] of tableHook.select.entries()) {
5031
+ if (notLoaded) continue;
5182
5032
  if (as) {
5183
5033
  (renames ?? (renames = {}))[column] = as;
5184
5034
  }
@@ -5264,7 +5114,7 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5264
5114
  const afterCommitKey = `after${purpose2}Commit`;
5265
5115
  const afterCommit = tableHook2[afterCommitKey];
5266
5116
  if (afterCommit) {
5267
- const arr = cteAfterHooks ?? (cteAfterHooks = []);
5117
+ const arr = cteAfterCommitHooks ?? (cteAfterCommitHooks = []);
5268
5118
  for (const fn of afterCommit) {
5269
5119
  const hookData = addedAfterCommitHooks.has(fn);
5270
5120
  if (!hookData) {
@@ -5306,7 +5156,13 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5306
5156
  afterActionAndSaveCommit
5307
5157
  );
5308
5158
  }
5309
- if (cteAfterCommitHooks) ;
5159
+ if (cteAfterCommitHooks) {
5160
+ (state.afterCommit ?? (state.afterCommit = [])).push(
5161
+ result,
5162
+ q,
5163
+ cteAfterCommitHooks
5164
+ );
5165
+ }
5310
5166
  } else {
5311
5167
  const localResult = result;
5312
5168
  queueMicrotask(async () => {
@@ -5322,7 +5178,15 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5322
5178
  }
5323
5179
  }
5324
5180
  }
5325
- if (cteAfterCommitHooks) ;
5181
+ if (cteAfterCommitHooks) {
5182
+ for (const fn of cteAfterCommitHooks) {
5183
+ try {
5184
+ promises.push(fn());
5185
+ } catch (err) {
5186
+ promises.push(Promise.reject(err));
5187
+ }
5188
+ }
5189
+ }
5326
5190
  await _runAfterCommitHooks(
5327
5191
  localResult,
5328
5192
  promises,
@@ -5336,56 +5200,22 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5336
5200
  }
5337
5201
  }
5338
5202
  }
5339
- if (delayedRelationSelect?.value) {
5340
- const q2 = delayedRelationSelect.query;
5341
- const primaryKeys = requirePrimaryKeys(
5342
- q2,
5343
- "Cannot select a relation of a table that has no primary keys"
5344
- );
5345
- const selectQuery = q2.clone();
5346
- selectQuery.q.type = selectQuery.q.returnType = void 0;
5347
- const matchSourceTableIds = {};
5348
- for (const pkey of primaryKeys) {
5349
- matchSourceTableIds[pkey] = {
5350
- in: result.map((row) => row[pkey])
5351
- };
5352
- }
5353
- ((_a = selectQuery.q).and ?? (_a.and = [])).push(matchSourceTableIds);
5354
- const relationsSelect = delayedRelationSelect.value;
5355
- const selectAs = { ...relationsSelect };
5356
- const select = [{ selectAs }];
5357
- const relationKeyAliases = primaryKeys.map((key) => {
5358
- if (key in selectAs) {
5359
- const as = getFreeAlias(selectAs, key);
5360
- selectAs[as] = key;
5361
- return as;
5362
- } else {
5363
- select.push(key);
5364
- return key;
5365
- }
5366
- });
5367
- selectQuery.q.select = select;
5368
- const relationsResult = await selectQuery;
5369
- for (const row of result) {
5370
- const relationRow = relationsResult.find((relationRow2) => {
5371
- return !primaryKeys.some(
5372
- (key, i) => relationRow2[relationKeyAliases[i]] !== row[key]
5373
- );
5374
- });
5375
- if (relationRow) {
5376
- Object.assign(row, relationRow);
5377
- }
5378
- }
5379
- if (renames) {
5380
- for (const key in relationsSelect) {
5381
- if (key in renames) {
5382
- delete renames[key];
5383
- }
5384
- }
5385
- }
5203
+ const promise = loadMutativeQueriesSelectRelations(
5204
+ localSql,
5205
+ result,
5206
+ adapter,
5207
+ startingSavepoint,
5208
+ renames
5209
+ ) || /**
5210
+ * In case when we have MutativeQueriesSelectRelations, the first query does insert/update/delete,
5211
+ * it must not run batchParsers because it doesn't have the data yet.
5212
+ * The second query loads data and performs batchParsers.
5213
+ */
5214
+ //
5215
+ parseBatch(q, queryResult);
5216
+ if (promise) {
5217
+ await promise;
5386
5218
  }
5387
- const promise = parseBatch(q, queryResult, delayedRelationSelect);
5388
- if (promise) await promise;
5389
5219
  if (tableHook?.select || tempReturnType !== returnType) {
5390
5220
  if (renames) {
5391
5221
  const renamedResult = Array.from({
@@ -5404,7 +5234,7 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5404
5234
  result = filterResult(
5405
5235
  q,
5406
5236
  returnType,
5407
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
5237
+ //
5408
5238
  queryResult,
5409
5239
  result,
5410
5240
  tempColumns,
@@ -5451,12 +5281,15 @@ const then = async (q, adapter, state, beforeHooks, afterHooks, afterSaveHooks,
5451
5281
  throw error;
5452
5282
  }
5453
5283
  };
5454
- const execQuery = (adapter, method, sql, catchTrx) => {
5455
- const catchingSavepoint = catchTrx ? `s${catchTrx.catchI = (catchTrx.catchI || 0) + 1}` : void 0;
5284
+ const setCatchingSavepoint = (catchTrx) => {
5285
+ return catchTrx ? `s${catchTrx.catchI = (catchTrx.catchI || 0) + 1}` : void 0;
5286
+ };
5287
+ const execQuery = (adapter, method, sql, startingSavepoint, releasingSavepoint) => {
5456
5288
  return adapter[method](
5457
5289
  sql.text,
5458
5290
  sql.values,
5459
- catchingSavepoint
5291
+ startingSavepoint,
5292
+ releasingSavepoint
5460
5293
  ).then((result) => {
5461
5294
  if (result.rowCount && !result.rows.length) {
5462
5295
  result.rows.length = result.rowCount;
@@ -5523,9 +5356,9 @@ const handleResult = (q, returnType, result, sql, isSubQuery) => {
5523
5356
  }
5524
5357
  }
5525
5358
  };
5526
- const parseBatch = (q, queryResult, delayedRelationSelect) => {
5359
+ const parseBatch = (q, queryResult) => {
5527
5360
  let promises;
5528
- if (q.q.batchParsers && !delayedRelationSelect?.value) {
5361
+ if (q.q.batchParsers) {
5529
5362
  for (const parser of q.q.batchParsers) {
5530
5363
  const res = parser.fn(parser.path, queryResult);
5531
5364
  if (res) (promises ?? (promises = [])).push(res);
@@ -5615,27 +5448,193 @@ const getFirstResultKey = (q, queryResult) => {
5615
5448
  return key;
5616
5449
  }
5617
5450
  }
5618
- return;
5451
+ return;
5452
+ };
5453
+ const filterAllResult = (result, tempColumns, hasAfterHook) => {
5454
+ if (tempColumns?.size) {
5455
+ if (hasAfterHook) {
5456
+ return result.map((data) => {
5457
+ const record = { ...data };
5458
+ for (const key of tempColumns) {
5459
+ delete record[key];
5460
+ }
5461
+ return record;
5462
+ });
5463
+ } else {
5464
+ for (const record of result) {
5465
+ for (const key of tempColumns) {
5466
+ delete record[key];
5467
+ }
5468
+ }
5469
+ }
5470
+ }
5471
+ return result;
5472
+ };
5473
+
5474
+ const getQueryAs = (q) => {
5475
+ return q.q.as || q.table;
5476
+ };
5477
+ const _getQueryAs = (q) => q.q.as;
5478
+ const _getQueryFreeAlias = (q, as) => q.aliases ? getFreeAlias(q.aliases, as) : as;
5479
+ const _checkIfAliased = (q, as, name) => {
5480
+ return q.q.aliases?.[as] === name;
5481
+ };
5482
+ const _getQueryAliasOrName = (q, as) => {
5483
+ return q.aliases?.[as] || as;
5484
+ };
5485
+ const _getQueryOuterAliases = (q) => {
5486
+ return q.outerAliases;
5487
+ };
5488
+ const _setQueryAs = (self, as) => {
5489
+ const { q } = self;
5490
+ q.as = as;
5491
+ q.aliases = {
5492
+ ...q.aliases,
5493
+ [as]: _getQueryFreeAlias(q, as)
5494
+ };
5495
+ return self;
5496
+ };
5497
+ const _setQueryAlias = (q, name, as) => {
5498
+ q.q.aliases = { ...q.q.aliases, [as]: name };
5499
+ };
5500
+ const _setSubQueryAliases = (q) => {
5501
+ q.q.outerAliases = q.q.aliases;
5502
+ };
5503
+ const _applyRelationAliases = (query, relQueryData) => {
5504
+ const aliases = query.q.as ? { ...query.q.aliases } : { ...query.q.aliases, [query.table]: query.table };
5505
+ const relAliases = relQueryData.aliases;
5506
+ for (const as in relAliases) {
5507
+ aliases[as] = getFreeAlias(aliases, as);
5508
+ }
5509
+ relQueryData.as = aliases[relQueryData.as];
5510
+ relQueryData.aliases = aliases;
5511
+ };
5512
+ const _copyQueryAliasToQuery = (fromQuery, toQuery, key) => {
5513
+ const name = _getQueryAliasOrName(fromQuery.q, key);
5514
+ if (name !== key) {
5515
+ _setQueryAlias(toQuery, name, key);
5516
+ }
5517
+ return name;
5518
+ };
5519
+ class QueryAsMethods {
5520
+ /**
5521
+ * Sets table alias:
5522
+ *
5523
+ * ```ts
5524
+ * db.table.as('u').select('u.name');
5525
+ *
5526
+ * // Can be used in the join:
5527
+ * db.table.join(db.profile.as('p'), 'p.userId', 'user.id');
5528
+ * ```
5529
+ *
5530
+ * @param as - alias for the table of this query
5531
+ */
5532
+ as(as) {
5533
+ return _setQueryAs(_clone(this), as);
5534
+ }
5535
+ }
5536
+
5537
+ const pushQueryArrayImmutable = (q, key, value) => {
5538
+ const arr = q.q[key];
5539
+ q.q[key] = arr ? [...arr, ...value] : value;
5540
+ return q;
5541
+ };
5542
+ const setQueryObjectValueImmutable = (q, object, key, value) => {
5543
+ q.q[object] = {
5544
+ ...q.q[object],
5545
+ [key]: value
5546
+ };
5547
+ return q;
5548
+ };
5549
+ const throwIfNoWhere = (q, method) => {
5550
+ if (!q.q.or && !q.q.and && !q.q.scopes && !q.q.all) {
5551
+ throw new OrchidOrmInternalError(
5552
+ q,
5553
+ `Dangerous ${method} without conditions`
5554
+ );
5555
+ }
5556
+ };
5557
+ const throwIfJoinLateral = (q, method) => {
5558
+ if (q.q.join?.some((x) => Array.isArray(x) || "s" in x.args && x.args.s)) {
5559
+ throw new OrchidOrmInternalError(
5560
+ q,
5561
+ `Cannot join a complex query in ${method}`
5562
+ );
5563
+ }
5564
+ };
5565
+ const throwOnReadOnlyUpdate = (query, column, key) => {
5566
+ if (column.data.appReadOnly || column.data.readOnly) {
5567
+ throw new OrchidOrmInternalError(
5568
+ query,
5569
+ "Trying to update a readonly column",
5570
+ { column: key }
5571
+ );
5572
+ }
5573
+ };
5574
+ const saveAliasedShape = (q, as, key) => {
5575
+ const shapes = q.q[key];
5576
+ as = getFreeAlias(shapes, as);
5577
+ setQueryObjectValueImmutable(q, key, as, emptyObject);
5578
+ return as;
5579
+ };
5580
+ const extendQuery = (q, methods) => {
5581
+ const base = Object.create(q.baseQuery);
5582
+ base.baseQuery = base;
5583
+ Object.assign(base, methods);
5584
+ const cloned = Object.create(base);
5585
+ cloned.q = getClonedQueryData(q.q);
5586
+ return cloned;
5587
+ };
5588
+ const _queryAll = (q) => {
5589
+ q.q.returnType = "all";
5590
+ q.q.all = true;
5591
+ return q;
5592
+ };
5593
+ const _queryTake = (query) => {
5594
+ const q = query.q;
5595
+ switch (q.returnType) {
5596
+ case "valueOrThrow":
5597
+ case "pluck":
5598
+ case "void":
5599
+ break;
5600
+ case "value": {
5601
+ q.returnType = "valueOrThrow";
5602
+ break;
5603
+ }
5604
+ default: {
5605
+ q.returnType = "oneOrThrow";
5606
+ }
5607
+ }
5608
+ return query;
5619
5609
  };
5620
- const filterAllResult = (result, tempColumns, hasAfterHook) => {
5621
- if (tempColumns?.size) {
5622
- if (hasAfterHook) {
5623
- return result.map((data) => {
5624
- const record = { ...data };
5625
- for (const key of tempColumns) {
5626
- delete record[key];
5627
- }
5628
- return record;
5629
- });
5630
- } else {
5631
- for (const record of result) {
5632
- for (const key of tempColumns) {
5633
- delete record[key];
5634
- }
5635
- }
5610
+ const _queryTakeOptional = (query) => {
5611
+ const q = query.q;
5612
+ switch (q.returnType) {
5613
+ case "value":
5614
+ case "pluck":
5615
+ case "void":
5616
+ break;
5617
+ case "valueOrThrow": {
5618
+ q.returnType = "value";
5619
+ break;
5620
+ }
5621
+ default: {
5622
+ q.returnType = "one";
5636
5623
  }
5637
5624
  }
5638
- return result;
5625
+ return query;
5626
+ };
5627
+ const _queryExec = (q) => {
5628
+ q.q.returnType = "void";
5629
+ return q;
5630
+ };
5631
+ const _queryRows = (q) => {
5632
+ q.q.returnType = "rows";
5633
+ return q;
5634
+ };
5635
+ const getFullColumnTable = (q, column, index, as) => {
5636
+ const table = column.slice(0, index);
5637
+ return as && table !== as && _checkIfAliased(q, table, as) ? as : table;
5639
5638
  };
5640
5639
 
5641
5640
  const noneResult = (q, queryData, type) => {
@@ -5685,6 +5684,38 @@ const _queryNone = (q) => {
5685
5684
  };
5686
5685
  const isQueryNone = (q) => q.then === noneMethods.then;
5687
5686
 
5687
+ const prepareSubQueryForSql = (mainQuery, subQuery) => {
5688
+ if (subQuery.dynamicBefore) {
5689
+ pushQueryValueImmutable(mainQuery, "dynamicBefore", subQuery.q);
5690
+ return subQuery;
5691
+ }
5692
+ let beforeAction = subQuery.q.type ? subQuery.q.type === "insert" ? subQuery.q.beforeCreate : subQuery.q.type === "update" ? subQuery.q.beforeUpdate : subQuery.q.type === "upsert" ? subQuery.q.upsertUpdate && subQuery.q.updateData ? subQuery.q.beforeUpdate && subQuery.q.beforeCreate ? [...subQuery.q.beforeUpdate, ...subQuery.q.beforeCreate] : subQuery.q.beforeUpdate || subQuery.q.beforeCreate : subQuery.q.beforeCreate : subQuery.q.type === "delete" ? subQuery.q.beforeDelete : void 0 : void 0;
5693
+ const { beforeSet } = subQuery.q;
5694
+ beforeAction = beforeAction && beforeSet ? [...beforeAction, ...beforeSet] : beforeSet ? [...beforeSet] : beforeAction;
5695
+ if (beforeAction) {
5696
+ const newSet = new Set(mainQuery.q.beforeSet);
5697
+ const filteredHooks = [];
5698
+ for (const hook of beforeAction) {
5699
+ if (!newSet.has(hook)) {
5700
+ newSet.add(hook);
5701
+ filteredHooks.push(hook);
5702
+ }
5703
+ }
5704
+ mainQuery.q.beforeSet = newSet;
5705
+ beforeAction = filteredHooks;
5706
+ if (beforeAction.length) {
5707
+ pushQueryArrayImmutable(
5708
+ mainQuery,
5709
+ "before",
5710
+ beforeAction.map((fn) => () => fn(subQuery))
5711
+ );
5712
+ }
5713
+ }
5714
+ return subQuery;
5715
+ };
5716
+ setPrepareSubQueryForSql(prepareSubQueryForSql);
5717
+ setRawSqlPrepareSubQueryForSql(prepareSubQueryForSql);
5718
+
5688
5719
  const addWithParsers = (w, parsers) => {
5689
5720
  for (const key in w.shape) {
5690
5721
  const { _parse } = w.shape[key];
@@ -6960,7 +6991,9 @@ const wrapMainQueryInCte = (ctx, q, isSubSql) => {
6960
6991
  if (!isSubSql && !ctx.cteName) {
6961
6992
  as = addTopCteSql$1(ctx, ctx.wrapAs, ctx.sql.join(" "));
6962
6993
  }
6963
- q.appendQueries?.forEach((query) => addTopCte$1("after", ctx, query));
6994
+ q.appendQueries?.forEach(
6995
+ (query) => addTopCte$1("after", ctx, query, query.q.type)
6996
+ );
6964
6997
  if (!isSubSql && !ctx.cteName) {
6965
6998
  const addNull = ctx.topCtx.cteHooks?.hasSelect;
6966
6999
  ctx.sql = [`SELECT *${addNull ? ", NULL" : ""} FROM ${as}`];
@@ -6980,9 +7013,6 @@ const makeSql = (ctx, type, isSubSql, runAfterQuery) => {
6980
7013
  runAfterQuery
6981
7014
  };
6982
7015
  };
6983
- const quoteSchemaAndTable = (schema, table) => {
6984
- return schema ? `"${schema}"."${table}"` : `"${table}"`;
6985
- };
6986
7016
  const requireTableOrStringFrom = (query) => {
6987
7017
  const table = query.table || (typeof query.q.from === "string" ? query.q.from : void 0);
6988
7018
  if (!table) {
@@ -7314,7 +7344,7 @@ const _joinLateral = (self, type, joinQuery, as, innerJoinLateral) => {
7314
7344
  existingValue.q.q.select = [
7315
7345
  {
7316
7346
  selectAs: {
7317
- ...(existingValue.q.q.select?.[0]).selectAs,
7347
+ ...existingValue.q.q.select[0].selectAs,
7318
7348
  [joinAs]: joinValueSelect
7319
7349
  }
7320
7350
  }
@@ -8054,17 +8084,6 @@ const pushQueryOrOn = (q, joinFrom, joinTo, ...on) => {
8054
8084
  makeOnItem(joinFrom, joinTo, on)
8055
8085
  ]);
8056
8086
  };
8057
- const addQueryOn = (query, joinFrom, joinTo, ...args) => {
8058
- const cloned = _clone(query);
8059
- const { q } = cloned;
8060
- setObjectValueImmutable(
8061
- q,
8062
- "joinedShapes",
8063
- joinFrom.q.as || joinFrom.table,
8064
- joinFrom.q.shape
8065
- );
8066
- return pushQueryOn(cloned, joinFrom, joinTo, ...args);
8067
- };
8068
8087
  const _queryJoinOn = (q, args) => {
8069
8088
  return pushQueryOn(
8070
8089
  q,
@@ -8131,11 +8150,12 @@ class OnMethods {
8131
8150
  }
8132
8151
  }
8133
8152
 
8134
- const _addToHookSelect = (query, selects) => {
8153
+ const _addToHookSelect = (query, selects, notLoaded) => {
8135
8154
  const { q } = query;
8136
8155
  const map = q.hookSelect = new Map(q.hookSelect);
8137
8156
  for (const key of selects) {
8138
- map.set(key, { select: key });
8157
+ const item = map.get(key) || { select: key };
8158
+ map.set(key, notLoaded ? { ...item, notLoaded } : item);
8139
8159
  }
8140
8160
  };
8141
8161
  const _addToHookSelectWithTable = (query, selects, table) => {
@@ -8146,6 +8166,10 @@ const _addToHookSelectWithTable = (query, selects, table) => {
8146
8166
  }
8147
8167
  };
8148
8168
 
8169
+ const setSelectRelation = (q) => {
8170
+ q.selectRelation = true;
8171
+ };
8172
+
8149
8173
  const addParserForRawExpression = (q, key, raw) => {
8150
8174
  if (raw.result.value) addColumnParserToQuery(q.q, key, raw.result.value);
8151
8175
  };
@@ -8404,7 +8428,8 @@ const processSelectArg = (q, as, arg, columnAs) => {
8404
8428
  if (isRelationQuery(value) && // `subQuery = 1` case is when callback returns the same query as it gets,
8405
8429
  // for example `q => q.get('name')`.
8406
8430
  value.q.subQuery !== 1) {
8407
- query.q.selectRelation = joinQuery = true;
8431
+ joinQuery = true;
8432
+ setSelectRelation(query.q);
8408
8433
  value = value.joinQuery(value, q);
8409
8434
  let subQuery;
8410
8435
  const { returnType, innerJoinLateral } = value.q;
@@ -8588,48 +8613,198 @@ const getShapeFromSelect = (q, isSubQuery) => {
8588
8613
  }
8589
8614
  }
8590
8615
  }
8591
- return result;
8592
- };
8593
- const addColumnToShapeFromSelect = (q, arg, shape, query, result, isSubQuery, key) => {
8594
- const index = arg.indexOf(".");
8595
- if (index !== -1) {
8596
- const as = q.q.as || q.table;
8597
- const table = getFullColumnTable(q, arg, index, as);
8598
- const column = arg.slice(index + 1);
8599
- if (table === as) {
8600
- result[key || column] = shape[column];
8601
- } else {
8602
- const it = query.joinedShapes?.[table]?.[column];
8603
- if (it)
8604
- result[key || column] = mapSubSelectColumn(
8605
- it,
8606
- isSubQuery
8607
- );
8608
- }
8609
- } else if (arg === "*") {
8610
- for (const key2 in shape) {
8611
- if (!shape[key2].data.explicitSelect) {
8612
- result[key2] = mapSubSelectColumn(
8613
- shape[key2],
8614
- isSubQuery
8615
- );
8616
- }
8617
- }
8618
- } else {
8619
- result[key || arg] = mapSubSelectColumn(
8620
- shape[arg],
8621
- isSubQuery
8616
+ return result;
8617
+ };
8618
+ const addColumnToShapeFromSelect = (q, arg, shape, query, result, isSubQuery, key) => {
8619
+ const index = arg.indexOf(".");
8620
+ if (index !== -1) {
8621
+ const as = q.q.as || q.table;
8622
+ const table = getFullColumnTable(q, arg, index, as);
8623
+ const column = arg.slice(index + 1);
8624
+ if (table === as) {
8625
+ result[key || column] = shape[column];
8626
+ } else {
8627
+ const it = query.joinedShapes?.[table]?.[column];
8628
+ if (it)
8629
+ result[key || column] = mapSubSelectColumn(
8630
+ it,
8631
+ isSubQuery
8632
+ );
8633
+ }
8634
+ } else if (arg === "*") {
8635
+ for (const key2 in shape) {
8636
+ if (!shape[key2].data.explicitSelect) {
8637
+ result[key2] = mapSubSelectColumn(
8638
+ shape[key2],
8639
+ isSubQuery
8640
+ );
8641
+ }
8642
+ }
8643
+ } else {
8644
+ result[key || arg] = mapSubSelectColumn(
8645
+ shape[arg],
8646
+ isSubQuery
8647
+ );
8648
+ }
8649
+ };
8650
+ const mapSubSelectColumn = (column, isSubQuery) => {
8651
+ if (!isSubQuery || !column || !column.data.name && !column.data.explicitSelect) {
8652
+ return column;
8653
+ }
8654
+ const cloned = Object.create(column);
8655
+ cloned.data = { ...column.data, name: void 0, explicitSelect: void 0 };
8656
+ return cloned;
8657
+ };
8658
+
8659
+ const _queryUnion = (base, args, k, p, m) => {
8660
+ const query = base.baseQuery.clone();
8661
+ const u = args.map(
8662
+ (a) => ({
8663
+ a: prepareSubQueryForSql(
8664
+ base,
8665
+ typeof a === "function" ? a(query) : a
8666
+ ),
8667
+ k,
8668
+ m
8669
+ })
8670
+ );
8671
+ const { q } = query;
8672
+ const baseQ = base.q;
8673
+ q.union = baseQ.union ? {
8674
+ ...baseQ.union,
8675
+ u: [...baseQ.union.u, ...u]
8676
+ } : {
8677
+ b: base,
8678
+ u,
8679
+ p
8680
+ };
8681
+ return query;
8682
+ };
8683
+ class Union {
8684
+ /**
8685
+ * Creates a union query, takes one or more queries or SQL expressions.
8686
+ *
8687
+ * ```ts
8688
+ * import { sql } from './baseTable';
8689
+ *
8690
+ * // The first query of the union
8691
+ * db.one
8692
+ * .select('id', 'name')
8693
+ * // add two more queries to the union
8694
+ * .union(
8695
+ * db.two.select('id', 'name'),
8696
+ * (q = sql`SELECT id, name FROM "thirdTable"`),
8697
+ * )
8698
+ * // sub-sequent `union` is equivalent to passing multiple queries into a single `union`
8699
+ * .union(db.three.select('id', 'name'));
8700
+ * ```
8701
+ *
8702
+ * `order`, `limit`, `offset` are special, it matters if you place them **before** or **after** the `union`, it also have a meaning to place them before and after.
8703
+ *
8704
+ * ```ts
8705
+ * // order, limit, offset are applied ONLY to 'one'
8706
+ * db.one
8707
+ * .order('x')
8708
+ * .limit(1)
8709
+ * .offset(1)
8710
+ * // 'two' also has order, limit, and offset
8711
+ * .unionAll(db.two.order('y').limit(2).offset(2))
8712
+ * // sets order, limit, offset for all records
8713
+ * .order('z')
8714
+ * .limit(3)
8715
+ * .offset(3);
8716
+ * ```
8717
+ *
8718
+ * Equivalent SQL:
8719
+ *
8720
+ * ```sql
8721
+ * -- both union parts have their own order, limit, offset
8722
+ * ( SELECT * FROM one ORDER x ASC LIMIT 1 OFFSET 1 )
8723
+ * UNION ALL
8724
+ * ( SELECT * FROM two ORDER y ASC LIMIT 2 OFFSET 2 )
8725
+ * -- order, limit, offset of the whole query
8726
+ * ORDER BY z ASC LIMIT 3 OFFSET 3
8727
+ * ```
8728
+ *
8729
+ * All the listed methods have the same signature, they are only different by SQL keyword:
8730
+ *
8731
+ * - `union` - union of all queries, performs deduplication
8732
+ * - `unionAll` - `union` that allows duplicated rows
8733
+ * - `intersect` - get only rows that are present in all queries
8734
+ * - `intersectAll` - `intersect` that allows duplicated rows
8735
+ * - `except` - get only rows that are in the first query but not in the second
8736
+ * - `exceptAll` - `except` that allows duplicated rows
8737
+ *
8738
+ * @param args - array of queries or SQL expressions
8739
+ */
8740
+ union(...args) {
8741
+ return _queryUnion(
8742
+ _clone(this),
8743
+ args,
8744
+ "UNION"
8745
+ );
8746
+ }
8747
+ /**
8748
+ * Same as {@link union}, but allows duplicated rows.
8749
+ *
8750
+ * @param args - array of queries or SQL expressions
8751
+ */
8752
+ unionAll(...args) {
8753
+ return _queryUnion(
8754
+ _clone(this),
8755
+ args,
8756
+ "UNION ALL"
8757
+ );
8758
+ }
8759
+ /**
8760
+ * Same as {@link union}, but uses a `INTERSECT` SQL keyword instead
8761
+ *
8762
+ * @param args - array of queries or SQL expressions
8763
+ */
8764
+ intersect(...args) {
8765
+ return _queryUnion(
8766
+ _clone(this),
8767
+ args,
8768
+ "INTERSECT"
8769
+ );
8770
+ }
8771
+ /**
8772
+ * Same as {@link intersect}, but allows duplicated rows.
8773
+ *
8774
+ * @param args - array of queries or SQL expressions
8775
+ */
8776
+ intersectAll(...args) {
8777
+ return _queryUnion(
8778
+ _clone(this),
8779
+ args,
8780
+ "INTERSECT ALL"
8622
8781
  );
8623
8782
  }
8624
- };
8625
- const mapSubSelectColumn = (column, isSubQuery) => {
8626
- if (!isSubQuery || !column || !column.data.name && !column.data.explicitSelect) {
8627
- return column;
8783
+ /**
8784
+ * Same as {@link union}, but uses an `EXCEPT` SQL keyword instead
8785
+ *
8786
+ * @param args - array of queries or SQL expressions
8787
+ */
8788
+ except(...args) {
8789
+ return _queryUnion(
8790
+ _clone(this),
8791
+ args,
8792
+ "EXCEPT"
8793
+ );
8628
8794
  }
8629
- const cloned = Object.create(column);
8630
- cloned.data = { ...column.data, name: void 0, explicitSelect: void 0 };
8631
- return cloned;
8632
- };
8795
+ /**
8796
+ * Same as {@link except}, but allows duplicated rows.
8797
+ *
8798
+ * @param args - array of queries or SQL expressions
8799
+ */
8800
+ exceptAll(...args) {
8801
+ return _queryUnion(
8802
+ _clone(this),
8803
+ args,
8804
+ "EXCEPT ALL"
8805
+ );
8806
+ }
8807
+ }
8633
8808
 
8634
8809
  const _addCte = (query, item) => pushOrNewArrayToObjectImmutable(query.q, "with", item);
8635
8810
  const _prependWith = (q, name, queryArg) => _with(q, name, queryArg, void 0, true);
@@ -8740,9 +8915,6 @@ const columnToSql = (ctx, data, shape, column, quotedAs, select) => {
8740
8915
  select
8741
8916
  );
8742
8917
  }
8743
- if (!select && data.joinedShapes?.[column]) {
8744
- return `"${column}"."${column}"`;
8745
- }
8746
8918
  return simpleColumnToSQL(ctx, column, shape[column], quotedAs);
8747
8919
  };
8748
8920
  const maybeSelectedColumnToSql = (ctx, data, column, quotedAs) => {
@@ -9080,97 +9252,285 @@ const _getSelectableColumn = (q, arg) => {
9080
9252
  }
9081
9253
  }
9082
9254
  }
9083
- return type;
9255
+ return type;
9256
+ };
9257
+ const _get = (query, returnType, arg) => {
9258
+ const q = query.q;
9259
+ if (q.returning) q.returning = void 0;
9260
+ q.returnType = returnType;
9261
+ let type;
9262
+ if (typeof arg === "string") {
9263
+ const joinedAs = q.valuesJoinedAs?.[arg];
9264
+ type = joinedAs ? q.joinedShapes?.[joinedAs]?.value : _getSelectableColumn(query, arg);
9265
+ q.getColumn = type;
9266
+ const selected = setParserForSelectedString(
9267
+ query,
9268
+ joinedAs ? joinedAs + "." + arg : arg,
9269
+ getQueryAs(query),
9270
+ getValueKey
9271
+ );
9272
+ q.select = selected ? [q.expr = new SelectItemExpression(query, selected, type)] : void 0;
9273
+ } else {
9274
+ type = arg.result.value;
9275
+ q.getColumn = type;
9276
+ addParserForRawExpression(query, getValueKey, arg);
9277
+ q.select = [q.expr = arg];
9278
+ }
9279
+ return setQueryOperators(
9280
+ query,
9281
+ type?.operators || Operators.any
9282
+ );
9283
+ };
9284
+ function _queryGet(self, arg) {
9285
+ return _get(self, "valueOrThrow", arg);
9286
+ }
9287
+ function _queryGetOptional(self, arg) {
9288
+ return _get(self, "value", arg);
9289
+ }
9290
+
9291
+ class RowToJsonExpression extends Expression {
9292
+ constructor(from, one, coalesce) {
9293
+ super();
9294
+ this.from = from;
9295
+ this.one = one;
9296
+ this.coalesce = coalesce;
9297
+ this.result = { value: UnknownColumn.instance };
9298
+ this.q = { expr: this };
9299
+ }
9300
+ makeSQL(ctx) {
9301
+ const q = this.from;
9302
+ const aliases = [];
9303
+ const jsonList = {};
9304
+ const select = selectToSql(
9305
+ ctx,
9306
+ q,
9307
+ q.q,
9308
+ `"${getQueryAs(q)}"`,
9309
+ q.q.hookSelect,
9310
+ void 0,
9311
+ aliases,
9312
+ jsonList
9313
+ );
9314
+ q.q.selectCache = { sql: select, aliases };
9315
+ let rowToJson;
9316
+ if (Object.values(jsonList).some((x) => x?.data.jsonCast)) {
9317
+ rowToJson = `json_build_object(${Object.entries(jsonList).map(
9318
+ ([key, column]) => `'${key}', t."${key}"${column?.data.jsonCast ? `::${column.data.jsonCast}` : ""}`
9319
+ ).join(", ")})`;
9320
+ } else {
9321
+ rowToJson = "row_to_json(t.*)";
9322
+ }
9323
+ return this.one ? rowToJson : this.coalesce !== false ? `COALESCE(json_agg(${rowToJson}), '[]')` : `json_agg(${rowToJson})`;
9324
+ }
9325
+ }
9326
+ function queryJson(self, coalesce) {
9327
+ const inner = self.clone();
9328
+ const q = queryWrap(inner, cloneQueryBaseUnscoped(inner));
9329
+ _queryGetOptional(
9330
+ q,
9331
+ new RowToJsonExpression(
9332
+ inner,
9333
+ queryTypeWithLimitOne[self.q.returnType],
9334
+ coalesce
9335
+ )
9336
+ );
9337
+ q.q.returnsOne = true;
9338
+ return q;
9339
+ }
9340
+
9341
+ const moveQueryToCte = (ctx, query, type, dontAddTableHook) => {
9342
+ const { returnType } = query.q;
9343
+ let valueAs;
9344
+ if (returnType === "value" || returnType === "valueOrThrow" || returnType === "pluck") {
9345
+ const first = query.q.select[0];
9346
+ if (first instanceof SelectItemExpression && typeof first.item === "string") {
9347
+ valueAs = first.item;
9348
+ } else {
9349
+ query = _clone(query);
9350
+ query.q.returnType = "one";
9351
+ query.q.select = [{ selectAs: { value: query.q.select[0] } }];
9352
+ valueAs = "value";
9353
+ }
9354
+ }
9355
+ const as = addTopCte("before", ctx, query, type, void 0, dontAddTableHook);
9356
+ const makeSelectList = (isSubSql) => {
9357
+ const list = [];
9358
+ let selectedCount = 0;
9359
+ if (valueAs) {
9360
+ selectedCount = 1;
9361
+ list.push(`"${as}"."${valueAs}"`);
9362
+ } else if (returnType !== "void") {
9363
+ const shape = getShapeFromSelect(query, true);
9364
+ const keys = Object.keys(shape);
9365
+ selectedCount = keys.length;
9366
+ list.push(...keys.map((key) => `"${as}"."${key}"`));
9367
+ }
9368
+ if (!isSubSql && ctx.topCtx.cteHooks?.hasSelect) {
9369
+ list.push("NULL::json");
9370
+ ctx.selectedCount = selectedCount;
9371
+ }
9372
+ return list;
9373
+ };
9374
+ return {
9375
+ as,
9376
+ makeSelectList
9377
+ };
9378
+ };
9379
+ const moveMutativeQueryToCteBase = (toSql, ctx, query, type = query.q.type) => {
9380
+ if (!query.q.type) {
9381
+ const as2 = getQueryAs(query);
9382
+ return {
9383
+ as: as2,
9384
+ makeSql: () => getSqlText(toSql(query, query.q.type, ctx, true))
9385
+ };
9386
+ }
9387
+ const { as, makeSelectList } = moveQueryToCte(ctx, query, type);
9388
+ return {
9389
+ as,
9390
+ // need to be called lazily for the upsert case because `ctx.cteHooks?.hasSelect` can change after the first query
9391
+ makeSql(isSubSql) {
9392
+ return "SELECT " + makeSelectList(isSubSql) + ` FROM "${as}"`;
9393
+ }
9394
+ };
9395
+ };
9396
+
9397
+ const addTableHook = (ctx, q, data, select, hookPurpose, dontAddTableHook) => {
9398
+ var _a, _b;
9399
+ if (data.ensureCount !== void 0 && ctx.cteName) {
9400
+ const cteHooks = setCteHooks(ctx, true);
9401
+ (cteHooks.ensureCount ?? (cteHooks.ensureCount = {}))[ctx.cteName] = { count: data.ensureCount };
9402
+ }
9403
+ const afterCreate = data.afterCreate;
9404
+ const afterUpdate = data.afterUpdate;
9405
+ const afterSave = data.afterSave;
9406
+ const afterDelete = data.afterDelete;
9407
+ const afterCreateCommit = data.afterCreateCommit;
9408
+ const afterUpdateCommit = data.afterUpdateCommit;
9409
+ const afterSaveCommit = data.afterSaveCommit;
9410
+ const afterDeleteCommit = data.afterDeleteCommit;
9411
+ const throwOnNotFound = (
9412
+ // Assuming that Create always returns a record, though needs to be cautions with onConflictDoNothing
9413
+ hookPurpose !== "Create" && (data.returnType === "oneOrThrow" || data.returnType === "valueOrThrow")
9414
+ );
9415
+ const hasAfterHook = afterCreate || afterUpdate || afterSave || afterDelete || afterCreateCommit || afterUpdateCommit || afterSaveCommit || afterDeleteCommit;
9416
+ if (!select && !hasAfterHook && !throwOnNotFound) {
9417
+ return;
9418
+ }
9419
+ const tableHook = {
9420
+ hookPurpose,
9421
+ select,
9422
+ afterCreate,
9423
+ afterUpdate,
9424
+ afterSave,
9425
+ afterDelete,
9426
+ afterCreateCommit,
9427
+ afterUpdateCommit,
9428
+ afterSaveCommit,
9429
+ afterDeleteCommit
9430
+ };
9431
+ if (ctx.cteName && !dontAddTableHook) {
9432
+ if (tableHook && (hasAfterHook || throwOnNotFound)) {
9433
+ const shape = {};
9434
+ if (tableHook.select) {
9435
+ for (const key of tableHook.select.keys()) {
9436
+ shape[key] = q.shape[key];
9437
+ }
9438
+ }
9439
+ const item = {
9440
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
9441
+ table: q.table,
9442
+ shape,
9443
+ tableHook,
9444
+ throwOnNotFound
9445
+ };
9446
+ const hasSelect = throwOnNotFound || !!tableHook.select;
9447
+ const cteHooks = setCteHooks(ctx, hasSelect);
9448
+ (_a = cteHooks.tableHooks ?? (cteHooks.tableHooks = {}))[_b = ctx.cteName] ?? (_a[_b] = item);
9449
+ }
9450
+ } else {
9451
+ ctx.topCtx.tableHook = tableHook;
9452
+ }
9084
9453
  };
9085
- const _get = (query, returnType, arg) => {
9086
- const q = query.q;
9087
- if (q.returning) q.returning = void 0;
9088
- q.returnType = returnType;
9089
- let type;
9090
- if (typeof arg === "string") {
9091
- const joinedAs = q.valuesJoinedAs?.[arg];
9092
- type = joinedAs ? q.joinedShapes?.[joinedAs]?.value : _getSelectableColumn(query, arg);
9093
- q.getColumn = type;
9094
- const selected = setParserForSelectedString(
9095
- query,
9096
- joinedAs ? joinedAs + "." + arg : arg,
9097
- getQueryAs(query),
9098
- getValueKey
9099
- );
9100
- q.select = selected ? [q.expr = new SelectItemExpression(query, selected, type)] : void 0;
9454
+ const setCteHooks = (ctx, hasSelect) => {
9455
+ if (hasSelect && ctx.topCtx.selectList && ctx.topCtx === ctx.topCtx.topCtx && !ctx.topCtx.cteHookTopNullSelectAppended) {
9456
+ ctx.topCtx.selectList.push("NULL");
9457
+ ctx.topCtx.cteHookTopNullSelectAppended = true;
9458
+ }
9459
+ if (ctx.topCtx.cteHooks) {
9460
+ if (hasSelect) ctx.topCtx.cteHooks.hasSelect = true;
9461
+ return ctx.topCtx.cteHooks;
9101
9462
  } else {
9102
- type = arg.result.value;
9103
- q.getColumn = type;
9104
- addParserForRawExpression(query, getValueKey, arg);
9105
- q.select = [q.expr = arg];
9463
+ return ctx.topCtx.cteHooks = {
9464
+ hasSelect
9465
+ };
9106
9466
  }
9107
- return setQueryOperators(
9108
- query,
9109
- type?.operators || Operators.any
9110
- );
9111
9467
  };
9112
- function _queryGet(self, arg) {
9113
- return _get(self, "valueOrThrow", arg);
9114
- }
9115
- function _queryGetOptional(self, arg) {
9116
- return _get(self, "value", arg);
9117
- }
9468
+ const ensureCTECount = (ctx, cteName, countItem) => {
9469
+ var _a;
9470
+ ((_a = setCteHooks(ctx, true)).ensureCount ?? (_a.ensureCount = {}))[cteName] = countItem;
9471
+ };
9118
9472
 
9119
- class RowToJsonExpression extends Expression {
9120
- constructor(from, one, coalesce) {
9121
- super();
9122
- this.from = from;
9123
- this.one = one;
9124
- this.coalesce = coalesce;
9125
- this.result = { value: UnknownColumn.instance };
9126
- this.q = { expr: this };
9473
+ const newMutativeQueriesSelectRelationsSqlState = (query) => query.q.selectRelation && {
9474
+ query
9475
+ };
9476
+ const setMutativeQueriesSelectRelationsSqlState = (d, as, rel) => {
9477
+ (d.value ?? (d.value = {}))[as] = rel;
9478
+ };
9479
+ const handleInsertAndUpdateSelectRelationsSqlState = (ctx, state) => {
9480
+ if (state) {
9481
+ ctx.topCtx.mutativeQueriesSelectRelationsSqlState = state;
9127
9482
  }
9128
- makeSQL(ctx) {
9129
- const q = this.from;
9130
- const aliases = [];
9131
- const jsonList = {};
9132
- const select = selectToSql(
9133
- ctx,
9134
- q,
9135
- q.q,
9136
- `"${getQueryAs(q)}"`,
9137
- q.q.hookSelect,
9138
- void 0,
9139
- aliases,
9140
- jsonList
9141
- );
9142
- q.q.selectCache = { sql: select, aliases };
9143
- let rowToJson;
9144
- if (Object.values(jsonList).some((x) => x?.data.jsonCast)) {
9145
- rowToJson = `json_build_object(${Object.entries(jsonList).map(
9146
- ([key, column]) => `'${key}', t."${key}"${column?.data.jsonCast ? `::${column.data.jsonCast}` : ""}`
9147
- ).join(", ")})`;
9148
- } else {
9149
- rowToJson = "row_to_json(t.*)";
9483
+ };
9484
+ const handleDeleteSelectRelationsSqlState = (ctx, query, relationSelectState, returning) => {
9485
+ const selectRelations = relationSelectState?.value;
9486
+ if (!selectRelations) return;
9487
+ const selectPrimaryKeysQuery = prepareSubQueryForSql(query, _clone(query));
9488
+ const primaryKeys = requirePrimaryKeys(
9489
+ query,
9490
+ "primary keys are required for selecting relation in delete"
9491
+ );
9492
+ _addToHookSelect(selectPrimaryKeysQuery, primaryKeys, true);
9493
+ const { as: cteAs } = moveQueryToCte(
9494
+ ctx,
9495
+ selectPrimaryKeysQuery,
9496
+ void 0,
9497
+ true
9498
+ );
9499
+ const relKeys = Object.keys(selectRelations);
9500
+ ctx.selectedCount = (returning ? ctx.selectedCount : 0) + relKeys.length;
9501
+ const hookSelect = selectPrimaryKeysQuery.q.hookSelect;
9502
+ const join = {
9503
+ type: "JOIN",
9504
+ args: {
9505
+ w: cteAs,
9506
+ a: [
9507
+ Object.fromEntries(
9508
+ primaryKeys.map((key) => {
9509
+ const selected = hookSelect.get(key);
9510
+ return [
9511
+ cteAs + "." + (selected.as || selected.select),
9512
+ key
9513
+ ];
9514
+ })
9515
+ )
9516
+ ]
9517
+ }
9518
+ };
9519
+ for (const relKey in selectRelations) {
9520
+ const rel = selectRelations[relKey];
9521
+ if (rel.q.returnType === "oneOrThrow" || rel.q.returnType === "valueOrThrow") {
9522
+ ensureCTECount(ctx, cteAs, { jsonNotNull: relKey });
9150
9523
  }
9151
- return this.one ? rowToJson : this.coalesce !== false ? `COALESCE(json_agg(${rowToJson}), '[]')` : `json_agg(${rowToJson})`;
9152
9524
  }
9153
- }
9154
- function queryJson(self, coalesce) {
9155
- const inner = self.clone();
9156
- const q = queryWrap(inner, cloneQueryBaseUnscoped(inner));
9157
- _queryGetOptional(
9158
- q,
9159
- new RowToJsonExpression(
9160
- inner,
9161
- queryTypeWithLimitOne[self.q.returnType],
9162
- coalesce
9163
- )
9164
- );
9165
- q.q.returnsOne = true;
9166
- return q;
9167
- }
9168
-
9169
- const newDelayedRelationSelect = (query) => ({
9170
- query
9171
- });
9172
- const setDelayedRelation = (d, as, value) => {
9173
- (d.value ?? (d.value = {}))[as] = value;
9525
+ return {
9526
+ join,
9527
+ joinedShape: cteAs,
9528
+ movedWhereToCte: true,
9529
+ addReturning: relKeys.map((key) => `${cteAs}."${key}"`).join(", ")
9530
+ };
9531
+ };
9532
+ const setMutativeQueriesSelectRelationsStateOnSql = (ctx, sql) => {
9533
+ sql.mutativeQueriesSelectRelationsState = ctx.topCtx.mutativeQueriesSelectRelationsSqlState;
9174
9534
  };
9175
9535
 
9176
9536
  const setSqlCtxSelectList = (ctx, table, query, quotedAs, isSubSql, aliases) => {
@@ -9269,7 +9629,11 @@ const selectToSqlList = (ctx, table, query, quotedAs, hookSelect = query.hookSel
9269
9629
  }
9270
9630
  aliases?.push(as);
9271
9631
  } else if (delayedRelationSelect && isRelationQuery(value)) {
9272
- setDelayedRelation(delayedRelationSelect, as, value);
9632
+ setMutativeQueriesSelectRelationsSqlState(
9633
+ delayedRelationSelect,
9634
+ as,
9635
+ value
9636
+ );
9273
9637
  } else {
9274
9638
  pushSubQuerySql(ctx, query, value, as, list, quotedAs, aliases);
9275
9639
  if (jsonList) {
@@ -9401,13 +9765,13 @@ const internalSelectAllSql = (ctx, query, quotedAs, jsonList) => {
9401
9765
  }
9402
9766
  let columnsCount;
9403
9767
  if (query.shape !== anyShape) {
9404
- let columnsCount2 = 0;
9768
+ columnsCount = 0;
9405
9769
  for (const key in query.shape) {
9406
9770
  if (!query.shape[key].data.explicitSelect) {
9407
- columnsCount2++;
9771
+ columnsCount++;
9408
9772
  }
9409
9773
  }
9410
- ctx.selectedCount += columnsCount2;
9774
+ ctx.selectedCount += columnsCount;
9411
9775
  }
9412
9776
  return selectAllSql(query, quotedAs, columnsCount);
9413
9777
  };
@@ -9778,134 +10142,6 @@ const pushIn = (ctx, query, ands, quotedAs, arg) => {
9778
10142
 
9779
10143
  const MAX_BINDING_PARAMS = 65536;
9780
10144
 
9781
- const addTableHook = (ctx, q, data, select, hookPurpose) => {
9782
- var _a, _b;
9783
- if (data.ensureCount !== void 0 && ctx.cteName) {
9784
- const cteHooks = setCteHooks(ctx, true);
9785
- (cteHooks.ensureCount ?? (cteHooks.ensureCount = {}))[ctx.cteName] = data.ensureCount;
9786
- }
9787
- const afterCreate = data.afterCreate;
9788
- const afterUpdate = data.afterUpdate;
9789
- const afterSave = data.afterSave;
9790
- const afterDelete = data.afterDelete;
9791
- const afterCreateCommit = data.afterCreateCommit;
9792
- const afterUpdateCommit = data.afterUpdateCommit;
9793
- const afterSaveCommit = data.afterSaveCommit;
9794
- const afterDeleteCommit = data.afterDeleteCommit;
9795
- const throwOnNotFound = (
9796
- // Assuming that Create always returns a record, though needs to be cautions with onConflictDoNothing
9797
- hookPurpose !== "Create" && (data.returnType === "oneOrThrow" || data.returnType === "valueOrThrow")
9798
- );
9799
- const hasAfterHook = afterCreate || afterUpdate || afterSave || afterDelete || afterCreateCommit || afterUpdateCommit || afterSaveCommit || afterDeleteCommit;
9800
- if (!select && !hasAfterHook && !throwOnNotFound) {
9801
- return;
9802
- }
9803
- const tableHook = {
9804
- hookPurpose,
9805
- select,
9806
- afterCreate,
9807
- afterUpdate,
9808
- afterSave,
9809
- afterDelete,
9810
- afterCreateCommit,
9811
- afterUpdateCommit,
9812
- afterSaveCommit,
9813
- afterDeleteCommit
9814
- };
9815
- if (ctx.cteName) {
9816
- if (tableHook && (hasAfterHook || throwOnNotFound)) {
9817
- const shape = {};
9818
- if (tableHook.select) {
9819
- for (const key of tableHook.select.keys()) {
9820
- shape[key] = q.shape[key];
9821
- }
9822
- }
9823
- const item = {
9824
- table: q.table,
9825
- shape,
9826
- tableHook,
9827
- throwOnNotFound
9828
- };
9829
- const hasSelect = throwOnNotFound || !!tableHook.select;
9830
- const cteHooks = setCteHooks(ctx, hasSelect);
9831
- (_a = cteHooks.tableHooks)[_b = ctx.cteName] ?? (_a[_b] = item);
9832
- }
9833
- } else {
9834
- ctx.topCtx.tableHook = tableHook;
9835
- }
9836
- };
9837
- const setCteHooks = (ctx, hasSelect) => {
9838
- if (hasSelect && ctx.topCtx.selectList && ctx.topCtx === ctx.topCtx.topCtx && !ctx.topCtx.cteHookTopNullSelectAppended) {
9839
- ctx.topCtx.selectList.push("NULL");
9840
- ctx.topCtx.cteHookTopNullSelectAppended = true;
9841
- }
9842
- if (ctx.topCtx.cteHooks) {
9843
- if (hasSelect) ctx.topCtx.cteHooks.hasSelect = true;
9844
- return ctx.topCtx.cteHooks;
9845
- } else {
9846
- return ctx.topCtx.cteHooks = {
9847
- hasSelect,
9848
- tableHooks: {}
9849
- };
9850
- }
9851
- };
9852
-
9853
- const moveQueryToCte = (ctx, query, type = query.q.type) => {
9854
- const { returnType } = query.q;
9855
- let valueAs;
9856
- if (returnType === "value" || returnType === "valueOrThrow" || returnType === "pluck") {
9857
- const first = query.q.select[0];
9858
- if (first instanceof SelectItemExpression && typeof first.item === "string") {
9859
- valueAs = first.item;
9860
- } else {
9861
- query = _clone(query);
9862
- query.q.returnType = "one";
9863
- query.q.select = [{ selectAs: { value: query.q.select[0] } }];
9864
- valueAs = "value";
9865
- }
9866
- }
9867
- const as = addTopCte("before", ctx, query, void 0, type);
9868
- const makeSelectList = (isSubSql) => {
9869
- const list = [];
9870
- let selectedCount = 0;
9871
- if (valueAs) {
9872
- selectedCount = 1;
9873
- list.push(`"${as}"."${valueAs}"`);
9874
- } else if (returnType !== "void") {
9875
- const shape = getShapeFromSelect(query, true);
9876
- const keys = Object.keys(shape);
9877
- selectedCount = keys.length;
9878
- list.push(...keys.map((key) => `"${as}"."${key}"`));
9879
- }
9880
- if (!isSubSql && ctx.topCtx.cteHooks?.hasSelect) {
9881
- list.push("NULL::json");
9882
- ctx.selectedCount = selectedCount;
9883
- }
9884
- return list;
9885
- };
9886
- return {
9887
- as,
9888
- makeSelectList
9889
- };
9890
- };
9891
- const moveMutativeQueryToCteBase = (toSql, ctx, query, type = query.q.type) => {
9892
- if (!query.q.type) {
9893
- const as2 = getQueryAs(query);
9894
- return {
9895
- as: as2,
9896
- makeSql: () => getSqlText(toSql(query, query.q.type, ctx, true))
9897
- };
9898
- }
9899
- const { as, makeSelectList } = moveQueryToCte(ctx, query, type);
9900
- return {
9901
- as,
9902
- // need to be called lazily for the upsert case because `ctx.cteHooks?.hasSelect` can change after the first query
9903
- makeSql(isSubSql) {
9904
- return "SELECT " + makeSelectList(isSubSql) + ` FROM "${as}"`;
9905
- }
9906
- };
9907
- };
9908
-
9909
10145
  const makeInsertSql = (ctx, q, query, quotedAs, isSubSql) => {
9910
10146
  let { columns } = query;
9911
10147
  const { shape, hookCreateSet } = query;
@@ -9974,7 +10210,7 @@ const makeInsertSql = (ctx, q, query, quotedAs, isSubSql) => {
9974
10210
  if (upsert || insertFrom && !isRelationQuery(q) || hasOnConflictWhere) {
9975
10211
  pushWhereStatementSql(ctx, q, query, quotedAs);
9976
10212
  }
9977
- sqlState.delayedRelationSelect = q.q.selectRelation ? newDelayedRelationSelect(q) : void 0;
10213
+ sqlState.relationSelectState = newMutativeQueriesSelectRelationsSqlState(q);
9978
10214
  sqlState.returningPos = ctx.sql.length;
9979
10215
  let insertManyFromValuesAs;
9980
10216
  if (insertFrom) {
@@ -9998,7 +10234,11 @@ const makeInsertSql = (ctx, q, query, quotedAs, isSubSql) => {
9998
10234
  }
9999
10235
  ctx.sql[1] = moveMutativeQueryToCte(ctx, q2);
10000
10236
  } else {
10001
- const { as, makeSelectList } = moveQueryToCte(ctx, insertFrom);
10237
+ const { as, makeSelectList } = moveQueryToCte(
10238
+ ctx,
10239
+ insertFrom,
10240
+ insertFrom.q.type
10241
+ );
10002
10242
  const selectList = makeSelectList(true);
10003
10243
  insertManyFromValuesAs = query.insertValuesAs;
10004
10244
  selectList.push(
@@ -10064,18 +10304,20 @@ const makeInsertSql = (ctx, q, query, quotedAs, isSubSql) => {
10064
10304
  }
10065
10305
  applySqlState(sqlState);
10066
10306
  batch.push(composeCteSingleSql(ctx));
10067
- if (sqlState.delayedRelationSelect) {
10068
- ctx.topCtx.delayedRelationSelect = sqlState.delayedRelationSelect;
10069
- }
10307
+ handleInsertAndUpdateSelectRelationsSqlState(
10308
+ ctx,
10309
+ sqlState.relationSelectState
10310
+ );
10070
10311
  return {
10071
10312
  batch
10072
10313
  };
10073
10314
  }
10074
10315
  }
10075
10316
  applySqlState(sqlState);
10076
- if (sqlState.delayedRelationSelect) {
10077
- ctx.topCtx.delayedRelationSelect = sqlState.delayedRelationSelect;
10078
- }
10317
+ handleInsertAndUpdateSelectRelationsSqlState(
10318
+ ctx,
10319
+ sqlState.relationSelectState
10320
+ );
10079
10321
  return {
10080
10322
  text: ctx.sql.join(" "),
10081
10323
  values: ctx.values
@@ -10162,7 +10404,7 @@ const applySqlState = (sqlState) => {
10162
10404
  sqlState.q,
10163
10405
  sqlState.query,
10164
10406
  sqlState.quotedAs,
10165
- sqlState.delayedRelationSelect,
10407
+ sqlState.relationSelectState,
10166
10408
  "Create",
10167
10409
  void 0,
10168
10410
  sqlState.isSubSql || !!ctx.topCtx.cteHooks
@@ -10345,7 +10587,7 @@ const encodeValue = (ctx, values, QueryClass, value, quotedAs) => {
10345
10587
  }
10346
10588
  return value === void 0 ? "DEFAULT" : addValue(values, value);
10347
10589
  };
10348
- const makeReturningSql = (ctx, q, data, quotedAs, delayedRelationSelect, hookPurpose, addHookPurpose, isSubSql) => {
10590
+ const makeReturningSql = (ctx, q, data, quotedAs, relationSelectState, hookPurpose, addHookPurpose, isSubSql) => {
10349
10591
  const hookSelect = hookPurpose && data[`after${hookPurpose}Select`];
10350
10592
  const { select } = data;
10351
10593
  if (!q.q.hookSelect && !hookSelect?.size && !select?.length && !hookPurpose) {
@@ -10354,7 +10596,7 @@ const makeReturningSql = (ctx, q, data, quotedAs, delayedRelationSelect, hookPur
10354
10596
  ctx.selectedCount = 1;
10355
10597
  return returnSqlOrNull(ctx, q, isSubSql);
10356
10598
  }
10357
- const otherCTEHookSelect = addHookPurpose && data[`after${addHookPurpose}Select`];
10599
+ const otherCTEHookSelect = addHookPurpose;
10358
10600
  let tempSelect;
10359
10601
  if (q.q.hookSelect || hookSelect || otherCTEHookSelect || q.q.selectRelation) {
10360
10602
  tempSelect = new Map(q.q.hookSelect);
@@ -10365,14 +10607,7 @@ const makeReturningSql = (ctx, q, data, quotedAs, delayedRelationSelect, hookPur
10365
10607
  }
10366
10608
  }
10367
10609
  }
10368
- if (otherCTEHookSelect) {
10369
- for (const column of otherCTEHookSelect) {
10370
- if (!tempSelect.has(column)) {
10371
- tempSelect.set(column, { select: column });
10372
- }
10373
- }
10374
- }
10375
- if (q.q.selectRelation) {
10610
+ if (q.q.selectRelation && hookPurpose !== "Delete") {
10376
10611
  for (const column of getPrimaryKeys(q)) {
10377
10612
  if (!tempSelect.has(column)) {
10378
10613
  tempSelect.set(column, { select: column });
@@ -10391,7 +10626,7 @@ const makeReturningSql = (ctx, q, data, quotedAs, delayedRelationSelect, hookPur
10391
10626
  isSubSql,
10392
10627
  void 0,
10393
10628
  void 0,
10394
- delayedRelationSelect
10629
+ relationSelectState
10395
10630
  );
10396
10631
  }
10397
10632
  addTableHook(ctx, q, data, tempSelect, hookPurpose);
@@ -10435,7 +10670,7 @@ const pushUpdateSql = (ctx, query, q, quotedAs, isSubSql) => {
10435
10670
  const hookSet = q.hookUpdateSet ? Object.fromEntries(
10436
10671
  q.hookUpdateSet.flatMap((item) => Object.entries(item))
10437
10672
  ) : emptyObject;
10438
- const delayedRelationSelect = q.selectRelation ? newDelayedRelationSelect(query) : void 0;
10673
+ const relationSelectState = newMutativeQueriesSelectRelationsSqlState(query);
10439
10674
  const usedSetKeys = /* @__PURE__ */ new Set();
10440
10675
  if (q.hookUpdateSet) {
10441
10676
  applySet(ctx, query, set, hookSet, emptyObject, usedSetKeys, quotedAs);
@@ -10467,7 +10702,7 @@ const pushUpdateSql = (ctx, query, q, quotedAs, isSubSql) => {
10467
10702
  from,
10468
10703
  isSubSql,
10469
10704
  updateManyValuesSql,
10470
- delayedRelationSelect
10705
+ relationSelectState
10471
10706
  );
10472
10707
  } else {
10473
10708
  ctx.sql.push(`UPDATE ${from}`);
@@ -10491,16 +10726,14 @@ const pushUpdateSql = (ctx, query, q, quotedAs, isSubSql) => {
10491
10726
  q,
10492
10727
  quotedAs,
10493
10728
  "RETURNING",
10494
- delayedRelationSelect,
10729
+ relationSelectState,
10495
10730
  isSubSql
10496
10731
  );
10497
10732
  }
10498
- if (delayedRelationSelect) {
10499
- ctx.topCtx.delayedRelationSelect = delayedRelationSelect;
10500
- }
10733
+ handleInsertAndUpdateSelectRelationsSqlState(ctx, relationSelectState);
10501
10734
  return makeSql(ctx, "update", isSubSql);
10502
10735
  };
10503
- const pushSelectForEmptySet = (ctx, query, q, quotedAs, from, isSubSql, updateManyValuesSql, delayedRelationSelect) => {
10736
+ const pushSelectForEmptySet = (ctx, query, q, quotedAs, from, isSubSql, updateManyValuesSql, relationSelectState) => {
10504
10737
  if (!q.select) {
10505
10738
  q.select = countSelect;
10506
10739
  }
@@ -10510,7 +10743,7 @@ const pushSelectForEmptySet = (ctx, query, q, quotedAs, from, isSubSql, updateMa
10510
10743
  q,
10511
10744
  quotedAs,
10512
10745
  "SELECT",
10513
- delayedRelationSelect,
10746
+ relationSelectState,
10514
10747
  isSubSql
10515
10748
  );
10516
10749
  let fromSql = `FROM ${from}`;
@@ -10522,15 +10755,9 @@ const pushSelectForEmptySet = (ctx, query, q, quotedAs, from, isSubSql, updateMa
10522
10755
  pushLimitSQL(ctx.sql, ctx.values, q);
10523
10756
  };
10524
10757
  const addUpdateManyCteForStrict = (ctx, updateMany) => {
10525
- var _a;
10526
10758
  const wrapAs = setFreeTopCteAs(ctx);
10527
10759
  ctx.wrapAs = wrapAs;
10528
- const cteHooks = (_a = ctx.topCtx).cteHooks ?? (_a.cteHooks = {
10529
- hasSelect: true,
10530
- tableHooks: {}
10531
- });
10532
- cteHooks.hasSelect = true;
10533
- (cteHooks.ensureCount ?? (cteHooks.ensureCount = {}))[wrapAs] = updateMany.data.length;
10760
+ ensureCTECount(ctx, wrapAs, { count: updateMany.data.length });
10534
10761
  };
10535
10762
  const pushUpdateFromSql = (ctx, query, q, quotedAs, updateFrom) => {
10536
10763
  const { target, on } = processJoinItem(ctx, query, q, updateFrom, quotedAs);
@@ -10566,13 +10793,13 @@ const pushUpdateWhereSql = (ctx, query, q, quotedAs, fromWhereSql) => {
10566
10793
  ctx.sql.push("WHERE", whereSql);
10567
10794
  }
10568
10795
  };
10569
- const pushUpdateReturning = (ctx, query, q, quotedAs, keyword, delayedRelationSelect, isSubSql) => {
10796
+ const pushUpdateReturning = (ctx, query, q, quotedAs, keyword, relationSelectState, isSubSql) => {
10570
10797
  const returning = makeReturningSql(
10571
10798
  ctx,
10572
10799
  query,
10573
10800
  q,
10574
10801
  quotedAs,
10575
- delayedRelationSelect,
10802
+ relationSelectState,
10576
10803
  "Update",
10577
10804
  void 0,
10578
10805
  isSubSql
@@ -10698,12 +10925,41 @@ const pushDeleteSql = (ctx, query, q, quotedAs, isSubSql) => {
10698
10925
  if (q.as && query.table !== q.as) {
10699
10926
  ctx.sql.push(quotedAs);
10700
10927
  }
10928
+ const relationSelectState = newMutativeQueriesSelectRelationsSqlState(query);
10929
+ let returning = makeReturningSql(
10930
+ ctx,
10931
+ query,
10932
+ q,
10933
+ quotedAs,
10934
+ relationSelectState,
10935
+ "Delete",
10936
+ void 0,
10937
+ isSubSql
10938
+ );
10939
+ const selectRelations = handleDeleteSelectRelationsSqlState(
10940
+ ctx,
10941
+ query,
10942
+ relationSelectState,
10943
+ returning
10944
+ );
10945
+ let join = q.join;
10946
+ if (selectRelations) {
10947
+ returning = (returning ? returning + ", " : "") + selectRelations.addReturning;
10948
+ join = join ? [...join, selectRelations.join] : [selectRelations.join];
10949
+ q = {
10950
+ ...q,
10951
+ joinedShapes: {
10952
+ ...q.joinedShapes,
10953
+ [selectRelations.joinedShape]: anyShape
10954
+ }
10955
+ };
10956
+ }
10701
10957
  let conditions;
10702
- if (q.join?.length) {
10958
+ if (join?.length) {
10703
10959
  const targets = [];
10704
10960
  const ons = [];
10705
- const joinSet = q.join.length > 1 ? /* @__PURE__ */ new Set() : null;
10706
- for (const item of q.join) {
10961
+ const joinSet = join.length > 1 ? /* @__PURE__ */ new Set() : null;
10962
+ for (const item of join) {
10707
10963
  const lateral = "l" in item.args && item.args.l;
10708
10964
  if (lateral) {
10709
10965
  if (isRelationQuery(lateral)) {
@@ -10714,42 +10970,32 @@ const pushDeleteSql = (ctx, query, q, quotedAs, isSubSql) => {
10714
10970
  "Join lateral is not supported in delete"
10715
10971
  );
10716
10972
  }
10717
- const join = processJoinItem(ctx, query, q, item.args, quotedAs);
10718
- const key = `${join.target}${join.on}`;
10973
+ const join2 = processJoinItem(ctx, query, q, item.args, quotedAs);
10974
+ const key = `${join2.target}${join2.on}`;
10719
10975
  if (joinSet) {
10720
10976
  if (joinSet.has(key)) continue;
10721
10977
  joinSet.add(key);
10722
10978
  }
10723
- targets.push(join.target);
10724
- if (join.on) ons.push(join.on);
10979
+ targets.push(join2.target);
10980
+ if (join2.on) ons.push(join2.on);
10725
10981
  }
10726
10982
  if (targets.length) {
10727
10983
  ctx.sql.push(`USING ${targets.join(", ")}`);
10728
10984
  }
10729
10985
  conditions = ons.join(" AND ");
10730
10986
  }
10731
- pushWhereStatementSql(ctx, query, q, quotedAs);
10987
+ if (!selectRelations?.movedWhereToCte) {
10988
+ pushWhereStatementSql(ctx, query, q, quotedAs);
10989
+ }
10732
10990
  if (conditions) {
10733
- if (q.and?.length || q.or?.length || q.scopes) {
10991
+ if (!selectRelations?.movedWhereToCte && (q.and?.length || q.or?.length || q.scopes)) {
10734
10992
  ctx.sql.push("AND", conditions);
10735
10993
  } else {
10736
10994
  ctx.sql.push("WHERE", conditions);
10737
10995
  }
10738
10996
  }
10739
- const delayedRelationSelect = q.selectRelation ? newDelayedRelationSelect(query) : void 0;
10740
- const returning = makeReturningSql(
10741
- ctx,
10742
- query,
10743
- q,
10744
- quotedAs,
10745
- delayedRelationSelect,
10746
- "Delete",
10747
- void 0,
10748
- isSubSql
10749
- );
10750
- if (returning) ctx.sql.push("RETURNING", returning);
10751
- if (delayedRelationSelect) {
10752
- ctx.topCtx.delayedRelationSelect = delayedRelationSelect;
10997
+ if (returning) {
10998
+ ctx.sql.push("RETURNING", returning);
10753
10999
  }
10754
11000
  return makeSql(ctx, "delete", isSubSql);
10755
11001
  };
@@ -11009,7 +11255,19 @@ const pushForSql = (ctx, q, type, quotedAs) => {
11009
11255
  }
11010
11256
  };
11011
11257
 
11012
- const toSql = (table, type, topCtx, isSubSql, cteName, calledByThen) => {
11258
+ const newToSqlCtx = (query) => {
11259
+ const ctx = {
11260
+ topCtx: void 0,
11261
+ qb: query.qb,
11262
+ q: query.q,
11263
+ sql: [],
11264
+ values: [],
11265
+ selectedCount: 0
11266
+ };
11267
+ ctx.topCtx = ctx;
11268
+ return ctx;
11269
+ };
11270
+ const toSql = (table, type, topCtx, isSubSql, cteName, calledByThen, dontAddTableHook) => {
11013
11271
  const query = table.q;
11014
11272
  const sql = [];
11015
11273
  const values = topCtx?.values || [];
@@ -11189,7 +11447,14 @@ const toSql = (table, type, topCtx, isSubSql, cteName, calledByThen) => {
11189
11447
  }
11190
11448
  pushLimitOffsetSql(ctx, query, fromQuery);
11191
11449
  pushForSql(ctx, query, type, quotedAs);
11192
- addTableHook(ctx, table, query, query.hookSelect);
11450
+ addTableHook(
11451
+ ctx,
11452
+ table,
11453
+ query,
11454
+ query.hookSelect,
11455
+ void 0,
11456
+ dontAddTableHook
11457
+ );
11193
11458
  if (selectSqlPos !== void 0 && ctx.selectList?.length) {
11194
11459
  sql[selectSqlPos] += " " + ctx.selectList.join(", ");
11195
11460
  }
@@ -11202,7 +11467,7 @@ const toSql = (table, type, topCtx, isSubSql, cteName, calledByThen) => {
11202
11467
  if (!ctx.cteName) {
11203
11468
  result.tableHook = ctx.topCtx.tableHook;
11204
11469
  if (!topCtx) {
11205
- result.delayedRelationSelect = ctx.topCtx.delayedRelationSelect;
11470
+ setMutativeQueriesSelectRelationsStateOnSql(ctx, result);
11206
11471
  }
11207
11472
  }
11208
11473
  if (!isSubSql) {
@@ -11212,21 +11477,20 @@ const toSql = (table, type, topCtx, isSubSql, cteName, calledByThen) => {
11212
11477
  if (prependedSelectParenthesis) {
11213
11478
  result.text += ")";
11214
11479
  }
11215
- const keyValues = Object.entries(ctx.topCtx.cteHooks.tableHooks).map(
11216
- ([cteName2, data]) => `'${cteName2}', (SELECT json_agg(${makeRowToJson(
11217
- cteName2,
11218
- data.shape,
11219
- false,
11220
- true
11221
- )}) FROM "${cteName2}")`
11222
- );
11223
- if (ctx.topCtx.cteHooks.ensureCount) {
11224
- keyValues.push(
11225
- ...Object.entries(ctx.topCtx.cteHooks.ensureCount).map(
11226
- ([cteName2, count]) => `'#${cteName2}', CASE WHEN (SELECT count(*) FROM "${cteName2}") < ${count} THEN (SELECT 'not-found')::int END`
11227
- )
11228
- );
11229
- }
11480
+ const { tableHooks, ensureCount } = ctx.topCtx.cteHooks;
11481
+ const keyValues = [
11482
+ ...tableHooks ? Object.entries(tableHooks).map(
11483
+ ([cteName2, data]) => `'${cteName2}', (SELECT json_agg(${makeRowToJson(
11484
+ cteName2,
11485
+ data.shape,
11486
+ false,
11487
+ true
11488
+ )}) FROM "${cteName2}")`
11489
+ ) : emptyArray$1,
11490
+ ...ensureCount ? Object.entries(ensureCount).map(
11491
+ ([cteName2, item]) => `'#${cteName2}', CASE WHEN ${"count" in item ? `(SELECT count(*) FROM "${cteName2}") < ${item.count}` : `(SELECT "${cteName2}"."${item.jsonNotNull}" FROM "${cteName2}") IS NULL`} THEN (SELECT 'not-found')::int END`
11492
+ ) : emptyArray$1
11493
+ ];
11230
11494
  result.text += ` UNION ALL SELECT ${"NULL, ".repeat(
11231
11495
  ctx.selectedCount || 0
11232
11496
  )}json_build_object(${keyValues.join(", ")})`;
@@ -11259,13 +11523,13 @@ const ctesToSql = (ctx, ctes) => {
11259
11523
  for (const item of ctes) {
11260
11524
  const place = item.p ? "before" : "after";
11261
11525
  if (ctx !== ctx.topCtx && item.q?.q.type) {
11262
- addTopCte(place, ctx, item.q, item.n);
11526
+ addTopCte(place, ctx, item.q, item.q.q.type, item.n);
11263
11527
  } else {
11264
- addTopCteInternal(place, ctx, item);
11528
+ addTopCteInternal(place, ctx, item, item.q?.q.type);
11265
11529
  }
11266
11530
  }
11267
11531
  };
11268
- const cteToSqlGiveAs = (ctx, item, type) => {
11532
+ const cteToSqlGiveAs = (ctx, item, type, dontAddTableHook) => {
11269
11533
  var _a;
11270
11534
  let inner;
11271
11535
  let as;
@@ -11282,13 +11546,7 @@ const cteToSqlGiveAs = (ctx, item, type) => {
11282
11546
  }
11283
11547
  if (item.q) {
11284
11548
  inner = getSqlText(
11285
- toSql(
11286
- item.q,
11287
- type === void 0 ? item.q.q.type : type,
11288
- ctx.topCtx,
11289
- true,
11290
- as
11291
- )
11549
+ toSql(item.q, type, ctx.topCtx, true, as, void 0, dontAddTableHook)
11292
11550
  );
11293
11551
  } else {
11294
11552
  inner = item.s.toSQL(ctx.topCtx, `"${as}"`);
@@ -11299,7 +11557,7 @@ const cteToSqlGiveAs = (ctx, item, type) => {
11299
11557
  sql: `${o.recursive ? "RECURSIVE " : ""}"${as}"${o.columns ? `(${o.columns.map((x) => `"${x}"`).join(", ")})` : ""} AS ${o.materialized ? "MATERIALIZED " : o.notMaterialized ? "NOT MATERIALIZED " : ""}(${inner})`
11300
11558
  };
11301
11559
  };
11302
- const cteToSql = (ctx, item, type) => cteToSqlGiveAs(ctx, item, type).sql;
11560
+ const cteToSql = (ctx, item, type, dontAddTableHook) => cteToSqlGiveAs(ctx, item, type, dontAddTableHook).sql;
11303
11561
  const setFreeTopCteAs = (ctx) => {
11304
11562
  var _a;
11305
11563
  const topCTE = (_a = ctx.topCtx).topCTE ?? (_a.topCTE = newTopCte(ctx));
@@ -11316,7 +11574,7 @@ const addTopCteSql = (ctx, as, sql) => {
11316
11574
  target.push(as + " AS (" + sql + ")");
11317
11575
  return as;
11318
11576
  };
11319
- const addTopCte = (place, ctx, q, as, type) => {
11577
+ const addTopCte = (place, ctx, q, type, as, dontAddTableHook) => {
11320
11578
  var _a;
11321
11579
  const topCTE = (_a = ctx.topCtx).topCTE ?? (_a.topCTE = newTopCte(ctx));
11322
11580
  if (typeof as !== "string") {
@@ -11326,16 +11584,16 @@ const addTopCte = (place, ctx, q, as, type) => {
11326
11584
  }
11327
11585
  as = name;
11328
11586
  }
11329
- addTopCteInternal(place, ctx, { n: as, q }, type);
11587
+ addTopCteInternal(place, ctx, { n: as, q }, type, dontAddTableHook);
11330
11588
  return as;
11331
11589
  };
11332
- const addTopCteInternal = (place, ctx, item, type) => {
11590
+ const addTopCteInternal = (place, ctx, item, type, dontAddTableHook) => {
11333
11591
  var _a;
11334
11592
  const topCTE = (_a = ctx.topCtx).topCTE ?? (_a.topCTE = newTopCte(ctx));
11335
11593
  const target = place === "before" && topCTE.stack[topCTE.stack.length - 1] || (topCTE.append[topCTE.append.length] = []);
11336
11594
  const prepend = [];
11337
11595
  topCTE.stack.push(prepend);
11338
- const sql = cteToSql(ctx, item, type);
11596
+ const sql = cteToSql(ctx, item, type, dontAddTableHook);
11339
11597
  target.push(...prepend, sql);
11340
11598
  topCTE.stack.pop();
11341
11599
  };
@@ -14194,54 +14452,6 @@ class MergeQueryMethods {
14194
14452
  }
14195
14453
  }
14196
14454
 
14197
- class QueryScope {
14198
- /**
14199
- * See {@link QueryScope}
14200
- *
14201
- * Use the `scope` method to apply a pre-defined scope.
14202
- *
14203
- * ```ts
14204
- * // use the `active` scope that is defined in the table:
14205
- * await db.some.scope('active');
14206
- * ```
14207
- *
14208
- * @param scope - name of the scope to apply
14209
- */
14210
- scope(scope) {
14211
- const q = _clone(this);
14212
- if (!q.q.scopes?.[scope]) {
14213
- const s = q.internal.scopes[scope];
14214
- if (!s) throw new Error(`Scope ${scope} is not defined`);
14215
- setObjectValueImmutable(q.q, "scopes", scope, s);
14216
- }
14217
- return q;
14218
- }
14219
- /**
14220
- * See {@link QueryScope}
14221
- *
14222
- * Remove conditions that were added by the scope from the query.
14223
- *
14224
- * ```ts
14225
- * // SomeTable has a default scope, ignore it for this query:
14226
- * await db.some.unscope('default');
14227
- * ```
14228
- *
14229
- * @param scope - name of the scope to remove from the query
14230
- */
14231
- unscope(scope) {
14232
- const q = _clone(this);
14233
- if (q.q.scopes) {
14234
- q.q.scopes = { ...q.q.scopes };
14235
- delete q.q.scopes[scope];
14236
- for (const _ in q.q.scopes) {
14237
- return q;
14238
- }
14239
- delete q.q.scopes;
14240
- }
14241
- return q;
14242
- }
14243
- }
14244
-
14245
14455
  const DEFAULT_PRIVILEGE = {
14246
14456
  OBJECT_TYPES: [
14247
14457
  "TABLES",
@@ -14792,7 +15002,7 @@ class SoftDeleteMethods {
14792
15002
  * ```
14793
15003
  */
14794
15004
  includeDeleted() {
14795
- return this.unscope("nonDeleted");
15005
+ return _unscope(_clone(this), "nonDeleted");
14796
15006
  }
14797
15007
  /**
14798
15008
  * `hardDelete` deletes records bypassing the `softDelete` behavior:
@@ -14802,7 +15012,7 @@ class SoftDeleteMethods {
14802
15012
  * ```
14803
15013
  */
14804
15014
  hardDelete(..._args) {
14805
- return _queryDelete(_clone(this).unscope("nonDeleted"));
15015
+ return _queryDelete(_unscope(_clone(this), "nonDeleted"));
14806
15016
  }
14807
15017
  }
14808
15018
 
@@ -15560,108 +15770,6 @@ applyMixins(QueryMethods, [
15560
15770
  QueryWindow
15561
15771
  ]);
15562
15772
 
15563
- const makeIndex = (columns, first, second) => {
15564
- if (typeof first === "string") {
15565
- const options = { ...second, name: first };
15566
- return {
15567
- index: { columns, options }
15568
- };
15569
- } else {
15570
- const options = first ?? {};
15571
- return {
15572
- index: { columns, options }
15573
- };
15574
- }
15575
- };
15576
- const tableDataMethods = {
15577
- primaryKey(columns, name) {
15578
- return { primaryKey: { columns, name } };
15579
- },
15580
- unique(columns, ...args) {
15581
- const [first, second] = args;
15582
- const input = makeIndex(columns, first, second);
15583
- input.index.options.unique = true;
15584
- return input;
15585
- },
15586
- index: makeIndex,
15587
- searchIndex(columns, ...args) {
15588
- var _a;
15589
- const [first, second] = args;
15590
- const input = makeIndex(columns, first, second);
15591
- (_a = input.index.options).using ?? (_a.using = "gin");
15592
- input.index.options.tsVector = true;
15593
- return input;
15594
- },
15595
- exclude(columns, ...args) {
15596
- const [first, second] = args;
15597
- if (typeof first === "string") {
15598
- const options = second ?? {};
15599
- return {
15600
- exclude: { columns, options: { ...options, name: first } }
15601
- };
15602
- } else {
15603
- const options = first ?? {};
15604
- return {
15605
- exclude: { columns, options }
15606
- };
15607
- }
15608
- },
15609
- foreignKey(columns, fnOrTable, foreignColumns, options) {
15610
- return {
15611
- constraint: {
15612
- name: options?.name,
15613
- references: { columns, fnOrTable, foreignColumns, options }
15614
- }
15615
- };
15616
- },
15617
- check(check, name) {
15618
- return { constraint: { check, name } };
15619
- },
15620
- sql: sqlFn
15621
- };
15622
- const parseTableData = (dataFn) => {
15623
- const tableData = {};
15624
- if (dataFn) {
15625
- const input = dataFn(tableDataMethods);
15626
- if (Array.isArray(input)) {
15627
- for (const item of input) {
15628
- parseTableDataInput(tableData, item);
15629
- }
15630
- } else {
15631
- parseTableDataInput(tableData, input);
15632
- }
15633
- }
15634
- return tableData;
15635
- };
15636
- const parseTableDataInput = (tableData, item) => {
15637
- if (item.primaryKey) {
15638
- tableData.primaryKey = item.primaryKey;
15639
- } else if (item.index) {
15640
- (tableData.indexes ?? (tableData.indexes = [])).push(
15641
- parseIndexOrExclude(item.index)
15642
- );
15643
- } else if (item.exclude) {
15644
- (tableData.excludes ?? (tableData.excludes = [])).push(
15645
- parseIndexOrExclude(item.exclude)
15646
- );
15647
- } else if (item.constraint) {
15648
- (tableData.constraints ?? (tableData.constraints = [])).push(item.constraint);
15649
- if (item.constraint.references?.options?.dropMode) {
15650
- item.constraint.dropMode = item.constraint.references.options.dropMode;
15651
- }
15652
- }
15653
- };
15654
- const parseIndexOrExclude = (item) => {
15655
- for (let i = item.columns.length - 1; i >= 0; i--) {
15656
- if (typeof item.columns[i] === "string") {
15657
- item.columns[i] = {
15658
- column: item.columns[i]
15659
- };
15660
- }
15661
- }
15662
- return item;
15663
- };
15664
-
15665
15773
  const performQuery = async (q, args, method) => {
15666
15774
  const trx = q.internal.asyncStorage.getStore();
15667
15775
  let sql;
@@ -16083,6 +16191,126 @@ const _initQueryBuilder = (adapter, columnTypes, asyncStorage, commonOptions, op
16083
16191
  return qb.qb = qb;
16084
16192
  };
16085
16193
 
16194
+ const setConnectRetryConfig = (adapter, config) => {
16195
+ adapter.connectRetryConfig = {
16196
+ attempts: config.attempts ?? 10,
16197
+ strategy: typeof config.strategy === "function" ? config.strategy : defaultConnectRetryStrategy(config.strategy ?? emptyObject)
16198
+ };
16199
+ };
16200
+ const wrapAdapterFnWithConnectRetry = (adapter, fn) => {
16201
+ return async function(...args) {
16202
+ let attempt = 1;
16203
+ for (; ; ) {
16204
+ try {
16205
+ return await fn.call(this, ...args);
16206
+ } catch (err) {
16207
+ const config = adapter.connectRetryConfig;
16208
+ if (!err || typeof err !== "object" || err.code !== "ECONNREFUSED" || !config || attempt >= config.attempts) {
16209
+ throw err;
16210
+ }
16211
+ await config.strategy(attempt, config.attempts);
16212
+ attempt++;
16213
+ }
16214
+ }
16215
+ };
16216
+ };
16217
+ const defaultConnectRetryStrategy = (param) => {
16218
+ return (attempt) => setTimeout((param.factor ?? 1.5) ** (attempt - 1) * (param.delay ?? 50));
16219
+ };
16220
+
16221
+ const makeColumnInfoSql = (query, column) => {
16222
+ const values = [];
16223
+ const schema = getQuerySchema(query);
16224
+ let text = `SELECT * FROM information_schema.columns WHERE table_name = ${addValue(
16225
+ values,
16226
+ query.table
16227
+ )} AND table_catalog = current_database() AND table_schema = ${schema ? addValue(values, schema) : "current_schema()"}`;
16228
+ if (column) {
16229
+ text += ` AND column_name = ${addValue(
16230
+ values,
16231
+ query.q.shape[column]?.data.name || column
16232
+ )}`;
16233
+ }
16234
+ return {
16235
+ text,
16236
+ values
16237
+ };
16238
+ };
16239
+
16240
+ const rowToColumnInfo = (row) => {
16241
+ const typed = row;
16242
+ return {
16243
+ defaultValue: typed.column_default,
16244
+ type: typed.data_type,
16245
+ maxLength: typed.character_maximum_length,
16246
+ nullable: typed.is_nullable === "YES"
16247
+ };
16248
+ };
16249
+ function getColumnInfo(query, column) {
16250
+ const q = Object.create(_clone$1(query));
16251
+ q.toSQL = () => makeColumnInfoSql(query, column);
16252
+ q.q.handleResult = (_, _t, result) => {
16253
+ if (column) {
16254
+ return rowToColumnInfo(result.rows[0]);
16255
+ } else {
16256
+ const info = {};
16257
+ result.rows.forEach((row) => {
16258
+ info[row.column_name] = rowToColumnInfo(row);
16259
+ });
16260
+ return info;
16261
+ }
16262
+ };
16263
+ return q;
16264
+ }
16265
+
16266
+ const makeCopySql = (table, copy) => {
16267
+ const ctx = newToSqlCtx(table);
16268
+ const { q } = table;
16269
+ const quotedAs = `"${q.as || table.table}"`;
16270
+ const columns = copy.columns ? `(${copy.columns.map((item) => `"${q.shape[item]?.data.name || item}"`).join(", ")})` : "";
16271
+ const target = "from" in copy ? copy.from : copy.to;
16272
+ const quotedTable = quoteTableWithSchema(table);
16273
+ ctx.sql.push(
16274
+ `COPY ${quotedTable}${columns} ${"from" in copy ? "FROM" : "TO"} ${typeof target === "string" ? escapeString(target) : `PROGRAM ${escapeString(target.program)}`}`
16275
+ );
16276
+ if (Object.keys(copy).length > (copy.columns ? 2 : 1)) {
16277
+ const options = [];
16278
+ if (copy.format) options.push(`FORMAT ${copy.format}`);
16279
+ if (copy.freeze) options.push(`FREEZE ${copy.freeze}`);
16280
+ if (copy.delimiter)
16281
+ options.push(`DELIMITER ${escapeString(copy.delimiter)}`);
16282
+ if (copy.null) options.push(`NULL ${escapeString(copy.null)}`);
16283
+ if (copy.header) options.push(`HEADER ${copy.header}`);
16284
+ if (copy.quote) options.push(`QUOTE ${escapeString(copy.quote)}`);
16285
+ if (copy.escape) options.push(`ESCAPE ${escapeString(copy.escape)}`);
16286
+ if (copy.forceQuote)
16287
+ options.push(
16288
+ `FORCE_QUOTE ${copy.forceQuote === "*" ? "*" : `(${copy.forceQuote.map((x) => `"${x}"`).join(", ")})`}`
16289
+ );
16290
+ if (copy.forceNotNull)
16291
+ options.push(
16292
+ `FORCE_NOT_NULL (${copy.forceNotNull.map((x) => `"${x}"`).join(", ")})`
16293
+ );
16294
+ if (copy.forceNull)
16295
+ options.push(
16296
+ `FORCE_NULL (${copy.forceNull.map((x) => `"${x}"`).join(", ")})`
16297
+ );
16298
+ if (copy.encoding) options.push(`ENCODING ${escapeString(copy.encoding)}`);
16299
+ ctx.sql.push(`WITH (${options.join(", ")})`);
16300
+ }
16301
+ pushWhereStatementSql(ctx, table, q, quotedAs);
16302
+ return {
16303
+ text: ctx.sql.join(" "),
16304
+ values: ctx.values
16305
+ };
16306
+ };
16307
+
16308
+ function copyTableData(query, arg) {
16309
+ const q = Object.create(query);
16310
+ q.toSQL = () => makeCopySql(q, arg);
16311
+ return q;
16312
+ }
16313
+
16086
16314
  class Rollback extends Error {
16087
16315
  }
16088
16316
  const trxForTest = Symbol("trxForTest");
@@ -16167,5 +16395,5 @@ const testTransaction = {
16167
16395
  }
16168
16396
  };
16169
16397
 
16170
- export { AfterCommitError, ArrayColumn, BigIntColumn, BigSerialColumn, BitColumn, BitVaryingColumn, BooleanColumn, BoxColumn, ByteaColumn, CidrColumn, CircleColumn, CitextColumn, Column, ColumnRefExpression, ComputedColumn, CteQuery, CustomTypeColumn, DateBaseColumn, DateColumn, DateTimeBaseClass, DateTimeTzBaseClass, Db, DecimalColumn, DomainColumn, DoublePrecisionColumn, DynamicRawSQL, EnumColumn, Expression, ExpressionTypeMethod, FnExpression, FromMethods, InetColumn, IntegerBaseColumn, IntegerColumn, IntervalColumn, JSONColumn, JSONTextColumn, LimitedTextBaseColumn, LineColumn, LsegColumn, MacAddr8Column, MacAddrColumn, MergeQueryMethods, MoneyColumn, MoreThanOneRowError, NotFoundError, NumberAsStringBaseColumn, NumberBaseColumn, OnConflictQueryBuilder, OnMethods, Operators, OrExpression, OrchidOrmError, OrchidOrmInternalError, PathColumn, PointColumn, PolygonColumn, PostgisGeographyPointColumn, QueryAsMethods, QueryClone, QueryCreate, QueryCreateFrom, QueryDelete, QueryError, QueryExpressions, QueryGet, QueryHookUtils, QueryHooks, QueryJoin, QueryLog, QueryMethods, QueryOrCreate, QueryScope, QuerySql, QueryTransaction, QueryTransform, QueryUpdate, QueryUpsert, QueryWithSchema, QueryWrap, RawSql, RealColumn, RefExpression, Select, SerialColumn, SmallIntColumn, SmallSerialColumn, SqlRefExpression, StringColumn, TextBaseColumn, TextColumn, Then, TimeColumn, TimestampColumn, TimestampTZColumn, TsQueryColumn, TsVectorColumn, UUIDColumn, UnhandledTypeError, UnknownColumn, UnsafeSqlExpression, VarCharColumn, VirtualColumn, Where, XMLColumn, _addToHookSelect, _addToHookSelectWithTable, _appendQuery, _applyRelationAliases, _checkIfAliased, _clone, _copyQueryAliasToQuery, _createDbSqlMethod, _getQueryAliasOrName, _getQueryAs, _getQueryFreeAlias, _getQueryOuterAliases, _hookSelectColumns, _initQueryBuilder, _join, _joinLateral, _joinLateralProcessArg, _joinReturningArgs, _orCreate, _prependWith, _queryAfterSaveCommit, _queryAll, _queryChangeCounter, _queryCreate, _queryCreateForEachFrom, _queryCreateMany, _queryCreateManyFrom, _queryCreateOneFrom, _queryDefaults, _queryDelete, _queryExec, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterCreateCommit, _queryHookAfterDelete, _queryHookAfterDeleteCommit, _queryHookAfterQuery, _queryHookAfterSave, _queryHookAfterUpdate, _queryHookAfterUpdateCommit, _queryHookBeforeCreate, _queryHookBeforeDelete, _queryHookBeforeQuery, _queryHookBeforeSave, _queryHookBeforeUpdate, _queryInsert, _queryInsertForEachFrom, _queryInsertMany, _queryInsertManyFrom, _queryInsertOneFrom, _queryJoinOn, _queryJoinOnJsonPathEquals, _queryJoinOrOn, _queryOr, _queryOrNot, _queryRows, _querySelect, _querySelectAll, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, _queryWhereNot, _queryWhereNotExists, _queryWhereNotOneOf, _queryWhereNotSql, _queryWhereOneOf, _queryWhereSql, _runAfterCommitHooks, _setQueryAlias, _setQueryAs, _setSubQueryAliases, _with, addCode, addColumnParserToQuery, addParserForRawExpression, addParserForSelectItem, addQueryOn, addTopCte, addTopCteSql, addValue, addWithToSql, anyShape, applyBatchTransforms, applyComputedColumns, applyMixins, applyTransforms, arrayDataToCode, arrayMethodNames, assignDbDataToColumn, backtickQuote, callWithThis, checkIfASimpleQuery, cloneQueryBaseUnscoped, codeToString, colors, columnCheckToCode, columnCode, columnDefaultArgumentToCode, columnErrorMessagesToCode, columnExcludesToCode, columnForeignKeysToCode, columnIndexesToCode, columnMethodsToCode, columnsShapeToCode, commitSql, composeCteSingleSql, constraintInnerToCode, constraintToCode, consumeColumnName, countSelect, createCtx, createDbWithAdapter, createSelect, cteToSql, cteToSqlGiveAs, ctesToSql, dateDataToCode, dateMethodNames, deepCompare, defaultSchemaConfig, emptyArray, emptyObject, escapeForLog, escapeForMigration, escapeString, excludeInnerToCode, excludeToCode, exhaustive, extendQuery, filterResult, finalizeNestedHookSelect, foreignKeyArgumentToCode, getCallerFilePath, getClonedQueryData, getColumnBaseType, getColumnTypes, getDefaultLanguage, getDefaultNowFn, getFreeAlias, getFreeSetAlias, getFromSelectColumns, getFullColumnTable, getImportPath, getPrimaryKeys, getQueryAs, getQuerySchema, getSearchLang, getSearchText, getShapeFromSelect, getSqlText, getStackTrace, getSupportedDefaultPrivileges, getThen, getTopCteSize, handleManyData, handleOneData, handleResult, havingToSql, identityToCode, indexInnerToCode, indexToCode, insert, isDefaultTimeStamp, isExpression, isInUserTransaction, isIterable, isObjectEmpty, isQuery, isQueryReturnsAll, isRawSQL, isRelationQuery, isTemplateLiteralArgs, joinSubQuery, joinTruthy, logColors, logParamToLogObject, makeColumnNullable, makeColumnTypes, makeColumnsByType, makeFnExpression, makeInsertSql, makeReturningSql, makeRowToJson, makeSql, moveMutativeQueryToCte, newDelayedRelationSelect, noop, numberDataToCode, numberMethodNames, objectHasValues, omit, orderByToSql, parseRecord, parseTableData, parseTableDataInput, pathToLog, pick, pluralize, postgisTypmodToSql, prepareOpArg, prepareSubQueryForSql, primaryKeyInnerToCode, processComputedBatches, processComputedResult, processJoinItem, processSelectArg, pushColumnData, pushHavingSql, pushJoinSql, pushOrNewArray, pushOrNewArrayToObjectImmutable, pushOrderBySql, pushQueryArrayImmutable, pushQueryOn, pushQueryOnForOuter, pushQueryOrOn, pushQueryValueImmutable, pushTableDataCode, pushUnionSql, pushWhereStatementSql, pushWhereToSql, queryColumnNameToKey, queryFrom, queryFromSql, queryMethodByReturnType, queryTypeWithLimitOne, queryWrap, quoteFromWithSchema, quoteObjectKey, quoteSchemaAndTable, quoteTableWithSchema, raw$1 as raw, rawSqlToCode, referencesArgsToCode, requirePrimaryKeys, requireQueryAs, requireTableOrStringFrom, resetDefaultNowFn, resolveSubQueryCallback, returnArg, rollbackSql, saveAliasedShape, searchSourcesToSql, selectAllSql, selectToSql, selectToSqlList, setColumnData, setColumnDefaultParse, setColumnEncode, setColumnParse, setColumnParseNull, setConnectRetryConfig, setCurrentColumnName, setDataValue, setDb, setDefaultLanguage, setDefaultNowFn, setDelayedRelation, setFreeAlias, setFreeTopCteAs, setMoveMutativeQueryToCte, setObjectValueImmutable, setParserForSelectedString, setPrepareSubQueryForSql, setQueryObjectValueImmutable, setQueryOperators, setRawSqlPrepareSubQueryForSql, setSqlCtxSelectList, setTopCteSize, singleQuote, singleQuoteArray, snakeCaseKey, spreadObjectValues, sqlFn, sqlQueryArgsToExpression, stringDataToCode, stringMethodNames, tableDataMethods, templateLiteralSQLToCode, templateLiteralToSQL, testTransaction, throwIfJoinLateral, throwIfNoWhere, throwOnReadOnly, throwOnReadOnlyUpdate, timestampHelpers, toArray, toCamelCase, toPascalCase, toSnakeCase, whereToSql, windowToSql, wrapAdapterFnWithConnectRetry };
16398
+ export { ArrayColumn, BigIntColumn, BigSerialColumn, BitColumn, BitVaryingColumn, BooleanColumn, BoxColumn, ByteaColumn, CidrColumn, CircleColumn, CitextColumn, Column, CustomTypeColumn, DateBaseColumn, DateColumn, DateTimeBaseClass, DateTimeTzBaseClass, Db, DecimalColumn, DomainColumn, DoublePrecisionColumn, DynamicRawSQL, EnumColumn, Expression, InetColumn, IntegerBaseColumn, IntegerColumn, IntervalColumn, JSONColumn, JSONTextColumn, LimitedTextBaseColumn, LineColumn, LsegColumn, MacAddr8Column, MacAddrColumn, MoneyColumn, NotFoundError, NumberAsStringBaseColumn, NumberBaseColumn, Operators, OrchidOrmInternalError, PathColumn, PointColumn, PolygonColumn, PostgisGeographyPointColumn, QueryError, QueryHookUtils, QueryHooks, RawSql, RealColumn, SerialColumn, SmallIntColumn, SmallSerialColumn, StringColumn, TextBaseColumn, TextColumn, TimeColumn, TimestampColumn, TimestampTZColumn, TsQueryColumn, TsVectorColumn, UUIDColumn, UnknownColumn, VarCharColumn, VirtualColumn, XMLColumn, _appendQuery, _clone, _createDbSqlMethod, _hookSelectColumns, _initQueryBuilder, _orCreate, _prependWith, _queryCreate, _queryCreateMany, _queryCreateManyFrom, _queryDefaults, _queryDelete, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterUpdate, _queryInsert, _queryInsertMany, _queryJoinOn, _queryRows, _querySelect, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, addCode, addTopCte, addTopCteSql, applyMixins, assignDbDataToColumn, backtickQuote, cloneQueryBaseUnscoped, codeToString, colors, columnsShapeToCode, constraintInnerToCode, consumeColumnName, copyTableData, createDbWithAdapter, deepCompare, defaultSchemaConfig, emptyArray, emptyObject, escapeForMigration, escapeString, excludeInnerToCode, exhaustive, getCallerFilePath, getClonedQueryData, getColumnBaseType, getColumnInfo, getColumnTypes, getFreeAlias, getFreeSetAlias, getImportPath, getPrimaryKeys, getQueryAs, getQuerySchema, getShapeFromSelect, getSqlText, getStackTrace, getSupportedDefaultPrivileges, indexInnerToCode, isExpression, isQueryReturnsAll, isRawSQL, logColors, logParamToLogObject, makeColumnNullable, makeColumnTypes, makeColumnsByType, noop, objectHasValues, omit, parseTableData, parseTableDataInput, pathToLog, pick, pluralize, prepareSubQueryForSql, primaryKeyInnerToCode, pushQueryOnForOuter, pushQueryValueImmutable, pushTableDataCode, quoteObjectKey, quoteTableWithSchema, raw$1 as raw, rawSqlToCode, referencesArgsToCode, returnArg, setColumnData, setColumnEncode, setColumnParse, setColumnParseNull, setConnectRetryConfig, setCurrentColumnName, setDataValue, setDefaultLanguage, setFreeAlias, setQueryObjectValueImmutable, singleQuote, snakeCaseKey, tableDataMethods, testTransaction, toArray, toCamelCase, toPascalCase, toSnakeCase, wrapAdapterFnWithConnectRetry };
16171
16399
  //# sourceMappingURL=index.mjs.map