@fireproof/core 0.20.5 → 0.21.0-dev-preview-3

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 (152) hide show
  1. package/blockstore/commitor.js +3 -3
  2. package/blockstore/commitor.js.map +1 -1
  3. package/blockstore/loader.d.ts +2 -1
  4. package/blockstore/loader.d.ts.map +1 -1
  5. package/blockstore/loader.js +40 -10
  6. package/blockstore/loader.js.map +1 -1
  7. package/blockstore/store.js +1 -1
  8. package/blockstore/store.js.map +1 -1
  9. package/crdt.d.ts +1 -1
  10. package/crdt.d.ts.map +1 -1
  11. package/crdt.js.map +1 -1
  12. package/database.d.ts +2 -3
  13. package/database.d.ts.map +1 -1
  14. package/database.js +7 -3
  15. package/database.js.map +1 -1
  16. package/deno.json +1 -1
  17. package/index.d.ts +1 -0
  18. package/index.d.ts.map +1 -1
  19. package/index.js +1 -0
  20. package/index.js.map +1 -1
  21. package/indexer-helpers.d.ts +29 -28
  22. package/indexer-helpers.d.ts.map +1 -1
  23. package/indexer-helpers.js +21 -3
  24. package/indexer-helpers.js.map +1 -1
  25. package/indexer.d.ts +3 -3
  26. package/indexer.d.ts.map +1 -1
  27. package/indexer.js +16 -24
  28. package/indexer.js.map +1 -1
  29. package/ledger.d.ts +3 -2
  30. package/ledger.d.ts.map +1 -1
  31. package/ledger.js +7 -4
  32. package/ledger.js.map +1 -1
  33. package/package.json +2 -2
  34. package/protocols/cloud/http-connection.d.ts +2 -1
  35. package/protocols/cloud/http-connection.d.ts.map +1 -1
  36. package/protocols/cloud/http-connection.js +1 -0
  37. package/protocols/cloud/http-connection.js.map +1 -1
  38. package/protocols/cloud/msg-types-data.d.ts +4 -4
  39. package/protocols/cloud/msg-types-data.d.ts.map +1 -1
  40. package/protocols/cloud/msg-types-data.js.map +1 -1
  41. package/protocols/cloud/msg-types-meta.d.ts +13 -13
  42. package/protocols/cloud/msg-types-meta.d.ts.map +1 -1
  43. package/protocols/cloud/msg-types-meta.js.map +1 -1
  44. package/protocols/cloud/msg-types-wal.d.ts +4 -4
  45. package/protocols/cloud/msg-types-wal.d.ts.map +1 -1
  46. package/protocols/cloud/msg-types-wal.js.map +1 -1
  47. package/protocols/cloud/msg-types.d.ts +33 -19
  48. package/protocols/cloud/msg-types.d.ts.map +1 -1
  49. package/protocols/cloud/msg-types.js +4 -1
  50. package/protocols/cloud/msg-types.js.map +1 -1
  51. package/protocols/cloud/msger.d.ts +47 -38
  52. package/protocols/cloud/msger.d.ts.map +1 -1
  53. package/protocols/cloud/msger.js +211 -106
  54. package/protocols/cloud/msger.js.map +1 -1
  55. package/protocols/cloud/ws-connection.d.ts +14 -3
  56. package/protocols/cloud/ws-connection.d.ts.map +1 -1
  57. package/protocols/cloud/ws-connection.js +73 -34
  58. package/protocols/cloud/ws-connection.js.map +1 -1
  59. package/protocols/dashboard/index.d.ts +4 -0
  60. package/protocols/dashboard/index.d.ts.map +1 -0
  61. package/protocols/dashboard/index.js +4 -0
  62. package/protocols/dashboard/index.js.map +1 -0
  63. package/protocols/dashboard/msg-api.d.ts +11 -0
  64. package/protocols/dashboard/msg-api.d.ts.map +1 -0
  65. package/protocols/dashboard/msg-api.js +55 -0
  66. package/protocols/dashboard/msg-api.js.map +1 -0
  67. package/protocols/dashboard/msg-is.d.ts +45 -0
  68. package/protocols/dashboard/msg-is.d.ts.map +1 -0
  69. package/protocols/dashboard/msg-is.js +63 -0
  70. package/protocols/dashboard/msg-is.js.map +1 -0
  71. package/protocols/dashboard/msg-types.d.ts +397 -0
  72. package/protocols/dashboard/msg-types.d.ts.map +1 -0
  73. package/protocols/dashboard/msg-types.js +4 -0
  74. package/protocols/dashboard/msg-types.js.map +1 -0
  75. package/protocols/index.d.ts +1 -0
  76. package/protocols/index.d.ts.map +1 -1
  77. package/protocols/index.js +1 -0
  78. package/protocols/index.js.map +1 -1
  79. package/react/img-file.d.ts +2 -2
  80. package/react/img-file.d.ts.map +1 -1
  81. package/react/img-file.js +62 -27
  82. package/react/img-file.js.map +1 -1
  83. package/react/types.d.ts +29 -9
  84. package/react/types.d.ts.map +1 -1
  85. package/react/use-all-docs.d.ts +1 -1
  86. package/react/use-all-docs.d.ts.map +1 -1
  87. package/react/use-all-docs.js.map +1 -1
  88. package/react/use-attach.d.ts +9 -4
  89. package/react/use-attach.d.ts.map +1 -1
  90. package/react/use-attach.js +136 -43
  91. package/react/use-attach.js.map +1 -1
  92. package/react/use-fireproof.js +2 -2
  93. package/react/use-fireproof.js.map +1 -1
  94. package/react/use-live-query.d.ts.map +1 -1
  95. package/react/use-live-query.js +1 -4
  96. package/react/use-live-query.js.map +1 -1
  97. package/runtime/gateways/cloud/gateway.d.ts +8 -8
  98. package/runtime/gateways/cloud/gateway.d.ts.map +1 -1
  99. package/runtime/gateways/cloud/gateway.js +17 -15
  100. package/runtime/gateways/cloud/gateway.js.map +1 -1
  101. package/runtime/gateways/cloud/to-cloud.d.ts +22 -9
  102. package/runtime/gateways/cloud/to-cloud.d.ts.map +1 -1
  103. package/runtime/gateways/cloud/to-cloud.js +75 -59
  104. package/runtime/gateways/cloud/to-cloud.js.map +1 -1
  105. package/runtime/gateways/file/key-bag-file.d.ts +1 -0
  106. package/runtime/gateways/file/key-bag-file.d.ts.map +1 -1
  107. package/runtime/gateways/file/key-bag-file.js +12 -0
  108. package/runtime/gateways/file/key-bag-file.js.map +1 -1
  109. package/runtime/gateways/indexeddb/gateway-impl.d.ts.map +1 -1
  110. package/runtime/gateways/indexeddb/gateway-impl.js.map +1 -1
  111. package/runtime/gateways/indexeddb/key-bag-indexeddb.d.ts +1 -0
  112. package/runtime/gateways/indexeddb/key-bag-indexeddb.d.ts.map +1 -1
  113. package/runtime/gateways/indexeddb/key-bag-indexeddb.js +6 -0
  114. package/runtime/gateways/indexeddb/key-bag-indexeddb.js.map +1 -1
  115. package/runtime/key-bag-memory.d.ts +1 -0
  116. package/runtime/key-bag-memory.d.ts.map +1 -1
  117. package/runtime/key-bag-memory.js +7 -0
  118. package/runtime/key-bag-memory.js.map +1 -1
  119. package/runtime/key-bag.d.ts +3 -0
  120. package/runtime/key-bag.d.ts.map +1 -1
  121. package/runtime/key-bag.js +6 -0
  122. package/runtime/key-bag.js.map +1 -1
  123. package/tests/fireproof/attachable.test.ts +1 -1
  124. package/tests/fireproof/charwise-boolean.test.ts +66 -0
  125. package/tests/fireproof/crdt.test.ts +3 -3
  126. package/tests/fireproof/deleted-docs-handling.test.ts +111 -0
  127. package/tests/fireproof/fireproof.test.ts +10 -10
  128. package/tests/fireproof/hello.test.ts +1 -1
  129. package/tests/fireproof/indexer.test.ts +21 -21
  130. package/tests/fireproof/query-docs.test.ts +42 -7
  131. package/tests/fireproof/query-limit-issue.test.ts +147 -0
  132. package/tests/fireproof/query-property-inconsistency.test.ts +89 -0
  133. package/tests/fireproof/query-result-properties.test.ts +42 -0
  134. package/tests/protocols/cloud/msger.test.ts +563 -0
  135. package/types.d.ts +9 -9
  136. package/types.d.ts.map +1 -1
  137. package/types.js.map +1 -1
  138. package/use-fireproof/iframe-strategy.d.ts +6 -4
  139. package/use-fireproof/iframe-strategy.d.ts.map +1 -1
  140. package/use-fireproof/iframe-strategy.js +7 -11
  141. package/use-fireproof/iframe-strategy.js.map +1 -1
  142. package/use-fireproof/index.d.ts +6 -2
  143. package/use-fireproof/index.d.ts.map +1 -1
  144. package/use-fireproof/index.js +23 -3
  145. package/use-fireproof/index.js.map +1 -1
  146. package/use-fireproof/redirect-strategy.d.ts +11 -4
  147. package/use-fireproof/redirect-strategy.d.ts.map +1 -1
  148. package/use-fireproof/redirect-strategy.js +142 -20
  149. package/use-fireproof/redirect-strategy.js.map +1 -1
  150. package/utils.d.ts +3 -0
  151. package/utils.d.ts.map +1 -1
  152. package/utils.js.map +1 -1
@@ -23,7 +23,7 @@ interface TestType {
23
23
 
24
24
  describe("basic Index", () => {
25
25
  let db: Database;
26
- let indexer: Index<string, TestType>;
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<string, TestType>(sthis, db.ledger.crdt, "hello", (doc) => {
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], TestType>;
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], TestType>(sthis, db.ledger.crdt, "hello", (doc) => {
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<string, TestType>;
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<string, TestType>(sthis, db.ledger.crdt, "hello", (doc, map) => {
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<string, TestType, number>;
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<string, TestType, number>(sthis, db.ledger.crdt, "hello", (doc, map) => {
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], TestType>;
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], TestType>(sthis, db.ledger.crdt, "hello", (doc, emit) => {
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<string, TestType>;
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<string, TestType>(sthis, db.ledger.crdt, "title");
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<string, TestType>;
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<string, TestType>(sthis, db.ledger.crdt, "points");
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<string, TestType>;
311
+ let indexer: Index<TestType>;
312
312
  let didMap: number;
313
313
  let mapFn: (doc: TestType) => string;
314
- let result: IndexRows<string, TestType>;
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<string, TestType>(crdt, "hello", mapFn);
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<string, TestType>(crdt2, "hello", mapFn);
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<string, TestType>(crdt2, "hello", (doc) => doc.title.split("").reverse().join("")).query();
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<string, TestType>;
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<string, TestType>(sthis, db.ledger.crdt, "hello", (doc) => {
430
+ indexer = new Index<TestType>(sthis, db.ledger.crdt, "hello", (doc) => {
431
431
  didMap = true;
432
432
  return doc.title;
433
433
  });
@@ -1,5 +1,4 @@
1
- import { describe, it, beforeEach, afterEach, expect } from "vitest";
2
- import { Database, DocWithId, ensureSuperThis, fireproof } from "@fireproof/core";
1
+ import { Database, DocWithId, fireproof } from "@fireproof/core";
3
2
 
4
3
  interface TestDoc {
5
4
  text: string;
@@ -9,10 +8,8 @@ interface TestDoc {
9
8
 
10
9
  describe("query return value consistency", function () {
11
10
  let db: Database;
12
- const sthis = ensureSuperThis();
13
11
 
14
12
  beforeEach(async () => {
15
- await sthis.start();
16
13
  db = fireproof("test-query-docs");
17
14
 
18
15
  // Add test documents
@@ -28,7 +25,7 @@ describe("query return value consistency", function () {
28
25
 
29
26
  it("database query should return docs property like useLiveQuery", async function () {
30
27
  // This test should initially fail because the query method doesn't return docs yet
31
- const result = await db.query<string, TestDoc>("category");
28
+ const result = await db.query<TestDoc>("category");
32
29
 
33
30
  // Check that rows property exists (this should pass)
34
31
  expect(result).toHaveProperty("rows");
@@ -45,7 +42,7 @@ describe("query return value consistency", function () {
45
42
  });
46
43
 
47
44
  it("should return docs with the same order as rows", async function () {
48
- const result = await db.query<string, TestDoc>("category");
45
+ const result = await db.query<TestDoc>("category");
49
46
 
50
47
  // Ensure docs array exists
51
48
  expect(result).toHaveProperty("docs");
@@ -60,7 +57,7 @@ describe("query return value consistency", function () {
60
57
 
61
58
  it("should work with complex map functions and query options", async function () {
62
59
  // Test with a map function and query options
63
- const result = await db.query<boolean, TestDoc>((doc) => doc.active, {
60
+ const result = await db.query<TestDoc, boolean>((doc) => doc.active, {
64
61
  key: true,
65
62
  includeDocs: true,
66
63
  });
@@ -78,4 +75,42 @@ describe("query return value consistency", function () {
78
75
  expect((doc as DocWithId<TestDoc>).active).toBe(true);
79
76
  });
80
77
  });
78
+
79
+ it("should only return docs with false value when queried with {key: false}", async function () {
80
+ // Test with a map function and query options for false value
81
+ const result = await db.query<TestDoc, boolean>((doc) => doc.active, {
82
+ key: false,
83
+ includeDocs: true,
84
+ });
85
+
86
+ // Should only return documents where active is false
87
+ expect(result.rows.length).toBe(1); // We only have one document with active: false
88
+
89
+ // Check docs property exists and matches rows length
90
+ expect(result).toHaveProperty("docs");
91
+ expect(result.docs.length).toBe(result.rows.length);
92
+
93
+ // Verify all returned docs have active set to false
94
+ result.docs.forEach((doc) => {
95
+ expect((doc as DocWithId<TestDoc>).active).toBe(false);
96
+ });
97
+
98
+ // Make sure no documents with active: true are included
99
+ const activeTrue = result.docs.filter((doc) => (doc as DocWithId<TestDoc>).active === true);
100
+ expect(activeTrue.length).toBe(0); // No active: true docs should be included
101
+
102
+ // Now run a query with key: true for comparison
103
+ const trueResult = await db.query<TestDoc, boolean>((doc) => doc.active, {
104
+ key: true,
105
+ includeDocs: true,
106
+ });
107
+
108
+ // This correctly returns only active: true documents
109
+ expect(trueResult.rows.length).toBe(2);
110
+
111
+ // All returned docs have active set to true
112
+ trueResult.docs.forEach((doc) => {
113
+ expect((doc as DocWithId<TestDoc>).active).toBe(true);
114
+ });
115
+ });
81
116
  });
@@ -0,0 +1,147 @@
1
+ import { describe, it, beforeEach, afterEach, expect } from "vitest";
2
+ import { Database, fireproof } from "@fireproof/core";
3
+
4
+ interface TodoDoc {
5
+ task: string;
6
+ completed: boolean;
7
+ priority?: number;
8
+ }
9
+
10
+ describe("query limit handling", () => {
11
+ let db: Database;
12
+
13
+ beforeEach(async () => {
14
+ db = await fireproof("test-query-limit");
15
+
16
+ // Create multiple documents with different completed values and priorities
17
+ await db.put({ _id: "task1", task: "Task 1", completed: true, priority: 1 });
18
+ await db.put({ _id: "task2", task: "Task 2", completed: true, priority: 2 });
19
+ await db.put({ _id: "task3", task: "Task 3", completed: false, priority: 3 });
20
+ await db.put({ _id: "task4", task: "Task 4", completed: false, priority: 4 });
21
+ await db.put({ _id: "task5", task: "Task 5", completed: true, priority: 5 });
22
+ });
23
+
24
+ afterEach(async () => {
25
+ await db.destroy();
26
+ });
27
+
28
+ // PASSING CASES - These should work correctly with the current implementation
29
+
30
+ it("should correctly limit results for regular queries", async () => {
31
+ // Regular query with limit (no key/keys specified)
32
+ const queryResult = await db.query("completed", {
33
+ includeDocs: false,
34
+ limit: 2,
35
+ });
36
+
37
+ // This should pass - limit should work for regular queries
38
+ expect(queryResult.rows.length).toBe(2);
39
+ });
40
+
41
+ it("should correctly limit results for 'key' parameter queries", async () => {
42
+ // Query with a single key and limit
43
+ const queryResult = await db.query("completed", {
44
+ key: true,
45
+ includeDocs: false,
46
+ limit: 2,
47
+ });
48
+
49
+ // This should pass - limit should work for queries with 'key' option
50
+ expect(queryResult.rows.length).toBe(2);
51
+
52
+ // All results should have completed=true
53
+ queryResult.rows.forEach((row) => {
54
+ expect(row.key).toBe(true);
55
+ });
56
+ });
57
+
58
+ it("should correctly limit range query results", async () => {
59
+ // Query with range and limit
60
+ const queryResult = await db.query("priority", {
61
+ range: [2, 4],
62
+ includeDocs: false,
63
+ limit: 2,
64
+ });
65
+
66
+ // This should pass - limit should work for range queries
67
+ expect(queryResult.rows.length).toBe(2);
68
+
69
+ // All results should have priority between 2 and 4
70
+ queryResult.rows.forEach((row) => {
71
+ expect(row.key).toBeGreaterThanOrEqual(2);
72
+ expect(row.key).toBeLessThanOrEqual(4);
73
+ });
74
+ });
75
+
76
+ // FAILING CASES - These demonstrate the current bug
77
+
78
+ it("should respect the limit option with 'keys' parameter (currently failing)", async () => {
79
+ // Query with multiple keys and limit=1
80
+ // This should return only 1 result total, but currently returns 1 per key
81
+ const queryResult = await db.query("completed", {
82
+ keys: [true, false],
83
+ includeDocs: false,
84
+ limit: 1,
85
+ });
86
+
87
+ // This assertion will fail with the current implementation
88
+ // Current behavior: Returns limit=1 for EACH key, so 2 results total
89
+ // Expected behavior: Returns limit=1 across ALL keys combined
90
+ expect(queryResult.rows.length).toBe(1);
91
+ });
92
+
93
+ it("should apply limit correctly to combined results from multiple keys", async () => {
94
+ // Query with multiple keys and limit=3
95
+ // Should return exactly 3 results total
96
+ const queryResult = await db.query<TodoDoc, boolean>("completed", {
97
+ keys: [true, false],
98
+ includeDocs: false,
99
+ limit: 3,
100
+ });
101
+
102
+ // This assertion verifies that limit is applied to the combined result
103
+ expect(queryResult.rows.length).toBe(3);
104
+ });
105
+
106
+ it("demonstrates the limit+1 issue with the 'keys' parameter", async () => {
107
+ // Create a controlled test case with exact document counts
108
+ await db.destroy();
109
+ db = await fireproof("test-exact-limit");
110
+
111
+ // Create exactly 2 documents with completed=true and 2 with completed=false
112
+ await db.put({ _id: "doc1", task: "Doc 1", completed: true });
113
+ await db.put({ _id: "doc2", task: "Doc 2", completed: true });
114
+ await db.put({ _id: "doc3", task: "Doc 3", completed: false });
115
+ await db.put({ _id: "doc4", task: "Doc 4", completed: false });
116
+
117
+ // Query with limit=1 - should return exactly 1 result total
118
+ const result1 = await db.query("completed", {
119
+ keys: [true, false],
120
+ limit: 1,
121
+ includeDocs: false,
122
+ });
123
+
124
+ // Will fail - returns 2 instead of 1
125
+ expect(result1.rows.length).toBe(1);
126
+
127
+ // Query with limit=2 - should return exactly 2 results total
128
+ const result2 = await db.query("completed", {
129
+ keys: [true, false],
130
+ limit: 2,
131
+ includeDocs: false,
132
+ });
133
+
134
+ // Will fail - returns 4 instead of 2
135
+ expect(result2.rows.length).toBe(2);
136
+
137
+ // Query with limit=3 - should return exactly 3 results total
138
+ const result3 = await db.query("completed", {
139
+ keys: [true, false],
140
+ limit: 3,
141
+ includeDocs: false,
142
+ });
143
+
144
+ // Will fail - returns 4 instead of 3
145
+ expect(result3.rows.length).toBe(3);
146
+ });
147
+ });
@@ -0,0 +1,89 @@
1
+ import { Database, fireproof } from "@fireproof/core";
2
+
3
+ interface TestDoc {
4
+ text: string;
5
+ category: string;
6
+ count: number;
7
+ }
8
+
9
+ describe("query property inconsistency issue", function () {
10
+ let db: Database;
11
+
12
+ beforeEach(async () => {
13
+ db = fireproof("test-query-property-inconsistency");
14
+
15
+ // Add test documents
16
+ await db.put({ _id: "doc1", text: "hello world", category: "greeting", count: 1 });
17
+ await db.put({ _id: "doc2", text: "goodbye world", category: "farewell", count: 2 });
18
+ await db.put({ _id: "doc3", text: "hello again", category: "greeting", count: 3 });
19
+ });
20
+
21
+ afterEach(async () => {
22
+ await db.close();
23
+ await db.destroy();
24
+ });
25
+
26
+ it("demonstrates property inconsistency in query results", async function () {
27
+ // Case 1: Query without key option - should have 'value' property
28
+ const queryNoKey = await db.query<TestDoc>((doc) => doc.category);
29
+
30
+ // Verify it has 'value' property
31
+ expect(queryNoKey.rows[0]).toHaveProperty("value");
32
+
33
+ // Case 2: Query with key option - currently has 'row' property instead of 'value'
34
+ const queryWithKey = await db.query<TestDoc>((doc) => doc.category, {
35
+ key: "greeting",
36
+ });
37
+
38
+ // THIS WILL FAIL - Demonstrating the inconsistency
39
+ // After standardizing on 'value', this assertion should pass
40
+ expect(queryWithKey.rows[0]).toHaveProperty("value");
41
+
42
+ // This assertion will pass after standardizing on 'value' and removing 'row'
43
+ expect(queryWithKey.rows[0]).not.toHaveProperty("row");
44
+ });
45
+
46
+ it("should use consistent property names regardless of query type", async function () {
47
+ // Multiple query variations to test different code paths
48
+
49
+ // 1. Regular query (no options)
50
+ const regularQuery = await db.query<TestDoc>((doc) => doc.category);
51
+
52
+ // 2. Query with key option
53
+ const keyQuery = await db.query<TestDoc>((doc) => doc.category, {
54
+ key: "greeting",
55
+ });
56
+
57
+ // 3. Query with range option
58
+ const rangeQuery = await db.query<TestDoc>((doc) => doc.count, {
59
+ range: [1, 3],
60
+ });
61
+
62
+ // 4. Query with prefix option
63
+ const prefixQuery = await db.query<TestDoc>((doc) => [doc.category, doc.count], {
64
+ prefix: ["greeting"],
65
+ });
66
+
67
+ // Check each query type has the 'value' property
68
+ expect(regularQuery.rows[0]).toHaveProperty("value");
69
+ expect(keyQuery.rows[0]).toHaveProperty("value");
70
+ expect(rangeQuery.rows[0]).toHaveProperty("value");
71
+ expect(prefixQuery.rows[0]).toHaveProperty("value");
72
+
73
+ // Ensure no query has the 'row' property
74
+ expect(regularQuery.rows[0]).not.toHaveProperty("row");
75
+ expect(keyQuery.rows[0]).not.toHaveProperty("row");
76
+ expect(rangeQuery.rows[0]).not.toHaveProperty("row");
77
+ expect(prefixQuery.rows[0]).not.toHaveProperty("row");
78
+
79
+ // Ensure all queries have the same set of properties
80
+ const regularProps = Object.keys(regularQuery.rows[0]).sort();
81
+ const keyProps = Object.keys(keyQuery.rows[0]).sort();
82
+ const rangeProps = Object.keys(rangeQuery.rows[0]).sort();
83
+ const prefixProps = Object.keys(prefixQuery.rows[0]).sort();
84
+
85
+ expect(keyProps).toEqual(regularProps);
86
+ expect(rangeProps).toEqual(regularProps);
87
+ expect(prefixProps).toEqual(regularProps);
88
+ });
89
+ });
@@ -0,0 +1,42 @@
1
+ import { Database, fireproof } from "@fireproof/core";
2
+
3
+ interface TestDoc {
4
+ text: string;
5
+ category: string;
6
+ count: number;
7
+ }
8
+
9
+ describe("query result property consistency", function () {
10
+ let db: Database;
11
+
12
+ beforeEach(async () => {
13
+ db = fireproof("test-query-result-properties");
14
+
15
+ // Add test documents
16
+ await db.put({ _id: "doc1", text: "hello world", category: "greeting", count: 1 });
17
+ await db.put({ _id: "doc2", text: "goodbye world", category: "farewell", count: 2 });
18
+ await db.put({ _id: "doc3", text: "hello again", category: "greeting", count: 3 });
19
+ });
20
+
21
+ afterEach(async () => {
22
+ await db.close();
23
+ await db.destroy();
24
+ });
25
+
26
+ it("should have consistent result properties regardless of query options", async function () {
27
+ // Query without using the key option
28
+ const resultWithoutKey = await db.query<TestDoc>((doc) => doc.category);
29
+
30
+ // Query with the key option
31
+ const resultWithKey = await db.query<TestDoc>((doc) => doc.category, {
32
+ key: "greeting",
33
+ });
34
+
35
+ // Add assertions to check property existence
36
+ const withoutKeyProps = Object.keys(resultWithoutKey.rows[0]);
37
+ const withKeyProps = Object.keys(resultWithKey.rows[0]);
38
+
39
+ // Test if the properties are the same in both cases
40
+ expect(withoutKeyProps).toEqual(withKeyProps);
41
+ });
42
+ });