@strapi/database 5.50.0 → 5.50.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entity-manager/index.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAsB,MAAM,SAAS,CAAC;AAE5D,cAAc,SAAS,CAAC;AA4OxB,eAAO,MAAM,mBAAmB,GAAI,IAAI,QAAQ,KAAG,aAo1ClD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entity-manager/index.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAGnC,OAAO,EAAE,aAAa,EAAsB,MAAM,SAAS,CAAC;AAE5D,cAAc,SAAS,CAAC;AA4OxB,eAAO,MAAM,mBAAmB,GAAI,IAAI,QAAQ,KAAG,aAy9ClD,CAAC"}
@@ -902,7 +902,126 @@ const createEntityManager = (db)=>{
902
902
  if (isPartialUpdate) {
903
903
  if (relations.isAnyToOne(attribute)) ;
904
904
  relIdsToaddOrMove = toIds(cleanRelationData.connect);
905
- const relIdsToDelete = toIds(_.differenceWith(_.isEqual, cleanRelationData.disconnect, cleanRelationData.connect ?? []));
905
+ // Use id-only comparison so a disconnect item whose id also appears in
906
+ // the connect array is correctly excluded from deletion (deep-equality
907
+ // fails because connect items carry extra fields like `position`).
908
+ const relIdsToDelete = toIds(_.differenceWith((a, b)=>a.id === b.id, cleanRelationData.disconnect, cleanRelationData.connect ?? []));
909
+ // When a connect item's position.before/after references an id that is
910
+ // about to be deleted (relIdsToDelete), the referenced row won't exist by
911
+ // the time the adjacentRelations query runs below, causing sortConnectArray
912
+ // to throw. Rewrite such a position to point at the nearest surviving
913
+ // neighbor in the relation's current order, so the item lands where the
914
+ // deleted relation used to be instead of always falling back to the end.
915
+ const idKey = (value)=>String(value);
916
+ const deletedIds = new Set(relIdsToDelete.map(idKey));
917
+ let resolvedConnect = cleanRelationData.connect ?? [];
918
+ if (relations.hasOrderColumn(attribute) && !_.isEmpty(relIdsToDelete) && resolvedConnect.some((item)=>{
919
+ const adjacentId = item.position?.before ?? item.position?.after;
920
+ return adjacentId != null && deletedIds.has(idKey(adjacentId));
921
+ })) {
922
+ const currentOrder = await this.createQueryBuilder(joinTable.name).select([
923
+ inverseJoinColumn.name,
924
+ orderColumnName
925
+ ]).where({
926
+ [joinColumn.name]: id
927
+ }).where(joinTable.on || {}).orderBy(orderColumnName).transacting(trx).execute();
928
+ const orderedIds = currentOrder.map((rel)=>rel[inverseJoinColumn.name]);
929
+ const orderedIdKeys = orderedIds.map(idKey);
930
+ const connectIds = new Set(resolvedConnect.map((item)=>idKey(item.id)));
931
+ const deletedIdsInCurrentOrder = new Set(orderedIds.map(idKey).filter((orderedId)=>deletedIds.has(orderedId)));
932
+ // A neighbor is only a valid fallback target if it survives the delete
933
+ // and isn't being moved by this connect payload.
934
+ const findSurvivingNeighbor = (targetId, direction)=>{
935
+ let index = orderedIdKeys.indexOf(idKey(targetId));
936
+ while(index !== -1){
937
+ index += direction;
938
+ const candidate = orderedIds[index];
939
+ if (candidate === undefined) {
940
+ return undefined;
941
+ }
942
+ const candidateKey = idKey(candidate);
943
+ if (!deletedIds.has(candidateKey) && !connectIds.has(candidateKey)) {
944
+ return candidate;
945
+ }
946
+ }
947
+ return undefined;
948
+ };
949
+ const positionByConnectId = new Map();
950
+ const connectGroups = new Map();
951
+ const getConnectGroup = (targetId)=>{
952
+ const targetKey = idKey(targetId);
953
+ let group = connectGroups.get(targetKey);
954
+ if (!group) {
955
+ group = {
956
+ targetId,
957
+ before: [],
958
+ after: []
959
+ };
960
+ connectGroups.set(targetKey, group);
961
+ }
962
+ return group;
963
+ };
964
+ resolvedConnect.forEach((item)=>{
965
+ const { before, after } = item.position ?? {};
966
+ const adjacentId = before ?? after;
967
+ if (adjacentId == null || !deletedIds.has(idKey(adjacentId)) || !deletedIdsInCurrentOrder.has(idKey(adjacentId))) {
968
+ return;
969
+ }
970
+ const group = getConnectGroup(adjacentId);
971
+ if (before) {
972
+ group.before.push(item);
973
+ } else {
974
+ group.after.push(item);
975
+ }
976
+ });
977
+ connectGroups.forEach(({ targetId, before, after })=>{
978
+ const previousNeighbor = findSurvivingNeighbor(targetId, -1);
979
+ const nextNeighbor = findSurvivingNeighbor(targetId, 1);
980
+ let previousPositionId = previousNeighbor;
981
+ before.forEach((item)=>{
982
+ if (previousPositionId !== undefined) {
983
+ positionByConnectId.set(item.id, {
984
+ after: previousPositionId
985
+ });
986
+ } else if (nextNeighbor !== undefined) {
987
+ positionByConnectId.set(item.id, {
988
+ before: nextNeighbor
989
+ });
990
+ } else {
991
+ positionByConnectId.set(item.id, {
992
+ start: true
993
+ });
994
+ }
995
+ previousPositionId = item.id;
996
+ });
997
+ after.forEach((item)=>{
998
+ if (previousPositionId !== undefined) {
999
+ positionByConnectId.set(item.id, {
1000
+ after: previousPositionId
1001
+ });
1002
+ } else if (nextNeighbor !== undefined) {
1003
+ positionByConnectId.set(item.id, {
1004
+ before: nextNeighbor
1005
+ });
1006
+ } else {
1007
+ positionByConnectId.set(item.id, {
1008
+ start: true
1009
+ });
1010
+ }
1011
+ previousPositionId = item.id;
1012
+ });
1013
+ });
1014
+ resolvedConnect = resolvedConnect.map((item)=>{
1015
+ const position = positionByConnectId.get(item.id);
1016
+ if (position) {
1017
+ return {
1018
+ ...item,
1019
+ position
1020
+ };
1021
+ }
1022
+ return item;
1023
+ });
1024
+ }
906
1025
  if (!_.isEmpty(relIdsToDelete)) {
907
1026
  await regularRelations.deleteRelations({
908
1027
  id,
@@ -939,7 +1058,7 @@ const createEntityManager = (db)=>{
939
1058
  {
940
1059
  [joinColumn.name]: id,
941
1060
  [inverseJoinColumn.name]: {
942
- $in: _.compact(cleanRelationData.connect?.map((r)=>r.position?.after || r.position?.before))
1061
+ $in: _.compact(resolvedConnect.map((r)=>r.position?.after || r.position?.before))
943
1062
  }
944
1063
  },
945
1064
  {
@@ -950,7 +1069,7 @@ const createEntityManager = (db)=>{
950
1069
  }
951
1070
  ]
952
1071
  }).where(joinTable.on || {}).transacting(trx).execute();
953
- const orderMap = relationsOrderer.relationsOrderer(adjacentRelations, inverseJoinColumn.name, joinTable.orderColumnName, cleanRelationData.options?.strict).connect(cleanRelationData.connect ?? []).getOrderMap();
1072
+ const orderMap = relationsOrderer.relationsOrderer(adjacentRelations, inverseJoinColumn.name, joinTable.orderColumnName, cleanRelationData.options?.strict).connect(resolvedConnect).getOrderMap();
954
1073
  insert.forEach((row)=>{
955
1074
  row[orderColumnName] = orderMap[row[inverseJoinColumn.name]];
956
1075
  });