started query builder
This commit is contained in:
parent
fbdf6116ff
commit
9e2d1358bb
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue