UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

96 lines (95 loc) 3.64 kB
import { RequiredError } from "../../error/RequiredError.js"; import { FetchStore } from "../../store/FetchStore.js"; import { getFirst, getLast } from "../../util/array.js"; import { getGetter } from "../../util/class.js"; import { NONE } from "../../util/constants.js"; import { getQueryLimit } from "../../util/query.js"; import { runSequence } from "../../util/sequence.js"; /** Store that queries multiple items in a collection from a database provider. */ export class QueryStore extends FetchStore { provider; collection; query; get limit() { return getQueryLimit(this.query) ?? Number.POSITIVE_INFINITY; } /** Can more items be loaded after the current result. */ get hasMore() { return this._hasMore; } _hasMore = false; /** Get the first item in this store or `null` if this query has no items. */ get optionalFirst() { return getFirst(this.value); } /** Get the last item in this store or `null` if this query has no items. */ get optionalLast() { return getLast(this.value); } /** Get the first item in this store. */ get first() { const first = this.optionalFirst; if (!first) throw new RequiredError(`First item does not exist in collection "${this.collection.name}"`, { store: this, provider: this.provider, collection: this.collection.name, query: this.query, caller: getGetter(this, "first"), }); return first; } /** Get the last item in this store. */ get last() { const last = this.optionalLast; if (!last) throw new RequiredError(`Last item does not exist in collection "${this.collection.name}"`, { store: this, provider: this.provider, collection: this.collection.name, query: this.query, caller: getGetter(this, "first"), }); return last; } constructor(collection, query, provider, memory) { const items = memory?.getTable(collection).getQuery(query); super(items ?? NONE); // Use the current memory snapshot if available. if (memory) this.starter = store => runSequence(store.through(memory.getQuerySequence(collection, query))); this.provider = provider; this.collection = collection; this.query = query; } // Override to fetch the result from the database provider. _fetch(_signal) { return this.provider.getQuery(this.collection, this.query); } /** * Load more items after the last once. * - Promise that needs to be handled. * @todo Make this work. */ // fetchMore(): void { // if (!this.busy.value) void this._fetchMore(); // } // private async _fetchMore(): Promise<void> { // this.busy.value = true; // this.reason = undefined; // Optimistically clear the error. // try { // const last = this.last; // const query = last ? getAfterQuery(this.query, last) : this.query; // const items = await this.provider.getQuery(this.collection, query); // this.value = [...this.value, ...items]; // this._hasMore = items.length >= this.limit; // If the query returned {limit} or more items, we can assume there are more items waiting to be queried. // } catch (thrown) { // this.reason = thrown; // } finally { // this.busy.value = false; // } // } // Implement `Iterable` [Symbol.iterator]() { return this.value.values(); } }