UNPKG

@electric-sql/d2mini

Version:

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

94 lines 2.96 kB
import { DefaultMap, chunkedArrayPush, hash } from './utils.js'; /** * A multiset of data. */ export class MultiSet { #inner; constructor(data = []) { this.#inner = data; } toString(indent = false) { return `MultiSet(${JSON.stringify(this.#inner, null, indent ? 2 : undefined)})`; } 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(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(this.#inner.filter(([data, _]) => f(data))); } /** * Negate all multiplicities in the collection. */ negate() { return new MultiSet(this.#inner.map(([data, multiplicity]) => [data, -multiplicity])); } /** * Concatenate two collections together. */ concat(other) { const out = []; chunkedArrayPush(out, this.#inner); 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() { const consolidated = new DefaultMap(() => 0); const values = new Map(); let hasString = false; let hasNumber = false; let hasOther = false; for (const [data, _] of 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 this.#inner) { const key = requireJson ? 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); } extend(other) { const otherArray = other instanceof MultiSet ? other.getInner() : other; chunkedArrayPush(this.#inner, otherArray); } getInner() { return this.#inner; } } //# sourceMappingURL=multiset.js.map