Skip to content

Commit 84010a4

Browse files
committed
feat: support listing of blobs
1 parent 61446d8 commit 84010a4

File tree

6 files changed

+836
-63
lines changed

6 files changed

+836
-63
lines changed

_test_util.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export { assertEquals } from "jsr:@std/assert@~1/equals";
66
export { assertNotEquals } from "jsr:@std/assert@~1/not-equals";
77
export { assertRejects } from "jsr:@std/assert@~1/rejects";
88
export { assertStrictEquals } from "jsr:@std/assert@~1/strict-equals";
9+
export { assertThrows } from "jsr:@std/assert@~1/throws";
910
export { timingSafeEqual } from "jsr:@std/crypto@~1/timing-safe-equal";
1011

1112
let kv: { close(): void } | undefined;
@@ -16,12 +17,13 @@ export async function getPath() {
1617
}
1718

1819
export async function setup() {
19-
return kv = await Deno.openKv(await getPath());
20+
return kv = await Deno.openKv(":memory:");
2021
}
2122

22-
export function cleanup() {
23-
assert(path);
24-
return Deno.remove(path);
23+
export function cleanup(): Promise<void> | void {
24+
if (path && path !== ":memory:") {
25+
return Deno.remove(path);
26+
}
2527
}
2628

2729
export function teardown() {

blob.test.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
assert,
33
assertEquals,
44
assertRejects,
5+
assertThrows,
56
setup,
67
teardown,
78
timingSafeEqual,
@@ -14,6 +15,7 @@ import {
1415
getAsResponse,
1516
getAsStream,
1617
getMeta,
18+
list,
1719
remove,
1820
set,
1921
toBlob,
@@ -428,6 +430,167 @@ Deno.test({
428430
},
429431
});
430432

433+
Deno.test({
434+
name: "list - default",
435+
async fn() {
436+
const kv = await setup();
437+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
438+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
439+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
440+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
441+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
442+
const entries = await Array.fromAsync(
443+
list(kv, { prefix: ["hello"] }),
444+
);
445+
assertEquals(entries.length, 3);
446+
for (const [idx, entry] of entries.entries()) {
447+
assertEquals(entry.key, ["hello", idx + 1]);
448+
assertEquals(entry.value, { kind: "buffer", size: 3 });
449+
}
450+
return teardown();
451+
},
452+
});
453+
454+
Deno.test({
455+
name: "list - with limit",
456+
async fn() {
457+
const kv = await setup();
458+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
459+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
460+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
461+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
462+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
463+
const entries = await Array.fromAsync(
464+
list(kv, { prefix: ["hello"] }, { limit: 2 }),
465+
);
466+
assertEquals(entries.length, 2);
467+
for (const [idx, entry] of entries.entries()) {
468+
assertEquals(entry.key, ["hello", idx + 1]);
469+
assertEquals(entry.value, { kind: "buffer", size: 3 });
470+
}
471+
return teardown();
472+
},
473+
});
474+
475+
Deno.test({
476+
name: "list - meta",
477+
async fn() {
478+
const kv = await setup();
479+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
480+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
481+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
482+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
483+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
484+
const entries = await Array.fromAsync(
485+
list(kv, { prefix: ["hello"] }, { meta: true }),
486+
);
487+
assertEquals(entries.length, 3);
488+
for (const [idx, entry] of entries.entries()) {
489+
assertEquals(entry.key, ["hello", idx + 1]);
490+
assertEquals(entry.value, { kind: "buffer", size: 3 });
491+
}
492+
return teardown();
493+
},
494+
});
495+
496+
Deno.test({
497+
name: "list - bytes",
498+
async fn() {
499+
const kv = await setup();
500+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
501+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
502+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
503+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
504+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
505+
const entries = await Array.fromAsync(
506+
list(kv, { prefix: ["hello"] }, { bytes: true }),
507+
);
508+
assertEquals(entries.length, 3);
509+
for (const [idx, entry] of entries.entries()) {
510+
assertEquals(entry.key, ["hello", idx + 1]);
511+
assert(timingSafeEqual(entry.value, new Uint8Array([1, 2, 3])));
512+
}
513+
return teardown();
514+
},
515+
});
516+
517+
Deno.test({
518+
name: "list - blob",
519+
async fn() {
520+
const kv = await setup();
521+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
522+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
523+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
524+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
525+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
526+
const entries = await Array.fromAsync(
527+
list(kv, { prefix: ["hello"] }, { blob: true }),
528+
);
529+
assertEquals(entries.length, 3);
530+
for (const [idx, entry] of entries.entries()) {
531+
assertEquals(entry.key, ["hello", idx + 1]);
532+
assert(entry.value instanceof Blob);
533+
assert(
534+
timingSafeEqual(await entry.value.bytes(), new Uint8Array([1, 2, 3])),
535+
);
536+
}
537+
return teardown();
538+
},
539+
});
540+
541+
Deno.test({
542+
name: "list - stream",
543+
async fn() {
544+
const kv = await setup();
545+
await set(kv, ["hello", 1], new Uint8Array([1, 2, 3]));
546+
await set(kv, ["hello", 2], new Uint8Array([1, 2, 3]));
547+
await set(kv, ["hello", 3], new Uint8Array([1, 2, 3]));
548+
await set(kv, ["hello"], new Uint8Array([1, 2, 3]));
549+
await set(kv, ["world"], new Uint8Array([1, 2, 3]));
550+
const entries = await Array.fromAsync(
551+
list(kv, { prefix: ["hello"] }, { stream: true }),
552+
);
553+
assertEquals(entries.length, 3);
554+
for (const [idx, entry] of entries.entries()) {
555+
assertEquals(entry.key, ["hello", idx + 1]);
556+
assert(entry.value instanceof ReadableStream);
557+
}
558+
return teardown();
559+
},
560+
});
561+
562+
Deno.test({
563+
name: "list - with invalid options throws",
564+
async fn() {
565+
const kv = await setup();
566+
assertThrows(
567+
() => list(kv, { prefix: [] }, { blob: true, meta: true }),
568+
TypeError,
569+
);
570+
assertThrows(
571+
() => list(kv, { prefix: [] }, { blob: true, stream: true }),
572+
TypeError,
573+
);
574+
assertThrows(
575+
() => list(kv, { prefix: [] }, { blob: true, bytes: true }),
576+
TypeError,
577+
);
578+
assertThrows(
579+
() => list(kv, { prefix: [] }, { bytes: true, meta: true }),
580+
TypeError,
581+
);
582+
assertThrows(
583+
() => list(kv, { prefix: [] }, { bytes: true, stream: true }),
584+
TypeError,
585+
);
586+
assertThrows(
587+
() => list(kv, { prefix: [] }, { stream: true, meta: true }),
588+
TypeError,
589+
);
590+
return teardown();
591+
},
592+
});
593+
431594
Deno.test({
432595
name: "toJSON/toValue - File",
433596
async fn() {

0 commit comments

Comments
 (0)