@fireproof/core 0.19.0-dev-publish → 0.19.0-dev-global

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.
Files changed (49) hide show
  1. package/{chunk-EVSZA26U.js → chunk-AZVWSRER.js} +2 -2
  2. package/{chunk-UCMXU3DH.js → chunk-NZNG6TQT.js} +103 -1
  3. package/chunk-NZNG6TQT.js.map +1 -0
  4. package/{chunk-5X6APJDY.js → chunk-ZHO4NMWL.js} +2 -2
  5. package/index.cjs +122 -92
  6. package/index.cjs.map +1 -1
  7. package/index.d.cts +21 -1
  8. package/index.d.ts +21 -1
  9. package/index.global.js +24688 -0
  10. package/index.global.js.map +1 -0
  11. package/index.js +41 -122
  12. package/index.js.map +1 -1
  13. package/metafile-cjs.json +1 -1
  14. package/metafile-esm.json +1 -1
  15. package/metafile-iife.json +1 -0
  16. package/package.json +1 -1
  17. package/{sqlite-data-store-RIH56645.js → sqlite-data-store-3ST7XOLX.js} +3 -3
  18. package/{sqlite-meta-store-6347MWOR.js → sqlite-meta-store-QOIMCSJ7.js} +3 -3
  19. package/{sqlite-wal-store-G5YGK77N.js → sqlite-wal-store-JFBQPOYT.js} +3 -3
  20. package/{store-file-D472VFCS.js → store-file-CSS5THFH.js} +2 -2
  21. package/{store-indexdb-FRX5PTKR.js → store-indexdb-DR4HELVP.js} +3 -3
  22. package/{store-sql-MDSU23Y7.js → store-sql-BG6SMGQJ.js} +5 -5
  23. package/tests/blockstore/loader.test.ts +265 -0
  24. package/tests/blockstore/store.test.ts +164 -0
  25. package/tests/blockstore/transaction.test.ts +121 -0
  26. package/tests/fireproof/config.test.ts +212 -0
  27. package/tests/fireproof/crdt.test.ts +434 -0
  28. package/tests/fireproof/database.test.ts +466 -0
  29. package/tests/fireproof/fireproof.test.ts +602 -0
  30. package/tests/fireproof/hello.test.ts +54 -0
  31. package/tests/fireproof/indexer.test.ts +389 -0
  32. package/tests/helpers.ts +81 -0
  33. package/tests/react/useFireproof.test.tsx +19 -0
  34. package/tests/www/gallery.html +132 -0
  35. package/tests/www/iife.html +42 -0
  36. package/tests/www/todo-aws.html +232 -0
  37. package/tests/www/todo-ipfs.html +213 -0
  38. package/tests/www/todo-local.html +214 -0
  39. package/tests/www/todo-netlify.html +227 -0
  40. package/tests/www/todo.html +236 -0
  41. package/chunk-UCMXU3DH.js.map +0 -1
  42. /package/{chunk-EVSZA26U.js.map → chunk-AZVWSRER.js.map} +0 -0
  43. /package/{chunk-5X6APJDY.js.map → chunk-ZHO4NMWL.js.map} +0 -0
  44. /package/{sqlite-data-store-RIH56645.js.map → sqlite-data-store-3ST7XOLX.js.map} +0 -0
  45. /package/{sqlite-meta-store-6347MWOR.js.map → sqlite-meta-store-QOIMCSJ7.js.map} +0 -0
  46. /package/{sqlite-wal-store-G5YGK77N.js.map → sqlite-wal-store-JFBQPOYT.js.map} +0 -0
  47. /package/{store-file-D472VFCS.js.map → store-file-CSS5THFH.js.map} +0 -0
  48. /package/{store-indexdb-FRX5PTKR.js.map → store-indexdb-DR4HELVP.js.map} +0 -0
  49. /package/{store-sql-MDSU23Y7.js.map → store-sql-BG6SMGQJ.js.map} +0 -0
@@ -0,0 +1,212 @@
1
+ import { describe, it, expect, beforeAll } from "vitest";
2
+ import { fireproof, rt } from "@fireproof/core";
3
+ import { isNode } from "std-env";
4
+
5
+ describe("fireproof/config", () => {
6
+ let _my_app = "my-app";
7
+ function my_app() {
8
+ return _my_app;
9
+ }
10
+ beforeAll(async () => {
11
+ await rt.SysContainer.start();
12
+ if (isNode) {
13
+ const fpStorageUrl = rt.SysContainer.env.get("FP_STORAGE_URL");
14
+ if (fpStorageUrl) {
15
+ let url: URL;
16
+ try {
17
+ url = new URL(fpStorageUrl);
18
+ } catch (e) {
19
+ url = new URL(`file://${fpStorageUrl}`);
20
+ }
21
+ _my_app = `my-app-${url.protocol.replace(/:$/, "")}`;
22
+ }
23
+ }
24
+ });
25
+
26
+ if (!isNode) {
27
+ it("default", async () => {
28
+ const db = fireproof(my_app());
29
+ await db.put({ name: "my-app" });
30
+ expect(db.name).toBe(my_app());
31
+ const carStore = await db.blockstore.loader?.carStore();
32
+ expect(carStore?.url.toString()).toMatch(new RegExp(`indexdb://fp\\?name=my-app&store=data&version=${rt.INDEXDB_VERSION}`));
33
+ const fileStore = await db.blockstore.loader?.fileStore();
34
+ expect(fileStore?.url.toString()).toMatch(new RegExp(`indexdb://fp\\?name=my-app&store=data&version=${rt.INDEXDB_VERSION}`));
35
+ const metaStore = await db.blockstore.loader?.metaStore();
36
+ expect(metaStore?.url.toString()).toMatch(new RegExp(`indexdb://fp\\?name=my-app&store=meta&version=${rt.INDEXDB_VERSION}`));
37
+ await db.close();
38
+ });
39
+ return;
40
+ }
41
+ it("node default", async () => {
42
+ const old = rt.SysContainer.env.get("FP_STORAGE_URL");
43
+ rt.SysContainer.env.del("FP_STORAGE_URL");
44
+ let baseDir = rt
45
+ .dataDir(my_app())
46
+ .replace(/\?.*$/, "")
47
+ .replace(/^file:\/\//, "");
48
+ baseDir = rt.SysContainer.join(baseDir, rt.FILESTORE_VERSION, my_app());
49
+ await rt.SysContainer.rm(baseDir, { recursive: true }).catch(() => {
50
+ /* */
51
+ });
52
+
53
+ expect(baseDir).toMatch(new RegExp(`/\\.fireproof/${rt.FILESTORE_VERSION}/${my_app()}`));
54
+
55
+ const db = fireproof(my_app());
56
+ await db.put({ name: "my-app" });
57
+ expect(db.name).toBe(my_app());
58
+ const carStore = await db.blockstore.loader?.carStore();
59
+
60
+ expect(carStore?.url.toString()).toMatch(
61
+ new RegExp(`file:.*\\/\\.fireproof\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
62
+ );
63
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "data"))).isDirectory()).toBeTruthy();
64
+
65
+ const fileStore = await db.blockstore.loader?.fileStore();
66
+ expect(fileStore?.url.toString()).toMatch(
67
+ new RegExp(`file:.*\\/\\.fireproof\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
68
+ );
69
+ const metaStore = await db.blockstore.loader?.metaStore();
70
+ expect(metaStore?.url.toString()).toMatch(
71
+ new RegExp(`file:.*\\/\\.fireproof\\?name=${my_app()}&store=meta&version=${rt.FILESTORE_VERSION}`),
72
+ );
73
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "meta"))).isDirectory()).toBeTruthy();
74
+ rt.SysContainer.env.set("FP_STORAGE_URL", old);
75
+ await db.close();
76
+ });
77
+
78
+ it("set by env", async () => {
79
+ const old = rt.SysContainer.env.get("FP_STORAGE_URL");
80
+ rt.SysContainer.env.set("FP_STORAGE_URL", "./dist/env");
81
+
82
+ let baseDir = rt
83
+ .dataDir(my_app())
84
+ .replace(/\?.*$/, "")
85
+ .replace(/^file:\/\//, "");
86
+ baseDir = rt.SysContainer.join(baseDir, rt.FILESTORE_VERSION, my_app());
87
+ await rt.SysContainer.rm(baseDir, { recursive: true }).catch(() => {
88
+ /* */
89
+ });
90
+
91
+ const db = fireproof(my_app());
92
+ await db.put({ name: "my-app" });
93
+ expect(db.name).toBe(my_app());
94
+ const carStore = await db.blockstore.loader?.carStore();
95
+ expect(carStore?.url.toString()).toMatch(
96
+ new RegExp(`file://\\./dist/env\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
97
+ );
98
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "data"))).isDirectory()).toBeTruthy();
99
+ const fileStore = await db.blockstore.loader?.fileStore();
100
+ expect(fileStore?.url.toString()).toMatch(
101
+ new RegExp(`file://\\./dist/env\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
102
+ );
103
+ const metaStore = await db.blockstore.loader?.metaStore();
104
+ expect(metaStore?.url.toString()).toMatch(
105
+ new RegExp(`file://\\./dist/env\\?name=${my_app()}&store=meta&version=${rt.FILESTORE_VERSION}`),
106
+ );
107
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "meta"))).isDirectory()).toBeTruthy();
108
+ await db.close();
109
+ rt.SysContainer.env.set("FP_STORAGE_URL", old);
110
+ });
111
+
112
+ it("file path", async () => {
113
+ let baseDir = "./dist/data".replace(/\?.*$/, "").replace(/^file:\/\//, "");
114
+ baseDir = rt.SysContainer.join(baseDir, rt.FILESTORE_VERSION, my_app());
115
+ await rt.SysContainer.rm(baseDir, { recursive: true }).catch(() => {
116
+ /* */
117
+ });
118
+
119
+ const db = fireproof(my_app(), {
120
+ store: {
121
+ stores: {
122
+ base: "./dist/data",
123
+ },
124
+ },
125
+ });
126
+ // console.log(`>>>>>>>>>>>>>>>file-path`)
127
+ await db.put({ name: "my-app" });
128
+ expect(db.name).toBe(my_app());
129
+ const carStore = await db.blockstore.loader?.carStore();
130
+ expect(carStore?.url.toString()).toMatch(
131
+ new RegExp(`file://.\\/dist\\/data\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
132
+ );
133
+ const fileStore = await db.blockstore.loader?.fileStore();
134
+ expect(fileStore?.url.toString()).toMatch(
135
+ new RegExp(`file://.\\/dist\\/data\\?name=${my_app()}&store=data&version=${rt.FILESTORE_VERSION}`),
136
+ );
137
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "data"))).isDirectory()).toBeTruthy();
138
+ const metaStore = await db.blockstore.loader?.metaStore();
139
+ expect(metaStore?.url.toString()).toMatch(
140
+ new RegExp(`file://.\\/dist\\/data\\?name=${my_app()}&store=meta&version=${rt.FILESTORE_VERSION}`),
141
+ );
142
+ expect((await rt.SysContainer.stat(rt.SysContainer.join(baseDir, "meta"))).isDirectory()).toBeTruthy();
143
+ await db.close();
144
+ });
145
+
146
+ it("sqlite path", async () => {
147
+ let dbFile = "sqlite://./dist/sqlite".replace(/\?.*$/, "").replace(/^sqlite:\/\//, "");
148
+ dbFile = rt.SysContainer.join(dbFile, `${my_app()}.sqlite`);
149
+ await rt.SysContainer.rm(dbFile, { recursive: true }).catch(() => {
150
+ /* */
151
+ });
152
+
153
+ const db = fireproof(my_app(), {
154
+ store: {
155
+ stores: {
156
+ base: "sqlite://./dist/sqlite",
157
+ },
158
+ },
159
+ });
160
+ // console.log(`>>>>>>>>>>>>>>>file-path`)
161
+ await db.put({ name: "my-app" });
162
+ expect((await rt.SysContainer.stat(dbFile)).isFile()).toBeTruthy();
163
+ expect(db.name).toBe(my_app());
164
+ const carStore = await db.blockstore.loader?.carStore();
165
+ expect(carStore?.url.toString()).toMatch(
166
+ new RegExp(`sqlite://./dist/sqlite\\?name=${my_app()}&store=data&version=${rt.SQLITE_VERSION}`),
167
+ );
168
+ const fileStore = await db.blockstore.loader?.fileStore();
169
+ expect(fileStore?.url.toString()).toMatch(
170
+ new RegExp(`sqlite://./dist/sqlite\\?name=${my_app()}&store=data&version=${rt.SQLITE_VERSION}`),
171
+ );
172
+ const metaStore = await db.blockstore.loader?.metaStore();
173
+ expect(metaStore?.url.toString()).toMatch(
174
+ new RegExp(`sqlite://./dist/sqlite\\?name=${my_app()}&store=meta&version=${rt.SQLITE_VERSION}`),
175
+ );
176
+ await db.close();
177
+ });
178
+
179
+ it("full config path", async () => {
180
+ const db = fireproof(my_app(), {
181
+ store: {
182
+ stores: {
183
+ base: "sqlite://./dist/sqlite",
184
+
185
+ meta: "sqlite://./dist/sqlite/meta",
186
+ data: "sqlite://./dist/sqlite/data",
187
+ index: "sqlite://./dist/sqlite/index",
188
+ remoteWAL: "sqlite://./dist/sqlite/wal",
189
+ },
190
+ },
191
+ });
192
+ // console.log(`>>>>>>>>>>>>>>>file-path`)
193
+ await db.put({ name: my_app() });
194
+ expect(db.name).toBe(my_app());
195
+
196
+ const carStore = await db.blockstore.loader?.carStore();
197
+ expect(carStore?.url.toString()).toMatch(
198
+ // sqlite://./dist/sqlite/data?store=data&version=v0.19-sqlite
199
+ new RegExp(`sqlite://./dist/sqlite/data\\?name=${my_app()}&store=data&version=${rt.SQLITE_VERSION}`),
200
+ );
201
+
202
+ const fileStore = await db.blockstore.loader?.fileStore();
203
+ expect(fileStore?.url.toString()).toMatch(
204
+ new RegExp(`sqlite://./dist/sqlite/data\\?name=${my_app()}&store=data&version=${rt.SQLITE_VERSION}`),
205
+ );
206
+ const metaStore = await db.blockstore.loader?.metaStore();
207
+ expect(metaStore?.url.toString()).toMatch(
208
+ new RegExp(`sqlite://./dist/sqlite/meta\\?name=${my_app()}&store=meta&version=${rt.SQLITE_VERSION}`),
209
+ );
210
+ await db.close();
211
+ });
212
+ });
@@ -0,0 +1,434 @@
1
+ import { itSkip } from "../helpers.js";
2
+
3
+ import { uuidv4 } from "uuidv7";
4
+
5
+ import { CRDT } from "@fireproof/core";
6
+ import { bs, rt } from "@fireproof/core";
7
+ import { CRDTMeta, DocValue } from "@fireproof/core";
8
+ import { Index, index } from "@fireproof/core";
9
+
10
+ describe("Fresh crdt", function () {
11
+ let crdt: CRDT<{ hello: string } | { points: number }>;
12
+ afterEach(async function () {
13
+ await crdt.close();
14
+ await crdt.destroy();
15
+ });
16
+ beforeEach(async function () {
17
+ await rt.SysContainer.start();
18
+ crdt = new CRDT();
19
+ });
20
+ it("should have an empty head", async function () {
21
+ const head = crdt.clock.head;
22
+ expect(head.length).toBe(0);
23
+ });
24
+ it("should accept put and return results", async function () {
25
+ const didPut = await crdt.bulk([{ id: "hello", value: { hello: "world" } }]);
26
+ const head = didPut.head;
27
+ expect(head.length).toBe(1);
28
+ });
29
+ it("should accept multi-put and return results", async function () {
30
+ const didPut = await crdt.bulk([
31
+ { id: "ace", value: { points: 11 } },
32
+ { id: "king", value: { points: 10 } },
33
+ ]);
34
+ const head = didPut.head;
35
+ expect(head.length).toBe(1);
36
+ });
37
+ });
38
+
39
+ describe("CRDT with one record", function () {
40
+ interface CRDTTestType {
41
+ readonly hello: string;
42
+ readonly nice: string;
43
+ }
44
+ let crdt: CRDT<Partial<CRDTTestType>>;
45
+ let firstPut: CRDTMeta;
46
+
47
+ afterEach(async function () {
48
+ await crdt.close();
49
+ await crdt.destroy();
50
+ });
51
+
52
+ beforeEach(async function () {
53
+ await rt.SysContainer.start();
54
+ crdt = new CRDT(`test@${uuidv4()}`);
55
+ firstPut = await crdt.bulk([{ id: "hello", value: { hello: "world" } }]);
56
+ });
57
+ it("should have a one-element head", async function () {
58
+ const head = crdt.clock.head;
59
+ expect(head.length).toBe(1);
60
+ });
61
+ it("should return the head", async function () {
62
+ expect(firstPut.head.length).toBe(1);
63
+ });
64
+ it("return the record on get", async function () {
65
+ const got = (await crdt.get("hello")) as DocValue<CRDTTestType>;
66
+ expect(got).toBeTruthy();
67
+ expect(got.doc.hello).toBe("world");
68
+ });
69
+ it("should accept another put and return results", async function () {
70
+ const didPut = await crdt.bulk([{ id: "nice", value: { nice: "data" } }]);
71
+ const head = didPut.head;
72
+ expect(head.length).toBe(1);
73
+ const { doc } = (await crdt.get("nice")) as DocValue<CRDTTestType>;
74
+ expect(doc.nice).toBe("data");
75
+ });
76
+ it("should allow for a delete", async function () {
77
+ const didDel = await crdt.bulk([{ id: "hello", del: true }]);
78
+ expect(didDel.head).toBeTruthy();
79
+ const got = await crdt.get("hello");
80
+ expect(got).toBeFalsy();
81
+ });
82
+ it("should offer changes", async function () {
83
+ const { result } = await crdt.changes([]);
84
+ expect(result.length).toBe(1);
85
+ expect(result[0].id).toBe("hello");
86
+ expect(result[0].value?.hello).toBe("world");
87
+ });
88
+ });
89
+
90
+ describe("CRDT with a multi-write", function () {
91
+ interface CRDTTestType {
92
+ readonly points: number;
93
+ }
94
+ let crdt: CRDT<CRDTTestType>;
95
+ let firstPut: CRDTMeta;
96
+
97
+ afterEach(async function () {
98
+ await crdt.close();
99
+ await crdt.destroy();
100
+ });
101
+ beforeEach(async function () {
102
+ await rt.SysContainer.start();
103
+ crdt = new CRDT();
104
+ firstPut = await crdt.bulk([
105
+ { id: "ace", value: { points: 11 } },
106
+ { id: "king", value: { points: 10 } },
107
+ ]);
108
+ });
109
+ it("should have a one-element head", async function () {
110
+ const head = crdt.clock.head;
111
+ expect(head.length).toBe(1);
112
+ expect(firstPut.head.length).toBe(1);
113
+ });
114
+ it("return the records on get", async function () {
115
+ const { doc } = (await crdt.get("ace")) as DocValue<CRDTTestType>;
116
+ expect(doc.points).toBe(11);
117
+
118
+ const got2 = (await crdt.get("king")) as DocValue<CRDTTestType>;
119
+ expect(got2).toBeTruthy();
120
+ expect(got2.doc.points).toBe(10);
121
+ });
122
+ it("should accept another put and return results", async function () {
123
+ const didPut = await crdt.bulk([{ id: "queen", value: { points: 10 } }]);
124
+ const head = didPut.head;
125
+ expect(head.length).toBe(1);
126
+ const got = (await crdt.get("queen")) as DocValue<CRDTTestType>;
127
+ expect(got).toBeTruthy();
128
+ expect(got.doc.points).toBe(10);
129
+ });
130
+ it("should offer changes", async function () {
131
+ const { result } = await crdt.changes([]);
132
+ expect(result.length).toBe(2);
133
+ expect(result[0].id).toBe("ace");
134
+ expect(result[0].value?.points).toBe(11);
135
+ expect(result[1].id).toBe("king");
136
+ });
137
+ it("should offer changes since", async function () {
138
+ /** @type {CRDTMeta} */
139
+ const secondPut = await crdt.bulk([
140
+ { id: "queen", value: { points: 10 } },
141
+ { id: "jack", value: { points: 10 } },
142
+ ]);
143
+ expect(secondPut.head).toBeTruthy();
144
+ const { result: r2, head: h2 } = await crdt.changes();
145
+ expect(r2.length).toBe(4);
146
+ const { result: r3 } = await crdt.changes(firstPut.head);
147
+ expect(r3.length).toBe(2);
148
+ const { result: r4 } = await crdt.changes(h2);
149
+ expect(r4.length).toBe(0);
150
+ });
151
+ });
152
+
153
+ interface CRDTTestType {
154
+ readonly points: number;
155
+ }
156
+ describe("CRDT with two multi-writes", function () {
157
+ /** @type {CRDT} */
158
+ let crdt: CRDT<CRDTTestType>;
159
+ let firstPut: CRDTMeta;
160
+ let secondPut: CRDTMeta;
161
+ afterEach(async function () {
162
+ await crdt.close();
163
+ await crdt.destroy();
164
+ });
165
+ beforeEach(async () => {
166
+ await rt.SysContainer.start();
167
+ crdt = new CRDT();
168
+ firstPut = await crdt.bulk([
169
+ { id: "ace", value: { points: 11 } },
170
+ { id: "king", value: { points: 10 } },
171
+ ]);
172
+ secondPut = await crdt.bulk([
173
+ { id: "queen", value: { points: 10 } },
174
+ { id: "jack", value: { points: 10 } },
175
+ ]);
176
+ });
177
+ it("should have a one-element head", async function () {
178
+ const head = crdt.clock.head;
179
+ expect(head.length).toBe(1);
180
+ expect(firstPut.head.length).toBe(1);
181
+ expect(secondPut.head.length).toBe(1);
182
+ expect(firstPut.head[0]).not.toBe(secondPut.head[0]);
183
+ });
184
+ it("return the records on get", async function () {
185
+ const ret = await crdt.get("ace");
186
+ expect(ret).not.toBeNull();
187
+ const { doc } = ret as DocValue<CRDTTestType>;
188
+ expect(doc.points).toBe(11);
189
+
190
+ for (const key of ["king", "queen", "jack"]) {
191
+ const { doc } = (await crdt.get(key)) as DocValue<CRDTTestType>;
192
+ expect(doc.points).toBe(10);
193
+ }
194
+ });
195
+ it("should offer changes", async function () {
196
+ const { result } = await crdt.changes();
197
+ expect(result.length).toBe(4);
198
+ expect(result[0].id).toBe("ace");
199
+ expect(result[0].value?.points).toBe(11);
200
+ expect(result[1].id).toBe("king");
201
+ expect(result[2].id).toBe("queen");
202
+ expect(result[3].id).toBe("jack");
203
+ });
204
+ });
205
+
206
+ describe("Compact a named CRDT with writes", function () {
207
+ let crdt: CRDT<CRDTTestType>;
208
+ afterEach(async function () {
209
+ await crdt.close();
210
+ await crdt.destroy();
211
+ });
212
+ beforeEach(async function () {
213
+ await rt.SysContainer.start();
214
+ crdt = new CRDT("named-crdt-compaction");
215
+ for (let i = 0; i < 10; i++) {
216
+ const bulk = [
217
+ { id: "ace", value: { points: 11 } },
218
+ { id: "king", value: { points: 10 } },
219
+ ];
220
+ await crdt.bulk(bulk);
221
+ }
222
+ });
223
+ it("has data", async function () {
224
+ const got = (await crdt.get("ace")) as DocValue<CRDTTestType>;
225
+ expect(got.doc).toBeTruthy();
226
+ expect(got.doc.points).toBe(11);
227
+ });
228
+ it("should start with blocks", async function () {
229
+ const blz: bs.AnyBlock[] = [];
230
+ for await (const blk of crdt.blockstore.entries()) {
231
+ blz.push(blk);
232
+ }
233
+ expect(blz.length).toBe(13);
234
+ });
235
+ it("should start with changes", async function () {
236
+ const { result } = await crdt.changes();
237
+ expect(result.length).toBe(2);
238
+ expect(result[0].id).toBe("ace");
239
+ });
240
+ itSkip("should have fewer blocks after compact", async function () {
241
+ await crdt.compact();
242
+ const blz: bs.AnyBlock[] = [];
243
+ for await (const blk of crdt.blockstore.entries()) {
244
+ blz.push(blk);
245
+ }
246
+ expect(blz.length).toBe(23);
247
+ });
248
+ it("should have data after compact", async function () {
249
+ await crdt.compact();
250
+ const got = (await crdt.get("ace")) as DocValue<CRDTTestType>;
251
+ expect(got.doc).toBeTruthy();
252
+ expect(got.doc.points).toBe(11);
253
+ });
254
+ it("should have changes after compact", async function () {
255
+ const chs = await crdt.changes();
256
+ expect(chs.result[0].id).toBe("ace");
257
+ });
258
+ });
259
+
260
+ describe("CRDT with an index", function () {
261
+ let crdt: CRDT<CRDTTestType>;
262
+ let idx: Index<number, CRDTTestType>;
263
+ afterEach(async function () {
264
+ await crdt.close();
265
+ await crdt.destroy();
266
+ });
267
+ beforeEach(async function () {
268
+ await rt.SysContainer.start();
269
+ crdt = new CRDT<CRDTTestType>();
270
+ await crdt.bulk([
271
+ { id: "ace", value: { points: 11 } },
272
+ { id: "king", value: { points: 10 } },
273
+ ]);
274
+ idx = await index<number, CRDTTestType>({ _crdt: crdt }, "points");
275
+ });
276
+ it("should query the data", async function () {
277
+ const got = await idx.query({ range: [9, 12] });
278
+ expect(got.rows.length).toBe(2);
279
+ expect(got.rows[0].id).toBe("king");
280
+ expect(got.rows[0].key).toBe(10);
281
+ });
282
+ it("should register the index", async function () {
283
+ const rIdx = await index<number, CRDTTestType>({ _crdt: crdt }, "points");
284
+ expect(rIdx).toBeTruthy();
285
+ expect(rIdx.name).toBe("points");
286
+ const got = await rIdx.query({ range: [9, 12] });
287
+ expect(got.rows.length).toBe(2);
288
+ expect(got.rows[0].id).toBe("king");
289
+ expect(got.rows[0].key).toBe(10);
290
+ });
291
+ it("creating a different index with same name should not work", async function () {
292
+ const e = await index({ _crdt: crdt }, "points", (doc) => doc._id)
293
+ .query()
294
+ .catch((err) => err);
295
+ expect(e.message).toMatch(/cannot apply/);
296
+ });
297
+ });
298
+
299
+ describe("Loader with a committed transaction", function () {
300
+ interface CRDTTestType {
301
+ readonly foo: string;
302
+ }
303
+ let loader: bs.Loader;
304
+ let blockstore: bs.EncryptedBlockstore;
305
+ let crdt: CRDT<CRDTTestType>;
306
+ let done: CRDTMeta;
307
+ const dbname = "test-loader";
308
+ afterEach(async function () {
309
+ await crdt.close();
310
+ await crdt.destroy();
311
+ });
312
+ beforeEach(async function () {
313
+ await rt.SysContainer.start();
314
+ crdt = new CRDT(dbname);
315
+ blockstore = crdt.blockstore as bs.EncryptedBlockstore;
316
+ expect(blockstore.loader).toBeTruthy();
317
+ loader = blockstore.loader;
318
+ done = await crdt.bulk([{ id: "foo", value: { foo: "bar" } }]);
319
+ });
320
+ it("should have a name", function () {
321
+ expect(loader.name).toBe(dbname);
322
+ });
323
+ it("should commit a transaction", function () {
324
+ expect(done.head).toBeTruthy();
325
+ // expect(done.cars).toBeTruthy();
326
+ expect(loader.carLog.length).toBe(1);
327
+ });
328
+ it("can load the car", async function () {
329
+ const blk = loader.carLog[0][0];
330
+ expect(blk).toBeTruthy();
331
+ const reader = await loader.loadCar(blk);
332
+ expect(reader).toBeTruthy();
333
+ const parsed = await bs.parseCarFile<CRDTMeta>(reader, loader.logger);
334
+ expect(parsed.cars).toBeTruthy();
335
+ expect(parsed.cars.length).toBe(0);
336
+ expect(parsed.meta).toBeTruthy();
337
+ expect(parsed.meta.head).toBeTruthy();
338
+ });
339
+ });
340
+
341
+ describe("Loader with two committed transactions", function () {
342
+ interface CRDTTestType {
343
+ readonly foo: string;
344
+ }
345
+ let loader: bs.Loader;
346
+ let crdt: CRDT<CRDTTestType>;
347
+ let blockstore: bs.EncryptedBlockstore;
348
+ let done1: CRDTMeta;
349
+ let done2: CRDTMeta;
350
+ afterEach(async function () {
351
+ await crdt.close();
352
+ await crdt.destroy();
353
+ });
354
+ beforeEach(async function () {
355
+ await rt.SysContainer.start();
356
+ crdt = new CRDT("test-loader");
357
+ blockstore = crdt.blockstore as bs.EncryptedBlockstore;
358
+ expect(blockstore.loader).toBeTruthy();
359
+ loader = blockstore.loader;
360
+ done1 = await crdt.bulk([{ id: "apple", value: { foo: "bar" } }]);
361
+ done2 = await crdt.bulk([{ id: "orange", value: { foo: "bar" } }]);
362
+ });
363
+ it("should commit two transactions", function () {
364
+ expect(done1.head).toBeTruthy();
365
+ // expect(done1.cars).toBeTruthy();
366
+ expect(done2.head).toBeTruthy();
367
+ // expect(done2.cars).toBeTruthy();
368
+ expect(done1.head).not.toBe(done2.head);
369
+ // expect(done1.cars).not.toBe(done2.cars);
370
+ // expect(blockstore.transactions.size).toBe(2);
371
+ expect(loader.carLog.length).toBe(2);
372
+ // expect(loader.carLog.indexOf(done1.cars)).toBe(1);
373
+ // expect(loader.carLog.map((cs) => cs.toString()).indexOf(done1.cars.toString())).toBe(1);
374
+ // expect(loader.carLog.indexOf(done2.cars)).toBe(0);
375
+ // expect(loader.carLog.map((cs) => cs.toString()).indexOf(done2.cars.toString())).toBe(0);
376
+ });
377
+ it("can load the car", async function () {
378
+ const blk = loader.carLog[0][0];
379
+ expect(blk).toBeTruthy();
380
+ const reader = await loader.loadCar(blk);
381
+ expect(reader).toBeTruthy();
382
+ const parsed = await bs.parseCarFile<CRDTMeta>(reader, loader.logger);
383
+ expect(parsed.cars).toBeTruthy();
384
+ expect(parsed.cars.length).toBe(1);
385
+ expect(parsed.meta).toBeTruthy();
386
+ expect(parsed.meta.head).toBeTruthy();
387
+ });
388
+ });
389
+
390
+ describe("Loader with many committed transactions", function () {
391
+ interface Doc {
392
+ foo: string;
393
+ }
394
+ let loader: bs.Loader;
395
+ let blockstore: bs.EncryptedBlockstore;
396
+ let crdt: CRDT<Doc>;
397
+ let dones: CRDTMeta[];
398
+ const count = 10;
399
+ afterEach(async function () {
400
+ await crdt.close();
401
+ await crdt.destroy();
402
+ });
403
+ beforeEach(async function () {
404
+ await rt.SysContainer.start();
405
+ crdt = new CRDT("test-loader-many");
406
+ blockstore = crdt.blockstore as bs.EncryptedBlockstore;
407
+ expect(blockstore.loader).toBeTruthy();
408
+ loader = blockstore.loader;
409
+ dones = [];
410
+ for (let i = 0; i < count; i++) {
411
+ const did = await crdt.bulk([{ id: `apple${i}`, value: { foo: "bar" } }]);
412
+ dones.push(did);
413
+ }
414
+ });
415
+ it("should commit many transactions", function () {
416
+ for (const done of dones) {
417
+ expect(done.head).toBeTruthy();
418
+ // expect(done.cars).toBeTruthy();
419
+ }
420
+ expect(blockstore.transactions.size).toBe(0); // cleaned up on commit
421
+ expect(loader.carLog.length).toBe(count);
422
+ });
423
+ it("can load the car", async function () {
424
+ const blk = loader.carLog[2][0];
425
+ // expect(dones[5].cars).toBeTruthy();
426
+ const reader = await loader.loadCar(blk);
427
+ expect(reader).toBeTruthy();
428
+ const parsed = await bs.parseCarFile<CRDTMeta>(reader, loader.logger);
429
+ expect(parsed.cars).toBeTruthy();
430
+ expect(parsed.cars.length).toBe(7);
431
+ expect(parsed.meta).toBeTruthy();
432
+ expect(parsed.meta.head).toBeTruthy();
433
+ });
434
+ });