{"version":3,"file":"joins.cjs","sources":["../../../../src/query/compiler/joins.ts"],"sourcesContent":["import { filter, join as joinOperator, map, tap } from '@tanstack/db-ivm'\nimport {\n  CollectionInputNotFoundError,\n  InvalidJoinCondition,\n  InvalidJoinConditionLeftSourceError,\n  InvalidJoinConditionRightSourceError,\n  InvalidJoinConditionSameSourceError,\n  InvalidJoinConditionSourceMismatchError,\n  JoinCollectionNotFoundError,\n  SubscriptionNotFoundError,\n  UnsupportedJoinSourceTypeError,\n  UnsupportedJoinTypeError,\n} from '../../errors.js'\nimport { normalizeValue } from '../../utils/comparison.js'\nimport { ensureIndexForField } from '../../indexes/auto-index.js'\nimport { PropRef, followRef } from '../ir.js'\nimport { inArray } from '../builder/functions.js'\nimport { compileExpression } from './evaluators.js'\nimport type { CompileQueryFn } from './index.js'\nimport type { OrderByOptimizationInfo } from './order-by.js'\nimport type {\n  BasicExpression,\n  CollectionRef,\n  JoinClause,\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  KeyedStream,\n  NamespacedAndKeyedStream,\n  NamespacedRow,\n} from '../../types.js'\nimport type { QueryCache, QueryMapping, WindowOptions } from './types.js'\nimport type { CollectionSubscription } from '../../collection/subscription.js'\n\n/** Function type for loading specific keys into a lazy collection */\nexport type LoadKeysFn = (key: Set<string | number>) => void\n\n/** Callbacks for managing lazy-loaded collections in optimized joins */\nexport type LazyCollectionCallbacks = {\n  loadKeys: LoadKeysFn\n  loadInitialState: () => void\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  cache: QueryCache,\n  queryMapping: QueryMapping,\n  collections: Record<string, Collection>,\n  subscriptions: Record<string, CollectionSubscription>,\n  callbacks: Record<string, LazyCollectionCallbacks>,\n  lazySources: Set<string>,\n  optimizableOrderByCollections: Record<string, OrderByOptimizationInfo>,\n  setWindowFn: (windowFn: (options: WindowOptions) => void) => void,\n  rawQuery: QueryIR,\n  onCompileSubquery: CompileQueryFn,\n  aliasToCollectionId: Record<string, string>,\n  aliasRemapping: Record<string, string>,\n  sourceWhereClauses: Map<string, BasicExpression<boolean>>,\n): NamespacedAndKeyedStream {\n  let resultPipeline = pipeline\n\n  for (const joinClause of joinClauses) {\n    resultPipeline = processJoin(\n      resultPipeline,\n      joinClause,\n      sources,\n      mainCollectionId,\n      mainSource,\n      allInputs,\n      cache,\n      queryMapping,\n      collections,\n      subscriptions,\n      callbacks,\n      lazySources,\n      optimizableOrderByCollections,\n      setWindowFn,\n      rawQuery,\n      onCompileSubquery,\n      aliasToCollectionId,\n      aliasRemapping,\n      sourceWhereClauses,\n    )\n  }\n\n  return resultPipeline\n}\n\n/**\n * Processes a single join clause with lazy loading optimization.\n * For LEFT/RIGHT/INNER joins, marks one side as \"lazy\" (loads on-demand based on join keys).\n */\nfunction processJoin(\n  pipeline: NamespacedAndKeyedStream,\n  joinClause: JoinClause,\n  sources: Record<string, KeyedStream>,\n  mainCollectionId: string,\n  mainSource: string,\n  allInputs: Record<string, KeyedStream>,\n  cache: QueryCache,\n  queryMapping: QueryMapping,\n  collections: Record<string, Collection>,\n  subscriptions: Record<string, CollectionSubscription>,\n  callbacks: Record<string, LazyCollectionCallbacks>,\n  lazySources: Set<string>,\n  optimizableOrderByCollections: Record<string, OrderByOptimizationInfo>,\n  setWindowFn: (windowFn: (options: WindowOptions) => void) => void,\n  rawQuery: QueryIR,\n  onCompileSubquery: CompileQueryFn,\n  aliasToCollectionId: Record<string, string>,\n  aliasRemapping: Record<string, string>,\n  sourceWhereClauses: Map<string, BasicExpression<boolean>>,\n): NamespacedAndKeyedStream {\n  const isCollectionRef = joinClause.from.type === `collectionRef`\n\n  // Get the joined source alias and input stream\n  const {\n    alias: joinedSource,\n    input: joinedInput,\n    collectionId: joinedCollectionId,\n  } = processJoinSource(\n    joinClause.from,\n    allInputs,\n    collections,\n    subscriptions,\n    callbacks,\n    lazySources,\n    optimizableOrderByCollections,\n    setWindowFn,\n    cache,\n    queryMapping,\n    onCompileSubquery,\n    aliasToCollectionId,\n    aliasRemapping,\n    sourceWhereClauses,\n  )\n\n  // Add the joined source to the sources map\n  sources[joinedSource] = joinedInput\n  if (isCollectionRef) {\n    // Only direct collection references form new alias bindings. Subquery\n    // aliases reuse the mapping returned from the recursive compilation above.\n    aliasToCollectionId[joinedSource] = joinedCollectionId\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 { activeSource, lazySource } = getActiveAndLazySources(\n    joinClause.type,\n    mainCollection,\n    joinedCollection,\n  )\n\n  // Analyze which source each expression refers to and swap if necessary\n  const availableSources = Object.keys(sources)\n  const { mainExpr, joinedExpr } = analyzeJoinExpressions(\n    joinClause.left,\n    joinClause.right,\n    availableSources,\n    joinedSource,\n  )\n\n  // Pre-compile the join expressions\n  const compiledMainExpr = compileExpression(mainExpr)\n  const compiledJoinedExpr = compileExpression(joinedExpr)\n\n  // Prepare the main pipeline for joining\n  let mainPipeline = pipeline.pipe(\n    map(([currentKey, namespacedRow]) => {\n      // Extract the join key from the main source expression\n      const mainKey = normalizeValue(compiledMainExpr(namespacedRow))\n\n      // Return [joinKey, [originalKey, namespacedRow]]\n      return [mainKey, [currentKey, namespacedRow]] as [\n        unknown,\n        [string, typeof namespacedRow],\n      ]\n    }),\n  )\n\n  // Prepare the joined pipeline\n  let joinedPipeline = joinedInput.pipe(\n    map(([currentKey, row]) => {\n      // Wrap the row in a namespaced structure\n      const namespacedRow: NamespacedRow = { [joinedSource]: row }\n\n      // Extract the join key from the joined source expression\n      const joinedKey = normalizeValue(compiledJoinedExpr(namespacedRow))\n\n      // Return [joinKey, [originalKey, namespacedRow]]\n      return [joinedKey, [currentKey, namespacedRow]] as [\n        unknown,\n        [string, typeof namespacedRow],\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 || lazyFrom.query.offset)\n\n    // If join expressions contain computed values (like concat functions)\n    // we don't optimize the join because we don't have an index over the computed values\n    const hasComputedJoinExpr =\n      mainExpr.type === `func` || joinedExpr.type === `func`\n\n    if (!limitedSubquery && !hasComputedJoinExpr) {\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 alias 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      const lazyAlias = activeSource === `main` ? joinedSource : mainSource\n      lazySources.add(lazyAlias)\n\n      const activePipeline =\n        activeSource === `main` ? mainPipeline : joinedPipeline\n\n      const lazySourceJoinExpr =\n        activeSource === `main`\n          ? (joinedExpr as PropRef)\n          : (mainExpr as PropRef)\n\n      const followRefResult = followRef(\n        rawQuery,\n        lazySourceJoinExpr,\n        lazySource,\n      )!\n      const followRefCollection = followRefResult.collection\n\n      const fieldName = followRefResult.path[0]\n      if (fieldName) {\n        ensureIndexForField(\n          fieldName,\n          followRefResult.path,\n          followRefCollection,\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: unknown, [originalKey: string, namespacedRow: NamespacedRow]]\n      > = activePipeline.pipe(\n        tap((data) => {\n          // Find the subscription for lazy loading.\n          // Subscriptions are keyed by the innermost alias (where the collection subscription\n          // was actually created). For subqueries, the join alias may differ from the inner alias.\n          // aliasRemapping provides a flattened one-hop lookup from outer → innermost alias.\n          // Example: .join({ activeUser: subquery }) where subquery uses .from({ user: collection })\n          // → aliasRemapping['activeUser'] = 'user' (always maps directly to innermost, never recursive)\n          const resolvedAlias = aliasRemapping[lazyAlias] || lazyAlias\n          const lazySourceSubscription = subscriptions[resolvedAlias]\n\n          if (!lazySourceSubscription) {\n            throw new SubscriptionNotFoundError(\n              resolvedAlias,\n              lazyAlias,\n              lazySource.id,\n              Object.keys(subscriptions),\n            )\n          }\n\n          if (lazySourceSubscription.hasLoadedInitialState()) {\n            // Entire state was already loaded because we deoptimized the join\n            return\n          }\n\n          // Deduplicate and filter null keys before requesting snapshot\n          const joinKeys = [\n            ...new Set(\n              data\n                .getInner()\n                .map(([[joinKey]]) => joinKey)\n                .filter((key) => key != null),\n            ),\n          ]\n\n          if (joinKeys.length === 0) {\n            return\n          }\n\n          const lazyJoinRef = new PropRef(followRefResult.path)\n          const loaded = lazySourceSubscription.requestSnapshot({\n            where: inArray(lazyJoinRef, joinKeys),\n            optimizedOnly: true,\n          })\n\n          if (!loaded) {\n            // Snapshot wasn't sent because it could not be loaded from the indexes\n            const collectionId = followRefCollection.id\n            const fieldPath = followRefResult.path.join(`.`)\n            console.warn(\n              `[TanStack DB]${collectionId ? ` [${collectionId}]` : ``} Join requires an index on \"${fieldPath}\" for efficient loading. ` +\n                `Falling back to loading all data. ` +\n                `Consider creating an index on the collection with collection.createIndex((row) => row.${fieldPath}) ` +\n                `or enable auto-indexing with autoIndex: 'eager' and a defaultIndexType.`,\n            )\n            lazySourceSubscription.requestSnapshot()\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(joinClause.type),\n  )\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  allAvailableSourceAliases: Array<string>,\n  joinedSource: string,\n): { mainExpr: BasicExpression; joinedExpr: BasicExpression } {\n  // Filter out the joined source alias from the available source aliases\n  const availableSources = allAvailableSourceAliases.filter(\n    (alias) => alias !== joinedSource,\n  )\n\n  const leftSourceAlias = getSourceAliasFromExpression(left)\n  const rightSourceAlias = getSourceAliasFromExpression(right)\n\n  // If left expression refers to an available source and right refers to joined source, keep as is\n  if (\n    leftSourceAlias &&\n    availableSources.includes(leftSourceAlias) &&\n    rightSourceAlias === joinedSource\n  ) {\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 (\n    leftSourceAlias === joinedSource &&\n    rightSourceAlias &&\n    availableSources.includes(rightSourceAlias)\n  ) {\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 (!leftSourceAlias || !rightSourceAlias) {\n    throw new InvalidJoinConditionSourceMismatchError()\n  }\n\n  // If both expressions refer to the same alias, this is an invalid join\n  if (leftSourceAlias === rightSourceAlias) {\n    throw new InvalidJoinConditionSameSourceError(leftSourceAlias)\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 (!availableSources.includes(leftSourceAlias)) {\n    throw new InvalidJoinConditionLeftSourceError(leftSourceAlias)\n  }\n\n  // Right side must refer to the joined source\n  if (rightSourceAlias !== joinedSource) {\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 * Extracts the source alias from a join expression\n */\nfunction getSourceAliasFromExpression(expr: BasicExpression): string | null {\n  switch (expr.type) {\n    case `ref`:\n      // PropRef path has the source alias as the first element\n      return expr.path[0] || null\n    case `func`: {\n      // For function expressions, we need to check if all arguments refer to the same source\n      const sourceAliases = new Set<string>()\n      for (const arg of expr.args) {\n        const alias = getSourceAliasFromExpression(arg)\n        if (alias) {\n          sourceAliases.add(alias)\n        }\n      }\n      // If all arguments refer to the same source, return that source alias\n      return sourceAliases.size === 1 ? Array.from(sourceAliases)[0]! : null\n    }\n    default:\n      // Values (type='val') don't reference any source\n      return null\n  }\n}\n\n/**\n * Processes the join source (collection or sub-query)\n */\nfunction processJoinSource(\n  from: CollectionRef | QueryRef,\n  allInputs: Record<string, KeyedStream>,\n  collections: Record<string, Collection>,\n  subscriptions: Record<string, CollectionSubscription>,\n  callbacks: Record<string, LazyCollectionCallbacks>,\n  lazySources: Set<string>,\n  optimizableOrderByCollections: Record<string, OrderByOptimizationInfo>,\n  setWindowFn: (windowFn: (options: WindowOptions) => void) => void,\n  cache: QueryCache,\n  queryMapping: QueryMapping,\n  onCompileSubquery: CompileQueryFn,\n  aliasToCollectionId: Record<string, string>,\n  aliasRemapping: Record<string, string>,\n  sourceWhereClauses: Map<string, BasicExpression<boolean>>,\n): { alias: string; input: KeyedStream; collectionId: string } {\n  switch (from.type) {\n    case `collectionRef`: {\n      const input = allInputs[from.alias]\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 { alias: from.alias, input, collectionId: from.collection.id }\n    }\n    case `queryRef`: {\n      // Find the original query for caching purposes\n      const originalQuery = queryMapping.get(from.query) || from.query\n\n      // Recursively compile the sub-query with cache\n      const subQueryResult = onCompileSubquery(\n        originalQuery,\n        allInputs,\n        collections,\n        subscriptions,\n        callbacks,\n        lazySources,\n        optimizableOrderByCollections,\n        setWindowFn,\n        cache,\n        queryMapping,\n      )\n\n      // Pull up alias mappings from subquery to parent scope.\n      // This includes both the innermost alias-to-collection mappings AND\n      // any existing remappings from nested subquery levels.\n      Object.assign(aliasToCollectionId, subQueryResult.aliasToCollectionId)\n      Object.assign(aliasRemapping, subQueryResult.aliasRemapping)\n\n      // Pull up source WHERE clauses from subquery to parent scope.\n      // This enables loadSubset to receive the correct where clauses for subquery collections.\n      //\n      // IMPORTANT: Skip pull-up for optimizer-created subqueries. These are detected when:\n      // 1. The outer alias (from.alias) matches the inner alias (from.query.from.alias)\n      // 2. The subquery was found in queryMapping (it's a user-defined subquery, not optimizer-created)\n      //\n      // For optimizer-created subqueries, the parent already has the sourceWhereClauses\n      // extracted from the original raw query, so pulling up would be redundant.\n      const isUserDefinedSubquery = queryMapping.has(from.query)\n      const fromInnerAlias = from.query.from.alias\n      const isOptimizerCreated =\n        !isUserDefinedSubquery && from.alias === fromInnerAlias\n\n      if (!isOptimizerCreated) {\n        for (const [alias, whereClause] of subQueryResult.sourceWhereClauses) {\n          sourceWhereClauses.set(alias, whereClause)\n        }\n      }\n\n      // Create a flattened remapping from outer alias to innermost alias.\n      // For nested subqueries, this ensures one-hop lookups (not recursive chains).\n      //\n      // Example with 3-level nesting:\n      //   Inner:  .from({ user: usersCollection })\n      //   Middle: .from({ activeUser: innerSubquery })     → creates: activeUser → user\n      //   Outer:  .join({ author: middleSubquery }, ...)   → creates: author → user (not author → activeUser)\n      //\n      // We search through the PULLED-UP aliasToCollectionId (which contains the\n      // innermost 'user' alias), so we always map directly to the deepest level.\n      // This means aliasRemapping[lazyAlias] is always a single lookup, never recursive.\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\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 [key, [value, _orderByIndex]] = data\n          return [key, value] as [unknown, any]\n        }),\n      )\n\n      return {\n        alias: from.alias,\n        input: extractedInput as KeyedStream,\n        collectionId: subQueryResult.collectionId,\n      }\n    }\n    default:\n      throw new UnsupportedJoinSourceTypeError((from as any).type)\n  }\n}\n\n/**\n * Processes the results of a join operation\n */\nfunction processJoinResults(joinType: string) {\n  return function (\n    pipeline: IStreamBuilder<\n      [\n        key: string,\n        [\n          [string, NamespacedRow] | undefined,\n          [string, NamespacedRow] | undefined,\n        ],\n      ]\n    >,\n  ): NamespacedAndKeyedStream {\n    return pipeline.pipe(\n      // Process the join result and handle nulls\n      filter((result) => {\n        const [_key, [main, joined]] = result\n        const mainNamespacedRow = main?.[1]\n        const joinedNamespacedRow = joined?.[1]\n\n        // Handle different join types\n        if (joinType === `inner`) {\n          return !!(mainNamespacedRow && joinedNamespacedRow)\n        }\n\n        if (joinType === `left`) {\n          return !!mainNamespacedRow\n        }\n\n        if (joinType === `right`) {\n          return !!joinedNamespacedRow\n        }\n\n        // For full joins, always include\n        return true\n      }),\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        // Merge the namespaced rows\n        const mergedNamespacedRow: NamespacedRow = {}\n\n        // Add main row data if it exists\n        if (mainNamespacedRow) {\n          Object.assign(mergedNamespacedRow, mainNamespacedRow)\n        }\n\n        // Add joined row data if it exists\n        if (joinedNamespacedRow) {\n          Object.assign(mergedNamespacedRow, joinedNamespacedRow)\n        }\n\n        // We create a composite key that combines the main and joined keys\n        const resultKey = `[${mainKey},${joinedKey}]`\n\n        return [resultKey, mergedNamespacedRow] as [string, NamespacedRow]\n      }),\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):\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      // 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":["JoinCollectionNotFoundError","compileExpression","map","normalizeValue","UnsupportedJoinTypeError","followRef","ensureIndexForField","tap","SubscriptionNotFoundError","PropRef","inArray","joinOperator","InvalidJoinConditionSourceMismatchError","InvalidJoinConditionSameSourceError","InvalidJoinConditionLeftSourceError","InvalidJoinConditionRightSourceError","InvalidJoinCondition","CollectionInputNotFoundError","UnsupportedJoinSourceTypeError","filter"],"mappings":"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"}