@remit/drizzle-service 0.0.106 → 0.0.108
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 +4 -2
- package/src/id.ts +9 -0
- package/src/index.ts +4 -0
- package/src/repair/junk-only-address.sqlite.test.ts +2 -0
- package/src/repos/account.conformance.d1.test.ts +3 -1
- package/src/repos/account.conformance.sqlite.test.ts +2 -0
- package/src/repos/calendar-default.suite.ts +5 -1
- package/src/repos/calendar-put.suite.ts +5 -1
- package/src/repos/cascade-delete.ts +1 -1
- package/src/repos/envelope.sqlite.test.ts +2 -0
- package/src/repos/envelope.test.ts +2 -0
- package/src/repos/envelope.ts +5 -3
- package/src/repos/i4-account-config.suite.ts +5 -1
- package/src/repos/i4-account.test.ts +3 -0
- package/src/repos/i4-address-junk-move.sqlite.test.ts +2 -0
- package/src/repos/i4-mailbox-special-use.sqlite.test.ts +2 -0
- package/src/repos/i4-mailbox.sqlite.test.ts +3 -0
- package/src/repos/i4-mailbox.test.ts +4 -3
- package/src/repos/i4-mailbox.ts +7 -28
- package/src/repos/i4-outbox-attachment.test.ts +2 -0
- package/src/repos/message-objects.sqlite.test.ts +271 -0
- package/src/repos/message-objects.ts +70 -0
- package/src/repos/message.sqlite.test.ts +11 -17
- package/src/repos/message.test.ts +4 -6
- package/src/repos/message.ts +341 -46
- package/src/repos/thread-message-body-muted.sqlite.test.ts +2 -0
- package/src/repos/thread-message-field-terms.sqlite.test.ts +2 -0
- package/src/repos/thread-message.sqlite.test.ts +2 -0
- package/src/repos/thread-message.test.ts +5 -0
- package/src/search/thread-message-search.sqlite.test.ts +2 -0
- package/src/sqlite-repositories.ts +18 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/drizzle-service",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.108",
|
|
4
4
|
"description": "Drizzle ORM service over SQLite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
"uuid": "^13.0.2",
|
|
37
37
|
"@remit/drizzle-sqlite-schema": "*",
|
|
38
38
|
"better-sqlite3": "^12.11.1",
|
|
39
|
-
"@types/better-sqlite3": "^7.6.13"
|
|
39
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
40
|
+
"@remit/storage-service": "*",
|
|
41
|
+
"p-map": "^2.1.0"
|
|
40
42
|
},
|
|
41
43
|
"license": "MIT",
|
|
42
44
|
"publishConfig": {
|
package/src/id.ts
CHANGED
|
@@ -42,3 +42,12 @@ export const envelopeAddressId = (
|
|
|
42
42
|
order: number,
|
|
43
43
|
): string =>
|
|
44
44
|
generateDeterministicId(`envelopeaddress:${messageId}:${role}:${order}`);
|
|
45
|
+
|
|
46
|
+
export const messageReferenceId = (
|
|
47
|
+
messageId: string,
|
|
48
|
+
referenceType: string,
|
|
49
|
+
referenceOrder: number,
|
|
50
|
+
): string =>
|
|
51
|
+
deterministicBase36Id(
|
|
52
|
+
`msgref:${messageId}:${referenceType}:${referenceOrder}`,
|
|
53
|
+
);
|
package/src/index.ts
CHANGED
|
@@ -74,6 +74,10 @@ export {
|
|
|
74
74
|
} from "./repos/message.js";
|
|
75
75
|
export { DrizzleMessageFlagRepository } from "./repos/message-flag.js";
|
|
76
76
|
export { MessageLabelRepo } from "./repos/message-label.js";
|
|
77
|
+
export {
|
|
78
|
+
type MessageObjectStore,
|
|
79
|
+
messageObjectsInMemory,
|
|
80
|
+
} from "./repos/message-objects.js";
|
|
77
81
|
export { QuarantineRepo } from "./repos/quarantine.js";
|
|
78
82
|
export { SyncWarningRepo } from "./repos/sync-warning.js";
|
|
79
83
|
export { DrizzleThreadMessageRepository } from "./repos/thread-message.js";
|
|
@@ -7,6 +7,7 @@ import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
|
7
7
|
import { BETTER_SQLITE3_LIMITS } from "../bound-parameters.js";
|
|
8
8
|
import { AccountSettingRepo } from "../repos/i4-account-setting.js";
|
|
9
9
|
import type { MailboxSpecialUseRepo } from "../repos/i4-mailbox-special-use.js";
|
|
10
|
+
import { messageObjectsInMemory } from "../repos/message-objects.js";
|
|
10
11
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
11
12
|
import { applyMigrationSet } from "../test-shipped-sqlite-schema.js";
|
|
12
13
|
import {
|
|
@@ -190,6 +191,7 @@ describe("addresses standing only on mail in Junk", () => {
|
|
|
190
191
|
search: db,
|
|
191
192
|
},
|
|
192
193
|
BETTER_SQLITE3_LIMITS,
|
|
194
|
+
messageObjectsInMemory(),
|
|
193
195
|
).mailboxSpecialUse;
|
|
194
196
|
accountSetting = new AccountSettingRepo(db as never);
|
|
195
197
|
applyMigrationSet(sqlite, "app");
|
|
@@ -3,6 +3,7 @@ import { NotFoundError } from "../error.js";
|
|
|
3
3
|
import { randomId } from "../id.js";
|
|
4
4
|
import { composeSqliteRepositories } from "../sqlite-repositories.js";
|
|
5
5
|
import { openD1TestStores } from "../test-d1.js";
|
|
6
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
6
7
|
|
|
7
8
|
let close: (() => Promise<void>) | undefined;
|
|
8
9
|
|
|
@@ -10,7 +11,8 @@ accountRepositoryConformance({
|
|
|
10
11
|
async createRepository() {
|
|
11
12
|
const opened = await openD1TestStores();
|
|
12
13
|
close = opened.close;
|
|
13
|
-
return composeSqliteRepositories(opened.stores)
|
|
14
|
+
return composeSqliteRepositories(opened.stores, messageObjectsInMemory())
|
|
15
|
+
.account;
|
|
14
16
|
},
|
|
15
17
|
teardown: async () => {
|
|
16
18
|
await close?.();
|
|
@@ -5,6 +5,7 @@ import { randomId } from "../id.js";
|
|
|
5
5
|
import { accountTable } from "../schema.js";
|
|
6
6
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
7
7
|
import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
8
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
8
9
|
|
|
9
10
|
let close: (() => Promise<void>) | undefined;
|
|
10
11
|
|
|
@@ -21,6 +22,7 @@ accountRepositoryConformance({
|
|
|
21
22
|
search: db,
|
|
22
23
|
},
|
|
23
24
|
BETTER_SQLITE3_LIMITS,
|
|
25
|
+
messageObjectsInMemory(),
|
|
24
26
|
).account;
|
|
25
27
|
},
|
|
26
28
|
teardown: async () => {
|
|
@@ -6,6 +6,7 @@ import type { RepositoryDb } from "../db.js";
|
|
|
6
6
|
import { composeSqliteRepositories } from "../sqlite-repositories.js";
|
|
7
7
|
import type { OpenTestStores } from "../test-stores.js";
|
|
8
8
|
import { CalendarCollectionRepo } from "./calendar-collection.js";
|
|
9
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
9
10
|
|
|
10
11
|
const ACCOUNT_CONFIG_ID = "account-config-default";
|
|
11
12
|
|
|
@@ -19,7 +20,10 @@ export const calendarDefaultSuite = (open: OpenTestStores): void => {
|
|
|
19
20
|
const opened = await open();
|
|
20
21
|
db = opened.stores.app.db;
|
|
21
22
|
close = opened.close;
|
|
22
|
-
store = composeSqliteRepositories(
|
|
23
|
+
store = composeSqliteRepositories(
|
|
24
|
+
opened.stores,
|
|
25
|
+
messageObjectsInMemory(),
|
|
26
|
+
).calendarStore;
|
|
23
27
|
});
|
|
24
28
|
|
|
25
29
|
after(() => close());
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "../schema.js";
|
|
19
19
|
import { composeSqliteRepositories } from "../sqlite-repositories.js";
|
|
20
20
|
import type { OpenTestStores } from "../test-stores.js";
|
|
21
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
21
22
|
|
|
22
23
|
const ACCOUNT_CONFIG_ID = "account-config-1";
|
|
23
24
|
|
|
@@ -74,7 +75,10 @@ export const calendarPutSuite = (open: OpenTestStores): void => {
|
|
|
74
75
|
const opened = await open();
|
|
75
76
|
db = opened.stores.app.db;
|
|
76
77
|
close = opened.close;
|
|
77
|
-
store = composeSqliteRepositories(
|
|
78
|
+
store = composeSqliteRepositories(
|
|
79
|
+
opened.stores,
|
|
80
|
+
messageObjectsInMemory(),
|
|
81
|
+
).calendarStore;
|
|
78
82
|
const collection = await provisionDefaultCalendar(
|
|
79
83
|
store,
|
|
80
84
|
ACCOUNT_CONFIG_ID,
|
|
@@ -102,7 +102,7 @@ export const runDrizzleCascadeDelete = async (
|
|
|
102
102
|
const items: SqliteBatchItem[] = [];
|
|
103
103
|
const appItems: SqliteBatchItem[] = [];
|
|
104
104
|
const messageIds = (grouped.get("Message") ?? []).map((k) => k.messageId);
|
|
105
|
-
items.push(...deleteMessageSubtree(mail, messageIds));
|
|
105
|
+
items.push(...deleteMessageSubtree(mail, messageIds).statements);
|
|
106
106
|
|
|
107
107
|
const threadMessageIds = (grouped.get("ThreadMessage") ?? []).map(
|
|
108
108
|
(k) => k.threadMessageId,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
9
9
|
import { createSqliteTestDb, type SqliteTestDb } from "../test-db-sqlite.js";
|
|
10
10
|
import type { DrizzleEnvelopeRepository } from "./envelope.js";
|
|
11
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
11
12
|
|
|
12
13
|
// Envelope repo on sqlite (RFC 036 D1): the onConflictDoUpdate upsert path and
|
|
13
14
|
// the transactional body-part upsert both run on better-sqlite3 unchanged.
|
|
@@ -24,6 +25,7 @@ describe("DrizzleEnvelopeRepository (sqlite)", () => {
|
|
|
24
25
|
repo = createSqliteRepositories(
|
|
25
26
|
{ app: db, mail: db, search: db },
|
|
26
27
|
BETTER_SQLITE3_LIMITS,
|
|
28
|
+
messageObjectsInMemory(),
|
|
27
29
|
).envelope;
|
|
28
30
|
});
|
|
29
31
|
|
|
@@ -5,6 +5,7 @@ import { BETTER_SQLITE3_LIMITS } from "../bound-parameters.js";
|
|
|
5
5
|
import { envelopeId as deriveEnvelopeId } from "../id.js";
|
|
6
6
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
7
7
|
import type { DrizzleEnvelopeRepository } from "./envelope.js";
|
|
8
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
8
9
|
import { createTestDb, type TestDb } from "./test-helpers.js";
|
|
9
10
|
|
|
10
11
|
describe("DrizzleEnvelopeRepository", () => {
|
|
@@ -23,6 +24,7 @@ describe("DrizzleEnvelopeRepository", () => {
|
|
|
23
24
|
repo = createSqliteRepositories(
|
|
24
25
|
{ app: db, mail: db, search: db },
|
|
25
26
|
BETTER_SQLITE3_LIMITS,
|
|
27
|
+
messageObjectsInMemory(),
|
|
26
28
|
).envelope;
|
|
27
29
|
|
|
28
30
|
await repo.upsertEnvelope({
|
package/src/repos/envelope.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
bodyPartId as deriveBodyPartId,
|
|
22
22
|
bodyPartParameterId as deriveBodyPartParameterId,
|
|
23
23
|
envelopeId as deriveEnvelopeId,
|
|
24
|
-
|
|
24
|
+
messageReferenceId as deriveMessageReferenceId,
|
|
25
25
|
} from "../id.js";
|
|
26
26
|
import {
|
|
27
27
|
bodyPartParameterTable,
|
|
@@ -229,8 +229,10 @@ export class DrizzleEnvelopeRepository implements IEnvelopeRepository {
|
|
|
229
229
|
.where(eq(messageReferenceTable.messageId, messageId));
|
|
230
230
|
const rows = references.map((reference) => ({
|
|
231
231
|
...reference,
|
|
232
|
-
messageReferenceId:
|
|
233
|
-
|
|
232
|
+
messageReferenceId: deriveMessageReferenceId(
|
|
233
|
+
messageId,
|
|
234
|
+
reference.referenceType,
|
|
235
|
+
reference.referenceOrder,
|
|
234
236
|
),
|
|
235
237
|
messageId,
|
|
236
238
|
envelopeId,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "../sqlite-repositories.js";
|
|
8
8
|
import type { OpenTestStores } from "../test-stores.js";
|
|
9
9
|
import type { AccountConfigRepo } from "./i4-account-config.js";
|
|
10
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
10
11
|
|
|
11
12
|
export const accountConfigRepoSuite = (open: OpenTestStores): void => {
|
|
12
13
|
describe("AccountConfigRepo", () => {
|
|
@@ -17,7 +18,10 @@ export const accountConfigRepoSuite = (open: OpenTestStores): void => {
|
|
|
17
18
|
before(async () => {
|
|
18
19
|
const opened = await open();
|
|
19
20
|
close = opened.close;
|
|
20
|
-
repos = composeSqliteRepositories(
|
|
21
|
+
repos = composeSqliteRepositories(
|
|
22
|
+
opened.stores,
|
|
23
|
+
messageObjectsInMemory(),
|
|
24
|
+
);
|
|
21
25
|
repo = repos.accountConfig;
|
|
22
26
|
});
|
|
23
27
|
|
|
@@ -4,6 +4,7 @@ import { BETTER_SQLITE3_LIMITS } from "../bound-parameters.js";
|
|
|
4
4
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
5
5
|
import { createTestDb, randomId, type TestDb } from "../test-db.js";
|
|
6
6
|
import type { AccountRepo } from "./i4-account.js";
|
|
7
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
7
8
|
import { mailboxCreated } from "./test-helpers.js";
|
|
8
9
|
|
|
9
10
|
function makeAccountInput(accountConfigId: string) {
|
|
@@ -34,6 +35,7 @@ describe("AccountRepo", () => {
|
|
|
34
35
|
search: db,
|
|
35
36
|
},
|
|
36
37
|
BETTER_SQLITE3_LIMITS,
|
|
38
|
+
messageObjectsInMemory(),
|
|
37
39
|
).account;
|
|
38
40
|
});
|
|
39
41
|
|
|
@@ -175,6 +177,7 @@ describe("AccountRepo", () => {
|
|
|
175
177
|
search: db,
|
|
176
178
|
},
|
|
177
179
|
BETTER_SQLITE3_LIMITS,
|
|
180
|
+
messageObjectsInMemory(),
|
|
178
181
|
).mailbox;
|
|
179
182
|
mailboxCreated(
|
|
180
183
|
await mailboxRepo.create({
|
|
@@ -6,6 +6,7 @@ import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
|
6
6
|
import { createTestDb, type TestDb } from "../test-db.js";
|
|
7
7
|
import { AddressRepo } from "./i4-address.js";
|
|
8
8
|
import type { MailboxSpecialUseRepo } from "./i4-mailbox-special-use.js";
|
|
9
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
9
10
|
|
|
10
11
|
const CONFIG = "cfg-1";
|
|
11
12
|
|
|
@@ -133,6 +134,7 @@ describe("reconciling one message's addresses at the moment it moves", () => {
|
|
|
133
134
|
search: db,
|
|
134
135
|
},
|
|
135
136
|
BETTER_SQLITE3_LIMITS,
|
|
137
|
+
messageObjectsInMemory(),
|
|
136
138
|
).mailboxSpecialUse;
|
|
137
139
|
});
|
|
138
140
|
|
|
@@ -18,6 +18,7 @@ import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
|
18
18
|
import type { AccountSettingRepo } from "./i4-account-setting.js";
|
|
19
19
|
import type { MailboxRepo } from "./i4-mailbox.js";
|
|
20
20
|
import type { MailboxSpecialUseRepo } from "./i4-mailbox-special-use.js";
|
|
21
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
21
22
|
import { mailboxCreated } from "./test-helpers.js";
|
|
22
23
|
|
|
23
24
|
const makeMailboxInput = (
|
|
@@ -65,6 +66,7 @@ describe("MailboxSpecialUseRepo role lookups (sqlite)", () => {
|
|
|
65
66
|
search: testDb.db,
|
|
66
67
|
},
|
|
67
68
|
BETTER_SQLITE3_LIMITS,
|
|
69
|
+
messageObjectsInMemory(),
|
|
68
70
|
);
|
|
69
71
|
repo = repos.mailboxSpecialUse;
|
|
70
72
|
mailboxes = repos.mailbox;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
shippedTableDdl,
|
|
14
14
|
} from "../test-shipped-sqlite-schema.js";
|
|
15
15
|
import type { MailboxRepo } from "./i4-mailbox.js";
|
|
16
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
16
17
|
import { mailboxCreated } from "./test-helpers.js";
|
|
17
18
|
|
|
18
19
|
function makeMailboxInput(accountId: string, fullPath = "INBOX") {
|
|
@@ -49,6 +50,7 @@ describe("MailboxRepo (sqlite)", () => {
|
|
|
49
50
|
search: testDb.db,
|
|
50
51
|
},
|
|
51
52
|
BETTER_SQLITE3_LIMITS,
|
|
53
|
+
messageObjectsInMemory(),
|
|
52
54
|
).mailbox;
|
|
53
55
|
});
|
|
54
56
|
|
|
@@ -222,6 +224,7 @@ describe("MailboxRepo (sqlite, shipped migrations)", () => {
|
|
|
222
224
|
search: db,
|
|
223
225
|
},
|
|
224
226
|
BETTER_SQLITE3_LIMITS,
|
|
227
|
+
messageObjectsInMemory(),
|
|
225
228
|
).mailbox;
|
|
226
229
|
close = async () => {
|
|
227
230
|
sqlite.close();
|
|
@@ -18,6 +18,7 @@ import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
|
18
18
|
import { createTestDb, randomId, type TestDb } from "../test-db.js";
|
|
19
19
|
import type { MailboxRepo } from "./i4-mailbox.js";
|
|
20
20
|
import { deleteMessageSubtree } from "./message.js";
|
|
21
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
21
22
|
import { mailboxCreated } from "./test-helpers.js";
|
|
22
23
|
|
|
23
24
|
/** Every state a row can carry, for a transition that decides against none. */
|
|
@@ -62,6 +63,7 @@ describe("MailboxRepo", () => {
|
|
|
62
63
|
search: db,
|
|
63
64
|
},
|
|
64
65
|
BETTER_SQLITE3_LIMITS,
|
|
66
|
+
messageObjectsInMemory(),
|
|
65
67
|
).mailbox;
|
|
66
68
|
});
|
|
67
69
|
|
|
@@ -554,6 +556,7 @@ describe("MailboxRepo", () => {
|
|
|
554
556
|
search: db,
|
|
555
557
|
},
|
|
556
558
|
BETTER_SQLITE3_LIMITS,
|
|
559
|
+
messageObjectsInMemory(),
|
|
557
560
|
).message.create({
|
|
558
561
|
messageId,
|
|
559
562
|
mailboxId,
|
|
@@ -561,8 +564,6 @@ describe("MailboxRepo", () => {
|
|
|
561
564
|
sequenceNumber: uid,
|
|
562
565
|
rfc822Size: 10,
|
|
563
566
|
internalDate: 1700000000000,
|
|
564
|
-
envelopeId: deriveEnvelopeId(messageId),
|
|
565
|
-
rootBodyPartId: deriveRootBodyPartId(messageId),
|
|
566
567
|
});
|
|
567
568
|
await db.insert(threadMessageTable).values({
|
|
568
569
|
threadMessageId: randomId(),
|
|
@@ -682,7 +683,7 @@ describe("MailboxRepo", () => {
|
|
|
682
683
|
|
|
683
684
|
// The shape an interruption leaves: one message's rows already gone,
|
|
684
685
|
// the mailbox row still there and still `deleting`.
|
|
685
|
-
await syncBatch(db)(deleteMessageSubtree(db, [first]));
|
|
686
|
+
await syncBatch(db)(deleteMessageSubtree(db, [first]).statements);
|
|
686
687
|
await repo.transition(accountId, mailbox.mailboxId, {
|
|
687
688
|
from: EVERY_STATE,
|
|
688
689
|
to: MailboxSyncStatus.deleting,
|
package/src/repos/i4-mailbox.ts
CHANGED
|
@@ -42,10 +42,8 @@ import { messageFlagPushTable } from "../schema/i4-message-flag-push.js";
|
|
|
42
42
|
import { messagePlacementMoveTable } from "../schema/i4-message-placement-move.js";
|
|
43
43
|
import { messageTable } from "../schema/message-data.js";
|
|
44
44
|
import { syncWarningTable } from "../schema/sync-warning.js";
|
|
45
|
-
import { threadMessageTable } from "../schema/thread-message.js";
|
|
46
|
-
import type { SearchIndex } from "../search/thread-message-search.js";
|
|
47
45
|
import { inList } from "./in-list.js";
|
|
48
|
-
import {
|
|
46
|
+
import type { DrizzleMessageRepository } from "./message.js";
|
|
49
47
|
|
|
50
48
|
const base36Translator = shortUuid.createTranslator(
|
|
51
49
|
shortUuid.constants.uuid25Base36,
|
|
@@ -60,7 +58,6 @@ type DB = RepositoryDb<Record<string, unknown>>;
|
|
|
60
58
|
* the file's write lock, so the bound is what keeps a large folder's delete from
|
|
61
59
|
* parking every other writer behind it (D8).
|
|
62
60
|
*/
|
|
63
|
-
const MAIL_DELETE_BATCH_SIZE = 100;
|
|
64
61
|
|
|
65
62
|
/**
|
|
66
63
|
* The folders under `path`. A flat namespace nests nothing: with no delimiter
|
|
@@ -154,7 +151,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
154
151
|
|
|
155
152
|
constructor(
|
|
156
153
|
store: SqliteStore<Record<string, unknown>>,
|
|
157
|
-
private
|
|
154
|
+
private messages: Pick<DrizzleMessageRepository, "deleteMany">,
|
|
158
155
|
) {
|
|
159
156
|
this.db = store.db;
|
|
160
157
|
this.batch = store.batch;
|
|
@@ -547,29 +544,11 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
547
544
|
// Ordered, batched and resumable rather than one transaction (D8). The
|
|
548
545
|
// caller keeps the row `deleting` until the last commit, so an interrupted
|
|
549
546
|
// run re-enters here and continues against whatever is left.
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
.limit(MAIL_DELETE_BATCH_SIZE);
|
|
556
|
-
if (rows.length === 0) break;
|
|
557
|
-
const messageIds = rows.map((row) => row.messageId);
|
|
558
|
-
const listings = await this.db
|
|
559
|
-
.select({ threadMessageId: threadMessageTable.threadMessageId })
|
|
560
|
-
.from(threadMessageTable)
|
|
561
|
-
.where(inList(threadMessageTable.messageId, messageIds));
|
|
562
|
-
|
|
563
|
-
// The primitive the rest of the codebase deletes mail with: nine
|
|
564
|
-
// per-message child tables. A bespoke table list would orphan them.
|
|
565
|
-
await this.batch([
|
|
566
|
-
...deleteMessageSubtree(this.db, messageIds),
|
|
567
|
-
this.db
|
|
568
|
-
.delete(threadMessageTable)
|
|
569
|
-
.where(inList(threadMessageTable.messageId, messageIds)),
|
|
570
|
-
]);
|
|
571
|
-
await this.search.sync(listings.map((row) => row.threadMessageId));
|
|
572
|
-
}
|
|
547
|
+
const rows = await this.db
|
|
548
|
+
.select({ messageId: messageTable.messageId })
|
|
549
|
+
.from(messageTable)
|
|
550
|
+
.where(eq(messageTable.mailboxId, mailboxId));
|
|
551
|
+
await this.messages.deleteMany(rows.map((row) => row.messageId));
|
|
573
552
|
|
|
574
553
|
await this.db
|
|
575
554
|
.delete(mailboxSpecialUseTable)
|
|
@@ -4,6 +4,7 @@ import { BETTER_SQLITE3_LIMITS } from "../bound-parameters.js";
|
|
|
4
4
|
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
5
5
|
import { createTestDb, randomId } from "../test-db.js";
|
|
6
6
|
import type { OutboxAttachmentRepo } from "./i4-outbox-attachment.js";
|
|
7
|
+
import { messageObjectsInMemory } from "./message-objects.js";
|
|
7
8
|
|
|
8
9
|
const CAP = { maxTotalBytes: 1000, maxCount: 3, nowSeconds: 1_000_000 };
|
|
9
10
|
|
|
@@ -36,6 +37,7 @@ before(async () => {
|
|
|
36
37
|
search: harness.db,
|
|
37
38
|
},
|
|
38
39
|
BETTER_SQLITE3_LIMITS,
|
|
40
|
+
messageObjectsInMemory(),
|
|
39
41
|
).outboxAttachment;
|
|
40
42
|
});
|
|
41
43
|
|