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)};
}
}