UNPKG

@tanstack/db-ivm

Version:

Incremental View Maintenance for TanStack DB based on Differential Dataflow

175 lines (174 loc) 6.43 kB
"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 _inner, _MultiSet_instances, consolidateKeyed_fn, consolidateUnkeyed_fn; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const utils = require("./utils.cjs"); const hash = require("./hashing/hash.cjs"); const _MultiSet = class _MultiSet { constructor(data = []) { __privateAdd(this, _MultiSet_instances); __privateAdd(this, _inner); __privateSet(this, _inner, data); } toString(indent = false) { return `MultiSet(${JSON.stringify(__privateGet(this, _inner), null, indent ? 2 : void 0)})`; } toJSON() { return JSON.stringify(Array.from(this.getInner())); } static fromJSON(json) { return new _MultiSet(JSON.parse(json)); } /** * Apply a function to all records in the collection. */ map(f) { return new _MultiSet( __privateGet(this, _inner).map(([data, multiplicity]) => [f(data), multiplicity]) ); } /** * Filter out records for which a function f(record) evaluates to False. */ filter(f) { return new _MultiSet(__privateGet(this, _inner).filter(([data, _]) => f(data))); } /** * Negate all multiplicities in the collection. */ negate() { return new _MultiSet( __privateGet(this, _inner).map(([data, multiplicity]) => [data, -multiplicity]) ); } /** * Concatenate two collections together. */ concat(other) { const out = []; utils.chunkedArrayPush(out, __privateGet(this, _inner)); utils.chunkedArrayPush(out, other.getInner()); return new _MultiSet(out); } /** * Produce as output a collection that is logically equivalent to the input * but which combines identical instances of the same record into one * (record, multiplicity) pair. */ consolidate() { var _a; if (__privateGet(this, _inner).length > 0) { const firstItem = (_a = __privateGet(this, _inner)[0]) == null ? void 0 : _a[0]; if (Array.isArray(firstItem) && firstItem.length === 2) { return __privateMethod(this, _MultiSet_instances, consolidateKeyed_fn).call(this); } } return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this); } extend(other) { const otherArray = other instanceof _MultiSet ? other.getInner() : other; utils.chunkedArrayPush(__privateGet(this, _inner), otherArray); } getInner() { return __privateGet(this, _inner); } }; _inner = new WeakMap(); _MultiSet_instances = new WeakSet(); /** * Private method for consolidating keyed multisets where keys are strings/numbers * and values are compared by reference equality. * * This method provides significant performance improvements over the hash-based approach * by using WeakMap for object reference tracking and avoiding expensive serialization. * * Special handling for join operations: When values are tuples of length 2 (common in joins), * we unpack them and compare each element individually to maintain proper equality semantics. */ consolidateKeyed_fn = function() { const consolidated = /* @__PURE__ */ new Map(); const values = /* @__PURE__ */ new Map(); const getTupleId = (tuple) => { if (tuple.length !== 2) { throw new Error(`Expected tuple of length 2`); } const [first, second] = tuple; return `${utils.globalObjectIdGenerator.getStringId(first)}|${utils.globalObjectIdGenerator.getStringId(second)}`; }; for (const [data, multiplicity] of __privateGet(this, _inner)) { if (!Array.isArray(data) || data.length !== 2) { return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this); } const [key, value] = data; if (typeof key !== `string` && typeof key !== `number`) { return __privateMethod(this, _MultiSet_instances, consolidateUnkeyed_fn).call(this); } let valueId; if (Array.isArray(value) && value.length === 2) { valueId = getTupleId(value); } else { valueId = utils.globalObjectIdGenerator.getStringId(value); } const compositeKey = key + `|` + valueId; consolidated.set( compositeKey, (consolidated.get(compositeKey) || 0) + multiplicity ); if (!values.has(compositeKey)) { values.set(compositeKey, data); } } const result = []; for (const [compositeKey, multiplicity] of consolidated) { if (multiplicity !== 0) { result.push([values.get(compositeKey), multiplicity]); } } return new _MultiSet(result); }; /** * Private method for consolidating unkeyed multisets using the original approach. */ consolidateUnkeyed_fn = function() { const consolidated = new utils.DefaultMap(() => 0); const values = /* @__PURE__ */ new Map(); let hasString = false; let hasNumber = false; let hasOther = false; for (const [data, _] of __privateGet(this, _inner)) { if (typeof data === `string`) { hasString = true; } else if (typeof data === `number`) { hasNumber = true; } else { hasOther = true; break; } } const requireJson = hasOther || hasString && hasNumber; for (const [data, multiplicity] of __privateGet(this, _inner)) { const key = requireJson ? hash.hash(data) : data; if (requireJson && !values.has(key)) { values.set(key, data); } consolidated.update(key, (count) => count + multiplicity); } const result = []; for (const [key, multiplicity] of consolidated.entries()) { if (multiplicity !== 0) { const parsedKey = requireJson ? values.get(key) : key; result.push([parsedKey, multiplicity]); } } return new _MultiSet(result); }; let MultiSet = _MultiSet; exports.MultiSet = MultiSet; //# sourceMappingURL=multiset.cjs.map