UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

179 lines (157 loc) • 4.95 kB
import { CollectionRef, ConditionalSelect, DescriptorRef, IncludesSubquery, QueryRef, UnionAll, UnionFrom, isExpressionLike, } from '../ir.js' import { isRefProxy } from './ref-proxy-identity.js' import type { CollectionImpl } from '../../collection/index.js' import type { CollectionOptionsIdentity } from '../../collection-options.js' import type { CollectionSourceRef, From, QueryIR, Select, SelectValueExpression, } from '../ir.js' export type CollectionResolver = ( options: CollectionOptionsIdentity<any, string | number, any, any, any>, ) => CollectionImpl<any, string | number, any, any, any> type CloneContext = { clones: WeakMap<object, object> resolveDescriptor?: CollectionResolver } /** * Gives every query-source placement its own runtime source identities. * * A reused builder describes the same query meaning, but each FROM, JOIN, * UNION, or include placement owns an independent position in the dataflow * graph. Expressions are immutable and can remain shared; source refs cannot * because their sourceId identifies that lexical position. A supplied * resolver also binds any retained descriptors while cloning the plan. */ export function cloneQueryForPlacement( query: QueryIR, resolveCollection?: CollectionResolver, ): QueryIR { return cloneQuery(query, { clones: new WeakMap(), resolveDescriptor: resolveCollection, }) } function cloneQuery(query: QueryIR, context: CloneContext): QueryIR { const { clones } = context const existing = clones.get(query) if (existing) return existing as QueryIR const cloned: QueryIR = { ...query, } clones.set(query, cloned) cloned.from = cloneFromForPlacement(query.from, context) cloned.join = query.join?.map((join) => ({ ...join, from: cloneSourceForPlacement(join.from, context), })) cloned.select = query.select === undefined || isExpressionLike(query.select) ? query.select : cloneSelectForPlacement(query.select, context) return cloned } function cloneFromForPlacement(from: From, context: CloneContext): From { if (from.type === `unionFrom`) { return new UnionFrom( from.sources.map((source) => cloneSourceForPlacement(source, context)), ) } if (from.type === `unionAll`) { return new UnionAll(from.queries.map((query) => cloneQuery(query, context))) } return cloneSourceForPlacement(from, context) } function cloneSourceForPlacement( source: CollectionSourceRef | QueryRef, context: CloneContext, ): CollectionSourceRef | QueryRef { if (source.type === `collectionRef`) { return new CollectionRef(source.collection, source.alias, source.bindingId) } if (source.type === `descriptorRef`) { return context.resolveDescriptor ? new CollectionRef( context.resolveDescriptor(source.descriptor), source.alias, source.bindingId, ) : new DescriptorRef(source.descriptor, source.alias, source.bindingId) } return new QueryRef( cloneQuery(source.query, context), source.alias, source.bindingId, ) } function cloneSelectForPlacement( select: Select, context: CloneContext, ): Select { const { clones } = context const existing = clones.get(select) if (existing) return existing as Select const cloned: Select = {} clones.set(select, cloned) for (const [field, value] of Object.entries(select)) { cloned[field] = cloneSelectValueForPlacement(value, context) } return cloned } function cloneSelectValueForPlacement( value: unknown, context: CloneContext, ): SelectValueExpression { const { clones } = context if (value instanceof IncludesSubquery) { const existing = clones.get(value) if (existing) return existing as IncludesSubquery const cloned = new IncludesSubquery( cloneQuery(value.query, context), value.correlationField, value.childCorrelationField, value.fieldName, value.parentFilters, value.parentProjection, value.materialization, value.scalarField, ) clones.set(value, cloned) return cloned } if (value instanceof ConditionalSelect) { const existing = clones.get(value) if (existing) return existing as ConditionalSelect const cloned = new ConditionalSelect( value.branches.map((branch) => ({ ...branch, value: cloneSelectValueForPlacement(branch.value, context), })), value.defaultValue !== undefined ? cloneSelectValueForPlacement(value.defaultValue, context) : undefined, ) clones.set(value, cloned) return cloned } if (value === null || typeof value !== `object` || Array.isArray(value)) { return value as SelectValueExpression } if (isRefProxy(value)) { return value as unknown as SelectValueExpression } return isExpressionLike(value) ? (value as SelectValueExpression) : cloneSelectForPlacement(value as Select, context) }