@remit/data-ports 0.0.77 → 0.0.79
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
|
@@ -170,6 +170,45 @@ export function calendarObjectRepositoryConformance(
|
|
|
170
170
|
);
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
+
test("listByUidPrefix finds the resources whose UID starts with the prefix, in one collection", async () => {
|
|
174
|
+
const calendarId = harness.makeId();
|
|
175
|
+
const other = harness.makeId();
|
|
176
|
+
const tail = await repo.put(
|
|
177
|
+
objectInput(calendarId, {
|
|
178
|
+
resourceName: "tail.ics",
|
|
179
|
+
icalUid: "root@example.com/following/1",
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
await repo.put(
|
|
183
|
+
objectInput(calendarId, {
|
|
184
|
+
resourceName: "root.ics",
|
|
185
|
+
icalUid: "root@example.com",
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
await repo.put(
|
|
189
|
+
objectInput(calendarId, {
|
|
190
|
+
resourceName: "lookalike.ics",
|
|
191
|
+
icalUid: "root@example.comx/following/2",
|
|
192
|
+
}),
|
|
193
|
+
);
|
|
194
|
+
await repo.put(
|
|
195
|
+
objectInput(other, {
|
|
196
|
+
resourceName: "elsewhere.ics",
|
|
197
|
+
icalUid: "root@example.com/following/3",
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const found = await repo.listByUidPrefix(
|
|
202
|
+
calendarId,
|
|
203
|
+
"root@example.com/following/",
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
assert.deepEqual(
|
|
207
|
+
found.map((object) => object.calendarObjectId),
|
|
208
|
+
[tail.calendarObjectId],
|
|
209
|
+
);
|
|
210
|
+
});
|
|
211
|
+
|
|
173
212
|
test("listByCalendar scopes to the collection", async () => {
|
|
174
213
|
const calendarId = harness.makeId();
|
|
175
214
|
const other = harness.makeId();
|
|
@@ -213,6 +213,56 @@ export function calendarSuggestionRepositoryConformance(
|
|
|
213
213
|
assert.equal(new Set(seen).size, 3);
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
+
test("listByAcceptedCalendarObjects returns, in one read, the account's suggestions answered into any of the resources", async () => {
|
|
217
|
+
const accountConfigId = harness.makeId();
|
|
218
|
+
const first = await repo.put(
|
|
219
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
220
|
+
);
|
|
221
|
+
const second = await repo.put(
|
|
222
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
223
|
+
);
|
|
224
|
+
const elsewhere = await repo.put(
|
|
225
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
226
|
+
);
|
|
227
|
+
const unasked = await repo.put(
|
|
228
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
229
|
+
);
|
|
230
|
+
const stranger = harness.makeId();
|
|
231
|
+
const strangers = await repo.put(
|
|
232
|
+
suggestion(stranger, harness.makeId(), harness.makeId(), "uid"),
|
|
233
|
+
);
|
|
234
|
+
for (const [owner, row, objectId] of [
|
|
235
|
+
[accountConfigId, first, "cal-object-1"],
|
|
236
|
+
[accountConfigId, second, "cal-object-1"],
|
|
237
|
+
[accountConfigId, elsewhere, "cal-object-2"],
|
|
238
|
+
[accountConfigId, unasked, "cal-object-3"],
|
|
239
|
+
[stranger, strangers, "cal-object-1"],
|
|
240
|
+
] as const) {
|
|
241
|
+
await repo.settle(owner, row.suggestionId, {
|
|
242
|
+
state: CalendarSuggestionState.Accepted,
|
|
243
|
+
acceptedCalendarObjectId: objectId,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const rows = await repo.listByAcceptedCalendarObjects(accountConfigId, [
|
|
248
|
+
"cal-object-1",
|
|
249
|
+
"cal-object-2",
|
|
250
|
+
]);
|
|
251
|
+
|
|
252
|
+
assert.deepEqual(
|
|
253
|
+
rows.map((row) => row.suggestionId).sort(),
|
|
254
|
+
[
|
|
255
|
+
first.suggestionId,
|
|
256
|
+
second.suggestionId,
|
|
257
|
+
elsewhere.suggestionId,
|
|
258
|
+
].sort(),
|
|
259
|
+
);
|
|
260
|
+
assert.deepEqual(
|
|
261
|
+
await repo.listByAcceptedCalendarObjects(accountConfigId, []),
|
|
262
|
+
[],
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
216
266
|
test("settle records the accepted resource", async () => {
|
|
217
267
|
const accountConfigId = harness.makeId();
|
|
218
268
|
const written = await repo.put(
|
|
@@ -234,12 +284,38 @@ export function calendarSuggestionRepositoryConformance(
|
|
|
234
284
|
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
235
285
|
);
|
|
236
286
|
|
|
287
|
+
const newerMessageId = harness.makeId();
|
|
237
288
|
const retired = await repo.supersedeIfPending(
|
|
238
289
|
accountConfigId,
|
|
239
290
|
written.suggestionId,
|
|
291
|
+
newerMessageId,
|
|
240
292
|
);
|
|
241
293
|
|
|
242
294
|
assert.equal(retired?.state, CalendarSuggestionState.Superseded);
|
|
295
|
+
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
296
|
+
assert.equal(reread.supersededByMessageId, newerMessageId);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test("a re-read of the retired message keeps the revision that retired it", async () => {
|
|
300
|
+
const accountConfigId = harness.makeId();
|
|
301
|
+
const input = suggestion(
|
|
302
|
+
accountConfigId,
|
|
303
|
+
harness.makeId(),
|
|
304
|
+
harness.makeId(),
|
|
305
|
+
"uid",
|
|
306
|
+
);
|
|
307
|
+
const written = await repo.put(input);
|
|
308
|
+
const newerMessageId = harness.makeId();
|
|
309
|
+
await repo.supersedeIfPending(
|
|
310
|
+
accountConfigId,
|
|
311
|
+
written.suggestionId,
|
|
312
|
+
newerMessageId,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
const rewritten = await repo.put(input);
|
|
316
|
+
|
|
317
|
+
assert.equal(rewritten.state, CalendarSuggestionState.Superseded);
|
|
318
|
+
assert.equal(rewritten.supersededByMessageId, newerMessageId);
|
|
243
319
|
});
|
|
244
320
|
|
|
245
321
|
test("supersedeIfPending leaves an answered card alone and says so", async () => {
|
|
@@ -258,11 +334,13 @@ export function calendarSuggestionRepositoryConformance(
|
|
|
258
334
|
const retired = await repo.supersedeIfPending(
|
|
259
335
|
accountConfigId,
|
|
260
336
|
written.suggestionId,
|
|
337
|
+
harness.makeId(),
|
|
261
338
|
);
|
|
262
339
|
|
|
263
340
|
assert.equal(retired, null);
|
|
264
341
|
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
265
342
|
assert.equal(reread.state, CalendarSuggestionState.Accepted);
|
|
343
|
+
assert.equal(reread.supersededByMessageId, "");
|
|
266
344
|
assert.equal(reread.acceptedCalendarObjectId, "cal-object-7");
|
|
267
345
|
});
|
|
268
346
|
|
|
@@ -273,9 +351,56 @@ export function calendarSuggestionRepositoryConformance(
|
|
|
273
351
|
);
|
|
274
352
|
|
|
275
353
|
assert.equal(
|
|
276
|
-
await repo.supersedeIfPending(
|
|
354
|
+
await repo.supersedeIfPending(
|
|
355
|
+
harness.makeId(),
|
|
356
|
+
written.suggestionId,
|
|
357
|
+
harness.makeId(),
|
|
358
|
+
),
|
|
359
|
+
null,
|
|
360
|
+
);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
test("repointSuperseded moves a retired card to a later revision", async () => {
|
|
364
|
+
const accountConfigId = harness.makeId();
|
|
365
|
+
const written = await repo.put(
|
|
366
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
367
|
+
);
|
|
368
|
+
await repo.supersedeIfPending(
|
|
369
|
+
accountConfigId,
|
|
370
|
+
written.suggestionId,
|
|
371
|
+
harness.makeId(),
|
|
372
|
+
);
|
|
373
|
+
const newest = harness.makeId();
|
|
374
|
+
|
|
375
|
+
const repointed = await repo.repointSuperseded(
|
|
376
|
+
accountConfigId,
|
|
377
|
+
written.suggestionId,
|
|
378
|
+
newest,
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
assert.equal(repointed?.supersededByMessageId, newest);
|
|
382
|
+
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
383
|
+
assert.equal(reread.state, CalendarSuggestionState.Superseded);
|
|
384
|
+
assert.equal(reread.supersededByMessageId, newest);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("repointSuperseded leaves a card that is not superseded alone", async () => {
|
|
388
|
+
const accountConfigId = harness.makeId();
|
|
389
|
+
const written = await repo.put(
|
|
390
|
+
suggestion(accountConfigId, harness.makeId(), harness.makeId(), "uid"),
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
assert.equal(
|
|
394
|
+
await repo.repointSuperseded(
|
|
395
|
+
accountConfigId,
|
|
396
|
+
written.suggestionId,
|
|
397
|
+
harness.makeId(),
|
|
398
|
+
),
|
|
277
399
|
null,
|
|
278
400
|
);
|
|
401
|
+
const reread = await repo.get(accountConfigId, written.suggestionId);
|
|
402
|
+
assert.equal(reread.state, CalendarSuggestionState.Pending);
|
|
403
|
+
assert.equal(reread.supersededByMessageId, "");
|
|
279
404
|
});
|
|
280
405
|
|
|
281
406
|
test("settle rejects a suggestion that is not there", async () => {
|
|
@@ -30,6 +30,10 @@ export interface ICalendarObjectRepository {
|
|
|
30
30
|
calendarId: string,
|
|
31
31
|
icalUid: string,
|
|
32
32
|
): Promise<CalendarObjectItem | null>;
|
|
33
|
+
listByUidPrefix(
|
|
34
|
+
calendarId: string,
|
|
35
|
+
prefix: string,
|
|
36
|
+
): Promise<CalendarObjectItem[]>;
|
|
33
37
|
listByCalendar(calendarId: string): Promise<CalendarObjectItem[]>;
|
|
34
38
|
/**
|
|
35
39
|
* The resources whose occurrence rows stop before `instant` — the series a
|
|
@@ -37,6 +37,10 @@ export interface ICalendarSuggestionRepository {
|
|
|
37
37
|
accountConfigId: string,
|
|
38
38
|
messageId: string,
|
|
39
39
|
): Promise<CalendarSuggestionItem[]>;
|
|
40
|
+
listByAcceptedCalendarObjects(
|
|
41
|
+
accountConfigId: string,
|
|
42
|
+
calendarObjectIds: string[],
|
|
43
|
+
): Promise<CalendarSuggestionItem[]>;
|
|
40
44
|
/**
|
|
41
45
|
* The account's suggestions in one state, newest first. Also how the
|
|
42
46
|
* producer finds the revision a new message supersedes: only a `Pending`
|
|
@@ -56,8 +60,9 @@ export interface ICalendarSuggestionRepository {
|
|
|
56
60
|
input: SettleCalendarSuggestionInput,
|
|
57
61
|
): Promise<CalendarSuggestionItem>;
|
|
58
62
|
/**
|
|
59
|
-
* Retires a card as `Superseded`, but only while it is still `Pending
|
|
60
|
-
*
|
|
63
|
+
* Retires a card as `Superseded`, but only while it is still `Pending`, and
|
|
64
|
+
* records the message whose revision retired it so the card can open that
|
|
65
|
+
* one. Returns the retired row, or `null` when the card had already been
|
|
61
66
|
* answered and nothing was written.
|
|
62
67
|
*
|
|
63
68
|
* A compare-and-set rather than a plain `settle` because the producer reads
|
|
@@ -69,5 +74,16 @@ export interface ICalendarSuggestionRepository {
|
|
|
69
74
|
supersedeIfPending(
|
|
70
75
|
accountConfigId: string,
|
|
71
76
|
suggestionId: string,
|
|
77
|
+
supersededByMessageId: string,
|
|
78
|
+
): Promise<CalendarSuggestionItem | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Points a card already `Superseded` at a later revision, so every retired
|
|
81
|
+
* revision of an event opens the newest one. Returns the updated row, or
|
|
82
|
+
* `null` when the card is not superseded and nothing was written.
|
|
83
|
+
*/
|
|
84
|
+
repointSuperseded(
|
|
85
|
+
accountConfigId: string,
|
|
86
|
+
suggestionId: string,
|
|
87
|
+
supersededByMessageId: string,
|
|
72
88
|
): Promise<CalendarSuggestionItem | null>;
|
|
73
89
|
}
|
package/src/types.ts
CHANGED
|
@@ -788,13 +788,15 @@ export type CalendarSuggestionItem = z.infer<typeof CalendarSuggestionSchema>;
|
|
|
788
788
|
* `state` and `acceptedCalendarObjectId` are excluded: a producer only ever
|
|
789
789
|
* writes a `Pending` suggestion, and the two fields that record what a person
|
|
790
790
|
* decided move exclusively through `settle`, so a re-sync can never walk an
|
|
791
|
-
* answered card back to Pending.
|
|
791
|
+
* answered card back to Pending. `supersededByMessageId` moves only through
|
|
792
|
+
* `supersedeIfPending`, with the state it explains.
|
|
792
793
|
*/
|
|
793
794
|
export type PutCalendarSuggestionInput = Omit<
|
|
794
795
|
CalendarSuggestionItem,
|
|
795
796
|
| "suggestionId"
|
|
796
797
|
| "state"
|
|
797
798
|
| "acceptedCalendarObjectId"
|
|
799
|
+
| "supersededByMessageId"
|
|
798
800
|
| "createdAt"
|
|
799
801
|
| "updatedAt"
|
|
800
802
|
>;
|