started query builder

This commit is contained in:
2023-11-01 19:55:09 +01:00
parent fbdf6116ff
commit 9e2d1358bb
16 changed files with 866 additions and 34 deletions
+23
View File
@@ -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_;
}
}
+53
View File
@@ -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;
}
}
+119
View File
@@ -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();
}
}