@tanstack/db
Version:
A reactive client store for building super fast apps on sync
110 lines (109 loc) • 5.36 kB
TypeScript
import { RootStreamBuilder } from '@tanstack/db-ivm';
import { Collection } from '../../collection/index.js';
import { ChangeMessage } from '../../types.js';
import { InitialQueryBuilder, QueryBuilder } from '../builder/index.js';
import { Context } from '../builder/types.js';
import { OrderBy, QueryIR } from '../ir.js';
import { OrderByOptimizationInfo } from '../compiler/order-by.js';
/**
* Helper function to extract collections from a compiled query.
* Traverses the query IR to find all collection references.
* Maps collections by their ID (not alias) as expected by the compiler.
*/
export declare function extractCollectionsFromQuery(query: any): Record<string, Collection<any, any, any>>;
/**
* Helper function to extract the collection that is referenced in the query's FROM clause.
* The FROM clause may refer directly to a collection or indirectly to a subquery.
*/
export declare function extractCollectionFromSource(query: any): Collection<any, any, any>;
/**
* Extracts all aliases used for each collection across the entire query tree.
*
* Traverses the QueryIR recursively to build a map from collection ID to all aliases
* that reference that collection. This is essential for self-join support, where the
* same collection may be referenced multiple times with different aliases.
*
* For example, given a query like:
* ```ts
* q.from({ employee: employeesCollection })
* .join({ manager: employeesCollection }, ({ employee, manager }) =>
* eq(employee.managerId, manager.id)
* )
* ```
*
* This function would return:
* ```
* Map { "employees" => Set { "employee", "manager" } }
* ```
*
* @param query - The query IR to extract aliases from
* @returns A map from collection ID to the set of all aliases referencing that collection
*/
export declare function extractCollectionAliases(query: QueryIR): Map<string, Set<string>>;
/**
* Builds a query IR from a config object that contains either a query builder
* function or a QueryBuilder instance.
*/
export declare function buildQueryFromConfig<TContext extends Context>(config: {
query: ((q: InitialQueryBuilder) => QueryBuilder<TContext>) | QueryBuilder<TContext>;
}): QueryIR;
/**
* Helper function to send changes to a D2 input stream.
* Converts ChangeMessages to D2 MultiSet data and sends to the input.
*
* @returns The number of multiset entries sent
*/
export declare function sendChangesToInput(input: RootStreamBuilder<unknown>, changes: Iterable<ChangeMessage>, getKey: (item: ChangeMessage[`value`]) => any): number;
/** Splits updates into a delete of the old value and an insert of the new value */
export declare function splitUpdates<T extends object = Record<string, unknown>, TKey extends string | number = string | number>(changes: Iterable<ChangeMessage<T, TKey>>): Generator<ChangeMessage<T, TKey>>;
/**
* Filter changes to prevent duplicate inserts to a D2 pipeline.
* Maintains D2 multiplicity at 1 for visible items so that deletes
* properly reduce multiplicity to 0.
*
* Mutates `sentKeys` in place: adds keys on insert, removes on delete.
*/
export declare function filterDuplicateInserts(changes: Array<ChangeMessage<any, string | number>>, sentKeys: Set<string | number>): Array<ChangeMessage<any, string | number>>;
/**
* Track the biggest value seen in a stream of changes, used for cursor-based
* pagination in ordered subscriptions. Returns whether the load request key
* should be reset (allowing another load).
*
* @param changes - changes to process (deletes are skipped)
* @param current - the current biggest value (or undefined if none)
* @param sentKeys - set of keys already sent to D2 (for new-key detection)
* @param comparator - orderBy comparator
* @returns `{ biggest, shouldResetLoadKey }` — the new biggest value and
* whether the caller should clear its last-load-request-key
*/
export declare function trackBiggestSentValue(changes: Array<ChangeMessage<any, string | number>>, current: unknown | undefined, sentKeys: Set<string | number>, comparator: (a: any, b: any) => number): {
biggest: unknown;
shouldResetLoadKey: boolean;
};
/**
* Compute orderBy/limit subscription hints for an alias.
* Returns normalised orderBy and effective limit suitable for passing to
* `subscribeChanges`, or `undefined` values when the query's orderBy cannot
* be scoped to the given alias (e.g. cross-collection refs or aggregates).
*/
export declare function computeSubscriptionOrderByHints(query: {
orderBy?: OrderBy;
limit?: number;
offset?: number;
}, alias: string): {
orderBy: OrderBy | undefined;
limit: number | undefined;
};
/**
* Compute the cursor for loading the next batch of ordered data.
* Extracts values from the biggest sent row and builds the `minValues`
* array and a deduplication key.
*
* @returns `undefined` if the load should be skipped (duplicate request),
* otherwise `{ minValues, normalizedOrderBy, loadRequestKey }`.
*/
export declare function computeOrderedLoadCursor(orderByInfo: Pick<OrderByOptimizationInfo, 'orderBy' | 'valueExtractorForRawRow' | 'offset'>, biggestSentRow: unknown | undefined, lastLoadRequestKey: string | undefined, alias: string, limit: number): {
minValues: Array<unknown> | undefined;
normalizedOrderBy: OrderBy;
loadRequestKey: string;
} | undefined;