@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
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
type SQLWrapper,
|
|
24
24
|
sql,
|
|
25
25
|
} from "drizzle-orm";
|
|
26
|
-
import {
|
|
27
|
-
import type {
|
|
26
|
+
import type { WriteBatch } from "../batch.js";
|
|
27
|
+
import type { RepositoryDb, SqliteStore } from "../db.js";
|
|
28
28
|
import { NotFoundError } from "../error.js";
|
|
29
29
|
import { deterministicBase36Id } from "../id.js";
|
|
30
30
|
import { decodeToken } from "../pagination.js";
|
|
@@ -44,6 +44,8 @@ import {
|
|
|
44
44
|
subjectMatch,
|
|
45
45
|
} from "./thread-search-predicates.js";
|
|
46
46
|
|
|
47
|
+
type DB = RepositoryDb<Record<string, unknown>>;
|
|
48
|
+
|
|
47
49
|
export const deriveThreadMessageId = (
|
|
48
50
|
threadId: string,
|
|
49
51
|
messageId: string,
|
|
@@ -326,10 +328,16 @@ function sentDateCursorCond(
|
|
|
326
328
|
export class DrizzleThreadMessageRepository
|
|
327
329
|
implements IThreadMessageRepository
|
|
328
330
|
{
|
|
331
|
+
private readonly db: DB;
|
|
332
|
+
private readonly batch: WriteBatch;
|
|
333
|
+
|
|
329
334
|
constructor(
|
|
330
|
-
|
|
335
|
+
store: SqliteStore<Record<string, unknown>>,
|
|
331
336
|
private readonly search: SearchIndex,
|
|
332
|
-
) {
|
|
337
|
+
) {
|
|
338
|
+
this.db = store.db;
|
|
339
|
+
this.batch = store.batch;
|
|
340
|
+
}
|
|
333
341
|
|
|
334
342
|
/**
|
|
335
343
|
* One page of rows in date order (ranked first when asked). Without a text
|
|
@@ -1082,7 +1090,7 @@ export class DrizzleThreadMessageRepository
|
|
|
1082
1090
|
.returning({ threadMessageId: threadMessageTable.threadMessageId }),
|
|
1083
1091
|
];
|
|
1084
1092
|
});
|
|
1085
|
-
const results = await
|
|
1093
|
+
const results = await this.batch(items);
|
|
1086
1094
|
await this.search.sync(
|
|
1087
1095
|
rows.flatMap((row) => [
|
|
1088
1096
|
row.threadMessageId,
|
|
@@ -3,8 +3,9 @@ import { after, before, describe, test } from "node:test";
|
|
|
3
3
|
import type { CreateThreadMessageInput } from "@remit/data-ports";
|
|
4
4
|
import Database from "better-sqlite3";
|
|
5
5
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
6
|
+
import { syncStore } from "../databases.js";
|
|
6
7
|
import type { Db } from "../db.js";
|
|
7
|
-
import {
|
|
8
|
+
import { createSqliteRepositories } from "../sqlite-repositories.js";
|
|
8
9
|
import { applyMigrationSet } from "../test-shipped-sqlite-schema.js";
|
|
9
10
|
import {
|
|
10
11
|
SearchIndex,
|
|
@@ -48,8 +49,12 @@ const open = (set: "mail" | "search") => {
|
|
|
48
49
|
describe("the thread-message search index in its own database", () => {
|
|
49
50
|
const mail = open("mail");
|
|
50
51
|
const search = open("search");
|
|
51
|
-
const index = new SearchIndex(mail.db, search.db);
|
|
52
|
-
const repo =
|
|
52
|
+
const index = new SearchIndex(mail.db, syncStore(search.db));
|
|
53
|
+
const repo = createSqliteRepositories({
|
|
54
|
+
app: mail.db,
|
|
55
|
+
mail: mail.db,
|
|
56
|
+
search: search.db,
|
|
57
|
+
}).threadMessage;
|
|
53
58
|
|
|
54
59
|
const found = async (query: string): Promise<string[]> =>
|
|
55
60
|
(await repo.searchByMailboxWindow(ACCOUNT, MAILBOX, { query })).items.map(
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
sql,
|
|
13
13
|
} from "drizzle-orm";
|
|
14
14
|
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
15
|
-
import {
|
|
16
|
-
import type {
|
|
15
|
+
import type { SqliteBatchItem, WriteBatch } from "../batch.js";
|
|
16
|
+
import type { RepositoryDb, SqliteStore } from "../db.js";
|
|
17
17
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
18
18
|
|
|
19
19
|
// The FTS5 trigram table the search migration set creates
|
|
@@ -32,7 +32,7 @@ export const threadMessageSearchTable = sqliteTable("thread_message_fts", {
|
|
|
32
32
|
body: text("body").notNull(),
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
type AnyDb =
|
|
35
|
+
type AnyDb = RepositoryDb<Record<string, unknown>>;
|
|
36
36
|
|
|
37
37
|
type SearchDocument = typeof threadMessageSearchTable.$inferInsert;
|
|
38
38
|
|
|
@@ -138,10 +138,16 @@ export interface CandidateQuery {
|
|
|
138
138
|
* only, so no statement carries more ids than a page holds.
|
|
139
139
|
*/
|
|
140
140
|
export class SearchIndex {
|
|
141
|
+
private readonly search: AnyDb;
|
|
142
|
+
private readonly batch: WriteBatch;
|
|
143
|
+
|
|
141
144
|
constructor(
|
|
142
145
|
private readonly mail: AnyDb,
|
|
143
|
-
|
|
144
|
-
) {
|
|
146
|
+
store: SqliteStore<Record<string, unknown>>,
|
|
147
|
+
) {
|
|
148
|
+
this.search = store.db;
|
|
149
|
+
this.batch = store.batch;
|
|
150
|
+
}
|
|
145
151
|
|
|
146
152
|
/** Make the index match the mail database for these thread messages. */
|
|
147
153
|
async sync(threadMessageIds: readonly string[]): Promise<void> {
|
|
@@ -165,7 +171,7 @@ export class SearchIndex {
|
|
|
165
171
|
.values(rows.map(toDocument)),
|
|
166
172
|
);
|
|
167
173
|
}
|
|
168
|
-
await
|
|
174
|
+
await this.batch(items);
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
177
|
|
|
@@ -256,8 +262,7 @@ export class SearchIndex {
|
|
|
256
262
|
.limit(DOCUMENTS_PER_REBUILD_PAGE);
|
|
257
263
|
const last = rows.at(-1);
|
|
258
264
|
if (!last) return indexed;
|
|
259
|
-
await
|
|
260
|
-
this.search,
|
|
265
|
+
await this.batch(
|
|
261
266
|
chunk(rows, DOCUMENTS_PER_STATEMENT).map((slice) =>
|
|
262
267
|
this.search
|
|
263
268
|
.insert(threadMessageSearchTable)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
type SqliteDatabases,
|
|
3
|
+
type SqliteStores,
|
|
4
|
+
syncStores,
|
|
5
|
+
} from "./databases.js";
|
|
2
6
|
import { CalendarCollectionRepo } from "./repos/calendar-collection.js";
|
|
3
7
|
import { CalendarEventIndexRepo } from "./repos/calendar-event-index.js";
|
|
4
8
|
import { CalendarFeedTokenRepo } from "./repos/calendar-feed-token.js";
|
|
@@ -31,45 +35,57 @@ import { SyncWarningRepo } from "./repos/sync-warning.js";
|
|
|
31
35
|
import { DrizzleThreadMessageRepository } from "./repos/thread-message.js";
|
|
32
36
|
import { SearchIndex } from "./search/thread-message-search.js";
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
export const createSqliteRepositories = ({
|
|
38
|
+
export const composeSqliteRepositories = ({
|
|
36
39
|
app,
|
|
37
40
|
mail,
|
|
38
41
|
search,
|
|
39
|
-
}:
|
|
40
|
-
const searchIndex = new SearchIndex(mail, search);
|
|
42
|
+
}: SqliteStores) => {
|
|
43
|
+
const searchIndex = new SearchIndex(mail.db, search);
|
|
44
|
+
const accountSetting = new AccountSettingRepo(app.db);
|
|
45
|
+
const address = new AddressRepo(mail.db);
|
|
46
|
+
const mailbox = new MailboxRepo(mail, searchIndex);
|
|
47
|
+
const account = new AccountRepo(app.db, mailbox);
|
|
48
|
+
const calendarSuggestion = new CalendarSuggestionRepo(mail.db);
|
|
41
49
|
return {
|
|
42
|
-
accountConfig: new AccountConfigRepo(app,
|
|
43
|
-
account
|
|
44
|
-
accountSetting
|
|
45
|
-
address
|
|
46
|
-
mailbox
|
|
47
|
-
mailboxSpecialUse: new MailboxSpecialUseRepo(
|
|
48
|
-
|
|
50
|
+
accountConfig: new AccountConfigRepo(app.db, address),
|
|
51
|
+
account,
|
|
52
|
+
accountSetting,
|
|
53
|
+
address,
|
|
54
|
+
mailbox,
|
|
55
|
+
mailboxSpecialUse: new MailboxSpecialUseRepo(
|
|
56
|
+
mail.db,
|
|
57
|
+
account,
|
|
58
|
+
accountSetting,
|
|
59
|
+
),
|
|
60
|
+
mailboxLock: new MailboxLockRepo(mail.db),
|
|
49
61
|
message: new DrizzleMessageRepository(mail, searchIndex),
|
|
50
|
-
messageFlag: new DrizzleMessageFlagRepository(mail),
|
|
51
|
-
outboxMessage: new OutboxMessageRepo(mail),
|
|
62
|
+
messageFlag: new DrizzleMessageFlagRepository(mail.db),
|
|
63
|
+
outboxMessage: new OutboxMessageRepo(mail.db),
|
|
52
64
|
outboxAttachment: new OutboxAttachmentRepo(mail),
|
|
53
65
|
threadMessage: new DrizzleThreadMessageRepository(mail, searchIndex),
|
|
54
66
|
envelope: new DrizzleEnvelopeRepository(mail),
|
|
55
|
-
accountExportRequest: new AccountExportRequestRepo(app),
|
|
56
|
-
configImport: new ConfigImportRepo(app),
|
|
57
|
-
quarantine: new QuarantineRepo(mail),
|
|
58
|
-
syncWarning: new SyncWarningRepo(mail),
|
|
59
|
-
organizeJobRequest: new OrganizeJobRequestRepo(mail),
|
|
60
|
-
placementMove: new MessagePlacementMoveRepo(mail),
|
|
61
|
-
flagPush: new MessageFlagPushRepo(mail),
|
|
62
|
-
filter: new FilterRepo(app),
|
|
63
|
-
label: new LabelRepo(app),
|
|
64
|
-
messageLabel: new MessageLabelRepo(mail),
|
|
65
|
-
senderSignerStanding: new SenderSignerStandingRepo(mail),
|
|
66
|
-
calendarCollection: new CalendarCollectionRepo(app),
|
|
67
|
-
calendarObject: new CalendarObjectRepo(app),
|
|
68
|
-
calendarEventIndex: new CalendarEventIndexRepo(app),
|
|
69
|
-
calendarFeedToken: new CalendarFeedTokenRepo(app),
|
|
70
|
-
calendarSuggestion
|
|
71
|
-
calendarStore: new DrizzleCalendarStore(app,
|
|
67
|
+
accountExportRequest: new AccountExportRequestRepo(app.db),
|
|
68
|
+
configImport: new ConfigImportRepo(app.db),
|
|
69
|
+
quarantine: new QuarantineRepo(mail.db),
|
|
70
|
+
syncWarning: new SyncWarningRepo(mail.db),
|
|
71
|
+
organizeJobRequest: new OrganizeJobRequestRepo(mail.db),
|
|
72
|
+
placementMove: new MessagePlacementMoveRepo(mail.db),
|
|
73
|
+
flagPush: new MessageFlagPushRepo(mail.db),
|
|
74
|
+
filter: new FilterRepo(app.db),
|
|
75
|
+
label: new LabelRepo(app.db),
|
|
76
|
+
messageLabel: new MessageLabelRepo(mail.db),
|
|
77
|
+
senderSignerStanding: new SenderSignerStandingRepo(mail.db),
|
|
78
|
+
calendarCollection: new CalendarCollectionRepo(app.db),
|
|
79
|
+
calendarObject: new CalendarObjectRepo(app.db),
|
|
80
|
+
calendarEventIndex: new CalendarEventIndexRepo(app.db),
|
|
81
|
+
calendarFeedToken: new CalendarFeedTokenRepo(app.db),
|
|
82
|
+
calendarSuggestion,
|
|
83
|
+
calendarStore: new DrizzleCalendarStore(app, calendarSuggestion),
|
|
72
84
|
};
|
|
73
85
|
};
|
|
74
86
|
|
|
75
|
-
export type SqliteRepositories = ReturnType<typeof
|
|
87
|
+
export type SqliteRepositories = ReturnType<typeof composeSqliteRepositories>;
|
|
88
|
+
|
|
89
|
+
export const createSqliteRepositories = (
|
|
90
|
+
databases: SqliteDatabases,
|
|
91
|
+
): SqliteRepositories => composeSqliteRepositories(syncStores(databases));
|