diff --git a/CHANGELOG.md b/CHANGELOG.md index 23d74e3..0819f21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.15.6 + +## Additions + +- Fixed order of transactions returned by `iterate` and `listAll` + ## 0.15.5 ## Additions diff --git a/db.db b/db.db deleted file mode 100644 index 7cc5ed7..0000000 Binary files a/db.db and /dev/null differ diff --git a/deno.json b/deno.json index b7fe083..ab53666 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@cross/kv", - "version": "0.15.5", + "version": "0.15.6", "exports": { ".": "./mod.ts", "./cli": "./src/cli/mod.ts" diff --git a/src/lib/index.ts b/src/lib/index.ts index 47594f2..8e8da5f 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -175,10 +175,8 @@ export class KVIndex { recurse(this.index, 0); // Sort the array by transaction offset, to give results sorted in insertion order - resultSet.sort(); - - // Reverse if requested, after sorting - if (reverse) resultSet.reverse(); + // - Reverse if requested + resultSet.sort((a, b) => reverse ? b - a : a - b); // Limit if requested, after sorting and reversing if (limit !== undefined) resultSet.splice(limit); diff --git a/src/lib/kv.ts b/src/lib/kv.ts index 7f559fc..e288ea8 100644 --- a/src/lib/kv.ts +++ b/src/lib/kv.ts @@ -534,6 +534,7 @@ export class KV extends EventEmitter { this.ensureOpen(); this.ensureIndex(); const validatedKey = new KVKeyInstance(key, true); + const offsets = this.index!.get(validatedKey, limit, reverse)!; if (offsets === null || offsets.length === 0) { @@ -547,7 +548,6 @@ export class KV extends EventEmitter { yield result.transaction.asResult(); count++; } - if (limit && count >= limit) break; } } diff --git a/test/kv.test.ts b/test/kv.test.ts index 8eb74e9..d9135bc 100644 --- a/test/kv.test.ts +++ b/test/kv.test.ts @@ -702,3 +702,37 @@ test("KV: listAll in reverse order with limit", async () => { assertEquals(results, expectedValues); await kvStore.close(); }); + +test("KV: iterate and listAll respect reverse insertion order with multiple key matches", async () => { + const tempFilePrefix = await tempfile(); + const kvStore = new KV(); + await kvStore.open(tempFilePrefix); + + // Inserting items with a common prefix and different suffixes + await kvStore.set(["data", "d", "b"], "Value A"); + await kvStore.set(["data", "c", "a"], "Value B"); + await kvStore.set(["data", "c", "b"], "Value C"); + await kvStore.set(["data", "a"], "Value D"); + + // Iterate in reverse order + const iterateResults = []; + for await (const entry of kvStore.iterate(["data"], undefined, true)) { + iterateResults.push(entry.data); + } + assertEquals(iterateResults, ["Value D", "Value C", "Value B", "Value A"]); + + // ListAll in reverse order + const listAllResults = (await kvStore.listAll(["data"], undefined, true)).map( + (entry) => entry.data, + ); + assertEquals(listAllResults, ["Value D", "Value C", "Value B", "Value A"]); + + // ListAll in insertion order + const listAllResults2 = (await kvStore.listAll(["data"], undefined, false)) + .map( + (entry) => entry.data, + ); + assertEquals(listAllResults2, ["Value A", "Value B", "Value C", "Value D"]); + + await kvStore.close(); +});