@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/drizzle-service",
3
- "version": "0.0.58",
3
+ "version": "0.0.60",
4
4
  "description": "Drizzle ORM service over SQLite",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
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(envId);
164
- assert.equal(fetched.envelopeAddressId, envId);
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(envId);
163
+ await repo.deleteEnvelopeAddress(ea.envelopeAddressId);
167
164
  await repo.deleteAddress(addr.accountConfigId, addr.addressId);
168
165
  });
169
166
 
170
- test("upsertEnvelopeAddress is idempotent", async () => {
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(input);
182
- assert.equal(first.envelopeAddressId, second.envelopeAddressId);
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(input.envelopeAddressId);
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
- ea1.envelopeAddressId,
209
- ea2.envelopeAddressId,
214
+ created1.envelopeAddressId,
215
+ created2.envelopeAddressId,
210
216
  ]);
211
217
 
212
218
  const results = await repo.getEnvelopeAddress([
213
- ea1.envelopeAddressId,
214
- ea2.envelopeAddressId,
219
+ created1.envelopeAddressId,
220
+ created2.envelopeAddressId,
215
221
  ]);
216
222
  assert.equal(results.length, 0);
217
223
  });
@@ -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 as deriveEnvelopeAddressId } from "../id.js";
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 envelopeAddressId = deriveEnvelopeAddressId(
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(envelopeAddressId);
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
+ });