started query builder
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
set(SQL_SOURCES
|
||||
sql/dialect.cpp
|
||||
sql/query_builder.cpp
|
||||
sql/column.cpp)
|
||||
|
||||
set(SQL_HEADER
|
||||
../include/matador/sql/dialect.hpp
|
||||
../include/matador/sql/query_builder.hpp
|
||||
../include/matador/sql/column.hpp
|
||||
../include/matador/sql/types.hpp)
|
||||
|
||||
set(UTILS_HEADER
|
||||
../include/matador/utils/field_attributes.hpp
|
||||
../include/matador/utils/string.hpp
|
||||
../include/matador/utils/constraints.hpp)
|
||||
|
||||
set(UTILS_SOURCES
|
||||
utils/field_attributes.cpp
|
||||
utils/string.cpp)
|
||||
|
||||
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
||||
set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX)
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
field_attributes::field_attributes(size_t size)
|
||||
: size_(size)
|
||||
{}
|
||||
|
||||
field_attributes::field_attributes(constraints options)
|
||||
: options_(options)
|
||||
{}
|
||||
|
||||
field_attributes::field_attributes(size_t size, constraints options)
|
||||
: size_(size)
|
||||
, options_(options)
|
||||
{}
|
||||
|
||||
size_t field_attributes::size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
constraints field_attributes::options() const
|
||||
{
|
||||
return options_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
void replace_all(std::string &in, const std::string &from, const std::string &to)
|
||||
{
|
||||
if(from.empty()) {
|
||||
return;
|
||||
}
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = in.find(from, start_pos)) != std::string::npos) {
|
||||
in.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user