1
0

KV Primitives refactor and in-memory version

This commit is contained in:
Zef Hemel 2023-12-11 12:11:47 +01:00
parent 30b987fecb
commit 341be037f8
4 changed files with 110 additions and 43 deletions

View File

@ -11,46 +11,3 @@ export interface KvPrimitives {
query(options: KvQueryOptions): AsyncIterableIterator<KV>;
close(): void;
}
/**
* Turns any KvPrimitives into a KvPrimitives that automatically prefixes all keys (and removes them again when reading)
*/
export class PrefixedKvPrimitives implements KvPrimitives {
constructor(private wrapped: KvPrimitives, private prefix: KvKey) {
}
batchGet(keys: KvKey[]): Promise<any[]> {
return this.wrapped.batchGet(keys.map((key) => this.applyPrefix(key)));
}
batchSet(entries: KV[]): Promise<void> {
return this.wrapped.batchSet(
entries.map(({ key, value }) => ({ key: this.applyPrefix(key), value })),
);
}
batchDelete(keys: KvKey[]): Promise<void> {
return this.wrapped.batchDelete(keys.map((key) => this.applyPrefix(key)));
}
async *query(options: KvQueryOptions): AsyncIterableIterator<KV> {
for await (
const result of this.wrapped.query({
prefix: this.applyPrefix(options.prefix),
})
) {
yield { key: this.stripPrefix(result.key), value: result.value };
}
}
close(): void {
this.wrapped.close();
}
private applyPrefix(key?: KvKey): KvKey {
return [...this.prefix, ...(key ? key : [])];
}
private stripPrefix(key: KvKey): KvKey {
return key.slice(this.prefix.length);
}
}

View File

@ -0,0 +1,8 @@
import { allTests } from "./kv_primitives.test.ts";
import { MemoryKvPrimitives } from "./memory_kv_primitives.ts";
Deno.test("Test Memory KV Primitives", async () => {
const db = new MemoryKvPrimitives();
await allTests(db);
db.close();
});

View File

@ -0,0 +1,57 @@
import { KV, KvKey } from "$sb/types.ts";
import { KvPrimitives, KvQueryOptions } from "./kv_primitives.ts";
const memoryKeySeparator = "\0";
export class MemoryKvPrimitives implements KvPrimitives {
protected store = new Map<string, any>();
batchGet(keys: KvKey[]): Promise<any[]> {
return Promise.resolve(
keys.map((key) => this.store.get(key.join(memoryKeySeparator))),
);
}
batchSet(entries: KV[]): Promise<void> {
for (const { key, value } of entries) {
this.store.set(key.join(memoryKeySeparator), value);
}
return Promise.resolve();
}
batchDelete(keys: KvKey[]): Promise<void> {
for (const key of keys) {
this.store.delete(key.join(memoryKeySeparator));
}
return Promise.resolve();
}
toJSON(): Record<string, any> {
const result: Record<string, any> = {};
for (const [key, value] of this.store) {
result[key] = value;
}
return result;
}
static fromJSON(json: Record<string, any>): MemoryKvPrimitives {
const result = new MemoryKvPrimitives();
for (const key of Object.keys(json)) {
result.store.set(key, json[key]);
}
return result;
}
async *query(options: KvQueryOptions): AsyncIterableIterator<KV> {
const prefix = options.prefix?.join("/");
for (const [key, value] of this.store) {
if (prefix && !key.startsWith(prefix)) {
continue;
}
yield { key: key.split(memoryKeySeparator), value };
}
}
close(): void {
}
}

View File

@ -0,0 +1,45 @@
import { KV, KvKey } from "$sb/types.ts";
import { KvPrimitives, KvQueryOptions } from "./kv_primitives.ts";
/**
* Turns any KvPrimitives into a KvPrimitives that automatically prefixes all keys (and removes them again when reading)
*/
export class PrefixedKvPrimitives implements KvPrimitives {
constructor(private wrapped: KvPrimitives, private prefix: KvKey) {
}
batchGet(keys: KvKey[]): Promise<any[]> {
return this.wrapped.batchGet(keys.map((key) => this.applyPrefix(key)));
}
batchSet(entries: KV[]): Promise<void> {
return this.wrapped.batchSet(
entries.map(({ key, value }) => ({ key: this.applyPrefix(key), value })),
);
}
batchDelete(keys: KvKey[]): Promise<void> {
return this.wrapped.batchDelete(keys.map((key) => this.applyPrefix(key)));
}
async *query(options: KvQueryOptions): AsyncIterableIterator<KV> {
for await (
const result of this.wrapped.query({
prefix: this.applyPrefix(options.prefix),
})
) {
yield { key: this.stripPrefix(result.key), value: result.value };
}
}
close(): void {
this.wrapped.close();
}
private applyPrefix(key?: KvKey): KvKey {
return [...this.prefix, ...(key ? key : [])];
}
private stripPrefix(key: KvKey): KvKey {
return key.slice(this.prefix.length);
}
}