UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

280 lines (279 loc) • 8.59 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const dbIvm = require("@tanstack/db-ivm"); const comparison = require("../utils/comparison.cjs"); const errorMessage = require("../error-message.cjs"); const arrayUtils = require("../utils/array-utils.cjs"); const baseIndex = require("./base-index.cjs"); function orderValue(value) { return value instanceof Date ? value.getTime() : value; } class BasicIndex extends baseIndex.BaseIndex { constructor() { super(...arguments); this.ax = /* @__PURE__ */ new Map(); this.J = []; this.gG = []; this.aK = /* @__PURE__ */ new Set(); } /** * Adds a value to the index */ add(key, item) { const indexedValue = this.evaluateAddedValue(key, item); const normalizedValue = comparison.normalizeValue(indexedValue); this.dF(key, normalizedValue, indexedValue); this.addRangeValue(indexedValue); this.aK.add(key); } dF(key, normalizedValue, value) { const keySet = this.ax.get(normalizedValue); if (keySet) { keySet.add(key); } else { const orderedValue = orderValue(value); const insertIdx = arrayUtils.findInsertPositionInArray( this.J, orderedValue, this.compareFn ); this.ax.set(normalizedValue, /* @__PURE__ */ new Set([key])); this.J.splice(insertIdx, 0, orderedValue); this.gG.splice(insertIdx, 0, normalizedValue); } } /** * Removes a value from the index */ remove(key, item) { let indexedValue; try { indexedValue = this.evaluateIndexExpression(item); } catch (error) { baseIndex.warnRemovalFailure(key, error); this.aK.delete(key); return; } const normalizedValue = comparison.normalizeValue(indexedValue); this.cf(key, normalizedValue, indexedValue); this.removeRangeValue(indexedValue); this.aK.delete(key); } cf(key, normalizedValue, value) { const keySet = this.ax.get(normalizedValue); if (keySet?.has(key)) { if (keySet.size === 1) { const orderedValue = orderValue(value); let sortedIndex = arrayUtils.findInsertPositionInArray( this.J, orderedValue, this.compareFn ); while (sortedIndex < this.J.length && this.compareFn(this.J[sortedIndex], orderedValue) === 0) { if (comparison.areSameValueZeroEqual( this.gG[sortedIndex], normalizedValue )) { this.J.splice(sortedIndex, 1); this.gG.splice(sortedIndex, 1); break; } sortedIndex++; } this.ax.delete(normalizedValue); } keySet.delete(key); } } /** * Updates a value in the index */ update(key, oldItem, newItem) { let oldIndexedValue; let newIndexedValue; try { oldIndexedValue = this.evaluateIndexExpression(oldItem); newIndexedValue = this.evaluateIndexExpression(newItem); } catch { this.remove(key, oldItem); this.add(key, newItem); return; } const oldValue = comparison.normalizeValue(oldIndexedValue); const newValue = comparison.normalizeValue(newIndexedValue); if (comparison.areSameValueZeroEqual(oldValue, newValue) && this.ax.get(newValue)?.has(key) && this.aK.has(key)) { this.removeRangeValue(oldIndexedValue); this.addRangeValue(newIndexedValue); return; } this.cf(key, oldValue, oldIndexedValue); this.removeRangeValue(oldIndexedValue); this.dF(key, newValue, newIndexedValue); this.addRangeValue(newIndexedValue); this.aK.add(key); } /** * Builds the index from a collection of entries */ build(entries) { this.clear(); for (const [key, item] of entries) { const indexedValue = this.evaluateAddedValue(key, item); const value = comparison.normalizeValue(indexedValue); const keys = this.ax.get(value); if (keys) keys.add(key); else { this.ax.set(value, /* @__PURE__ */ new Set([key])); this.J.push(orderValue(indexedValue)); this.gG.push(value); } this.addRangeValue(indexedValue); this.aK.add(key); } const sortable = this.J.map((value, index) => ({ value, exact: this.gG[index] })); sortable.sort((left, right) => this.compareFn(left.value, right.value)); this.J = sortable.map(({ value }) => value); this.gG = sortable.map(({ exact }) => exact); } /** * Clears all data from the index */ clear() { this.ax.clear(); this.J = []; this.gG = []; this.aK.clear(); this.clearRangeValues(); } lookup(operation, value) { const result = this.lookupSupportedOperation(operation, value); if (result !== void 0) return result; throw new Error( errorMessage.devBuild() && process.env.NODE_ENV !== `production` ? `Operation ${operation} not supported by BasicIndex` : errorMessage.codedMessage(100, { operation }) ); } /** * Gets the number of indexed keys */ get keyCount() { return this.aK.size; } /** * Performs an equality lookup - O(1) */ equalityLookup(value) { const normalizedValue = comparison.normalizeValue(value); return this.ax.get(normalizedValue) ?? /* @__PURE__ */ new Set(); } /** * Performs a range query using binary search - O(log n + m) */ rangeQuery(options = {}) { const { from, to, fromInclusive = true, toInclusive = true } = options; const result = /* @__PURE__ */ new Set(); if (this.J.length === 0) { return result; } const orderedFrom = orderValue(from); const orderedTo = orderValue(to); const hasFrom = `from` in options; const hasTo = `to` in options; let startIdx = 0; if (hasFrom) { startIdx = arrayUtils.findInsertPositionInArray( this.J, orderedFrom, this.compareFn ); while (!fromInclusive && startIdx < this.J.length && this.compareFn(this.J[startIdx], orderedFrom) === 0) { startIdx++; } } let endIdx = this.J.length; if (hasTo) { endIdx = arrayUtils.findInsertPositionInArray( this.J, orderedTo, this.compareFn ); while (toInclusive && endIdx < this.J.length && this.compareFn(this.J[endIdx], orderedTo) === 0) { endIdx++; } } for (let i = startIdx; i < endIdx; i++) { const keys = this.ax.get(this.gG[i]); if (keys) { keys.forEach((key) => result.add(key)); } } return result; } /** * Returns the next n items in sorted order */ take(n, from, filterFn) { const orderedFrom = orderValue(from); let startIdx = arrayUtils.findInsertPositionInArray( this.J, orderedFrom, this.compareFn ); while (startIdx < this.J.length && this.compareFn(this.J[startIdx], orderedFrom) <= 0) { startIdx++; } return this.dM(n, startIdx, 1, filterFn); } /** * Returns the next n items in reverse sorted order */ takeReversed(n, from, filterFn) { const orderedFrom = orderValue(from); let startIdx = arrayUtils.findInsertPositionInArray( this.J, orderedFrom, this.compareFn ) - 1; while (startIdx >= 0 && this.compareFn(this.J[startIdx], orderedFrom) >= 0) { startIdx--; } return this.dM(n, startIdx, -1, filterFn); } /** * Returns the first n items in sorted order (from the start) */ takeFromStart(n, filterFn) { return this.dM(n, 0, 1, filterFn); } /** * Returns the first n items in reverse sorted order (from the end) */ takeReversedFromEnd(n, filterFn) { return this.dM(n, this.J.length - 1, -1, filterFn); } dM(n, startIndex, step, filterFn) { const result = []; let index = startIndex; while (index >= 0 && index < this.J.length && result.length < n) { const groupValue = this.J[index]; const groupKeys = []; do { for (const key of this.ax.get(this.gG[index]) ?? []) { groupKeys.push(key); } index += step; } while (index >= 0 && index < this.J.length && this.compareFn(this.J[index], groupValue) === 0); groupKeys.sort(step === 1 ? dbIvm.compareKeys : arrayUtils.compareKeysReversed); for (const key of groupKeys) { if (filterFn?.(key) ?? true) result.push(key); if (result.length >= n) break; } } return result; } } baseIndex.builtInIndexResolverNames.set(BasicIndex, `BasicIndex`); exports.BasicIndex = BasicIndex; //# sourceMappingURL=basic-index.cjs.map