started query builder
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user