@fireproof/core 0.20.5 → 0.21.0-dev-preview-2
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/blockstore/commitor.js +3 -3
- package/blockstore/commitor.js.map +1 -1
- package/crdt.d.ts +1 -1
- package/crdt.d.ts.map +1 -1
- package/crdt.js.map +1 -1
- package/database.d.ts +1 -1
- package/database.d.ts.map +1 -1
- package/database.js +7 -2
- package/database.js.map +1 -1
- package/deno.json +1 -1
- package/indexer-helpers.d.ts +29 -28
- package/indexer-helpers.d.ts.map +1 -1
- package/indexer-helpers.js +21 -3
- package/indexer-helpers.js.map +1 -1
- package/indexer.d.ts +3 -3
- package/indexer.d.ts.map +1 -1
- package/indexer.js +16 -24
- package/indexer.js.map +1 -1
- package/package.json +2 -2
- package/react/img-file.d.ts +1 -1
- package/react/img-file.d.ts.map +1 -1
- package/react/img-file.js +62 -27
- package/react/img-file.js.map +1 -1
- package/react/use-live-query.d.ts.map +1 -1
- package/react/use-live-query.js +1 -4
- package/react/use-live-query.js.map +1 -1
- package/tests/fireproof/charwise-boolean.test.ts +67 -0
- package/tests/fireproof/crdt.test.ts +3 -3
- package/tests/fireproof/deleted-docs-handling.test.ts +112 -0
- package/tests/fireproof/fireproof.test.ts +10 -10
- package/tests/fireproof/hello.test.ts +1 -1
- package/tests/fireproof/indexer.test.ts +21 -21
- package/tests/fireproof/query-docs.test.ts +41 -3
- package/tests/fireproof/query-limit-issue.test.ts +147 -0
- package/tests/fireproof/query-property-inconsistency.test.ts +92 -0
- package/tests/fireproof/query-result-properties.test.ts +45 -0
- package/types.d.ts +4 -3
- package/types.d.ts.map +1 -1
- package/types.js.map +1 -1
package/react/img-file.js
CHANGED
@@ -1,49 +1,84 @@
|
|
1
|
-
import
|
1
|
+
import { LRUMap } from "@adviser/cement";
|
2
|
+
import React, { useState, useEffect, useRef, useMemo } from "react";
|
3
|
+
const objectUrlCache = new LRUMap();
|
2
4
|
function isFile(obj) {
|
3
5
|
return "type" in obj && "size" in obj && "stream" in obj && typeof obj.stream === "function";
|
4
6
|
}
|
5
7
|
function isFileMeta(obj) {
|
6
8
|
return "type" in obj && "size" in obj && "file" in obj && typeof obj.file === "function";
|
7
9
|
}
|
10
|
+
function getCacheKey(fileObj) {
|
11
|
+
return `${fileObj.name}-${fileObj.size}-${fileObj.lastModified}`;
|
12
|
+
}
|
13
|
+
function getObjectUrl(fileObj) {
|
14
|
+
const cacheKey = getCacheKey(fileObj);
|
15
|
+
if (!objectUrlCache.has(cacheKey)) {
|
16
|
+
objectUrlCache.set(cacheKey, URL.createObjectURL(fileObj));
|
17
|
+
}
|
18
|
+
return objectUrlCache.get(cacheKey);
|
19
|
+
}
|
20
|
+
async function loadFile({ fileData, fileObjRef, cleanupRef, setImgDataUrl, }) {
|
21
|
+
let fileObj = null;
|
22
|
+
let fileType = "";
|
23
|
+
if (fileData) {
|
24
|
+
switch (true) {
|
25
|
+
case isFile(fileData):
|
26
|
+
fileObj = fileData;
|
27
|
+
fileType = fileData.type;
|
28
|
+
break;
|
29
|
+
case isFileMeta(fileData):
|
30
|
+
fileType = fileData.type;
|
31
|
+
fileObj = typeof fileData.file === "function" ? await fileData.file() : null;
|
32
|
+
break;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
if (fileObjRef.current !== fileObj && cleanupRef.current) {
|
36
|
+
cleanupRef.current();
|
37
|
+
cleanupRef.current = null;
|
38
|
+
}
|
39
|
+
if (fileObj && /image/.test(fileType)) {
|
40
|
+
if (fileObjRef.current !== fileObj) {
|
41
|
+
const src = getObjectUrl(fileObj);
|
42
|
+
setImgDataUrl(src);
|
43
|
+
fileObjRef.current = fileObj;
|
44
|
+
cleanupRef.current = () => {
|
45
|
+
const cacheKey = getCacheKey(fileObj);
|
46
|
+
if (objectUrlCache.has(cacheKey)) {
|
47
|
+
URL.revokeObjectURL(objectUrlCache.get(cacheKey));
|
48
|
+
objectUrlCache.delete(cacheKey);
|
49
|
+
}
|
50
|
+
};
|
51
|
+
return cleanupRef.current;
|
52
|
+
}
|
53
|
+
return cleanupRef.current;
|
54
|
+
}
|
55
|
+
return null;
|
56
|
+
}
|
8
57
|
export function ImgFile({ file, meta, ...imgProps }) {
|
9
58
|
const [imgDataUrl, setImgDataUrl] = useState("");
|
10
|
-
const
|
59
|
+
const fileObjRef = useRef(null);
|
60
|
+
const cleanupRef = useRef(null);
|
61
|
+
const fileData = useMemo(() => {
|
62
|
+
return file || meta;
|
63
|
+
}, [file, meta]);
|
11
64
|
useEffect(() => {
|
12
65
|
if (!fileData)
|
13
66
|
return;
|
14
|
-
const loadFile = async () => {
|
15
|
-
let fileObj = null;
|
16
|
-
let fileType = "";
|
17
|
-
switch (true) {
|
18
|
-
case isFile(fileData):
|
19
|
-
fileObj = fileData;
|
20
|
-
fileType = fileData.type;
|
21
|
-
break;
|
22
|
-
case isFileMeta(fileData):
|
23
|
-
fileType = fileData.type;
|
24
|
-
fileObj = (await fileData.file?.()) || null;
|
25
|
-
break;
|
26
|
-
}
|
27
|
-
if (fileObj && /image/.test(fileType)) {
|
28
|
-
const src = URL.createObjectURL(fileObj);
|
29
|
-
setImgDataUrl(src);
|
30
|
-
return () => URL.revokeObjectURL(src);
|
31
|
-
}
|
32
|
-
};
|
33
67
|
let isMounted = true;
|
34
|
-
|
35
|
-
loadFile().then((result) => {
|
68
|
+
loadFile({ fileData, fileObjRef, cleanupRef, setImgDataUrl }).then(function handleResult(result) {
|
36
69
|
if (isMounted) {
|
37
|
-
|
70
|
+
cleanupRef.current = result;
|
38
71
|
}
|
39
72
|
else if (result) {
|
40
73
|
result();
|
41
74
|
}
|
42
75
|
});
|
43
|
-
return ()
|
76
|
+
return function cleanupEffect() {
|
44
77
|
isMounted = false;
|
45
|
-
if (
|
46
|
-
|
78
|
+
if (cleanupRef.current) {
|
79
|
+
cleanupRef.current();
|
80
|
+
cleanupRef.current = null;
|
81
|
+
}
|
47
82
|
};
|
48
83
|
}, [fileData]);
|
49
84
|
return imgDataUrl
|
package/react/img-file.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"img-file.js","sourceRoot":"","sources":["../../../../src/react/img-file.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"img-file.js","sourceRoot":"","sources":["../../../../src/react/img-file.ts"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"use-live-query.d.ts","sourceRoot":"","sources":["../../../../src/react/use-live-query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAa,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,IACtB,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,YAAY,GAAG,MAAM,EAAE,CAAC,SAAS,WAAW,GAAG,CAAC,EACzG,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,EACxB,UAAU,EACV,cAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAO,KACpC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,
|
1
|
+
{"version":3,"file":"use-live-query.d.ts","sourceRoot":"","sources":["../../../../src/react/use-live-query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAa,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,IACtB,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,YAAY,GAAG,MAAM,EAAE,CAAC,SAAS,WAAW,GAAG,CAAC,EACzG,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,EACxB,UAAU,EACV,cAAa,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAO,KACpC,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAwB5B"}
|
package/react/use-live-query.js
CHANGED
@@ -9,10 +9,7 @@ export function createUseLiveQuery(database) {
|
|
9
9
|
const mapFnString = useMemo(() => mapFn.toString(), [mapFn]);
|
10
10
|
const refreshRows = useCallback(async () => {
|
11
11
|
const res = await database.query(mapFn, query);
|
12
|
-
setResult(
|
13
|
-
docs: res.rows.map((r) => r.doc).filter((r) => !!r),
|
14
|
-
rows: res.rows,
|
15
|
-
});
|
12
|
+
setResult(res);
|
16
13
|
}, [database, mapFnString, queryString]);
|
17
14
|
useEffect(() => {
|
18
15
|
refreshRows();
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"use-live-query.js","sourceRoot":"","sources":["../../../../src/react/use-live-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAOlE,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,OAAO,SAAS,YAAY,CAC1B,KAAwB,EACxB,KAAK,GAAG,EAAE,EACV,cAAmC,EAAE;QAErC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA2B;YAC7D,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAE7D,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YACzC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAU,KAAK,EAAE,KAAK,CAAC,CAAC;YACxD,SAAS,CAAC
|
1
|
+
{"version":3,"file":"use-live-query.js","sourceRoot":"","sources":["../../../../src/react/use-live-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAOlE,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,OAAO,SAAS,YAAY,CAC1B,KAAwB,EACxB,KAAK,GAAG,EAAE,EACV,cAAmC,EAAE;QAErC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA2B;YAC7D,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAE7D,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YACzC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAU,KAAK,EAAE,KAAK,CAAC,CAAC;YACxD,SAAS,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;QAEzC,SAAS,CAAC,GAAG,EAAE;YACb,WAAW,EAAE,CAAC;YACd,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACpD,OAAO,GAAG,EAAE;gBACV,WAAW,EAAE,CAAC;YAChB,CAAC,CAAC;QACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;QAE5B,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
2
|
+
// @ts-expect-error "charwise" has no types
|
3
|
+
import charwise from "charwise";
|
4
|
+
import { encodeKey } from "../../src/indexer-helpers.js";
|
5
|
+
|
6
|
+
describe("charwise boolean handling", () => {
|
7
|
+
it("should encode and decode boolean values correctly", () => {
|
8
|
+
// Test true
|
9
|
+
const trueEncoded = charwise.encode(true);
|
10
|
+
expect(charwise.decode(trueEncoded)).toBe(true);
|
11
|
+
|
12
|
+
// Test false
|
13
|
+
const falseEncoded = charwise.encode(false);
|
14
|
+
expect(charwise.decode(falseEncoded)).toBe(false);
|
15
|
+
});
|
16
|
+
|
17
|
+
it("should differentiate between boolean values", () => {
|
18
|
+
const trueEncoded = charwise.encode(true);
|
19
|
+
const falseEncoded = charwise.encode(false);
|
20
|
+
|
21
|
+
// Ensure encoded values are different
|
22
|
+
expect(trueEncoded).not.toBe(falseEncoded);
|
23
|
+
|
24
|
+
// Test ordering
|
25
|
+
const orderedArray = [falseEncoded, trueEncoded].sort();
|
26
|
+
|
27
|
+
// In most collation systems, false should come before true
|
28
|
+
expect(orderedArray[0]).toBe(falseEncoded);
|
29
|
+
expect(orderedArray[1]).toBe(trueEncoded);
|
30
|
+
});
|
31
|
+
|
32
|
+
it("should differentiate boolean false from other values", () => {
|
33
|
+
const falseEncoded = charwise.encode(false);
|
34
|
+
const nullEncoded = charwise.encode(null);
|
35
|
+
const undefinedEncoded = charwise.encode(undefined);
|
36
|
+
const zeroEncoded = charwise.encode(0);
|
37
|
+
const emptyStringEncoded = charwise.encode("");
|
38
|
+
|
39
|
+
// Ensure false is different from other "falsy" values
|
40
|
+
expect(falseEncoded).not.toBe(nullEncoded);
|
41
|
+
expect(falseEncoded).not.toBe(undefinedEncoded);
|
42
|
+
expect(falseEncoded).not.toBe(zeroEncoded);
|
43
|
+
expect(falseEncoded).not.toBe(emptyStringEncoded);
|
44
|
+
});
|
45
|
+
|
46
|
+
it("should handle comparison of encoded boolean values", () => {
|
47
|
+
// Test with the charwise.encode directly
|
48
|
+
const falseEncoded = charwise.encode(false);
|
49
|
+
const trueEncoded = charwise.encode(true);
|
50
|
+
|
51
|
+
// Test with Fireproof's encodeKey function
|
52
|
+
const falseFireproofEncoded = encodeKey(false);
|
53
|
+
const trueFireproofEncoded = encodeKey(true);
|
54
|
+
|
55
|
+
// Check if Fireproof's encoding matches charwise directly
|
56
|
+
expect(falseFireproofEncoded).toBe(falseEncoded);
|
57
|
+
expect(trueFireproofEncoded).toBe(trueEncoded);
|
58
|
+
|
59
|
+
// Test exact matching
|
60
|
+
const falseTest = charwise.encode(false);
|
61
|
+
expect(falseTest).toBe(falseEncoded);
|
62
|
+
|
63
|
+
// Test if equality comparison works after encoding/decoding
|
64
|
+
expect(charwise.decode(falseEncoded)).toBe(false);
|
65
|
+
expect(charwise.decode(falseEncoded) === false).toBe(true);
|
66
|
+
});
|
67
|
+
});
|
@@ -356,7 +356,7 @@ describe("Compact a named CRDT with writes", function () {
|
|
356
356
|
|
357
357
|
describe("CRDT with an index", function () {
|
358
358
|
let crdt: CRDT;
|
359
|
-
let idx: Index<
|
359
|
+
let idx: Index<CRDTTestType, number>;
|
360
360
|
const sthis = ensureSuperThis();
|
361
361
|
afterEach(async () => {
|
362
362
|
await crdt.close();
|
@@ -378,7 +378,7 @@ describe("CRDT with an index", function () {
|
|
378
378
|
{ id: "ace", value: { points: 11 } },
|
379
379
|
{ id: "king", value: { points: 10 } },
|
380
380
|
]);
|
381
|
-
idx = await index<
|
381
|
+
idx = await index<CRDTTestType, number>(crdt, "points");
|
382
382
|
});
|
383
383
|
it("should query the data", async () => {
|
384
384
|
const got = await idx.query({ range: [9, 12] });
|
@@ -387,7 +387,7 @@ describe("CRDT with an index", function () {
|
|
387
387
|
expect(got.rows[0].key).toBe(10);
|
388
388
|
});
|
389
389
|
it("should register the index", async () => {
|
390
|
-
const rIdx = await index<
|
390
|
+
const rIdx = await index<CRDTTestType, number>(crdt, "points");
|
391
391
|
expect(rIdx).toBeTruthy();
|
392
392
|
expect(rIdx.name).toBe("points");
|
393
393
|
const got = await rIdx.query({ range: [9, 12] });
|
@@ -0,0 +1,112 @@
|
|
1
|
+
import { describe, it, beforeEach, afterEach, expect } from "vitest";
|
2
|
+
import { Database, fireproof } from "@fireproof/core";
|
3
|
+
|
4
|
+
describe("allDocs deleted document handling", () => {
|
5
|
+
let db: Database;
|
6
|
+
|
7
|
+
beforeEach(async () => {
|
8
|
+
db = await fireproof("test-deleted-docs");
|
9
|
+
|
10
|
+
// Create a mix of regular and deleted documents
|
11
|
+
await db.put({ _id: "doc1", value: "one" });
|
12
|
+
await db.put({ _id: "doc2", value: "two" });
|
13
|
+
await db.put({ _id: "doc3", value: "three" });
|
14
|
+
|
15
|
+
// Create deleted documents
|
16
|
+
await db.put({ _id: "deleted1", value: "deleted-one", _deleted: true });
|
17
|
+
await db.put({ _id: "deleted2", value: "deleted-two", _deleted: true });
|
18
|
+
});
|
19
|
+
|
20
|
+
afterEach(async () => {
|
21
|
+
await db.destroy();
|
22
|
+
});
|
23
|
+
|
24
|
+
it("should exclude deleted documents by default (currently failing)", async () => {
|
25
|
+
const result = await db.allDocs();
|
26
|
+
|
27
|
+
// This test will fail because allDocs() currently returns deleted documents
|
28
|
+
expect(result.rows.length).toBe(3); // Only non-deleted docs should be returned
|
29
|
+
|
30
|
+
const ids = result.rows.map((row) => row.key);
|
31
|
+
expect(ids).toContain("doc1");
|
32
|
+
expect(ids).toContain("doc2");
|
33
|
+
expect(ids).toContain("doc3");
|
34
|
+
expect(ids).not.toContain("deleted1");
|
35
|
+
expect(ids).not.toContain("deleted2");
|
36
|
+
});
|
37
|
+
|
38
|
+
it("should include deleted documents when includeDeleted is true (new feature)", async () => {
|
39
|
+
// This test will fail because the includeDeleted option doesn't exist yet
|
40
|
+
const result = await db.allDocs({ includeDeleted: true });
|
41
|
+
|
42
|
+
expect(result.rows.length).toBe(5); // All docs
|
43
|
+
|
44
|
+
const ids = result.rows.map((row) => row.key);
|
45
|
+
expect(ids).toContain("doc1");
|
46
|
+
expect(ids).toContain("doc2");
|
47
|
+
expect(ids).toContain("doc3");
|
48
|
+
expect(ids).toContain("deleted1");
|
49
|
+
expect(ids).toContain("deleted2");
|
50
|
+
});
|
51
|
+
|
52
|
+
it("handles empty databases correctly", async () => {
|
53
|
+
// Create a new empty database
|
54
|
+
const emptyDb = await fireproof("test-empty-db");
|
55
|
+
|
56
|
+
// Test with default options
|
57
|
+
const defaultResult = await emptyDb.allDocs();
|
58
|
+
expect(defaultResult.rows.length).toBe(0);
|
59
|
+
|
60
|
+
// Test with includeDeleted option
|
61
|
+
const includeDeletedResult = await emptyDb.allDocs({ includeDeleted: true });
|
62
|
+
expect(includeDeletedResult.rows.length).toBe(0);
|
63
|
+
|
64
|
+
await emptyDb.destroy();
|
65
|
+
});
|
66
|
+
|
67
|
+
it("handles database with only deleted documents", async () => {
|
68
|
+
// Create a database with only deleted documents
|
69
|
+
const deletedOnlyDb = await fireproof("test-deleted-only-db");
|
70
|
+
|
71
|
+
// Add only deleted documents
|
72
|
+
await deletedOnlyDb.put({ _id: "deleted1", value: "deleted-one", _deleted: true });
|
73
|
+
await deletedOnlyDb.put({ _id: "deleted2", value: "deleted-two", _deleted: true });
|
74
|
+
|
75
|
+
// By default, should return empty result
|
76
|
+
const defaultResult = await deletedOnlyDb.allDocs();
|
77
|
+
expect(defaultResult.rows.length).toBe(0); // This will fail with current implementation
|
78
|
+
|
79
|
+
// With includeDeleted, should return all deleted docs
|
80
|
+
const includeDeletedResult = await deletedOnlyDb.allDocs({ includeDeleted: true });
|
81
|
+
expect(includeDeletedResult.rows.length).toBe(2);
|
82
|
+
|
83
|
+
await deletedOnlyDb.destroy();
|
84
|
+
});
|
85
|
+
|
86
|
+
it("respects limit option while excluding deleted documents", async () => {
|
87
|
+
// Test with limit option
|
88
|
+
const limitResult = await db.allDocs({ limit: 2 });
|
89
|
+
|
90
|
+
expect(limitResult.rows.length).toBe(2);
|
91
|
+
|
92
|
+
// All returned documents should be non-deleted
|
93
|
+
const docs = await Promise.all(limitResult.rows.map((row) => db.get(row.key)));
|
94
|
+
docs.forEach((doc) => {
|
95
|
+
expect(doc._deleted).not.toBe(true);
|
96
|
+
});
|
97
|
+
});
|
98
|
+
|
99
|
+
it("respects limit option while including deleted documents", async () => {
|
100
|
+
// Test with limit and includeDeleted options
|
101
|
+
const result = await db.allDocs({ limit: 3, includeDeleted: true });
|
102
|
+
|
103
|
+
expect(result.rows.length).toBe(3);
|
104
|
+
|
105
|
+
// Can include both deleted and non-deleted documents
|
106
|
+
const ids = result.rows.map((row) => row.key);
|
107
|
+
|
108
|
+
// We don't test specific IDs here because the order depends on implementation
|
109
|
+
// Just verify that the limit is respected
|
110
|
+
expect(ids.length).toBe(3);
|
111
|
+
});
|
112
|
+
});
|
@@ -39,7 +39,7 @@ describe("dreamcode", function () {
|
|
39
39
|
}
|
40
40
|
let ok: DocResponse;
|
41
41
|
let doc: DocWithId<Doc>;
|
42
|
-
let result: IndexRows<
|
42
|
+
let result: IndexRows<Doc, string>;
|
43
43
|
let db: Database;
|
44
44
|
const sthis = ensureSuperThis();
|
45
45
|
afterEach(async () => {
|
@@ -67,7 +67,7 @@ describe("dreamcode", function () {
|
|
67
67
|
expect(result.rows[0].key).toBe("fireproof");
|
68
68
|
});
|
69
69
|
it("should query with function", async () => {
|
70
|
-
const result = await db.query<
|
70
|
+
const result = await db.query<Doc, boolean>((doc) => doc.dream);
|
71
71
|
expect(result).toBeTruthy();
|
72
72
|
expect(result.rows).toBeTruthy();
|
73
73
|
expect(result.rows.length).toBe(1);
|
@@ -82,7 +82,7 @@ describe("public API", function () {
|
|
82
82
|
let db: Database;
|
83
83
|
let ok: DocResponse;
|
84
84
|
let doc: DocWithId<Doc>;
|
85
|
-
let query: IndexRows<
|
85
|
+
let query: IndexRows<Doc, string>;
|
86
86
|
const sthis = ensureSuperThis();
|
87
87
|
|
88
88
|
afterEach(async () => {
|
@@ -96,7 +96,7 @@ describe("public API", function () {
|
|
96
96
|
// index = index(db, 'test-index', (doc) => doc.foo)
|
97
97
|
ok = await db.put({ _id: "test", foo: "bar" });
|
98
98
|
doc = await db.get("test");
|
99
|
-
query = await db.query<
|
99
|
+
query = await db.query<Doc, string>((doc) => doc.foo);
|
100
100
|
});
|
101
101
|
it("should be a ledger instance", function () {
|
102
102
|
expect(db).toBeTruthy();
|
@@ -199,7 +199,7 @@ describe("basic ledger", function () {
|
|
199
199
|
it("can define an index", async () => {
|
200
200
|
const ok = await db.put({ _id: "test", foo: "bar" });
|
201
201
|
expect(ok).toBeTruthy();
|
202
|
-
const idx = index<
|
202
|
+
const idx = index<{ foo: string }, string>(db, "test-index", (doc) => doc.foo);
|
203
203
|
const result = await idx.query();
|
204
204
|
expect(result).toBeTruthy();
|
205
205
|
expect(result.rows).toBeTruthy();
|
@@ -223,10 +223,10 @@ describe("basic ledger", function () {
|
|
223
223
|
baz: string;
|
224
224
|
}
|
225
225
|
await db.put<TestDoc>({ _id: "test", foo: "bar", baz: "qux" });
|
226
|
-
const query1 = await db.query<
|
226
|
+
const query1 = await db.query<TestDoc, string>((doc) => {
|
227
227
|
return doc.foo;
|
228
228
|
});
|
229
|
-
const query2 = await db.query<
|
229
|
+
const query2 = await db.query<TestDoc, string>((doc) => {
|
230
230
|
return doc.baz;
|
231
231
|
});
|
232
232
|
expect(query1).toBeTruthy();
|
@@ -550,7 +550,7 @@ describe("Reopening a ledger with indexes", function () {
|
|
550
550
|
foo: string;
|
551
551
|
}
|
552
552
|
let db: Database;
|
553
|
-
let idx: Index<
|
553
|
+
let idx: Index<Doc, string>;
|
554
554
|
let didMap: boolean;
|
555
555
|
let mapFn: MapFn<Doc>;
|
556
556
|
const sthis = ensureSuperThis();
|
@@ -570,13 +570,13 @@ describe("Reopening a ledger with indexes", function () {
|
|
570
570
|
didMap = true;
|
571
571
|
return doc.foo;
|
572
572
|
};
|
573
|
-
idx = index<
|
573
|
+
idx = index<Doc, string>(db, "foo", mapFn);
|
574
574
|
});
|
575
575
|
|
576
576
|
it("should persist data", async () => {
|
577
577
|
const doc = await db.get<Doc>("test");
|
578
578
|
expect(doc.foo).toBe("bar");
|
579
|
-
const idx2 = index<
|
579
|
+
const idx2 = index<Doc, string>(db, "foo");
|
580
580
|
expect(idx2).toBe(idx);
|
581
581
|
const result = await idx2.query();
|
582
582
|
expect(result).toBeTruthy();
|
@@ -24,7 +24,7 @@ describe("hello public API", () => {
|
|
24
24
|
beforeEach(async () => {
|
25
25
|
await sthis.start();
|
26
26
|
db = fireproof("test-public-api");
|
27
|
-
index<
|
27
|
+
index<TestDoc, string>(db, "test-index", (doc) => doc.foo);
|
28
28
|
ok = await db.put({ _id: "test", foo: "bar" });
|
29
29
|
doc = await db.get("test");
|
30
30
|
});
|
@@ -23,7 +23,7 @@ interface TestType {
|
|
23
23
|
|
24
24
|
describe("basic Index", () => {
|
25
25
|
let db: Database;
|
26
|
-
let indexer: Index<
|
26
|
+
let indexer: Index<TestType, string>;
|
27
27
|
let didMap: boolean;
|
28
28
|
const sthis = ensureSuperThis();
|
29
29
|
afterEach(async () => {
|
@@ -38,7 +38,7 @@ describe("basic Index", () => {
|
|
38
38
|
await db.put({ title: "amazing" });
|
39
39
|
await db.put({ title: "creative" });
|
40
40
|
await db.put({ title: "bazillas" });
|
41
|
-
indexer = new Index<
|
41
|
+
indexer = new Index<TestType, string>(sthis, db.ledger.crdt, "hello", (doc) => {
|
42
42
|
didMap = true;
|
43
43
|
return doc.title;
|
44
44
|
});
|
@@ -111,7 +111,7 @@ describe("basic Index", () => {
|
|
111
111
|
|
112
112
|
describe("Index query with compound key", function () {
|
113
113
|
let db: Database;
|
114
|
-
let indexer: Index<[string, number]
|
114
|
+
let indexer: Index<TestType, [string, number]>;
|
115
115
|
const sthis = ensureSuperThis();
|
116
116
|
afterEach(async () => {
|
117
117
|
await db.close();
|
@@ -126,7 +126,7 @@ describe("Index query with compound key", function () {
|
|
126
126
|
await db.put({ title: "creative", score: 2 });
|
127
127
|
await db.put({ title: "creative", score: 20 });
|
128
128
|
await db.put({ title: "bazillas", score: 3 });
|
129
|
-
indexer = new Index<[string, number]
|
129
|
+
indexer = new Index<TestType, [string, number]>(sthis, db.ledger.crdt, "hello", (doc) => {
|
130
130
|
return [doc.title, doc.score];
|
131
131
|
});
|
132
132
|
await indexer.ready();
|
@@ -141,7 +141,7 @@ describe("Index query with compound key", function () {
|
|
141
141
|
|
142
142
|
describe("basic Index with map fun", function () {
|
143
143
|
let db: Database;
|
144
|
-
let indexer: Index<
|
144
|
+
let indexer: Index<TestType, string>;
|
145
145
|
const sthis = ensureSuperThis();
|
146
146
|
afterEach(async () => {
|
147
147
|
await db.close();
|
@@ -155,7 +155,7 @@ describe("basic Index with map fun", function () {
|
|
155
155
|
await db.put({ title: "amazing" });
|
156
156
|
await db.put({ title: "creative" });
|
157
157
|
await db.put({ title: "bazillas" });
|
158
|
-
indexer = new Index<
|
158
|
+
indexer = new Index<TestType, string>(sthis, db.ledger.crdt, "hello", (doc, map) => {
|
159
159
|
map(doc.title);
|
160
160
|
});
|
161
161
|
await indexer.ready();
|
@@ -171,7 +171,7 @@ describe("basic Index with map fun", function () {
|
|
171
171
|
|
172
172
|
describe("basic Index with map fun with value", function () {
|
173
173
|
let db: Database;
|
174
|
-
let indexer: Index<
|
174
|
+
let indexer: Index<TestType, string, number>;
|
175
175
|
const sthis = ensureSuperThis();
|
176
176
|
afterEach(async () => {
|
177
177
|
await db.close();
|
@@ -183,7 +183,7 @@ describe("basic Index with map fun with value", function () {
|
|
183
183
|
await db.put({ title: "amazing" });
|
184
184
|
await db.put({ title: "creative" });
|
185
185
|
await db.put({ title: "bazillas" });
|
186
|
-
indexer = new Index<
|
186
|
+
indexer = new Index<TestType, string, number>(sthis, db.ledger.crdt, "hello", (doc, map) => {
|
187
187
|
map(doc.title, doc.title.length);
|
188
188
|
});
|
189
189
|
});
|
@@ -209,7 +209,7 @@ describe("basic Index with map fun with value", function () {
|
|
209
209
|
|
210
210
|
describe("Index query with map and compound key", function () {
|
211
211
|
let db: Database;
|
212
|
-
let indexer: Index<[string, number]
|
212
|
+
let indexer: Index<TestType, [string, number]>;
|
213
213
|
const sthis = ensureSuperThis();
|
214
214
|
afterEach(async () => {
|
215
215
|
await db.close();
|
@@ -224,7 +224,7 @@ describe("Index query with map and compound key", function () {
|
|
224
224
|
await db.put({ title: "creative", score: 2 });
|
225
225
|
await db.put({ title: "creative", score: 20 });
|
226
226
|
await db.put({ title: "bazillas", score: 3 });
|
227
|
-
indexer = new Index<[string, number]
|
227
|
+
indexer = new Index<TestType, [string, number]>(sthis, db.ledger.crdt, "hello", (doc, emit) => {
|
228
228
|
emit([doc.title, doc.score]);
|
229
229
|
});
|
230
230
|
await indexer.ready();
|
@@ -239,7 +239,7 @@ describe("Index query with map and compound key", function () {
|
|
239
239
|
|
240
240
|
describe("basic Index with string fun", function () {
|
241
241
|
let db: Database;
|
242
|
-
let indexer: Index<
|
242
|
+
let indexer: Index<TestType, string>;
|
243
243
|
const sthis = ensureSuperThis();
|
244
244
|
afterEach(async () => {
|
245
245
|
await db.close();
|
@@ -253,7 +253,7 @@ describe("basic Index with string fun", function () {
|
|
253
253
|
await db.put({ title: "amazing" });
|
254
254
|
await db.put({ title: "creative" });
|
255
255
|
await db.put({ title: "bazillas" });
|
256
|
-
indexer = new Index<
|
256
|
+
indexer = new Index<TestType, string>(sthis, db.ledger.crdt, "title");
|
257
257
|
await indexer.ready();
|
258
258
|
});
|
259
259
|
it("should get results", async () => {
|
@@ -271,7 +271,7 @@ describe("basic Index with string fun", function () {
|
|
271
271
|
|
272
272
|
describe("basic Index with string fun and numeric keys", function () {
|
273
273
|
let db: Database;
|
274
|
-
let indexer: Index<
|
274
|
+
let indexer: Index<TestType, string>;
|
275
275
|
const sthis = ensureSuperThis();
|
276
276
|
afterEach(async () => {
|
277
277
|
await db.close();
|
@@ -286,7 +286,7 @@ describe("basic Index with string fun and numeric keys", function () {
|
|
286
286
|
await db.put({ points: 1 });
|
287
287
|
await db.put({ points: 2 });
|
288
288
|
await db.put({ points: 3 });
|
289
|
-
indexer = new Index<
|
289
|
+
indexer = new Index<TestType, string>(sthis, db.ledger.crdt, "points");
|
290
290
|
await indexer.ready();
|
291
291
|
});
|
292
292
|
it("should get results", async () => {
|
@@ -308,10 +308,10 @@ describe("basic Index upon cold start", function () {
|
|
308
308
|
score?: number;
|
309
309
|
}
|
310
310
|
let crdt: CRDT;
|
311
|
-
let indexer: Index<
|
311
|
+
let indexer: Index<TestType>;
|
312
312
|
let didMap: number;
|
313
313
|
let mapFn: (doc: TestType) => string;
|
314
|
-
let result: IndexRows<
|
314
|
+
let result: IndexRows<TestType>;
|
315
315
|
const sthis = ensureSuperThis();
|
316
316
|
let dbOpts: LedgerOpts;
|
317
317
|
// result, mapFn;
|
@@ -346,7 +346,7 @@ describe("basic Index upon cold start", function () {
|
|
346
346
|
didMap++;
|
347
347
|
return doc.title;
|
348
348
|
};
|
349
|
-
indexer = await index<
|
349
|
+
indexer = await index<TestType>(crdt, "hello", mapFn);
|
350
350
|
logger.Debug().Msg("post index beforeEach");
|
351
351
|
await indexer.ready();
|
352
352
|
logger.Debug().Msg("post indexer.ready beforeEach");
|
@@ -371,7 +371,7 @@ describe("basic Index upon cold start", function () {
|
|
371
371
|
const { result, head } = await crdt2.changes();
|
372
372
|
expect(result).toBeTruthy();
|
373
373
|
await crdt2.ready();
|
374
|
-
const indexer2 = await index<
|
374
|
+
const indexer2 = await index<TestType>(crdt2, "hello", mapFn);
|
375
375
|
await indexer2.ready();
|
376
376
|
const result2 = await indexer2.query();
|
377
377
|
expect(indexer2.indexHead).toEqual(head);
|
@@ -407,7 +407,7 @@ describe("basic Index upon cold start", function () {
|
|
407
407
|
});
|
408
408
|
it("should ignore meta when map function definiton changes", async () => {
|
409
409
|
const crdt2 = new CRDTImpl(sthis, dbOpts);
|
410
|
-
const result = await index<
|
410
|
+
const result = await index<TestType>(crdt2, "hello", (doc) => doc.title.split("").reverse().join("")).query();
|
411
411
|
expect(result.rows.length).toEqual(3);
|
412
412
|
expect(result.rows[0].key).toEqual("evitaerc"); // creative
|
413
413
|
});
|
@@ -415,7 +415,7 @@ describe("basic Index upon cold start", function () {
|
|
415
415
|
|
416
416
|
describe("basic Index with no data", function () {
|
417
417
|
let db: Database;
|
418
|
-
let indexer: Index<
|
418
|
+
let indexer: Index<TestType>;
|
419
419
|
let didMap: boolean;
|
420
420
|
const sthis = ensureSuperThis();
|
421
421
|
afterEach(async () => {
|
@@ -427,7 +427,7 @@ describe("basic Index with no data", function () {
|
|
427
427
|
beforeEach(async () => {
|
428
428
|
await sthis.start();
|
429
429
|
db = fireproof("test-indexer");
|
430
|
-
indexer = new Index<
|
430
|
+
indexer = new Index<TestType>(sthis, db.ledger.crdt, "hello", (doc) => {
|
431
431
|
didMap = true;
|
432
432
|
return doc.title;
|
433
433
|
});
|