{"version":3,"file":"base-index.cjs","sources":["../../../src/indexes/base-index.ts"],"sourcesContent":["import { compileSingleRowExpression } from '../query/compiler/evaluators.js'\nimport { comparisonFunctions } from '../query/builder/functions.js'\nimport { DEFAULT_COMPARE_OPTIONS, deepEquals } from '../utils.js'\nimport type { RangeQueryOptions } from './btree-index.js'\nimport type { CompareOptions } from '../query/builder/types.js'\nimport type { BasicExpression, OrderByDirection } from '../query/ir.js'\n\n/**\n * Operations that indexes can support, imported from available comparison functions\n */\nexport const IndexOperation = comparisonFunctions\n\n/**\n * Type for index operation values\n */\nexport type IndexOperation = (typeof comparisonFunctions)[number]\n\n/**\n * Statistics about index usage and performance\n */\nexport interface IndexStats {\n  readonly entryCount: number\n  readonly lookupCount: number\n  readonly averageLookupTime: number\n  readonly lastUpdated: Date\n}\n\nexport interface IndexInterface<\n  TKey extends string | number = string | number,\n> {\n  add: (key: TKey, item: any) => void\n  remove: (key: TKey, item: any) => void\n  update: (key: TKey, oldItem: any, newItem: any) => void\n\n  build: (entries: Iterable<[TKey, any]>) => void\n  clear: () => void\n\n  lookup: (operation: IndexOperation, value: any) => Set<TKey>\n\n  equalityLookup: (value: any) => Set<TKey>\n  inArrayLookup: (values: Array<any>) => Set<TKey>\n\n  rangeQuery: (options: RangeQueryOptions) => Set<TKey>\n  rangeQueryReversed: (options: RangeQueryOptions) => Set<TKey>\n\n  take: (\n    n: number,\n    from: TKey,\n    filterFn?: (key: TKey) => boolean,\n  ) => Array<TKey>\n  takeFromStart: (n: number, filterFn?: (key: TKey) => boolean) => Array<TKey>\n  takeReversed: (\n    n: number,\n    from: TKey,\n    filterFn?: (key: TKey) => boolean,\n  ) => Array<TKey>\n  takeReversedFromEnd: (\n    n: number,\n    filterFn?: (key: TKey) => boolean,\n  ) => Array<TKey>\n\n  get keyCount(): number\n  get orderedEntriesArray(): Array<[any, Set<TKey>]>\n  get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]>\n\n  get indexedKeysSet(): Set<TKey>\n  get valueMapData(): Map<any, Set<TKey>>\n\n  supports: (operation: IndexOperation) => boolean\n\n  matchesField: (fieldPath: Array<string>) => boolean\n  matchesCompareOptions: (compareOptions: CompareOptions) => boolean\n  matchesDirection: (direction: OrderByDirection) => boolean\n\n  getStats: () => IndexStats\n}\n\n/**\n * Base abstract class that all index types extend\n */\nexport abstract class BaseIndex<\n  TKey extends string | number = string | number,\n> implements IndexInterface<TKey> {\n  public readonly id: number\n  public readonly name?: string\n  public readonly expression: BasicExpression\n  public abstract readonly supportedOperations: Set<IndexOperation>\n\n  protected lookupCount = 0\n  protected totalLookupTime = 0\n  protected lastUpdated = new Date()\n  protected compareOptions: CompareOptions\n\n  constructor(\n    id: number,\n    expression: BasicExpression,\n    name?: string,\n    options?: any,\n  ) {\n    this.id = id\n    this.expression = expression\n    this.compareOptions = DEFAULT_COMPARE_OPTIONS\n    this.name = name\n    this.initialize(options)\n  }\n\n  // Abstract methods that each index type must implement\n  abstract add(key: TKey, item: any): void\n  abstract remove(key: TKey, item: any): void\n  abstract update(key: TKey, oldItem: any, newItem: any): void\n  abstract build(entries: Iterable<[TKey, any]>): void\n  abstract clear(): void\n  abstract lookup(operation: IndexOperation, value: any): Set<TKey>\n  abstract take(\n    n: number,\n    from: TKey,\n    filterFn?: (key: TKey) => boolean,\n  ): Array<TKey>\n  abstract takeFromStart(\n    n: number,\n    filterFn?: (key: TKey) => boolean,\n  ): Array<TKey>\n  abstract takeReversed(\n    n: number,\n    from: TKey,\n    filterFn?: (key: TKey) => boolean,\n  ): Array<TKey>\n  abstract takeReversedFromEnd(\n    n: number,\n    filterFn?: (key: TKey) => boolean,\n  ): Array<TKey>\n  abstract get keyCount(): number\n  abstract equalityLookup(value: any): Set<TKey>\n  abstract inArrayLookup(values: Array<any>): Set<TKey>\n  abstract rangeQuery(options: RangeQueryOptions): Set<TKey>\n  abstract rangeQueryReversed(options: RangeQueryOptions): Set<TKey>\n  abstract get orderedEntriesArray(): Array<[any, Set<TKey>]>\n  abstract get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]>\n  abstract get indexedKeysSet(): Set<TKey>\n  abstract get valueMapData(): Map<any, Set<TKey>>\n\n  // Common methods\n  supports(operation: IndexOperation): boolean {\n    return this.supportedOperations.has(operation)\n  }\n\n  matchesField(fieldPath: Array<string>): boolean {\n    return (\n      this.expression.type === `ref` &&\n      this.expression.path.length === fieldPath.length &&\n      this.expression.path.every((part, i) => part === fieldPath[i])\n    )\n  }\n\n  /**\n   * Checks if the compare options match the index's compare options.\n   * The direction is ignored because the index can be reversed if the direction is different.\n   */\n  matchesCompareOptions(compareOptions: CompareOptions): boolean {\n    const thisCompareOptionsWithoutDirection = {\n      ...this.compareOptions,\n      direction: undefined,\n    }\n    const compareOptionsWithoutDirection = {\n      ...compareOptions,\n      direction: undefined,\n    }\n\n    return deepEquals(\n      thisCompareOptionsWithoutDirection,\n      compareOptionsWithoutDirection,\n    )\n  }\n\n  /**\n   * Checks if the index matches the provided direction.\n   */\n  matchesDirection(direction: OrderByDirection): boolean {\n    return this.compareOptions.direction === direction\n  }\n\n  getStats(): IndexStats {\n    return {\n      entryCount: this.keyCount,\n      lookupCount: this.lookupCount,\n      averageLookupTime:\n        this.lookupCount > 0 ? this.totalLookupTime / this.lookupCount : 0,\n      lastUpdated: this.lastUpdated,\n    }\n  }\n\n  protected abstract initialize(options?: any): void\n\n  protected evaluateIndexExpression(item: any): any {\n    const evaluator = compileSingleRowExpression(this.expression)\n    return evaluator(item as Record<string, unknown>)\n  }\n\n  protected trackLookup(startTime: number): void {\n    const duration = performance.now() - startTime\n    this.lookupCount++\n    this.totalLookupTime += duration\n  }\n\n  protected updateTimestamp(): void {\n    this.lastUpdated = new Date()\n  }\n}\n\n/**\n * Type for index constructor\n */\nexport type IndexConstructor<TKey extends string | number = string | number> =\n  new (\n    id: number,\n    expression: BasicExpression,\n    name?: string,\n    options?: any,\n  ) => BaseIndex<TKey>\n"],"names":["DEFAULT_COMPARE_OPTIONS","deepEquals","compileSingleRowExpression"],"mappings":";;;;AAgFO,MAAe,UAEY;AAAA,EAWhC,YACE,IACA,YACA,MACA,SACA;AAVF,SAAU,cAAc;AACxB,SAAU,kBAAkB;AAC5B,SAAU,kCAAkB,KAAA;AAS1B,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,SAAK,iBAAiBA,MAAAA;AACtB,SAAK,OAAO;AACZ,SAAK,WAAW,OAAO;AAAA,EACzB;AAAA;AAAA,EAsCA,SAAS,WAAoC;AAC3C,WAAO,KAAK,oBAAoB,IAAI,SAAS;AAAA,EAC/C;AAAA,EAEA,aAAa,WAAmC;AAC9C,WACE,KAAK,WAAW,SAAS,SACzB,KAAK,WAAW,KAAK,WAAW,UAAU,UAC1C,KAAK,WAAW,KAAK,MAAM,CAAC,MAAM,MAAM,SAAS,UAAU,CAAC,CAAC;AAAA,EAEjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsB,gBAAyC;AAC7D,UAAM,qCAAqC;AAAA,MACzC,GAAG,KAAK;AAAA,MACR,WAAW;AAAA,IAAA;AAEb,UAAM,iCAAiC;AAAA,MACrC,GAAG;AAAA,MACH,WAAW;AAAA,IAAA;AAGb,WAAOC,MAAAA;AAAAA,MACL;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,WAAsC;AACrD,WAAO,KAAK,eAAe,cAAc;AAAA,EAC3C;AAAA,EAEA,WAAuB;AACrB,WAAO;AAAA,MACL,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBACE,KAAK,cAAc,IAAI,KAAK,kBAAkB,KAAK,cAAc;AAAA,MACnE,aAAa,KAAK;AAAA,IAAA;AAAA,EAEtB;AAAA,EAIU,wBAAwB,MAAgB;AAChD,UAAM,YAAYC,WAAAA,2BAA2B,KAAK,UAAU;AAC5D,WAAO,UAAU,IAA+B;AAAA,EAClD;AAAA,EAEU,YAAY,WAAyB;AAC7C,UAAM,WAAW,YAAY,IAAA,IAAQ;AACrC,SAAK;AACL,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEU,kBAAwB;AAChC,SAAK,kCAAkB,KAAA;AAAA,EACzB;AACF;;"}