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