@tanstack/db
Version:
A reactive client store for building super fast apps on sync
140 lines (121 loc) • 3.89 kB
text/typescript
import {
CollectionRef,
ConditionalSelect,
IncludesSubquery,
QueryRef,
UnionAll,
UnionFrom,
isExpressionLike,
} from '../ir.js'
import { isRefProxy } from './ref-proxy-identity.js'
import type { From, QueryIR, Select, SelectValueExpression } from '../ir.js'
/**
* 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; CollectionRefs
* cannot because their sourceId identifies that lexical position.
*/
export function cloneQueryForPlacement(query: QueryIR): QueryIR {
return cloneQuery(query, new WeakMap())
}
function cloneQuery(query: QueryIR, clones: WeakMap<object, object>): QueryIR {
const existing = clones.get(query)
if (existing) return existing as QueryIR
const cloned: QueryIR = {
...query,
}
clones.set(query, cloned)
cloned.from = cloneFromForPlacement(query.from, clones)
cloned.join = query.join?.map((join) => ({
...join,
from: cloneSourceForPlacement(join.from, clones),
}))
cloned.select =
query.select === undefined || isExpressionLike(query.select)
? query.select
: cloneSelectForPlacement(query.select, clones)
return cloned
}
function cloneFromForPlacement(
from: From,
clones: WeakMap<object, object>,
): From {
if (from.type === `unionFrom`) {
return new UnionFrom(
from.sources.map((source) => cloneSourceForPlacement(source, clones)),
)
}
if (from.type === `unionAll`) {
return new UnionAll(from.queries.map((query) => cloneQuery(query, clones)))
}
return cloneSourceForPlacement(from, clones)
}
function cloneSourceForPlacement(
source: CollectionRef | QueryRef,
clones: WeakMap<object, object>,
): CollectionRef | QueryRef {
if (source.type === `collectionRef`) {
return new CollectionRef(source.collection, source.alias)
}
return new QueryRef(cloneQuery(source.query, clones), source.alias)
}
function cloneSelectForPlacement(
select: Select,
clones: WeakMap<object, object>,
): Select {
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, clones)
}
return cloned
}
function cloneSelectValueForPlacement(
value: unknown,
clones: WeakMap<object, object>,
): SelectValueExpression {
if (value instanceof IncludesSubquery) {
const existing = clones.get(value)
if (existing) return existing as IncludesSubquery
const cloned = new IncludesSubquery(
cloneQuery(value.query, clones),
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, clones),
})),
value.defaultValue !== undefined
? cloneSelectValueForPlacement(value.defaultValue, clones)
: 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, clones)
}