shelving
Version:
Toolkit for using data in JavaScript.
96 lines (95 loc) • 3.64 kB
JavaScript
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();
}
}