UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

186 lines (185 loc) • 7.11 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const evaluators = require("../query/compiler/evaluators.cjs"); const functions = require("../query/builder/functions.cjs"); const utils = require("../utils.cjs"); const comparison = require("../utils/comparison.cjs"); const errorMessage = require("../error-message.cjs"); function normalizeLocaleOptions(options) { return Object.fromEntries( Object.entries(options ?? {}).filter(([, value]) => value !== void 0) ); } function canonicalizeLocale(locale) { return locale === void 0 ? void 0 : Intl.getCanonicalLocales(locale)[0]; } function resolveStringSort(options) { return options.stringSort ?? utils.DEFAULT_COMPARE_OPTIONS.stringSort; } const builtInIndexResolverNames = /* @__PURE__ */ new WeakMap(); class BaseIndex { constructor(id, expression, name, options) { this.aH = /* @__PURE__ */ new Map(); this.id = id; this.expression = expression; this.compareOptions = options?.compareOptions ?? utils.DEFAULT_COMPARE_OPTIONS; this.hasCustomComparator = options?.compareFn != null; this.compareFn = comparison.makeCheckedComparator( options?.compareFn ? (a, b) => options.compareFn(comparison.normalizeValue(a), comparison.normalizeValue(b)) : comparison.makeComparator(this.compareOptions, `index`) ); this.name = name; this.supportedOperations = new Set(functions.indexableOperations); this.initialize(options); } exactBucketKeys(value) { return this.equalityLookup(value); } // Common methods lookupSupportedOperation(operation, value) { if (operation === `eq`) return this.equalityLookup(value); if (operation === `in`) return this.inArrayLookup(value); if (operation === `gt` || operation === `gte`) return this.rangeQuery({ from: value, fromInclusive: operation === `gte` }); if (operation === `lt` || operation === `lte`) return this.rangeQuery({ to: value, toInclusive: operation === `lte` }); return void 0; } /** Combine exact buckets without copying each bucket first. */ inArrayLookup(values) { const result = /* @__PURE__ */ new Set(); for (const value of values) { const keys = this.exactBucketKeys(value); if (keys) for (const key of keys) result.add(key); } return result; } rangeQueryReversed(options = {}) { const { from, to, fromInclusive = true, toInclusive = true } = options; const reversed = {}; if (`to` in options) { reversed.from = to; reversed.fromInclusive = toInclusive; } if (`from` in options) { reversed.to = from; reversed.toInclusive = fromInclusive; } return this.rangeQuery(reversed); } supports(operation) { return this.supportedOperations.has(operation); } get supportsRangeOptimization() { return !this.hasCustomComparator; } get supportsOrderOptimization() { if (this.hasCustomComparator || this.aH.size > 1) return false; const domain = this.aH.keys().next().value; return domain === void 0 || ![ `Array`, `Binary`, `Temporal.Duration.calendar`, `Temporal.PlainMonthDay`, `function` ].includes(domain); } addRangeValue(value) { const domain = rangeValueDomain(value); if (domain === void 0) return; this.aH.set( domain, (this.aH.get(domain) ?? 0) + 1 ); } removeRangeValue(value) { const domain = rangeValueDomain(value); if (domain === void 0) return; const count = this.aH.get(domain); if (count === void 0) return; if (count === 1) this.aH.delete(domain); else this.aH.set(domain, count - 1); } clearRangeValues() { this.aH.clear(); } canOptimizeRangeFor(value) { const domain = rangeValueDomain(value); if (domain === void 0) return true; if (!isNativeRangeDomain(domain)) return false; return this.aH.size === 0 || this.aH.size === 1 && this.aH.has(domain); } matchesField(fieldPath) { return this.expression.type === `ref` && this.expression.path.length === fieldPath.length && this.expression.path.every((part, i) => part === fieldPath[i]); } /** * Checks if the compare options match the index's compare options. * The direction is ignored because the index can be reversed if the direction is different. */ matchesCompareOptions(compareOptions) { const indexCompareOptions = this.compareOptions; const indexStringSort = resolveStringSort(indexCompareOptions); const requestedStringSort = resolveStringSort(compareOptions); if (indexCompareOptions.nulls !== compareOptions.nulls || indexStringSort !== requestedStringSort) { return false; } if (indexStringSort === `custom` && requestedStringSort === `custom`) { return indexCompareOptions.stringSort === `custom` && compareOptions.stringSort === `custom` && indexCompareOptions.compare === compareOptions.compare; } if (indexStringSort !== `locale` || requestedStringSort !== `locale`) { return true; } const indexLocaleOptions = indexCompareOptions; const requestedLocaleOptions = compareOptions; return canonicalizeLocale(indexLocaleOptions.locale) === canonicalizeLocale(requestedLocaleOptions.locale) && utils.deepEquals( normalizeLocaleOptions(indexLocaleOptions.localeOptions), normalizeLocaleOptions(requestedLocaleOptions.localeOptions) ); } /** * Checks if the index matches the provided direction. */ matchesDirection(direction) { return this.compareOptions.direction === direction; } initialize(_options) { } evaluateIndexExpression(item) { const evaluator = this.eK ??= evaluators.compileSingleRowExpression(this.expression); return evaluator(item); } /** The indexed value of a row being added. A throwing expression fails the write. */ evaluateAddedValue(key, item) { try { return this.evaluateIndexExpression(item); } catch (error) { throw new Error( errorMessage.devBuild() && process.env.NODE_ENV !== `production` ? `Failed to evaluate index expression for key ${key}: ${error}` : errorMessage.codedMessage(99, { key, error }), { cause: error } ); } } } function rangeValueDomain(value) { if (value == null) return void 0; if (value instanceof Date) return `date`; if (typeof value === `object`) return comparison.indexObjectKind(value); return typeof value; } function isNativeRangeDomain(domain) { return domain === `number` || domain === `bigint` || domain === `boolean` || domain === `string` || domain === `date`; } function warnRemovalFailure(key, error) { console.warn( errorMessage.devBuild() && process.env.NODE_ENV !== `production` ? `Failed to evaluate index expression for key ${key} during removal:` : errorMessage.codedWarning(216, { key }), error ); } exports.indexableOperations = functions.indexableOperations; exports.BaseIndex = BaseIndex; exports.builtInIndexResolverNames = builtInIndexResolverNames; exports.warnRemovalFailure = warnRemovalFailure; //# sourceMappingURL=base-index.cjs.map