<commit_before>
import KeyRange from "./KeyRange"

/**
 * Converts the provided key range object into a field range map object.
 *
 * @param {IDBKeyRange} keyRange The key range object to convert.
 * @param {(string|string[])} keyPath The key path of this storage.
 * @return {Object<string, IDBKeyRange>} A field range map object.
 */
export function keyRangeToFieldRangeObject(keyRange, keyPath) {
  let fieldRangeObject = {}

  if (!(keyPath instanceof Array)) {
    setFieldValue(fieldRangeObject, keyPath, keyRange)
    return fieldRangeObject
  }

  let lowerBound = keyRange.lower
  let upperBound = keyRange.upper
  let lowerBoundOpen = keyRange.lowerOpen
  let upperBoundOpen = keyRange.upperOpen

  keyPath.forEach((fieldPath, index) => {
    let fieldLowerBound = lowerBound ? lowerBound[index] : undefined
    let fieldUpperBound = upperBound ? upperBound[index] : undefined
    let fieldRange = KeyRange.bound(
      fieldLowerBound,
      fieldUpperBound,
      lowerBoundOpen,
      upperBoundOpen
    )
    setFieldValue(fieldRangeObject, fieldPath, fieldRange)
  })

  return fieldRangeObject
}

/**
 * Normalizes the provided filter to an {@code undefined}, an
 * {@codelink IDBKeyRange} instance or a filter predicate function.
 *
 * @param {?(undefined|number|string|Date|Array|IDBKeyRange|Object<string, (number|string|Date|Array|IDBKeyRange)>|function(*, (number|string|Date|Array), (number|string|Date|Array)): boolean)}
 *        filter A filter to use, as provided by the client code.
 * @param {?(string|string[]) keyPath The key path of the storage. This
 *        parameter is used to optimize field map filters that specify a the
 *        field constraints matching the field paths - such field map filters
 *        will be optimized to an IDBKeyRange.
 * @return {(undefined|IDBKeyRange|function(*): boolean)} Normalized filter.
 */
export function normalizeFilter(filter, keyPath) {
  if (keyPath) {
    let normalizedFilter = convertFieldMapToKeyRange(filter, keyPath)
    if (normalizedFilter) {
      filter = normalizedFilter
    }
  }

  if ((filter === null) || (filter === undefined)) {
    return undefined
  }

  let isFieldMap = (filter instanceof Object) &&
      !(filter instanceof Function) &&
      !(filter instanceof IDBKeyRange) &&
      !(filter instanceof Array) &&
      !(filter instanceof Date)
  if (isFieldMap) {
    filter = compileFieldRangeFilter(filter)
  }

  if (!(filter instanceof Function) && !(filter instanceof IDBKeyRange)) {
    filter = KeyRange.only(filter)
  }

  return filter
}

/**
 * Compiles the provided map of field names to expected values or value ranges
 * to a predicate function that takes a record and returns {@code true} if the
 * record satisfies the provided field values restrictions.
 *
 * @param {Object<string, (number|string|Date|Array|IDBKeyRange)>} filter A map
 *        of field names to expected values or key ranges representing the
 *        expected values for those fields.
 * @return {function(*): boolean} The compiled filter.
 */
export function compileFieldRangeFilter(filter) {
  let fieldPaths = getFieldPaths(filter, false)

  let fieldFilters = fieldPaths.map((fieldPath) => {
    let fieldRange = getFieldValue(filter, fieldPath)
    if (!(fieldRange instanceof IDBKeyRange)) {
      fieldRange = KeyRange.only(fieldRange)
    }

    return (record) => {
      let fieldValue = getFieldValue(record, fieldPath)

      if (fieldRange.lower !== undefined) {
        let lowerComparison
        lowerComparison = indexedDB.cmp(fieldRange.lower, fieldValue)

        let failedTest = (lowerComparison > 0) ||
            (fieldRange.lowerOpen && (lowerComparison === 0))
        if (failedTest) {
          return false
        }
      }

      if (fieldRange.upper !== undefined) {
        let upperComparison
        upperComparison = indexedDB.cmp(fieldRange.upper, fieldValue)

        let failedTest = (lowerComparison < 0) ||
            (fieldRange.upperOpen && (lowerComparison === 0))
        if (failedTest) {
          return false
        }
      }

      return true
    }
  })

  return (record) => {
    if (!(record instanceof Object)) {
      return false
    }

    return fieldFilters.every(fieldFilter => fieldFilter(record))
  }
}

/**
 * Attempts to convert the provided filter to a single {@codelink IDBKeyRange}
 * instance.
 *
 * The conversion is only possible if the filter is a field map filter, field<commit_msg>fixed filter field map compilation<commit_after>
import KeyRange from "./KeyRange"

/**
 * Converts the provided key range object into a field range map object.
 *
 * @param {IDBKeyRange} keyRange The key range object to convert.
 * @param {(string|string[])} keyPath The key path of this storage.
 * @return {Object<string, IDBKeyRange>} A field range map object.
 */
export function keyRangeToFieldRangeObject(keyRange, keyPath) {
  let fieldRangeObject = {}

  if (!(keyPath instanceof Array)) {
    setFieldValue(fieldRangeObject, keyPath, keyRange)
    return fieldRangeObject
  }

  let lowerBound = keyRange.lower
  let upperBound = keyRange.upper
  let lowerBoundOpen = keyRange.lowerOpen
  let upperBoundOpen = keyRange.upperOpen

  keyPath.forEach((fieldPath, index) => {
    let fieldLowerBound = lowerBound ? lowerBound[index] : undefined
    let fieldUpperBound = upperBound ? upperBound[index] : undefined
    let fieldRange = KeyRange.bound(
      fieldLowerBound,
      fieldUpperBound,
      lowerBoundOpen,
      upperBoundOpen
    )
    setFieldValue(fieldRangeObject, fieldPath, fieldRange)
  })

  return fieldRangeObject
}

/**
 * Normalizes the provided filter to an {@code undefined}, an
 * {@codelink IDBKeyRange} instance or a filter predicate function.
 *
 * @param {?(undefined|number|string|Date|Array|IDBKeyRange|Object<string, (number|string|Date|Array|IDBKeyRange)>|function(*, (number|string|Date|Array), (number|string|Date|Array)): boolean)}
 *        filter A filter to use, as provided by the client code.
 * @param {?(string|string[]) keyPath The key path of the storage. This
 *        parameter is used to optimize field map filters that specify a the
 *        field constraints matching the field paths - such field map filters
 *        will be optimized to an IDBKeyRange.
 * @return {(undefined|IDBKeyRange|function(*): boolean)} Normalized filter.
 */
export function normalizeFilter(filter, keyPath) {
  if (keyPath) {
    let normalizedFilter = convertFieldMapToKeyRange(filter, keyPath)
    if (normalizedFilter) {
      filter = normalizedFilter
    }
  }

  if ((filter === null) || (filter === undefined)) {
    return undefined
  }

  let isFieldMap = (filter instanceof Object) &&
      !(filter instanceof Function) &&
      !(filter instanceof IDBKeyRange) &&
      !(filter instanceof Array) &&
      !(filter instanceof Date)
  if (isFieldMap) {
    filter = compileFieldRangeFilter(filter)
  }

  if (!(filter instanceof Function) && !(filter instanceof IDBKeyRange)) {
    filter = KeyRange.only(filter)
  }

  return filter
}

/**
 * Compiles the provided map of field names to expected values or value ranges
 * to a predicate function that takes a record and returns {@code true} if the
 * record satisfies the provided field values restrictions.
 *
 * @param {Object<string, (number|string|Date|Array|IDBKeyRange)>} filter A map
 *        of field names to expected values or key ranges representing the
 *        expected values for those fields.
 * @return {function(*): boolean} The compiled filter.
 */
export function compileFieldRangeFilter(filter) {
  let fieldPaths = getFieldPaths(filter, false)

  let fieldFilters = fieldPaths.map((fieldPath) => {
    let fieldRange = getFieldValue(filter, fieldPath)
    if (!(fieldRange instanceof IDBKeyRange)) {
      fieldRange = KeyRange.only(fieldRange)
    }

    return (record) => {
      let fieldValue = getFieldValue(record, fieldPath)

      if (fieldRange.lower !== undefined) {
        let lowerComparison
        lowerComparison = indexedDB.cmp(fieldRange.lower, fieldValue)

        let failedTest = (lowerComparison > 0) ||
            (fieldRange.lowerOpen && (lowerComparison === 0))
        if (failedTest) {
          return false
        }
      }

      if (fieldRange.upper !== undefined) {
        let upperComparison
        upperComparison = indexedDB.cmp(fieldRange.upper, fieldValue)

        let failedTest = (upperComparison < 0) ||
            (fieldRange.upperOpen && (upperComparison === 0))
        if (failedTest) {
          return false
        }
      }

      return true
    }
  })

  return (record) => {
    if (!(record instanceof Object)) {
      return false
    }

    return fieldFilters.every(fieldFilter => fieldFilter(record))
  }
}

/**
 * Attempts to convert the provided filter to a single {@codelink IDBKeyRange}
 * instance.
 *
 * The conversion is only possible if the filter is a field map filter, field
{'fraction_non_alphanumeric': 0.09929395943068475, 'fraction_numerical': 0.0008965594530987336, 'mean_word_length': 3.4243926623698564, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1277330', 'n_tokens_mistral': 2451, 'n_tokens_neox': 2398, 'n_words': 781}