@electric-sql/d2mini
Version:
D2Mini is a minimal implementation of Differential Dataflow for performing in-memory incremental view maintenance.
94 lines • 2.96 kB
JavaScript
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