@tanstack/db-ivm
Version:
Incremental View Maintenance for TanStack DB based on Differential Dataflow
157 lines (156 loc) • 6.29 kB
JavaScript
"use strict";
var __typeError = (msg) => {
throw TypeError(msg);
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
var _valueIndex, _hashIndex, _Index_instances, entries_fn, entriesIterators_fn;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const multiset = require("./multiset.cjs");
const hashIndex = require("./hashIndex.cjs");
const valueIndex = require("./valueIndex.cjs");
const utils = require("./utils.cjs");
class Index {
constructor() {
__privateAdd(this, _Index_instances);
/*
* This is a hybrid Index that composes a ValueIndex and a HashIndex.
* Keys that have only one value are stored in the ValueIndex.
* Keys that have multiple values are stored in the HashIndex, the hash distinguishes between the values.
* This reduces the amount of hashes we need to compute since often times only a small portion of the keys are updated
* so we don't have to hash the keys that are never updated.
*
* Note: The `valueIndex` and `hashIndex` have disjoint keys.
* When a key that has only one value gets a new distinct value,
* it is added to the `hashIndex` and removed from the `valueIndex` and vice versa.
*/
__privateAdd(this, _valueIndex);
__privateAdd(this, _hashIndex);
__privateSet(this, _valueIndex, new valueIndex.ValueIndex());
__privateSet(this, _hashIndex, new hashIndex.HashIndex());
}
toString(indent = false) {
return `Index(
${__privateGet(this, _valueIndex).toString(indent)},
${__privateGet(this, _hashIndex).toString(indent)}
)`;
}
get(key) {
if (__privateGet(this, _valueIndex).has(key)) {
return [__privateGet(this, _valueIndex).get(key)];
}
return __privateGet(this, _hashIndex).get(key);
}
getMultiplicity(key, value) {
if (__privateGet(this, _valueIndex).has(key)) {
return __privateGet(this, _valueIndex).getMultiplicity(key);
}
return __privateGet(this, _hashIndex).getMultiplicity(key, value);
}
has(key) {
return __privateGet(this, _valueIndex).has(key) || __privateGet(this, _hashIndex).has(key);
}
get size() {
return __privateGet(this, _valueIndex).size + __privateGet(this, _hashIndex).size;
}
addValue(key, value) {
const containedInValueIndex = __privateGet(this, _valueIndex).has(key);
const containedInHashIndex = __privateGet(this, _hashIndex).has(key);
if (containedInHashIndex && containedInValueIndex) {
throw new Error(
`Key ${key} is contained in both the value index and the hash index. This should never happen because they should have disjoint keysets.`
);
}
if (!containedInValueIndex && !containedInHashIndex) {
__privateGet(this, _valueIndex).addValue(key, value);
return;
}
if (containedInValueIndex) {
try {
__privateGet(this, _valueIndex).addValue(key, value);
} catch {
const existingValue = __privateGet(this, _valueIndex).get(key);
__privateGet(this, _valueIndex).delete(key);
__privateGet(this, _hashIndex).addValue(key, existingValue);
__privateGet(this, _hashIndex).addValue(key, value);
}
return;
}
if (containedInHashIndex) {
const singleRemainingValue = __privateGet(this, _hashIndex).addValue(key, value);
if (singleRemainingValue) {
__privateGet(this, _hashIndex).delete(key);
__privateGet(this, _valueIndex).addValue(key, singleRemainingValue);
}
return;
}
}
append(other) {
var _a;
for (const [key, value] of __privateMethod(_a = other, _Index_instances, entries_fn).call(_a)) {
this.addValue(key, value);
}
}
join(other) {
var _a;
const result = [];
if (this.size <= other.size) {
for (const [key, valueIt] of __privateMethod(this, _Index_instances, entriesIterators_fn).call(this)) {
if (!other.has(key)) continue;
const otherValues = other.get(key);
for (const [val1, mul1] of valueIt) {
for (const [val2, mul2] of otherValues) {
if (mul1 !== 0 && mul2 !== 0) {
result.push([[key, [val1, val2]], mul1 * mul2]);
}
}
}
}
} else {
for (const [key, otherValueIt] of __privateMethod(_a = other, _Index_instances, entriesIterators_fn).call(_a)) {
if (!this.has(key)) continue;
const values = this.get(key);
for (const [val2, mul2] of otherValueIt) {
for (const [val1, mul1] of values) {
if (mul1 !== 0 && mul2 !== 0) {
result.push([[key, [val1, val2]], mul1 * mul2]);
}
}
}
}
}
return new multiset.MultiSet(result);
}
}
_valueIndex = new WeakMap();
_hashIndex = new WeakMap();
_Index_instances = new WeakSet();
/**
* This returns an iterator that iterates over all key-value pairs.
* @returns An iterable of all key-value pairs (and their multiplicities) in the index.
*/
entries_fn = function() {
return utils.concatIterable(
__privateGet(this, _valueIndex).entries(),
__privateGet(this, _hashIndex).entriesIterator()
);
};
entriesIterators_fn = function* () {
for (const [key, [value, multiplicity]] of __privateGet(this, _valueIndex).entries()) {
yield [key, /* @__PURE__ */ new Map([[value, multiplicity]])];
}
for (const [key, valueMap] of __privateGet(this, _hashIndex).entries()) {
yield [
key,
utils.mapIterable(valueMap, ([_hash, [value, multiplicity]]) => [
value,
multiplicity
])
];
}
};
exports.Index = Index;
//# sourceMappingURL=indexes.cjs.map