#include "matador/rsql/binary_condition_node.hpp" #include "matador/rsql/collection_condition_node.hpp" #include "matador/rsql/lexer.hpp" #include "matador/rsql/logical_node.hpp" #include "matador/rsql/node_visitor.hpp" #include "matador/rsql/parser.hpp" #include // ---------------- Evaluator Visitor (prints AST) ---------------- class Evaluator final : public matador::rsql::node_visitor { public: void visit(const matador::rsql::binary_condition_node& node) override { std::cout << "Condition: " << node.field() << " " << to_string(node.operand()) << " " << node.value() << "\n"; } void visit( const matador::rsql::collection_condition_node& node ) override { std::cout << "Condition: " << node.field() << " " << to_string(node.operand()) << " "; std::cout << "("; for (size_t i = 0; i < node.values().size(); ++i) { std::cout << node.values()[i]; if (i + 1 < node.values().size()) std::cout << ","; } std::cout << ")\n"; } void visit(const matador::rsql::logical_node& node) override { std::cout << "Logical (" << (node.operand() == matador::rsql::logical_operator::And ? "AND" : "OR") << ")\n"; for (const auto& child : node.children()) { child->accept(*this); } } private: static std::string to_string(const matador::rsql::binary_operator op) { static std::map bin_to_string { { matador::rsql::binary_operator::Equals, "==" }, { matador::rsql::binary_operator::NotEquals, "!=" }, { matador::rsql::binary_operator::GreaterThan, ">" }, { matador::rsql::binary_operator::GreaterThanOrEqual, ">=" }, { matador::rsql::binary_operator::LessThan, "<" }, { matador::rsql::binary_operator::LessThanOrEqual, "<=" }, }; return bin_to_string.at(op); } static std::string to_string(const matador::rsql::collection_operator op) { static std::map col_to_string { { matador::rsql::collection_operator::In, "=IN=" }, { matador::rsql::collection_operator::Out, "=OUT=" } }; return col_to_string.at(op); } }; // ---------------- SQLBuilderVisitor ---------------- class SQLBuilderVisitor final : public matador::rsql::node_visitor { public: std::string result; void visit(const matador::rsql::binary_condition_node& node) override { result += "(" + field(node.field()) + " " + binary_op_string(node.operand(), node.value()) + ")"; } void visit( const matador::rsql::collection_condition_node& node ) override { result += "(" + field(node.field()) + " " + collection_op_string(node.operand(), node.values()) + ")"; } void visit(const matador::rsql::logical_node& node) override { // Build children SQL and join std::vector parts; for (const auto& child : node.children()) { SQLBuilderVisitor sub; child->accept(sub); parts.push_back(sub.result); } const std::string operand = (node.operand() == matador::rsql::logical_operator::And ? " AND " : " OR "); result += "("; for (size_t i = 0; i < parts.size(); ++i) { result += parts[i]; if (i + 1 < parts.size()) { result += operand; } } result += ")"; } private: static std::string escape_sql(const std::string& s) { std::string out; out.reserve(s.size() + 2); for (const char c : s) { if (c == '\'') out.push_back('\''); // double single-quote out.push_back(c); } return out; } static bool is_number(const std::string& s) { if (s.empty()) { return false; } // allow optional leading '-' and digits, optional decimal point size_t i = 0; if (s[0] == '-') i = 1; bool seenDigit = false; bool seenDot = false; for (; i < s.size(); ++i) { if (std::isdigit(static_cast(s[i]))) seenDigit = true; else if (s[i] == '.' && !seenDot) seenDot = true; else return false; } return seenDigit; } static std::string quote(const std::string& str) { if (is_number(str)) { return str; } return std::string("'") + escape_sql(str) + std::string("'"); } static std::string field(const std::string& f) { // Todo: add quoting rules return f; } static std::string binary_op_string(const matador::rsql::binary_operator op, const std::string& val) { using namespace matador::rsql; switch (op) { case binary_operator::Equals: return "= " + quote(val); case binary_operator::NotEquals: return "<> " + quote(val); case binary_operator::GreaterThan: return "> " + quote(val); case binary_operator::GreaterThanOrEqual: return ">= " + quote(val); case binary_operator::LessThan: return "< " + quote(val); case binary_operator::LessThanOrEqual: return "<= " + quote(val); default: return "??"; } } static std::string collection_op_string(const matador::rsql::collection_operator op, const std::vector& list) { if (list.empty()) { return (op == matador::rsql::collection_operator::Out ? "NOT IN (NULL)" : "IN (NULL)"); } std::string joined; joined += "("; for (size_t i = 0; i < list.size(); ++i) { joined += quote(list[i]); if (i + 1 < list.size()) joined += ", "; } joined += ")"; if (op == matador::rsql::collection_operator::Out) { return "IN " + joined; } return "NOT IN " + joined; } }; // ---------------- Main / usage ---------------- int main(const int argc, char** argv) { using namespace matador::rsql; std::string input; if (argc >= 2) { input = argv[1]; } else { // example default input = "(status=in=(OPEN,CLOSED);priority==HIGH),category=out=(internal,test)"; std::cout << "No query provided, using default example:\n" << input << "\n\n"; } try { const auto tokens = lexer::tokenize(input); parser p(tokens); const auto ast = p.parse(); std::cout << "=== AST (Evaluator) ===\n"; Evaluator ev; ast->accept(ev); std::cout << "\n=== SQL WHERE clause ===\n"; SQLBuilderVisitor sql; ast->accept(sql); std::cout << sql.result << "\n"; } catch (const std::exception& ex) { std::cerr << "Error: " << ex.what() << "\n"; return 2; } return 0; }