Skip to content

Commit 2e387a5

Browse files
committed
Merge branch 'feat/events-multiselect-bulk-actions' into stage
2 parents f3366d8 + ae8d3dc commit 2e387a5

12 files changed

Lines changed: 329 additions & 484 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hawk.api",
3-
"version": "1.5.1",
3+
"version": "1.5.0",
44
"main": "index.ts",
55
"license": "BUSL-1.1",
66
"scripts": {

src/models/eventsFactory.js

Lines changed: 36 additions & 218 deletions
Original file line numberDiff line numberDiff line change
@@ -887,69 +887,20 @@ class EventsFactory extends Factory {
887887
*
888888
* @param {string[]} eventIds - original event ids
889889
* @param {string|ObjectId} userId - id of the user who is visiting events
890-
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
890+
* @returns {Promise<UpdateWriteOpResult>}
891891
*/
892892
async bulkVisitEvents(eventIds, userId) {
893-
const {
894-
collection,
895-
found,
896-
failedEventIds,
897-
} = await this._resolveBulkEventsByIds(eventIds);
898-
const userIdStr = String(userId);
899-
900-
const docsToUpdate = found.filter((doc) => {
901-
const visitedBy = Array.isArray(doc.visitedBy) ? doc.visitedBy : [];
902-
903-
return !visitedBy.some((visitedUserId) => String(visitedUserId) === userIdStr);
904-
});
905-
906-
if (docsToUpdate.length === 0) {
907-
return {
908-
updatedEventIds: [],
909-
failedEventIds,
910-
};
911-
}
912-
893+
const uniqueEventIds = [ ...new Set((eventIds || []).map(id => String(id))) ];
894+
const collection = this.getCollection(this.TYPES.EVENTS);
913895
const userObjectId = new ObjectId(userId);
914-
const settled = await Promise.allSettled(
915-
docsToUpdate.map(async (doc) => {
916-
const eventId = doc._id.toString();
917-
const updateResult = await collection.updateOne(
918-
{
919-
_id: doc._id,
920-
visitedBy: { $ne: userObjectId },
921-
},
922-
{ $addToSet: { visitedBy: userObjectId } }
923-
);
924896

925-
return {
926-
eventId,
927-
updated: updateResult.modifiedCount > 0,
928-
};
929-
})
897+
return collection.updateMany(
898+
{
899+
_id: { $in: uniqueEventIds.map(id => new ObjectId(id)) },
900+
visitedBy: { $ne: userObjectId },
901+
},
902+
{ $addToSet: { visitedBy: userObjectId } }
930903
);
931-
932-
const updatedEventIds = [];
933-
const failedByUpdate = [];
934-
935-
settled.forEach((result, index) => {
936-
const fallbackEventId = docsToUpdate[index]._id.toString();
937-
938-
if (result.status === 'fulfilled') {
939-
if (result.value.updated) {
940-
updatedEventIds.push(result.value.eventId);
941-
} else {
942-
failedByUpdate.push(result.value.eventId);
943-
}
944-
} else {
945-
failedByUpdate.push(fallbackEventId);
946-
}
947-
});
948-
949-
return {
950-
updatedEventIds,
951-
failedEventIds: this._mergeFailedEventIds(failedEventIds, failedByUpdate),
952-
};
953904
}
954905

955906
/**
@@ -993,148 +944,55 @@ class EventsFactory extends Factory {
993944
*
994945
* @param {string[]} eventIds - original event ids
995946
* @param {string} mark - 'resolved' | 'ignored' | 'starred'
996-
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
947+
* @returns {Promise<UpdateWriteOpResult>}
997948
*/
998949
async bulkToggleEventMark(eventIds, mark) {
999-
const {
1000-
collection,
1001-
found,
1002-
failedEventIds,
1003-
} = await this._resolveBulkEventsByIds(eventIds);
1004-
950+
const uniqueEventIds = [ ...new Set((eventIds || []).map(id => String(id))) ];
951+
const objectIds = uniqueEventIds.map(id => new ObjectId(id));
952+
const collection = this.getCollection(this.TYPES.EVENTS);
953+
const found = await collection.find({ _id: { $in: objectIds } }).toArray();
1005954
const nowSec = Math.floor(Date.now() / 1000);
1006955
const markKey = `marks.${mark}`;
1007956
const allHaveMark = found.length > 0 && found.every(doc => doc.marks && doc.marks[mark]);
1008-
const ops = [];
1009-
1010-
for (const doc of found) {
1011-
const hasMark = doc.marks && doc.marks[mark];
1012-
let update;
1013-
1014-
if (allHaveMark) {
1015-
update = { $unset: { [markKey]: '' } };
1016-
} else if (!hasMark) {
1017-
update = { $set: { [markKey]: nowSec } };
1018-
} else {
1019-
continue;
1020-
}
1021957

1022-
ops.push({
1023-
updateOne: {
1024-
filter: { _id: doc._id },
1025-
update,
958+
if (allHaveMark) {
959+
return collection.updateMany(
960+
{
961+
_id: { $in: objectIds },
962+
[markKey]: { $exists: true },
1026963
},
1027-
});
1028-
}
1029-
1030-
if (ops.length === 0) {
1031-
return {
1032-
updatedEventIds: [],
1033-
failedEventIds,
1034-
};
964+
{ $unset: { [markKey]: '' } }
965+
);
1035966
}
1036967

1037-
const settled = await Promise.allSettled(
1038-
ops.map(async ({ updateOne }) => {
1039-
const eventId = updateOne.filter._id.toString();
1040-
const updateResult = await collection.updateOne(
1041-
updateOne.filter,
1042-
updateOne.update
1043-
);
1044-
1045-
return {
1046-
eventId,
1047-
updated: updateResult.modifiedCount > 0,
1048-
};
1049-
})
968+
return collection.updateMany(
969+
{
970+
_id: { $in: objectIds },
971+
[markKey]: { $exists: false },
972+
},
973+
{ $set: { [markKey]: nowSec } }
1050974
);
1051-
1052-
const updatedEventIds = [];
1053-
const failedByUpdate = [];
1054-
1055-
settled.forEach((result, index) => {
1056-
const fallbackEventId = ops[index].updateOne.filter._id.toString();
1057-
1058-
if (result.status === 'fulfilled') {
1059-
if (result.value.updated) {
1060-
updatedEventIds.push(result.value.eventId);
1061-
} else {
1062-
failedByUpdate.push(result.value.eventId);
1063-
}
1064-
} else {
1065-
failedByUpdate.push(fallbackEventId);
1066-
}
1067-
});
1068-
1069-
return {
1070-
updatedEventIds,
1071-
failedEventIds: this._mergeFailedEventIds(failedEventIds, failedByUpdate),
1072-
};
1073975
}
1074976

1075977
/**
1076978
* Bulk set/clear assignee for many original events.
1077979
*
1078980
* @param {string[]} eventIds - original event ids
1079981
* @param {string|null|undefined} assignee - target assignee id, null/undefined to clear
1080-
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
982+
* @returns {Promise<UpdateWriteOpResult>}
1081983
*/
1082984
async bulkUpdateAssignee(eventIds, assignee) {
1083-
const {
1084-
collection,
1085-
found,
1086-
failedEventIds,
1087-
} = await this._resolveBulkEventsByIds(eventIds);
1088-
985+
const uniqueEventIds = [ ...new Set((eventIds || []).map(id => String(id))) ];
986+
const collection = this.getCollection(this.TYPES.EVENTS);
1089987
const normalizedAssignee = assignee ? String(assignee) : '';
1090-
const docsToUpdate = found.filter(doc => String(doc.assignee || '') !== normalizedAssignee);
1091-
1092-
if (docsToUpdate.length === 0) {
1093-
return {
1094-
updatedEventIds: [],
1095-
failedEventIds,
1096-
};
1097-
}
1098988

1099-
const settled = await Promise.allSettled(
1100-
docsToUpdate.map(async (doc) => {
1101-
const eventId = doc._id.toString();
1102-
const updateResult = await collection.updateOne(
1103-
{
1104-
_id: doc._id,
1105-
assignee: { $ne: normalizedAssignee },
1106-
},
1107-
{ $set: { assignee: normalizedAssignee } }
1108-
);
1109-
1110-
return {
1111-
eventId,
1112-
updated: updateResult.modifiedCount > 0,
1113-
};
1114-
})
989+
return collection.updateMany(
990+
{
991+
_id: { $in: uniqueEventIds.map(id => new ObjectId(id)) },
992+
assignee: { $ne: normalizedAssignee },
993+
},
994+
{ $set: { assignee: normalizedAssignee } }
1115995
);
1116-
1117-
const updatedEventIds = [];
1118-
const failedByUpdate = [];
1119-
1120-
settled.forEach((result, index) => {
1121-
const fallbackEventId = docsToUpdate[index]._id.toString();
1122-
1123-
if (result.status === 'fulfilled') {
1124-
if (result.value.updated) {
1125-
updatedEventIds.push(result.value.eventId);
1126-
} else {
1127-
failedByUpdate.push(result.value.eventId);
1128-
}
1129-
} else {
1130-
failedByUpdate.push(fallbackEventId);
1131-
}
1132-
});
1133-
1134-
return {
1135-
updatedEventIds,
1136-
failedEventIds: this._mergeFailedEventIds(failedEventIds, failedByUpdate),
1137-
};
1138996
}
1139997

1140998
/**
@@ -1185,46 +1043,6 @@ class EventsFactory extends Factory {
11851043
return result;
11861044
}
11871045

1188-
/**
1189-
* Resolve original events for bulk operations and collect not found ids.
1190-
*
1191-
* @param {string[]} eventIds - original event ids
1192-
* @returns {Promise<{ collection: any, found: any[], failedEventIds: string[] }>}
1193-
*/
1194-
async _resolveBulkEventsByIds(eventIds) {
1195-
const unique = [ ...new Set((eventIds || []).map(id => String(id))) ];
1196-
const objectIds = unique.map(id => new ObjectId(id));
1197-
const collection = this.getCollection(this.TYPES.EVENTS);
1198-
const found = await collection.find({ _id: { $in: objectIds } }).toArray();
1199-
const foundByIdStr = new Set(found.map(doc => doc._id.toString()));
1200-
const failedEventIds = objectIds
1201-
.map(id => id.toString())
1202-
.filter(id => !foundByIdStr.has(id));
1203-
1204-
return {
1205-
collection,
1206-
found,
1207-
failedEventIds,
1208-
};
1209-
}
1210-
1211-
/**
1212-
* Merge two failed ids collections preserving uniqueness.
1213-
*
1214-
* @param {string[]} baseFailedEventIds - existing failed ids
1215-
* @param {string[]} extraFailedEventIds - failed ids collected from update results
1216-
* @returns {string[]}
1217-
*/
1218-
_mergeFailedEventIds(baseFailedEventIds, extraFailedEventIds) {
1219-
const mergedFailedEventIds = new Set(baseFailedEventIds);
1220-
1221-
extraFailedEventIds.forEach((eventId) => {
1222-
mergedFailedEventIds.add(eventId);
1223-
});
1224-
1225-
return Array.from(mergedFailedEventIds);
1226-
}
1227-
12281046
/**
12291047
* Compose event with repetition
12301048
*

0 commit comments

Comments
 (0)