{"version":3,"file":"index-optimization.cjs","sources":["../../../src/utils/index-optimization.ts"],"sourcesContent":["/**\n * # Index-Based Query Optimization\n *\n * This module provides utilities for optimizing query expressions by leveraging\n * available indexes to quickly find matching keys instead of scanning all data.\n *\n * This is different from the query structure optimizer in `query/optimizer.ts`\n * which rewrites query IR structure. This module focuses on using indexes during\n * query execution to speed up data filtering.\n *\n * ## Key Features:\n * - Uses indexes to find matching keys for WHERE conditions\n * - Supports AND/OR logic with set operations\n * - Handles range queries (eq, gt, gte, lt, lte)\n * - Optimizes IN array expressions\n */\n\nimport { DEFAULT_COMPARE_OPTIONS } from '../utils.js'\nimport { ReverseIndex } from '../indexes/reverse-index.js'\nimport { hasVirtualPropPath } from '../virtual-props.js'\nimport type { CompareOptions } from '../query/builder/types.js'\nimport type { IndexInterface, IndexOperation } from '../indexes/base-index.js'\nimport type { BasicExpression } from '../query/ir.js'\nimport type { CollectionLike } from '../types.js'\n\n/**\n * Result of index-based query optimization\n */\nexport interface OptimizationResult<TKey> {\n  canOptimize: boolean\n  matchingKeys: Set<TKey>\n}\n\n/**\n * Finds an index that matches a given field path\n */\nexport function findIndexForField<TKey extends string | number>(\n  collection: CollectionLike<any, TKey>,\n  fieldPath: Array<string>,\n  compareOptions?: CompareOptions,\n): IndexInterface<TKey> | undefined {\n  if (hasVirtualPropPath(fieldPath)) {\n    return undefined\n  }\n  const compareOpts = compareOptions ?? {\n    ...DEFAULT_COMPARE_OPTIONS,\n    ...collection.compareOptions,\n  }\n\n  for (const index of collection.indexes.values()) {\n    if (\n      index.matchesField(fieldPath) &&\n      index.matchesCompareOptions(compareOpts)\n    ) {\n      if (!index.matchesDirection(compareOpts.direction)) {\n        return new ReverseIndex(index)\n      }\n      return index\n    }\n  }\n  return undefined\n}\n\n/**\n * Intersects multiple sets (AND logic)\n */\nexport function intersectSets<T>(sets: Array<Set<T>>): Set<T> {\n  if (sets.length === 0) return new Set()\n  if (sets.length === 1) return new Set(sets[0])\n\n  let result = new Set(sets[0])\n  for (let i = 1; i < sets.length; i++) {\n    const newResult = new Set<T>()\n    for (const item of result) {\n      if (sets[i]!.has(item)) {\n        newResult.add(item)\n      }\n    }\n    result = newResult\n  }\n  return result\n}\n\n/**\n * Unions multiple sets (OR logic)\n */\nexport function unionSets<T>(sets: Array<Set<T>>): Set<T> {\n  const result = new Set<T>()\n  for (const set of sets) {\n    for (const item of set) {\n      result.add(item)\n    }\n  }\n  return result\n}\n\n/**\n * Optimizes a query expression using available indexes to find matching keys\n */\nexport function optimizeExpressionWithIndexes<\n  T extends object,\n  TKey extends string | number,\n>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  return optimizeQueryRecursive(expression, collection)\n}\n\n/**\n * Recursively optimizes query expressions\n */\nfunction optimizeQueryRecursive<T extends object, TKey extends string | number>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type === `func`) {\n    switch (expression.name) {\n      case `eq`:\n      case `gt`:\n      case `gte`:\n      case `lt`:\n      case `lte`:\n        return optimizeSimpleComparison(expression, collection)\n\n      case `and`:\n        return optimizeAndExpression(expression, collection)\n\n      case `or`:\n        return optimizeOrExpression(expression, collection)\n\n      case `in`:\n        return optimizeInArrayExpression(expression, collection)\n    }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Checks if an expression can be optimized\n */\nexport function canOptimizeExpression<\n  T extends object,\n  TKey extends string | number,\n>(expression: BasicExpression, collection: CollectionLike<T, TKey>): boolean {\n  if (expression.type === `func`) {\n    switch (expression.name) {\n      case `eq`:\n      case `gt`:\n      case `gte`:\n      case `lt`:\n      case `lte`:\n        return canOptimizeSimpleComparison(expression, collection)\n\n      case `and`:\n        return canOptimizeAndExpression(expression, collection)\n\n      case `or`:\n        return canOptimizeOrExpression(expression, collection)\n\n      case `in`:\n        return canOptimizeInArrayExpression(expression, collection)\n    }\n  }\n\n  return false\n}\n\n/**\n * Optimizes compound range queries on the same field\n * Example: WHERE age > 5 AND age < 10\n */\nfunction optimizeCompoundRangeQuery<\n  T extends object,\n  TKey extends string | number,\n>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type !== `func` || expression.args.length < 2) {\n    return { canOptimize: false, matchingKeys: new Set() }\n  }\n\n  // Group range operations by field\n  const fieldOperations = new Map<\n    string,\n    Array<{\n      operation: `gt` | `gte` | `lt` | `lte`\n      value: any\n    }>\n  >()\n\n  // Collect all range operations from AND arguments\n  for (const arg of expression.args) {\n    if (arg.type === `func` && [`gt`, `gte`, `lt`, `lte`].includes(arg.name)) {\n      const rangeOp = arg as any\n      if (rangeOp.args.length === 2) {\n        const leftArg = rangeOp.args[0]!\n        const rightArg = rangeOp.args[1]!\n\n        // Check both directions: field op value AND value op field\n        let fieldArg: BasicExpression | null = null\n        let valueArg: BasicExpression | null = null\n        let operation = rangeOp.name as `gt` | `gte` | `lt` | `lte`\n\n        if (leftArg.type === `ref` && rightArg.type === `val`) {\n          // field op value\n          fieldArg = leftArg\n          valueArg = rightArg\n        } else if (leftArg.type === `val` && rightArg.type === `ref`) {\n          // value op field - need to flip the operation\n          fieldArg = rightArg\n          valueArg = leftArg\n\n          // Flip the operation for reverse comparison\n          switch (operation) {\n            case `gt`:\n              operation = `lt`\n              break\n            case `gte`:\n              operation = `lte`\n              break\n            case `lt`:\n              operation = `gt`\n              break\n            case `lte`:\n              operation = `gte`\n              break\n          }\n        }\n\n        if (fieldArg && valueArg) {\n          const fieldPath = (fieldArg as any).path\n          const fieldKey = fieldPath.join(`.`)\n          const value = (valueArg as any).value\n\n          if (!fieldOperations.has(fieldKey)) {\n            fieldOperations.set(fieldKey, [])\n          }\n          fieldOperations.get(fieldKey)!.push({ operation, value })\n        }\n      }\n    }\n  }\n\n  // Check if we have multiple operations on the same field\n  for (const [fieldKey, operations] of fieldOperations) {\n    if (operations.length >= 2) {\n      const fieldPath = fieldKey.split(`.`)\n      const index = findIndexForField(collection, fieldPath)\n\n      if (index && index.supports(`gt`) && index.supports(`lt`)) {\n        // Build range query options\n        let from: any = undefined\n        let to: any = undefined\n        let fromInclusive = true\n        let toInclusive = true\n\n        for (const { operation, value } of operations) {\n          switch (operation) {\n            case `gt`:\n              if (from === undefined || value > from) {\n                from = value\n                fromInclusive = false\n              }\n              break\n            case `gte`:\n              if (from === undefined || value > from) {\n                from = value\n                fromInclusive = true\n              }\n              break\n            case `lt`:\n              if (to === undefined || value < to) {\n                to = value\n                toInclusive = false\n              }\n              break\n            case `lte`:\n              if (to === undefined || value < to) {\n                to = value\n                toInclusive = true\n              }\n              break\n          }\n        }\n\n        const matchingKeys = (index as any).rangeQuery({\n          from,\n          to,\n          fromInclusive,\n          toInclusive,\n        })\n\n        return { canOptimize: true, matchingKeys }\n      }\n    }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Optimizes simple comparison expressions (eq, gt, gte, lt, lte)\n */\nfunction optimizeSimpleComparison<\n  T extends object,\n  TKey extends string | number,\n>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type !== `func` || expression.args.length !== 2) {\n    return { canOptimize: false, matchingKeys: new Set() }\n  }\n\n  const leftArg = expression.args[0]!\n  const rightArg = expression.args[1]!\n\n  // Check both directions: field op value AND value op field\n  let fieldArg: BasicExpression | null = null\n  let valueArg: BasicExpression | null = null\n  let operation = expression.name as `eq` | `gt` | `gte` | `lt` | `lte`\n\n  if (leftArg.type === `ref` && rightArg.type === `val`) {\n    // field op value\n    fieldArg = leftArg\n    valueArg = rightArg\n  } else if (leftArg.type === `val` && rightArg.type === `ref`) {\n    // value op field - need to flip the operation\n    fieldArg = rightArg\n    valueArg = leftArg\n\n    // Flip the operation for reverse comparison\n    switch (operation) {\n      case `gt`:\n        operation = `lt`\n        break\n      case `gte`:\n        operation = `lte`\n        break\n      case `lt`:\n        operation = `gt`\n        break\n      case `lte`:\n        operation = `gte`\n        break\n      // eq stays the same\n    }\n  }\n\n  if (fieldArg && valueArg) {\n    const fieldPath = (fieldArg as any).path\n    const index = findIndexForField(collection, fieldPath)\n\n    if (index) {\n      const queryValue = (valueArg as any).value\n\n      // Map operation to IndexOperation enum\n      const indexOperation = operation as IndexOperation\n\n      // Check if the index supports this operation\n      if (!index.supports(indexOperation)) {\n        return { canOptimize: false, matchingKeys: new Set() }\n      }\n\n      const matchingKeys = index.lookup(indexOperation, queryValue)\n      return { canOptimize: true, matchingKeys }\n    }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Checks if a simple comparison can be optimized\n */\nfunction canOptimizeSimpleComparison<\n  T extends object,\n  TKey extends string | number,\n>(expression: BasicExpression, collection: CollectionLike<T, TKey>): boolean {\n  if (expression.type !== `func` || expression.args.length !== 2) {\n    return false\n  }\n\n  const leftArg = expression.args[0]!\n  const rightArg = expression.args[1]!\n\n  // Check both directions: field op value AND value op field\n  let fieldPath: Array<string> | null = null\n\n  if (leftArg.type === `ref` && rightArg.type === `val`) {\n    fieldPath = (leftArg as any).path\n  } else if (leftArg.type === `val` && rightArg.type === `ref`) {\n    fieldPath = (rightArg as any).path\n  }\n\n  if (fieldPath) {\n    const index = findIndexForField(collection, fieldPath)\n    return index !== undefined\n  }\n\n  return false\n}\n\n/**\n * Optimizes AND expressions\n */\nfunction optimizeAndExpression<T extends object, TKey extends string | number>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type !== `func` || expression.args.length < 2) {\n    return { canOptimize: false, matchingKeys: new Set() }\n  }\n\n  // First, try to optimize compound range queries on the same field\n  const compoundRangeResult = optimizeCompoundRangeQuery(expression, collection)\n  if (compoundRangeResult.canOptimize) {\n    return compoundRangeResult\n  }\n\n  const results: Array<OptimizationResult<TKey>> = []\n\n  // Try to optimize each part, keep the optimizable ones\n  for (const arg of expression.args) {\n    const result = optimizeQueryRecursive(arg, collection)\n    if (result.canOptimize) {\n      results.push(result)\n    }\n  }\n\n  if (results.length > 0) {\n    // Use intersectSets utility for AND logic\n    const allMatchingSets = results.map((r) => r.matchingKeys)\n    const intersectedKeys = intersectSets(allMatchingSets)\n    return { canOptimize: true, matchingKeys: intersectedKeys }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Checks if an AND expression can be optimized\n */\nfunction canOptimizeAndExpression<\n  T extends object,\n  TKey extends string | number,\n>(expression: BasicExpression, collection: CollectionLike<T, TKey>): boolean {\n  if (expression.type !== `func` || expression.args.length < 2) {\n    return false\n  }\n\n  // If any argument can be optimized, we can gain some speedup\n  return expression.args.some((arg) => canOptimizeExpression(arg, collection))\n}\n\n/**\n * Optimizes OR expressions\n */\nfunction optimizeOrExpression<T extends object, TKey extends string | number>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type !== `func` || expression.args.length < 2) {\n    return { canOptimize: false, matchingKeys: new Set() }\n  }\n\n  const results: Array<OptimizationResult<TKey>> = []\n\n  // Try to optimize each part, keep the optimizable ones\n  for (const arg of expression.args) {\n    const result = optimizeQueryRecursive(arg, collection)\n    if (result.canOptimize) {\n      results.push(result)\n    }\n  }\n\n  if (results.length > 0) {\n    // Use unionSets utility for OR logic\n    const allMatchingSets = results.map((r) => r.matchingKeys)\n    const unionedKeys = unionSets(allMatchingSets)\n    return { canOptimize: true, matchingKeys: unionedKeys }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Checks if an OR expression can be optimized\n */\nfunction canOptimizeOrExpression<\n  T extends object,\n  TKey extends string | number,\n>(expression: BasicExpression, collection: CollectionLike<T, TKey>): boolean {\n  if (expression.type !== `func` || expression.args.length < 2) {\n    return false\n  }\n\n  // If any argument can be optimized, we can gain some speedup\n  return expression.args.some((arg) => canOptimizeExpression(arg, collection))\n}\n\n/**\n * Optimizes IN array expressions\n */\nfunction optimizeInArrayExpression<\n  T extends object,\n  TKey extends string | number,\n>(\n  expression: BasicExpression,\n  collection: CollectionLike<T, TKey>,\n): OptimizationResult<TKey> {\n  if (expression.type !== `func` || expression.args.length !== 2) {\n    return { canOptimize: false, matchingKeys: new Set() }\n  }\n\n  const fieldArg = expression.args[0]!\n  const arrayArg = expression.args[1]!\n\n  if (\n    fieldArg.type === `ref` &&\n    arrayArg.type === `val` &&\n    Array.isArray((arrayArg as any).value)\n  ) {\n    const fieldPath = (fieldArg as any).path\n    const values = (arrayArg as any).value\n    const index = findIndexForField(collection, fieldPath)\n\n    if (index) {\n      // Check if the index supports IN operation\n      if (index.supports(`in`)) {\n        const matchingKeys = index.lookup(`in`, values)\n        return { canOptimize: true, matchingKeys }\n      } else if (index.supports(`eq`)) {\n        // Fallback to multiple equality lookups\n        const matchingKeys = new Set<TKey>()\n        for (const value of values) {\n          const keysForValue = index.lookup(`eq`, value)\n          for (const key of keysForValue) {\n            matchingKeys.add(key)\n          }\n        }\n        return { canOptimize: true, matchingKeys }\n      }\n    }\n  }\n\n  return { canOptimize: false, matchingKeys: new Set() }\n}\n\n/**\n * Checks if an IN array expression can be optimized\n */\nfunction canOptimizeInArrayExpression<\n  T extends object,\n  TKey extends string | number,\n>(expression: BasicExpression, collection: CollectionLike<T, TKey>): boolean {\n  if (expression.type !== `func` || expression.args.length !== 2) {\n    return false\n  }\n\n  const fieldArg = expression.args[0]!\n  const arrayArg = expression.args[1]!\n\n  if (\n    fieldArg.type === `ref` &&\n    arrayArg.type === `val` &&\n    Array.isArray((arrayArg as any).value)\n  ) {\n    const fieldPath = (fieldArg as any).path\n    const index = findIndexForField(collection, fieldPath)\n    return index !== undefined\n  }\n\n  return false\n}\n"],"names":["hasVirtualPropPath","DEFAULT_COMPARE_OPTIONS","ReverseIndex"],"mappings":"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"}