UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

120 lines (119 loc) 4 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const dbIvm = require("@tanstack/db-ivm"); const functions = require("../builder/functions.cjs"); const ir = require("../ir.cjs"); class SubsetDemandController { constructor() { this.states = /* @__PURE__ */ new Map(); this.warnedPlans = /* @__PURE__ */ new Set(); } setDemand(subscription, plan, keys) { const nextKeys = canonicalizeKeys(keys); const previous = this.states.get(plan.id); const hasFailedCoverage = previous?.segments.some( (segment) => segment.state === `failed` && intersects(segment.keys, nextKeys) ); if (previous && equalKeySets(previous.keys, nextKeys) && !hasFailedCoverage) { return { changed: false, empty: nextKeys.size === 0, ready: true }; } const segments = []; for (const segment of previous?.segments ?? []) { if (segment.state !== `failed` && intersects(segment.keys, nextKeys)) { segments.push(segment); continue; } segment.abortController.abort(); subscription.releaseSnapshot(segment.where); } const coveredKeys = new Set( segments.flatMap((segment) => [...segment.keys.keys()]) ); const added = new Map( [...nextKeys].filter(([key]) => !coveredKeys.has(key)) ); if (added.size > 0) { segments.push( requestSegment( subscription, plan, added, () => this.warnUnoptimized(plan) ) ); } if (nextKeys.size === 0) { this.states.delete(plan.id); } else { this.states.set(plan.id, { keys: nextKeys, segments }); } const activeSegments = segments.filter( (segment) => intersects(segment.keys, nextKeys) ); const pending = activeSegments.map((segment) => segment.ready).filter((ready) => ready instanceof Promise); return { changed: true, empty: nextKeys.size === 0, ready: pending.length > 0 ? Promise.all(pending).then(() => void 0) : true }; } clear() { for (const state of this.states.values()) { for (const segment of state.segments) segment.abortController.abort(); } this.states.clear(); this.warnedPlans.clear(); } warnUnoptimized(plan) { if (this.warnedPlans.has(plan.id)) return; this.warnedPlans.add(plan.id); const path = plan.path.join(`.`); console.warn( `[TanStack DB]${plan.collectionId ? ` [${plan.collectionId}]` : ``} Join requires an index on "${path}" for efficient loading. Falling back to scanning local data. Consider creating an index on the collection with collection.createIndex((row) => row.${path}) or enable auto-indexing with autoIndex: 'eager' and a defaultIndexType.` ); } } function canonicalizeKeys(keys) { return new Map([...keys].map((key) => [dbIvm.serializeValue(key), key])); } function equalKeySets(left, right) { return left.size === right.size && [...left.keys()].every((key) => right.has(key)); } function intersects(left, right) { return [...left.keys()].some((key) => right.has(key)); } function requestSegment(subscription, plan, keys, onUnoptimized) { const where = functions.inArray(new ir.PropRef(plan.path), [...keys.values()]); const abortController = new AbortController(); const load = { ready: true }; subscription.requestSnapshot({ where, signal: abortController.signal, trackLoadSubsetPromise: false, onUnoptimized, onLoadSubsetResult: (result) => { load.ready = result; } }); const ready = load.ready; const segment = { keys, where, abortController, ready, state: ready instanceof Promise ? `pending` : `settled` }; if (ready instanceof Promise) { void ready.then( () => { segment.state = `settled`; }, () => { segment.state = `failed`; } ); } return segment; } exports.SubsetDemandController = SubsetDemandController; //# sourceMappingURL=subset-demand-controller.cjs.map