@remit/drizzle-service 0.0.58 → 0.0.60
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/id.test.ts +69 -0
- package/src/repos/i4-address.test.ts +26 -20
- package/src/repos/i4-address.ts +9 -10
- package/src/repos/thread-message.test.ts +10 -0
package/package.json
CHANGED
package/src/id.test.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
bodyPartContentId,
|
|
5
|
+
bodyPartId,
|
|
6
|
+
bodyPartParameterId,
|
|
7
|
+
deterministicBase36Id,
|
|
8
|
+
envelopeAddressId,
|
|
9
|
+
envelopeId,
|
|
10
|
+
generateDeterministicId,
|
|
11
|
+
rootBodyPartId,
|
|
12
|
+
} from "./id.js";
|
|
13
|
+
|
|
14
|
+
const MESSAGE = "message-golden";
|
|
15
|
+
|
|
16
|
+
describe("derived ids are stored primary keys: a changed value orphans every row already written and needs a migration, never a new expectation here", () => {
|
|
17
|
+
test("generateDeterministicId pins the namespace and the UUIDv5 encoding", () => {
|
|
18
|
+
assert.equal(
|
|
19
|
+
generateDeterministicId("golden-seed"),
|
|
20
|
+
"68dd8eea-ad03-5221-b37c-52bbf1772c30",
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("deterministicBase36Id pins the base36 encoding shared with the electrodb adapter", () => {
|
|
25
|
+
assert.equal(
|
|
26
|
+
deterministicBase36Id("golden-seed"),
|
|
27
|
+
"67hxxs95ofdk5frbprqyrgwmo",
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("bodyPartId pins the body_part primary key", () => {
|
|
32
|
+
assert.equal(
|
|
33
|
+
bodyPartId(MESSAGE, "1.2"),
|
|
34
|
+
"022d58cc-585c-5391-8106-f2d2c1c0b228",
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("rootBodyPartId pins the root MIME node's key, part path 0", () => {
|
|
39
|
+
assert.equal(
|
|
40
|
+
rootBodyPartId(MESSAGE),
|
|
41
|
+
"f15cb8cc-8e03-5d68-812a-70bac87e2261",
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("bodyPartParameterId pins the body_part_parameter primary key", () => {
|
|
46
|
+
assert.equal(
|
|
47
|
+
bodyPartParameterId(MESSAGE, "1.2", "charset"),
|
|
48
|
+
"fdac41cc-7cbf-5bf7-bfb3-48f66e2e7f0c",
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("envelopeId pins the envelope primary key", () => {
|
|
53
|
+
assert.equal(envelopeId(MESSAGE), "fdfd34a1-84fb-535f-a586-965338211e99");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("envelopeAddressId pins the envelope_address primary key", () => {
|
|
57
|
+
assert.equal(
|
|
58
|
+
envelopeAddressId(MESSAGE, "to", 1),
|
|
59
|
+
"5f4e930e-e418-51a2-9402-657822f8688b",
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("bodyPartContentId pins the body_part_content primary key", () => {
|
|
64
|
+
assert.equal(
|
|
65
|
+
bodyPartContentId(MESSAGE, "bodypart-golden"),
|
|
66
|
+
"c0ee5f7d-1894-5957-9f65-d9aafdf306ab",
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { after, before, describe, test } from "node:test";
|
|
4
|
-
import { envelopeAddressId } from "../id.js";
|
|
5
4
|
import { createTestDb, randomId, type TestDb } from "../test-db.js";
|
|
6
5
|
import { AddressRepo } from "./i4-address.js";
|
|
7
6
|
|
|
@@ -140,7 +139,6 @@ describe("AddressRepo", () => {
|
|
|
140
139
|
test("createEnvelopeAddress and getEnvelopeAddress", async () => {
|
|
141
140
|
const messageId = randomUUID();
|
|
142
141
|
const addressId = randomUUID();
|
|
143
|
-
const envId = envelopeAddressId(messageId, "from", 0);
|
|
144
142
|
|
|
145
143
|
const addr = await repo.createAddress({
|
|
146
144
|
...makeAddressInput(randomId()),
|
|
@@ -148,7 +146,6 @@ describe("AddressRepo", () => {
|
|
|
148
146
|
});
|
|
149
147
|
|
|
150
148
|
const ea = await repo.createEnvelopeAddress({
|
|
151
|
-
envelopeAddressId: envId,
|
|
152
149
|
messageId,
|
|
153
150
|
addressId,
|
|
154
151
|
normalizedEmail: "test@example.com",
|
|
@@ -156,21 +153,20 @@ describe("AddressRepo", () => {
|
|
|
156
153
|
addressOrder: 0,
|
|
157
154
|
});
|
|
158
155
|
|
|
159
|
-
assert.equal(ea.envelopeAddressId, envId);
|
|
160
156
|
assert.equal(ea.messageId, messageId);
|
|
161
157
|
assert.equal(ea.addressRole, "from");
|
|
162
158
|
|
|
163
|
-
const fetched = await repo.getEnvelopeAddress(
|
|
164
|
-
assert.equal(fetched.envelopeAddressId,
|
|
159
|
+
const fetched = await repo.getEnvelopeAddress(ea.envelopeAddressId);
|
|
160
|
+
assert.equal(fetched.envelopeAddressId, ea.envelopeAddressId);
|
|
161
|
+
assert.equal(fetched.addressId, addressId);
|
|
165
162
|
|
|
166
|
-
await repo.deleteEnvelopeAddress(
|
|
163
|
+
await repo.deleteEnvelopeAddress(ea.envelopeAddressId);
|
|
167
164
|
await repo.deleteAddress(addr.accountConfigId, addr.addressId);
|
|
168
165
|
});
|
|
169
166
|
|
|
170
|
-
test("upsertEnvelopeAddress
|
|
167
|
+
test("upsertEnvelopeAddress keys the row on messageId, role and order", async () => {
|
|
171
168
|
const messageId = randomUUID();
|
|
172
169
|
const input = {
|
|
173
|
-
envelopeAddressId: envelopeAddressId(messageId, "to", 1),
|
|
174
170
|
messageId,
|
|
175
171
|
addressId: randomUUID(),
|
|
176
172
|
normalizedEmail: "x@example.com",
|
|
@@ -178,16 +174,27 @@ describe("AddressRepo", () => {
|
|
|
178
174
|
addressOrder: 1,
|
|
179
175
|
};
|
|
180
176
|
const first = await repo.upsertEnvelopeAddress(input);
|
|
181
|
-
const second = await repo.upsertEnvelopeAddress(
|
|
182
|
-
|
|
177
|
+
const second = await repo.upsertEnvelopeAddress({
|
|
178
|
+
...input,
|
|
179
|
+
addressId: randomUUID(),
|
|
180
|
+
normalizedEmail: "y@example.com",
|
|
181
|
+
});
|
|
182
|
+
assert.equal(second.envelopeAddressId, first.envelopeAddressId);
|
|
183
|
+
assert.equal(second.normalizedEmail, "x@example.com");
|
|
184
|
+
|
|
185
|
+
const reordered = await repo.upsertEnvelopeAddress({
|
|
186
|
+
...input,
|
|
187
|
+
addressOrder: 2,
|
|
188
|
+
});
|
|
189
|
+
assert.notEqual(reordered.envelopeAddressId, first.envelopeAddressId);
|
|
183
190
|
|
|
184
|
-
await repo.deleteEnvelopeAddress(
|
|
191
|
+
await repo.deleteEnvelopeAddress(first.envelopeAddressId);
|
|
192
|
+
await repo.deleteEnvelopeAddress(reordered.envelopeAddressId);
|
|
185
193
|
});
|
|
186
194
|
|
|
187
195
|
test("deleteManyEnvelopeAddresses removes in batch", async () => {
|
|
188
196
|
const messageId = randomUUID();
|
|
189
197
|
const ea1 = {
|
|
190
|
-
envelopeAddressId: envelopeAddressId(messageId, "from", 0),
|
|
191
198
|
messageId,
|
|
192
199
|
addressId: randomUUID(),
|
|
193
200
|
normalizedEmail: "a@x.com",
|
|
@@ -196,22 +203,21 @@ describe("AddressRepo", () => {
|
|
|
196
203
|
};
|
|
197
204
|
const ea2 = {
|
|
198
205
|
...ea1,
|
|
199
|
-
envelopeAddressId: envelopeAddressId(messageId, "to", 1),
|
|
200
206
|
addressRole: "to" as const,
|
|
201
207
|
addressOrder: 1,
|
|
202
208
|
};
|
|
203
209
|
|
|
204
|
-
await repo.createEnvelopeAddress(ea1);
|
|
205
|
-
await repo.createEnvelopeAddress(ea2);
|
|
210
|
+
const created1 = await repo.createEnvelopeAddress(ea1);
|
|
211
|
+
const created2 = await repo.createEnvelopeAddress(ea2);
|
|
206
212
|
|
|
207
213
|
await repo.deleteManyEnvelopeAddresses([
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
created1.envelopeAddressId,
|
|
215
|
+
created2.envelopeAddressId,
|
|
210
216
|
]);
|
|
211
217
|
|
|
212
218
|
const results = await repo.getEnvelopeAddress([
|
|
213
|
-
|
|
214
|
-
|
|
219
|
+
created1.envelopeAddressId,
|
|
220
|
+
created2.envelopeAddressId,
|
|
215
221
|
]);
|
|
216
222
|
assert.equal(results.length, 0);
|
|
217
223
|
});
|
package/src/repos/i4-address.ts
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "drizzle-orm";
|
|
24
24
|
import type { Db } from "../db.js";
|
|
25
25
|
import { NotFoundError } from "../error.js";
|
|
26
|
-
import { envelopeAddressId
|
|
26
|
+
import { envelopeAddressId } from "../id.js";
|
|
27
27
|
import { decodeToken, resultList } from "../pagination.js";
|
|
28
28
|
import {
|
|
29
29
|
JUNK_ONLY_FLAG,
|
|
@@ -744,15 +744,14 @@ export class AddressRepo implements IAddressRepository {
|
|
|
744
744
|
input: CreateEnvelopeAddressInput,
|
|
745
745
|
): Promise<EnvelopeAddressItem> {
|
|
746
746
|
const now = Date.now();
|
|
747
|
-
const envelopeAddressId = deriveEnvelopeAddressId(
|
|
748
|
-
input.messageId,
|
|
749
|
-
input.addressRole,
|
|
750
|
-
input.addressOrder,
|
|
751
|
-
);
|
|
752
747
|
const [row] = await this.db
|
|
753
748
|
.insert(envelopeAddressTable)
|
|
754
749
|
.values({
|
|
755
|
-
envelopeAddressId
|
|
750
|
+
envelopeAddressId: envelopeAddressId(
|
|
751
|
+
input.messageId,
|
|
752
|
+
input.addressRole,
|
|
753
|
+
input.addressOrder,
|
|
754
|
+
),
|
|
756
755
|
messageId: input.messageId,
|
|
757
756
|
addressId: input.addressId,
|
|
758
757
|
displayName: input.displayName,
|
|
@@ -770,7 +769,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
770
769
|
input: CreateEnvelopeAddressInput,
|
|
771
770
|
): Promise<EnvelopeAddressItem> {
|
|
772
771
|
const now = Date.now();
|
|
773
|
-
const
|
|
772
|
+
const rowId = envelopeAddressId(
|
|
774
773
|
input.messageId,
|
|
775
774
|
input.addressRole,
|
|
776
775
|
input.addressOrder,
|
|
@@ -778,7 +777,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
778
777
|
const [row] = await this.db
|
|
779
778
|
.insert(envelopeAddressTable)
|
|
780
779
|
.values({
|
|
781
|
-
envelopeAddressId,
|
|
780
|
+
envelopeAddressId: rowId,
|
|
782
781
|
messageId: input.messageId,
|
|
783
782
|
addressId: input.addressId,
|
|
784
783
|
displayName: input.displayName,
|
|
@@ -791,7 +790,7 @@ export class AddressRepo implements IAddressRepository {
|
|
|
791
790
|
.onConflictDoNothing()
|
|
792
791
|
.returning();
|
|
793
792
|
if (!row) {
|
|
794
|
-
return this.getEnvelopeAddress(
|
|
793
|
+
return this.getEnvelopeAddress(rowId);
|
|
795
794
|
}
|
|
796
795
|
return rowToEnvelopeAddress(row);
|
|
797
796
|
}
|
|
@@ -7,6 +7,7 @@ import { createSqliteTestDb } from "../test-db-sqlite.js";
|
|
|
7
7
|
import {
|
|
8
8
|
clampThreadSearchLimit,
|
|
9
9
|
DrizzleThreadMessageRepository,
|
|
10
|
+
deriveThreadMessageId,
|
|
10
11
|
THREAD_SEARCH_MAX_LIMIT,
|
|
11
12
|
} from "./thread-message.js";
|
|
12
13
|
|
|
@@ -936,3 +937,12 @@ describe("DrizzleThreadMessageRepository — core CRUD", () => {
|
|
|
936
937
|
assert.equal(await repo.countByThread(other, threadId), 0);
|
|
937
938
|
});
|
|
938
939
|
});
|
|
940
|
+
|
|
941
|
+
describe("derived ids are stored primary keys: a changed value orphans every row already written and needs a migration, never a new expectation here", () => {
|
|
942
|
+
test("deriveThreadMessageId pins the thread_message primary key", () => {
|
|
943
|
+
assert.equal(
|
|
944
|
+
deriveThreadMessageId("thread-golden", "message-golden"),
|
|
945
|
+
"agmlamuvd9feee9fmfvqxrb35",
|
|
946
|
+
);
|
|
947
|
+
});
|
|
948
|
+
});
|