@remit/drizzle-service 0.0.102 → 0.0.103
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 +1 -1
- package/src/batch.sqlite.test.ts +4 -4
- package/src/batch.ts +47 -21
- package/src/databases.ts +24 -6
- package/src/db.ts +20 -5
- package/src/index.ts +12 -0
- package/src/repair/junk-only-address.sqlite.test.ts +7 -2
- package/src/repos/account.conformance.sqlite.test.ts +6 -2
- package/src/repos/calendar-collection.ts +2 -2
- package/src/repos/calendar-default.sqlite.test.ts +6 -2
- package/src/repos/calendar-event-index.ts +2 -2
- package/src/repos/calendar-feed-token.ts +2 -2
- package/src/repos/calendar-object.ts +2 -2
- package/src/repos/calendar-put.sqlite.test.ts +6 -2
- package/src/repos/calendar-store.ts +36 -40
- package/src/repos/calendar-suggestion.ts +2 -2
- package/src/repos/cascade-delete.test.ts +3 -2
- package/src/repos/cascade-delete.ts +11 -7
- package/src/repos/envelope.sqlite.test.ts +3 -2
- package/src/repos/envelope.test.ts +3 -2
- package/src/repos/envelope.ts +14 -9
- package/src/repos/filter.ts +2 -2
- package/src/repos/i4-account-config.test.ts +10 -6
- package/src/repos/i4-account-config.ts +8 -10
- package/src/repos/i4-account-export-request.ts +2 -2
- package/src/repos/i4-account-setting.ts +2 -2
- package/src/repos/i4-account.test.ts +12 -8
- package/src/repos/i4-account.ts +6 -10
- package/src/repos/i4-address-junk-move.sqlite.test.ts +7 -2
- package/src/repos/i4-address.ts +12 -2
- package/src/repos/i4-config-import.ts +2 -2
- package/src/repos/i4-mailbox-lock.ts +2 -2
- package/src/repos/i4-mailbox-special-use.sqlite.test.ts +12 -10
- package/src/repos/i4-mailbox-special-use.ts +29 -40
- package/src/repos/i4-mailbox.sqlite.test.ts +12 -10
- package/src/repos/i4-mailbox.test.ts +15 -14
- package/src/repos/i4-mailbox.ts +13 -7
- package/src/repos/i4-message-flag-push.ts +2 -2
- package/src/repos/i4-message-placement-move.ts +2 -2
- package/src/repos/i4-organize-job-request.ts +2 -2
- package/src/repos/i4-outbox-attachment.test.ts +7 -2
- package/src/repos/i4-outbox-attachment.ts +11 -5
- package/src/repos/i4-outbox-message.ts +2 -2
- package/src/repos/i4-sender-signer-standing.ts +2 -2
- package/src/repos/label.ts +2 -2
- package/src/repos/message-flag.ts +3 -6
- package/src/repos/message-label.ts +2 -2
- package/src/repos/message.sqlite.test.ts +3 -3
- package/src/repos/message.test.ts +6 -5
- package/src/repos/message.ts +15 -10
- package/src/repos/quarantine.ts +2 -2
- package/src/repos/sync-warning.ts +2 -2
- package/src/repos/thread-message-body-muted.sqlite.test.ts +7 -3
- package/src/repos/thread-message-field-terms.sqlite.test.ts +7 -6
- package/src/repos/thread-message.sqlite.test.ts +7 -3
- package/src/repos/thread-message.test.ts +22 -18
- package/src/repos/thread-message.ts +13 -5
- package/src/search/thread-message-search.sqlite.test.ts +8 -3
- package/src/search/thread-message-search.ts +13 -8
- package/src/sqlite-repositories.ts +48 -32
|
@@ -2,7 +2,7 @@ import assert from "node:assert";
|
|
|
2
2
|
import { after, before, describe, test } from "node:test";
|
|
3
3
|
import { MailboxSyncStatus } from "@remit/domain-enums";
|
|
4
4
|
import { eq } from "drizzle-orm";
|
|
5
|
-
import {
|
|
5
|
+
import { syncBatch } from "../batch.js";
|
|
6
6
|
import {
|
|
7
7
|
envelopeId as deriveEnvelopeId,
|
|
8
8
|
rootBodyPartId as deriveRootBodyPartId,
|
|
@@ -10,14 +10,13 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
filterTable,
|
|
12
12
|
mailboxSpecialUseTable,
|
|
13
|
-
mailboxTable,
|
|
14
13
|
messageTable,
|
|
15
14
|
threadMessageTable,
|
|
16
15
|
} from "../schema.js";
|
|
17
|
-
import {
|
|
16
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
18
17
|
import { createTestDb, randomId, type TestDb } from "../test-db.js";
|
|
19
|
-
import { MailboxRepo } from "./i4-mailbox.js";
|
|
20
|
-
import {
|
|
18
|
+
import type { MailboxRepo } from "./i4-mailbox.js";
|
|
19
|
+
import { deleteMessageSubtree } from "./message.js";
|
|
21
20
|
import { mailboxCreated } from "./test-helpers.js";
|
|
22
21
|
|
|
23
22
|
/** Every state a row can carry, for a transition that decides against none. */
|
|
@@ -55,10 +54,11 @@ describe("MailboxRepo", () => {
|
|
|
55
54
|
|
|
56
55
|
before(async () => {
|
|
57
56
|
({ db, close } = await createTestDb());
|
|
58
|
-
repo =
|
|
59
|
-
db
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
repo = createSqliteRepositories({
|
|
58
|
+
app: db,
|
|
59
|
+
mail: db,
|
|
60
|
+
search: db,
|
|
61
|
+
}).mailbox;
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
after(async () => {
|
|
@@ -543,10 +543,11 @@ describe("MailboxRepo", () => {
|
|
|
543
543
|
describe("deleteMailboxWithMail — the folder's mail goes with it (D8)", () => {
|
|
544
544
|
const seedMessage = async (mailboxId: string, uid: number) => {
|
|
545
545
|
const messageId = randomId();
|
|
546
|
-
await
|
|
547
|
-
db
|
|
548
|
-
|
|
549
|
-
|
|
546
|
+
await createSqliteRepositories({
|
|
547
|
+
app: db,
|
|
548
|
+
mail: db,
|
|
549
|
+
search: db,
|
|
550
|
+
}).message.create({
|
|
550
551
|
messageId,
|
|
551
552
|
mailboxId,
|
|
552
553
|
uid,
|
|
@@ -674,7 +675,7 @@ describe("MailboxRepo", () => {
|
|
|
674
675
|
|
|
675
676
|
// The shape an interruption leaves: one message's rows already gone,
|
|
676
677
|
// the mailbox row still there and still `deleting`.
|
|
677
|
-
await
|
|
678
|
+
await syncBatch(db)(deleteMessageSubtree(db, [first]));
|
|
678
679
|
await repo.transition(accountId, mailbox.mailboxId, {
|
|
679
680
|
from: EVERY_STATE,
|
|
680
681
|
to: MailboxSyncStatus.deleting,
|
package/src/repos/i4-mailbox.ts
CHANGED
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
sql,
|
|
28
28
|
} from "drizzle-orm";
|
|
29
29
|
import shortUuid from "short-uuid";
|
|
30
|
-
import {
|
|
31
|
-
import type {
|
|
30
|
+
import type { WriteBatch } from "../batch.js";
|
|
31
|
+
import type { RepositoryDb, SqliteStore } from "../db.js";
|
|
32
32
|
import { NotFoundError } from "../error.js";
|
|
33
33
|
import { decodeToken, resultList } from "../pagination.js";
|
|
34
34
|
import {
|
|
@@ -52,7 +52,7 @@ const base36Translator = shortUuid.createTranslator(
|
|
|
52
52
|
);
|
|
53
53
|
const generateMailboxId = () => base36Translator.fromUUID(randomUUID());
|
|
54
54
|
|
|
55
|
-
type DB =
|
|
55
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Message subtrees removed per batch by {@link MailboxRepo.deleteMailboxWithMail},
|
|
@@ -149,10 +149,16 @@ export function rowToMailbox(
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
export class MailboxRepo implements IMailboxRepository {
|
|
152
|
+
private readonly db: DB;
|
|
153
|
+
private readonly batch: WriteBatch;
|
|
154
|
+
|
|
152
155
|
constructor(
|
|
153
|
-
|
|
156
|
+
store: SqliteStore<Record<string, unknown>>,
|
|
154
157
|
private search: SearchIndex,
|
|
155
|
-
) {
|
|
158
|
+
) {
|
|
159
|
+
this.db = store.db;
|
|
160
|
+
this.batch = store.batch;
|
|
161
|
+
}
|
|
156
162
|
|
|
157
163
|
async create(input: CreateMailboxInput): Promise<CreateMailboxResult> {
|
|
158
164
|
const now = Date.now();
|
|
@@ -379,7 +385,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
379
385
|
|
|
380
386
|
async deleteMany(accountId: string, mailboxIds: string[]): Promise<void> {
|
|
381
387
|
if (mailboxIds.length === 0) return;
|
|
382
|
-
await
|
|
388
|
+
await this.batch([
|
|
383
389
|
this.db
|
|
384
390
|
.delete(syncWarningTable)
|
|
385
391
|
.where(
|
|
@@ -556,7 +562,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
556
562
|
|
|
557
563
|
// The primitive the rest of the codebase deletes mail with: nine
|
|
558
564
|
// per-message child tables. A bespoke table list would orphan them.
|
|
559
|
-
await
|
|
565
|
+
await this.batch([
|
|
560
566
|
...deleteMessageSubtree(this.db, messageIds),
|
|
561
567
|
this.db
|
|
562
568
|
.delete(threadMessageTable)
|
|
@@ -3,10 +3,10 @@ import type {
|
|
|
3
3
|
PutMessageFlagPushInput,
|
|
4
4
|
} from "@remit/data-ports";
|
|
5
5
|
import { and, eq } from "drizzle-orm";
|
|
6
|
-
import type {
|
|
6
|
+
import type { RepositoryDb } from "../db.js";
|
|
7
7
|
import { messageFlagPushTable } from "../schema/i4-message-flag-push.js";
|
|
8
8
|
|
|
9
|
-
type DB =
|
|
9
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
10
10
|
|
|
11
11
|
export type { MessageFlagPushItem, PutMessageFlagPushInput };
|
|
12
12
|
export type FlagPushOperation = MessageFlagPushItem["operation"];
|
|
@@ -3,10 +3,10 @@ import type {
|
|
|
3
3
|
PutMessagePlacementMoveInput,
|
|
4
4
|
} from "@remit/data-ports";
|
|
5
5
|
import { eq } from "drizzle-orm";
|
|
6
|
-
import type {
|
|
6
|
+
import type { RepositoryDb } from "../db.js";
|
|
7
7
|
import { messagePlacementMoveTable } from "../schema/i4-message-placement-move.js";
|
|
8
8
|
|
|
9
|
-
type DB =
|
|
9
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
10
10
|
|
|
11
11
|
export type { MessagePlacementMoveItem, PutMessagePlacementMoveInput };
|
|
12
12
|
export type MessagePlacementMoveState = MessagePlacementMoveItem["state"];
|
|
@@ -6,13 +6,13 @@ import type {
|
|
|
6
6
|
UpdateOrganizeJobRequestInput,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { eq } from "drizzle-orm";
|
|
9
|
-
import type {
|
|
9
|
+
import type { RepositoryDb } from "../db.js";
|
|
10
10
|
import { NotFoundError } from "../error.js";
|
|
11
11
|
import { randomId } from "../id.js";
|
|
12
12
|
import { decodeToken, resultList } from "../pagination.js";
|
|
13
13
|
import { organizeJobRequestTable } from "../schema/i4-organize-job-request.js";
|
|
14
14
|
|
|
15
|
-
type DB =
|
|
15
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
16
16
|
|
|
17
17
|
function rowToItem(
|
|
18
18
|
row: typeof organizeJobRequestTable.$inferSelect,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { after, before, describe, test } from "node:test";
|
|
3
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
3
4
|
import { createTestDb, randomId } from "../test-db.js";
|
|
4
|
-
import { OutboxAttachmentRepo } from "./i4-outbox-attachment.js";
|
|
5
|
+
import type { OutboxAttachmentRepo } from "./i4-outbox-attachment.js";
|
|
5
6
|
|
|
6
7
|
const CAP = { maxTotalBytes: 1000, maxCount: 3, nowSeconds: 1_000_000 };
|
|
7
8
|
|
|
@@ -27,7 +28,11 @@ const input = (
|
|
|
27
28
|
|
|
28
29
|
before(async () => {
|
|
29
30
|
harness = await createTestDb();
|
|
30
|
-
repo =
|
|
31
|
+
repo = createSqliteRepositories({
|
|
32
|
+
app: harness.db,
|
|
33
|
+
mail: harness.db,
|
|
34
|
+
search: harness.db,
|
|
35
|
+
}).outboxAttachment;
|
|
31
36
|
});
|
|
32
37
|
|
|
33
38
|
after(async () => {
|
|
@@ -7,13 +7,13 @@ import type {
|
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { holdsRoom } from "@remit/data-ports";
|
|
9
9
|
import { and, eq, gt, gte, lt, or, sum } from "drizzle-orm";
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
10
|
+
import type { WriteBatch } from "../batch.js";
|
|
11
|
+
import type { RepositoryDb, SqliteStore } from "../db.js";
|
|
12
12
|
import { NotFoundError } from "../error.js";
|
|
13
13
|
import { outboxAttachmentTable } from "../schema/i4-outbox-attachment.js";
|
|
14
14
|
import { inList } from "./in-list.js";
|
|
15
15
|
|
|
16
|
-
type DB =
|
|
16
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
17
17
|
|
|
18
18
|
function rowToOutboxAttachment(
|
|
19
19
|
row: typeof outboxAttachmentTable.$inferSelect,
|
|
@@ -35,7 +35,13 @@ function rowToOutboxAttachment(
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export class OutboxAttachmentRepo implements IOutboxAttachmentRepository {
|
|
38
|
-
|
|
38
|
+
private readonly db: DB;
|
|
39
|
+
private readonly batch: WriteBatch;
|
|
40
|
+
|
|
41
|
+
constructor(store: SqliteStore<Record<string, unknown>>) {
|
|
42
|
+
this.db = store.db;
|
|
43
|
+
this.batch = store.batch;
|
|
44
|
+
}
|
|
39
45
|
|
|
40
46
|
/**
|
|
41
47
|
* The per-message cap. The insert, the read of the draft's live rows and a
|
|
@@ -60,7 +66,7 @@ export class OutboxAttachmentRepo implements IOutboxAttachmentRepository {
|
|
|
60
66
|
gte(outboxAttachmentTable.reservationExpiresAt, cap.nowSeconds),
|
|
61
67
|
),
|
|
62
68
|
);
|
|
63
|
-
const [inserted, rows, removed] = await
|
|
69
|
+
const [inserted, rows, removed] = await this.batch([
|
|
64
70
|
this.db
|
|
65
71
|
.insert(outboxAttachmentTable)
|
|
66
72
|
.values({
|
|
@@ -6,13 +6,13 @@ import type {
|
|
|
6
6
|
UpdateOutboxMessageInput,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { and, desc, eq, lt, or } from "drizzle-orm";
|
|
9
|
-
import type {
|
|
9
|
+
import type { RepositoryDb } from "../db.js";
|
|
10
10
|
import { ForbiddenError, NotFoundError } from "../error.js";
|
|
11
11
|
import { decodeToken, resultList } from "../pagination.js";
|
|
12
12
|
import { outboxMessageTable } from "../schema/i4-outbox-message.js";
|
|
13
13
|
import { inList } from "./in-list.js";
|
|
14
14
|
|
|
15
|
-
type DB =
|
|
15
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
16
16
|
|
|
17
17
|
function rowToOutboxMessage(
|
|
18
18
|
row: typeof outboxMessageTable.$inferSelect,
|
|
@@ -4,11 +4,11 @@ import type {
|
|
|
4
4
|
SenderSignerStandingItem,
|
|
5
5
|
} from "@remit/data-ports";
|
|
6
6
|
import { and, eq, sql } from "drizzle-orm";
|
|
7
|
-
import type {
|
|
7
|
+
import type { RepositoryDb } from "../db.js";
|
|
8
8
|
import { NotFoundError } from "../error.js";
|
|
9
9
|
import { senderSignerStandingTable } from "../schema.js";
|
|
10
10
|
|
|
11
|
-
type DB =
|
|
11
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
12
12
|
|
|
13
13
|
function rowToStanding(
|
|
14
14
|
row: typeof senderSignerStandingTable.$inferSelect,
|
package/src/repos/label.ts
CHANGED
|
@@ -6,13 +6,13 @@ import type {
|
|
|
6
6
|
UpdateLabelInput,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
9
|
-
import type {
|
|
9
|
+
import type { RepositoryDb } from "../db.js";
|
|
10
10
|
import { NotFoundError } from "../error.js";
|
|
11
11
|
import { randomId } from "../id.js";
|
|
12
12
|
import { decodeToken, resultList } from "../pagination.js";
|
|
13
13
|
import { labelTable } from "../schema.js";
|
|
14
14
|
|
|
15
|
-
type DB =
|
|
15
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
16
16
|
|
|
17
17
|
const normalize = (name: string): string => name.trim().toLowerCase();
|
|
18
18
|
|
|
@@ -5,15 +5,12 @@ import type {
|
|
|
5
5
|
MessageFlagItem,
|
|
6
6
|
} from "@remit/data-ports";
|
|
7
7
|
import { and, eq } from "drizzle-orm";
|
|
8
|
-
import type {
|
|
8
|
+
import type { RepositoryDb } from "../db.js";
|
|
9
9
|
import { NotFoundError } from "../error.js";
|
|
10
|
-
import {
|
|
11
|
-
type MessageDataSchema,
|
|
12
|
-
messageFlagTable,
|
|
13
|
-
} from "../schema/message-data.js";
|
|
10
|
+
import { messageFlagTable } from "../schema/message-data.js";
|
|
14
11
|
import { inList } from "./in-list.js";
|
|
15
12
|
|
|
16
|
-
type DB =
|
|
13
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
17
14
|
|
|
18
15
|
function rowToMessageFlag(
|
|
19
16
|
row: typeof messageFlagTable.$inferSelect,
|
|
@@ -4,12 +4,12 @@ import type {
|
|
|
4
4
|
MessageLabelItem,
|
|
5
5
|
} from "@remit/data-ports";
|
|
6
6
|
import { and, desc, eq } from "drizzle-orm";
|
|
7
|
-
import type {
|
|
7
|
+
import type { RepositoryDb } from "../db.js";
|
|
8
8
|
import { deterministicBase36Id } from "../id.js";
|
|
9
9
|
import { messageLabelTable } from "../schema.js";
|
|
10
10
|
import { inList } from "./in-list.js";
|
|
11
11
|
|
|
12
|
-
type DB =
|
|
12
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
13
13
|
|
|
14
14
|
function rowToMessageLabel(
|
|
15
15
|
row: typeof messageLabelTable.$inferSelect,
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
} from "../id.js";
|
|
7
7
|
import { messageDataSchema } from "../schema/message-data.js";
|
|
8
8
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
10
10
|
import { createSqliteTestDb, type SqliteTestDb } from "../test-db-sqlite.js";
|
|
11
|
-
import { DrizzleMessageRepository } from "./message.js";
|
|
11
|
+
import type { DrizzleMessageRepository } from "./message.js";
|
|
12
12
|
|
|
13
13
|
const SCHEMA = { ...messageDataSchema, threadMessages: threadMessageTable };
|
|
14
14
|
|
|
@@ -43,7 +43,7 @@ describe("DrizzleMessageRepository (sqlite)", () => {
|
|
|
43
43
|
|
|
44
44
|
before(async () => {
|
|
45
45
|
({ db, close } = await createSqliteTestDb(SCHEMA));
|
|
46
|
-
repo =
|
|
46
|
+
repo = createSqliteRepositories({ app: db, mail: db, search: db }).message;
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
after(async () => {
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
envelopeId as deriveEnvelopeId,
|
|
5
5
|
rootBodyPartId as deriveRootBodyPartId,
|
|
6
6
|
} from "../id.js";
|
|
7
|
-
import {
|
|
8
|
-
import { DrizzleEnvelopeRepository } from "./envelope.js";
|
|
9
|
-
import { DrizzleMessageRepository } from "./message.js";
|
|
7
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
8
|
+
import type { DrizzleEnvelopeRepository } from "./envelope.js";
|
|
9
|
+
import type { DrizzleMessageRepository } from "./message.js";
|
|
10
10
|
import { createTestDb, type TestDb } from "./test-helpers.js";
|
|
11
11
|
|
|
12
12
|
describe("DrizzleMessageRepository", () => {
|
|
@@ -37,8 +37,9 @@ describe("DrizzleMessageRepository", () => {
|
|
|
37
37
|
|
|
38
38
|
before(async () => {
|
|
39
39
|
({ db, stop } = await createTestDb());
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const repos = createSqliteRepositories({ app: db, mail: db, search: db });
|
|
41
|
+
messageRepo = repos.message;
|
|
42
|
+
envelopeRepo = repos.envelope;
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
after(async () => {
|
package/src/repos/message.ts
CHANGED
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
or,
|
|
19
19
|
type SQL,
|
|
20
20
|
} from "drizzle-orm";
|
|
21
|
-
import {
|
|
22
|
-
import type {
|
|
21
|
+
import type { SqliteBatchItem, WriteBatch } from "../batch.js";
|
|
22
|
+
import type { RepositoryDb, SqliteStore } from "../db.js";
|
|
23
23
|
import {
|
|
24
24
|
CreateFailedConflictError,
|
|
25
25
|
isUniqueViolation,
|
|
@@ -37,7 +37,6 @@ import {
|
|
|
37
37
|
bodyStructureRefetchTable,
|
|
38
38
|
envelopeAddressTable,
|
|
39
39
|
envelopeTable,
|
|
40
|
-
type MessageDataSchema,
|
|
41
40
|
messageFlagTable,
|
|
42
41
|
messageReferenceTable,
|
|
43
42
|
messageTable,
|
|
@@ -56,7 +55,7 @@ import {
|
|
|
56
55
|
toRawMessageStorageItem,
|
|
57
56
|
} from "./mappers.js";
|
|
58
57
|
|
|
59
|
-
type DB =
|
|
58
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
60
59
|
|
|
61
60
|
function toMessageItem(row: typeof messageTable.$inferSelect): MessageItem {
|
|
62
61
|
return {
|
|
@@ -112,7 +111,7 @@ function toMessageItem(row: typeof messageTable.$inferSelect): MessageItem {
|
|
|
112
111
|
};
|
|
113
112
|
}
|
|
114
113
|
|
|
115
|
-
export type SubtreeDb = Pick<
|
|
114
|
+
export type SubtreeDb = Pick<RepositoryDb<Record<string, unknown>>, "delete">;
|
|
116
115
|
|
|
117
116
|
/**
|
|
118
117
|
* The statements that delete a message and its whole per-message subtree by
|
|
@@ -193,10 +192,16 @@ const placementTerms = (expected: PlacementPredicate): SQL[] => {
|
|
|
193
192
|
};
|
|
194
193
|
|
|
195
194
|
export class DrizzleMessageRepository implements IMessageRepository {
|
|
195
|
+
private readonly db: DB;
|
|
196
|
+
private readonly batch: WriteBatch;
|
|
197
|
+
|
|
196
198
|
constructor(
|
|
197
|
-
|
|
199
|
+
store: SqliteStore<Record<string, unknown>>,
|
|
198
200
|
private search: SearchIndex,
|
|
199
|
-
) {
|
|
201
|
+
) {
|
|
202
|
+
this.db = store.db;
|
|
203
|
+
this.batch = store.batch;
|
|
204
|
+
}
|
|
200
205
|
|
|
201
206
|
private rowOf(input: CreateMessageInput) {
|
|
202
207
|
const now = Date.now();
|
|
@@ -462,7 +467,7 @@ export class DrizzleMessageRepository implements IMessageRepository {
|
|
|
462
467
|
.select({ threadMessageId: threadMessageTable.threadMessageId })
|
|
463
468
|
.from(threadMessageTable)
|
|
464
469
|
.where(eq(threadMessageTable.messageId, messageId));
|
|
465
|
-
const results = await
|
|
470
|
+
const results = await this.batch([
|
|
466
471
|
this.db
|
|
467
472
|
.delete(threadMessageTable)
|
|
468
473
|
.where(and(eq(threadMessageTable.messageId, messageId), placed)),
|
|
@@ -475,7 +480,7 @@ export class DrizzleMessageRepository implements IMessageRepository {
|
|
|
475
480
|
|
|
476
481
|
async deleteMany(messageIds: string[]): Promise<void> {
|
|
477
482
|
if (messageIds.length === 0) return;
|
|
478
|
-
await
|
|
483
|
+
await this.batch(deleteMessageSubtree(this.db, messageIds));
|
|
479
484
|
}
|
|
480
485
|
|
|
481
486
|
async listByMailbox(
|
|
@@ -623,7 +628,7 @@ export class DrizzleMessageRepository implements IMessageRepository {
|
|
|
623
628
|
.select({ threadMessageId: threadMessageTable.threadMessageId })
|
|
624
629
|
.from(threadMessageTable)
|
|
625
630
|
.where(eq(threadMessageTable.messageId, messageId));
|
|
626
|
-
const [moved] = await
|
|
631
|
+
const [moved] = await this.batch([
|
|
627
632
|
this.db
|
|
628
633
|
.update(messageTable)
|
|
629
634
|
.set({
|
package/src/repos/quarantine.ts
CHANGED
|
@@ -6,10 +6,10 @@ import type {
|
|
|
6
6
|
} from "@remit/data-ports";
|
|
7
7
|
import { deriveQuarantineId } from "@remit/data-ports/id";
|
|
8
8
|
import { desc, eq } from "drizzle-orm";
|
|
9
|
-
import type {
|
|
9
|
+
import type { RepositoryDb } from "../db.js";
|
|
10
10
|
import { quarantineTable } from "../schema/quarantine.js";
|
|
11
11
|
|
|
12
|
-
type DB =
|
|
12
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
13
13
|
|
|
14
14
|
function rowToItem(row: typeof quarantineTable.$inferSelect): QuarantineItem {
|
|
15
15
|
return {
|
|
@@ -6,11 +6,11 @@ import type {
|
|
|
6
6
|
} from "@remit/data-ports";
|
|
7
7
|
import { deriveSyncWarningId } from "@remit/data-ports/id";
|
|
8
8
|
import { and, count, desc, eq, gte, sql } from "drizzle-orm";
|
|
9
|
-
import type {
|
|
9
|
+
import type { RepositoryDb } from "../db.js";
|
|
10
10
|
import { syncWarningTable } from "../schema/sync-warning.js";
|
|
11
11
|
import { inList } from "./in-list.js";
|
|
12
12
|
|
|
13
|
-
type DB =
|
|
13
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
14
14
|
|
|
15
15
|
export class SyncWarningRepo implements ISyncWarningRepository {
|
|
16
16
|
constructor(private db: DB) {}
|
|
@@ -12,10 +12,10 @@ import { after, before, describe, test } from "node:test";
|
|
|
12
12
|
import type { CreateThreadMessageInput } from "@remit/data-ports";
|
|
13
13
|
import { addressTable } from "../schema/i4-address.js";
|
|
14
14
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
15
|
-
import {
|
|
15
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
16
16
|
import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
17
17
|
import { shippedIndexDdl } from "../test-shipped-sqlite-schema.js";
|
|
18
|
-
import { DrizzleThreadMessageRepository } from "./thread-message.js";
|
|
18
|
+
import type { DrizzleThreadMessageRepository } from "./thread-message.js";
|
|
19
19
|
|
|
20
20
|
// The index the mail baseline creates for this predicate, read from the one
|
|
21
21
|
// committed source so the plan assertion below is about the real object.
|
|
@@ -61,7 +61,11 @@ describe("thread-message body and muted-sender predicates (sqlite)", () => {
|
|
|
61
61
|
{ searchIndex: true },
|
|
62
62
|
));
|
|
63
63
|
sqlite.exec(mutedIndexDdl);
|
|
64
|
-
repo =
|
|
64
|
+
repo = createSqliteRepositories({
|
|
65
|
+
app: db,
|
|
66
|
+
mail: db,
|
|
67
|
+
search: db,
|
|
68
|
+
}).threadMessage;
|
|
65
69
|
});
|
|
66
70
|
|
|
67
71
|
after(async () => {
|
|
@@ -2,10 +2,10 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { after, before, describe, test } from "node:test";
|
|
3
3
|
import type { CreateThreadMessageInput } from "@remit/data-ports";
|
|
4
4
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
6
6
|
import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
7
7
|
import {
|
|
8
|
-
DrizzleThreadMessageRepository,
|
|
8
|
+
type DrizzleThreadMessageRepository,
|
|
9
9
|
THREAD_SEARCH_MAX_LIMIT,
|
|
10
10
|
} from "./thread-message.js";
|
|
11
11
|
|
|
@@ -55,10 +55,11 @@ describe("DrizzleThreadMessageRepository.listByFieldTerms (sqlite, #459)", () =>
|
|
|
55
55
|
{ searchIndex: true },
|
|
56
56
|
);
|
|
57
57
|
close = created.close;
|
|
58
|
-
repo =
|
|
59
|
-
created.db,
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
repo = createSqliteRepositories({
|
|
59
|
+
app: created.db,
|
|
60
|
+
mail: created.db,
|
|
61
|
+
search: created.db,
|
|
62
|
+
}).threadMessage;
|
|
62
63
|
|
|
63
64
|
await repo.create(
|
|
64
65
|
makeInput({
|
|
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import { after, before, describe, test } from "node:test";
|
|
3
3
|
import type { CreateThreadMessageInput } from "@remit/data-ports";
|
|
4
4
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
6
6
|
import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
7
7
|
import {
|
|
8
8
|
BASE_DATE,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
totalRows,
|
|
13
13
|
} from "./category-fixture.js";
|
|
14
14
|
import {
|
|
15
|
-
DrizzleThreadMessageRepository,
|
|
15
|
+
type DrizzleThreadMessageRepository,
|
|
16
16
|
THREAD_SEARCH_MAX_LIMIT,
|
|
17
17
|
} from "./thread-message.js";
|
|
18
18
|
|
|
@@ -58,7 +58,11 @@ describe("DrizzleThreadMessageRepository (sqlite)", () => {
|
|
|
58
58
|
},
|
|
59
59
|
{ searchIndex: true },
|
|
60
60
|
));
|
|
61
|
-
repo =
|
|
61
|
+
repo = createSqliteRepositories({
|
|
62
|
+
app: db,
|
|
63
|
+
mail: db,
|
|
64
|
+
search: db,
|
|
65
|
+
}).threadMessage;
|
|
62
66
|
});
|
|
63
67
|
|
|
64
68
|
after(async () => {
|
|
@@ -3,11 +3,11 @@ import { after, before, describe, test } from "node:test";
|
|
|
3
3
|
import type { CreateThreadMessageInput } from "@remit/data-ports";
|
|
4
4
|
import shortUuid from "short-uuid";
|
|
5
5
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
7
7
|
import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
8
8
|
import {
|
|
9
9
|
clampThreadSearchLimit,
|
|
10
|
-
DrizzleThreadMessageRepository,
|
|
10
|
+
type DrizzleThreadMessageRepository,
|
|
11
11
|
deriveThreadMessageId,
|
|
12
12
|
THREAD_SEARCH_MAX_LIMIT,
|
|
13
13
|
} from "./thread-message.js";
|
|
@@ -87,10 +87,11 @@ describe("DrizzleThreadMessageRepository.searchByMailboxWindow / countByMailbox"
|
|
|
87
87
|
before(async () => {
|
|
88
88
|
const harness = await setupDb();
|
|
89
89
|
close = harness.close;
|
|
90
|
-
repo =
|
|
91
|
-
harness.db,
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
repo = createSqliteRepositories({
|
|
91
|
+
app: harness.db,
|
|
92
|
+
mail: harness.db,
|
|
93
|
+
search: harness.db,
|
|
94
|
+
}).threadMessage;
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
after(async () => {
|
|
@@ -391,10 +392,11 @@ describe("DrizzleThreadMessageRepository.searchByDate", () => {
|
|
|
391
392
|
before(async () => {
|
|
392
393
|
const harness = await setupDb();
|
|
393
394
|
close = harness.close;
|
|
394
|
-
repo =
|
|
395
|
-
harness.db,
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
repo = createSqliteRepositories({
|
|
396
|
+
app: harness.db,
|
|
397
|
+
mail: harness.db,
|
|
398
|
+
search: harness.db,
|
|
399
|
+
}).threadMessage;
|
|
398
400
|
});
|
|
399
401
|
|
|
400
402
|
after(async () => {
|
|
@@ -921,10 +923,11 @@ describe("DrizzleThreadMessageRepository — native text search", () => {
|
|
|
921
923
|
before(async () => {
|
|
922
924
|
const harness = await setupDb();
|
|
923
925
|
close = harness.close;
|
|
924
|
-
repo =
|
|
925
|
-
harness.db,
|
|
926
|
-
|
|
927
|
-
|
|
926
|
+
repo = createSqliteRepositories({
|
|
927
|
+
app: harness.db,
|
|
928
|
+
mail: harness.db,
|
|
929
|
+
search: harness.db,
|
|
930
|
+
}).threadMessage;
|
|
928
931
|
});
|
|
929
932
|
|
|
930
933
|
after(async () => {
|
|
@@ -1096,10 +1099,11 @@ describe("DrizzleThreadMessageRepository — core CRUD", () => {
|
|
|
1096
1099
|
before(async () => {
|
|
1097
1100
|
const harness = await setupDb();
|
|
1098
1101
|
close = harness.close;
|
|
1099
|
-
repo =
|
|
1100
|
-
harness.db,
|
|
1101
|
-
|
|
1102
|
-
|
|
1102
|
+
repo = createSqliteRepositories({
|
|
1103
|
+
app: harness.db,
|
|
1104
|
+
mail: harness.db,
|
|
1105
|
+
search: harness.db,
|
|
1106
|
+
}).threadMessage;
|
|
1103
1107
|
});
|
|
1104
1108
|
|
|
1105
1109
|
after(async () => {
|