query/source/orm/query/criteria_evaluator.cpp

122 lines
4.4 KiB
C++

#include "matador/query/criteria_evaluator.hpp"
#include "matador/query/criteria/between_criteria.hpp"
#include "matador/query/criteria/binary_criteria.hpp"
#include "matador/query/criteria/collection_criteria.hpp"
#include "matador/query/criteria/like_criteria.hpp"
#include "matador/query/criteria/logical_criteria.hpp"
#include "matador/query/criteria/not_criteria.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/utils/value.hpp"
#include "matador/utils/enum_mapper.hpp"
namespace matador::query {
namespace detail {
static const utils::enum_mapper<binary_operator> BinaryOperatorEnum({
{binary_operator::EQUALS, "="},
{binary_operator::NOT_EQUALS, "<>"},
{binary_operator::GREATER_THAN, ">"},
{binary_operator::GREATER_THAN_OR_EQUAL, ">="},
{binary_operator::LESS_THAN, "<"},
{binary_operator::LESS_THAN_OR_EQUAL, "<="},
});
}
criteria_evaluator::criteria_evaluator(const sql::dialect &d, sql::query_context &query)
: dialect_(d)
, query_(query) {
}
std::string criteria_evaluator::evaluate(const abstract_criteria &node) {
clause_.clear();
node.accept(*this);
return clause_;
}
void criteria_evaluator::visit(const between_criteria &node) {
query_.bind_vars.emplace_back(node.column().name);
query_.bind_vars.emplace_back(node.column().name);
clause_ += dialect_.prepare_identifier(node.column()) + " " + dialect_.token_at(sql::dialect_token::Between) + " ";
evaluate_value(node.minimum());
clause_ += " " + dialect_.token_at(sql::dialect_token::And) + " ";
evaluate_value(node.maximum());
}
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
void criteria_evaluator::visit(const binary_criteria &node) {
clause_ += dialect_.prepare_condition(node.column()) + " " + detail::BinaryOperatorEnum.to_string(node.operand()) + " ";
evaluate_value(node.value());
}
void criteria_evaluator::visit( const binary_column_criteria& node ) {
clause_ += dialect_.prepare_condition(node.left_column()) + " " + detail::BinaryOperatorEnum.to_string(node.operand()) + " " + dialect_.prepare_condition(node.right_column());
}
void criteria_evaluator::visit(const collection_criteria &node) {
const auto count = node.values().size();
for (size_t i = 0; i < count; ++i) {
query_.bind_vars.emplace_back(node.column().name);
}
clause_ += dialect_.prepare_identifier(node.column()) +
(node.operand() == collection_operator::Out ? " " + dialect_.token_at(sql::dialect_token::Not) + " " : " ") +
dialect_.token_at(sql::dialect_token::In) + " (";
if (node.values().size() < 2) {
for (const auto &val: node.values()) {
evaluate_value(val);
}
} else {
auto it = node.values().begin();
evaluate_value(*it++);
for (; it != node.values().end(); ++it) {
clause_ += ", ";
evaluate_value(*it);
}
}
clause_ += ")";
}
void criteria_evaluator::visit(const collection_query_criteria &node) {
clause_ += dialect_.prepare_identifier(node.column()) +
(node.operand() == collection_operator::Out ? " " + dialect_.token_at(sql::dialect_token::Not) + " " : " ") +
dialect_.token_at(sql::dialect_token::In) + " (" +node.context().sql + ")";
}
void criteria_evaluator::visit(const like_criteria &node) {
clause_ += dialect_.prepare_condition(node.column()) + " " + dialect_.token_at(sql::dialect_token::Like) +
" " + dialect_.token_at(sql::dialect_token::BeginStringData) + node.pattern() + dialect_.token_at(
sql::dialect_token::EndStringData);
}
void criteria_evaluator::visit(const logical_criteria &node) {
clause_ += "(";
node.left_clause()->accept(*this);
clause_ += " " + dialect_.token_at(node.operand() == logical_operator::AND
? sql::dialect_token::And
: sql::dialect_token::Or) + " ";
node.right_clause()->accept(*this);
clause_ += ")";
}
void criteria_evaluator::visit(const not_criteria &node) {
clause_ += dialect_.token_at(sql::dialect_token::Not) + " (";
node.clause()->accept(*this);
clause_ += ")";
}
void criteria_evaluator::evaluate_value(const criteria_value &value) {
std::visit(overload{
[this](const utils::value& val){ clause_ += dialect_.to_sql_string(val); },
[this](const utils::placeholder&) { clause_ += dialect_.next_placeholder(query_.bind_vars); }
}, value);
}
}