std::unique_ptr parseCronField()

in utils/src/utils/Cron.cpp [374:457]


std::unique_ptr<CronField> parseCronField(const std::string& field_str) {
  try {
    if (field_str == "*") {
      return std::make_unique<AllValuesField>();
    }

    if (field_str == "?") {
      return std::make_unique<NotCheckedField>();
    }

    if (field_str == "L") {
      if constexpr (std::is_same<day, FieldType>())
        return std::make_unique<LastNthDayInMonthField>(days(0));
      if constexpr (std::is_same<weekday, FieldType>())
        return std::make_unique<SingleValueField<weekday>>(Saturday);
      throw BadCronExpression("L can only be used in the Day of month/Day of week fields");
    }

    if (field_str == "LW") {
      if constexpr (!std::is_same<day, FieldType>())
        throw BadCronExpression("LW can only be used in the Day of month field");
      return std::make_unique<LastWeekDayField>();
    }

    if (field_str.find('#') != std::string::npos) {
      if constexpr (!std::is_same<weekday, FieldType>())
        throw BadCronExpression("# can only be used in the Day of week field");
      auto operands = string::split(field_str, "#");
      if (operands.size() != 2)
        throw BadCronExpression("Invalid field " + field_str);

      if (auto second_operand = fromChars<uint8_t>(operands[1]))
        return std::make_unique<NthWeekdayField>(parse<weekday>(operands[0]), *second_operand);
    }

    if (field_str.find('-') != std::string::npos) {
      auto operands = string::split(field_str, "-");
      if (operands.size() != 2)
        throw BadCronExpression("Invalid field " + field_str);
      if (operands[0] == "L") {
        if constexpr (std::is_same<day, FieldType>())
          return std::make_unique<LastNthDayInMonthField>(parse<days>(operands[1]));
      }
      return std::make_unique<RangeField<FieldType>>(parse<FieldType>(operands[0]), parse<FieldType>(operands[1]));
    }

    if (field_str.ends_with('L')) {
      if constexpr (!std::is_same<weekday, FieldType>())
        throw BadCronExpression("<X>L can only be used in the Day of week field");
      auto prefix = field_str.substr(0, field_str.size()-1);
      return std::make_unique<LastSpecificDayOfTheWeekOfTheMonth>(parse<weekday>(prefix));
    }

    if (field_str.find('/') != std::string::npos) {
      auto operands = string::split(field_str, "/");
      if (operands.size() != 2)
        throw BadCronExpression("Invalid field " + field_str);
      if (operands[0] == "*")
        operands[0] = "0";
      if (auto second_operand = fromChars<int>(operands[1]))
        return std::make_unique<IncrementField<FieldType>>(parse<FieldType>(operands[0]), *second_operand);
    }

    if (field_str.find(',') != std::string::npos) {
      auto operands_str = string::split(field_str, ",");
      std::vector<FieldType> operands;
      std::transform(operands_str.begin(), operands_str.end(), std::back_inserter(operands), parse<FieldType>);
      return std::make_unique<ListField<FieldType>>(std::move(operands));
    }

    if (field_str.ends_with('W')) {
      if constexpr (!std::is_same<day, FieldType>())
        throw BadCronExpression("W can only be used in the Day of month field");
      auto operands_str = string::split(field_str, "W");
      if (operands_str.size() != 2)
        throw BadCronExpression("Invalid field " + field_str);
      return std::make_unique<ClosestWeekdayToTheNthDayOfTheMonth>(parse<day>(operands_str[0]));
    }

    return std::make_unique<SingleValueField<FieldType>>(parse<FieldType>(field_str));
  } catch (const std::exception& e) {
    throw BadCronExpression("Couldn't parse cron field: " + field_str + " " + e.what());
  }
}