UNPKG

@worker-tools/deno-kv-storage

Version:

An implementation of the StorageArea (1,2,3) interface for Deno with an extensible system for supporting various database backends.

96 lines (74 loc) 2.83 kB
// deno-lint-ignore-file no-explicit-any import "./_dnt.polyfills.js"; import * as dntShim from "./_dnt.shims.js"; import type { StorageArea, AllowedKey, Key } from 'kv-storage-interface'; import { encodeKey, decodeKey, throwForDisallowedKey } from 'idb-key-to-string'; import * as Structured from '@worker-tools/structured-json'; import type { Adapter, DBProtocol, AdapterClass, DB_URL } from './adapters/mod.js'; const OLD_DEFAULT_URL_KEY = 'DENO_STORAGE_AREA__DEFAULT_URL'; const DEFAULT_URL_KEY = 'DEFAULT_KV_URL'; const DEFAULT_STORAGE_AREA_NAME = 'default'; export interface DenoStorageAreaOptions { url?: DB_URL, [k: string]: any, } export class DenoStorageArea implements StorageArea { #store: Adapter; static defaultURL?: DB_URL; constructor(name: string = DEFAULT_STORAGE_AREA_NAME, options: DenoStorageAreaOptions = {}) { const dbURL = options.url || DenoStorageArea.defaultURL || Reflect.get(self, DEFAULT_URL_KEY) || Reflect.get(self, OLD_DEFAULT_URL_KEY) || Deno.env.get(DEFAULT_URL_KEY) || Deno.env.get(OLD_DEFAULT_URL_KEY) || 'sqlite://'; const { protocol } = new URL(dbURL); const adapters: Map<DBProtocol, AdapterClass> = (<any>dntShim.dntGlobalThis).deno_storage_area__adapters || new Map() const AdapterCtor = adapters.get(protocol as DBProtocol); if (!AdapterCtor) { throw Error(`Adapter for database protocol '${protocol}' not registered. Try importing 'adapters/${protocol.replace(':', '')}.ts'`); } this.#store = new AdapterCtor({ area: name, url: dbURL }); } async get<T>(key: AllowedKey): Promise<T | undefined> { throwForDisallowedKey(key); const s = await this.#store.get(encodeKey(key)) return s && Structured.parse(s); } async set<T>(key: AllowedKey, value: T | undefined): Promise<void> { throwForDisallowedKey(key); if (value === undefined) { await this.#store.delete(encodeKey(key)); } else { await this.#store.set(encodeKey(key), Structured.stringify(value)); } } async delete(key: AllowedKey) { throwForDisallowedKey(key); await this.#store.delete(encodeKey(key)); } async clear() { await this.#store.clear(); } async *keys(): AsyncGenerator<Key> { for await (const key of this.#store.keys()) { yield decodeKey(key); } } async *values<T>(): AsyncGenerator<T> { for await (const value of this.#store.values()) { yield Structured.parse(value); } } async *entries<T>(): AsyncGenerator<[Key, T]> { for await (const [key, value] of this.#store.entries()) { yield [decodeKey(key), Structured.parse(value)]; } } backingStore() { return this.#store.backingStore(); } } export type { AllowedKey, Key, DBProtocol, DB_URL }; export { DenoStorageArea as StorageArea };