UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

72 lines (71 loc) 2.72 kB
import { RequiredError } from "../error/RequiredError.js"; import { BooleanStore } from "../store/BooleanStore.js"; import { OptionalDataStore } from "../store/DataStore.js"; import { getGetter } from "../util/class.js"; import { NONE } from "../util/constants.js"; import { getItem } from "../util/item.js"; import { runSequence } from "../util/sequence.js"; /** Store a single item. */ export class ItemStore extends OptionalDataStore { provider; collection; id; busy = new BooleanStore(); /** Get the data of this store (throws `RequiredError` if item doesn't exist). */ get data() { const item = this.value; if (!item) throw new RequiredError(`Item does not exist in collection "${this.collection}"`, { store: this, provider: this.provider, collection: this.collection, id: this.id, caller: getGetter(this, "data"), }); return item; } /** Set the data of this store. */ set data(data) { this.value = getItem(this.id, data); } constructor(collection, id, provider, memory) { const time = memory?.getItemTime(collection, id); const item = memory?.getItem(collection, id); super(typeof time === "number" || item ? item : NONE, time); // Use the cached value if it was definitely cached or is not undefined. if (memory) this.starter = store => runSequence(store.through(memory.getCachedItemSequence(collection, id))); this.provider = provider; this.collection = collection; this.id = id; // Start loading the value from the provider if it wasn't cached. if (typeof time !== "number") this.refresh(); } /** Refresh this store from the source provider. */ refresh(provider = this.provider) { if (!this.busy.value) void this._refresh(provider); } async _refresh(provider) { this.busy.value = true; this.reason = undefined; // Optimistically clear the error. try { this.value = await provider.getItem(this.collection, this.id); } catch (thrown) { this.reason = thrown; } finally { this.busy.value = false; } } /** Refresh this store if data in the cache is older than `maxAge` (in milliseconds). */ refreshStale(maxAge, provider) { if (this.age > maxAge) this.refresh(provider); } /** Subscribe this store to a provider. */ connect(provider = this.provider) { return runSequence(this.through(provider.getItemSequence(this.collection, this.id))); } }