@tanstack/db
Version:
A reactive client store for building super fast apps on sync
1 lines • 10.8 kB
Source Map (JSON)
{"version":3,"file":"lazy-targets.cjs","sources":["../../../../src/query/compiler/lazy-targets.ts"],"sourcesContent":["import {\n PropRef,\n collectCollectionSources,\n followRef,\n getFromSources,\n} from '../ir.js'\nimport type {\n BasicExpression,\n CollectionRef,\n From,\n QueryIR,\n QueryRef,\n} from '../ir.js'\nimport type { Collection } from '../../collection/index.js'\n\nexport type LazyLoadTarget = {\n sourceId: string\n alias: string\n collection: Collection\n path: Array<string>\n}\n\nexport function getLazyLoadTargets(\n rawQuery: QueryIR,\n lazyFrom: From,\n lazyAlias: string,\n lazySourceExpr: BasicExpression,\n lazySource: Collection | undefined,\n aliasRemapping: Record<string, string>,\n): Array<LazyLoadTarget> {\n if (lazyFrom.type === `unionFrom`) {\n return getTargetsFromExpression(rawQuery, lazySourceExpr)\n }\n\n if (lazyFrom.type === `queryRef` && containsUnionFrom(lazyFrom.query.from)) {\n const targets = getTargetsFromQueryRef(\n lazyFrom.query,\n lazyAlias,\n lazySourceExpr,\n )\n return dedupeLazyLoadTargets(targets)\n }\n\n if (!lazySource) {\n return []\n }\n\n const lazySourceRef = toPropRef(lazySourceExpr)\n if (!lazySourceRef) {\n return []\n }\n\n const followRefResult = followRef(rawQuery, lazySourceRef, lazySource)\n if (!followRefResult) {\n return []\n }\n\n const alias = followRefResult.alias || aliasRemapping[lazyAlias] || lazyAlias\n const source = resolveLazySource(rawQuery, lazyFrom, {\n alias,\n collection: followRefResult.collection,\n sourceId: followRefResult.sourceId,\n })\n if (!source) {\n return []\n }\n\n // The subscription we drive lazy loading through must be the one for the\n // collection the join key actually resolves to. When the key traces through a\n // subquery's select into a *joined* source, that collection differs from the\n // subquery's from clause (which is what `aliasRemapping[lazyAlias]` yields),\n // so prefer the alias reported by `followRef`. Fall back to the from-clause\n // remapping when the key resolves directly to the from source.\n return [\n {\n sourceId: source.sourceId,\n alias,\n collection: followRefResult.collection,\n path: followRefResult.path,\n },\n ]\n}\n\nexport function containsUnionFrom(from: From): boolean {\n if (from.type === `unionFrom`) {\n return true\n }\n if (from.type === `queryRef`) {\n return containsUnionFrom(from.query.from)\n }\n if (from.type === `unionAll`) {\n return from.queries.some((query) => containsUnionFrom(query.from))\n }\n return false\n}\n\nfunction getTargetsFromQueryRef(\n query: QueryIR,\n outerAlias: string,\n expr: unknown,\n): Array<LazyLoadTarget> {\n if (!expr || typeof expr !== `object` || !(`type` in expr)) {\n return []\n }\n\n const expression = expr as BasicExpression\n if (expression.type === `func` && expression.name === `coalesce`) {\n return dedupeLazyLoadTargets(\n expression.args.flatMap((arg) =>\n getTargetsFromQueryRef(query, outerAlias, arg),\n ),\n )\n }\n\n const ref = toPropRef(expression)\n if (!ref || ref.path[0] !== outerAlias) {\n return []\n }\n\n return getTargetsFromPropRef(query, new PropRef(ref.path.slice(1)))\n}\n\nfunction getTargetsFromExpression(\n query: QueryIR,\n expr: unknown,\n): Array<LazyLoadTarget> {\n if (!expr || typeof expr !== `object` || !(`type` in expr)) {\n return []\n }\n\n const expression = expr as BasicExpression\n if (expression.type === `ref`) {\n return getTargetsFromPropRef(query, expression)\n }\n\n if (expression.type === `func` && expression.name === `coalesce`) {\n return dedupeLazyLoadTargets(\n expression.args.flatMap((arg) => getTargetsFromExpression(query, arg)),\n )\n }\n\n return []\n}\n\nfunction getTargetsFromPropRef(\n query: QueryIR,\n ref: PropRef,\n): Array<LazyLoadTarget> {\n if (ref.path.length === 0) {\n return []\n }\n\n if (ref.path.length === 1) {\n const field = ref.path[0]!\n const selectedField = query.select?.[field]\n if (selectedField) {\n return getTargetsFromExpression(query, selectedField)\n }\n return []\n }\n\n const [alias, ...path] = ref.path\n const source = getSourceFromAlias(query, alias!, ref.bindingId)\n if (!source) {\n return []\n }\n\n if (source.type === `collectionRef`) {\n return [\n {\n sourceId: source.sourceId,\n alias: source.alias,\n collection: source.collection,\n path,\n },\n ]\n }\n\n if (\n source.query.limit !== undefined ||\n source.query.offset !== undefined ||\n source.query.singleResult\n ) {\n return []\n }\n\n return getTargetsFromQueryRef(source.query, source.alias, ref)\n}\n\nfunction getSourceFromAlias(\n query: QueryIR,\n alias: string,\n bindingId?: string,\n): CollectionRef | QueryRef | undefined {\n if (query.join) {\n for (const join of query.join) {\n if (\n join.from.alias === alias &&\n (bindingId === undefined || join.from.bindingId === bindingId)\n ) {\n return join.from\n }\n }\n }\n\n return getFromSources(query.from).find(\n (source) =>\n source.alias === alias &&\n (bindingId === undefined || source.bindingId === bindingId),\n )\n}\n\nfunction resolveLazySource(\n query: QueryIR,\n lazyFrom: From,\n target: { alias: string; collection: Collection; sourceId?: string },\n): CollectionRef | undefined {\n // Subscription and demand callbacks belong to one lexical source. An alias\n // may also name a source in a nested scope, so text cannot resolve it here.\n if (target.sourceId !== undefined) {\n return collectCollectionSources(query).find(\n (source) =>\n source.sourceId === target.sourceId &&\n source.collection === target.collection,\n )\n }\n\n // A direct source has no recursive alias ambiguity. A recursive source with\n // no resolved ID cannot safely receive a keyed demand.\n if (\n lazyFrom.type === `collectionRef` &&\n lazyFrom.collection === target.collection &&\n lazyFrom.alias === target.alias\n ) {\n return lazyFrom\n }\n\n return undefined\n}\n\nfunction dedupeLazyLoadTargets(\n targets: Array<LazyLoadTarget>,\n): Array<LazyLoadTarget> {\n const seen = new Set<string>()\n const deduped: Array<LazyLoadTarget> = []\n for (const target of targets) {\n const key = `${target.sourceId}:${JSON.stringify(target.path)}`\n if (!seen.has(key)) {\n seen.add(key)\n deduped.push(target)\n }\n }\n return deduped\n}\n\nfunction toPropRef(expr: unknown): PropRef | undefined {\n if (expr instanceof PropRef) {\n return expr\n }\n if (\n expr &&\n typeof expr === `object` &&\n `type` in expr &&\n (expr as { type?: string }).type === `ref` &&\n Array.isArray((expr as { path?: unknown }).path)\n ) {\n const ref = expr as unknown as {\n path: Array<string>\n sourceAlias?: string\n }\n return new PropRef(ref.path, ref.sourceAlias)\n }\n return undefined\n}\n"],"names":["followRef","PropRef","getFromSources","collectCollectionSources"],"mappings":"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"}