@jcbuisson/express-x 3.0.3 → 3.0.4

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.
@@ -0,0 +1,127 @@
1
+ import { test, describe, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { computeSyncResult } from '#root/src/drizzle-plugins.mjs'
5
+
6
+ const T0 = new Date('2026-01-01T00:00:00Z')
7
+ const T1 = new Date('2026-01-02T00:00:00Z')
8
+ const T2 = new Date('2026-01-03T00:00:00Z')
9
+
10
+ // ─── Dialog helpers ────────────────────────────────────────────────────────────
11
+ // Lightweight simulations of server (drizzle-plugins.mjs) and client (client.mts)
12
+ // that run the sync protocol using plain objects instead of Dexie / PostgreSQL.
13
+
14
+ function matchesWhere(value, where) {
15
+ return Object.entries(where).every(([k, v]) => value[k] === v)
16
+ }
17
+
18
+ describe('computeSyncResult', () => {
19
+
20
+ test('both empty → all arrays empty', () => {
21
+ const result = computeSyncResult({}, {}, {})
22
+ assert.deepEqual(result.addClient, [])
23
+ assert.deepEqual(result.updateClient, [])
24
+ assert.deepEqual(result.deleteClient, [])
25
+ assert.deepEqual(result.addDatabase, [])
26
+ assert.deepEqual(result.updateDatabase, [])
27
+ assert.deepEqual(result.deleteDatabase, [])
28
+ })
29
+
30
+ test('record only in DB → sent to client (addClient)', () => {
31
+ const value = { uid: 'a', label: 'Vacances' }
32
+ const meta = { uid: 'a', created_at: T0 }
33
+ const result = computeSyncResult({ a: value }, {}, { a: meta })
34
+ assert.equal(result.addClient.length, 1)
35
+ assert.deepEqual(result.addClient[0], [value, meta])
36
+ assert.deepEqual(result.addDatabase, [])
37
+ })
38
+
39
+ test('record only on client, not deleted → sent to database (addDatabase)', () => {
40
+ const clientMeta = { uid: 'b', created_at: T0 }
41
+ const result = computeSyncResult({}, { b: clientMeta }, {})
42
+ assert.deepEqual(result.addDatabase, [clientMeta])
43
+ assert.deepEqual(result.addClient, [])
44
+ assert.deepEqual(result.deleteClient, [])
45
+ })
46
+
47
+ test('record only on client, deleted → ignored on both sides (deleteClient)', () => {
48
+ const clientMeta = { uid: 'c', created_at: T0, deleted_at: T1 }
49
+ const result = computeSyncResult({}, { c: clientMeta }, {})
50
+ assert.deepEqual(result.deleteClient, [['c', T1]])
51
+ assert.deepEqual(result.addDatabase, [])
52
+ })
53
+
54
+ test('record in both, client newer → update database (updateDatabase)', () => {
55
+ const value = { uid: 'd', label: 'old' }
56
+ const dbMeta = { uid: 'd', created_at: T0, updated_at: T1 }
57
+ const clientMeta = { uid: 'd', created_at: T0, updated_at: T2 }
58
+ const result = computeSyncResult({ d: value }, { d: clientMeta }, { d: dbMeta })
59
+ assert.deepEqual(result.updateDatabase, [clientMeta])
60
+ assert.deepEqual(result.updateClient, [])
61
+ })
62
+
63
+ test('record in both, DB newer → update client (updateClient)', () => {
64
+ const value = { uid: 'e', label: 'new' }
65
+ const dbMeta = { uid: 'e', created_at: T0, updated_at: T2 }
66
+ const clientMeta = { uid: 'e', created_at: T0, updated_at: T1 }
67
+ const result = computeSyncResult({ e: value }, { e: clientMeta }, { e: dbMeta })
68
+ assert.deepEqual(result.updateClient, [[value, dbMeta]])
69
+ assert.deepEqual(result.updateDatabase, [])
70
+ })
71
+
72
+ test('sub-day timestamp matches its day-truncated DB counterpart → no action', () => {
73
+ // The DB stores TIMESTAMP. Before this fix it stored DATE (day precision), which
74
+ // caused new Date('2026-01-02T06:00:00Z') - new Date('2026-01-02') > 0, triggering
75
+ // a spurious updateDatabase on every sync after the initial addDatabase push.
76
+ const value = { uid: 'p', label: 'precision' }
77
+ const dbMeta = { uid: 'p', created_at: '2026-01-02T06:00:00.000Z' } // TIMESTAMP from server
78
+ const clientMeta = { uid: 'p', created_at: new Date('2026-01-02T06:00:00.000Z') } // full timestamp on client
79
+ const result = computeSyncResult({ p: value }, { p: clientMeta }, { p: dbMeta })
80
+ assert.deepEqual(result.updateDatabase, [], 'identical timestamps must not trigger spurious updateDatabase')
81
+ assert.deepEqual(result.updateClient, [])
82
+ })
83
+
84
+ test('record in both, same timestamp → no action', () => {
85
+ const value = { uid: 'f', label: 'same' }
86
+ const dbMeta = { uid: 'f', created_at: T0, updated_at: T1 }
87
+ const clientMeta = { uid: 'f', created_at: T0, updated_at: T1 }
88
+ const result = computeSyncResult({ f: value }, { f: clientMeta }, { f: dbMeta })
89
+ assert.deepEqual(result.updateClient, [])
90
+ assert.deepEqual(result.updateDatabase, [])
91
+ })
92
+
93
+ test('record in both, client deleted → delete on DB and notify client', () => {
94
+ const value = { uid: 'g', label: 'bye' }
95
+ const dbMeta = { uid: 'g', created_at: T0 }
96
+ const clientMeta = { uid: 'g', created_at: T0, deleted_at: T1 }
97
+ const result = computeSyncResult({ g: value }, { g: clientMeta }, { g: dbMeta })
98
+ assert.deepEqual(result.deleteDatabase, ['g'])
99
+ assert.deepEqual(result.deleteClient, [['g', T1]])
100
+ })
101
+
102
+ test('mixed scenario: one of each case', () => {
103
+ const dbOnly = { uid: 'db', label: 'db-only' }
104
+ const dbOnlyMeta = { uid: 'db', created_at: T0 }
105
+
106
+ const clientNewMeta = { uid: 'cn', created_at: T1 }
107
+
108
+ const sharedValue = { uid: 'sh', label: 'shared' }
109
+ const sharedDbMeta = { uid: 'sh', created_at: T0, updated_at: T1 }
110
+ const sharedClientMeta = { uid: 'sh', created_at: T0, updated_at: T2 }
111
+
112
+ const result = computeSyncResult(
113
+ { db: dbOnly, sh: sharedValue },
114
+ { cn: clientNewMeta, sh: sharedClientMeta },
115
+ { db: dbOnlyMeta, sh: sharedDbMeta },
116
+ )
117
+
118
+ assert.equal(result.addClient.length, 1)
119
+ assert.deepEqual(result.addClient[0], [dbOnly, dbOnlyMeta])
120
+ assert.deepEqual(result.addDatabase, [clientNewMeta])
121
+ assert.deepEqual(result.updateDatabase, [sharedClientMeta])
122
+ assert.deepEqual(result.updateClient, [])
123
+ assert.deepEqual(result.deleteClient, [])
124
+ assert.deepEqual(result.deleteDatabase, [])
125
+ })
126
+
127
+ })