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

Sign up to get free protection for your applications and to get access to all the features.
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
+ });