122 lines
4.4 KiB
C++
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);
|
|
|
|
}
|
|
}
|