UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

139 lines (138 loc) 4.31 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const d2mini = require("@electric-sql/d2mini"); const collection = require("../collection.cjs"); const pipelineCompiler = require("./pipeline-compiler.cjs"); function compileQuery(queryBuilder) { return new CompiledQuery(queryBuilder); } class CompiledQuery { constructor(queryBuilder) { this.state = `compiled`; this.unsubscribeCallbacks = []; const query = queryBuilder._query; const collections = query.collections; if (!collections) { throw new Error(`No collections provided`); } this.inputCollections = collections; const graph = new d2mini.D2(); const inputs = Object.fromEntries( Object.entries(collections).map(([key]) => [key, graph.newInput()]) ); const sync = ({ begin, write, commit }) => { pipelineCompiler.compileQueryPipeline( query, inputs ).pipe( d2mini.output((data) => { begin(); data.getInner().reduce((acc, [[key, value], multiplicity]) => { const changes = acc.get(key) || { deletes: 0, inserts: 0, value }; if (multiplicity < 0) { changes.deletes += Math.abs(multiplicity); } else if (multiplicity > 0) { changes.inserts += multiplicity; changes.value = value; } acc.set(key, changes); return acc; }, /* @__PURE__ */ new Map()).forEach((changes, rawKey) => { const { deletes, inserts, value } = changes; const valueWithKey = { ...value, _key: rawKey }; if (inserts && !deletes) { write({ value: valueWithKey, type: `insert` }); } else if (inserts >= deletes) { write({ value: valueWithKey, type: `update` }); } else if (deletes > 0) { write({ value: valueWithKey, type: `delete` }); } }); commit(); }) ); graph.finalize(); }; this.graph = graph; this.inputs = inputs; this.resultCollection = collection.createCollection({ id: crypto.randomUUID(), // TODO: remove when we don't require any more getKey: (val) => { return val._key; }, sync: { sync } }); } get results() { return this.resultCollection; } sendChangesToInput(inputKey, changes, getKey) { const input = this.inputs[inputKey]; const multiSetArray = []; for (const change of changes) { const key = getKey(change.value); if (change.type === `insert`) { multiSetArray.push([[key, change.value], 1]); } else if (change.type === `update`) { multiSetArray.push([[key, change.previousValue], -1]); multiSetArray.push([[key, change.value], 1]); } else { multiSetArray.push([[key, change.value], -1]); } } input.sendData(new d2mini.MultiSet(multiSetArray)); } runGraph() { this.graph.run(); } start() { if (this.state === `running`) { throw new Error(`Query is already running`); } else if (this.state === `stopped`) { throw new Error(`Query is stopped`); } Object.entries(this.inputCollections).forEach(([key, collection2]) => { this.sendChangesToInput( key, collection2.currentStateAsChanges(), collection2.config.getKey ); }); this.runGraph(); Object.entries(this.inputCollections).forEach(([key, collection2]) => { const unsubscribe = collection2.subscribeChanges((changes) => { this.sendChangesToInput(key, changes, collection2.config.getKey); this.runGraph(); }); this.unsubscribeCallbacks.push(unsubscribe); }); this.state = `running`; return () => { this.stop(); }; } stop() { this.unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe()); this.unsubscribeCallbacks = []; this.state = `stopped`; } } exports.CompiledQuery = CompiledQuery; exports.compileQuery = compileQuery; //# sourceMappingURL=compiled-query.cjs.map