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