Skip to content

Commit c271563

Browse files
committed
refactor(events): simplify bulk event operations by removing updatedCount from responses and enhancing error handling
1 parent 81a682f commit c271563

12 files changed

Lines changed: 292 additions & 343 deletions

src/models/eventsFactory.js

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ 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<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
890+
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
891891
*/
892892
async bulkVisitEvents(eventIds, userId) {
893893
const {
@@ -902,25 +902,53 @@ class EventsFactory extends Factory {
902902

903903
return !visitedBy.some((visitedUserId) => String(visitedUserId) === userIdStr);
904904
});
905-
const updatedEventIds = docsToUpdate.map(doc => doc._id.toString());
906905

907906
if (docsToUpdate.length === 0) {
908907
return {
909-
updatedCount: 0,
910908
updatedEventIds: [],
911909
failedEventIds,
912910
};
913911
}
914912

915-
const updateManyResult = await collection.updateMany(
916-
{ _id: { $in: docsToUpdate.map(doc => doc._id) } },
917-
{ $addToSet: { visitedBy: new ObjectId(userId) } }
913+
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+
);
924+
925+
return {
926+
eventId,
927+
updated: updateResult.modifiedCount > 0,
928+
};
929+
})
918930
);
919931

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+
920949
return {
921-
updatedCount: updateManyResult.modifiedCount,
922950
updatedEventIds,
923-
failedEventIds,
951+
failedEventIds: [ ...new Set([ ...failedEventIds, ...failedByUpdate ]) ],
924952
};
925953
}
926954

@@ -965,7 +993,7 @@ class EventsFactory extends Factory {
965993
*
966994
* @param {string[]} eventIds - original event ids
967995
* @param {string} mark - 'resolved' | 'ignored' | 'starred'
968-
* @returns {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
996+
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
969997
*/
970998
async bulkToggleEventMark(eventIds, mark) {
971999
const {
@@ -978,7 +1006,6 @@ class EventsFactory extends Factory {
9781006
const markKey = `marks.${mark}`;
9791007
const allHaveMark = found.length > 0 && found.every(doc => doc.marks && doc.marks[mark]);
9801008
const ops = [];
981-
const updatedEventIds = [];
9821009

9831010
for (const doc of found) {
9841011
const hasMark = doc.marks && doc.marks[mark];
@@ -998,23 +1025,50 @@ class EventsFactory extends Factory {
9981025
update,
9991026
},
10001027
});
1001-
updatedEventIds.push(doc._id.toString());
10021028
}
10031029

10041030
if (ops.length === 0) {
10051031
return {
1006-
updatedCount: 0,
10071032
updatedEventIds: [],
10081033
failedEventIds,
10091034
};
10101035
}
10111036

1012-
const bulkResult = await collection.bulkWrite(ops, { ordered: false });
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+
})
1050+
);
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+
});
10131068

10141069
return {
1015-
updatedCount: bulkResult.modifiedCount + bulkResult.upsertedCount,
10161070
updatedEventIds,
1017-
failedEventIds,
1071+
failedEventIds: [ ...new Set([ ...failedEventIds, ...failedByUpdate ]) ],
10181072
};
10191073
}
10201074

@@ -1023,7 +1077,7 @@ class EventsFactory extends Factory {
10231077
*
10241078
* @param {string[]} eventIds - original event ids
10251079
* @param {string|null|undefined} assignee - target assignee id, null/undefined to clear
1026-
* @returns {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
1080+
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
10271081
*/
10281082
async bulkUpdateAssignee(eventIds, assignee) {
10291083
const {
@@ -1034,25 +1088,51 @@ class EventsFactory extends Factory {
10341088

10351089
const normalizedAssignee = assignee ? String(assignee) : '';
10361090
const docsToUpdate = found.filter(doc => String(doc.assignee || '') !== normalizedAssignee);
1037-
const updatedEventIds = docsToUpdate.map(doc => doc._id.toString());
1038-
10391091
if (docsToUpdate.length === 0) {
10401092
return {
1041-
updatedCount: 0,
10421093
updatedEventIds: [],
10431094
failedEventIds,
10441095
};
10451096
}
10461097

1047-
const updateManyResult = await collection.updateMany(
1048-
{ _id: { $in: docsToUpdate.map(doc => doc._id) } },
1049-
{ $set: { assignee: normalizedAssignee } }
1098+
const settled = await Promise.allSettled(
1099+
docsToUpdate.map(async (doc) => {
1100+
const eventId = doc._id.toString();
1101+
const updateResult = await collection.updateOne(
1102+
{
1103+
_id: doc._id,
1104+
assignee: { $ne: normalizedAssignee },
1105+
},
1106+
{ $set: { assignee: normalizedAssignee } }
1107+
);
1108+
1109+
return {
1110+
eventId,
1111+
updated: updateResult.modifiedCount > 0,
1112+
};
1113+
})
10501114
);
10511115

1116+
const updatedEventIds = [];
1117+
const failedByUpdate = [];
1118+
1119+
settled.forEach((result, index) => {
1120+
const fallbackEventId = docsToUpdate[index]._id.toString();
1121+
1122+
if (result.status === 'fulfilled') {
1123+
if (result.value.updated) {
1124+
updatedEventIds.push(result.value.eventId);
1125+
} else {
1126+
failedByUpdate.push(result.value.eventId);
1127+
}
1128+
} else {
1129+
failedByUpdate.push(fallbackEventId);
1130+
}
1131+
});
1132+
10521133
return {
1053-
updatedCount: updateManyResult.modifiedCount,
10541134
updatedEventIds,
1055-
failedEventIds,
1135+
failedEventIds: [ ...new Set([ ...failedEventIds, ...failedByUpdate ]) ],
10561136
};
10571137
}
10581138

src/resolvers/event.js

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
const getEventsFactory = require('./helpers/eventsFactory').default;
22
const {
3-
fireAndForgetAssigneeNotifications,
43
parseBulkEventIds,
5-
mergeFailedEventIds,
6-
} = require('./helpers/bulkEvents');
4+
withMergedInvalidEventIds,
5+
enqueueAssigneeNotification,
6+
enqueueBulkAssigneeNotifications,
7+
} = require('./helpers/bulkEventUtils');
78
const { aiService } = require('../services/ai');
89
const { UserInputError } = require('apollo-server-express');
910
const { ObjectId } = require('mongodb');
@@ -148,14 +149,13 @@ module.exports = {
148149
* @param {string} projectId - project id
149150
* @param {string[]} eventIds - original event ids
150151
* @param {UserInContext} user - user context
151-
* @returns {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
152+
* @returns {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
152153
*/
153154
async bulkVisitEvents(_obj, { projectId, eventIds }, { user, ...context }) {
154155
const { validEventIds, invalidEventIds } = parseBulkEventIds(eventIds);
155156

156157
if (validEventIds.length === 0) {
157158
return {
158-
updatedCount: 0,
159159
updatedEventIds: [],
160160
failedEventIds: invalidEventIds,
161161
};
@@ -164,10 +164,7 @@ module.exports = {
164164
const factory = getEventsFactory(context, projectId);
165165
const result = await factory.bulkVisitEvents(validEventIds, user.id);
166166

167-
return {
168-
...result,
169-
failedEventIds: mergeFailedEventIds(result, invalidEventIds),
170-
};
167+
return withMergedInvalidEventIds(result, invalidEventIds);
171168
},
172169

173170
/**
@@ -196,14 +193,13 @@ module.exports = {
196193
* @param {string[]} eventIds - original event ids
197194
* @param {string} mark - EventMark enum value
198195
* @param {object} context - gql context
199-
* @return {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
196+
* @return {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
200197
*/
201198
async bulkToggleEventMarks(_obj, { projectId, eventIds, mark }, context) {
202199
const { validEventIds, invalidEventIds } = parseBulkEventIds(eventIds);
203200

204201
if (validEventIds.length === 0) {
205202
return {
206-
updatedCount: 0,
207203
updatedEventIds: [],
208204
failedEventIds: invalidEventIds,
209205
};
@@ -212,10 +208,7 @@ module.exports = {
212208
const factory = getEventsFactory(context, projectId);
213209
const result = await factory.bulkToggleEventMark(validEventIds, mark);
214210

215-
return {
216-
...result,
217-
failedEventIds: mergeFailedEventIds(result, invalidEventIds),
218-
};
211+
return withMergedInvalidEventIds(result, invalidEventIds);
219212
},
220213

221214
/**
@@ -261,12 +254,12 @@ module.exports = {
261254

262255
const assigneeData = await factories.usersFactory.dataLoaders.userById.load(assignee);
263256

264-
fireAndForgetAssigneeNotifications({
257+
enqueueAssigneeNotification({
265258
assigneeData,
266-
eventIds: [ eventId ],
267-
projectId,
268259
assigneeId: assignee,
260+
projectId,
269261
whoAssignedId: user.id,
262+
eventId,
270263
});
271264

272265
return {
@@ -300,7 +293,7 @@ module.exports = {
300293
* @param {ResolverObj} _obj - resolver context
301294
* @param {BulkUpdateAssigneeInput} input - object of arguments
302295
* @param factories - factories for working with models
303-
* @return {Promise<{ updatedCount: number, updatedEventIds: string[], failedEventIds: string[] }>}
296+
* @return {Promise<{ updatedEventIds: string[], failedEventIds: string[] }>}
304297
*/
305298
async bulkUpdateAssignee(_obj, { input }, { factories, user, ...context }) {
306299
const { projectId, eventIds, assignee } = input;
@@ -309,7 +302,6 @@ module.exports = {
309302

310303
if (validEventIds.length === 0) {
311304
return {
312-
updatedCount: 0,
313305
updatedEventIds: [],
314306
failedEventIds: invalidEventIds,
315307
};
@@ -340,18 +332,15 @@ module.exports = {
340332
}
341333

342334
const result = await factory.bulkUpdateAssignee(validEventIds, assignee);
343-
const resultWithInvalid = {
344-
...result,
345-
failedEventIds: mergeFailedEventIds(result, invalidEventIds),
346-
};
335+
const resultWithInvalid = withMergedInvalidEventIds(result, invalidEventIds);
347336

348337
if (assignee && resultWithInvalid.updatedEventIds.length > 0) {
349-
fireAndForgetAssigneeNotifications({
338+
enqueueBulkAssigneeNotifications({
350339
assigneeData,
351-
eventIds: resultWithInvalid.updatedEventIds,
352-
projectId,
353340
assigneeId: assignee,
341+
projectId,
354342
whoAssignedId: user.id,
343+
eventIds: resultWithInvalid.updatedEventIds,
355344
});
356345
}
357346

0 commit comments

Comments
 (0)