📄 src/models/test/localRecordTable.test.ts
D-OPEN SOVEREIGN
1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15import 'fake-indexeddb/auto';
16import { describe, it, expect, beforeEach, afterEach } from 'vitest';
17import { localRecordTable, type LocalRecordEntry } from '../localRecordTable.ts';
18import { configureDb, clear } from '../db.ts';
19import { Db } from '../indexdb/common.ts';
20
21describe('LocalRecordTable', () => {
22 beforeEach(async () => {
23 clear();
24 await configureDb({ cacheLimit: 2 });
25 const db = await Db();
26 localRecordTable.init(db);
27
28 await new Promise<void>((resolve) => {
29 const tx = db.transaction(['localRecords', 'instanceRemaps'], 'readwrite');
30 tx.objectStore('localRecords').clear();
31 tx.objectStore('instanceRemaps').clear();
32 tx.oncomplete = () => resolve();
33 });
34 });
35
36 const createMockEntry = (wireId: number, status: LocalRecordEntry['status'] = 'active'): LocalRecordEntry => ({
37 wireId,
38 creatorUsername: 'test_user',
39 objectType: 1,
40 localId: wireId & 0x7FFFFFFF,
41 createdAt: Date.now(),
42 status
43 });
44
45 it('put and get correctly retrieve entries', async () => {
46 const entry = createMockEntry(12345);
47 await localRecordTable.put(entry);
48
49 const retrieved = await localRecordTable.get('test_user', 12345);
50 expect(retrieved).toBeDefined();
51 expect(retrieved?.wireId).toBe(12345);
52 expect(retrieved?.status).toBe('active');
53 });
54
55 it('putIfAbsent inserts if missing, skips if present', async () => {
56 const entry1 = createMockEntry(1);
57 await localRecordTable.putIfAbsent(entry1);
58
59 const entry2 = createMockEntry(1, 'submitted');
60 await localRecordTable.putIfAbsent(entry2);
61
62 const retrieved = await localRecordTable.get('test_user', 1);
63 expect(retrieved?.status).toBe('active'); // Should not have updated to 'submitted'
64 });
65
66 it('getByCreator retrieves all entries for a specific user', async () => {
67 await localRecordTable.put(createMockEntry(10));
68 await localRecordTable.put(createMockEntry(11));
69 await localRecordTable.put({ ...createMockEntry(12), creatorUsername: 'other_user' });
70
71 const myRecords = await localRecordTable.getByCreator('test_user');
72 expect(myRecords.length).toBe(2);
73 const wireIds = myRecords.map(r => r.wireId).sort();
74 expect(wireIds).toEqual([10, 11]);
75 });
76
77 it('setStatus updates the status of an existing entry', async () => {
78 await localRecordTable.put(createMockEntry(50));
79 await localRecordTable.setStatus('test_user', 50, 'community_pending');
80
81 const retrieved = await localRecordTable.get('test_user', 50);
82 expect(retrieved?.status).toBe('community_pending');
83 });
84
85 it('setStatus throws if entry not found', async () => {
86 await expect(localRecordTable.setStatus('test_user', 999, 'canonical'))
87 .rejects.toThrow(/not found/);
88 });
89
90 it('setCanonicalId updates canonical mapping', async () => {
91 await localRecordTable.put(createMockEntry(100));
92 await localRecordTable.setCanonicalId('test_user', 100, 200);
93
94 const retrieved = await localRecordTable.get('test_user', 100);
95 expect(retrieved?.canonicalId).toBe(200);
96 });
97
98 it('setCanonicalId throws if entry not found', async () => {
99 await expect(localRecordTable.setCanonicalId('test_user', 999, 200))
100 .rejects.toThrow(/not found/);
101 });
102});
103
104describe('IDBInstanceRemapStore', () => {
105 beforeEach(async () => {
106 clear();
107 await configureDb({ cacheLimit: 2 });
108 const db = await Db();
109 localRecordTable.init(db);
110
111 await new Promise<void>((resolve) => {
112 const tx = db.transaction(['localRecords', 'instanceRemaps'], 'readwrite');
113 tx.objectStore('localRecords').clear();
114 tx.objectStore('instanceRemaps').clear();
115 tx.oncomplete = () => resolve();
116 });
117 });
118
119 it('can put and get index remaps', async () => {
120 const store = localRecordTable.instanceRemaps;
121
122 // Return undefined for missing
123 const missing = await store.get(1, 1, 'bob', 0);
124 expect(missing).toBeUndefined();
125
126 // Put and retrieve
127 await store.put(1, 1, 'bob', 0, 5);
128 const found = await store.get(1, 1, 'bob', 0);
129 expect(found).toBe(5);
130 });
131});
132