export function targetGetUpperBound()

in packages/firestore/src/core/target.ts [381:461]


export function targetGetUpperBound(
  target: Target,
  fieldIndex: FieldIndex
): Bound | null {
  const values: ProtoValue[] = [];
  let inclusive = true;

  // For each segment, retrieve an upper bound if there is a suitable filter or
  // endAt.
  for (const segment of fieldIndexGetDirectionalSegments(fieldIndex)) {
    let segmentValue: ProtoValue | undefined = undefined;
    let segmentInclusive = true;

    // Process all filters to find a value for the current field segment
    for (const fieldFilter of targetGetFieldFiltersForPath(
      target,
      segment.fieldPath
    )) {
      let filterValue: ProtoValue | undefined = undefined;
      let filterInclusive = true;

      switch (fieldFilter.op) {
        case Operator.GREATER_THAN_OR_EQUAL:
        case Operator.GREATER_THAN:
          filterValue = valuesGetUpperBound(fieldFilter.value);
          filterInclusive = false;
          break;
        case Operator.EQUAL:
        case Operator.IN:
        case Operator.LESS_THAN_OR_EQUAL:
          filterValue = fieldFilter.value;
          break;
        case Operator.LESS_THAN:
          filterValue = fieldFilter.value;
          filterInclusive = false;
          break;
        case Operator.NOT_EQUAL:
          filterValue = MAX_VALUE;
          break;
        case Operator.NOT_IN:
          const length = (fieldFilter.value.arrayValue!.values || []).length;
          filterValue = {
            arrayValue: { values: new Array(length).fill(MIN_VALUE) }
          };
          break;
        default:
        // Remaining filters cannot be used as upper bounds.
      }

      if (valuesMin(segmentValue, filterValue) === filterValue) {
        segmentValue = filterValue;
        segmentInclusive = filterInclusive;
      }
    }

    // If there is a endAt bound, compare the values against the existing
    // boundary to see if we can narrow the scope.
    if (target.endAt !== null) {
      for (let i = 0; i < target.orderBy.length; ++i) {
        const orderBy = target.orderBy[i];
        if (orderBy.field.isEqual(segment.fieldPath)) {
          const cursorValue = target.endAt.position[i];
          if (valuesMin(segmentValue, cursorValue) === cursorValue) {
            segmentValue = cursorValue;
            segmentInclusive = target.endAt.inclusive;
          }
          break;
        }
      }
    }

    if (segmentValue === undefined) {
      // No lower bound exists
      return null;
    }
    values.push(segmentValue);
    inclusive &&= segmentInclusive;
  }

  return new Bound(values, inclusive);
}