@remit/drizzle-service 0.0.97 → 0.0.99

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/drizzle-service",
3
- "version": "0.0.97",
3
+ "version": "0.0.99",
4
4
  "description": "Drizzle ORM service over SQLite",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -43,6 +43,7 @@ describe("MailboxLockRepo", () => {
43
43
  eventName,
44
44
  accountId,
45
45
  lockId,
46
+ 3600,
46
47
  );
47
48
  assert.equal(acquired, true, "should acquire lock");
48
49
 
@@ -71,6 +72,7 @@ describe("MailboxLockRepo", () => {
71
72
  eventName,
72
73
  accountId,
73
74
  lockId1,
75
+ 3600,
74
76
  );
75
77
  assert.equal(first, true, "first acquire should succeed");
76
78
 
@@ -79,6 +81,7 @@ describe("MailboxLockRepo", () => {
79
81
  eventName,
80
82
  accountId,
81
83
  lockId2,
84
+ 3600,
82
85
  );
83
86
  assert.equal(second, false, "second acquire should fail");
84
87
 
@@ -104,6 +107,7 @@ describe("MailboxLockRepo", () => {
104
107
  eventName,
105
108
  accountId,
106
109
  freshLockId,
110
+ 3600,
107
111
  );
108
112
  assert.equal(acquired, true, "should steal the expired lock");
109
113
 
@@ -129,13 +133,20 @@ describe("MailboxLockRepo", () => {
129
133
  const contenderLockId = randomId();
130
134
  const eventName = "SYNC_MESSAGES";
131
135
 
132
- await repo.tryAcquireLock(mailboxId, eventName, accountId, liveLockId);
136
+ await repo.tryAcquireLock(
137
+ mailboxId,
138
+ eventName,
139
+ accountId,
140
+ liveLockId,
141
+ 3600,
142
+ );
133
143
 
134
144
  const acquired = await repo.tryAcquireLock(
135
145
  mailboxId,
136
146
  eventName,
137
147
  accountId,
138
148
  contenderLockId,
149
+ 3600,
139
150
  );
140
151
  assert.equal(acquired, false, "should not steal a live lock");
141
152
 
@@ -166,8 +177,8 @@ describe("MailboxLockRepo", () => {
166
177
  });
167
178
 
168
179
  const results = await Promise.all([
169
- repo.tryAcquireLock(mailboxId, eventName, accountId, contenderA),
170
- repo.tryAcquireLock(mailboxId, eventName, accountId, contenderB),
180
+ repo.tryAcquireLock(mailboxId, eventName, accountId, contenderA, 3600),
181
+ repo.tryAcquireLock(mailboxId, eventName, accountId, contenderB, 3600),
171
182
  ]);
172
183
 
173
184
  assert.equal(
@@ -187,7 +198,7 @@ describe("MailboxLockRepo", () => {
187
198
  const lockId = randomId();
188
199
  const eventName = "SYNC_MESSAGES";
189
200
 
190
- await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId);
201
+ await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId, 3600);
191
202
  await repo.releaseLock(accountId, mailboxId, eventName, lockId);
192
203
 
193
204
  const lock = await repo.get(accountId, mailboxId, eventName);
@@ -201,7 +212,7 @@ describe("MailboxLockRepo", () => {
201
212
  const lockId2 = randomId();
202
213
  const eventName = "SYNC_MESSAGES";
203
214
 
204
- await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId1);
215
+ await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId1, 3600);
205
216
  await repo.releaseLock(accountId, mailboxId, eventName, lockId2); // wrong lockId
206
217
 
207
218
  const lock = await repo.get(accountId, mailboxId, eventName);
@@ -241,7 +252,7 @@ describe("MailboxLockRepo", () => {
241
252
  const lockId = randomId();
242
253
  const eventName = "SYNC_MESSAGES";
243
254
 
244
- await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId);
255
+ await repo.tryAcquireLock(mailboxId, eventName, accountId, lockId, 3600);
245
256
 
246
257
  const result = await repo.withMailboxLock(
247
258
  mailboxId,
@@ -287,12 +298,14 @@ describe("MailboxLockRepo", () => {
287
298
  "SYNC_MESSAGES",
288
299
  accountId,
289
300
  lockId1,
301
+ 3600,
290
302
  );
291
303
  const a2 = await repo.tryAcquireLock(
292
304
  mailboxId,
293
305
  "SYNC_FLAGS",
294
306
  accountId,
295
307
  lockId2,
308
+ 3600,
296
309
  );
297
310
 
298
311
  assert.equal(a1, true);
@@ -311,8 +324,8 @@ describe("MailboxLockRepo", () => {
311
324
  const lockId2 = randomId();
312
325
  const eventName = "SYNC_MESSAGES";
313
326
 
314
- await repo.tryAcquireLock(mailboxId1, eventName, accountId1, lockId1);
315
- await repo.tryAcquireLock(mailboxId2, eventName, accountId2, lockId2);
327
+ await repo.tryAcquireLock(mailboxId1, eventName, accountId1, lockId1, 3600);
328
+ await repo.tryAcquireLock(mailboxId2, eventName, accountId2, lockId2, 3600);
316
329
 
317
330
  const locks = await repo.listByAccount(accountId1);
318
331
  assert.equal(locks.filter((l) => l.lockId === lockId1).length, 1);
@@ -329,8 +342,8 @@ describe("MailboxLockRepo", () => {
329
342
  const mb1 = randomId();
330
343
  const mb2 = randomId();
331
344
 
332
- await repo.tryAcquireLock(mb1, "SYNC_MESSAGES", accountId, lockId1);
333
- await repo.tryAcquireLock(mb2, "SYNC_FLAGS", accountId, lockId2);
345
+ await repo.tryAcquireLock(mb1, "SYNC_MESSAGES", accountId, lockId1, 3600);
346
+ await repo.tryAcquireLock(mb2, "SYNC_FLAGS", accountId, lockId2, 3600);
334
347
 
335
348
  await repo.deleteByAccount(accountId);
336
349
 
@@ -343,7 +356,13 @@ describe("MailboxLockRepo", () => {
343
356
  const other = randomId();
344
357
  const mailboxId = randomId();
345
358
  const lockId = randomId();
346
- await repo.tryAcquireLock(mailboxId, "SYNC_MESSAGES", accountId, lockId);
359
+ await repo.tryAcquireLock(
360
+ mailboxId,
361
+ "SYNC_MESSAGES",
362
+ accountId,
363
+ lockId,
364
+ 3600,
365
+ );
347
366
 
348
367
  assert.ok(await repo.get(accountId, mailboxId, "SYNC_MESSAGES"));
349
368
  assert.equal(await repo.get(other, mailboxId, "SYNC_MESSAGES"), null);
@@ -356,7 +375,13 @@ describe("MailboxLockRepo", () => {
356
375
  const other = randomId();
357
376
  const mailboxId = randomId();
358
377
  const lockId = randomId();
359
- await repo.tryAcquireLock(mailboxId, "SYNC_MESSAGES", accountId, lockId);
378
+ await repo.tryAcquireLock(
379
+ mailboxId,
380
+ "SYNC_MESSAGES",
381
+ accountId,
382
+ lockId,
383
+ 3600,
384
+ );
360
385
 
361
386
  // Foreign account with the (leaked) lockId still cannot release it.
362
387
  await repo.releaseLock(other, mailboxId, "SYNC_MESSAGES", lockId);
@@ -32,10 +32,11 @@ export class MailboxLockRepo implements IMailboxLockRepository {
32
32
  eventName: string,
33
33
  accountId: string,
34
34
  lockId: string,
35
+ ttlSeconds: number,
35
36
  ): Promise<boolean> {
36
37
  const now = Date.now();
37
38
  const nowSeconds = Math.floor(now / 1000);
38
- const ttl = nowSeconds + TTL_SECONDS;
39
+ const ttl = nowSeconds + ttlSeconds;
39
40
 
40
41
  const rows = await this.db
41
42
  .insert(mailboxLockTable)
@@ -90,6 +91,7 @@ export class MailboxLockRepo implements IMailboxLockRepository {
90
91
  eventName,
91
92
  accountId,
92
93
  lockId,
94
+ TTL_SECONDS,
93
95
  );
94
96
  if (!acquired) return { executed: false };
95
97
 
@@ -249,6 +249,40 @@ describe("DrizzleMessageRepository (sqlite)", () => {
249
249
  });
250
250
  });
251
251
 
252
+ describe("deleteIfPlacement", () => {
253
+ const GONE_ID = "00000000-0000-0000-2222-00000000000c";
254
+
255
+ before(async () => {
256
+ await repo.create({
257
+ ...BASE_INPUT,
258
+ messageId: GONE_ID,
259
+ uid: 9,
260
+ envelopeId: deriveEnvelopeId(GONE_ID),
261
+ rootBodyPartId: deriveRootBodyPartId(GONE_ID),
262
+ });
263
+ });
264
+
265
+ test("keeps the row when its placement no longer matches what was read", async () => {
266
+ const deleted = await repo.deleteIfPlacement(GONE_ID, {
267
+ mailboxId: MAILBOX_ID,
268
+ uid: 8,
269
+ });
270
+
271
+ assert.equal(deleted, false);
272
+ assert.equal((await repo.get(GONE_ID)).uid, 9);
273
+ });
274
+
275
+ test("deletes the row while its placement still matches", async () => {
276
+ const deleted = await repo.deleteIfPlacement(GONE_ID, {
277
+ mailboxId: MAILBOX_ID,
278
+ uid: 9,
279
+ });
280
+
281
+ assert.equal(deleted, true);
282
+ await assert.rejects(() => repo.get(GONE_ID));
283
+ });
284
+ });
285
+
252
286
  test("requestReembed queues a forced re-index for each message that still exists", async () => {
253
287
  const movedRows = () =>
254
288
  db
@@ -492,6 +492,27 @@ export class DrizzleMessageRepository implements IMessageRepository {
492
492
  await this.deleteMany([messageId]);
493
493
  }
494
494
 
495
+ async deleteIfPlacement(
496
+ messageId: string,
497
+ expected: PlacementPredicate,
498
+ ): Promise<boolean> {
499
+ return runInTransaction(this.db, async (tx) => {
500
+ const claimed = await tx
501
+ .update(messageTable)
502
+ .set({ updatedAt: Date.now() })
503
+ .where(
504
+ and(
505
+ eq(messageTable.messageId, messageId),
506
+ ...placementTerms(expected),
507
+ ),
508
+ )
509
+ .returning({ messageId: messageTable.messageId });
510
+ if (claimed.length === 0) return false;
511
+ await deleteMessageSubtree(tx as unknown as SubtreeDb, [messageId]);
512
+ return true;
513
+ });
514
+ }
515
+
495
516
  async deleteMany(messageIds: string[]): Promise<void> {
496
517
  if (messageIds.length === 0) return;
497
518
  await runInTransaction(this.db, (tx) =>