started query builder

This commit is contained in:
Sascha Kuehl 2023-11-01 19:46:53 +01:00
parent fbdf6116ff
commit 9e2d1358bb
16 changed files with 866 additions and 34 deletions

36
.gitignore vendored
View File

@ -1,34 +1,2 @@
# ---> C++
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
.idea
cmake-build-debug

11
CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.26)
project(query)
set(CMAKE_CXX_STANDARD 17)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_subdirectory(src)
add_executable(query main.cpp)
target_link_libraries(query matador)

View File

@ -0,0 +1,31 @@
#ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP
#include "matador/sql/types.hpp"
#include "matador/utils/field_attributes.hpp"
#include <any>
namespace matador::sql {
class column {
public:
template<typename Type>
explicit column(std::string name, utils::field_attributes attr = utils::null_attributes)
: column(std::move(name), data_type_traits<Type>::data_type(), attr)
{}
column(std::string name, data_type_t type, utils::field_attributes attr = utils::null_attributes);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] data_type_t type() const;
private:
std::string name_;
utils::field_attributes attributes_;
data_type_t type_{};
std::any value_;
};
}
#endif //QUERY_COLUMN_HPP

View File

@ -0,0 +1,152 @@
#ifndef QUERY_DIALECT_HPP
#define QUERY_DIALECT_HPP
#include <cstdint>
#include <string>
#include <unordered_map>
namespace matador::sql {
class dialect
{
public:
enum class token_t : uint8_t
{
CREATE = 0,
DROP,
REMOVE,
INSERT,
UPDATE,
SELECT,
TABLE,
VALUES,
VALUE,
COLUMNS,
COLUMN,
FROM,
INTO,
WHERE,
AND,
OR,
LIKE,
ORDER_BY,
GROUP_BY,
ASC,
DESC,
TOP,
AS,
OFFSET,
DISTINCT,
CONDITION,
SET,
NOT_NULL,
PRIMARY_KEY,
BEGIN,
COMMIT,
ROLLBACK,
START_QUOTE,
END_QUOTE,
STRING_QUOTE,
NONE
};
/**
* Holding enums concerning escaping identifiers
*/
enum class escape_identifier_t : uint8_t {
ESCAPE_BOTH_SAME, /**< The escape quotes are the same */
ESCAPE_CLOSING_BRACKET /**< The escape quotes differ; escape the closing one */
};
public:
const std::string& token_at(token_t token) const;
/**
* Prepare sql dialect identifier for execution
* and escape quotes and quote the identifier
* string
*
* @param str The identifier string to be prepared
* @return The prepared string
*/
std::string prepare_identifier(const std::string &str) const;
/**
* Prepare string literal
*
* @param str String literal to be prepared
*/
std::string prepare_literal(const std::string &str) const;
/**
* Wrap identifier quotes around a sql identifier keyword
*
* @param str Identifier to put quotes around
*/
void quote_identifier(std::string &str) const;
/**
* Escape identifier quotes inside identifiers.
*
* @param str Identifier to be escaped
*/
void escape_quotes_in_identifier(std::string &str) const;
/**
* Escape quotes in string literals
*
* @param str String literal to be escaped
*/
void escape_quotes_in_literals(std::string &str) const;
/**
* Returns how the identifier quotes should be
* escaped.
*
* @return How the identifier quotes should be escaped
*/
virtual escape_identifier_t identifier_escape_type() const;
private:
using token_to_string_map = std::unordered_map<token_t, std::string>;
token_to_string_map tokens_ {
{token_t::CREATE, "CREATE"},
{token_t::DROP, "DROP"},
{token_t::REMOVE, "DELETE"},
{token_t::INSERT, "INSERT"},
{token_t::INTO, "INTO"},
{token_t::VALUES, "VALUES"},
{token_t::UPDATE, "UPDATE"},
{token_t::SELECT, "SELECT"},
{token_t::COLUMNS, "COLUMNS"},
{token_t::COLUMN, "COLUMN"},
{token_t::FROM, "FROM"},
{token_t::WHERE, "WHERE"},
{token_t::AND, "AND"},
{token_t::OR, "OR"},
{token_t::LIKE, "LIKE"},
{token_t::ORDER_BY, "ORDER BY"},
{token_t::GROUP_BY, "GROUP BY"},
{token_t::ASC, "ASC"},
{token_t::DESC, "DESC"},
{token_t::TOP, "LIMIT"},
{token_t::AS, "AS"},
{token_t::OFFSET, "OFFSET"},
{token_t::DISTINCT, "DISTINCT"},
{token_t::SET, "SET"},
{token_t::NOT_NULL, "NOT NULL"},
{token_t::PRIMARY_KEY, "PRIMARY KEY"},
{token_t::BEGIN, "BEGIN TRANSACTION"},
{token_t::COMMIT, "COMMIT TRANSACTION"},
{token_t::ROLLBACK, "ROLLBACK TRANSACTION"},
{token_t::START_QUOTE, "\""},
{token_t::END_QUOTE, "\""},
{token_t::STRING_QUOTE, "'"},
{token_t::NONE, ""}
};
};
}
#endif //QUERY_DIALECT_HPP

View File

@ -0,0 +1,84 @@
#ifndef QUERY_QUERY_BUILDER_HPP
#define QUERY_QUERY_BUILDER_HPP
#include "matador/sql/column.hpp"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace matador::sql {
class dialect;
class query_builder
{
private:
enum class state_t {
QUERY_INIT,
QUERY_CREATE,
QUERY_TABLE,
QUERY_DROP,
QUERY_SELECT,
QUERY_INSERT,
QUERY_UPDATE,
QUERY_DELETE,
QUERY_SET,
QUERY_FROM,
QUERY_INTO,
QUERY_WHERE,
QUERY_VALUES,
QUERY_ORDER_BY,
QUERY_ORDER_DIRECTION,
QUERY_GROUP_BY,
QUERY_LIMIT,
QUERY_FINISH
};
enum class command_t {
UNKNOWN, /**< Unknown query command */
CREATE, /**< Create query command */
DROP, /**< Drop query command */
SELECT, /**< Select query command */
INSERT, /**< Insert query command */
UPDATE, /**< Update query command */
REMOVE /**< Remove query command */
};
public:
explicit query_builder(const dialect &d);
query_builder& create();
query_builder& table(const std::string &table, std::initializer_list<column> columns);
query_builder& select(std::initializer_list<std::string> column_names);
query_builder& from(const std::string &table, const std::string &as = "");
std::string compile();
private:
void transition_to(state_t next);
void initialize(command_t cmd, state_t state);
private:
const dialect &dialect_;
command_t command_{command_t::UNKNOWN};
state_t state_{state_t::QUERY_INIT};
std::vector<std::string> query_parts_;
using query_state_set = std::unordered_set<state_t>;
using query_state_transition_map = std::unordered_map<state_t, query_state_set>;
using query_state_to_string_map = std::unordered_map<state_t, std::string>;
using query_command_to_string_map = std::unordered_map<command_t, std::string>;
static query_state_transition_map transitions_;
static query_state_to_string_map state_strings_;
static query_command_to_string_map command_strings_;
};
}
#endif //QUERY_QUERY_BUILDER_HPP

View File

@ -0,0 +1,215 @@
#ifndef QUERY_TYPES_HPP
#define QUERY_TYPES_HPP
#include <cstdint>
#include <string>
namespace matador::sql {
/**
* @brief Enumeration type of all supported builtin data types
*/
enum class data_type_t : uint8_t {
type_char = 0, /*!< Data type char */
type_short, /*!< Data type short */
type_int, /*!< Data type int */
type_long, /*!< Data type long */
type_long_long, /*!< Data type long long */
type_unsigned_char, /*!< Data type unsigned char */
type_unsigned_short, /*!< Data type unsigned short */
type_unsigned_int, /*!< Data type unsigned int */
type_unsigned_long, /*!< Data type unsigned long */
type_unsigned_long_long, /*!< Data type unsigned long long */
type_float, /*!< Data type float */
type_double, /*!< Data type double */
type_bool, /*!< Data type bool */
type_char_pointer, /*!< Data type character pointer */
type_varchar, /*!< Data type varchar */
type_text, /*!< Data type text */
type_date, /*!< Data type date */
type_time, /*!< Data type time */
type_blob, /*!< Data type blob */
type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */
};
/**
* @brief Enumeration of database data types
*/
enum struct database_type_t : uint8_t {
type_char = 0, /*!< Data type char */
type_float, /*!< Data type float */
type_double, /*!< Data type double */
type_smallint, /*!< Data type small int */
type_int, /*!< Data type integer */
type_bigint, /*!< Data type big integer */
type_bool, /*!< Data type bool */
type_char_pointer, /*!< Data type character pointer */
type_varchar, /*!< Data type varchar */
type_text, /*!< Data type text */
type_date, /*!< Data type date */
type_time, /*!< Data type time */
type_blob, /*!< Data type blob */
type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */
};
/**
* @tparam T The type of the traits
* @brief Type traits for database types
*
* This class is used to determine and
* provide the correct size information
* for a data type
*/
template < class T >
struct data_type_traits;
/// @cond MATADOR_DEV
template <> struct data_type_traits<char>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_char; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
inline static unsigned long size() { return sizeof(char); }
inline static const char* name() { return "char"; }
};
template <> struct data_type_traits<short>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_smallint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_short; }
inline static unsigned long size() { return sizeof(short); }
inline static const char* name() { return "short"; }
};
template <> struct data_type_traits<int>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_int; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
inline static unsigned long size() { return sizeof(int); }
inline static const char* name() { return "int"; }
};
template <> struct data_type_traits<long>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long; }
inline static unsigned long size() { return sizeof(long); }
inline static const char* name() { return "long"; }
};
template <> struct data_type_traits<long long>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long_long; }
inline static unsigned long size() { return sizeof(long long); }
inline static const char* name() { return "long long"; }
};
template <> struct data_type_traits<unsigned char>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_char; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_char; }
inline static unsigned long size() { return sizeof(unsigned char); }
inline static const char* name() { return "unsigned char"; }
};
template <> struct data_type_traits<unsigned short>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_smallint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_short; }
inline static unsigned long size() { return sizeof(unsigned short); }
inline static const char* name() { return "unsigned short"; }
};
template <> struct data_type_traits<unsigned int>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_int; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_int; }
inline static unsigned long size() { return sizeof(unsigned int); }
inline static const char* name() { return "unsigned int"; }
};
template <> struct data_type_traits<unsigned long>
{
inline static database_type_t type(std::size_t /*size*/ = 0) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/ = 0) { return data_type_t::type_unsigned_long; }
inline static unsigned long size() { return sizeof(unsigned long); }
inline static const char* name() { return "unsigned long"; }
};
template <> struct data_type_traits<unsigned long long>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_long_long; }
inline static unsigned long size() { return sizeof(unsigned long long); }
inline static const char* name() { return "unsigned long long"; }
};
template <> struct data_type_traits<bool>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bool; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_bool; }
inline static unsigned long size() { return sizeof(bool); }
inline static const char* name() { return "bool"; }
};
template <> struct data_type_traits<float>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_float; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_float; }
inline static unsigned long size() { return sizeof(float); }
inline static const char* name() { return "float"; }
};
template <> struct data_type_traits<double>
{
inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_double; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_double; }
inline static unsigned long size() { return sizeof(double); }
inline static const char* name() { return "double"; }
};
template <> struct data_type_traits<const char*>
{
inline static database_type_t type(std::size_t size) { return size == 0 ? database_type_t::type_text : database_type_t::type_varchar; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
inline static unsigned long size() { return sizeof(const char*); }
inline static const char* name() { return "const char*"; }
};
template <> struct data_type_traits<char*>
{
inline static database_type_t type(std::size_t size) { return size == 0 ? database_type_t::type_text : database_type_t::type_varchar; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
inline static unsigned long size() { return sizeof(char*); }
inline static const char* name() { return "char*"; }
};
template <> struct data_type_traits<std::string>
{
inline static database_type_t type(std::size_t size) { return size == 0 ? database_type_t::type_text : database_type_t::type_varchar; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
inline static unsigned long size() { return 1023; }
inline static const char* name() { return "std::string"; }
};
//template <> struct data_type_traits<matador::date>
//{
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_date; }
// inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_date; }
// inline static unsigned long size() { return 255; }
// inline static const char* name() { return "matador::date"; }
//};
//
//template <> struct data_type_traits<matador::time>
//{
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_time; }
// inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_time; }
// inline static unsigned long size() { return 255; }
// inline static const char* name() { return "matador::time"; }
//};
/// @endcond
}
#endif //QUERY_TYPES_HPP

View File

@ -0,0 +1,35 @@
#ifndef QUERY_CONSTRAINTS_HPP
#define QUERY_CONSTRAINTS_HPP
namespace matador::utils {
enum class constraints : unsigned char {
NONE = 0,
NOT_NULL = 1 << 0,
INDEX = 1 << 1,
UNIQUE = 1 << 2,
PRIMARY_KEY = 1 << 3,
FOREIGN_KEY = 1 << 4,
DEFAULT = 1 << 5,
UNIQUE_NOT_NULL = UNIQUE | NOT_NULL
};
//static std::unordered_map<constraints, std::string> constraints_to_name_map();
inline constraints operator|(constraints a, constraints b)
{
return static_cast<constraints>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b));
}
inline constraints operator&(constraints a, constraints b)
{
return static_cast<constraints>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b));
}
inline bool is_constraint_set(constraints source, constraints needle)
{
return static_cast<int>(source & needle) > 0;
}
}
#endif //QUERY_CONSTRAINTS_HPP

View File

@ -0,0 +1,34 @@
#ifndef QUERY_FIELD_ATTRIBUTES_HPP
#define QUERY_FIELD_ATTRIBUTES_HPP
#include "constraints.hpp"
#include <cstdlib>
namespace matador::utils {
class field_attributes
{
public:
field_attributes() = default;
field_attributes(size_t size); // NOLINT(*-explicit-constructor)
field_attributes(constraints options); // NOLINT(*-explicit-constructor)
field_attributes(size_t size, constraints options);
field_attributes(const field_attributes &x) = default;
field_attributes& operator=(const field_attributes &x) = default;
field_attributes(field_attributes &&x) = default;
field_attributes& operator=(field_attributes &&x) = default;
~field_attributes() = default;
[[nodiscard]] size_t size() const;
[[nodiscard]] constraints options() const;
private:
size_t size_ = 0;
constraints options_ = constraints::NONE;
};
const field_attributes null_attributes {};
}
#endif //QUERY_FIELD_ATTRIBUTES_HPP

View File

@ -0,0 +1,19 @@
#ifndef QUERY_STRING_HPP
#define QUERY_STRING_HPP
#include <string>
namespace matador::utils {
/**
* Replaces all occurrences of string from in given string
* with string to.
*
* @param in Source string where the replacement takes place
* @param from The string to be replaced
* @param to The new string
*/
void replace_all(std::string &in, const std::string &from, const std::string &to);
}
#endif //QUERY_STRING_HPP

21
main.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <matador/sql/dialect.hpp>
#include <matador/sql/query_builder.hpp>
#include <matador/sql/types.hpp>
#include <iostream>
using namespace matador;
int main() {
sql::dialect d;
sql::query_builder query(d);
query.create().table("person", {
{ "id", sql::data_type_traits<unsigned long>::builtin_type() },
{ "name", sql::data_type_traits<std::string>::builtin_type(255), 255 },
{ "id", sql::data_type_traits<unsigned long>::builtin_type() }
}).compile();
return 0;
}

22
src/CMakeLists.txt Normal file
View File

@ -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)

23
src/sql/column.cpp Normal file
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
src/sql/dialect.cpp Normal file
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
src/sql/query_builder.cpp Normal file
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();
}
}

View File

@ -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_;
}
}

17
src/utils/string.cpp Normal file
View File

@ -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'
}
}
}