Loading packages/cfworkers/src/mod.test.ts +22 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,28 @@ describe("WorkersKvStore", { strictEqual(entries.length, 1); strictEqual(entries[0].value, "value-a"); }); test("list() - empty prefix", async (t) => { const { env } = t as unknown as { env: Record<string, KVNamespace<string>>; }; const store = new WorkersKvStore(env.KV1); await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: readonly unknown[]; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push({ key: entry.key, value: entry.value }); } strictEqual(entries.length, 3); }); }); describe("WorkersMessageQueue", { Loading packages/cfworkers/src/mod.ts +69 −41 Original line number Diff line number Diff line Loading @@ -93,6 +93,33 @@ export class WorkersKvStore implements KvStore { async *list( options: KvStoreListOptions, ): AsyncIterable<KvStoreListEntry> { if (options.prefix.length === 0) { // Empty prefix: list all entries // JSON encoded keys start with '[', so prefix with '[' to match all arrays let cursor: string | undefined; do { const result = await this.#namespace.list<KvMetadata>({ prefix: "[", cursor, }); cursor = result.list_complete ? undefined : result.cursor; for (const keyInfo of result.keys) { const metadata = keyInfo.metadata as KvMetadata | undefined; if (metadata?.expires != null && metadata.expires < Date.now()) { continue; } const value = await this.#namespace.get(keyInfo.name, "json"); if (value == null) continue; yield { key: JSON.parse(keyInfo.name) as KvKey, value, }; } } while (cursor != null); } else { // Keys are JSON encoded: '["prefix","a"]' // Pattern to match keys starting with prefix: '["prefix",' matches children // Also check for exact match: '["prefix"]' Loading Loading @@ -141,6 +168,7 @@ export class WorkersKvStore implements KvStore { } while (cursor != null); } } } /** * Implementation of the {@link MessageQueue} interface for Cloudflare Loading packages/denokv/src/mod.test.ts +25 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,31 @@ Deno.test("DenoKvStore", async (t) => { await store.delete(["b"]); }); await t.step("list() - empty prefix", async () => { // Cleanup from previous tests await store.delete(["foo", "bar"]); await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: Deno.KvKey; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push(entry); } assertEquals(entries.length, 3); // Cleanup await store.delete(["a"]); await store.delete(["b", "c"]); await store.delete(["d", "e", "f"]); }); kv.close(); }); Loading packages/fedify/src/federation/kv.test.ts +23 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,27 @@ test("MemoryKvStore", async (t) => { await store.delete(["expired", "valid"]); }); await t.step("list() with empty prefix", async () => { // Cleanup from previous tests await store.delete(["foo", "bar"]); // Setup: add entries with various key structures await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); // Test: empty prefix should return all entries const entries: { key: KvKey; value: unknown }[] = []; for await (const entry of store.list!({ prefix: [] as unknown as KvKey })) { entries.push(entry); } assertEquals(entries.length, 3); // Cleanup await store.delete(["a"]); await store.delete(["b", "c"]); await store.delete(["d", "e", "f"]); }); }); packages/postgres/src/kv.test.ts +28 −0 Original line number Diff line number Diff line Loading @@ -221,4 +221,32 @@ test( }, ); test( "PostgresKvStore.list() - empty prefix", { skip: dbUrl == null }, async () => { if (dbUrl == null) return; // Bun does not support skip option const { sql, store } = getStore(); try { await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: readonly string[]; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push({ key: entry.key, value: entry.value }); } assert.strictEqual(entries.length, 3); } finally { await store.drop(); await sql.end(); } }, ); // cSpell: ignore regclass Loading
packages/cfworkers/src/mod.test.ts +22 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,28 @@ describe("WorkersKvStore", { strictEqual(entries.length, 1); strictEqual(entries[0].value, "value-a"); }); test("list() - empty prefix", async (t) => { const { env } = t as unknown as { env: Record<string, KVNamespace<string>>; }; const store = new WorkersKvStore(env.KV1); await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: readonly unknown[]; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push({ key: entry.key, value: entry.value }); } strictEqual(entries.length, 3); }); }); describe("WorkersMessageQueue", { Loading
packages/cfworkers/src/mod.ts +69 −41 Original line number Diff line number Diff line Loading @@ -93,6 +93,33 @@ export class WorkersKvStore implements KvStore { async *list( options: KvStoreListOptions, ): AsyncIterable<KvStoreListEntry> { if (options.prefix.length === 0) { // Empty prefix: list all entries // JSON encoded keys start with '[', so prefix with '[' to match all arrays let cursor: string | undefined; do { const result = await this.#namespace.list<KvMetadata>({ prefix: "[", cursor, }); cursor = result.list_complete ? undefined : result.cursor; for (const keyInfo of result.keys) { const metadata = keyInfo.metadata as KvMetadata | undefined; if (metadata?.expires != null && metadata.expires < Date.now()) { continue; } const value = await this.#namespace.get(keyInfo.name, "json"); if (value == null) continue; yield { key: JSON.parse(keyInfo.name) as KvKey, value, }; } } while (cursor != null); } else { // Keys are JSON encoded: '["prefix","a"]' // Pattern to match keys starting with prefix: '["prefix",' matches children // Also check for exact match: '["prefix"]' Loading Loading @@ -141,6 +168,7 @@ export class WorkersKvStore implements KvStore { } while (cursor != null); } } } /** * Implementation of the {@link MessageQueue} interface for Cloudflare Loading
packages/denokv/src/mod.test.ts +25 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,31 @@ Deno.test("DenoKvStore", async (t) => { await store.delete(["b"]); }); await t.step("list() - empty prefix", async () => { // Cleanup from previous tests await store.delete(["foo", "bar"]); await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: Deno.KvKey; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push(entry); } assertEquals(entries.length, 3); // Cleanup await store.delete(["a"]); await store.delete(["b", "c"]); await store.delete(["d", "e", "f"]); }); kv.close(); }); Loading
packages/fedify/src/federation/kv.test.ts +23 −0 Original line number Diff line number Diff line Loading @@ -88,4 +88,27 @@ test("MemoryKvStore", async (t) => { await store.delete(["expired", "valid"]); }); await t.step("list() with empty prefix", async () => { // Cleanup from previous tests await store.delete(["foo", "bar"]); // Setup: add entries with various key structures await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); // Test: empty prefix should return all entries const entries: { key: KvKey; value: unknown }[] = []; for await (const entry of store.list!({ prefix: [] as unknown as KvKey })) { entries.push(entry); } assertEquals(entries.length, 3); // Cleanup await store.delete(["a"]); await store.delete(["b", "c"]); await store.delete(["d", "e", "f"]); }); });
packages/postgres/src/kv.test.ts +28 −0 Original line number Diff line number Diff line Loading @@ -221,4 +221,32 @@ test( }, ); test( "PostgresKvStore.list() - empty prefix", { skip: dbUrl == null }, async () => { if (dbUrl == null) return; // Bun does not support skip option const { sql, store } = getStore(); try { await store.set(["a"], "value-a"); await store.set(["b", "c"], "value-bc"); await store.set(["d", "e", "f"], "value-def"); const entries: { key: readonly string[]; value: unknown }[] = []; for await ( const entry of store.list!({ prefix: [] as unknown as readonly [string, ...string[]], }) ) { entries.push({ key: entry.key, value: entry.value }); } assert.strictEqual(entries.length, 3); } finally { await store.drop(); await sql.end(); } }, ); // cSpell: ignore regclass