UNPKG

@tanstack/db-ivm

Version:

Incremental View Maintenance for TanStack DB based on Differential Dataflow

146 lines (145 loc) 4.42 kB
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 _indexA, _indexB; import { BinaryOperator, DifferenceStreamWriter } from "../graph.js"; import { StreamBuilder } from "../d2.js"; import { MultiSet } from "../multiset.js"; import { Index } from "../indexes.js"; import { negate } from "./negate.js"; import { map } from "./map.js"; import { concat } from "./concat.js"; class JoinOperator extends BinaryOperator { constructor(id, inputA, inputB, output) { super(id, inputA, inputB, output); __privateAdd(this, _indexA, new Index()); __privateAdd(this, _indexB, new Index()); } run() { const deltaA = new Index(); const deltaB = new Index(); const messagesA = this.inputAMessages(); for (const message of messagesA) { const multiSetMessage = message; for (const [item, multiplicity] of multiSetMessage.getInner()) { const [key, value] = item; deltaA.addValue(key, [value, multiplicity]); } } const messagesB = this.inputBMessages(); for (const message of messagesB) { const multiSetMessage = message; for (const [item, multiplicity] of multiSetMessage.getInner()) { const [key, value] = item; deltaB.addValue(key, [value, multiplicity]); } } const results = new MultiSet(); results.extend(deltaA.join(__privateGet(this, _indexB))); __privateGet(this, _indexA).append(deltaA); results.extend(__privateGet(this, _indexA).join(deltaB)); if (results.getInner().length > 0) { this.output.sendData(results); } __privateGet(this, _indexB).append(deltaB); } } _indexA = new WeakMap(); _indexB = new WeakMap(); function join(other, type = `inner`) { switch (type) { case `inner`: return innerJoin(other); case `anti`: return antiJoin(other); case `left`: return leftJoin(other); case `right`: return rightJoin(other); case `full`: return fullJoin(other); default: throw new Error(`Join type ${type} is invalid`); } } function innerJoin(other) { return (stream) => { if (stream.graph !== other.graph) { throw new Error(`Cannot join streams from different graphs`); } const output = new StreamBuilder( stream.graph, new DifferenceStreamWriter() ); const operator = new JoinOperator( stream.graph.getNextOperatorId(), stream.connectReader(), other.connectReader(), output.writer ); stream.graph.addOperator(operator); stream.graph.addStream(output.connectReader()); return output; }; } function antiJoin(other) { return (stream) => { const matchedLeft = stream.pipe( innerJoin(other), map(([key, [valueLeft, _valueRight]]) => [key, valueLeft]) ); const anti = stream.pipe( concat(matchedLeft.pipe(negate())), // @ts-ignore TODO: fix this map(([key, value]) => [key, [value, null]]) ); return anti; }; } function leftJoin(other) { return (stream) => { const left = stream; const right = other; const inner = left.pipe(innerJoin(right)); const anti = left.pipe(antiJoin(right)); return inner.pipe(concat(anti)); }; } function rightJoin(other) { return (stream) => { const left = stream; const right = other; const inner = left.pipe(innerJoin(right)); const anti = right.pipe( antiJoin(left), map(([key, [a, b]]) => [key, [b, a]]) ); return inner.pipe(concat(anti)); }; } function fullJoin(other) { return (stream) => { const left = stream; const right = other; const inner = left.pipe(innerJoin(right)); const antiLeft = left.pipe(antiJoin(right)); const antiRight = right.pipe( antiJoin(left), map(([key, [a, b]]) => [key, [b, a]]) ); return inner.pipe(concat(antiLeft), concat(antiRight)); }; } export { JoinOperator, antiJoin, fullJoin, innerJoin, join, leftJoin, rightJoin }; //# sourceMappingURL=join.js.map