{"version":3,"file":"joins.cjs","sources":["../../../../src/query/compiler/joins.ts"],"sourcesContent":["import {\n  join as joinOperator,\n  map,\n  serializeValue,\n  tap,\n} from '@tanstack/db-ivm'\nimport {\n  CollectionInputNotFoundError,\n  InvalidJoinCondition,\n  InvalidJoinConditionLeftSourceError,\n  InvalidJoinConditionRightSourceError,\n  InvalidJoinConditionSameSourceError,\n  InvalidJoinConditionSourceMismatchError,\n  JoinCollectionNotFoundError,\n  UnsupportedFromTypeError,\n  UnsupportedJoinSourceTypeError,\n  UnsupportedJoinTypeError,\n} from '../../errors.js'\nimport { getParentContextIdentity } from '../equality-value-identity.js'\nimport { ensureIndexForField } from '../../indexes/auto-index.js'\nimport { validateJoinConditions } from '../join-conditions.js'\nimport {\n  Value as ValClass,\n  collectPropRefs,\n  getFromSources,\n  getPropRefSourceAlias,\n  requireCollectionSource,\n} from '../ir.js'\nimport { compileExpression } from './evaluators.js'\nimport { getLazyLoadTargets } from './lazy-targets.js'\nimport { crossJoinParentRoutes } from './parent-routes.js'\nimport { queriesMatchForCaching } from './query-equivalence.js'\nimport {\n  INCLUDES_PUBLIC_KEY,\n  attachRouteMetadata,\n  attachRouteMetadataToResult,\n  getNamespacedRouteMetadata,\n  mergeSourceContext,\n  wrapInputRow,\n} from './route-metadata.js'\nimport type { RowMetadata } from './route-metadata.js'\nimport type { ValueIdentity } from '../equality-value-identity.js'\nimport type {\n  CompilationResult,\n  IncludesCompilationResult,\n  SourceInclude,\n} from './index.js'\nimport type {\n  BasicExpression,\n  CollectionSourceRef,\n  From,\n  JoinClause,\n  PropRef,\n  QueryIR,\n  QueryRef,\n} from '../ir.js'\nimport type { IStreamBuilder, JoinType } from '@tanstack/db-ivm'\nimport type { Collection } from '../../collection/index.js'\nimport type {\n  InputRow,\n  KeyedStream,\n  NamespacedAndKeyedStream,\n  NamespacedRow,\n} from '../../types.js'\nimport type { QueryMapping } from './types.js'\n\ntype CompileSubquery = (\n  query: QueryIR,\n  parentKeyStream?: KeyedStream,\n) => CompilationResult\n\nexport type LazyDemandPlan = {\n  id: string\n  path: Array<string>\n  collectionId: string\n  initialKeys: Set<unknown>\n}\n\n/** Callbacks for managing lazy-loaded collections in optimized joins */\nexport type LazyCollectionCallbacks = {\n  plans?: Array<LazyDemandPlan>\n  setDemand?: (plan: LazyDemandPlan, keys: Set<unknown>) => void\n}\n\ntype JoinInputValue = [\n  originalKey: unknown,\n  namespacedRow: NamespacedRow,\n  joinValue: unknown,\n]\n\nlet nextLazyDemandPlanId = 0\n\nfunction parameterizeJoinInputByParentRoutes(\n  input: KeyedStream,\n  parentKeyStream: KeyedStream,\n  valueIdentity: ValueIdentity,\n): KeyedStream {\n  return crossJoinParentRoutes(\n    input,\n    parentKeyStream,\n    (rowKey, row, correlationKey, parentContext, metadata) => {\n      return [\n        serializeValue([\n          valueIdentity.equality(rowKey),\n          valueIdentity.equality(correlationKey),\n          getParentContextIdentity(parentContext),\n        ]),\n        attachRouteMetadata(\n          {\n            ...(row as Record<string, unknown>),\n          },\n          correlationKey,\n          parentContext,\n        ),\n        metadata,\n      ] as unknown as [unknown, unknown]\n    },\n  )\n}\n\nfunction getRouteJoinKey(\n  row: NamespacedRow,\n  source: string,\n  equalityKey: unknown,\n  valueIdentity: ValueIdentity,\n): string {\n  const route = getNamespacedRouteMetadata(row, source)\n  return serializeValue([\n    valueIdentity.equality(route?.correlationKey),\n    getParentContextIdentity(route?.parentContext ?? null),\n    equalityKey,\n  ])\n}\n\nfunction keyJoinInput(\n  originalKey: unknown,\n  row: NamespacedRow,\n  source: string,\n  side: `main` | `joined`,\n  expressions: Array<(row: NamespacedRow) => unknown>,\n  routeJoinedSource: boolean,\n  valueIdentity: ValueIdentity,\n): [string, JoinInputValue] {\n  const value = expressions[0]!(row)\n  const input: JoinInputValue = [originalKey, row, undefined]\n  // NUL-prefixed side-local keys cannot collide with serializeValue output.\n  // Unsatisfiable tuples retain their row but contribute no lazy demand.\n  const unmatchedKey = side === `main` ? `\\0m` : `\\0j`\n  if (value == null) return [unmatchedKey, input]\n  let key = valueIdentity.equality(value)\n  // Keep the single-equality path free of temporary operand arrays.\n  if (expressions.length > 1) {\n    const values = [key]\n    for (let index = 1; index < expressions.length; index++) {\n      const component = expressions[index]!(row)\n      if (component == null) return [unmatchedKey, input]\n      values.push(valueIdentity.equality(component))\n    }\n    key = values\n  }\n  // Demand uses the raw value, while matching uses graph-local equality.\n  input[2] = value\n  return [\n    routeJoinedSource\n      ? getRouteJoinKey(row, source, key, valueIdentity)\n      : serializeValue(key),\n    input,\n  ]\n}\n\nexport function registerLazyDemandPlan(\n  callbacks: Record<string, LazyCollectionCallbacks>,\n  target: { sourceId: string; path: Array<string>; collection: Collection },\n  initialKeys: Set<unknown> = new Set(),\n): LazyDemandPlan {\n  const plan: LazyDemandPlan = {\n    id: `lazy-demand-${++nextLazyDemandPlanId}`,\n    path: target.path,\n    collectionId: target.collection.id,\n    initialKeys: new Set(initialKeys),\n  }\n  const state = (callbacks[target.sourceId] ??= {})\n  ;(state.plans ??= []).push(plan)\n  return plan\n}\n\n/**\n * Processes all join clauses, applying lazy loading optimizations and maintaining\n * alias tracking for per-alias subscriptions (enables self-joins).\n */\nexport function processJoins(\n  pipeline: NamespacedAndKeyedStream,\n  joinClauses: Array<JoinClause>,\n  sources: Record<string, KeyedStream>,\n  mainCollectionId: string,\n  mainSource: string,\n  allInputs: Record<string, KeyedStream>,\n  queryMapping: QueryMapping,\n  collections: Record<string, Collection>,\n  callbacks: Record<string, LazyCollectionCallbacks>,\n  lazySources: Set<string>,\n  rawQuery: QueryIR,\n  localFrom: From,\n  onCompileSubquery: CompileSubquery,\n  aliasToCollectionId: Record<string, string>,\n  aliasRemapping: Record<string, string>,\n  sourceWhereClauses: Map<string, BasicExpression<boolean>>,\n  mainSourceIsParentFiltered: boolean,\n  valueIdentity: ValueIdentity,\n  sourceIncludes: Array<SourceInclude>,\n  parentKeyStream?: KeyedStream,\n): NamespacedAndKeyedStream {\n  const localBindings = new Set(\n    getFromSources(localFrom).map((source) => source.bindingId),\n  )\n\n  // The loop owns the source bindings and compiler context for each join.\n  function processJoin(\n    inputPipeline: NamespacedAndKeyedStream,\n    joinClause: JoinClause,\n  ): NamespacedAndKeyedStream {\n    const joinedSource = joinClause.from.alias\n    const mainAliases = Object.keys(sources)\n    const role = (ref: PropRef): JoinRefRole => {\n      const alias = getJoinRefAlias(ref)\n      if (ref.bindingId !== undefined) {\n        if (ref.bindingId === joinClause.from.bindingId) return `joined`\n        return localBindings.has(ref.bindingId) ? `main` : `ancestor`\n      }\n      if (alias === joinedSource) return `joined`\n      if (\n        alias &&\n        (mainAliases.includes(alias) || rawQuery.from.type === `unionAll`)\n      )\n        return `main`\n      return `unknown`\n    }\n    const conditions = validateJoinConditions(joinClause.on).map(\n      ([left, right]) =>\n        analyzeJoinExpressions(left, right, joinedSource, role),\n    )\n    // The first equality supplies candidate demand; the full tuple decides matches.\n    const { mainExpr, joinedExpr } = conditions[0]!\n    const joinedExpressionUsesParent = conditions.some(\n      ({ joinedExpr: expression }) =>\n        collectPropRefs(expression).some((ref) => {\n          const sourceRole = role(ref)\n          return sourceRole === `ancestor` || sourceRole === `unknown`\n        }),\n    )\n    const routeJoinedSource =\n      parentKeyStream !== undefined &&\n      (joinClause.from.type === `queryRef` ||\n        ((joinClause.type === `right` || joinClause.type === `full`) &&\n          !mainSourceIsParentFiltered) ||\n        joinedExpressionUsesParent)\n\n    // Get the joined source alias and input stream\n    const {\n      alias: processedJoinedSource,\n      input: joinedInput,\n      collectionId: joinedCollectionId,\n      includes,\n    } = processSource(\n      joinClause.from,\n      allInputs,\n      queryMapping,\n      onCompileSubquery,\n      aliasToCollectionId,\n      aliasRemapping,\n      sourceWhereClauses,\n      valueIdentity,\n      `join`,\n      routeJoinedSource ? parentKeyStream : undefined,\n    )\n\n    if (processedJoinedSource !== joinedSource) {\n      throw new InvalidJoinConditionSourceMismatchError()\n    }\n\n    // Add the joined source to the sources map\n    sources[joinedSource] = joinedInput\n    if (includes)\n      sourceIncludes.push(\n        ...includes.map((include) => ({ sourceAlias: joinedSource, include })),\n      )\n\n    const mainCollection = collections[mainCollectionId]\n    const joinedCollection = collections[joinedCollectionId]\n\n    if (!mainCollection) {\n      throw new JoinCollectionNotFoundError(mainCollectionId)\n    }\n\n    if (!joinedCollection) {\n      throw new JoinCollectionNotFoundError(joinedCollectionId)\n    }\n\n    const sourceActivity = getActiveAndLazySources(\n      joinClause.type,\n      mainCollection,\n      joinedCollection,\n      mainSourceIsParentFiltered,\n    )\n    const activeSource = routeJoinedSource\n      ? undefined\n      : sourceActivity.activeSource\n    const lazySource = sourceActivity.lazySource\n\n    // Pre-compile the join expressions\n    const compiledMainExpressions = conditions.map((condition) =>\n      compileExpression(condition.mainExpr),\n    )\n    const compiledJoinedExpressions = conditions.map((condition) =>\n      compileExpression(condition.joinedExpr),\n    )\n\n    // Prepare both sides with the same key and raw-demand rules.\n    let mainPipeline = inputPipeline.pipe(\n      map(([currentKey, namespacedRow]) =>\n        keyJoinInput(\n          currentKey,\n          namespacedRow,\n          mainSource,\n          `main`,\n          compiledMainExpressions,\n          routeJoinedSource,\n          valueIdentity,\n        ),\n      ),\n    )\n\n    let joinedPipeline = joinedInput.pipe(\n      map(([currentKey, row, metadata]: [...InputRow, unknown?]) =>\n        keyJoinInput(\n          currentKey,\n          wrapInputRow(\n            joinedSource,\n            row,\n            metadata as RowMetadata | null | undefined,\n            routeJoinedSource || joinClause.from.type === `queryRef`,\n          ),\n          joinedSource,\n          `joined`,\n          compiledJoinedExpressions,\n          routeJoinedSource,\n          valueIdentity,\n        ),\n      ),\n    )\n\n    // Apply the join operation\n    if (![`inner`, `left`, `right`, `full`].includes(joinClause.type)) {\n      throw new UnsupportedJoinTypeError(joinClause.type)\n    }\n\n    if (activeSource) {\n      // If the lazy collection comes from a subquery that has a limit and/or an offset clause\n      // then we need to deoptimize the join because we don't know which rows are in the result set\n      // since we simply lookup matching keys in the index but the index contains all rows\n      // (not just the ones that pass the limit and offset clauses)\n      const lazyFrom = activeSource === `main` ? joinClause.from : rawQuery.from\n      const limitedSubquery =\n        lazyFrom.type === `queryRef` &&\n        (lazyFrom.query.limit !== undefined ||\n          lazyFrom.query.offset !== undefined ||\n          lazyFrom.query.singleResult)\n      const resultUnionLazySide = lazyFrom.type === `unionAll`\n\n      const lazySourceJoinExpr = activeSource === `main` ? joinedExpr : mainExpr\n      const lazyAlias = activeSource === `main` ? joinedSource : mainSource\n      const lazyTargets = resultUnionLazySide\n        ? []\n        : getLazyLoadTargets(\n            rawQuery,\n            lazyFrom,\n            lazyAlias,\n            lazySourceJoinExpr,\n            lazySource,\n            aliasRemapping,\n          )\n\n      if (!limitedSubquery && lazyTargets.length > 0) {\n        // This join can be optimized by having the active collection\n        // dynamically load keys into the lazy collection\n        // based on the value of the joinKey and by looking up\n        // matching rows in the index of the lazy collection\n\n        // Mark the lazy source aliases as lazy\n        // this Set is passed by the liveQueryCollection to the compiler\n        // such that the liveQueryCollection can check it after compilation\n        // to know which source aliases should load data lazily (not initially)\n        for (const target of lazyTargets) {\n          lazySources.add(target.sourceId)\n        }\n\n        const demandPlans = lazyTargets.map((target) =>\n          registerLazyDemandPlan(callbacks, target),\n        )\n        const demandWeights = new Map<\n          string,\n          { key: unknown; weight: number }\n        >()\n\n        const activePipeline =\n          activeSource === `main` ? mainPipeline : joinedPipeline\n\n        for (const target of lazyTargets) {\n          const fieldName = target.path[0]\n          if (fieldName) {\n            ensureIndexForField(fieldName, target.path, target.collection)\n          }\n        }\n\n        // Set up lazy loading: intercept active side's stream and dynamically load\n        // matching rows from lazy side based on join keys.\n        const activePipelineWithLoading: IStreamBuilder<\n          [key: string, value: JoinInputValue]\n        > = activePipeline.pipe(\n          tap((data) => {\n            for (const [\n              [joinKey, [, , joinValue]],\n              weight,\n            ] of data.getInner()) {\n              if (joinValue == null) continue\n              const previous = demandWeights.get(joinKey)\n              const nextWeight = (previous?.weight ?? 0) + weight\n              if (nextWeight === 0) {\n                demandWeights.delete(joinKey)\n              } else {\n                demandWeights.set(joinKey, {\n                  key: previous?.key ?? joinValue,\n                  weight: nextWeight,\n                })\n              }\n            }\n\n            const keys = new Set(\n              [...demandWeights.values()]\n                .filter(({ weight }) => weight > 0)\n                .map(({ key }) => key),\n            )\n            for (let index = 0; index < lazyTargets.length; index++) {\n              const target = lazyTargets[index]!\n              callbacks[target.sourceId]?.setDemand?.(demandPlans[index]!, keys)\n            }\n          }),\n        )\n\n        if (activeSource === `main`) {\n          mainPipeline = activePipelineWithLoading\n        } else {\n          joinedPipeline = activePipelineWithLoading\n        }\n      }\n    }\n\n    return mainPipeline.pipe(\n      joinOperator(joinedPipeline, joinClause.type as JoinType),\n      processJoinResults(\n        joinedSource,\n        mainAliases,\n        parentKeyStream !== undefined,\n      ),\n    )\n  }\n\n  for (const joinClause of joinClauses) {\n    pipeline = processJoin(pipeline, joinClause)\n    localBindings.add(joinClause.from.bindingId)\n  }\n\n  return pipeline\n}\n\ntype JoinRefRole = `joined` | `main` | `ancestor` | `unknown`\n\nfunction getJoinRefAlias(ref: PropRef): string | undefined {\n  return getPropRefSourceAlias(ref) ?? ref.path[0]\n}\n\n/**\n * Analyzes join expressions to determine which refers to which source\n * and returns them in the correct order (available source expression first, joined source expression second)\n */\nfunction analyzeJoinExpressions(\n  left: BasicExpression,\n  right: BasicExpression,\n  joinedSource: string,\n  role: (ref: PropRef) => JoinRefRole,\n): { mainExpr: BasicExpression; joinedExpr: BasicExpression } {\n  const leftRefs = collectPropRefs(left)\n  const rightRefs = collectPropRefs(right)\n  const leftRoles = new Set(leftRefs.map(role))\n  const rightRoles = new Set(rightRefs.map(role))\n  const leftMain = leftRoles.has(`main`) || leftRoles.has(`ancestor`)\n  const rightMain = rightRoles.has(`main`) || rightRoles.has(`ancestor`)\n  const leftJoined = leftRoles.has(`joined`)\n  const rightJoined = rightRoles.has(`joined`)\n\n  // If left expression refers to an available source and right refers to joined source, keep as is\n  if (leftMain && !leftJoined && rightJoined && !rightRoles.has(`main`)) {\n    return { mainExpr: left, joinedExpr: right }\n  }\n\n  // If left expression refers to joined source and right refers to an available source, swap them\n  if (leftJoined && !leftRoles.has(`main`) && rightMain && !rightJoined) {\n    return { mainExpr: right, joinedExpr: left }\n  }\n\n  // If one expression doesn't refer to any source, this is an invalid join\n  if (leftRefs.length === 0 || rightRefs.length === 0) {\n    throw new InvalidJoinConditionSourceMismatchError()\n  }\n\n  // If both expressions refer to the same alias, this is an invalid join\n  if (\n    leftRefs.length === 1 &&\n    rightRefs.length === 1 &&\n    (leftRefs[0]!.bindingId !== undefined &&\n    rightRefs[0]!.bindingId !== undefined\n      ? leftRefs[0]!.bindingId === rightRefs[0]!.bindingId\n      : getJoinRefAlias(leftRefs[0]!) === getJoinRefAlias(rightRefs[0]!))\n  ) {\n    throw new InvalidJoinConditionSameSourceError(\n      getJoinRefAlias(leftRefs[0]!)!,\n    )\n  }\n\n  // Left side must refer to an available source\n  // This cannot happen with the query builder as there is no way to build a ref\n  // to an unavailable source, but just in case, but could happen with the IR\n  if (!leftMain) {\n    throw new InvalidJoinConditionLeftSourceError(\n      getJoinRefAlias(leftRefs[0]!)!,\n    )\n  }\n\n  // Right side must refer to the joined source\n  if (!rightJoined) {\n    throw new InvalidJoinConditionRightSourceError(joinedSource)\n  }\n\n  // This should not be reachable given the logic above, but just in case\n  throw new InvalidJoinCondition()\n}\n\n/**\n * Compiles a FROM or JOIN source and propagates its source metadata.\n */\nexport function processSource(\n  from: CollectionSourceRef | QueryRef,\n  allInputs: Record<string, KeyedStream>,\n  queryMapping: QueryMapping,\n  onCompileSubquery: CompileSubquery,\n  aliasToCollectionId: Record<string, string>,\n  aliasRemapping: Record<string, string>,\n  sourceWhereClauses: Map<string, BasicExpression<boolean>>,\n  valueIdentity: ValueIdentity,\n  sourceKind: `from` | `join`,\n  parentKeyStream?: KeyedStream,\n): {\n  alias: string\n  input: KeyedStream\n  collectionId: string\n  includes?: Array<IncludesCompilationResult>\n} {\n  switch (from.type) {\n    case `descriptorRef`:\n      return requireCollectionSource(from)\n    case `collectionRef`: {\n      const input = allInputs[from.sourceId]\n      if (!input) {\n        throw new CollectionInputNotFoundError(\n          from.alias,\n          from.collection.id,\n          Object.keys(allInputs),\n        )\n      }\n      aliasToCollectionId[from.alias] = from.collection.id\n      return {\n        alias: from.alias,\n        input:\n          sourceKind === `join` && parentKeyStream\n            ? parameterizeJoinInputByParentRoutes(\n                input,\n                parentKeyStream,\n                valueIdentity,\n              )\n            : input,\n        collectionId: from.collection.id,\n      }\n    }\n    case `queryRef`: {\n      // Preserve the user-defined query as the cache key when optimization\n      // only copied it. If the optimizer changed the query, compile that IR;\n      // substituting its origin would discard pushed predicates.\n      const originalQuery = queryMapping.get(from.query)\n      const queryToCompile =\n        originalQuery && queriesMatchForCaching(from.query, originalQuery)\n          ? originalQuery\n          : from.query\n      const subQueryResult = onCompileSubquery(queryToCompile, parentKeyStream)\n\n      Object.assign(aliasToCollectionId, subQueryResult.aliasToCollectionId)\n      Object.assign(aliasRemapping, subQueryResult.aliasRemapping)\n      // Optimizer-created wrappers already contributed their predicates to the\n      // parent. User-authored subqueries must export their own source predicates.\n      if (\n        queryMapping.has(from.query) ||\n        from.alias !== getFromSources(from.query.from)[0]?.alias\n      ) {\n        for (const [alias, where] of subQueryResult.sourceWhereClauses)\n          sourceWhereClauses.set(alias, where)\n      }\n      // Resolve directly to the innermost alias, so nested scopes need one lookup.\n      const innerAlias = Object.keys(subQueryResult.aliasToCollectionId).find(\n        (alias) =>\n          subQueryResult.aliasToCollectionId[alias] ===\n          subQueryResult.collectionId,\n      )\n      if (innerAlias && innerAlias !== from.alias)\n        aliasRemapping[from.alias] = innerAlias\n\n      // Extract the pipeline from the compilation result\n      const subQueryInput = subQueryResult.pipeline\n\n      // Subqueries may return [key, [value, orderByIndex]] (with ORDER BY) or [key, value] (without ORDER BY)\n      // We need to extract just the value for use in parent queries\n      const extractedInput = subQueryInput.pipe(\n        map((data: any) => {\n          const [\n            key,\n            [\n              value,\n              _orderByIndex,\n              correlationKey,\n              parentContext,\n              publicKey,\n              metadata,\n            ],\n          ] = data\n          if (sourceKind === `join` && !parentKeyStream) {\n            return [key, value, metadata] as unknown as InputRow\n          }\n          return [\n            key,\n            attachRouteMetadataToResult(\n              sourceKind === `from` && value instanceof ValClass\n                ? value.value\n                : value,\n              correlationKey,\n              parentContext,\n              publicKey,\n            ),\n            metadata,\n          ] as unknown as InputRow\n        }),\n      )\n\n      return {\n        alias: from.alias,\n        input: extractedInput as KeyedStream,\n        collectionId: subQueryResult.collectionId,\n        includes: subQueryResult.includes,\n      }\n    }\n    default:\n      throw sourceKind === `join`\n        ? new UnsupportedJoinSourceTypeError((from as any).type)\n        : new UnsupportedFromTypeError((from as any).type)\n  }\n}\n\n// JSON prints non-finite numbers as null, the missing-side marker. An object\n// never collides with a source key, which is a string or a number.\nfunction encodeNonFiniteKey(_: string, value: unknown): unknown {\n  return typeof value === `number` && !Number.isFinite(value)\n    ? { number: String(value) }\n    : value\n}\n\nfunction processJoinResults(\n  joinedSource: string,\n  mainAliases: ReadonlyArray<string>,\n  parentRouted: boolean,\n): (\n  pipeline: IStreamBuilder<\n    [key: string, [JoinInputValue | undefined, JoinInputValue | undefined]]\n  >,\n) => NamespacedAndKeyedStream {\n  return (pipeline) =>\n    pipeline.pipe(\n      map((result) => {\n        const [_key, [main, joined]] = result\n        const mainKey = main?.[0]\n        const mainNamespacedRow = main?.[1]\n        const joinedKey = joined?.[0]\n        const joinedNamespacedRow = joined?.[1]\n\n        // The main side owns inherited parent aliases. Missing local sides\n        // must not expose an ancestor with the same alias.\n        const mergedNamespacedRow = {\n          ...(mainNamespacedRow ?? joinedNamespacedRow),\n        } as NamespacedRow & Record<PropertyKey, unknown>\n        if (main == null)\n          for (const alias of mainAliases) delete mergedNamespacedRow[alias]\n        if (joinedNamespacedRow)\n          mergedNamespacedRow[joinedSource] = joinedNamespacedRow[joinedSource]!\n        else delete mergedNamespacedRow[joinedSource]\n        mergeSourceContext(\n          mergedNamespacedRow,\n          mainNamespacedRow,\n          joinedNamespacedRow,\n        )\n\n        // Combine the main and joined keys without ambiguity: keys may contain\n        // delimiters, numbers and strings may print alike, and a missing outer\n        // side encodes as null, which no source key can be.\n        const resultKey = JSON.stringify(\n          [mainKey ?? null, joinedKey ?? null],\n          encodeNonFiniteKey,\n        )\n\n        // A join contributes one row per pair, including an absent outer side.\n        // Inherited source keys name only one member of that pair.\n        if (parentRouted)\n          mergedNamespacedRow[INCLUDES_PUBLIC_KEY] = JSON.stringify(\n            [\n              (mainNamespacedRow as Record<PropertyKey, unknown> | undefined)?.[\n                INCLUDES_PUBLIC_KEY\n              ] ??\n                mainKey ??\n                null,\n              (\n                joinedNamespacedRow as Record<PropertyKey, unknown> | undefined\n              )?.[INCLUDES_PUBLIC_KEY] ??\n                joinedKey ??\n                null,\n            ],\n            encodeNonFiniteKey,\n          )\n        return [resultKey, mergedNamespacedRow] as [string, NamespacedRow]\n      }),\n    )\n}\n\n/**\n * Returns the active and lazy collections for a join clause.\n * The active collection is the one that we need to fully iterate over\n * and it can be the main source (i.e. left collection) or the joined source (i.e. right collection).\n * The lazy collection is the one that we should join-in lazily based on matches in the active collection.\n * @param joinClause - The join clause to analyze\n * @param leftCollection - The left collection\n * @param rightCollection - The right collection\n * @returns The active and lazy collections. They are undefined if we need to loop over both collections (i.e. both are active)\n */\nfunction getActiveAndLazySources(\n  joinType: JoinClause[`type`],\n  leftCollection: Collection,\n  rightCollection: Collection,\n  mainSourceIsParentFiltered: boolean,\n):\n  | { activeSource: `main` | `joined`; lazySource: Collection }\n  | { activeSource: undefined; lazySource: undefined } {\n  // Self-joins can now be optimized since we track lazy loading by source alias\n  // rather than collection ID. Each alias has its own subscription and lazy state.\n\n  switch (joinType) {\n    case `left`:\n      return { activeSource: `main`, lazySource: rightCollection }\n    case `right`:\n      return { activeSource: `joined`, lazySource: leftCollection }\n    case `inner`:\n      // A correlated include has already reduced the main relation to active\n      // parent routes. Keep that relation active and load the joined side from\n      // its keys; reversing the join would create an independent demand plan\n      // that widens the correlated source back to a union of constraints.\n      if (mainSourceIsParentFiltered) {\n        return { activeSource: `main`, lazySource: rightCollection }\n      }\n      // The smallest collection should be the active collection\n      // and the biggest collection should be lazy\n      return leftCollection.size < rightCollection.size\n        ? { activeSource: `main`, lazySource: rightCollection }\n        : { activeSource: `joined`, lazySource: leftCollection }\n    default:\n      return { activeSource: undefined, lazySource: undefined }\n  }\n}\n"],"names":["crossJoinParentRoutes","serializeValue","getParentContextIdentity","attachRouteMetadata","getNamespacedRouteMetadata","getFromSources","validateJoinConditions","collectPropRefs","InvalidJoinConditionSourceMismatchError","JoinCollectionNotFoundError","compileExpression","map","wrapInputRow","UnsupportedJoinTypeError","lazyTargets","getLazyLoadTargets","ensureIndexForField","tap","joinOperator","getPropRefSourceAlias","InvalidJoinConditionSameSourceError","InvalidJoinConditionLeftSourceError","InvalidJoinConditionRightSourceError","InvalidJoinCondition","requireCollectionSource","CollectionInputNotFoundError","queriesMatchForCaching","attachRouteMetadataToResult","ValClass","UnsupportedJoinSourceTypeError","UnsupportedFromTypeError","mergeSourceContext","INCLUDES_PUBLIC_KEY"],"mappings":"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"}