@remit/drizzle-service 0.0.101 → 0.0.102
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/repos/calendar-suggestion.ts +3 -2
- package/src/repos/cascade-delete.ts +27 -28
- package/src/repos/envelope.ts +5 -4
- package/src/repos/i4-account-config.ts +4 -3
- package/src/repos/i4-account-setting.ts +4 -3
- package/src/repos/i4-account.ts +4 -3
- package/src/repos/i4-address.ts +5 -5
- package/src/repos/i4-mailbox-special-use.ts +6 -5
- package/src/repos/i4-mailbox.ts +6 -5
- package/src/repos/i4-outbox-attachment.ts +3 -5
- package/src/repos/i4-outbox-message.ts +5 -4
- package/src/repos/in-list.sqlite.test.ts +61 -0
- package/src/repos/in-list.ts +14 -0
- package/src/repos/message-flag.ts +5 -4
- package/src/repos/message-label.ts +3 -2
- package/src/repos/message.ts +15 -14
- package/src/repos/sync-warning.ts +3 -2
- package/src/repos/thread-message.ts +3 -2
package/package.json
CHANGED
|
@@ -7,11 +7,12 @@ 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, gte,
|
|
10
|
+
import { and, asc, desc, eq, gte, 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";
|
|
14
14
|
import { calendarSuggestionTable } from "../schema.js";
|
|
15
|
+
import { inList } from "./in-list.js";
|
|
15
16
|
|
|
16
17
|
type DB = Db<Record<string, unknown>>;
|
|
17
18
|
|
|
@@ -111,7 +112,7 @@ export class CalendarSuggestionRepo implements ICalendarSuggestionRepository {
|
|
|
111
112
|
.where(
|
|
112
113
|
and(
|
|
113
114
|
eq(calendarSuggestionTable.accountConfigId, accountConfigId),
|
|
114
|
-
|
|
115
|
+
inList(
|
|
115
116
|
calendarSuggestionTable.acceptedCalendarObjectId,
|
|
116
117
|
calendarObjectIds,
|
|
117
118
|
),
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { and, eq, inArray, or, type SQL } from "drizzle-orm";
|
|
2
1
|
import { runBatch, type SqliteBatchItem } from "../batch.js";
|
|
3
2
|
import {
|
|
4
3
|
openSqliteDatabases,
|
|
@@ -17,6 +16,7 @@ import { quarantineTable } from "../schema/quarantine.js";
|
|
|
17
16
|
import { syncWarningTable } from "../schema/sync-warning.js";
|
|
18
17
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
19
18
|
import { SearchIndex } from "../search/thread-message-search.js";
|
|
19
|
+
import { inList, pairInList } from "./in-list.js";
|
|
20
20
|
import { deleteMessageSubtree } from "./message.js";
|
|
21
21
|
|
|
22
22
|
export interface CascadeEntity {
|
|
@@ -107,7 +107,7 @@ export const runDrizzleCascadeDelete = async (
|
|
|
107
107
|
items.push(
|
|
108
108
|
mail
|
|
109
109
|
.delete(threadMessageTable)
|
|
110
|
-
.where(
|
|
110
|
+
.where(inList(threadMessageTable.threadMessageId, threadMessageIds)),
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -116,12 +116,12 @@ export const runDrizzleCascadeDelete = async (
|
|
|
116
116
|
items.push(
|
|
117
117
|
mail
|
|
118
118
|
.delete(syncWarningTable)
|
|
119
|
-
.where(
|
|
119
|
+
.where(inList(syncWarningTable.mailboxId, mailboxIds)),
|
|
120
120
|
);
|
|
121
121
|
items.push(
|
|
122
122
|
mail
|
|
123
123
|
.delete(mailboxTable)
|
|
124
|
-
.where(
|
|
124
|
+
.where(inList(mailboxTable.mailboxId, mailboxIds)),
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -132,19 +132,21 @@ export const runDrizzleCascadeDelete = async (
|
|
|
132
132
|
items.push(
|
|
133
133
|
mail
|
|
134
134
|
.delete(outboxMessageTable)
|
|
135
|
-
.where(
|
|
135
|
+
.where(inList(outboxMessageTable.outboxMessageId, outboxMessageIds)),
|
|
136
136
|
);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
const lockKeys = grouped.get("MailboxLock") ?? [];
|
|
140
140
|
if (lockKeys.length > 0) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
items.push(
|
|
142
|
+
mail.delete(mailboxLockTable).where(
|
|
143
|
+
pairInList(
|
|
144
|
+
mailboxLockTable.mailboxId,
|
|
145
|
+
mailboxLockTable.eventName,
|
|
146
|
+
lockKeys.map((k) => [k.mailboxId, k.eventName]),
|
|
147
|
+
),
|
|
145
148
|
),
|
|
146
|
-
)
|
|
147
|
-
items.push(mail.delete(mailboxLockTable).where(or(...conditions)));
|
|
149
|
+
);
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
const accountSettingIds = (grouped.get("AccountSetting") ?? []).map(
|
|
@@ -154,9 +156,7 @@ export const runDrizzleCascadeDelete = async (
|
|
|
154
156
|
appItems.push(
|
|
155
157
|
app
|
|
156
158
|
.delete(accountSettingTable)
|
|
157
|
-
.where(
|
|
158
|
-
inArray(accountSettingTable.accountSettingId, accountSettingIds),
|
|
159
|
-
),
|
|
159
|
+
.where(inList(accountSettingTable.accountSettingId, accountSettingIds)),
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -165,7 +165,7 @@ export const runDrizzleCascadeDelete = async (
|
|
|
165
165
|
items.push(
|
|
166
166
|
mail
|
|
167
167
|
.delete(addressTable)
|
|
168
|
-
.where(
|
|
168
|
+
.where(inList(addressTable.addressId, addressIds)),
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -178,17 +178,17 @@ export const runDrizzleCascadeDelete = async (
|
|
|
178
178
|
items.push(
|
|
179
179
|
mail
|
|
180
180
|
.delete(quarantineTable)
|
|
181
|
-
.where(
|
|
181
|
+
.where(inList(quarantineTable.accountId, accountIds)),
|
|
182
182
|
);
|
|
183
183
|
items.push(
|
|
184
184
|
mail
|
|
185
185
|
.delete(syncWarningTable)
|
|
186
|
-
.where(
|
|
186
|
+
.where(inList(syncWarningTable.accountId, accountIds)),
|
|
187
187
|
);
|
|
188
188
|
appItems.push(
|
|
189
189
|
app
|
|
190
190
|
.delete(accountTable)
|
|
191
|
-
.where(
|
|
191
|
+
.where(inList(accountTable.accountId, accountIds)),
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -200,23 +200,22 @@ export const runDrizzleCascadeDelete = async (
|
|
|
200
200
|
mail
|
|
201
201
|
.delete(messagePlacementMoveTable)
|
|
202
202
|
.where(
|
|
203
|
-
|
|
203
|
+
inList(messagePlacementMoveTable.messageId, placementMoveMessageIds),
|
|
204
204
|
),
|
|
205
205
|
);
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
// Composite key (messageId, flagName) — a message can carry an
|
|
209
|
-
// independent pending read-state marker and pending star marker at once
|
|
210
|
-
// (issue #1273), so a single-column inArray cannot target one row.
|
|
211
208
|
const flagPushKeys = grouped.get("MessageFlagPush") ?? [];
|
|
212
209
|
if (flagPushKeys.length > 0) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
210
|
+
items.push(
|
|
211
|
+
mail.delete(messageFlagPushTable).where(
|
|
212
|
+
pairInList(
|
|
213
|
+
messageFlagPushTable.messageId,
|
|
214
|
+
messageFlagPushTable.flagName,
|
|
215
|
+
flagPushKeys.map((k) => [k.messageId, k.flagName]),
|
|
216
|
+
),
|
|
217
217
|
),
|
|
218
|
-
)
|
|
219
|
-
items.push(mail.delete(messageFlagPushTable).where(or(...conditions)));
|
|
218
|
+
);
|
|
220
219
|
}
|
|
221
220
|
await runBatch(mail, items);
|
|
222
221
|
await runBatch(app, appItems);
|
package/src/repos/envelope.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
MessageReferenceInput,
|
|
9
9
|
UpdateEnvelopeInput,
|
|
10
10
|
} from "@remit/data-ports";
|
|
11
|
-
import { eq
|
|
11
|
+
import { eq } from "drizzle-orm";
|
|
12
12
|
import { runBatch } from "../batch.js";
|
|
13
13
|
import type { Db } from "../db.js";
|
|
14
14
|
import {
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
messageTable,
|
|
35
35
|
rawMessageStorageTable,
|
|
36
36
|
} from "../schema/message-data.js";
|
|
37
|
+
import { inList } from "./in-list.js";
|
|
37
38
|
import {
|
|
38
39
|
toBodyPartItem,
|
|
39
40
|
toBodyPartParameterItem,
|
|
@@ -235,7 +236,7 @@ export class DrizzleEnvelopeRepository implements IEnvelopeRepository {
|
|
|
235
236
|
|
|
236
237
|
await this.db
|
|
237
238
|
.delete(envelopeTable)
|
|
238
|
-
.where(
|
|
239
|
+
.where(inList(envelopeTable.envelopeId, envelopeIds));
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
async createEnvelope(input: CreateEnvelopeInput): Promise<EnvelopeItem> {
|
|
@@ -293,7 +294,7 @@ export class DrizzleEnvelopeRepository implements IEnvelopeRepository {
|
|
|
293
294
|
const rows = await this.db
|
|
294
295
|
.select()
|
|
295
296
|
.from(envelopeTable)
|
|
296
|
-
.where(
|
|
297
|
+
.where(inList(envelopeTable.envelopeId, envelopeId));
|
|
297
298
|
return rows.map(toEnvelopeItem);
|
|
298
299
|
}
|
|
299
300
|
|
|
@@ -353,6 +354,6 @@ export class DrizzleEnvelopeRepository implements IEnvelopeRepository {
|
|
|
353
354
|
if (messageIds.length === 0) return;
|
|
354
355
|
await this.db
|
|
355
356
|
.delete(bodyStructureRefetchTable)
|
|
356
|
-
.where(
|
|
357
|
+
.where(inList(bodyStructureRefetchTable.messageId, messageIds));
|
|
357
358
|
}
|
|
358
359
|
}
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
ResultList,
|
|
7
7
|
UpdateAccountConfigInput,
|
|
8
8
|
} from "@remit/data-ports";
|
|
9
|
-
import { and, asc, eq, gt,
|
|
9
|
+
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
10
10
|
import type { Db } from "../db.js";
|
|
11
11
|
import { NotFoundError } from "../error.js";
|
|
12
12
|
import { randomId } from "../id.js";
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import { addressTable } from "../schema/i4-address.js";
|
|
19
19
|
import { rowToAccount } from "./i4-account.js";
|
|
20
20
|
import { rowToAddress } from "./i4-address.js";
|
|
21
|
+
import { inList } from "./in-list.js";
|
|
21
22
|
|
|
22
23
|
type DB = Db<Record<string, unknown>>;
|
|
23
24
|
|
|
@@ -71,7 +72,7 @@ export class AccountConfigRepo implements IAccountConfigRepository {
|
|
|
71
72
|
const rows = await this.db
|
|
72
73
|
.select()
|
|
73
74
|
.from(accountConfigTable)
|
|
74
|
-
.where(
|
|
75
|
+
.where(inList(accountConfigTable.accountConfigId, accountConfigId));
|
|
75
76
|
return rows.map(rowToAccountConfig);
|
|
76
77
|
}
|
|
77
78
|
const [row] = await this.db
|
|
@@ -116,7 +117,7 @@ export class AccountConfigRepo implements IAccountConfigRepository {
|
|
|
116
117
|
if (accountConfigIds.length === 0) return;
|
|
117
118
|
await this.db
|
|
118
119
|
.delete(accountConfigTable)
|
|
119
|
-
.where(
|
|
120
|
+
.where(inList(accountConfigTable.accountConfigId, accountConfigIds));
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
async listByUser(
|
|
@@ -5,9 +5,10 @@ import type {
|
|
|
5
5
|
IAccountSettingRepository,
|
|
6
6
|
UpsertAccountSettingInput,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
|
-
import { and, eq
|
|
8
|
+
import { and, eq } from "drizzle-orm";
|
|
9
9
|
import type { Db } from "../db.js";
|
|
10
10
|
import { accountSettingTable } from "../schema/i4-account-setting.js";
|
|
11
|
+
import { inList } from "./in-list.js";
|
|
11
12
|
|
|
12
13
|
type DB = Db<Record<string, unknown>>;
|
|
13
14
|
|
|
@@ -63,8 +64,8 @@ export class AccountSettingRepo implements IAccountSettingRepository {
|
|
|
63
64
|
.from(accountSettingTable)
|
|
64
65
|
.where(
|
|
65
66
|
and(
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
inList(accountSettingTable.accountConfigId, accountConfigIds),
|
|
68
|
+
inList(accountSettingTable.name, names),
|
|
68
69
|
),
|
|
69
70
|
);
|
|
70
71
|
return rows.map(rowToAccountSetting);
|
package/src/repos/i4-account.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
UpdateAccountInput,
|
|
10
10
|
} from "@remit/data-ports";
|
|
11
11
|
import { AccountService, SyncPhase } from "@remit/domain-enums";
|
|
12
|
-
import { and, asc, eq, gt,
|
|
12
|
+
import { and, asc, eq, gt, like, or, sql } from "drizzle-orm";
|
|
13
13
|
import type { Db } from "../db.js";
|
|
14
14
|
import { NotFoundError } from "../error.js";
|
|
15
15
|
import { randomId } from "../id.js";
|
|
@@ -17,6 +17,7 @@ import { decodeToken, encodeToken, resultList } from "../pagination.js";
|
|
|
17
17
|
import { accountTable } from "../schema/i4-account-config.js";
|
|
18
18
|
import { mailboxTable } from "../schema/i4-mailbox.js";
|
|
19
19
|
import { rowToMailbox } from "./i4-mailbox.js";
|
|
20
|
+
import { inList } from "./in-list.js";
|
|
20
21
|
|
|
21
22
|
type DB = Db<Record<string, unknown>>;
|
|
22
23
|
|
|
@@ -129,7 +130,7 @@ export class AccountRepo implements IAccountRepository {
|
|
|
129
130
|
const rows = await this.db
|
|
130
131
|
.select()
|
|
131
132
|
.from(accountTable)
|
|
132
|
-
.where(
|
|
133
|
+
.where(inList(accountTable.accountId, accountId));
|
|
133
134
|
return rows.map(rowToAccount);
|
|
134
135
|
}
|
|
135
136
|
const [row] = await this.db
|
|
@@ -187,7 +188,7 @@ export class AccountRepo implements IAccountRepository {
|
|
|
187
188
|
if (accountIds.length === 0) return;
|
|
188
189
|
await this.db
|
|
189
190
|
.delete(accountTable)
|
|
190
|
-
.where(
|
|
191
|
+
.where(inList(accountTable.accountId, accountIds));
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
async list(
|
package/src/repos/i4-address.ts
CHANGED
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
eq,
|
|
20
20
|
getTableColumns,
|
|
21
21
|
gt,
|
|
22
|
-
inArray,
|
|
23
22
|
type SQL,
|
|
24
23
|
sql,
|
|
25
24
|
} from "drizzle-orm";
|
|
@@ -43,6 +42,7 @@ import {
|
|
|
43
42
|
addressRecency,
|
|
44
43
|
addressSearchMatch,
|
|
45
44
|
} from "./address-search-predicates.js";
|
|
45
|
+
import { inList } from "./in-list.js";
|
|
46
46
|
|
|
47
47
|
type DB = Db<Record<string, unknown>>;
|
|
48
48
|
|
|
@@ -400,7 +400,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
400
400
|
.where(
|
|
401
401
|
and(
|
|
402
402
|
eq(addressTable.accountConfigId, accountConfigId),
|
|
403
|
-
|
|
403
|
+
inList(addressTable.addressId, addressId),
|
|
404
404
|
),
|
|
405
405
|
);
|
|
406
406
|
return rows.map(rowToAddress);
|
|
@@ -666,7 +666,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
666
666
|
.where(
|
|
667
667
|
and(
|
|
668
668
|
eq(addressTable.accountConfigId, accountConfigId),
|
|
669
|
-
|
|
669
|
+
inList(addressTable.addressId, addressIds),
|
|
670
670
|
),
|
|
671
671
|
);
|
|
672
672
|
}
|
|
@@ -856,7 +856,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
856
856
|
.select()
|
|
857
857
|
.from(envelopeAddressTable)
|
|
858
858
|
.where(
|
|
859
|
-
|
|
859
|
+
inList(envelopeAddressTable.envelopeAddressId, envelopeAddressId),
|
|
860
860
|
);
|
|
861
861
|
return rows.map(rowToEnvelopeAddress);
|
|
862
862
|
}
|
|
@@ -884,7 +884,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
884
884
|
await this.db
|
|
885
885
|
.delete(envelopeAddressTable)
|
|
886
886
|
.where(
|
|
887
|
-
|
|
887
|
+
inList(envelopeAddressTable.envelopeAddressId, envelopeAddressIds),
|
|
888
888
|
);
|
|
889
889
|
}
|
|
890
890
|
}
|
|
@@ -14,12 +14,13 @@ import {
|
|
|
14
14
|
type UnappointedRoleResolution,
|
|
15
15
|
} from "@remit/data-ports/folder-role";
|
|
16
16
|
import { CanonicalMailboxRole } from "@remit/domain-enums";
|
|
17
|
-
import { eq
|
|
17
|
+
import { eq } from "drizzle-orm";
|
|
18
18
|
import type { Db } from "../db.js";
|
|
19
19
|
import { randomId } from "../id.js";
|
|
20
20
|
import { accountTable } from "../schema/i4-account-config.js";
|
|
21
21
|
import { mailboxSpecialUseTable, mailboxTable } from "../schema/i4-mailbox.js";
|
|
22
22
|
import { AccountSettingRepo } from "./i4-account-setting.js";
|
|
23
|
+
import { inList } from "./in-list.js";
|
|
23
24
|
|
|
24
25
|
type DB = Db<Record<string, unknown>>;
|
|
25
26
|
|
|
@@ -269,7 +270,7 @@ export class MailboxSpecialUseRepo implements IMailboxSpecialUseRepository {
|
|
|
269
270
|
accountConfigId: accountTable.accountConfigId,
|
|
270
271
|
})
|
|
271
272
|
.from(accountTable)
|
|
272
|
-
.where(
|
|
273
|
+
.where(inList(accountTable.accountId, accountIds));
|
|
273
274
|
if (accounts.length === 0) return new Map();
|
|
274
275
|
|
|
275
276
|
const wanted = new Map<string, string>();
|
|
@@ -303,14 +304,14 @@ export class MailboxSpecialUseRepo implements IMailboxSpecialUseRepository {
|
|
|
303
304
|
const rows = await this.db
|
|
304
305
|
.select()
|
|
305
306
|
.from(mailboxTable)
|
|
306
|
-
.where(
|
|
307
|
+
.where(inList(mailboxTable.accountId, accountIds));
|
|
307
308
|
if (rows.length === 0) return new Map();
|
|
308
309
|
|
|
309
310
|
const entries = await this.db
|
|
310
311
|
.select()
|
|
311
312
|
.from(mailboxSpecialUseTable)
|
|
312
313
|
.where(
|
|
313
|
-
|
|
314
|
+
inList(
|
|
314
315
|
mailboxSpecialUseTable.mailboxId,
|
|
315
316
|
rows.map((row) => row.mailboxId),
|
|
316
317
|
),
|
|
@@ -397,7 +398,7 @@ export class MailboxSpecialUseRepo implements IMailboxSpecialUseRepository {
|
|
|
397
398
|
.select()
|
|
398
399
|
.from(mailboxSpecialUseTable)
|
|
399
400
|
.where(
|
|
400
|
-
|
|
401
|
+
inList(
|
|
401
402
|
mailboxSpecialUseTable.mailboxId,
|
|
402
403
|
rows.map((row) => row.mailboxId),
|
|
403
404
|
),
|
package/src/repos/i4-mailbox.ts
CHANGED
|
@@ -44,6 +44,7 @@ import { messageTable } from "../schema/message-data.js";
|
|
|
44
44
|
import { syncWarningTable } from "../schema/sync-warning.js";
|
|
45
45
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
46
46
|
import type { SearchIndex } from "../search/thread-message-search.js";
|
|
47
|
+
import { inList } from "./in-list.js";
|
|
47
48
|
import { deleteMessageSubtree } from "./message.js";
|
|
48
49
|
|
|
49
50
|
const base36Translator = shortUuid.createTranslator(
|
|
@@ -207,7 +208,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
207
208
|
.where(
|
|
208
209
|
and(
|
|
209
210
|
eq(mailboxTable.accountId, accountId),
|
|
210
|
-
|
|
211
|
+
inList(mailboxTable.mailboxId, mailboxId),
|
|
211
212
|
),
|
|
212
213
|
);
|
|
213
214
|
return rows.map(rowToMailbox);
|
|
@@ -384,7 +385,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
384
385
|
.where(
|
|
385
386
|
and(
|
|
386
387
|
eq(syncWarningTable.accountId, accountId),
|
|
387
|
-
|
|
388
|
+
inList(syncWarningTable.mailboxId, mailboxIds),
|
|
388
389
|
),
|
|
389
390
|
),
|
|
390
391
|
this.db
|
|
@@ -392,7 +393,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
392
393
|
.where(
|
|
393
394
|
and(
|
|
394
395
|
eq(mailboxTable.accountId, accountId),
|
|
395
|
-
|
|
396
|
+
inList(mailboxTable.mailboxId, mailboxIds),
|
|
396
397
|
),
|
|
397
398
|
),
|
|
398
399
|
]);
|
|
@@ -551,7 +552,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
551
552
|
const listings = await this.db
|
|
552
553
|
.select({ threadMessageId: threadMessageTable.threadMessageId })
|
|
553
554
|
.from(threadMessageTable)
|
|
554
|
-
.where(
|
|
555
|
+
.where(inList(threadMessageTable.messageId, messageIds));
|
|
555
556
|
|
|
556
557
|
// The primitive the rest of the codebase deletes mail with: nine
|
|
557
558
|
// per-message child tables. A bespoke table list would orphan them.
|
|
@@ -559,7 +560,7 @@ export class MailboxRepo implements IMailboxRepository {
|
|
|
559
560
|
...deleteMessageSubtree(this.db, messageIds),
|
|
560
561
|
this.db
|
|
561
562
|
.delete(threadMessageTable)
|
|
562
|
-
.where(
|
|
563
|
+
.where(inList(threadMessageTable.messageId, messageIds)),
|
|
563
564
|
]);
|
|
564
565
|
await this.search.sync(listings.map((row) => row.threadMessageId));
|
|
565
566
|
}
|
|
@@ -6,11 +6,12 @@ import type {
|
|
|
6
6
|
ReserveOutboxAttachmentResult,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
8
|
import { holdsRoom } from "@remit/data-ports";
|
|
9
|
-
import { and, eq, gt, gte,
|
|
9
|
+
import { and, eq, gt, gte, lt, or, sum } from "drizzle-orm";
|
|
10
10
|
import { runBatch } from "../batch.js";
|
|
11
11
|
import type { Db } from "../db.js";
|
|
12
12
|
import { NotFoundError } from "../error.js";
|
|
13
13
|
import { outboxAttachmentTable } from "../schema/i4-outbox-attachment.js";
|
|
14
|
+
import { inList } from "./in-list.js";
|
|
14
15
|
|
|
15
16
|
type DB = Db<Record<string, unknown>>;
|
|
16
17
|
|
|
@@ -218,10 +219,7 @@ export class OutboxAttachmentRepo implements IOutboxAttachmentRepository {
|
|
|
218
219
|
.where(
|
|
219
220
|
and(
|
|
220
221
|
eq(outboxAttachmentTable.accountConfigId, accountConfigId),
|
|
221
|
-
|
|
222
|
-
outboxAttachmentTable.outboxAttachmentId,
|
|
223
|
-
outboxAttachmentIds,
|
|
224
|
-
),
|
|
222
|
+
inList(outboxAttachmentTable.outboxAttachmentId, outboxAttachmentIds),
|
|
225
223
|
),
|
|
226
224
|
);
|
|
227
225
|
}
|
|
@@ -5,11 +5,12 @@ import type {
|
|
|
5
5
|
ResultList,
|
|
6
6
|
UpdateOutboxMessageInput,
|
|
7
7
|
} from "@remit/data-ports";
|
|
8
|
-
import { and, desc, eq,
|
|
8
|
+
import { and, desc, eq, lt, or } from "drizzle-orm";
|
|
9
9
|
import type { Db } 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
|
+
import { inList } from "./in-list.js";
|
|
13
14
|
|
|
14
15
|
type DB = Db<Record<string, unknown>>;
|
|
15
16
|
|
|
@@ -99,7 +100,7 @@ export class OutboxMessageRepo implements IOutboxMessageRepository {
|
|
|
99
100
|
.where(
|
|
100
101
|
and(
|
|
101
102
|
eq(outboxMessageTable.accountConfigId, accountConfigId),
|
|
102
|
-
|
|
103
|
+
inList(outboxMessageTable.outboxMessageId, outboxMessageId),
|
|
103
104
|
),
|
|
104
105
|
);
|
|
105
106
|
return rows.map(rowToOutboxMessage);
|
|
@@ -264,7 +265,7 @@ export class OutboxMessageRepo implements IOutboxMessageRepository {
|
|
|
264
265
|
.where(
|
|
265
266
|
and(
|
|
266
267
|
eq(outboxMessageTable.accountConfigId, accountConfigId),
|
|
267
|
-
|
|
268
|
+
inList(outboxMessageTable.outboxMessageId, outboxMessageIds),
|
|
268
269
|
),
|
|
269
270
|
);
|
|
270
271
|
}
|
|
@@ -298,7 +299,7 @@ export class OutboxMessageRepo implements IOutboxMessageRepository {
|
|
|
298
299
|
.from(outboxMessageTable)
|
|
299
300
|
.where(
|
|
300
301
|
and(
|
|
301
|
-
|
|
302
|
+
inList(outboxMessageTable.accountId, accountIds),
|
|
302
303
|
after
|
|
303
304
|
? or(
|
|
304
305
|
lt(outboxMessageTable.createdAt, after.createdAt),
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { after, before, describe, test } from "node:test";
|
|
3
|
+
import { calendarTable } from "../schema.js";
|
|
4
|
+
import { createSqliteTestDb, type SqliteTestDb } from "../test-db-sqlite.js";
|
|
5
|
+
import { inList } from "./in-list.js";
|
|
6
|
+
|
|
7
|
+
const SCHEMA = { calendars: calendarTable };
|
|
8
|
+
|
|
9
|
+
const calendar = (calendarId: string): typeof calendarTable.$inferInsert => ({
|
|
10
|
+
calendarId,
|
|
11
|
+
accountConfigId: "account-config-in-list",
|
|
12
|
+
urlSegment: calendarId,
|
|
13
|
+
displayName: calendarId,
|
|
14
|
+
color: "Cal1",
|
|
15
|
+
componentSet: "VeventOnly",
|
|
16
|
+
source: "UserCreated",
|
|
17
|
+
timezone: "",
|
|
18
|
+
subscriptionUrl: "",
|
|
19
|
+
subscriptionEnabled: false,
|
|
20
|
+
syncSequence: 0,
|
|
21
|
+
createdAt: 0,
|
|
22
|
+
updatedAt: 0,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("inList on better-sqlite3", () => {
|
|
26
|
+
let db: SqliteTestDb<typeof SCHEMA>;
|
|
27
|
+
let close: () => Promise<void>;
|
|
28
|
+
const allIds = Array.from({ length: 150 }, (_, index) => `calendar-${index}`);
|
|
29
|
+
|
|
30
|
+
before(async () => {
|
|
31
|
+
({ db, close } = await createSqliteTestDb(SCHEMA));
|
|
32
|
+
await db.insert(calendarTable).values(allIds.map(calendar));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
after(() => close());
|
|
36
|
+
|
|
37
|
+
test("binds a single parameter for 150 ids", () => {
|
|
38
|
+
const query = db
|
|
39
|
+
.select({ calendarId: calendarTable.calendarId })
|
|
40
|
+
.from(calendarTable)
|
|
41
|
+
.where(inList(calendarTable.calendarId, allIds))
|
|
42
|
+
.toSQL();
|
|
43
|
+
assert.equal(query.params.length, 1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("matches only the listed ids", async () => {
|
|
47
|
+
const rows = await db
|
|
48
|
+
.select({ calendarId: calendarTable.calendarId })
|
|
49
|
+
.from(calendarTable)
|
|
50
|
+
.where(inList(calendarTable.calendarId, ["calendar-3", "missing"]));
|
|
51
|
+
assert.deepEqual(rows, [{ calendarId: "calendar-3" }]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("matches nothing for an empty list", async () => {
|
|
55
|
+
const rows = await db
|
|
56
|
+
.select({ calendarId: calendarTable.calendarId })
|
|
57
|
+
.from(calendarTable)
|
|
58
|
+
.where(inList(calendarTable.calendarId, []));
|
|
59
|
+
assert.deepEqual(rows, []);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Column, type SQL, sql } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
export const inList = <T extends Column>(
|
|
4
|
+
column: T,
|
|
5
|
+
values: readonly T["_"]["data"][],
|
|
6
|
+
): SQL =>
|
|
7
|
+
sql`${column} in (select value from json_each(${JSON.stringify(values)}))`;
|
|
8
|
+
|
|
9
|
+
export const pairInList = <A extends Column, B extends Column>(
|
|
10
|
+
first: A,
|
|
11
|
+
second: B,
|
|
12
|
+
pairs: readonly (readonly [A["_"]["data"], B["_"]["data"]])[],
|
|
13
|
+
): SQL =>
|
|
14
|
+
sql`(${first}, ${second}) in (select value->>0, value->>1 from json_each(${JSON.stringify(pairs)}))`;
|
|
@@ -4,13 +4,14 @@ import type {
|
|
|
4
4
|
IMessageFlagRepository,
|
|
5
5
|
MessageFlagItem,
|
|
6
6
|
} from "@remit/data-ports";
|
|
7
|
-
import { and, eq
|
|
7
|
+
import { and, eq } from "drizzle-orm";
|
|
8
8
|
import type { Db } from "../db.js";
|
|
9
9
|
import { NotFoundError } from "../error.js";
|
|
10
10
|
import {
|
|
11
11
|
type MessageDataSchema,
|
|
12
12
|
messageFlagTable,
|
|
13
13
|
} from "../schema/message-data.js";
|
|
14
|
+
import { inList } from "./in-list.js";
|
|
14
15
|
|
|
15
16
|
type DB = Db<MessageDataSchema>;
|
|
16
17
|
|
|
@@ -58,7 +59,7 @@ export class DrizzleMessageFlagRepository implements IMessageFlagRepository {
|
|
|
58
59
|
const rows = await this.db
|
|
59
60
|
.select()
|
|
60
61
|
.from(messageFlagTable)
|
|
61
|
-
.where(
|
|
62
|
+
.where(inList(messageFlagTable.messageFlagId, idOrIds));
|
|
62
63
|
return rows.map(rowToMessageFlag);
|
|
63
64
|
}
|
|
64
65
|
const [row] = await this.db
|
|
@@ -79,7 +80,7 @@ export class DrizzleMessageFlagRepository implements IMessageFlagRepository {
|
|
|
79
80
|
if (messageFlagIds.length === 0) return;
|
|
80
81
|
await this.db
|
|
81
82
|
.delete(messageFlagTable)
|
|
82
|
-
.where(
|
|
83
|
+
.where(inList(messageFlagTable.messageFlagId, messageFlagIds));
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
async getFlags(messageId: string): Promise<MessageFlagItem[]> {
|
|
@@ -155,7 +156,7 @@ export class DrizzleMessageFlagRepository implements IMessageFlagRepository {
|
|
|
155
156
|
.where(
|
|
156
157
|
and(
|
|
157
158
|
eq(messageFlagTable.messageId, messageId),
|
|
158
|
-
|
|
159
|
+
inList(messageFlagTable.flagName, flagNames),
|
|
159
160
|
),
|
|
160
161
|
);
|
|
161
162
|
}
|
|
@@ -3,10 +3,11 @@ import type {
|
|
|
3
3
|
IMessageLabelRepository,
|
|
4
4
|
MessageLabelItem,
|
|
5
5
|
} from "@remit/data-ports";
|
|
6
|
-
import { and, desc, eq
|
|
6
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
7
7
|
import type { Db } from "../db.js";
|
|
8
8
|
import { deterministicBase36Id } from "../id.js";
|
|
9
9
|
import { messageLabelTable } from "../schema.js";
|
|
10
|
+
import { inList } from "./in-list.js";
|
|
10
11
|
|
|
11
12
|
type DB = Db<Record<string, unknown>>;
|
|
12
13
|
|
|
@@ -82,7 +83,7 @@ export class MessageLabelRepo implements IMessageLabelRepository {
|
|
|
82
83
|
const rows = await this.db
|
|
83
84
|
.select()
|
|
84
85
|
.from(messageLabelTable)
|
|
85
|
-
.where(
|
|
86
|
+
.where(inList(messageLabelTable.messageId, messageIds));
|
|
86
87
|
return rows.map(rowToMessageLabel);
|
|
87
88
|
}
|
|
88
89
|
|
package/src/repos/message.ts
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from "../schema/message-data.js";
|
|
46
46
|
import { threadMessageTable } from "../schema/thread-message.js";
|
|
47
47
|
import type { SearchIndex } from "../search/thread-message-search.js";
|
|
48
|
+
import { inList } from "./in-list.js";
|
|
48
49
|
import {
|
|
49
50
|
toBodyPartItem,
|
|
50
51
|
toBodyPartParameterItem,
|
|
@@ -129,36 +130,36 @@ export function deleteMessageSubtree(
|
|
|
129
130
|
return [
|
|
130
131
|
db
|
|
131
132
|
.delete(messageFlagTable)
|
|
132
|
-
.where(and(
|
|
133
|
+
.where(and(inList(messageFlagTable.messageId, messageIds), guard)),
|
|
133
134
|
db
|
|
134
135
|
.delete(messageReferenceTable)
|
|
135
|
-
.where(and(
|
|
136
|
+
.where(and(inList(messageReferenceTable.messageId, messageIds), guard)),
|
|
136
137
|
db
|
|
137
138
|
.delete(envelopeAddressTable)
|
|
138
|
-
.where(and(
|
|
139
|
+
.where(and(inList(envelopeAddressTable.messageId, messageIds), guard)),
|
|
139
140
|
db
|
|
140
141
|
.delete(bodyPartParameterTable)
|
|
141
|
-
.where(and(
|
|
142
|
+
.where(and(inList(bodyPartParameterTable.messageId, messageIds), guard)),
|
|
142
143
|
db
|
|
143
144
|
.delete(bodyPartStorageTable)
|
|
144
|
-
.where(and(
|
|
145
|
+
.where(and(inList(bodyPartStorageTable.messageId, messageIds), guard)),
|
|
145
146
|
db
|
|
146
147
|
.delete(rawMessageStorageTable)
|
|
147
|
-
.where(and(
|
|
148
|
+
.where(and(inList(rawMessageStorageTable.messageId, messageIds), guard)),
|
|
148
149
|
db
|
|
149
150
|
.delete(bodyPartTable)
|
|
150
|
-
.where(and(
|
|
151
|
+
.where(and(inList(bodyPartTable.messageId, messageIds), guard)),
|
|
151
152
|
db
|
|
152
153
|
.delete(bodyStructureRefetchTable)
|
|
153
154
|
.where(
|
|
154
|
-
and(
|
|
155
|
+
and(inList(bodyStructureRefetchTable.messageId, messageIds), guard),
|
|
155
156
|
),
|
|
156
157
|
db
|
|
157
158
|
.delete(envelopeTable)
|
|
158
|
-
.where(and(
|
|
159
|
+
.where(and(inList(envelopeTable.messageId, messageIds), guard)),
|
|
159
160
|
db
|
|
160
161
|
.delete(messageTable)
|
|
161
|
-
.where(and(
|
|
162
|
+
.where(and(inList(messageTable.messageId, messageIds), guard))
|
|
162
163
|
.returning({ messageId: messageTable.messageId }),
|
|
163
164
|
];
|
|
164
165
|
}
|
|
@@ -275,7 +276,7 @@ export class DrizzleMessageRepository implements IMessageRepository {
|
|
|
275
276
|
const rows = await this.db
|
|
276
277
|
.select()
|
|
277
278
|
.from(messageTable)
|
|
278
|
-
.where(
|
|
279
|
+
.where(inList(messageTable.messageId, messageId));
|
|
279
280
|
return rows.map(toMessageItem);
|
|
280
281
|
}
|
|
281
282
|
|
|
@@ -547,18 +548,18 @@ export class DrizzleMessageRepository implements IMessageRepository {
|
|
|
547
548
|
or(
|
|
548
549
|
and(
|
|
549
550
|
eq(messageTable.status, "moving"),
|
|
550
|
-
|
|
551
|
+
inList(messageTable.originalMailboxId, ids),
|
|
551
552
|
isNotNull(messageTable.originalUid),
|
|
552
553
|
),
|
|
553
554
|
and(
|
|
554
555
|
eq(messageTable.status, "deleting"),
|
|
555
|
-
|
|
556
|
+
inList(messageTable.mailboxId, ids),
|
|
556
557
|
),
|
|
557
558
|
and(
|
|
558
559
|
eq(messageTable.status, "moving"),
|
|
559
560
|
eq(messageTable.uid, 0),
|
|
560
561
|
isNull(messageTable.originalUid),
|
|
561
|
-
|
|
562
|
+
inList(messageTable.mailboxId, ids),
|
|
562
563
|
),
|
|
563
564
|
),
|
|
564
565
|
),
|
|
@@ -5,9 +5,10 @@ import type {
|
|
|
5
5
|
SyncWarningKey,
|
|
6
6
|
} from "@remit/data-ports";
|
|
7
7
|
import { deriveSyncWarningId } from "@remit/data-ports/id";
|
|
8
|
-
import { and, count, desc, eq, gte,
|
|
8
|
+
import { and, count, desc, eq, gte, sql } from "drizzle-orm";
|
|
9
9
|
import type { Db } from "../db.js";
|
|
10
10
|
import { syncWarningTable } from "../schema/sync-warning.js";
|
|
11
|
+
import { inList } from "./in-list.js";
|
|
11
12
|
|
|
12
13
|
type DB = Db<Record<string, unknown>>;
|
|
13
14
|
|
|
@@ -71,6 +72,6 @@ export class SyncWarningRepo implements ISyncWarningRepository {
|
|
|
71
72
|
if (syncWarningIds.length === 0) return;
|
|
72
73
|
await this.db
|
|
73
74
|
.delete(syncWarningTable)
|
|
74
|
-
.where(
|
|
75
|
+
.where(inList(syncWarningTable.syncWarningId, syncWarningIds));
|
|
75
76
|
};
|
|
76
77
|
}
|
|
@@ -34,6 +34,7 @@ import type {
|
|
|
34
34
|
SearchIndex,
|
|
35
35
|
SearchPosition,
|
|
36
36
|
} from "../search/thread-message-search.js";
|
|
37
|
+
import { inList } from "./in-list.js";
|
|
37
38
|
import {
|
|
38
39
|
bodyMatch,
|
|
39
40
|
fromMatch,
|
|
@@ -579,7 +580,7 @@ export class DrizzleThreadMessageRepository
|
|
|
579
580
|
.where(
|
|
580
581
|
and(
|
|
581
582
|
eq(threadMessageTable.accountConfigId, accountConfigId),
|
|
582
|
-
|
|
583
|
+
inList(threadMessageTable.threadMessageId, threadMessageId),
|
|
583
584
|
),
|
|
584
585
|
);
|
|
585
586
|
return rows.map(toItem);
|
|
@@ -678,7 +679,7 @@ export class DrizzleThreadMessageRepository
|
|
|
678
679
|
.where(
|
|
679
680
|
and(
|
|
680
681
|
eq(threadMessageTable.accountConfigId, accountConfigId),
|
|
681
|
-
|
|
682
|
+
inList(threadMessageTable.threadMessageId, ids),
|
|
682
683
|
),
|
|
683
684
|
);
|
|
684
685
|
await this.search.sync(ids);
|