started query builder
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
#include <utility>
|
||||
|
||||
#include "matador/sql/column.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
column::column(std::string name, data_type_t type, utils::field_attributes attr)
|
||||
: name_(std::move(name))
|
||||
, type_(type)
|
||||
, attributes_(attr) {}
|
||||
|
||||
const std::string &column::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
const utils::field_attributes &column::attributes() const {
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
data_type_t column::type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
const std::string& dialect::token_at(dialect::token_t token) const {
|
||||
return tokens_.at(token);
|
||||
}
|
||||
|
||||
std::string dialect::prepare_identifier(const std::string &str) const
|
||||
{
|
||||
std::string result(str);
|
||||
escape_quotes_in_identifier(result);
|
||||
quote_identifier(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dialect::prepare_literal(const std::string &str) const
|
||||
{
|
||||
std::string result(str);
|
||||
escape_quotes_in_literals(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void dialect::quote_identifier(std::string &str) const
|
||||
{
|
||||
str.insert(0, token_at(token_t::START_QUOTE));
|
||||
str += token_at(token_t::END_QUOTE);
|
||||
}
|
||||
|
||||
void dialect::escape_quotes_in_identifier(std::string &str) const
|
||||
{
|
||||
const std::string open_char(token_at(token_t::START_QUOTE));
|
||||
std::string close_char(token_at(token_t::END_QUOTE));
|
||||
if (identifier_escape_type() == escape_identifier_t::ESCAPE_CLOSING_BRACKET) {
|
||||
utils::replace_all(str, close_char, close_char + close_char);
|
||||
} else {
|
||||
utils::replace_all(str, open_char, open_char + open_char);
|
||||
}
|
||||
}
|
||||
|
||||
void dialect::escape_quotes_in_literals(std::string &str) const
|
||||
{
|
||||
const std::string single_quote(token_at(token_t::STRING_QUOTE));
|
||||
const std::string double_quote(token_at(token_t::STRING_QUOTE) + token_at(token_t::STRING_QUOTE));
|
||||
utils::replace_all(str, single_quote, double_quote);
|
||||
}
|
||||
|
||||
dialect::escape_identifier_t dialect::identifier_escape_type() const {
|
||||
return dialect::escape_identifier_t::ESCAPE_BOTH_SAME;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "matador/sql/query_builder.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
// poor mens state machine
|
||||
// but does the job for query
|
||||
query_builder::query_state_transition_map query_builder::transitions_{
|
||||
{state_t::QUERY_INIT, {state_t::QUERY_CREATE, state_t::QUERY_DROP, state_t::QUERY_SELECT, state_t::QUERY_INSERT, state_t::QUERY_UPDATE, state_t::QUERY_DELETE}},
|
||||
{state_t::QUERY_CREATE, {state_t::QUERY_TABLE}},
|
||||
{state_t::QUERY_DROP, {state_t::QUERY_TABLE}},
|
||||
{state_t::QUERY_SELECT, {state_t::QUERY_FROM}},
|
||||
{state_t::QUERY_INSERT, {state_t::QUERY_INTO}},
|
||||
{state_t::QUERY_UPDATE, {state_t::QUERY_SET}},
|
||||
{state_t::QUERY_DELETE, {state_t::QUERY_FROM}},
|
||||
{state_t::QUERY_TABLE, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_FROM, {state_t::QUERY_WHERE, state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_SET, {state_t::QUERY_WHERE, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_INTO, {state_t::QUERY_VALUES}},
|
||||
{state_t::QUERY_WHERE, {state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_ORDER_BY, {state_t::QUERY_ORDER_DIRECTION}},
|
||||
{state_t::QUERY_ORDER_DIRECTION, {state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_GROUP_BY, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_LIMIT, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_VALUES, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_FINISH, {}},
|
||||
};
|
||||
|
||||
query_builder::query_state_to_string_map query_builder::state_strings_ {
|
||||
{ state_t::QUERY_INIT, "init" },
|
||||
{ state_t::QUERY_CREATE, "create" },
|
||||
{ state_t::QUERY_DROP, "drop" },
|
||||
{ state_t::QUERY_SELECT, "select" },
|
||||
{ state_t::QUERY_INSERT, "insert" },
|
||||
{ state_t::QUERY_UPDATE, "update" },
|
||||
{ state_t::QUERY_DELETE, "delete" },
|
||||
{ state_t::QUERY_TABLE, "table" },
|
||||
{ state_t::QUERY_FROM, "from" },
|
||||
{ state_t::QUERY_SET, "set" },
|
||||
{ state_t::QUERY_INTO, "into" },
|
||||
{ state_t::QUERY_WHERE, "where" },
|
||||
{ state_t::QUERY_ORDER_BY, "order_by" },
|
||||
{ state_t::QUERY_GROUP_BY, "group_by" },
|
||||
{ state_t::QUERY_LIMIT, "limit" },
|
||||
{ state_t::QUERY_FINISH, "finish" },
|
||||
};
|
||||
|
||||
query_builder::query_command_to_string_map query_builder::command_strings_ {
|
||||
{ command_t::UNKNOWN, "unknown" },
|
||||
{ command_t::CREATE, "create" },
|
||||
{ command_t::DROP, "drop" },
|
||||
{ command_t::SELECT, "select" },
|
||||
{ command_t::INSERT, "insert" },
|
||||
{ command_t::UPDATE, "update" },
|
||||
{ command_t::REMOVE, "remove" },
|
||||
};
|
||||
|
||||
query_builder::query_builder(const dialect &d)
|
||||
: dialect_(d) {}
|
||||
|
||||
query_builder &query_builder::create() {
|
||||
initialize(command_t::CREATE, state_t::QUERY_CREATE);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::CREATE) + " ");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::table(const std::string &table, std::initializer_list<column> columns) {
|
||||
transition_to(state_t::QUERY_TABLE);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(table) + " ");
|
||||
// auto cols =
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::select(std::initializer_list<std::string> column_names) {
|
||||
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::SELECT) + " ");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::from(const std::string &table, const std::string &as) {
|
||||
transition_to(state_t::QUERY_FROM);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::TABLE) + " " + (as.empty() ? "" : as + " "));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string query_builder::compile() {
|
||||
std::string result;
|
||||
for (const auto &part : query_parts_) {
|
||||
result.append(part);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_builder::transition_to(query_builder::state_t next)
|
||||
{
|
||||
if (transitions_[state_].count(next) == 0) {
|
||||
throw std::logic_error("invalid next state " + state_strings_[next]);
|
||||
}
|
||||
state_ = next;
|
||||
}
|
||||
|
||||
void query_builder::initialize(query_builder::command_t cmd, query_builder::state_t state)
|
||||
{
|
||||
command_ = cmd;
|
||||
state_ = state;
|
||||
query_parts_.clear();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user