Skip to content

Commit 9d77538

Browse files
committed
refactor(events): rename bulk toggle event mark methods to bulk set event marks and update related documentation for clarity
1 parent ae8d3dc commit 9d77538

8 files changed

Lines changed: 165 additions & 174 deletions

src/models/eventsFactory.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -940,22 +940,21 @@ class EventsFactory extends Factory {
940940
}
941941

942942
/**
943-
* Bulk toggle mark for original events.
943+
* Bulk set or clear mark for original events.
944944
*
945945
* @param {string[]} eventIds - original event ids
946946
* @param {string} mark - 'resolved' | 'ignored' | 'starred'
947+
* @param {boolean} enabled - true to set mark, false to clear
947948
* @returns {Promise<UpdateWriteOpResult>}
948949
*/
949-
async bulkToggleEventMark(eventIds, mark) {
950+
async bulkSetEventMarks(eventIds, mark, enabled) {
950951
const uniqueEventIds = [ ...new Set((eventIds || []).map(id => String(id))) ];
951952
const objectIds = uniqueEventIds.map(id => new ObjectId(id));
952953
const collection = this.getCollection(this.TYPES.EVENTS);
953-
const found = await collection.find({ _id: { $in: objectIds } }).toArray();
954954
const nowSec = Math.floor(Date.now() / 1000);
955955
const markKey = `marks.${mark}`;
956-
const allHaveMark = found.length > 0 && found.every(doc => doc.marks && doc.marks[mark]);
957956

958-
if (allHaveMark) {
957+
if (!enabled) {
959958
return collection.updateMany(
960959
{
961960
_id: { $in: objectIds },

src/resolvers/event.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,21 +179,21 @@ module.exports = {
179179
},
180180

181181
/**
182-
* Bulk set resolved/ignored: always set mark on events that lack it, unless all selected
183-
* already have the mark — then remove from all.
182+
* Bulk set or clear mark for original events.
184183
*
185184
* @param {ResolverObj} _obj - resolver context
186185
* @param {string} projectId - project id
187186
* @param {string[]} eventIds - original event ids
188187
* @param {string} mark - EventMark enum value
188+
* @param {boolean} enabled - true to set mark, false to remove
189189
* @param {object} context - gql context
190190
* @return {Promise<{ success: boolean, modifiedCount: number }>}
191191
*/
192-
async bulkToggleEventMarks(_obj, { projectId, eventIds, mark }, context) {
192+
async bulkSetEventMarks(_obj, { projectId, eventIds, mark, enabled }, context) {
193193
const validEventIds = parseBulkEventIds(eventIds);
194194

195195
const factory = getEventsFactory(context, projectId);
196-
const result = await factory.bulkToggleEventMark(validEventIds, mark);
196+
const result = await factory.bulkSetEventMarks(validEventIds, mark, enabled);
197197

198198
return {
199199
success: !!result.acknowledged,

src/typeDefs/event.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ type BulkUpdateAssigneeResponse {
484484
"""
485485
Response of bulk toggling event marks (resolve / ignore / starred)
486486
"""
487-
type BulkToggleEventMarksResponse {
487+
type BulkSetEventMarksResponse {
488488
"""
489489
True when database accepted mutation
490490
"""
@@ -586,11 +586,9 @@ extend type Mutation {
586586
): Boolean!
587587
588588
"""
589-
Toggle the same mark on many original events at once (resolved, ignored or starred).
590-
Uses bulk semantics: if every selected event already has the mark, clear it for all;
591-
otherwise set it on each selected event that does not have it yet.
589+
Set or clear one mark on many original events at once (resolved, ignored or starred).
592590
"""
593-
bulkToggleEventMarks(
591+
bulkSetEventMarks(
594592
"""
595593
Project id
596594
"""
@@ -602,11 +600,15 @@ extend type Mutation {
602600
eventIds: [ID!]!
603601
604602
"""
605-
Mark (resolved, ignored or starred): if every selected event already has it, clear it for all;
606-
otherwise set it on every selected event that does not have it yet.
603+
Mark (resolved, ignored or starred) to update
607604
"""
608605
mark: EventMark!
609-
): BulkToggleEventMarksResponse! @requireUserInWorkspace
606+
607+
"""
608+
True - set mark, false - remove mark
609+
"""
610+
enabled: Boolean!
611+
): BulkSetEventMarksResponse! @requireUserInWorkspace
610612
611613
"""
612614
Namespace that contains only mutations related to the events

test/models/eventsFactory-bulk-toggle.test.ts

Lines changed: 21 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import '../../src/env-test';
22
import { ObjectId } from 'mongodb';
33

44
const collectionMock = {
5-
find: jest.fn(),
65
updateMany: jest.fn(),
76
};
87

@@ -35,7 +34,7 @@ jest.mock('../../src/mongo', () => ({
3534
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-explicit-any
3635
const EventsFactory = require('../../src/models/eventsFactory') as any;
3736

38-
describe('EventsFactory.bulkToggleEventMark', () => {
37+
describe('EventsFactory.bulkSetEventMarks', () => {
3938
const projectId = '507f1f77bcf86cd799439011';
4039

4140
beforeEach(() => {
@@ -46,25 +45,16 @@ describe('EventsFactory.bulkToggleEventMark', () => {
4645
});
4746
});
4847

49-
it('should support starred mark', async () => {
48+
it('should set starred mark when enabled is true', async () => {
5049
const factory = new EventsFactory(projectId);
5150
const id = new ObjectId();
5251

53-
collectionMock.find.mockReturnValue({
54-
toArray: () =>
55-
Promise.resolve([
56-
{
57-
_id: id,
58-
marks: {},
59-
},
60-
]),
61-
});
6252
collectionMock.updateMany.mockResolvedValue({
6353
acknowledged: true,
6454
modifiedCount: 1,
6555
});
6656

67-
const result = await factory.bulkToggleEventMark([ id.toString() ], 'starred');
57+
const result = await factory.bulkSetEventMarks([ id.toString() ], 'starred', true);
6858

6959
expect(result).toEqual({
7060
acknowledged: true,
@@ -81,159 +71,51 @@ describe('EventsFactory.bulkToggleEventMark', () => {
8171
);
8272
});
8373

84-
it('should deduplicate duplicate event ids before applying', async () => {
74+
it('should clear mark when enabled is false', async () => {
8575
const factory = new EventsFactory(projectId);
8676
const id = new ObjectId();
8777

88-
collectionMock.find.mockReturnValue({
89-
toArray: () =>
90-
Promise.resolve([
91-
{
92-
_id: id,
93-
marks: {},
94-
},
95-
]),
96-
});
9778
collectionMock.updateMany.mockResolvedValue({
9879
acknowledged: true,
9980
modifiedCount: 1,
10081
});
10182

102-
await factory.bulkToggleEventMark([id.toString(), id.toString(), id.toString()], 'ignored');
103-
104-
const query = collectionMock.updateMany.mock.calls[0][0];
83+
await factory.bulkSetEventMarks([ id.toString() ], 'ignored', false);
10584

106-
expect(query._id.$in).toHaveLength(1);
85+
expect(collectionMock.updateMany).toHaveBeenCalledWith(
86+
{
87+
_id: { $in: [ id ] },
88+
'marks.ignored': { $exists: true },
89+
},
90+
{ $unset: { 'marks.ignored': '' } }
91+
);
10792
});
10893

109-
it('should return success shape even when nothing changed', async () => {
94+
it('should deduplicate duplicate event ids before applying', async () => {
11095
const factory = new EventsFactory(projectId);
11196
const id = new ObjectId();
11297

113-
collectionMock.find.mockReturnValue({
114-
toArray: () => Promise.resolve([ {
115-
_id: id,
116-
marks: { ignored: 1 },
117-
} ]),
118-
});
119-
collectionMock.updateMany.mockResolvedValue({
120-
acknowledged: true,
121-
modifiedCount: 0,
122-
});
98+
await factory.bulkSetEventMarks([ id.toString(), id.toString(), id.toString() ], 'ignored', true);
12399

124-
const result = await factory.bulkToggleEventMark([ id.toString() ], 'ignored');
100+
const query = collectionMock.updateMany.mock.calls[0][0];
125101

126-
expect(result).toEqual({
127-
acknowledged: true,
128-
modifiedCount: 0,
129-
});
102+
expect(query._id.$in).toHaveLength(1);
130103
});
131104

132-
it('should set mark only on events that do not have it when selection is mixed', async () => {
105+
it('should return success shape even when nothing changed', async () => {
133106
const factory = new EventsFactory(projectId);
134-
const a = new ObjectId();
135-
const b = new ObjectId();
136-
137-
collectionMock.find.mockReturnValue({
138-
toArray: () =>
139-
Promise.resolve([
140-
{
141-
_id: a,
142-
marks: { ignored: 1 },
143-
},
144-
{
145-
_id: b,
146-
marks: {},
147-
},
148-
]),
149-
});
150-
collectionMock.updateMany.mockResolvedValue({
151-
acknowledged: true,
152-
modifiedCount: 1,
153-
});
154-
155-
await factory.bulkToggleEventMark([a.toString(), b.toString()], 'ignored');
156-
157-
expect(collectionMock.updateMany).toHaveBeenCalledWith(
158-
{
159-
_id: { $in: [a, b] },
160-
'marks.ignored': { $exists: false },
161-
},
162-
expect.objectContaining({
163-
$set: { 'marks.ignored': expect.any(Number) },
164-
})
165-
);
166-
});
107+
const id = new ObjectId();
167108

168-
it('should remove mark from all when every selected event already has the mark', async () => {
169-
const factory = new EventsFactory(projectId);
170-
const a = new ObjectId();
171-
const b = new ObjectId();
172-
173-
collectionMock.find.mockReturnValue({
174-
toArray: () =>
175-
Promise.resolve([
176-
{
177-
_id: a,
178-
marks: { resolved: 1 },
179-
},
180-
{
181-
_id: b,
182-
marks: { resolved: 2 },
183-
},
184-
]),
185-
});
186109
collectionMock.updateMany.mockResolvedValue({
187110
acknowledged: true,
188-
modifiedCount: 2,
111+
modifiedCount: 0,
189112
});
190113

191-
const result = await factory.bulkToggleEventMark([a.toString(), b.toString()], 'resolved');
114+
const result = await factory.bulkSetEventMarks([ id.toString() ], 'ignored', true);
192115

193116
expect(result).toEqual({
194117
acknowledged: true,
195-
modifiedCount: 2,
196-
});
197-
expect(collectionMock.updateMany).toHaveBeenCalledWith(
198-
{
199-
_id: { $in: [a, b] },
200-
'marks.resolved': { $exists: true },
201-
},
202-
{ $unset: { 'marks.resolved': '' } }
203-
);
204-
});
205-
206-
it('should not remove mark from a subset when only some of the found events have the mark', async () => {
207-
const factory = new EventsFactory(projectId);
208-
const a = new ObjectId();
209-
const b = new ObjectId();
210-
211-
collectionMock.find.mockReturnValue({
212-
toArray: () =>
213-
Promise.resolve([
214-
{
215-
_id: a,
216-
marks: { ignored: 1 },
217-
},
218-
{
219-
_id: b,
220-
marks: {},
221-
},
222-
]),
223-
});
224-
collectionMock.updateMany.mockResolvedValue({
225-
acknowledged: true,
226-
modifiedCount: 1,
118+
modifiedCount: 0,
227119
});
228-
229-
await factory.bulkToggleEventMark([a.toString(), b.toString()], 'ignored');
230-
231-
expect(collectionMock.updateMany).toHaveBeenCalledWith(
232-
{
233-
_id: { $in: [a, b] },
234-
'marks.ignored': { $exists: false },
235-
},
236-
expect.objectContaining({ $set: { 'marks.ignored': expect.any(Number) } })
237-
);
238120
});
239121
});

test/models/eventsFactory-bulk-update-assignee.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,30 @@ describe('EventsFactory.bulkUpdateAssignee', () => {
9393
{ $set: { assignee: '' } }
9494
);
9595
});
96+
97+
it('should clear assignee when assignee is undefined', async () => {
98+
const factory = new EventsFactory(projectId);
99+
const a = new ObjectId();
100+
101+
await factory.bulkUpdateAssignee([ a.toString() ], undefined);
102+
103+
expect(collectionMock.updateMany).toHaveBeenCalledWith(
104+
{
105+
_id: { $in: [ a ] },
106+
assignee: { $ne: '' },
107+
},
108+
{ $set: { assignee: '' } }
109+
);
110+
});
111+
112+
it('should deduplicate duplicate event ids before updateMany', async () => {
113+
const factory = new EventsFactory(projectId);
114+
const id = new ObjectId();
115+
116+
await factory.bulkUpdateAssignee([id.toString(), id.toString(), id.toString()], 'user-1');
117+
118+
const query = collectionMock.updateMany.mock.calls[0][0];
119+
120+
expect(query._id.$in).toHaveLength(1);
121+
});
96122
});

0 commit comments

Comments
 (0)