auto Transform()

in src/search/sql_transformer.h [61:232]


  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<Boolean>(node)) {
      return Node::Create<ir::BoolLiteral>(node->string_view() == "true");
    } else if (Is<Number>(node)) {
      return Node::Create<ir::NumericLiteral>(*ParseFloat(node->string()));
    } else if (Is<StringL>(node)) {
      return Node::Create<ir::StringLiteral>(GET_OR_RET(UnescapeString(node->string_view())));
    } else if (Is<VectorLiteral>(node)) {
      std::vector<double> values;
      for (const auto& child : node->children) {
        values.push_back(*ParseFloat(child->string()));
      }
      return Node::Create<ir::VectorLiteral>(std::move(values));
    } else if (Is<HasTagExpr>(node)) {
      CHECK(node->children.size() == 2);

      const auto& tag = node->children[1];
      std::unique_ptr<ir::StringLiteral> res;
      if (Is<StringL>(tag)) {
        res = Node::MustAs<ir::StringLiteral>(GET_OR_RET(Transform(tag)));
      } else if (Is<Param>(tag)) {
        res = std::make_unique<ir::StringLiteral>(GET_OR_RET(GetParam(tag)));
      } else {
        return {Status::NotOK, "encountered invalid tag"};
      }

      return Node::Create<ir::TagContainExpr>(std::make_unique<ir::FieldRef>(node->children[0]->string()),
                                              std::move(res));
    } else if (Is<NumericCompareExpr>(node)) {
      CHECK(node->children.size() == 3);

      const auto& lhs = node->children[0];
      const auto& rhs = node->children[2];

      auto op = ir::NumericCompareExpr::FromOperator(node->children[1]->string_view()).value();
      if (Is<Identifier>(lhs) && (Is<Number>(rhs) || Is<Param>(rhs))) {
        return Node::Create<ir::NumericCompareExpr>(op, std::make_unique<ir::FieldRef>(lhs->string()),
                                                    GET_OR_RET(number_or_param(rhs)));
      } else if ((Is<Number>(lhs) || Is<Param>(lhs)) && Is<Identifier>(rhs)) {
        return Node::Create<ir::NumericCompareExpr>(ir::NumericCompareExpr::Flip(op),
                                                    std::make_unique<ir::FieldRef>(rhs->string()),
                                                    GET_OR_RET(number_or_param(lhs)));
      } else {
        return {Status::NotOK, "the left and right side of numeric comparison should be an identifier and a number"};
      }
    } else if (Is<VectorRangeExpr>(node)) {
      CHECK(node->children.size() == 2);
      const auto& vector_comp_expr = node->children[0];
      CHECK(vector_comp_expr->children.size() == 3);

      return Node::Create<ir::VectorRangeExpr>(
          std::make_unique<ir::FieldRef>(vector_comp_expr->children[0]->string()),
          GET_OR_RET(number_or_param(node->children[1])),
          Node::MustAs<ir::VectorLiteral>(GET_OR_RET(Transform(vector_comp_expr->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<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 (Is<SelectExpr>(node)) {
      std::vector<std::unique_ptr<ir::FieldRef>> fields;

      if (node->children.size() == 1 && Is<Wildcard>(node->children[0])) {
        return Node::Create<ir::SelectClause>(std::move(fields));
      }

      for (const auto& child : node->children) {
        fields.push_back(std::make_unique<ir::FieldRef>(child->string()));
      }

      return Node::Create<ir::SelectClause>(std::move(fields));
    } else if (Is<FromExpr>(node)) {
      CHECK(node->children.size() == 1);
      return Node::Create<ir::IndexRef>(node->children[0]->string());
    } else if (Is<WhereClause>(node)) {
      CHECK(node->children.size() == 1);
      return Transform(node->children[0]);
    } else if (Is<LimitClause>(node)) {
      CHECK(node->children.size() == 1 || node->children.size() == 2);

      size_t offset = 0, count = std::numeric_limits<size_t>::max();
      if (node->children.size() == 1) {
        count = *ParseInt(node->children[0]->string());
      } else {
        offset = *ParseInt(node->children[0]->string());
        count = *ParseInt(node->children[1]->string());
      }

      return Node::Create<ir::LimitClause>(offset, count);
    } else if (Is<OrderByClause>(node)) {
      CHECK(node->children.size() == 1);
      const auto& order_by_expr = node->children[0];
      CHECK(order_by_expr->children.size() == 1 || order_by_expr->children.size() == 2);

      if (Is<VectorCompareExpr>(order_by_expr->children[0])) {
        const auto& vector_compare_expr = order_by_expr->children[0];
        CHECK(vector_compare_expr->children.size() == 3);
        auto field = std::make_unique<FieldRef>(vector_compare_expr->children[0]->string());
        return Node::Create<SortByClause>(
            std::move(field), Node::MustAs<ir::VectorLiteral>(GET_OR_RET(Transform(vector_compare_expr->children[2]))));
      } else {
        auto field = std::make_unique<FieldRef>(order_by_expr->children[0]->string());
        auto order = SortByClause::Order::ASC;
        if (order_by_expr->children.size() == 2 && order_by_expr->children[1]->string_view() == "desc") {
          order = SortByClause::Order::DESC;
        }
        return Node::Create<SortByClause>(order, std::move(field));
      }
    } else if (Is<SearchStmt>(node)) {  // root node
      CHECK(node->children.size() >= 2 && node->children.size() <= 5);

      auto index = Node::MustAs<ir::IndexRef>(GET_OR_RET(Transform(node->children[1])));
      auto select = Node::MustAs<ir::SelectClause>(GET_OR_RET(Transform(node->children[0])));

      std::unique_ptr<ir::QueryExpr> query_expr;
      std::unique_ptr<ir::LimitClause> limit;
      std::unique_ptr<ir::SortByClause> sort_by;

      for (size_t i = 2; i < node->children.size(); ++i) {
        if (Is<WhereClause>(node->children[i])) {
          query_expr = Node::MustAs<ir::QueryExpr>(GET_OR_RET(Transform(node->children[i])));
        } else if (Is<LimitClause>(node->children[i])) {
          limit = Node::MustAs<ir::LimitClause>(GET_OR_RET(Transform(node->children[i])));
        } else if (Is<OrderByClause>(node->children[i])) {
          sort_by = Node::MustAs<ir::SortByClause>(GET_OR_RET(Transform(node->children[i])));
        }
      }

      if (!query_expr) {
        query_expr = std::make_unique<BoolLiteral>(true);
      }

      return Node::Create<ir::SearchExpr>(std::move(index), std::move(query_expr), std::move(limit), std::move(sort_by),
                                          std::move(select));
    } 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)};
    }
  }