@tanstack/db-ivm
Version:
Incremental View Maintenance for TanStack DB based on Differential Dataflow
146 lines (145 loc) • 4.42 kB
JavaScript
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