@tanstack/db
Version:
A reactive client store for building super fast apps on sync
192 lines (191 loc) • 5.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const comparison = require("../utils/comparison.cjs");
const btree = require("../utils/btree.cjs");
const baseIndex = require("./base-index.cjs");
class BTreeIndex extends baseIndex.BaseIndex {
constructor(id, expression, name, options) {
super(id, expression, name, options);
this.supportedOperations = /* @__PURE__ */ new Set([
`eq`,
`gt`,
`gte`,
`lt`,
`lte`,
`in`
]);
this.valueMap = /* @__PURE__ */ new Map();
this.indexedKeys = /* @__PURE__ */ new Set();
this.compareFn = comparison.ascComparator;
this.compareFn = (options == null ? void 0 : options.compareFn) ?? comparison.ascComparator;
this.orderedEntries = new btree.BTree(this.compareFn);
}
initialize(_options) {
}
/**
* Adds a value to the index
*/
add(key, item) {
let indexedValue;
try {
indexedValue = this.evaluateIndexExpression(item);
} catch (error) {
throw new Error(
`Failed to evaluate index expression for key ${key}: ${error}`
);
}
if (this.valueMap.has(indexedValue)) {
this.valueMap.get(indexedValue).add(key);
} else {
const keySet = /* @__PURE__ */ new Set([key]);
this.valueMap.set(indexedValue, keySet);
this.orderedEntries.set(indexedValue, void 0);
}
this.indexedKeys.add(key);
this.updateTimestamp();
}
/**
* Removes a value from the index
*/
remove(key, item) {
let indexedValue;
try {
indexedValue = this.evaluateIndexExpression(item);
} catch (error) {
console.warn(
`Failed to evaluate index expression for key ${key} during removal:`,
error
);
return;
}
if (this.valueMap.has(indexedValue)) {
const keySet = this.valueMap.get(indexedValue);
keySet.delete(key);
if (keySet.size === 0) {
this.valueMap.delete(indexedValue);
this.orderedEntries.delete(indexedValue);
}
}
this.indexedKeys.delete(key);
this.updateTimestamp();
}
/**
* Updates a value in the index
*/
update(key, oldItem, newItem) {
this.remove(key, oldItem);
this.add(key, newItem);
}
/**
* Builds the index from a collection of entries
*/
build(entries) {
this.clear();
for (const [key, item] of entries) {
this.add(key, item);
}
}
/**
* Clears all data from the index
*/
clear() {
this.orderedEntries.clear();
this.valueMap.clear();
this.indexedKeys.clear();
this.updateTimestamp();
}
/**
* Performs a lookup operation
*/
lookup(operation, value) {
const startTime = performance.now();
let result;
switch (operation) {
case `eq`:
result = this.equalityLookup(value);
break;
case `gt`:
result = this.rangeQuery({ from: value, fromInclusive: false });
break;
case `gte`:
result = this.rangeQuery({ from: value, fromInclusive: true });
break;
case `lt`:
result = this.rangeQuery({ to: value, toInclusive: false });
break;
case `lte`:
result = this.rangeQuery({ to: value, toInclusive: true });
break;
case `in`:
result = this.inArrayLookup(value);
break;
default:
throw new Error(`Operation ${operation} not supported by BTreeIndex`);
}
this.trackLookup(startTime);
return result;
}
/**
* Gets the number of indexed keys
*/
get keyCount() {
return this.indexedKeys.size;
}
// Public methods for backward compatibility (used by tests)
/**
* Performs an equality lookup
*/
equalityLookup(value) {
return new Set(this.valueMap.get(value) ?? []);
}
/**
* Performs a range query with options
* This is more efficient for compound queries like "WHERE a > 5 AND a < 10"
*/
rangeQuery(options = {}) {
const { from, to, fromInclusive = true, toInclusive = true } = options;
const result = /* @__PURE__ */ new Set();
const fromKey = from ?? this.orderedEntries.minKey();
const toKey = to ?? this.orderedEntries.maxKey();
this.orderedEntries.forRange(
fromKey,
toKey,
toInclusive,
(indexedValue, _) => {
if (!fromInclusive && this.compareFn(indexedValue, from) === 0) {
return;
}
const keys = this.valueMap.get(indexedValue);
if (keys) {
keys.forEach((key) => result.add(key));
}
}
);
return result;
}
/**
* Performs an IN array lookup
*/
inArrayLookup(values) {
const result = /* @__PURE__ */ new Set();
for (const value of values) {
const keys = this.valueMap.get(value);
if (keys) {
keys.forEach((key) => result.add(key));
}
}
return result;
}
// Getter methods for testing compatibility
get indexedKeysSet() {
return this.indexedKeys;
}
get orderedEntriesArray() {
return this.orderedEntries.keysArray().map((key) => [key, this.valueMap.get(key) ?? /* @__PURE__ */ new Set()]);
}
get valueMapData() {
return this.valueMap;
}
}
exports.BTreeIndex = BTreeIndex;
//# sourceMappingURL=btree-index.cjs.map