{"version":3,"file":"reverse-index.cjs","sources":["../../../src/indexes/reverse-index.ts"],"sourcesContent":["import { compareKeys } from '@tanstack/db-ivm'\nimport type { IndexInterface, IndexOperation, IndexReader } from './base-index'\nimport type { RangeQueryOptions } from './btree-index'\n\nexport class ReverseIndex<\n  TKey extends string | number,\n> implements IndexReader<TKey> {\n  private originalIndex: IndexInterface<TKey>\n\n  /**\n   * @param nullsFirst - Whether nullish values come first in the reversed\n   * order. The original index keeps them at the opposite end, so reversing\n   * it alone would move them; ordered reads put them back. Omit it to read\n   * the original index's plain reversed walk, as earlier releases did.\n   */\n  constructor(\n    index: IndexInterface<TKey>,\n    private readonly nullsFirst?: boolean,\n  ) {\n    this.originalIndex = index\n  }\n\n  // Define the reversed operations\n\n  lookup(operation: IndexOperation, value: any): Set<TKey> {\n    const reverseOperation =\n      operation === `gt`\n        ? `lt`\n        : operation === `gte`\n          ? `lte`\n          : operation === `lt`\n            ? `gt`\n            : operation === `lte`\n              ? `gte`\n              : operation\n    return this.originalIndex.lookup(reverseOperation, value)\n  }\n\n  rangeQuery(options: RangeQueryOptions = {}): Set<TKey> {\n    return this.originalIndex.rangeQueryReversed(options)\n  }\n\n  // Reversing the original index moves its nullish group to the opposite\n  // end, so reads put the group back at the end the query asks for. Nullish\n  // keys come in ascending key order; equal non-null values come in the\n  // reversed walk's order. Each read gathers the nullish group, so its cost\n  // grows with the number of nullish keys.\n\n  take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {\n    if (this.nullsFirst === undefined) {\n      return this.originalIndex.takeReversed(n, from, filterFn)\n    }\n    return this.read(n, filterFn, from ?? null)\n  }\n\n  takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {\n    if (this.nullsFirst === undefined) {\n      return this.originalIndex.takeReversedFromEnd(n, filterFn)\n    }\n    return this.read(n, filterFn)\n  }\n\n  /** Reads after `from` (`null` is the nullish group), or from the start. */\n  private read(\n    n: number,\n    filterFn?: (key: TKey) => boolean,\n    from?: unknown,\n  ): Array<TKey> {\n    // Every index implements `equalityLookup`; an `eq` lookup need not be\n    // advertised by an index that ordered reads accept.\n    const nullish = new Set([\n      ...this.originalIndex.equalityLookup(null),\n      ...this.originalIndex.equalityLookup(undefined),\n    ])\n    const keep = (key: TKey) => filterFn?.(key) ?? true\n    const accept = (key: TKey) => !nullish.has(key) && keep(key)\n    const values = (count: number) =>\n      count <= 0\n        ? []\n        : from == null\n          ? this.originalIndex.takeReversedFromEnd(count, accept)\n          : this.originalIndex.takeReversed(count, from, accept)\n    const nulls = (count: number) =>\n      count <= 0\n        ? []\n        : [...nullish].sort(compareKeys).filter(keep).slice(0, count)\n    if (from === null) return this.nullsFirst ? values(n) : []\n    if (this.nullsFirst && from === undefined) {\n      const head = nulls(n)\n      return [...head, ...values(n - head.length)]\n    }\n    const keys = values(n)\n    return this.nullsFirst ? keys : [...keys, ...nulls(n - keys.length)]\n  }\n\n  // All operations below delegate to the original index\n\n  supports(operation: IndexOperation): boolean {\n    return this.originalIndex.supports(operation)\n  }\n\n  get supportsRangeOptimization(): boolean {\n    return this.originalIndex.supportsRangeOptimization\n  }\n\n  canOptimizeRangeFor(value: unknown): boolean {\n    return this.originalIndex.canOptimizeRangeFor?.(value) ?? true\n  }\n\n  get keyCount(): number {\n    return this.originalIndex.keyCount\n  }\n}\n"],"names":["originalIndex","compareKeys"],"mappings":";;;AAIO,MAAM,aAEkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7B,YACE,OACiB,YACjB;AADiB,SAAA,aAAA;AAEjB,SAAKA,KAAgB;AAAA,EACvB;AAAA;AAAA,EAIA,OAAO,WAA2B,OAAuB;AACvD,UAAM,mBACJ,cAAc,OACV,OACA,cAAc,QACZ,QACA,cAAc,OACZ,OACA,cAAc,QACZ,QACA;AACZ,WAAO,KAAKA,GAAc,OAAO,kBAAkB,KAAK;AAAA,EAC1D;AAAA,EAEA,WAAW,UAA6B,IAAe;AACrD,WAAO,KAAKA,GAAc,mBAAmB,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,GAAW,MAAW,UAAgD;AACzE,QAAI,KAAK,eAAe,QAAW;AACjC,aAAO,KAAKA,GAAc,aAAa,GAAG,MAAM,QAAQ;AAAA,IAC1D;AACA,WAAO,KAAK,KAAK,GAAG,UAAU,QAAQ,IAAI;AAAA,EAC5C;AAAA,EAEA,cAAc,GAAW,UAAgD;AACvE,QAAI,KAAK,eAAe,QAAW;AACjC,aAAO,KAAKA,GAAc,oBAAoB,GAAG,QAAQ;AAAA,IAC3D;AACA,WAAO,KAAK,KAAK,GAAG,QAAQ;AAAA,EAC9B;AAAA;AAAA,EAGQ,KACN,GACA,UACA,MACa;AAGb,UAAM,8BAAc,IAAI;AAAA,MACtB,GAAG,KAAKA,GAAc,eAAe,IAAI;AAAA,MACzC,GAAG,KAAKA,GAAc,eAAe,MAAS;AAAA,IAAA,CAC/C;AACD,UAAM,OAAO,CAAC,QAAc,WAAW,GAAG,KAAK;AAC/C,UAAM,SAAS,CAAC,QAAc,CAAC,QAAQ,IAAI,GAAG,KAAK,KAAK,GAAG;AAC3D,UAAM,SAAS,CAAC,UACd,SAAS,IACL,KACA,QAAQ,OACN,KAAKA,GAAc,oBAAoB,OAAO,MAAM,IACpD,KAAKA,GAAc,aAAa,OAAO,MAAM,MAAM;AAC3D,UAAM,QAAQ,CAAC,UACb,SAAS,IACL,CAAA,IACA,CAAC,GAAG,OAAO,EAAE,KAAKC,MAAAA,WAAW,EAAE,OAAO,IAAI,EAAE,MAAM,GAAG,KAAK;AAChE,QAAI,SAAS,KAAM,QAAO,KAAK,aAAa,OAAO,CAAC,IAAI,CAAA;AACxD,QAAI,KAAK,cAAc,SAAS,QAAW;AACzC,YAAM,OAAO,MAAM,CAAC;AACpB,aAAO,CAAC,GAAG,MAAM,GAAG,OAAO,IAAI,KAAK,MAAM,CAAC;AAAA,IAC7C;AACA,UAAM,OAAO,OAAO,CAAC;AACrB,WAAO,KAAK,aAAa,OAAO,CAAC,GAAG,MAAM,GAAG,MAAM,IAAI,KAAK,MAAM,CAAC;AAAA,EACrE;AAAA;AAAA,EAIA,SAAS,WAAoC;AAC3C,WAAO,KAAKD,GAAc,SAAS,SAAS;AAAA,EAC9C;AAAA,EAEA,IAAI,4BAAqC;AACvC,WAAO,KAAKA,GAAc;AAAA,EAC5B;AAAA,EAEA,oBAAoB,OAAyB;AAC3C,WAAO,KAAKA,GAAc,sBAAsB,KAAK,KAAK;AAAA,EAC5D;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAKA,GAAc;AAAA,EAC5B;AACF;;"}