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
+31
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
+152
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
+84
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
+215
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