Status Parse()

in src/commands/cmd_zset.cc [734:816]


  Status Parse(const std::vector<std::string> &args) override {
    key_ = args[1];

    int64_t offset = 0;
    int64_t count = -1;
    // skip the <CMD> <src> <min> <max> args and parse remaining optional arguments
    CommandParser parser(args, 4);
    while (parser.Good()) {
      if (parser.EatEqICase("withscores")) {
        with_scores_ = true;
      } else if (parser.EatEqICase("limit")) {
        auto parse_offset = parser.TakeInt<int64_t>();
        auto parse_count = parser.TakeInt<int64_t>();
        if (!parse_offset || !parse_count) {
          return {Status::RedisParseErr, errValueNotInteger};
        }
        offset = *parse_offset;
        count = *parse_count;
      } else if (range_type_ == kZRangeAuto && parser.EatEqICase("bylex")) {
        range_type_ = kZRangeLex;
      } else if (range_type_ == kZRangeAuto && parser.EatEqICase("byscore")) {
        range_type_ = kZRangeScore;
      } else if (direction_ == kZRangeDirectionAuto && parser.EatEqICase("rev")) {
        direction_ = kZRangeDirectionReverse;
      } else {
        return parser.InvalidSyntax();
      }
    }

    // use defaults if not overridden by arguments
    if (range_type_ == kZRangeAuto) {
      range_type_ = kZRangeRank;
    }
    if (direction_ == kZRangeDirectionAuto) {
      direction_ = kZRangeDirectionForward;
    }

    // check for conflicting arguments
    if (with_scores_ && range_type_ == kZRangeLex) {
      return {Status::RedisParseErr, "syntax error, WITHSCORES not supported in combination with BYLEX"};
    }
    if (count != -1 && range_type_ == kZRangeRank) {
      return {Status::RedisParseErr,
              "syntax error, LIMIT is only supported in combination with either BYSCORE or BYLEX"};
    }

    // resolve index of <min> <max>
    int min_idx = 2;
    int max_idx = 3;
    if (direction_ == kZRangeDirectionReverse && (range_type_ == kZRangeLex || range_type_ == kZRangeScore)) {
      min_idx = 3;
      max_idx = 2;
    }

    // parse range spec
    switch (range_type_) {
      case kZRangeAuto:
      case kZRangeRank:
        GET_OR_RET(ParseRangeRankSpec(args[min_idx], args[max_idx], &rank_spec_));
        if (direction_ == kZRangeDirectionReverse) {
          rank_spec_.reversed = true;
        }
        break;
      case kZRangeLex:
        GET_OR_RET(ParseRangeLexSpec(args[min_idx], args[max_idx], &lex_spec_));
        lex_spec_.offset = offset;
        lex_spec_.count = count;
        if (direction_ == kZRangeDirectionReverse) {
          lex_spec_.reversed = true;
        }
        break;
      case kZRangeScore:
        GET_OR_RET(ParseRangeScoreSpec(args[min_idx], args[max_idx], &score_spec_));
        score_spec_.offset = offset;
        score_spec_.count = count;
        if (direction_ == kZRangeDirectionReverse) {
          score_spec_.reversed = true;
        }
        break;
    }

    return Status::OK();
  }