static std::unique_ptr parse()

in watchman/query/since.cpp [101:163]


  static std::unique_ptr<QueryExpr> parse(Query*, const json_ref& term) {
    auto selected_field = since_what::SINCE_OCLOCK;
    const char* fieldname = "oclock";

    if (!term.isArray()) {
      throw QueryParseError("\"since\" term must be an array");
    }

    if (json_array_size(term) < 2 || json_array_size(term) > 3) {
      throw QueryParseError("\"since\" term has invalid number of parameters");
    }

    const auto& jval = term.at(1);
    auto spec = ClockSpec::parseOptionalClockSpec(jval);
    if (!spec) {
      throw QueryParseError("invalid clockspec for \"since\" term");
    }
    if (std::holds_alternative<ClockSpec::NamedCursor>(spec->spec)) {
      throw QueryParseError("named cursors are not allowed in \"since\" terms");
    }

    if (term.array().size() == 3) {
      const auto& field = term.at(2);
      size_t i;
      bool valid = false;

      fieldname = json_string_value(field);
      if (!fieldname) {
        throw QueryParseError("field name for \"since\" term must be a string");
      }

      for (i = 0; i < sizeof(allowed_fields) / sizeof(allowed_fields[0]); ++i) {
        if (!strcmp(allowed_fields[i].label, fieldname)) {
          selected_field = allowed_fields[i].value;
          valid = true;
          break;
        }
      }

      if (!valid) {
        throw QueryParseError(
            "invalid field name \"", fieldname, "\" for \"since\" term");
      }
    }

    switch (selected_field) {
      case since_what::SINCE_CTIME:
      case since_what::SINCE_MTIME:
        if (!std::holds_alternative<ClockSpec::Timestamp>(spec->spec)) {
          throw QueryParseError(
              "field \"",
              fieldname,
              "\" requires a timestamp value for comparison in \"since\" term");
        }
        break;
      case since_what::SINCE_OCLOCK:
      case since_what::SINCE_CCLOCK:
        /* we'll work with clocks or timestamps */
        break;
    }

    return std::make_unique<SinceExpr>(std::move(spec), selected_field);
  }