UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

178 lines (177 loc) 7.8 kB
import { LIVE_QUERY_INTERNAL, LiveQueryInternalUtils } from './internal.js'; import { WindowOptions } from '../compiler/index.js'; import { SchedulerContextId } from '../../scheduler.js'; import { CollectionSubscription } from '../../collection/subscription.js'; import { OrderByOptimizationInfo } from '../compiler/order-by.js'; import { Collection } from '../../collection/index.js'; import { CollectionConfigSingleRowOption, SyncConfig, UtilsRecord } from '../../types.js'; import { Context, GetResult } from '../builder/types.js'; import { BasicExpression, QueryIR } from '../ir.js'; import { LazyCollectionCallbacks } from '../compiler/joins.js'; import { FullSyncState, LiveQueryCollectionConfig } from './types.js'; export type LiveQueryCollectionUtils = UtilsRecord & { /** Most recent subset-load failure observed by this live query. */ readonly lastSubsetError: unknown | undefined; /** * Sets the offset and limit of an ordered query. * Is a no-op if the query is not ordered. * * @returns `true` if no subset loading was triggered, or `Promise<void>` that resolves when the subset has been loaded */ setWindow: (options: WindowOptions) => true | Promise<void>; /** * Gets the current window (offset and limit) for an ordered query. * * @returns The current window settings, or `undefined` if the query is not windowed */ getWindow: () => { offset: number; limit: number; } | undefined; [LIVE_QUERY_INTERNAL]: LiveQueryInternalUtils; }; export declare class CollectionConfigBuilder<TContext extends Context, TResult extends object = GetResult<TContext>> { private readonly config; private readonly id; readonly query: QueryIR; private readonly collections; private readonly collectionSources; private readonly resultKeys; private readonly orderByIndices; private readonly compare?; private readonly compareOptions?; private isGraphRunning; currentSyncConfig: Parameters<SyncConfig<TResult>[`sync`]>[0] | undefined; currentSyncState: FullSyncState | undefined; private isInErrorState; private fatalQueryError; private readonly erroredSourceIds; private lastSubsetError; liveQueryCollection?: Collection<TResult, any, any>; private windowFn; private readonly initialWindow; private currentWindow; private settledWindow; private activeWindowOperation; private maybeRunGraphFn; private readonly builderDependencies; private readonly pendingGraphRuns; private unsubscribeFromSchedulerClears?; private graphCache; private inputsCache; private pipelineCache; sourceWhereClausesCache: Map<string, BasicExpression<boolean>> | undefined; private bucketFacadesCache; readonly subscriptions: Record<string, CollectionSubscription>; lazySourcesCallbacks: Record<string, LazyCollectionCallbacks>; readonly lazySources: Set<string>; private readonly activeDemands; private readonly demandGenerations; private readonly pendingOrderedLoads; private orderedLoadFailed; private windowFailed; private syncSession; private windowOperationGeneration; optimizableOrderByCollections: Record<string, OrderByOptimizationInfo>; constructor(config: LiveQueryCollectionConfig<TContext, TResult>); /** * Recursively checks if a query or any of its subqueries contains joins */ private hasJoins; getConfig(): CollectionConfigSingleRowOption<TResult> & { utils: LiveQueryCollectionUtils; }; setWindow(options: WindowOptions): true | Promise<void>; getWindow(): { offset: number; limit: number; } | undefined; isLazySource(sourceId: string): boolean; beginDemand(planId: string): number; settleDemand(planId: string, generation: number): void; failDemand(planId: string, generation: number, error: unknown): void; recordSubsetError(error: unknown, fatalBeforeReady?: boolean): Error; trackSubsetLoadPromise(promise: Promise<unknown>): void; trackSubsetLoadOperationPromise(promise: Promise<unknown>): void; hasActiveWindowOperation(): boolean; getActiveWindowOperationGeneration(): number | undefined; scheduleGraphRunForSession(syncSession: number): void; trackOrderedLoadPromise(promise: Promise<unknown>, holdPublication?: boolean): void; retireDemand(planId: string): void; hasPendingSourceRecovery(): boolean; private pendingSourceRecovery; private hasFailedSourceRecovery; getSyncSession(): number; maybeRunGraph(callback?: () => void): void; /** * Schedules a graph run with the transaction-scoped scheduler. * Ensures each builder runs at most once per transaction, with automatic dependency tracking * to run parent queries before child queries. Outside a transaction, runs immediately. * * Multiple calls during a transaction are coalesced into a single execution. * Dependencies are auto-discovered from subscribed live queries, or can be overridden. * Load callbacks are combined when entries merge. * * Uses the current sync session's config and syncState from instance properties. * * @param callback - Optional callback to load more data if needed * @param options - Optional scheduling configuration * @param options.contextId - Transaction ID to group work; defaults to active transaction * @param options.jobId - Unique identifier for this job; defaults to this builder instance * @param options.dependencies - Explicit dependency list; overrides auto-discovered dependencies */ scheduleGraphRun(callback?: () => void, options?: { contextId?: SchedulerContextId; jobId?: unknown; dependencies?: Array<CollectionConfigBuilder<any, any>>; }): void; /** * Clears pending graph run state for a specific context. * Called when the scheduler clears a context (e.g., transaction rollback/abort). */ clearPendingGraphRun(contextId: SchedulerContextId): void; /** * Returns true if this builder has a pending graph run for the given context. */ hasPendingGraphRun(contextId: SchedulerContextId): boolean; /** * Executes a pending graph run. Called by the scheduler when dependencies are satisfied. * Clears the pending state BEFORE execution so that any re-schedules during the run * create fresh state and don't interfere with the current execution. * Uses instance sync state - if sync has ended, gracefully returns without executing. * * @param contextId - Optional context ID to look up pending state * @param pendingParam - For immediate execution (no context), pending state is passed directly */ private executeGraphRun; private getSyncConfig; private syncFn; private clearSyncSessionState; /** * Compiles the query pipeline with all declared aliases. */ private compileBasePipeline; private maybeCompileBasePipeline; private extendPipelineWithChangeProcessing; private applyChanges; /** * Handle status changes from source collections */ private handleSourceStatusChange; /** * Update the live query status based on source collection statuses */ private updateLiveQueryStatus; /** * Transition the live query to error state */ private transitionToError; private setErrorState; private allRequiredSourcesReady; /** * Creates one subscription per lexical collection source. * Each source gets independent filters, even when aliases or collections repeat. * Example: `{ employee: col, manager: col }` creates two separate subscriptions. */ private subscribeToAllCollections; }