@marcoappio/marco-config 2.0.481 → 2.0.483

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":"threadMutators.d.ts","sourceRoot":"","sources":["../../../../src/zero/mutators/threadMutators/threadMutators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,KAAK,CAAC,MAAM,SAAS,CAAA;AAEjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAiB,MAAM,qBAAqB,CAAA;AAEnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEhE,MAAM,MAAM,sBAAsB,GAAG;KAClC,CAAC,IAAI,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAC1C,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAC1D,OAAO,CAAC,IAAI,CAAC;CACnB,CAAA;AAKD,eAAO,MAAM,cAAc,OACrB,WAAW,CAAC,eAAe,CAAC,YACtB,MAAM,oBACE,eAAe,KAChC,OAAO,CAAC,kBAAkB,EAAE,CA0G9B,CAAA;AAED,eAAO,MAAM,oBAAoB,cACpB,QAAQ,GAAG,SAAS,cACnB,sBAAsB,KACjC,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAkQxC,CAAA"}
1
+ {"version":3,"file":"threadMutators.d.ts","sourceRoot":"","sources":["../../../../src/zero/mutators/threadMutators/threadMutators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,KAAK,KAAK,CAAC,MAAM,SAAS,CAAA;AAEjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAiB,MAAM,qBAAqB,CAAA;AAEnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEhE,MAAM,MAAM,sBAAsB,GAAG;KAClC,CAAC,IAAI,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAC1C,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAC1D,OAAO,CAAC,IAAI,CAAC;CACnB,CAAA;AAKD,eAAO,MAAM,cAAc,OACrB,WAAW,CAAC,eAAe,CAAC,YACtB,MAAM,oBACE,eAAe,KAChC,OAAO,CAAC,kBAAkB,EAAE,CAsG9B,CAAA;AAED,eAAO,MAAM,oBAAoB,cACpB,QAAQ,GAAG,SAAS,cACnB,sBAAsB,KACjC,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAmQxC,CAAA"}
@@ -6,26 +6,22 @@ export const setSystemLabel = async (tx, threadId, targetSpecialUse) => {
6
6
  if (!thread) {
7
7
  throw new Error(MutationError.ENTITY_NOT_FOUND);
8
8
  }
9
- const targetLabel = await tx.query.accountLabel
10
- .where('accountId', thread.accountId)
11
- .where('specialUse', targetSpecialUse)
12
- .one()
13
- .run();
9
+ const [targetLabel, threadLabels] = await Promise.all([
10
+ tx.query.accountLabel.where('accountId', thread.accountId).where('specialUse', targetSpecialUse).one().run(),
11
+ tx.query.threadLabel.where('threadId', threadId).run(),
12
+ ]);
14
13
  if (!targetLabel) {
15
14
  throw new Error(MutationError.ENTITY_NOT_FOUND);
16
15
  }
17
- const threadLabels = await tx.query.threadLabel.where('threadId', threadId).run();
16
+ const currentLabelIds = new Set(threadsUtils.parseLabelIdList(thread.labelIdList));
17
+ const hasTarget = currentLabelIds.has(targetLabel.id);
18
+ const labelIdsToRemove = new Set(currentLabelIds);
19
+ labelIdsToRemove.delete(targetLabel.id);
18
20
  const sourceLocations = [];
19
- const labelsToDelete = [];
20
- const labelIdsToRemove = new Set();
21
- let hasTarget = false;
21
+ const threadLabelDeletePromises = [];
22
22
  for (const label of threadLabels) {
23
- if (label.labelId === targetLabel.id) {
24
- hasTarget = true;
23
+ if (label.labelId === targetLabel.id)
25
24
  continue;
26
- }
27
- labelsToDelete.push(label);
28
- labelIdsToRemove.add(label.labelId);
29
25
  if (label.uid > 0 && label.uidValidity > 0) {
30
26
  sourceLocations.push({
31
27
  labelId: label.labelId,
@@ -34,35 +30,28 @@ export const setSystemLabel = async (tx, threadId, targetSpecialUse) => {
34
30
  uidValidity: label.uidValidity,
35
31
  });
36
32
  }
37
- }
38
- for (const label of labelsToDelete) {
39
- await tx.mutate.threadLabel.delete({
33
+ threadLabelDeletePromises.push(tx.mutate.threadLabel.delete({
40
34
  accountId: thread.accountId,
41
35
  labelId: label.labelId,
42
36
  threadMessageId: label.threadMessageId,
43
- });
44
- }
45
- for (const labelId of labelIdsToRemove) {
46
- await tx.mutate.threadByLabel.delete({
47
- labelId,
48
- threadId,
49
- });
37
+ }));
50
38
  }
39
+ await Promise.all([
40
+ ...threadLabelDeletePromises,
41
+ ...[...labelIdsToRemove].map(labelId => tx.mutate.threadByLabel.delete({ labelId, threadId })),
42
+ ]);
51
43
  if (thread.seen === false && labelIdsToRemove.size > 0) {
52
44
  const labelsToUpdate = await tx.query.accountLabel.where('id', 'IN', [...labelIdsToRemove]).run();
53
- for (const label of labelsToUpdate) {
54
- await tx.mutate.accountLabel.update({
55
- id: label.id,
56
- unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
57
- });
58
- }
45
+ await Promise.all(labelsToUpdate.map(label => tx.mutate.accountLabel.update({
46
+ id: label.id,
47
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
48
+ })));
59
49
  }
60
50
  if (!hasTarget) {
61
51
  const messages = await tx.query.threadMessage.where('threadId', threadId).run();
62
52
  const baseTimestamp = Date.now();
63
- for (let i = 0; i < messages.length; i++) {
64
- const message = messages[i];
65
- await tx.mutate.threadLabel.insert({
53
+ await Promise.all([
54
+ ...messages.map((message, i) => tx.mutate.threadLabel.insert({
66
55
  accountId: thread.accountId,
67
56
  labelId: targetLabel.id,
68
57
  lastSyncedAt: 0,
@@ -70,19 +59,21 @@ export const setSystemLabel = async (tx, threadId, targetSpecialUse) => {
70
59
  threadMessageId: message.id,
71
60
  uid: -(baseTimestamp + i),
72
61
  uidValidity: targetLabel.uidValidity ?? 0,
73
- });
74
- }
75
- await tx.mutate.threadByLabel.insert({
76
- labelId: targetLabel.id,
77
- latestMessageDate: thread.latestMessageDate,
78
- threadId,
79
- });
80
- if (thread.seen === false) {
81
- await tx.mutate.accountLabel.update({
82
- id: targetLabel.id,
83
- unreadCount: (targetLabel.unreadCount ?? 0) + 1,
84
- });
85
- }
62
+ })),
63
+ tx.mutate.threadByLabel.insert({
64
+ labelId: targetLabel.id,
65
+ latestMessageDate: thread.latestMessageDate,
66
+ threadId,
67
+ }),
68
+ ...(thread.seen === false
69
+ ? [
70
+ tx.mutate.accountLabel.update({
71
+ id: targetLabel.id,
72
+ unreadCount: (targetLabel.unreadCount ?? 0) + 1,
73
+ }),
74
+ ]
75
+ : []),
76
+ ]);
86
77
  }
87
78
  await tx.mutate.thread.update({
88
79
  id: threadId,
@@ -97,53 +88,44 @@ export const createThreadMutators = (_authData, callbacks) => ({
97
88
  if (!thread) {
98
89
  throw new Error(MutationError.ENTITY_NOT_FOUND);
99
90
  }
100
- const label = await tx.query.accountLabel
101
- .where('accountId', thread.accountId)
102
- .where('path', args.labelPath)
103
- .one()
104
- .run();
91
+ const [label, messages] = await Promise.all([
92
+ tx.query.accountLabel.where('accountId', thread.accountId).where('path', args.labelPath).one().run(),
93
+ tx.query.threadMessage.where('threadId', threadId).run(),
94
+ ]);
105
95
  if (!label) {
106
96
  throw new Error(MutationError.ENTITY_NOT_FOUND);
107
97
  }
108
- const existingThreadByLabel = await tx.query.threadByLabel
109
- .where('labelId', label.id)
110
- .where('threadId', threadId)
111
- .one()
112
- .run();
113
- if (!existingThreadByLabel) {
114
- await tx.mutate.threadByLabel.insert({
115
- labelId: label.id,
116
- latestMessageDate: thread.latestMessageDate,
117
- threadId,
118
- });
119
- if (thread.seen === false) {
120
- await tx.mutate.accountLabel.update({
121
- id: label.id,
122
- unreadCount: (label.unreadCount ?? 0) + 1,
123
- });
124
- }
125
- }
126
- const messages = await tx.query.threadMessage.where('threadId', threadId).run();
127
- const baseTimestamp = Date.now();
128
- let insertIndex = 0;
129
- for (const message of messages) {
130
- const existing = await tx.query.threadLabel
131
- .where('threadMessageId', message.id)
132
- .where('labelId', label.id)
133
- .one()
134
- .run();
135
- if (!existing) {
136
- await tx.mutate.threadLabel.insert({
137
- accountId: thread.accountId,
98
+ const currentLabelIds = new Set(threadsUtils.parseLabelIdList(thread.labelIdList));
99
+ if (!currentLabelIds.has(label.id)) {
100
+ await Promise.all([
101
+ tx.mutate.threadByLabel.insert({
138
102
  labelId: label.id,
139
- lastSyncedAt: 0,
103
+ latestMessageDate: thread.latestMessageDate,
140
104
  threadId,
141
- threadMessageId: message.id,
142
- uid: -(baseTimestamp + insertIndex),
143
- uidValidity: label.uidValidity ?? 0,
144
- });
145
- insertIndex++;
146
- }
105
+ }),
106
+ ...(thread.seen === false
107
+ ? [
108
+ tx.mutate.accountLabel.update({
109
+ id: label.id,
110
+ unreadCount: (label.unreadCount ?? 0) + 1,
111
+ }),
112
+ ]
113
+ : []),
114
+ ]);
115
+ }
116
+ const existingChecks = await Promise.all(messages.map(message => tx.query.threadLabel.where('threadMessageId', message.id).where('labelId', label.id).one().run()));
117
+ const messagesToInsert = messages.filter((_, i) => !existingChecks[i]);
118
+ const baseTimestamp = Date.now();
119
+ if (messagesToInsert.length > 0) {
120
+ await Promise.all(messagesToInsert.map((message, i) => tx.mutate.threadLabel.insert({
121
+ accountId: thread.accountId,
122
+ labelId: label.id,
123
+ lastSyncedAt: 0,
124
+ threadId,
125
+ threadMessageId: message.id,
126
+ uid: -(baseTimestamp + i),
127
+ uidValidity: label.uidValidity ?? 0,
128
+ })));
147
129
  }
148
130
  const allLabels = await tx.query.threadLabel.where('threadId', threadId).run();
149
131
  await tx.mutate.thread.update({
@@ -161,12 +143,10 @@ export const createThreadMutators = (_authData, callbacks) => ({
161
143
  const labelIds = threadsUtils.parseLabelIdList(thread.labelIdList);
162
144
  if (labelIds.length > 0) {
163
145
  const labels = await tx.query.accountLabel.where('id', 'IN', labelIds).run();
164
- for (const label of labels) {
165
- await tx.mutate.accountLabel.update({
166
- id: label.id,
167
- unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
168
- });
169
- }
146
+ await Promise.all(labels.map(label => tx.mutate.accountLabel.update({
147
+ id: label.id,
148
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
149
+ })));
170
150
  }
171
151
  }
172
152
  await tx.mutate.thread.delete({
@@ -183,19 +163,18 @@ export const createThreadMutators = (_authData, callbacks) => ({
183
163
  if (!thread) {
184
164
  throw new Error(MutationError.ENTITY_NOT_FOUND);
185
165
  }
186
- const label = await tx.query.accountLabel
187
- .where('accountId', thread.accountId)
188
- .where('path', args.labelPath)
189
- .one()
190
- .run();
166
+ const [label, existingLabels] = await Promise.all([
167
+ tx.query.accountLabel.where('accountId', thread.accountId).where('path', args.labelPath).one().run(),
168
+ tx.query.threadLabel.where('threadId', threadId).run(),
169
+ ]);
191
170
  if (!label) {
192
171
  throw new Error(MutationError.ENTITY_NOT_FOUND);
193
172
  }
194
- const existingLabels = await tx.query.threadLabel.where('threadId', threadId).where('labelId', label.id).run();
195
- if (existingLabels.length === 0) {
173
+ const labelsForThisLabel = existingLabels.filter(x => x.labelId === label.id);
174
+ if (labelsForThisLabel.length === 0) {
196
175
  throw new Error(MutationError.ENTITY_NOT_FOUND);
197
176
  }
198
- for (const existing of existingLabels) {
177
+ for (const existing of labelsForThisLabel) {
199
178
  if (existing.uid > 0 && existing.uidValidity > 0) {
200
179
  allSourceLocations.push({
201
180
  labelId: existing.labelId,
@@ -204,52 +183,53 @@ export const createThreadMutators = (_authData, callbacks) => ({
204
183
  uidValidity: existing.uidValidity,
205
184
  });
206
185
  }
207
- await tx.mutate.threadLabel.delete({
186
+ }
187
+ const currentLabelIds = new Set(threadsUtils.parseLabelIdList(thread.labelIdList));
188
+ currentLabelIds.delete(label.id);
189
+ await Promise.all([
190
+ ...labelsForThisLabel.map(existing => tx.mutate.threadLabel.delete({
208
191
  accountId: thread.accountId,
209
192
  labelId: label.id,
210
193
  threadMessageId: existing.threadMessageId,
211
- });
212
- }
213
- await tx.mutate.threadByLabel.delete({
214
- labelId: label.id,
215
- threadId,
216
- });
217
- if (thread.seen === false) {
218
- await tx.mutate.accountLabel.update({
219
- id: label.id,
220
- unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
221
- });
222
- }
223
- const remainingLabels = await tx.query.threadLabel.where('threadId', threadId).run();
224
- await tx.mutate.thread.update({
225
- id: threadId,
226
- labelIdList: buildLabelIdList([...new Set(remainingLabels.map(x => x.labelId))]),
227
- });
194
+ })),
195
+ tx.mutate.threadByLabel.delete({
196
+ labelId: label.id,
197
+ threadId,
198
+ }),
199
+ ...(thread.seen === false
200
+ ? [
201
+ tx.mutate.accountLabel.update({
202
+ id: label.id,
203
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) - 1),
204
+ }),
205
+ ]
206
+ : []),
207
+ tx.mutate.thread.update({
208
+ id: threadId,
209
+ labelIdList: buildLabelIdList([...currentLabelIds]),
210
+ }),
211
+ ]);
228
212
  }
229
213
  callbacks?.removeLabel?.({ ...args, sourceLocations: allSourceLocations });
230
214
  },
231
215
  setArchive: async (tx, args) => {
232
216
  const allSourceLocations = [];
233
217
  for (const threadId of args.threadIds) {
234
- const sourceLocations = await setSystemLabel(tx, threadId, 'ARCHIVE');
235
- allSourceLocations.push(...sourceLocations);
218
+ allSourceLocations.push(...(await setSystemLabel(tx, threadId, 'ARCHIVE')));
236
219
  }
237
220
  callbacks?.setArchive?.({ ...args, sourceLocations: allSourceLocations });
238
221
  },
239
222
  setFlagged: async (tx, args) => {
240
- for (const threadId of args.threadIds) {
241
- await tx.mutate.thread.update({
242
- flagged: args.flagged,
243
- id: threadId,
244
- });
245
- }
223
+ await Promise.all(args.threadIds.map(threadId => tx.mutate.thread.update({
224
+ flagged: args.flagged,
225
+ id: threadId,
226
+ })));
246
227
  callbacks?.setFlagged?.(args);
247
228
  },
248
229
  setInbox: async (tx, args) => {
249
230
  const allSourceLocations = [];
250
231
  for (const threadId of args.threadIds) {
251
- const sourceLocations = await setSystemLabel(tx, threadId, 'INBOX');
252
- allSourceLocations.push(...sourceLocations);
232
+ allSourceLocations.push(...(await setSystemLabel(tx, threadId, 'INBOX')));
253
233
  }
254
234
  callbacks?.setInbox?.({ ...args, sourceLocations: allSourceLocations });
255
235
  },
@@ -266,37 +246,30 @@ export const createThreadMutators = (_authData, callbacks) => ({
266
246
  if (labelCounts.size > 0) {
267
247
  const labels = await tx.query.accountLabel.where('id', 'IN', [...labelCounts.keys()]).run();
268
248
  const delta = args.seen ? -1 : 1;
269
- for (const label of labels) {
270
- const threadCount = labelCounts.get(label.id);
271
- if (threadCount) {
272
- await tx.mutate.accountLabel.update({
273
- id: label.id,
274
- unreadCount: Math.max(0, (label.unreadCount ?? 0) + delta * threadCount),
275
- });
276
- }
277
- }
278
- }
279
- for (const threadId of args.threadIds) {
280
- await tx.mutate.thread.update({
281
- id: threadId,
282
- seen: args.seen,
283
- });
249
+ await Promise.all(labels
250
+ .filter(label => labelCounts.has(label.id))
251
+ .map(label => tx.mutate.accountLabel.update({
252
+ id: label.id,
253
+ unreadCount: Math.max(0, (label.unreadCount ?? 0) + delta * (labelCounts.get(label.id) ?? 0)),
254
+ })));
284
255
  }
256
+ await Promise.all(args.threadIds.map(threadId => tx.mutate.thread.update({
257
+ id: threadId,
258
+ seen: args.seen,
259
+ })));
285
260
  callbacks?.setSeen?.(args);
286
261
  },
287
262
  setSpam: async (tx, args) => {
288
263
  const allSourceLocations = [];
289
264
  for (const threadId of args.threadIds) {
290
- const sourceLocations = await setSystemLabel(tx, threadId, 'SPAM');
291
- allSourceLocations.push(...sourceLocations);
265
+ allSourceLocations.push(...(await setSystemLabel(tx, threadId, 'SPAM')));
292
266
  }
293
267
  callbacks?.setSpam?.({ ...args, sourceLocations: allSourceLocations });
294
268
  },
295
269
  setTrash: async (tx, args) => {
296
270
  const allSourceLocations = [];
297
271
  for (const threadId of args.threadIds) {
298
- const sourceLocations = await setSystemLabel(tx, threadId, 'TRASH');
299
- allSourceLocations.push(...sourceLocations);
272
+ allSourceLocations.push(...(await setSystemLabel(tx, threadId, 'TRASH')));
300
273
  }
301
274
  callbacks?.setTrash?.({ ...args, sourceLocations: allSourceLocations });
302
275
  },
@@ -30,6 +30,9 @@ describe('threadMutators', () => {
30
30
  if (field === 'threadId') {
31
31
  return { run: runAllThreadLabels, where: whereLabelId };
32
32
  }
33
+ if (field === 'threadMessageId') {
34
+ return { where: whereLabelId };
35
+ }
33
36
  return { where: whereLabelId };
34
37
  });
35
38
  const threadLabelInsert = mock(async () => { });
@@ -232,11 +235,10 @@ describe('threadMutators', () => {
232
235
  const whereLabelPath = mock(() => ({ one: oneLabel }));
233
236
  const whereLabelAccount = mock(() => ({ where: whereLabelPath }));
234
237
  const runExisting = mock(async () => existingRecords);
235
- const runRemainingLabels = mock(async () => []);
236
238
  const whereLabelId = mock(() => ({ run: runExisting }));
237
239
  const whereThreadLabel = mock((field) => {
238
240
  if (field === 'threadId') {
239
- return { run: runRemainingLabels, where: whereLabelId };
241
+ return { run: runExisting, where: whereLabelId };
240
242
  }
241
243
  return { where: whereLabelId };
242
244
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcoappio/marco-config",
3
- "version": "2.0.481",
3
+ "version": "2.0.483",
4
4
  "author": "team@marcoapp.io",
5
5
  "main": "dist/index.js",
6
6
  "repository": "git@github.com:marcoappio/marco-config.git",