import { greaterThan } from "compare-utf8";
import { asyncIterableToArray } from "./async-iterable-to-array.js";
import { encodeIndexScanKey } from "./db/index.js";
import { normalizeScanOptionIndexedStartKey, isScanIndexOptions } from "./scan-options.js";
import { throwIfClosed } from "./transaction-closed-error.js";
import "../../shared/src/config.js";
class ScanResultImpl {
  #iter;
  #options;
  #dbDelegateOptions;
  #onLimitKey;
  constructor(iter, options, dbDelegateOptions, onLimitKey) {
    this.#iter = iter;
    this.#options = options;
    this.#dbDelegateOptions = dbDelegateOptions;
    this.#onLimitKey = onLimitKey;
  }
  /** The default AsyncIterable. This is the same as {@link values}. */
  [Symbol.asyncIterator]() {
    return this.values();
  }
  /** Async iterator over the values of the {@link ReadTransaction.scan | scan} call. */
  values() {
    return new AsyncIterableIteratorToArrayWrapperImpl(
      this.#newIterator((e) => e[1])
    );
  }
  /**
   * Async iterator over the keys of the {@link ReadTransaction.scan | scan}
   * call. If the {@link ReadTransaction.scan | scan} is over an index the key
   * is a tuple of `[secondaryKey: string, primaryKey]`
   */
  keys() {
    return new AsyncIterableIteratorToArrayWrapperImpl(
      this.#newIterator((e) => e[0])
    );
  }
  /**
   * Async iterator over the entries of the {@link ReadTransaction.scan | scan}
   * call. An entry is a tuple of key values. If the
   * {@link ReadTransaction.scan | scan} is over an index the key is a tuple of
   * `[secondaryKey: string, primaryKey]`
   */
  entries() {
    return new AsyncIterableIteratorToArrayWrapperImpl(
      this.#newIterator((e) => [e[0], e[1]])
    );
  }
  /** Returns all the values as an array. Same as `values().toArray()` */
  toArray() {
    return this.values().toArray();
  }
  #newIterator(toValue) {
    return scanIterator(
      toValue,
      this.#iter,
      this.#options,
      this.#dbDelegateOptions,
      this.#onLimitKey
    );
  }
}
class AsyncIterableIteratorToArrayWrapperImpl {
  #it;
  constructor(it) {
    this.#it = it;
  }
  next() {
    return this.#it.next();
  }
  [Symbol.asyncIterator]() {
    return this.#it[Symbol.asyncIterator]();
  }
  toArray() {
    return asyncIterableToArray(this.#it);
  }
}
async function* scanIterator(toValue, iter, options, closed, onLimitKey) {
  throwIfClosed(closed);
  let { limit = Infinity } = options;
  const { prefix = "" } = options;
  let exclusive = options.start?.exclusive;
  const isIndexScan = isScanIndexOptions(options);
  for await (const entry of iter) {
    const key = entry[0];
    const keyToMatch = isIndexScan ? key[0] : key;
    if (!keyToMatch.startsWith(prefix)) {
      return;
    }
    if (exclusive) {
      exclusive = true;
      if (isIndexScan) {
        if (shouldSkipIndexScan(key, options.start.key)) {
          continue;
        }
      } else {
        if (shouldSkipNonIndexScan(key, options.start.key)) {
          continue;
        }
      }
    }
    yield toValue(entry);
    if (--limit === 0) {
      if (!isIndexScan) {
        onLimitKey(key);
      }
      return;
    }
  }
}
function shouldSkipIndexScan(key, startKey) {
  const [secondaryStartKey, primaryStartKey] = normalizeScanOptionIndexedStartKey(startKey);
  const [secondaryKey, primaryKey] = normalizeScanOptionIndexedStartKey(key);
  if (secondaryKey !== secondaryStartKey) {
    return false;
  }
  if (primaryStartKey === void 0) {
    return true;
  }
  return primaryKey === primaryStartKey;
}
function shouldSkipNonIndexScan(key, startKey) {
  return key === startKey;
}
function fromKeyForIndexScanInternal(options) {
  const { prefix, start } = options;
  let prefix2 = "";
  if (prefix !== void 0) {
    prefix2 = encodeIndexScanKey(prefix, void 0);
  }
  if (!start) {
    return prefix2;
  }
  const { key } = start;
  const [secondary, primary] = normalizeScanOptionIndexedStartKey(key);
  const startKey = encodeIndexScanKey(secondary, primary);
  if (greaterThan(startKey, prefix2)) {
    return startKey;
  }
  return prefix2;
}
export {
  ScanResultImpl,
  fromKeyForIndexScanInternal
};
//# sourceMappingURL=scan-iterator.js.map
