1 |
|
2 | import "./_dnt.polyfills.js";
|
3 |
|
4 | import * as dntShim from "./_dnt.shims.js";
|
5 |
|
6 | import type { StorageArea, AllowedKey, Key } from 'kv-storage-interface';
|
7 | import { encodeKey, decodeKey, throwForDisallowedKey } from 'idb-key-to-string';
|
8 |
|
9 | import * as Structured from '@worker-tools/structured-json';
|
10 |
|
11 | import type { Adapter, DBProtocol, AdapterClass, DB_URL } from './adapters/mod.js';
|
12 |
|
13 | const OLD_DEFAULT_URL_KEY = 'DENO_STORAGE_AREA__DEFAULT_URL';
|
14 | const DEFAULT_URL_KEY = 'DEFAULT_KV_URL';
|
15 | const DEFAULT_STORAGE_AREA_NAME = 'default';
|
16 |
|
17 | export interface DenoStorageAreaOptions {
|
18 | url?: DB_URL,
|
19 | [k: string]: any,
|
20 | }
|
21 |
|
22 | export class DenoStorageArea implements StorageArea {
|
23 | #store: Adapter;
|
24 |
|
25 | static defaultURL?: DB_URL;
|
26 |
|
27 | constructor(name: string = DEFAULT_STORAGE_AREA_NAME, options: DenoStorageAreaOptions = {}) {
|
28 | const dbURL = options.url
|
29 | || DenoStorageArea.defaultURL
|
30 | || Reflect.get(self, DEFAULT_URL_KEY)
|
31 | || Reflect.get(self, OLD_DEFAULT_URL_KEY)
|
32 | || Deno.env.get(DEFAULT_URL_KEY)
|
33 | || Deno.env.get(OLD_DEFAULT_URL_KEY)
|
34 | || 'sqlite://';
|
35 |
|
36 | const { protocol } = new URL(dbURL);
|
37 | const adapters: Map<DBProtocol, AdapterClass> = (<any>dntShim.dntGlobalThis).deno_storage_area__adapters || new Map()
|
38 | const AdapterCtor = adapters.get(protocol as DBProtocol);
|
39 |
|
40 | if (!AdapterCtor) {
|
41 | throw Error(`Adapter for database protocol '${protocol}' not registered. Try importing 'adapters/${protocol.replace(':', '')}.ts'`);
|
42 | }
|
43 |
|
44 | this.#store = new AdapterCtor({ area: name, url: dbURL });
|
45 | }
|
46 |
|
47 | async get<T>(key: AllowedKey): Promise<T | undefined> {
|
48 | throwForDisallowedKey(key);
|
49 | const s = await this.#store.get(encodeKey(key))
|
50 | return s && Structured.parse(s);
|
51 | }
|
52 |
|
53 | async set<T>(key: AllowedKey, value: T | undefined): Promise<void> {
|
54 | throwForDisallowedKey(key);
|
55 | if (value === undefined) {
|
56 | await this.#store.delete(encodeKey(key));
|
57 | } else {
|
58 | await this.#store.set(encodeKey(key), Structured.stringify(value));
|
59 | }
|
60 | }
|
61 |
|
62 | async delete(key: AllowedKey) {
|
63 | throwForDisallowedKey(key);
|
64 | await this.#store.delete(encodeKey(key));
|
65 | }
|
66 |
|
67 | async clear() {
|
68 | await this.#store.clear();
|
69 | }
|
70 |
|
71 | async *keys(): AsyncGenerator<Key> {
|
72 | for await (const key of this.#store.keys()) {
|
73 | yield decodeKey(key);
|
74 | }
|
75 | }
|
76 |
|
77 | async *values<T>(): AsyncGenerator<T> {
|
78 | for await (const value of this.#store.values()) {
|
79 | yield Structured.parse(value);
|
80 | }
|
81 | }
|
82 |
|
83 | async *entries<T>(): AsyncGenerator<[Key, T]> {
|
84 | for await (const [key, value] of this.#store.entries()) {
|
85 | yield [decodeKey(key), Structured.parse(value)];
|
86 | }
|
87 | }
|
88 |
|
89 | backingStore() {
|
90 | return this.#store.backingStore();
|
91 | }
|
92 | }
|
93 |
|
94 | export type { AllowedKey, Key, DBProtocol, DB_URL };
|
95 | export { DenoStorageArea as StorageArea };
|