UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines 19.8 kB
{"version":3,"file":"btree-index.cjs","sources":["../../../src/indexes/btree-index.ts"],"sourcesContent":["import { compareKeys } from '@tanstack/db-ivm'\nimport { compareKeysReversed } from '../utils/array-utils.js'\nimport { BTree } from '../utils/btree.js'\nimport {\n areSameValueZeroEqual,\n defaultComparator,\n denormalizeUndefined,\n makeComparator,\n normalizeForBTree,\n} from '../utils/comparison.js'\nimport { BaseIndex } from './base-index.js'\nimport type { CompareOptions } from '../query/builder/types.js'\nimport type { BasicExpression } from '../query/ir.js'\nimport type { IndexOperation } from './base-index.js'\n\n/**\n * Options for Ordered index\n */\nexport interface BTreeIndexOptions {\n compareFn?: (a: any, b: any) => number\n compareOptions?: CompareOptions\n}\n\n/**\n * Options for range queries\n */\nexport interface RangeQueryOptions {\n from?: any\n to?: any\n fromInclusive?: boolean\n toInclusive?: boolean\n}\n\ntype OrderedBucket<TKey> = {\n representative: unknown\n exactValues: Set<unknown>\n keys: Set<TKey>\n}\n\n/**\n * B+Tree index for sorted data with range queries\n * This maintains items in sorted order and provides efficient range operations\n */\nexport class BTreeIndex<\n TKey extends string | number = string | number,\n> extends BaseIndex<TKey> {\n public readonly supportedOperations = new Set<IndexOperation>([\n `eq`,\n `gt`,\n `gte`,\n `lt`,\n `lte`,\n `in`,\n ])\n\n // Internal data structures - private to hide implementation details\n // The `orderedEntries` B+ tree groups values that occupy the same comparator\n // position. The `valueMap` keeps exact values separate for equality lookups.\n private orderedEntries: BTree<any, OrderedBucket<TKey>>\n private valueMap = new Map<\n unknown,\n { keys: Set<TKey>; ordered: OrderedBucket<TKey> }\n >()\n private indexedKeys = new Set<TKey>()\n private compareFn: (a: any, b: any) => number = defaultComparator\n\n constructor(\n id: number,\n expression: BasicExpression,\n name?: string,\n options?: any,\n ) {\n super(id, expression, name, options)\n\n if (options?.compareOptions) {\n this.compareOptions = options!.compareOptions\n }\n\n // Get the base compare function\n const baseCompareFn =\n options?.compareFn ?? makeComparator(this.compareOptions)\n this.hasCustomComparator = options?.compareFn != null\n\n // Wrap it to denormalize sentinels before comparison\n // This ensures UNDEFINED_SENTINEL is converted back to undefined\n // before being passed to the baseCompareFn (which can be user-provided and is unaware of the UNDEFINED_SENTINEL)\n this.compareFn = (a: any, b: any) =>\n baseCompareFn(denormalizeUndefined(a), denormalizeUndefined(b))\n\n this.orderedEntries = new BTree(this.compareFn)\n }\n\n protected initialize(_options?: BTreeIndexOptions): void {}\n\n /**\n * Adds a value to the index\n */\n add(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n throw new Error(\n `Failed to evaluate index expression for key ${key}: ${error}`,\n )\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeForBTree(indexedValue)\n\n this.addToBucket(key, normalizedValue)\n this.addRangeValue(indexedValue)\n\n this.indexedKeys.add(key)\n }\n\n private addToBucket(key: TKey, normalizedValue: unknown): void {\n const exact = this.valueMap.get(normalizedValue)\n if (exact) {\n exact.keys.add(key)\n exact.ordered.keys.add(key)\n return\n }\n\n let orderedBucket = this.orderedEntries.get(normalizedValue)\n if (orderedBucket) {\n orderedBucket.keys.add(key)\n orderedBucket.exactValues.add(normalizedValue)\n } else {\n orderedBucket = {\n representative: normalizedValue,\n exactValues: new Set([normalizedValue]),\n keys: new Set([key]),\n }\n this.orderedEntries.set(normalizedValue, orderedBucket)\n }\n this.valueMap.set(normalizedValue, {\n keys: new Set([key]),\n ordered: orderedBucket,\n })\n }\n\n /**\n * Removes a value from the index\n */\n remove(key: TKey, item: any): void {\n let indexedValue: any\n try {\n indexedValue = this.evaluateIndexExpression(item)\n } catch (error) {\n console.warn(\n `Failed to evaluate index expression for key ${key} during removal:`,\n error,\n )\n return\n }\n\n // Normalize the value for Map key usage\n const normalizedValue = normalizeForBTree(indexedValue)\n\n this.removeFromBucket(key, normalizedValue)\n this.removeRangeValue(indexedValue)\n\n this.indexedKeys.delete(key)\n }\n\n private removeFromBucket(key: TKey, normalizedValue: unknown): void {\n const exact = this.valueMap.get(normalizedValue)\n if (!exact || !exact.keys.delete(key)) return\n const removedExactValue = exact.keys.size === 0\n if (removedExactValue) this.valueMap.delete(normalizedValue)\n const orderedBucket = exact.ordered\n orderedBucket.keys.delete(key)\n if (removedExactValue) orderedBucket.exactValues.delete(normalizedValue)\n\n if (orderedBucket.keys.size === 0) {\n this.orderedEntries.delete(normalizedValue)\n } else if (\n removedExactValue &&\n areSameValueZeroEqual(orderedBucket.representative, normalizedValue)\n ) {\n this.orderedEntries.delete(normalizedValue)\n const representative = orderedBucket.exactValues.values().next().value\n orderedBucket.representative = representative\n this.orderedEntries.set(representative, orderedBucket)\n }\n }\n\n /**\n * Updates a value in the index\n */\n update(key: TKey, oldItem: any, newItem: any): void {\n let oldIndexedValue: unknown\n let newIndexedValue: unknown\n try {\n oldIndexedValue = this.evaluateIndexExpression(oldItem)\n newIndexedValue = this.evaluateIndexExpression(newItem)\n } catch {\n this.remove(key, oldItem)\n this.add(key, newItem)\n return\n }\n\n const oldValue = normalizeForBTree(oldIndexedValue)\n const newValue = normalizeForBTree(newIndexedValue)\n if (\n areSameValueZeroEqual(oldValue, newValue) &&\n this.valueMap.get(newValue)?.keys.has(key)\n ) {\n this.removeRangeValue(oldIndexedValue)\n this.addRangeValue(newIndexedValue)\n return\n }\n\n this.removeFromBucket(key, oldValue)\n this.removeRangeValue(oldIndexedValue)\n this.addToBucket(key, newValue)\n this.addRangeValue(newIndexedValue)\n this.indexedKeys.add(key)\n }\n\n /**\n * Builds the index from a collection of entries\n */\n build(entries: Iterable<[TKey, any]>): void {\n this.clear()\n\n for (const [key, item] of entries) {\n this.add(key, item)\n }\n }\n\n /**\n * Clears all data from the index\n */\n clear(): void {\n this.orderedEntries.clear()\n this.valueMap.clear()\n this.indexedKeys.clear()\n this.clearRangeValues()\n }\n\n /**\n * Performs a lookup operation\n */\n lookup(operation: IndexOperation, value: any): Set<TKey> {\n let result: Set<TKey>\n\n switch (operation) {\n case `eq`:\n result = this.equalityLookup(value)\n break\n case `gt`:\n result = this.rangeQuery({ from: value, fromInclusive: false })\n break\n case `gte`:\n result = this.rangeQuery({ from: value, fromInclusive: true })\n break\n case `lt`:\n result = this.rangeQuery({ to: value, toInclusive: false })\n break\n case `lte`:\n result = this.rangeQuery({ to: value, toInclusive: true })\n break\n case `in`:\n result = this.inArrayLookup(value)\n break\n default:\n throw new Error(`Operation ${operation} not supported by BTreeIndex`)\n }\n return result\n }\n\n /**\n * Gets the number of indexed keys\n */\n get keyCount(): number {\n return this.indexedKeys.size\n }\n\n // Public methods for backward compatibility (used by tests)\n\n /**\n * Performs an equality lookup\n */\n equalityLookup(value: any): Set<TKey> {\n const normalizedValue = normalizeForBTree(value)\n return new Set(this.valueMap.get(normalizedValue)?.keys ?? [])\n }\n\n /**\n * Performs a range query with options\n * This is more efficient for compound queries like \"WHERE a > 5 AND a < 10\"\n */\n rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n const { from, to, fromInclusive = true, toInclusive = true } = options\n const result = new Set<TKey>()\n\n // Check if from/to were explicitly provided (even if undefined)\n // vs not provided at all (should use min/max key)\n const hasFrom = `from` in options\n const hasTo = `to` in options\n\n const fromKey = hasFrom\n ? normalizeForBTree(from)\n : this.orderedEntries.minKey()\n const toKey = hasTo ? normalizeForBTree(to) : this.orderedEntries.maxKey()\n\n this.orderedEntries.forRange(\n fromKey,\n toKey,\n toInclusive,\n (indexedValue, bucket) => {\n // Only exclude the boundary when an exclusive lower bound was\n // actually provided. Without a `from` bound, `fromKey` defaults to\n // the minimum key and must not be dropped. Compare against the\n // normalized key since indexed values are stored normalized\n // (e.g. dates as timestamps), so the raw `from` would never match.\n if (\n hasFrom &&\n !fromInclusive &&\n this.compareFn(indexedValue, fromKey) === 0\n ) {\n // the B+ tree `forRange` method does not support exclusive lower bounds\n // so we need to exclude it manually\n return\n }\n\n bucket.keys.forEach((key) => result.add(key))\n },\n )\n\n return result\n }\n\n /**\n * Internal method for taking items from the index.\n * @param n - The number of items to return\n * @param nextPair - Function to get the next pair from the BTree\n * @param from - Already normalized! undefined means \"start from beginning/end\", sentinel means \"start from the key undefined\"\n * @param filterFn - Optional filter function\n * @param reversed - Whether to reverse the order of keys within each value\n */\n private takeInternal(\n n: number,\n nextPair: (k?: any) => [any, OrderedBucket<TKey>] | undefined,\n from: any,\n filterFn?: (key: TKey) => boolean,\n reversed: boolean = false,\n ): Array<TKey> {\n const result: Array<TKey> = []\n let pair: [any, OrderedBucket<TKey>] | undefined\n let key = from // Use as-is - it's already normalized by the caller\n\n // Every key owns exactly one bucket, so the walk never repeats a key.\n while ((pair = nextPair(key)) !== undefined && result.length < n) {\n key = pair[0]\n // Sort keys for deterministic order within a comparator position.\n const sorted = Array.from(pair[1].keys).sort(\n reversed ? compareKeysReversed : compareKeys,\n )\n for (const ks of sorted) {\n if (result.length >= n) break\n if (filterFn?.(ks) ?? true) result.push(ks)\n }\n }\n\n return result\n }\n\n /**\n * Returns the next n items after the provided item.\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive).\n * @returns The next n items after the provided key.\n */\n take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)\n // Normalize the from value\n const normalizedFrom = normalizeForBTree(from)\n return this.takeInternal(n, nextPair, normalizedFrom, filterFn)\n }\n\n /**\n * Returns the first n items from the beginning.\n * @param n - The number of items to return\n * @param filterFn - Optional filter function\n * @returns The first n items\n */\n takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)\n // Pass undefined to mean \"start from beginning\" (BTree's native behavior)\n return this.takeInternal(n, nextPair, undefined, filterFn)\n }\n\n /**\n * Returns the next n items **before** the provided item (in descending order).\n * @param n - The number of items to return\n * @param from - The item to start from (exclusive). Required.\n * @returns The next n items **before** the provided key.\n */\n takeReversed(\n n: number,\n from: any,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)\n // Normalize the from value\n const normalizedFrom = normalizeForBTree(from)\n return this.takeInternal(n, nextPair, normalizedFrom, filterFn, true)\n }\n\n /**\n * Returns the last n items from the end.\n * @param n - The number of items to return\n * @param filterFn - Optional filter function\n * @returns The last n items\n */\n takeReversedFromEnd(\n n: number,\n filterFn?: (key: TKey) => boolean,\n ): Array<TKey> {\n const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)\n // Pass undefined to mean \"start from end\" (BTree's native behavior)\n return this.takeInternal(n, nextPair, undefined, filterFn, true)\n }\n\n /**\n * Performs an IN array lookup\n */\n inArrayLookup(values: Array<any>): Set<TKey> {\n const result = new Set<TKey>()\n\n for (const value of values) {\n const normalizedValue = normalizeForBTree(value)\n const keys = this.valueMap.get(normalizedValue)?.keys\n if (keys) {\n keys.forEach((key) => result.add(key))\n }\n }\n\n return result\n }\n}\n"],"names":["BaseIndex","defaultComparator","makeComparator","denormalizeUndefined","BTree","normalizeForBTree","areSameValueZeroEqual","compareKeysReversed","compareKeys"],"mappings":"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"}