1
0
silverbullet/plugos/lib/kv_store.deno_kv.ts

113 lines
3.0 KiB
TypeScript
Raw Normal View History

2023-08-04 16:56:55 +00:00
/// <reference lib="deno.unstable" />
import { KV, KVStore } from "./kv_store.ts";
2023-08-26 06:31:51 +00:00
const kvBatchSize = 10;
2023-08-04 16:56:55 +00:00
export class DenoKVStore implements KVStore {
2023-08-28 15:12:15 +00:00
constructor(private kv: Deno.Kv) {
2023-08-04 16:56:55 +00:00
}
2023-08-26 06:31:51 +00:00
del(key: string): Promise<void> {
return this.batchDelete([key]);
2023-08-04 16:56:55 +00:00
}
async deletePrefix(prefix: string): Promise<void> {
2023-08-26 06:31:51 +00:00
const allKeys: string[] = [];
2023-08-04 16:56:55 +00:00
for await (
2023-08-26 06:31:51 +00:00
const result of this.kv.list(
prefix
? {
start: [prefix],
end: [endRange(prefix)],
}
: { prefix: [] },
)
2023-08-04 16:56:55 +00:00
) {
2023-08-26 06:31:51 +00:00
allKeys.push(result.key[0] as string);
2023-08-04 16:56:55 +00:00
}
2023-08-26 06:31:51 +00:00
return this.batchDelete(allKeys);
2023-08-04 16:56:55 +00:00
}
2023-08-26 06:31:51 +00:00
deleteAll(): Promise<void> {
return this.deletePrefix("");
2023-08-04 16:56:55 +00:00
}
2023-08-26 06:31:51 +00:00
set(key: string, value: any): Promise<void> {
return this.batchSet([{ key, value }]);
2023-08-04 16:56:55 +00:00
}
async batchSet(kvs: KV[]): Promise<void> {
2023-08-26 06:31:51 +00:00
// Split into batches of kvBatchSize
const batches: KV[][] = [];
for (let i = 0; i < kvs.length; i += kvBatchSize) {
batches.push(kvs.slice(i, i + kvBatchSize));
}
for (const batch of batches) {
let batchOp = this.kv.atomic();
for (const { key, value } of batch) {
batchOp = batchOp.set([key], value);
}
const res = await batchOp.commit();
if (!res.ok) {
throw res;
}
2023-08-04 16:56:55 +00:00
}
}
async batchDelete(keys: string[]): Promise<void> {
2023-08-26 06:31:51 +00:00
const batches: string[][] = [];
for (let i = 0; i < keys.length; i += kvBatchSize) {
batches.push(keys.slice(i, i + kvBatchSize));
}
for (const batch of batches) {
let batchOp = this.kv.atomic();
for (const key of batch) {
batchOp = batchOp.delete([key]);
}
const res = await batchOp.commit();
if (!res.ok) {
throw res;
}
2023-08-04 16:56:55 +00:00
}
}
2023-08-26 06:31:51 +00:00
async batchGet(keys: string[]): Promise<any[]> {
const results: any[] = [];
const batches: Deno.KvKey[][] = [];
for (let i = 0; i < keys.length; i += kvBatchSize) {
batches.push(keys.slice(i, i + kvBatchSize).map((k) => [k]));
2023-08-04 16:56:55 +00:00
}
2023-08-26 06:31:51 +00:00
for (const batch of batches) {
const res = await this.kv.getMany(batch);
results.push(...res.map((r) => r.value));
}
return results;
2023-08-04 16:56:55 +00:00
}
async get(key: string): Promise<any> {
return (await this.kv.get([key])).value;
}
async has(key: string): Promise<boolean> {
return (await this.kv.get([key])).value !== null;
}
async queryPrefix(keyPrefix: string): Promise<{ key: string; value: any }[]> {
const results: { key: string; value: any }[] = [];
for await (
2023-08-26 06:31:51 +00:00
const result of this.kv.list(
keyPrefix
? {
start: [keyPrefix],
end: [endRange(keyPrefix)],
}
: { prefix: [] },
)
2023-08-04 16:56:55 +00:00
) {
results.push({
key: result.key[0] as string,
value: result.value as any,
});
}
return results;
}
}
function endRange(prefix: string) {
const lastChar = prefix[prefix.length - 1];
const nextLastChar = String.fromCharCode(lastChar.charCodeAt(0) + 1);
return prefix.slice(0, -1) + nextLastChar;
}