shelving
Version:
Toolkit for using data in JavaScript.
74 lines (73 loc) • 3.45 kB
JavaScript
import { DBProvider } from "../db/provider/DBProvider.js";
import { UnimplementedError } from "../error/UnimplementedError.js";
import { getItem } from "../util/item.js";
import { randomUUID } from "../util/uuid.js";
/**
* Cloudflare Workers KV database provider.
*
* Items are stored as JSON values under keys formatted as `collection:id`.
* The `KVNamespace` object is provided by the Cloudflare Workers runtime environment.
*
* ### Supported
* - Single item operations: `getItem`, `setItem`, `addItem`, `updateItem`, `deleteItem`.
* - ID generation: `addItem()` generates a UUID v4 identifier automatically.
*
* ### Not supported
* - **Realtime subscriptions:** `getItemSequence()` and `getQuerySequence()` throw `UnimplementedError`.
* KV has no change feed or push notification mechanism.
* - **Updates:** `updateItem()` and `updateQuery()` throw `UnimplementedError`.
* - **Collection queries:** `getQuery()`, `setQuery()`, `deleteQuery()`, and `countQuery()` are not supported.
* KV does not expose efficient filtering, sorting, or collection scans, so this provider avoids the old "read everything and filter in memory" behavior.
*
* ### Performance limitations
* - **Single-key store only:** This provider is intentionally limited to direct key reads and writes.
* If you need collection queries, filtering, sorting, or bulk mutations, use a different backend.
* - **Eventual consistency:** KV is eventually consistent, so reads may briefly return stale values shortly after writes.
*/
export class CloudflareKVProvider extends DBProvider {
_kv;
constructor(kv) {
super();
this._kv = kv;
}
async getItem({ name }, id) {
const data = (await this._kv.get(_getKey(name, id), { type: "json" })); // `as TT` needed: KV returns unknown from JSON parse.
if (data)
return getItem(id, data);
}
getItemSequence(_collection, _id) {
throw new UnimplementedError("CloudflareKVProvider does not support realtime subscriptions");
}
async addItem({ name }, data) {
const id = randomUUID(); // `as II` needed: TypeScript can't narrow II from string return type.
await this._kv.put(_getKey(name, id), JSON.stringify(data));
return id;
}
async setItem({ name }, id, data) {
await this._kv.put(_getKey(name, id), JSON.stringify(data));
}
async updateItem(_collection, _id, _updates) {
throw new UnimplementedError("CloudflareKVProvider does not support updates to items");
}
async deleteItem({ name }, id) {
await this._kv.delete(_getKey(name, id));
}
async getQuery(_collection, _query) {
throw new UnimplementedError("CloudflareKVProvider does not support querying items");
}
getQuerySequence(_collection, _query) {
throw new UnimplementedError("CloudflareKVProvider does not support realtime subscriptions");
}
async setQuery(_collection, _query, _data) {
throw new UnimplementedError("CloudflareKVProvider does not support querying items");
}
async updateQuery(_collection, _query, _updates) {
throw new UnimplementedError("CloudflareKVProvider does not support updates to items");
}
async deleteQuery(_collection, _query) {
throw new UnimplementedError("CloudflareKVProvider does not support querying items");
}
}
function _getKey(collection, id) {
return `${collection}:${id}`;
}