orchid-orm 1.72.5 → 1.72.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { DynamicRawSQL, QueryHooks, RawSql, VirtualColumn, _appendQuery, _clone, _createDbSqlMethod, _hookSelectColumns, _initQueryBuilder, _orCreate, _prependWith, _queryCreate, _queryCreateMany, _queryCreateManyFrom, _queryDefaults, _queryDelete, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterUpdate, _queryInsert, _queryInsertMany, _queryJoinOn, _queryRows, _querySelect, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, applyMixins, cloneQueryBaseUnscoped, defaultSchemaConfig, emptyArray, emptyObject, getCallerFilePath, getClonedQueryData, getColumnTypes, getFreeAlias, getPrimaryKeys, getQueryAs, getShapeFromSelect, getStackTrace, internalSchemaConfig, isExpression, isQueryReturnsAll, makeColumnTypes, noop, objectHasValues, parseTableData, pick, prepareSubQueryForSql, pushQueryOnForOuter, setQueryObjectValueImmutable, toArray, toSnakeCase } from "pqb/internal";
1
+ import { DynamicRawSQL, QueryHooks, RawSql, VirtualColumn, _appendQuery, _appendQueryOnUpsertCreate, _clone, _createDbSqlMethod, _hookSelectColumns, _initQueryBuilder, _orCreate, _prependWith, _queryCreate, _queryCreateMany, _queryCreateManyFrom, _queryDefaults, _queryDelete, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterUpdate, _queryInsert, _queryInsertMany, _queryJoinOn, _queryRows, _querySelect, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, applyMixins, cloneQueryBaseUnscoped, defaultSchemaConfig, emptyArray, emptyObject, getCallerFilePath, getClonedQueryData, getColumnTypes, getFreeAlias, getPrimaryKeys, getQueryAs, getShapeFromSelect, getStackTrace, internalSchemaConfig, isExpression, isQueryReturnsAll, makeColumnTypes, noop, objectHasValues, parseTableData, pick, prepareSubQueryForSql, pushQueryOnForOuter, setQueryObjectValueImmutable, toArray, toSnakeCase } from "pqb/internal";
2
2
  import { Db, NotFoundError, OrchidOrmInternalError } from "pqb";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
4
  export * from "pqb";
@@ -137,6 +137,25 @@ function createBaseTable({ schemaConfig = defaultSchemaConfig, columnTypes: colu
137
137
  base.prototype.autoForeignKeys = autoForeignKeys === true ? {} : autoForeignKeys || void 0;
138
138
  return base;
139
139
  }
140
+ const throwIfQueryReturnsAllForNestedUpdate = (q, params) => {
141
+ if (!(params.set || params.create || params.upsert) || !isQueryReturnsAll(q)) return;
142
+ let key;
143
+ if (params.set) key = "set";
144
+ else if (params.create) key = "create";
145
+ else key = "upsert";
146
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
147
+ };
148
+ const getNestedUpdateUpsertCreate = (upsert) => {
149
+ if (typeof upsert.create === "function") return upsert.create();
150
+ return upsert.create || emptyObject;
151
+ };
152
+ const makeNestedUpdateUpsertData = (upsert, setIds) => ({
153
+ update: upsert.update,
154
+ create: {
155
+ ...getNestedUpdateUpsertCreate(upsert),
156
+ ...setIds
157
+ }
158
+ });
140
159
  const getThroughRelation = (table, through) => {
141
160
  return table.relations[through];
142
161
  };
@@ -224,8 +243,27 @@ const getColumnKeyFromDbName = (query, name) => {
224
243
  for (const k in query.shape) if (query.shape[k].data.name === name) return k;
225
244
  return name;
226
245
  };
227
- const selectCteColumnsSql = (cteAs, columns) => `(SELECT ${columns.map((c) => `"${cteAs}"."${c}"`).join(", ")} FROM "${cteAs}")`;
228
- const selectCteColumnSql = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
246
+ const selectCteColumnsSql$1 = (cteAs, columns) => `(SELECT ${columns.map((c) => `"${cteAs}"."${c}"`).join(", ")} FROM "${cteAs}")`;
247
+ const selectCteColumnSql$1 = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
248
+ const makeNestedUpdateRelationIds = (q, relQuery, primaryKeys, foreignKeys) => {
249
+ const selectIdsSql = new RawSql("");
250
+ const setIds = {};
251
+ for (const foreignKey of foreignKeys) setIds[foreignKey] = new RawSql("");
252
+ let appendedAs;
253
+ _hookSelectColumns(q, primaryKeys, (aliasedPrimaryKeys) => {
254
+ selectIdsSql._sql = selectCteColumnsSql$1(appendedAs, aliasedPrimaryKeys);
255
+ foreignKeys.forEach((foreignKey, i) => {
256
+ setIds[foreignKey]._sql = selectCteColumnSql$1(appendedAs, aliasedPrimaryKeys[i]);
257
+ });
258
+ });
259
+ return {
260
+ existingRelQuery: _queryWhereIn(_clone(relQuery), true, foreignKeys, selectIdsSql),
261
+ setIds,
262
+ setAppendedAs(as) {
263
+ appendedAs = as;
264
+ }
265
+ };
266
+ };
229
267
  const selectCteColumnFromManySql = (cteAs, column, rowIndex, count) => {
230
268
  let sql = `(SELECT "${cteAs}"."${column}" FROM "${cteAs}"`;
231
269
  if (count > 1) {
@@ -406,7 +444,7 @@ const nestedUpdate$2 = ({ query, primaryKeys, foreignKeys, len }) => {
406
444
  } else if (params.update) {
407
445
  let appendedAs;
408
446
  _hookSelectColumns(self, foreignKeys, (aliasedForeignKeys) => {
409
- selectIdsSql._sql = selectCteColumnsSql(appendedAs, aliasedForeignKeys);
447
+ selectIdsSql._sql = selectCteColumnsSql$1(appendedAs, aliasedForeignKeys);
410
448
  });
411
449
  const selectIdsSql = new RawSql("");
412
450
  const updateQuery = _queryUpdate(_queryWhereIn(query.clone(), true, primaryKeys, selectIdsSql), params.update);
@@ -449,7 +487,7 @@ const relWithSelectIds = (self, rel, primaryKeys, foreignKeys) => {
449
487
  const selectIdsQuery = makeSelectIdsQuery(self, foreignKeys);
450
488
  const selectIdsSql = new RawSql("");
451
489
  _prependWith(self, (as) => {
452
- selectIdsSql._sql = selectCteColumnsSql(as, foreignKeys);
490
+ selectIdsSql._sql = selectCteColumnsSql$1(as, foreignKeys);
453
491
  }, selectIdsQuery);
454
492
  return {
455
493
  selectIdsSql,
@@ -470,12 +508,12 @@ const setForeignKeysFromCte = (record, primaryKeys, foreignKeys, mustExist) => {
470
508
  foreignKeys.forEach(mustExist ? (foreignKey, i) => {
471
509
  record[foreignKey]._sql = selectCteColumnMustExistSql(i, as, primaryKeys[i]);
472
510
  } : (foreignKey, i) => {
473
- record[foreignKey]._sql = selectCteColumnSql(as, primaryKeys[i]);
511
+ record[foreignKey]._sql = selectCteColumnSql$1(as, primaryKeys[i]);
474
512
  });
475
513
  };
476
514
  };
477
515
  const selectCteColumnMustExistSql = (i, cteAs, column) => {
478
- const selectColumn = selectCteColumnSql(cteAs, column);
516
+ const selectColumn = selectCteColumnSql$1(cteAs, column);
479
517
  return i === 0 ? `CASE WHEN (SELECT count(*) FROM "${cteAs}") = 0 AND (SELECT 'not-found')::int = 0 THEN NULL ELSE ${selectColumn} END` : selectColumn;
480
518
  };
481
519
  var HasOneVirtualColumn = class extends VirtualColumn {
@@ -541,43 +579,19 @@ var HasOneVirtualColumn = class extends VirtualColumn {
541
579
  update(self, set) {
542
580
  const querySelf = self;
543
581
  const params = set[this.key];
544
- if ((params.set || params.create || params.upsert) && isQueryReturnsAll(querySelf)) {
545
- const key = params.set ? "set" : params.create ? "create" : "upsert";
546
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
547
- }
582
+ throwIfQueryReturnsAllForNestedUpdate(querySelf, params);
548
583
  const { primaryKeys, foreignKeys, query: relQuery } = this.state;
549
584
  if (params.create || params.update || params.upsert || params.disconnect || params.set || params.delete) {
550
- let appendedAs;
551
- _hookSelectColumns(querySelf, primaryKeys, (aliasedPrimaryKeys) => {
552
- selectIdsSql._sql = selectCteColumnsSql(appendedAs, aliasedPrimaryKeys);
553
- if (params.create || params.set || params.upsert) foreignKeys.forEach((foreignKey, i) => {
554
- setIds[foreignKey]._sql = selectCteColumnSql(appendedAs, aliasedPrimaryKeys[i]);
555
- });
556
- });
557
- const selectIdsSql = new RawSql("");
558
- const existingRelQuery = _queryWhereIn(_clone(relQuery), true, foreignKeys, selectIdsSql);
559
- let setIds = void 0;
560
- if (params.create || params.set || params.upsert) {
561
- setIds = {};
562
- foreignKeys.forEach((foreignKey) => {
563
- setIds[foreignKey] = new RawSql("");
564
- });
565
- }
566
- const nullifyOrDeleteQuery = params.update ? _queryUpdate(existingRelQuery, params.update) : params.upsert ? _queryUpsert(existingRelQuery, {
567
- update: params.upsert.update,
568
- create: {
569
- ...typeof params.upsert.create === "function" ? params.upsert.create() : params.upsert.create,
570
- ...setIds
571
- }
572
- }) : params.delete ? _queryDelete(existingRelQuery) : _queryUpdate(existingRelQuery, this.setNulls);
585
+ const ids = makeNestedUpdateRelationIds(querySelf, relQuery, primaryKeys, foreignKeys);
586
+ const nullifyOrDeleteQuery = params.update ? _queryUpdate(ids.existingRelQuery, params.update) : params.upsert ? _queryUpsert(ids.existingRelQuery, makeNestedUpdateUpsertData(params.upsert, ids.setIds)) : params.delete ? _queryDelete(ids.existingRelQuery) : _queryUpdate(ids.existingRelQuery, this.setNulls);
573
587
  nullifyOrDeleteQuery.q.returnType = "void";
574
- _appendQuery(querySelf, nullifyOrDeleteQuery, (as) => appendedAs = as);
588
+ _appendQuery(querySelf, nullifyOrDeleteQuery, ids.setAppendedAs);
575
589
  if (params.create) _appendQuery(querySelf, _queryInsert(_clone(relQuery), {
576
590
  ...params.create,
577
- ...setIds
591
+ ...ids.setIds
578
592
  }), noop);
579
593
  else if (params.set) {
580
- const setQuery = _queryUpdate(_queryWhere(_clone(relQuery), [params.set]), setIds);
594
+ const setQuery = _queryUpdate(_queryWhere(_clone(relQuery), [params.set]), ids.setIds);
581
595
  setQuery.q.returnType = "void";
582
596
  _appendQuery(querySelf, setQuery, noop);
583
597
  }
@@ -691,6 +705,8 @@ var HasManyVirtualColumn = class extends VirtualColumn {
691
705
  this.state = state;
692
706
  this.nestedInsert = nestedInsert$1(state);
693
707
  this.nestedUpdate = nestedUpdate$1(state);
708
+ this.setNulls = {};
709
+ for (const foreignKey of state.foreignKeys) this.setNulls[foreignKey] = null;
694
710
  }
695
711
  create(self, ctx, items, rowIndexes, count) {
696
712
  const querySelf = self;
@@ -761,14 +777,18 @@ var HasManyVirtualColumn = class extends VirtualColumn {
761
777
  });
762
778
  } else hasRelationHandleCreate(querySelf, ctx, items, rowIndexes, this.key, this.state.primaryKeys, this.nestedInsert);
763
779
  }
764
- update(q, set) {
765
- const query = q;
780
+ update(self, set) {
781
+ const querySelf = self;
766
782
  const params = set[this.key];
767
- if ((params.set || params.create) && isQueryReturnsAll(query)) {
768
- const key = params.set ? "set" : "create";
769
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
783
+ throwIfQueryReturnsAllForNestedUpdate(querySelf, params);
784
+ hasRelationHandleUpdate(querySelf, set, this.key, this.state.primaryKeys, this.nestedUpdate);
785
+ if (params.upsert) {
786
+ const { primaryKeys, foreignKeys, query: relQuery } = this.state;
787
+ const ids = makeNestedUpdateRelationIds(querySelf, relQuery, primaryKeys, foreignKeys);
788
+ const appendedQuery = _queryUpsert(ids.existingRelQuery, makeNestedUpdateUpsertData(params.upsert, ids.setIds));
789
+ appendedQuery.q.returnType = "void";
790
+ _appendQuery(querySelf, appendedQuery, ids.setAppendedAs);
770
791
  }
771
- hasRelationHandleUpdate(query, set, this.key, this.state.primaryKeys, this.nestedUpdate);
772
792
  }
773
793
  };
774
794
  const makeHasManyMethod = (tableConfig, table, relation, relationName, query) => {
@@ -908,10 +928,10 @@ const nestedInsert$1 = ({ query, primaryKeys, foreignKeys }) => {
908
928
  }
909
929
  });
910
930
  };
911
- const nestedUpdate$1 = ({ query, primaryKeys, foreignKeys }) => {
931
+ const nestedUpdate$1 = ({ query: relQuery, primaryKeys, foreignKeys }) => {
912
932
  const len = primaryKeys.length;
913
933
  return (async (_, data, params) => {
914
- const t = query.clone();
934
+ const t = relQuery.clone();
915
935
  if (params.create) {
916
936
  const obj = {};
917
937
  for (let i = 0; i < len; i++) obj[foreignKeys[i]] = data[0][primaryKeys[i]];
@@ -921,12 +941,12 @@ const nestedUpdate$1 = ({ query, primaryKeys, foreignKeys }) => {
921
941
  })));
922
942
  }
923
943
  if (params.add) {
924
- if (data.length > 1) throw new OrchidOrmInternalError(query, "`connect` is not available when updating multiple records, it is only applicable for a single record update");
944
+ if (data.length > 1) throw new OrchidOrmInternalError(relQuery, "`connect` is not available when updating multiple records, it is only applicable for a single record update");
925
945
  const obj = {};
926
946
  for (let i = 0; i < len; i++) obj[foreignKeys[i]] = data[0][primaryKeys[i]];
927
947
  const relatedWheres = toArray(params.add);
928
948
  const count = await _queryUpdate(t.where({ OR: relatedWheres }), obj);
929
- if (count < relatedWheres.length) throw new OrchidOrmInternalError(query, `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count}`);
949
+ if (count < relatedWheres.length) throw new OrchidOrmInternalError(relQuery, `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count}`);
930
950
  }
931
951
  if (params.disconnect || params.set) {
932
952
  const obj = {};
@@ -961,9 +981,48 @@ var HasAndBelongsToManyVirtualColumn = class extends VirtualColumn {
961
981
  hasRelationHandleCreate(q, ctx, items, rowIndexes, this.key, this.state.primaryKeys, this.nestedInsert);
962
982
  }
963
983
  update(q, set) {
964
- hasRelationHandleUpdate(q, set, this.key, this.state.primaryKeys, this.nestedUpdate);
984
+ const querySelf = q;
985
+ const params = set[this.key];
986
+ hasRelationHandleUpdate(querySelf, set, this.key, this.state.primaryKeys, this.nestedUpdate);
987
+ if (params.upsert) {
988
+ throwIfQueryReturnsAllForNestedUpdate(querySelf, { upsert: params.upsert });
989
+ nestedUpdateUpsert(querySelf, this.state, params.upsert);
990
+ }
965
991
  }
966
992
  };
993
+ const selectCteColumnsSql = (cteAs, columns) => `(SELECT ${columns.map((c) => `"${cteAs}"."${c}"`).join(", ")} FROM "${cteAs}")`;
994
+ const selectCteColumnSql = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
995
+ const nestedUpdateUpsert = (querySelf, state, upsert) => {
996
+ const parentIdsSql = new RawSql("");
997
+ const parentValues = state.foreignKeys.map(() => new RawSql(""));
998
+ const relatedIdsSql = new RawSql("");
999
+ const relatedValues = state.throughPrimaryKeys.map(() => new RawSql(""));
1000
+ let parentAs;
1001
+ _hookSelectColumns(querySelf, state.primaryKeys, (aliasedPrimaryKeys) => {
1002
+ parentIdsSql._sql = selectCteColumnsSql(parentAs, aliasedPrimaryKeys);
1003
+ for (let i = 0; i < state.foreignKeys.length; i++) parentValues[i]._sql = selectCteColumnSql(parentAs, aliasedPrimaryKeys[i]);
1004
+ });
1005
+ const upsertQuery = _querySelect(_queryUpsert(_queryWhereExists(_queryWhere(_clone(state.relatedTableQuery), [upsert.findBy]), state.joinTableQuery, [(q) => {
1006
+ for (let i = 0; i < state.throughPrimaryKeys.length; i++) _queryJoinOn(q, [state.throughForeignKeysFull[i], state.throughPrimaryKeysFull[i]]);
1007
+ return _queryWhereIn(q, true, state.foreignKeysFull, parentIdsSql);
1008
+ }]), {
1009
+ update: upsert.update,
1010
+ create: upsert.create || {}
1011
+ }), state.throughPrimaryKeys);
1012
+ const selectAs = {};
1013
+ for (let i = 0; i < state.foreignKeys.length; i++) selectAs[state.foreignKeys[i]] = parentValues[i];
1014
+ for (let i = 0; i < state.throughForeignKeys.length; i++) selectAs[state.throughForeignKeys[i]] = relatedValues[i];
1015
+ const joinRows = _querySelect(_clone(state.queryBuilder), [selectAs]);
1016
+ _queryWhere(joinRows, [relatedIdsSql]);
1017
+ const joinQuery = state.joinTableQuery.insertForEachFrom(joinRows);
1018
+ joinQuery.q.returnType = "void";
1019
+ _appendQuery(querySelf, _appendQueryOnUpsertCreate(upsertQuery, joinQuery, (as) => {
1020
+ relatedIdsSql._sql = `EXISTS (SELECT 1 FROM "${as}")`;
1021
+ for (let i = 0; i < relatedValues.length; i++) relatedValues[i]._sql = selectCteColumnSql(as, state.throughPrimaryKeys[i]);
1022
+ }), (as) => {
1023
+ parentAs = as;
1024
+ });
1025
+ };
967
1026
  const removeColumnName = (column) => {
968
1027
  if (!column.data.name) return column;
969
1028
  const cloned = Object.create(column);
@@ -1021,6 +1080,7 @@ const makeHasAndBelongsToManyMethod = (tableConfig, table, qb, relation, relatio
1021
1080
  addAutoForeignKey(tableConfig, subQuery, table, primaryKeys, foreignKeys, relation.options, originalForeignKeys);
1022
1081
  addAutoForeignKey(tableConfig, subQuery, query, throughPrimaryKeys, throughForeignKeys, relation.options.through, originalThroughForeignKeys);
1023
1082
  const state = {
1083
+ queryBuilder: qb,
1024
1084
  relatedTableQuery: query,
1025
1085
  joinTableQuery: subQuery,
1026
1086
  primaryKeys,