@remit/drizzle-service 0.0.96 → 0.0.97
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
|
@@ -242,6 +242,7 @@ describe("the calendar tables under the shipped migrations", () => {
|
|
|
242
242
|
summary: "Design review",
|
|
243
243
|
dtStart: "2026-09-01T10:00:00+02:00",
|
|
244
244
|
dtEnd: "2026-09-01T11:00:00+02:00",
|
|
245
|
+
endsAtUtc: "2026-09-01T09:00:00Z",
|
|
245
246
|
allDay: false,
|
|
246
247
|
location: "",
|
|
247
248
|
organizer: "organizer@example.test",
|
|
@@ -256,3 +257,89 @@ describe("the calendar tables under the shipped migrations", () => {
|
|
|
256
257
|
assert.equal(fetched.organizer, "organizer@example.test");
|
|
257
258
|
});
|
|
258
259
|
});
|
|
260
|
+
|
|
261
|
+
describe("the ends_at_utc backfill of existing suggestions", () => {
|
|
262
|
+
const TAG = "0039_calendar_suggestion_ends_at_utc";
|
|
263
|
+
const VTIMEZONE = [
|
|
264
|
+
"BEGIN:VTIMEZONE",
|
|
265
|
+
"TZID:Europe/Amsterdam",
|
|
266
|
+
"BEGIN:DAYLIGHT",
|
|
267
|
+
"DTSTART:19700329T020000",
|
|
268
|
+
"RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU",
|
|
269
|
+
"END:DAYLIGHT",
|
|
270
|
+
"END:VTIMEZONE",
|
|
271
|
+
];
|
|
272
|
+
const invite = (...eventLines: string[]): string =>
|
|
273
|
+
[
|
|
274
|
+
"BEGIN:VCALENDAR",
|
|
275
|
+
...VTIMEZONE,
|
|
276
|
+
"BEGIN:VEVENT",
|
|
277
|
+
...eventLines,
|
|
278
|
+
"END:VEVENT",
|
|
279
|
+
"END:VCALENDAR",
|
|
280
|
+
"",
|
|
281
|
+
].join("\r\n");
|
|
282
|
+
|
|
283
|
+
const backfilled = (
|
|
284
|
+
rows: Record<string, { dtEnd: string; icalData: string }>,
|
|
285
|
+
): Record<string, string> => {
|
|
286
|
+
const sqlite = new Database(":memory:");
|
|
287
|
+
for (const entry of migrationJournal()) {
|
|
288
|
+
if (entry.tag === TAG) break;
|
|
289
|
+
applyMigration(sqlite, entry.tag);
|
|
290
|
+
}
|
|
291
|
+
const columns = sqlite
|
|
292
|
+
.prepare("PRAGMA table_info(calendar_suggestion)")
|
|
293
|
+
.all() as { name: string; type: string }[];
|
|
294
|
+
for (const [id, row] of Object.entries(rows)) {
|
|
295
|
+
const values: Record<string, string | number> = {};
|
|
296
|
+
for (const column of columns) {
|
|
297
|
+
values[column.name] = column.type === "integer" ? 0 : "";
|
|
298
|
+
}
|
|
299
|
+
values.suggestion_id = id;
|
|
300
|
+
values.dt_end = row.dtEnd;
|
|
301
|
+
values.ical_data = row.icalData;
|
|
302
|
+
const names = Object.keys(values);
|
|
303
|
+
sqlite
|
|
304
|
+
.prepare(
|
|
305
|
+
`INSERT INTO calendar_suggestion (${names.join(",")}) VALUES (${names.map(() => "?").join(",")})`,
|
|
306
|
+
)
|
|
307
|
+
.run(...Object.values(values));
|
|
308
|
+
}
|
|
309
|
+
applyMigration(sqlite, TAG);
|
|
310
|
+
const result = Object.fromEntries(
|
|
311
|
+
(
|
|
312
|
+
sqlite
|
|
313
|
+
.prepare("SELECT suggestion_id, ends_at_utc FROM calendar_suggestion")
|
|
314
|
+
.all() as { suggestion_id: string; ends_at_utc: string }[]
|
|
315
|
+
).map((row) => [row.suggestion_id, row.ends_at_utc]),
|
|
316
|
+
);
|
|
317
|
+
sqlite.close();
|
|
318
|
+
return result;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
test("converts a past non-recurring invite carrying a VTIMEZONE to its UTC end", () => {
|
|
322
|
+
const result = backfilled({
|
|
323
|
+
plain: {
|
|
324
|
+
dtEnd: "2024-03-01T11:00:00+02:00",
|
|
325
|
+
icalData: invite(
|
|
326
|
+
"UID:a@example.test",
|
|
327
|
+
"DTSTART;TZID=Europe/Amsterdam:20240301T100000",
|
|
328
|
+
"DTEND;TZID=Europe/Amsterdam:20240301T110000",
|
|
329
|
+
),
|
|
330
|
+
},
|
|
331
|
+
weekly: {
|
|
332
|
+
dtEnd: "2024-03-01T11:00:00+02:00",
|
|
333
|
+
icalData: invite(
|
|
334
|
+
"UID:b@example.test",
|
|
335
|
+
"DTSTART;TZID=Europe/Amsterdam:20240301T100000",
|
|
336
|
+
"DTEND;TZID=Europe/Amsterdam:20240301T110000",
|
|
337
|
+
"RRULE:FREQ=WEEKLY",
|
|
338
|
+
),
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
assert.equal(result.plain, "2024-03-01T09:00:00Z");
|
|
343
|
+
assert.equal(result.weekly, "9999-12-31T23:59:59Z");
|
|
344
|
+
});
|
|
345
|
+
});
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { deriveCalendarSuggestionId } from "@remit/data-ports/id";
|
|
9
9
|
import { CalendarSuggestionState } from "@remit/domain-enums";
|
|
10
|
-
import { and, asc, desc, eq, inArray, lt, or } from "drizzle-orm";
|
|
10
|
+
import { and, asc, desc, eq, gte, inArray, lt, or } from "drizzle-orm";
|
|
11
11
|
import type { Db } from "../db.js";
|
|
12
12
|
import { NotFoundError } from "../error.js";
|
|
13
13
|
import { decodeToken, resultList } from "../pagination.js";
|
|
@@ -31,6 +31,7 @@ function rowToCalendarSuggestion(
|
|
|
31
31
|
summary: row.summary,
|
|
32
32
|
dtStart: row.dtStart,
|
|
33
33
|
dtEnd: row.dtEnd,
|
|
34
|
+
endsAtUtc: row.endsAtUtc,
|
|
34
35
|
allDay: row.allDay,
|
|
35
36
|
location: row.location,
|
|
36
37
|
organizer: row.organizer,
|
|
@@ -147,10 +148,14 @@ export class CalendarSuggestionRepo implements ICalendarSuggestionRepository {
|
|
|
147
148
|
async listByState(
|
|
148
149
|
accountConfigId: string,
|
|
149
150
|
state: CalendarSuggestionItem["state"],
|
|
150
|
-
options
|
|
151
|
+
options: {
|
|
152
|
+
endsAfter: string;
|
|
153
|
+
limit?: number;
|
|
154
|
+
continuationToken?: string;
|
|
155
|
+
},
|
|
151
156
|
): Promise<ResultList<CalendarSuggestionItem>> {
|
|
152
|
-
const limit = options
|
|
153
|
-
const cursor = options
|
|
157
|
+
const limit = options.limit ?? 100;
|
|
158
|
+
const cursor = options.continuationToken
|
|
154
159
|
? decodeToken(options.continuationToken)
|
|
155
160
|
: undefined;
|
|
156
161
|
const after = cursor
|
|
@@ -167,6 +172,7 @@ export class CalendarSuggestionRepo implements ICalendarSuggestionRepository {
|
|
|
167
172
|
and(
|
|
168
173
|
eq(calendarSuggestionTable.accountConfigId, accountConfigId),
|
|
169
174
|
eq(calendarSuggestionTable.state, state),
|
|
175
|
+
gte(calendarSuggestionTable.endsAtUtc, options.endsAfter),
|
|
170
176
|
after
|
|
171
177
|
? or(
|
|
172
178
|
lt(calendarSuggestionTable.createdAt, after.createdAt),
|