orchid-orm 1.59.4 → 1.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -191,7 +191,7 @@ const hasRelationHandleUpdate = (q, set, key, primaryKeys, nestedUpdate) => {
191
191
  );
192
192
  });
193
193
  };
194
- const selectIfNotSelected = (q, columns) => {
194
+ const _selectIfNotSelected = (q, columns) => {
195
195
  const select = q.q.select || [];
196
196
  if (!select.includes("*")) {
197
197
  for (const column of columns) {
@@ -287,6 +287,8 @@ const getColumnKeyFromDbName = (query, name) => {
287
287
  }
288
288
  return name;
289
289
  };
290
+ const selectCteColumnsSql = (cteAs, columns) => `(SELECT ${columns.map((c) => `"${cteAs}"."${c}"`).join(", ")} FROM "${cteAs}")`;
291
+ const selectCteColumnSql = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
290
292
 
291
293
  const joinQueryChainHOF = (relPKeys, reverseJoin, joinQuery) => (joiningQuery, baseQuery) => {
292
294
  const jq = joiningQuery;
@@ -402,7 +404,7 @@ class BelongsToVirtualColumn extends pqb.VirtualColumn {
402
404
  super(schema);
403
405
  this.key = key;
404
406
  this.state = state;
405
- this.nestedUpdate = nestedUpdate$3(this.state);
407
+ this.nestedUpdate = nestedUpdate$2(this.state);
406
408
  }
407
409
  create(q, ctx, item) {
408
410
  const {
@@ -416,18 +418,11 @@ class BelongsToVirtualColumn extends pqb.VirtualColumn {
416
418
  }
417
419
  const value = item[key];
418
420
  if ("create" in value || "connectOrCreate" in value) {
419
- foreignKeys.forEach((foreignKey) => item[foreignKey] = new pqb.RawSql(""));
421
+ const asFn = setForeignKeysFromCte(item, primaryKeys, foreignKeys);
420
422
  const selectPKeys = query.select(...primaryKeys);
421
- pqb._with(
423
+ pqb._prependWith(
422
424
  q,
423
- (as) => {
424
- foreignKeys.forEach((foreignKey, i) => {
425
- item[foreignKey]._sql = selectCteColumnSql(
426
- as,
427
- primaryKeys[i]
428
- );
429
- });
430
- },
425
+ asFn,
431
426
  "create" in value ? pqb._queryCreate(selectPKeys, value.create) : pqb._orCreate(
432
427
  pqb._queryWhere(selectPKeys, [
433
428
  value.connectOrCreate.where
@@ -438,7 +433,7 @@ class BelongsToVirtualColumn extends pqb.VirtualColumn {
438
433
  return;
439
434
  } else if ("connect" in value) {
440
435
  const as = pqb.getFreeAlias(q.q.withShapes, "q");
441
- pqb._with(q, as, query.select(...primaryKeys).findBy(value.connect));
436
+ pqb._prependWith(q, as, query.select(...primaryKeys).findBy(value.connect));
442
437
  foreignKeys.map((foreignKey, i) => {
443
438
  item[foreignKey] = new pqb.RawSql(
444
439
  selectCteColumnMustExistSql(i, as, primaryKeys[i])
@@ -447,10 +442,10 @@ class BelongsToVirtualColumn extends pqb.VirtualColumn {
447
442
  return;
448
443
  }
449
444
  }
450
- update(q, ctx, set) {
445
+ update(q, set) {
451
446
  q.q.wrapInTransaction = true;
452
447
  const data = set[this.key];
453
- this.nestedUpdate(q, set, data, ctx);
448
+ this.nestedUpdate(q, set, data);
454
449
  }
455
450
  }
456
451
  const makeBelongsToMethod = (tableConfig, table, relation, relationName, query) => {
@@ -521,139 +516,138 @@ const makeBelongsToMethod = (tableConfig, table, relation, relationName, query)
521
516
  reverseJoin
522
517
  };
523
518
  };
524
- const nestedUpdate$3 = ({ query, primaryKeys, foreignKeys, len }) => {
525
- return (q, update, params, state) => {
526
- if (params.upsert && pqb.isQueryReturnsAll(q)) {
527
- throw new Error("`upsert` option is not allowed in a batch update");
528
- }
529
- let idsForDelete;
530
- pqb._queryHookBeforeUpdate(q, async ({ query: q2 }) => {
531
- if (params.disconnect) {
532
- for (const key of foreignKeys) {
533
- update[key] = null;
534
- }
535
- } else if (params.set) {
536
- let loadPrimaryKeys;
537
- let loadForeignKeys;
538
- for (let i = 0; i < len; i++) {
539
- const primaryKey = primaryKeys[i];
540
- if (primaryKey in params.set) {
541
- update[foreignKeys[i]] = params.set[primaryKey];
542
- } else {
543
- (loadPrimaryKeys ?? (loadPrimaryKeys = [])).push(primaryKey);
544
- (loadForeignKeys ?? (loadForeignKeys = [])).push(foreignKeys[i]);
545
- }
546
- }
547
- if (loadPrimaryKeys) {
548
- for (let i = 0, len2 = loadPrimaryKeys.length; i < len2; i++) {
549
- update[loadForeignKeys[i]] = new pqb.RawSql("");
550
- }
551
- pqb._with(
552
- q2,
553
- (as) => {
554
- for (let i = 0, len2 = loadPrimaryKeys.length; i < len2; i++) {
555
- update[loadForeignKeys[i]]._sql = selectCteColumnMustExistSql(i, as, loadPrimaryKeys[i]);
556
- }
557
- },
558
- pqb._queryFindBy(query.select(...loadPrimaryKeys), params.set)
559
- );
519
+ const nestedUpdate$2 = ({ query, primaryKeys, foreignKeys, len }) => {
520
+ return (self, update, params) => {
521
+ if (params.create) {
522
+ const createQuery = pqb._querySelect(
523
+ pqb._queryCreate(query.clone(), params.create),
524
+ primaryKeys
525
+ );
526
+ const asFn = setForeignKeysFromCte(update, primaryKeys, foreignKeys);
527
+ pqb._prependWith(self, asFn, createQuery);
528
+ } else if (params.update) {
529
+ _selectIfNotSelected(self, foreignKeys);
530
+ const selectIdsSql = new pqb.RawSql("");
531
+ const updateQuery = pqb._queryUpdate(
532
+ pqb._queryWhereIn(query.clone(), true, primaryKeys, selectIdsSql),
533
+ params.update
534
+ );
535
+ updateQuery.q.returnType = "value";
536
+ pqb._appendQuery(self, updateQuery, (as) => {
537
+ selectIdsSql._sql = selectCteColumnsSql(as, foreignKeys);
538
+ });
539
+ } else if (params.upsert) {
540
+ if (pqb.isQueryReturnsAll(self)) {
541
+ throw new Error("`upsert` option is not allowed in a batch update");
542
+ }
543
+ const { relQuery } = relWithSelectIds(
544
+ self,
545
+ query,
546
+ primaryKeys,
547
+ foreignKeys
548
+ );
549
+ const upsertQuery = pqb._querySelect(
550
+ pqb._queryUpsert(
551
+ relQuery,
552
+ params.upsert
553
+ ),
554
+ primaryKeys
555
+ );
556
+ const asFn = setForeignKeysFromCte(update, primaryKeys, foreignKeys);
557
+ pqb._prependWith(self, asFn, upsertQuery);
558
+ } else if (params.delete) {
559
+ _selectIfNotSelected(self, foreignKeys);
560
+ disconnect(update, foreignKeys);
561
+ const { selectIdsSql, relQuery } = relWithSelectIds(
562
+ self,
563
+ query,
564
+ primaryKeys,
565
+ foreignKeys
566
+ );
567
+ self.q.and = self.q.or = void 0;
568
+ pqb._queryWhereIn(self, true, foreignKeys, selectIdsSql);
569
+ const deleteQuery = pqb._queryDelete(relQuery);
570
+ deleteQuery.q.returnType = "value";
571
+ pqb._appendQuery(self, deleteQuery, pqb.noop);
572
+ } else if (params.disconnect) {
573
+ disconnect(update, foreignKeys);
574
+ } else if (params.set) {
575
+ let loadPrimaryKeys;
576
+ let loadForeignKeys;
577
+ for (let i = 0; i < len; i++) {
578
+ const primaryKey = primaryKeys[i];
579
+ if (primaryKey in params.set) {
580
+ update[foreignKeys[i]] = params.set[primaryKey];
581
+ } else {
582
+ (loadPrimaryKeys ?? (loadPrimaryKeys = [])).push(primaryKey);
583
+ (loadForeignKeys ?? (loadForeignKeys = [])).push(foreignKeys[i]);
560
584
  }
561
- } else if (params.create) {
562
- const q3 = query.clone();
563
- q3.q.select = primaryKeys;
564
- const record = await pqb._queryCreate(
565
- q3,
566
- params.create
585
+ }
586
+ if (loadPrimaryKeys) {
587
+ const asFn = setForeignKeysFromCte(
588
+ update,
589
+ loadPrimaryKeys,
590
+ loadForeignKeys,
591
+ true
592
+ );
593
+ pqb._prependWith(
594
+ self,
595
+ asFn,
596
+ pqb._queryFindBy(query.select(...loadPrimaryKeys), params.set)
567
597
  );
568
- for (let i = 0; i < len; i++) {
569
- update[foreignKeys[i]] = record[primaryKeys[i]];
570
- }
571
- } else if (params.delete) {
572
- const selectQuery = q2.clone();
573
- selectQuery.q.type = void 0;
574
- selectQuery.q.distinct = pqb.emptyArray;
575
- selectIfNotSelected(selectQuery, foreignKeys);
576
- idsForDelete = await pqb._queryRows(selectQuery);
577
- for (const foreignKey of foreignKeys) {
578
- update[foreignKey] = null;
579
- }
580
598
  }
581
- });
582
- const { upsert } = params;
583
- if (upsert || params.update || params.delete) {
584
- selectIfNotSelected(q, foreignKeys);
585
- }
586
- if (upsert) {
587
- (state.queries ?? (state.queries = [])).push(async (queryResult) => {
588
- const row = queryResult.rows[0];
589
- let obj = {};
590
- for (let i = 0; i < len; i++) {
591
- const id = row[foreignKeys[i]];
592
- if (id === null) {
593
- obj = void 0;
594
- break;
595
- }
596
- obj[primaryKeys[i]] = id;
597
- }
598
- const count = obj ? await pqb._queryUpdate(
599
- query.findBy(obj),
600
- upsert.update
601
- ) : 0;
602
- if (!count) {
603
- const data = typeof upsert.create === "function" ? upsert.create() : upsert.create;
604
- const result = await pqb._queryCreate(
605
- query.select(...primaryKeys),
606
- data
607
- );
608
- const collectData = {};
609
- state.collect = {
610
- data: collectData
611
- };
612
- for (let i = 0; i < len; i++) {
613
- collectData[foreignKeys[i]] = result[primaryKeys[i]];
614
- }
615
- }
616
- });
617
- } else if (params.delete || params.update) {
618
- pqb._queryHookAfterUpdate(
619
- q,
620
- params.update ? foreignKeys : pqb.emptyArray,
621
- async (data) => {
622
- let ids;
623
- if (params.delete) {
624
- ids = idsForDelete;
625
- } else {
626
- ids = [];
627
- for (const item of data) {
628
- let row;
629
- for (const foreignKey of foreignKeys) {
630
- const id = item[foreignKey];
631
- if (id === null) {
632
- row = void 0;
633
- break;
634
- } else {
635
- (row ?? (row = [])).push(id);
636
- }
637
- }
638
- if (row) ids.push(row);
639
- }
640
- }
641
- if (!ids?.length) return;
642
- const t = query.whereIn(
643
- primaryKeys,
644
- ids
645
- );
646
- if (params.delete) {
647
- await pqb._queryDelete(t);
648
- } else {
649
- await pqb._queryUpdate(t, params.update);
650
- }
651
- }
652
- );
653
599
  }
654
600
  };
655
601
  };
656
- const selectCteColumnSql = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
602
+ const disconnect = (update, foreignKeys) => {
603
+ for (const foreignKey of foreignKeys) {
604
+ update[foreignKey] = null;
605
+ }
606
+ };
607
+ const relWithSelectIds = (self, rel, primaryKeys, foreignKeys) => {
608
+ const selectIdsQuery = makeSelectIdsQuery(self, foreignKeys);
609
+ const selectIdsSql = new pqb.RawSql("");
610
+ pqb._prependWith(
611
+ self,
612
+ (as) => {
613
+ selectIdsSql._sql = selectCteColumnsSql(as, foreignKeys);
614
+ },
615
+ selectIdsQuery
616
+ );
617
+ return {
618
+ selectIdsSql,
619
+ relQuery: pqb._queryWhereIn(rel.clone(), true, primaryKeys, selectIdsSql)
620
+ };
621
+ };
622
+ const makeSelectIdsQuery = (self, foreignKeys) => {
623
+ const selectIdsQuery = self.baseQuery.clone();
624
+ selectIdsQuery.q.distinct = pqb.emptyArray;
625
+ selectIdsQuery.q.select = foreignKeys;
626
+ selectIdsQuery.q.and = self.q.and;
627
+ selectIdsQuery.q.or = self.q.or;
628
+ return selectIdsQuery;
629
+ };
630
+ const setForeignKeysFromCte = (record, primaryKeys, foreignKeys, mustExist) => {
631
+ for (const key of foreignKeys) {
632
+ record[key] = new pqb.RawSql("");
633
+ }
634
+ return (as) => {
635
+ foreignKeys.forEach(
636
+ mustExist ? (foreignKey, i) => {
637
+ record[foreignKey]._sql = selectCteColumnMustExistSql(
638
+ i,
639
+ as,
640
+ primaryKeys[i]
641
+ );
642
+ } : (foreignKey, i) => {
643
+ record[foreignKey]._sql = selectCteColumnSql(
644
+ as,
645
+ primaryKeys[i]
646
+ );
647
+ }
648
+ );
649
+ };
650
+ };
657
651
  const selectCteColumnMustExistSql = (i, cteAs, column) => {
658
652
  const selectColumn = selectCteColumnSql(cteAs, column);
659
653
  return i === 0 ? `CASE WHEN (SELECT count(*) FROM "${cteAs}") = 0 AND (SELECT 'not-found')::int = 0 THEN NULL ELSE ${selectColumn} END` : selectColumn;
@@ -665,32 +659,107 @@ class HasOneVirtualColumn extends pqb.VirtualColumn {
665
659
  this.key = key;
666
660
  this.state = state;
667
661
  this.nestedInsert = nestedInsert$2(state);
668
- this.nestedUpdate = nestedUpdate$2(state);
662
+ this.setNulls = {};
663
+ for (const foreignKey of state.foreignKeys) {
664
+ this.setNulls[foreignKey] = null;
665
+ }
669
666
  }
670
- create(q, ctx, item, rowIndex) {
671
- hasRelationHandleCreate(
672
- q,
673
- ctx,
674
- item,
675
- rowIndex,
676
- this.key,
677
- this.state.primaryKeys,
678
- this.nestedInsert
679
- );
667
+ create(self, ctx, item, rowIndex, one) {
668
+ if (one) {
669
+ const value = item[this.key];
670
+ if (!value.create && !value.connect && !value.connectOrCreate) {
671
+ return;
672
+ }
673
+ const { query: rel, primaryKeys, foreignKeys } = this.state;
674
+ _selectIfNotSelected(self, primaryKeys);
675
+ const data = value.create ? { ...value.create } : {};
676
+ foreignKeys.forEach((key) => {
677
+ data[key] = new pqb.RawSql("");
678
+ });
679
+ const query = value.create ? pqb._queryCreate(pqb._clone(rel), data) : value.connect ? pqb._queryUpdateOrThrow(
680
+ rel.where(value.connect),
681
+ data
682
+ ) : value.connectOrCreate ? pqb._queryUpsert(rel.where(value.connectOrCreate.where), {
683
+ update: data,
684
+ create: {
685
+ ...value.connectOrCreate.create,
686
+ ...data
687
+ }
688
+ }) : void 0;
689
+ pqb._appendQuery(self, query, (as) => {
690
+ foreignKeys.forEach((key, i) => {
691
+ data[key]._sql = selectCteColumnSql(as, primaryKeys[i]);
692
+ });
693
+ });
694
+ } else {
695
+ hasRelationHandleCreate(
696
+ self,
697
+ ctx,
698
+ item,
699
+ rowIndex,
700
+ this.key,
701
+ this.state.primaryKeys,
702
+ this.nestedInsert
703
+ );
704
+ }
680
705
  }
681
- update(q, _, set) {
706
+ update(self, set) {
682
707
  const params = set[this.key];
683
- if ((params.set || params.create || params.upsert) && pqb.isQueryReturnsAll(q)) {
708
+ if ((params.set || params.create || params.upsert) && pqb.isQueryReturnsAll(self)) {
684
709
  const key = params.set ? "set" : params.create ? "create" : "upsert";
685
710
  throw new Error(`\`${key}\` option is not allowed in a batch update`);
686
711
  }
687
- hasRelationHandleUpdate(
688
- q,
689
- set,
690
- this.key,
691
- this.state.primaryKeys,
692
- this.nestedUpdate
693
- );
712
+ const { primaryKeys, foreignKeys, query: relQuery } = this.state;
713
+ if (params.create || params.update || params.upsert || params.disconnect || params.set || params.delete) {
714
+ _selectIfNotSelected(self, primaryKeys);
715
+ const selectIdsSql = new pqb.RawSql("");
716
+ const existingRelQuery = pqb._queryWhereIn(
717
+ pqb._clone(relQuery),
718
+ true,
719
+ foreignKeys,
720
+ selectIdsSql
721
+ );
722
+ let setIds = void 0;
723
+ if (params.create || params.set || params.upsert) {
724
+ setIds = {};
725
+ foreignKeys.forEach((foreignKey) => {
726
+ setIds[foreignKey] = new pqb.RawSql("");
727
+ });
728
+ }
729
+ const nullifyOrDeleteQuery = params.update ? pqb._queryUpdate(existingRelQuery, params.update) : params.upsert ? pqb._queryUpsert(existingRelQuery, {
730
+ update: params.upsert.update,
731
+ create: {
732
+ ...typeof params.upsert.create === "function" ? params.upsert.create() : params.upsert.create,
733
+ ...setIds
734
+ }
735
+ }) : params.delete ? pqb._queryDelete(existingRelQuery) : pqb._queryUpdate(existingRelQuery, this.setNulls);
736
+ nullifyOrDeleteQuery.q.returnType = "void";
737
+ pqb._appendQuery(self, nullifyOrDeleteQuery, (as) => {
738
+ selectIdsSql._sql = selectCteColumnsSql(as, primaryKeys);
739
+ if (params.create || params.set || params.upsert) {
740
+ foreignKeys.forEach((foreignKey, i) => {
741
+ setIds[foreignKey]._sql = selectCteColumnSql(
742
+ as,
743
+ primaryKeys[i]
744
+ );
745
+ });
746
+ }
747
+ });
748
+ if (params.create) {
749
+ const createQuery = pqb._queryInsert(pqb._clone(relQuery), {
750
+ ...params.create,
751
+ ...setIds
752
+ });
753
+ pqb._appendQuery(self, createQuery, pqb.noop);
754
+ } else if (params.set) {
755
+ const setQuery = pqb._queryUpdate(
756
+ pqb._queryWhere(pqb._clone(relQuery), [params.set]),
757
+ setIds
758
+ );
759
+ setQuery.q.returnType = "void";
760
+ pqb._appendQuery(self, setQuery, pqb.noop);
761
+ }
762
+ }
694
763
  }
695
764
  }
696
765
  const makeHasOneMethod = (tableConfig, table, relation, relationName, query) => {
@@ -818,9 +887,9 @@ const nestedInsert$2 = ({ query, primaryKeys, foreignKeys }) => {
818
887
  for (let i = 0, len = items.length; i < len; i++) {
819
888
  const [selfData, item] = items[i];
820
889
  const data2 = {};
821
- for (let i2 = 0; i2 < len; i2++) {
822
- data2[foreignKeys[i2]] = selfData[primaryKeys[i2]];
823
- }
890
+ primaryKeys.forEach((primaryKey, i2) => {
891
+ data2[foreignKeys[i2]] = selfData[primaryKey];
892
+ });
824
893
  items[i] = "connect" in item ? pqb._queryUpdateOrThrow(
825
894
  t.where(item.connect),
826
895
  data2
@@ -861,78 +930,6 @@ const nestedInsert$2 = ({ query, primaryKeys, foreignKeys }) => {
861
930
  }
862
931
  };
863
932
  };
864
- const nestedUpdate$2 = ({ query, primaryKeys, foreignKeys }) => {
865
- const len = primaryKeys.length;
866
- const setNulls = {};
867
- for (const foreignKey of foreignKeys) {
868
- setNulls[foreignKey] = null;
869
- }
870
- return async (_, data, params) => {
871
- const t = query.clone();
872
- const ids = data.map(
873
- (item) => primaryKeys.map((primaryKey) => item[primaryKey])
874
- );
875
- const currentRelationsQuery = t.whereIn(
876
- foreignKeys,
877
- ids
878
- );
879
- if (params.create || params.disconnect || params.set) {
880
- let queryToDisconnect = currentRelationsQuery;
881
- if (params.set) {
882
- queryToDisconnect = queryToDisconnect.whereNot(params.set);
883
- }
884
- await pqb._queryUpdate(queryToDisconnect, setNulls);
885
- const record = data[0];
886
- if (params.create) {
887
- const obj = { ...params.create };
888
- for (let i = 0; i < len; i++) {
889
- obj[foreignKeys[i]] = record[primaryKeys[i]];
890
- }
891
- await t.insert(obj);
892
- }
893
- if (params.set) {
894
- const obj = {};
895
- for (let i = 0; i < len; i++) {
896
- obj[foreignKeys[i]] = record[primaryKeys[i]];
897
- }
898
- await pqb._queryUpdate(
899
- pqb._queryWhere(t, [params.set]),
900
- obj
901
- );
902
- }
903
- } else if (params.update) {
904
- await pqb._queryUpdate(currentRelationsQuery, params.update);
905
- } else if (params.delete) {
906
- const q = pqb._queryDelete(currentRelationsQuery);
907
- q.q.returnType = "value";
908
- await q;
909
- } else if (params.upsert) {
910
- const { update, create } = params.upsert;
911
- currentRelationsQuery.q.select = foreignKeys;
912
- const updatedIds = await pqb._queryUpdate(
913
- pqb._queryRows(currentRelationsQuery),
914
- update
915
- );
916
- if (updatedIds.length < ids.length) {
917
- const data2 = typeof create === "function" ? create() : create;
918
- await t.createMany(
919
- ids.reduce((rows, ids2) => {
920
- if (!updatedIds.some(
921
- (updated) => updated.every((value, i) => value === ids2[i])
922
- )) {
923
- const obj = { ...data2 };
924
- for (let i = 0; i < len; i++) {
925
- obj[foreignKeys[i]] = ids2[i];
926
- }
927
- rows.push(obj);
928
- }
929
- return rows;
930
- }, [])
931
- );
932
- }
933
- }
934
- };
935
- };
936
933
 
937
934
  class HasManyVirtualColumn extends pqb.VirtualColumn {
938
935
  constructor(schema, key, state) {
@@ -953,7 +950,7 @@ class HasManyVirtualColumn extends pqb.VirtualColumn {
953
950
  this.nestedInsert
954
951
  );
955
952
  }
956
- update(q, _, set) {
953
+ update(q, set) {
957
954
  const params = set[this.key];
958
955
  if ((params.set || params.create) && pqb.isQueryReturnsAll(q)) {
959
956
  const key = params.set ? "set" : "create";
@@ -1296,7 +1293,7 @@ class HasAndBelongsToManyVirtualColumn extends pqb.VirtualColumn {
1296
1293
  this.nestedInsert
1297
1294
  );
1298
1295
  }
1299
- update(q, _, set) {
1296
+ update(q, set) {
1300
1297
  hasRelationHandleUpdate(
1301
1298
  q,
1302
1299
  set,