auto Transform()

in src/search/redis_query_transformer.h [66:203]


  auto Transform(const TreeNode& node) -> StatusOr<std::unique_ptr<Node>> {
    auto number_or_param = [this](const TreeNode& node) -> StatusOr<std::unique_ptr<NumericLiteral>> {
      if (Is<Number>(node)) {
        return Node::MustAs<ir::NumericLiteral>(GET_OR_RET(Transform(node)));
      } else if (Is<Param>(node)) {
        auto val = GET_OR_RET(ParseFloat(GET_OR_RET(GetParam(node)))
                                  .Prefixed(fmt::format("parameter {} is not a number", node->string_view())));

        return std::make_unique<ir::NumericLiteral>(val);
      } else {
        return {Status::NotOK,
                fmt::format("expected a number or a parameter in numeric comparison but got {}", node->type)};
      }
    };

    if (Is<Number>(node)) {
      return Node::Create<ir::NumericLiteral>(*ParseFloat(node->string()));
    } else if (Is<Wildcard>(node)) {
      return Node::Create<ir::BoolLiteral>(true);
    } else if (Is<FieldQuery>(node)) {
      CHECK(node->children.size() == 2);

      auto field = node->children[0]->string();
      const auto& query = node->children[1];

      if (Is<TagList>(query)) {
        std::vector<std::unique_ptr<ir::QueryExpr>> exprs;

        for (const auto& tag : query->children) {
          std::string tag_str;
          if (Is<Identifier>(tag)) {
            tag_str = tag->string();
          } else if (Is<StringL>(tag)) {
            tag_str = GET_OR_RET(UnescapeString(tag->string()));
          } else if (Is<Param>(tag)) {
            tag_str = GET_OR_RET(GetParam(tag));
          } else {
            return {Status::NotOK, "encountered invalid tag"};
          }

          exprs.push_back(std::make_unique<ir::TagContainExpr>(std::make_unique<FieldRef>(field),
                                                               std::make_unique<StringLiteral>(tag_str)));
        }

        if (exprs.size() == 1) {
          return std::move(exprs[0]);
        } else {
          return std::make_unique<ir::OrExpr>(std::move(exprs));
        }
      } else if (Is<NumericRange>(query)) {
        std::vector<std::unique_ptr<ir::QueryExpr>> exprs;

        const auto& lhs = query->children[0];
        const auto& rhs = query->children[1];

        if (Is<ExclusiveNumber>(lhs)) {
          exprs.push_back(std::make_unique<NumericCompareExpr>(NumericCompareExpr::GT,
                                                               std::make_unique<FieldRef>(field),
                                                               GET_OR_RET(number_or_param(lhs->children[0]))));
        } else if (Is<Number>(lhs) || Is<Param>(lhs)) {
          exprs.push_back(std::make_unique<NumericCompareExpr>(
              NumericCompareExpr::GET, std::make_unique<FieldRef>(field), GET_OR_RET(number_or_param(lhs))));
        } else {  // Inf
          if (lhs->string_view() == "+inf") {
            return {Status::NotOK, "it's not allowed to set the lower bound as positive infinity"};
          }
        }

        if (Is<ExclusiveNumber>(rhs)) {
          exprs.push_back(std::make_unique<NumericCompareExpr>(NumericCompareExpr::LT,
                                                               std::make_unique<FieldRef>(field),
                                                               GET_OR_RET(number_or_param(rhs->children[0]))));
        } else if (Is<Number>(rhs) || Is<Param>(rhs)) {
          exprs.push_back(std::make_unique<NumericCompareExpr>(
              NumericCompareExpr::LET, std::make_unique<FieldRef>(field), GET_OR_RET(number_or_param(rhs))));
        } else {  // Inf
          if (rhs->string_view() == "-inf") {
            return {Status::NotOK, "it's not allowed to set the upper bound as negative infinity"};
          }
        }

        if (exprs.empty()) {
          return std::make_unique<BoolLiteral>(true);
        } else if (exprs.size() == 1) {
          return std::move(exprs[0]);
        } else {
          return std::make_unique<ir::AndExpr>(std::move(exprs));
        }
      } else if (Is<VectorRange>(query)) {
        return std::make_unique<VectorRangeExpr>(std::make_unique<FieldRef>(field),
                                                 GET_OR_RET(number_or_param(query->children[1])),
                                                 GET_OR_RET(Transform2Vector(query->children[2])));
      }
    } else if (Is<NotExpr>(node)) {
      CHECK(node->children.size() == 1);

      return Node::Create<ir::NotExpr>(Node::MustAs<ir::QueryExpr>(GET_OR_RET(Transform(node->children[0]))));
    } else if (Is<PrefilterExpr>(node)) {
      // TODO: allow hybrid query
      CHECK(node->children.size() == 3);

      const auto& knn_search = node->children[2];
      CHECK(knn_search->children.size() == 4);

      size_t k = 0;
      if (Is<UnsignedInteger>(knn_search->children[1])) {
        k = *ParseInt(knn_search->children[1]->string());
      } else {
        k = *ParseInt(GET_OR_RET(GetParam(knn_search->children[1])));
      }

      return std::make_unique<VectorKnnExpr>(std::make_unique<FieldRef>(knn_search->children[2]->string()),
                                             GET_OR_RET(Transform2Vector(knn_search->children[3])), k);
    } else if (Is<AndExpr>(node)) {
      std::vector<std::unique_ptr<ir::QueryExpr>> exprs;

      for (const auto& child : node->children) {
        exprs.push_back(Node::MustAs<ir::QueryExpr>(GET_OR_RET(Transform(child))));
      }

      return Node::Create<ir::AndExpr>(std::move(exprs));
    } else if (Is<OrExpr>(node)) {
      std::vector<std::unique_ptr<ir::QueryExpr>> exprs;

      for (const auto& child : node->children) {
        exprs.push_back(Node::MustAs<ir::QueryExpr>(GET_OR_RET(Transform(child))));
      }

      return Node::Create<ir::OrExpr>(std::move(exprs));
    } else if (IsRoot(node)) {
      CHECK(node->children.size() == 1);

      return Transform(node->children[0]);
    } else {
      // UNREACHABLE CODE, just for debugging here
      return {Status::NotOK, fmt::format("encountered invalid node type: {}", node->type)};
    }
  }  // NOLINT