UNPKG

@electric-sql/d2mini

Version:

D2Mini is a minimal implementation of Differential Dataflow for performing in-memory incremental view maintenance.

67 lines 2.69 kB
import { DifferenceStreamWriter, UnaryOperator, } from '../graph.js'; import { StreamBuilder } from '../d2.js'; import { hash } from '../utils.js'; import { MultiSet } from '../multiset.js'; /** * Operator that removes duplicates */ export class DistinctOperator extends UnaryOperator { #by; #values; // keeps track of the number of times each value has been seen constructor(id, input, output, by = (value) => value) { super(id, input, output); this.#by = by; this.#values = new Map(); } run() { const updatedValues = new Map(); // Compute the new multiplicity for each value for (const message of this.inputMessages()) { for (const [value, diff] of message.getInner()) { const hashedValue = hash(this.#by(value)); const oldMultiplicity = updatedValues.get(hashedValue)?.[0] ?? this.#values.get(hashedValue) ?? 0; const newMultiplicity = oldMultiplicity + diff; updatedValues.set(hashedValue, [newMultiplicity, value]); } } const result = []; // Check which values became visible or disappeared for (const [hashedValue, [newMultiplicity, value],] of updatedValues.entries()) { const oldMultiplicity = this.#values.get(hashedValue) ?? 0; if (newMultiplicity === 0) { this.#values.delete(hashedValue); } else { this.#values.set(hashedValue, newMultiplicity); } if (oldMultiplicity <= 0 && newMultiplicity > 0) { // The value wasn't present in the stream // but with this change it is now present in the stream result.push([value, 1]); } else if (oldMultiplicity > 0 && newMultiplicity <= 0) { // The value was present in the stream // but with this change it is no longer present in the stream result.push([value, -1]); } } if (result.length > 0) { this.output.sendData(new MultiSet(result)); } } } /** * Removes duplicate values */ export function distinct(by = (value) => value) { return (stream) => { const output = new StreamBuilder(stream.graph, new DifferenceStreamWriter()); const operator = new DistinctOperator(stream.graph.getNextOperatorId(), stream.connectReader(), output.writer, by); stream.graph.addOperator(operator); stream.graph.addStream(output.connectReader()); return output; }; } //# sourceMappingURL=distinct.js.map