added column generator and tests
This commit is contained in:
parent
ae236746ad
commit
30f2126225
|
|
@ -4,13 +4,20 @@ project(query)
|
|||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
find_package(ODBC REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
find_package(PostgreSQL REQUIRED)
|
||||
find_package(MySQL REQUIRED)
|
||||
|
||||
message(STATUS "Found SQLite3 ${SQLite3_VERSION}")
|
||||
message(STATUS "Adding SQLite3 include directory: ${SQLite3_INCLUDE_DIRS}")
|
||||
message(STATUS "Adding SQLite3 libs: ${SQLite3_LIBRARIES}")
|
||||
|
||||
message(STATUS "Adding MySQL include directory: ${MYSQL_INCLUDE_DIR}")
|
||||
message(STATUS "Adding MySQL libs: ${MYSQL_LIBRARY}")
|
||||
|
||||
message(STATUS "Common flags ${CMAKE_CXX_FLAGS}")
|
||||
message(STATUS "Debug flags ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
message(STATUS "Relase flags ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
# - Find mysqlclient
|
||||
# Find the native MySQL includes and library
|
||||
#
|
||||
# MYSQL_INCLUDE_DIR - where to find mysql.h, etc.
|
||||
# MYSQL_LIBRARY - List of libraries when using MySQL.
|
||||
# MYSQL_FOUND - True if MySQL found.
|
||||
|
||||
IF (MYSQL_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
SET(MYSQL_FIND_QUIETLY TRUE)
|
||||
ENDIF (MYSQL_INCLUDE_DIR)
|
||||
|
||||
if(WIN32)
|
||||
find_path(MYSQL_INCLUDE_DIR mysql.h
|
||||
PATHS
|
||||
$ENV{MYSQL_INCLUDE_DIR}
|
||||
$ENV{MYSQL_DIR}/include
|
||||
$ENV{ProgramFiles}/MySQL/*/include
|
||||
$ENV{SystemDrive}/MySQL/*/include
|
||||
$ENV{ProgramW6432}/MySQL/*/include
|
||||
$ENV{ProgramFiles}/MariaDB/*/include
|
||||
$ENV{SystemDrive}/MariaDB/*/include
|
||||
$ENV{ProgramW6432}/MariaDB/*/include
|
||||
)
|
||||
else(WIN32)
|
||||
find_path(MYSQL_INCLUDE_DIR mysql.h
|
||||
PATHS
|
||||
$ENV{MYSQL_DIR}/include
|
||||
$ENV{MYSQL_INCLUDE_DIR}
|
||||
/usr/local/mysql/include
|
||||
/opt/mysql/mysql/include
|
||||
PATH_SUFFIXES
|
||||
mysql
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
if(WIN32)
|
||||
if (${CMAKE_BUILD_TYPE})
|
||||
STRING(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_TOLOWER)
|
||||
endif()
|
||||
|
||||
# path suffix for debug/release mode
|
||||
# binary_dist: mysql binary distribution
|
||||
# build_dist: custom build
|
||||
if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug")
|
||||
SET(binary_dist debug)
|
||||
SET(build_dist Debug)
|
||||
else(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug")
|
||||
ADD_DEFINITIONS(-DDBUG_OFF)
|
||||
SET(binary_dist opt)
|
||||
SET(build_dist Release)
|
||||
endif(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug")
|
||||
|
||||
FIND_LIBRARY(MYSQL_LIBRARY NAMES libmysql libmariadb
|
||||
PATHS
|
||||
$ENV{MYSQL_DIR}/lib
|
||||
# $ENV{MYSQL_DIR}/lib/${binary_dist}
|
||||
# $ENV{MYSQL_DIR}/libmysql/${build_dist}
|
||||
# $ENV{MYSQL_DIR}/client/${build_dist}
|
||||
# $ENV{ProgramFiles}/MySQL/*/lib/${binary_dist}
|
||||
$ENV{ProgramFiles}/MySQL/*/lib
|
||||
$ENV{SystemDrive}/MySQL/*/lib
|
||||
$ENV{ProgramW6432}/MySQL/*/lib
|
||||
$ENV{ProgramFiles}/MariaDB/*/lib
|
||||
$ENV{SystemDrive}/MariaDB/*/lib
|
||||
$ENV{ProgramW6432}/MariaDB/*/lib
|
||||
# $ENV{SystemDrive}/MySQL/*/lib/${binary_dist}
|
||||
# $ENV{ProgramFiles}/MariaDB/*/lib/${binary_dist}
|
||||
# $ENV{SystemDrive}/MariaDB/*/lib/${binary_dist}
|
||||
# $ENV{MYSQL_DIR}/lib/opt
|
||||
# $ENV{MYSQL_DIR}/client/release
|
||||
# $ENV{ProgramFiles}/MySQL/*/lib/opt
|
||||
# $ENV{SystemDrive}/MySQL/*/lib/opt
|
||||
# $ENV{ProgramW6432}/MySQL/*/lib
|
||||
# $ENV{ProgramFiles}/MariaDB/*/lib/opt
|
||||
# $ENV{SystemDrive}/MariaDB/*/lib/opt
|
||||
# $ENV{ProgramW6432}/MariaDB/*/lib
|
||||
)
|
||||
else(WIN32)
|
||||
find_library(MYSQL_LIBRARY NAMES libmysql
|
||||
PATHS
|
||||
$ENV{MYSQL_DIR}/libmysql_r/.libs
|
||||
$ENV{MYSQL_DIR}/lib
|
||||
$ENV{MYSQL_DIR}/lib/mysql
|
||||
/usr/local/mysql/lib
|
||||
/opt/mysql/mysql/lib
|
||||
PATH_SUFFIXES
|
||||
mysql
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
if(WIN32)
|
||||
else(WIN32)
|
||||
set(MYSQL_LIB_PATHS
|
||||
$ENV{MYSQL_DIR}/libmysql_r/.libs
|
||||
$ENV{MYSQL_DIR}/lib
|
||||
$ENV{MYSQL_DIR}/lib/mysql
|
||||
/usr/local/mysql/lib
|
||||
/opt/mysql/mysql/lib
|
||||
PATH_SUFFIXES
|
||||
mysql
|
||||
)
|
||||
find_library(MYSQL_LIBRARY NAMES mysqlclient
|
||||
PATHS
|
||||
${MYSQL_LIB_PATHS}
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
IF (MYSQL_INCLUDE_DIR)
|
||||
MESSAGE(STATUS "MariaDB include ${MYSQL_INCLUDE_DIR}")
|
||||
ELSE (MYSQL_INCLUDE_DIR)
|
||||
MESSAGE(STATUS "MariaDB include dir not found")
|
||||
ENDIF (MYSQL_INCLUDE_DIR)
|
||||
|
||||
IF (MYSQL_LIBRARY)
|
||||
MESSAGE(STATUS "MariaDB libs ${MYSQL_LIBRARY}")
|
||||
ELSE (MYSQL_LIBRARY)
|
||||
MESSAGE(STATUS "MariaDB libs dir not found")
|
||||
ENDIF (MYSQL_LIBRARY)
|
||||
|
||||
|
||||
IF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
|
||||
SET(MYSQL_FOUND TRUE)
|
||||
ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
|
||||
SET(MYSQL_FOUND FALSE)
|
||||
SET(MYSQL_LIBRARY)
|
||||
ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY)
|
||||
|
||||
MARK_AS_ADVANCED(MYSQL_LIBRARY MYSQL_INCLUDE_DIR)
|
||||
|
|
@ -17,7 +17,11 @@ 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::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
|
||||
{}
|
||||
template<typename Type>
|
||||
column(std::string name, const Type &, utils::field_attributes attr = utils::null_attributes)
|
||||
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
|
||||
{}
|
||||
column(std::string name, data_type_t type, utils::field_attributes attr = utils::null_attributes);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef QUERY_COLUMN_GENERATOR_HPP
|
||||
#define QUERY_COLUMN_GENERATOR_HPP
|
||||
|
||||
#include "matador/sql/column.hpp"
|
||||
#include "matador/sql/types.hpp"
|
||||
|
||||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace matador::utils {
|
||||
class identifiable;
|
||||
enum class cascade_type;
|
||||
}
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
class column_generator
|
||||
{
|
||||
private:
|
||||
explicit column_generator(std::vector<column> &columns);
|
||||
|
||||
public:
|
||||
~column_generator() = default;
|
||||
|
||||
template < class Type >
|
||||
static std::vector<column> generate()
|
||||
{
|
||||
std::vector<column> columns;
|
||||
column_generator gen(columns);
|
||||
Type obj;
|
||||
matador::utils::access::process(gen, obj);
|
||||
return std::move(columns);
|
||||
}
|
||||
|
||||
template < class V >
|
||||
void on_primary_key(const char *, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0);
|
||||
void on_primary_key(const char *id, std::string &pk, size_t size);
|
||||
void on_revision(const char *id, unsigned long long &/*rev*/);
|
||||
|
||||
template<typename Type>
|
||||
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
|
||||
|
||||
void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type);
|
||||
void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type);
|
||||
// void on_has_many(const char *, abstract_container &, const char *, const char *, cascade_type) {}
|
||||
// void on_has_many(const char *, abstract_container &, cascade_type) {}
|
||||
|
||||
private:
|
||||
size_t index_ = 0;
|
||||
std::vector<column> &columns_;
|
||||
|
||||
// typed_column_identifier_serializer column_identifier_serializer_;
|
||||
};
|
||||
|
||||
template<typename V>
|
||||
void column_generator::on_primary_key(const char *id, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type*)
|
||||
{
|
||||
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void column_generator::on_attribute(const char *id, Type &x, const utils::field_attributes &attr)
|
||||
{
|
||||
columns_.emplace_back(id, x, attr);
|
||||
}
|
||||
|
||||
}
|
||||
#endif //QUERY_COLUMN_GENERATOR_HPP
|
||||
|
|
@ -100,6 +100,7 @@ public:
|
|||
query_builder& remove();
|
||||
|
||||
query_builder& table(const std::string &table, std::initializer_list<column> columns);
|
||||
query_builder& table(const std::string &table, const std::vector<column> &columns);
|
||||
query_builder& table(const std::string &table);
|
||||
query_builder& into(const std::string &table, std::initializer_list<std::string> column_names);
|
||||
query_builder& values(std::initializer_list<any_type> values);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define QUERY_QUERY_INTERMEDIATES_HPP
|
||||
|
||||
#include "matador/sql/column.hpp"
|
||||
#include "matador/sql/column_generator.hpp"
|
||||
#include "matador/sql/key_value_pair.hpp"
|
||||
#include "matador/sql/query_result.hpp"
|
||||
#include "matador/sql/record.hpp"
|
||||
|
|
@ -136,6 +137,11 @@ public:
|
|||
using query_intermediate::query_intermediate;
|
||||
|
||||
query_execute_finish table(const std::string &table, std::initializer_list<column> columns);
|
||||
template<class Type>
|
||||
query_execute_finish table(const std::string &table)
|
||||
{
|
||||
return {db(), query().table(table, column_generator::generate<Type>())};
|
||||
}
|
||||
};
|
||||
|
||||
class query_drop_intermediate : query_intermediate
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef QUERY_ACCESS_HPP
|
||||
#define QUERY_ACCESS_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
enum class cascade_type;
|
||||
|
||||
template < class Type, template < class ... > class ContainerType >
|
||||
class container;
|
||||
|
||||
class field_attributes;
|
||||
|
||||
namespace access {
|
||||
template<class Operator, class Type>
|
||||
void process(Operator &op, Type &object) {
|
||||
object.process(op);
|
||||
}
|
||||
|
||||
template<class Operator, class Type>
|
||||
void process(Operator &op, const Type &object) {
|
||||
const_cast<Type &>(object).process(op);
|
||||
}
|
||||
|
||||
template< class Operator, class Type >
|
||||
void primary_key(Operator &op, const char *id, Type &value) {
|
||||
op.on_primary_key(id, value);
|
||||
}
|
||||
|
||||
template< class Operator >
|
||||
void primary_key(Operator &op, const char *id, std::string &value, size_t size ) {
|
||||
op.on_primary_key(id, value, size);
|
||||
}
|
||||
|
||||
template<class Operator>
|
||||
void revision(Operator &op, const char *id, unsigned long long &value) {
|
||||
op.on_revision(id, value);
|
||||
}
|
||||
|
||||
template<class Operator, class Type>
|
||||
void attribute(Operator &op, const char *id, Type &value, const field_attributes &attr) {
|
||||
op.on_attribute(id, value, attr);
|
||||
}
|
||||
|
||||
template<class Operator, class Type>
|
||||
void attribute(Operator &op, const char *id, Type &value) {
|
||||
op.on_attribute(id, value);
|
||||
}
|
||||
|
||||
template<class Operator, class Type>
|
||||
void has_one(Operator &op, const char *id, Type &value, cascade_type cascade) {
|
||||
op.on_has_one(id, value, cascade);
|
||||
}
|
||||
|
||||
template<class Operator, class Type>
|
||||
void belongs_to(Operator &op, const char *id, Type &value, cascade_type cascade) {
|
||||
op.on_belongs_to(id, value, cascade);
|
||||
}
|
||||
|
||||
template<class Operator, class Type, template<class ...> class ContainerType>
|
||||
void has_many(Operator &op, const char *id, container<Type, ContainerType> &container, cascade_type cascade) {
|
||||
op.on_has_many(id, container, cascade);
|
||||
}
|
||||
|
||||
template<class Operator, class Type, template<class ...> class ContainerType>
|
||||
void has_many(Operator &op, const char *id, container<Type, ContainerType> &container, const char *left_column, const char *right_column, cascade_type cascade) {
|
||||
op.on_has_many(id, container, left_column, right_column, cascade);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_ACCESS_HPP
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef QUERY_CASCADE_TYPE_HPP
|
||||
#define QUERY_CASCADE_TYPE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
/**
|
||||
* @brief Cascade types for database actions
|
||||
*/
|
||||
enum class cascade_type : uint8_t
|
||||
{
|
||||
NONE = 0, /**< Cascade type none */
|
||||
REMOVE = 1, /**< Cascade type remove */
|
||||
UPDATE = 2, /**< Cascade type update */
|
||||
INSERT = 4, /**< Cascade type insert */
|
||||
ALL = REMOVE | UPDATE | INSERT /**< Cascade type all */
|
||||
};
|
||||
|
||||
inline cascade_type operator~ (cascade_type a) { return (cascade_type)~(int)a; }
|
||||
inline cascade_type operator| (cascade_type a, cascade_type b) { return (cascade_type)((int)a | (int)b); }
|
||||
inline cascade_type operator& (cascade_type a, cascade_type b) { return (cascade_type)((int)a & (int)b); }
|
||||
inline cascade_type operator^ (cascade_type a, cascade_type b) { return (cascade_type)((int)a ^ (int)b); }
|
||||
inline cascade_type& operator|= (cascade_type& a, cascade_type b) { return (cascade_type&)((int&)a |= (int)b); }
|
||||
inline cascade_type& operator&= (cascade_type& a, cascade_type b) { return (cascade_type&)((int&)a &= (int)b); }
|
||||
inline cascade_type& operator^= (cascade_type& a, cascade_type b) { return (cascade_type&)((int&)a ^= (int)b); }
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_CASCADE_TYPE_HPP
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef QUERY_IDENTIFIABLE_HPP
|
||||
#define QUERY_IDENTIFIABLE_HPP
|
||||
|
||||
#include "matador/utils/identifier.hpp"
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
/**
|
||||
* Base class for all pointer object
|
||||
* which can contain an identifiable
|
||||
*/
|
||||
class identifiable
|
||||
{
|
||||
public:
|
||||
virtual ~identifiable() = default;
|
||||
|
||||
/**
|
||||
* Resets the object_holder with the given
|
||||
* identifier. If the type of identifier differs
|
||||
* from internal type an exception is thrown
|
||||
*
|
||||
* @param id The identifier to set
|
||||
*/
|
||||
virtual void reset(const identifier &id) = 0;
|
||||
|
||||
/**
|
||||
* Returns true if serializable has a primary key
|
||||
*
|
||||
* @return true if serializable has a primary key
|
||||
*/
|
||||
[[nodiscard]] virtual bool has_primary_key() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the primary key of the foreign serializable
|
||||
*
|
||||
* @return The primary key of the foreign serializable
|
||||
*/
|
||||
[[nodiscard]] virtual const identifier& primary_key() const = 0;
|
||||
virtual identifier& primary_key() = 0;
|
||||
|
||||
/**
|
||||
* Creates a new identifier object.
|
||||
*
|
||||
* @return Returns a new identifier object.
|
||||
*/
|
||||
[[nodiscard]] virtual identifier create_identifier() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_IDENTIFIABLE_HPP
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
#ifndef QUERY_IDENTIFIER_HPP
|
||||
#define QUERY_IDENTIFIER_HPP
|
||||
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <type_traits>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
struct null_type_t {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
enum class identifier_type_t : unsigned int {
|
||||
INTEGRAL_TYPE,
|
||||
STRING_TYPE,
|
||||
NULL_TYPE
|
||||
};
|
||||
|
||||
template<typename Type, class Enabled = void>
|
||||
struct identifier_type_traits;
|
||||
|
||||
template<typename Type>
|
||||
struct identifier_type_traits<Type, typename std::enable_if<std::is_integral<Type>::value>::type> {
|
||||
static identifier_type_t type() { return identifier_type_t::INTEGRAL_TYPE; }
|
||||
static std::string type_string() { return "integral"; }
|
||||
static bool is_valid(Type value) { return value > 0; }
|
||||
static std::string to_string(Type value) { return std::to_string(value); }
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct identifier_type_traits<Type, typename std::enable_if<std::is_same<Type, std::string>::value>::type> {
|
||||
static identifier_type_t type() { return identifier_type_t::STRING_TYPE; }
|
||||
static std::string type_string() { return "string"; }
|
||||
static bool is_valid(const Type &value) { return !value.empty(); }
|
||||
static std::string to_string(Type value) { return value; }
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct identifier_type_traits<Type, typename std::enable_if<std::is_same<Type, null_type_t>::value>::type> {
|
||||
static identifier_type_t type() { return identifier_type_t::NULL_TYPE; }
|
||||
static std::string type_string() { return "null"; }
|
||||
static bool is_valid() { return false; }
|
||||
static std::string to_string() { return "null_pk"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class identifier_serializer
|
||||
{
|
||||
public:
|
||||
virtual ~identifier_serializer() = default;
|
||||
|
||||
virtual void serialize(short &, const field_attributes &) = 0;
|
||||
virtual void serialize(int &, const field_attributes &) = 0;
|
||||
virtual void serialize(long &, const field_attributes &) = 0;
|
||||
virtual void serialize(long long &, const field_attributes &) = 0;
|
||||
virtual void serialize(unsigned short &, const field_attributes &) = 0;
|
||||
virtual void serialize(unsigned int &, const field_attributes &) = 0;
|
||||
virtual void serialize(unsigned long &, const field_attributes &) = 0;
|
||||
virtual void serialize(unsigned long long &, const field_attributes &) = 0;
|
||||
virtual void serialize(std::string &, const field_attributes &) = 0;
|
||||
virtual void serialize(null_type_t &, const field_attributes &) = 0;
|
||||
};
|
||||
|
||||
class identifier
|
||||
{
|
||||
private:
|
||||
struct base
|
||||
{
|
||||
explicit base(const std::type_index &ti, detail::identifier_type_t id_type);
|
||||
base(const base &x) = delete;
|
||||
base &operator=(const base &x) = delete;
|
||||
base(base &&x) = delete;
|
||||
base &operator=(base &&x) = delete;
|
||||
virtual ~base() = default;
|
||||
|
||||
template<typename Type>
|
||||
bool is_similar_type() const
|
||||
{
|
||||
return identifier_type_ == detail::identifier_type_traits<Type>::type();
|
||||
}
|
||||
|
||||
bool is_similar_type(const base &x) const;
|
||||
detail::identifier_type_t type() const;
|
||||
|
||||
virtual base *copy() const = 0;
|
||||
virtual bool equal_to(const base &x) const = 0;
|
||||
virtual bool less(const base &x) const = 0;
|
||||
virtual bool is_valid() const = 0;
|
||||
virtual void serialize(identifier_serializer &s) = 0;
|
||||
virtual std::string str() const = 0;
|
||||
virtual size_t hash() const = 0;
|
||||
|
||||
std::type_index type_index_;
|
||||
detail::identifier_type_t identifier_type_;
|
||||
};
|
||||
|
||||
template<class IdType>
|
||||
struct pk : public base
|
||||
{
|
||||
using self = pk<IdType>;
|
||||
|
||||
explicit pk(const IdType &id, size_t size = 0) : base(std::type_index(typeid(IdType)), detail::identifier_type_traits<IdType>::type())
|
||||
, id_(id)
|
||||
, size_(size) {}
|
||||
|
||||
base *copy() const final {
|
||||
return new self(id_, size_);
|
||||
}
|
||||
|
||||
bool equal_to(const base &x) const final {
|
||||
return static_cast<const pk<IdType> &>(x).id_ == id_;
|
||||
}
|
||||
|
||||
bool less(const base &x) const final {
|
||||
return static_cast<const pk<IdType> &>(x).id_ < id_;
|
||||
}
|
||||
|
||||
bool is_valid() const final
|
||||
{
|
||||
return detail::identifier_type_traits<IdType>::is_valid(id_);
|
||||
}
|
||||
|
||||
std::string str() const final
|
||||
{
|
||||
return detail::identifier_type_traits<IdType>::to_string(id_);
|
||||
}
|
||||
|
||||
void serialize(identifier_serializer &s) final {
|
||||
s.serialize(id_, size_);
|
||||
}
|
||||
|
||||
size_t hash() const final {
|
||||
std::hash<IdType> hash_func;
|
||||
return hash_func(id_);
|
||||
}
|
||||
|
||||
IdType id_;
|
||||
size_t size_{};
|
||||
};
|
||||
|
||||
struct null_pk : public base
|
||||
{
|
||||
null_pk();
|
||||
base *copy() const final;
|
||||
bool equal_to(const base &x) const final;
|
||||
bool less(const base &x) const final;
|
||||
bool is_valid() const final;
|
||||
void serialize(identifier_serializer &s) final;
|
||||
std::string str() const final;
|
||||
size_t hash() const final;
|
||||
null_type_t null_;
|
||||
};
|
||||
|
||||
public:
|
||||
identifier();
|
||||
template<typename Type>
|
||||
explicit identifier(const Type &id, long size = -1)
|
||||
: id_(std::make_shared<pk<Type>>(id, size)) {}
|
||||
identifier(const identifier &x);
|
||||
identifier &operator=(const identifier &x);
|
||||
identifier(identifier &&x) noexcept ;
|
||||
identifier &operator=(identifier &&x) noexcept;
|
||||
|
||||
template<typename Type>
|
||||
identifier &operator=(const Type &value)
|
||||
{
|
||||
id_ = std::make_shared<pk<Type>>(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~identifier() = default;
|
||||
|
||||
bool operator==(const identifier &x) const;
|
||||
bool operator!=(const identifier &x) const;
|
||||
bool operator<(const identifier &x) const;
|
||||
bool operator<=(const identifier &x) const;
|
||||
bool operator>(const identifier &x) const;
|
||||
bool operator>=(const identifier &x) const;
|
||||
|
||||
bool is_similar_type(const identifier &x) const;
|
||||
template<typename Type>
|
||||
bool is_similar_type() const
|
||||
{
|
||||
return id_->is_similar_type<Type>();
|
||||
}
|
||||
|
||||
std::string str() const;
|
||||
const std::type_index &type_index() const;
|
||||
|
||||
identifier share() const;
|
||||
size_t use_count() const;
|
||||
|
||||
bool is_null() const;
|
||||
bool is_valid() const;
|
||||
void clear();
|
||||
|
||||
void serialize(identifier_serializer &s);
|
||||
|
||||
size_t hash() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &out, const identifier &id);
|
||||
|
||||
private:
|
||||
explicit identifier(const std::shared_ptr<base>& id);
|
||||
|
||||
private:
|
||||
std::shared_ptr<base> id_;
|
||||
};
|
||||
|
||||
static identifier null_identifier{};
|
||||
|
||||
struct id_pk_hash
|
||||
{
|
||||
size_t operator()(const identifier &id) const;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_IDENTIFIER_HPP
|
||||
|
|
@ -11,7 +11,8 @@ set(SQL_SOURCES
|
|||
sql/connection_impl.cpp
|
||||
sql/session.cpp
|
||||
sql/backend_provider.cpp
|
||||
sql/query_result_impl.cpp)
|
||||
sql/query_result_impl.cpp
|
||||
sql/column_generator.cpp)
|
||||
|
||||
set(SQL_HEADER
|
||||
../include/matador/sql/dialect.hpp
|
||||
|
|
@ -31,21 +32,27 @@ set(SQL_HEADER
|
|||
../include/matador/sql/connection_pool.hpp
|
||||
../include/matador/sql/session.hpp
|
||||
../include/matador/sql/backend_provider.hpp
|
||||
../include/matador/sql/query_result_impl.hpp)
|
||||
../include/matador/sql/query_result_impl.hpp
|
||||
../include/matador/sql/column_generator.hpp)
|
||||
|
||||
set(UTILS_HEADER
|
||||
../include/matador/utils/field_attributes.hpp
|
||||
../include/matador/utils/string.hpp
|
||||
../include/matador/utils/constraints.hpp
|
||||
../include/matador/utils/library.hpp
|
||||
../include/matador/utils/os.hpp)
|
||||
../include/matador/utils/os.hpp
|
||||
../include/matador/utils/access.hpp
|
||||
../include/matador/utils/identifiable.hpp
|
||||
../include/matador/utils/identifier.hpp
|
||||
../include/matador/utils/cascade_type.hpp)
|
||||
|
||||
set(UTILS_SOURCES
|
||||
utils/field_attributes.cpp
|
||||
utils/string.cpp
|
||||
sql/condition.cpp
|
||||
utils/library.cpp
|
||||
utils/os.cpp)
|
||||
utils/os.cpp
|
||||
utils/identifier.cpp)
|
||||
|
||||
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
||||
target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
#include "matador/sql/column_generator.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
column_generator::column_generator(std::vector<column> &columns)
|
||||
: columns_(columns) {}
|
||||
|
||||
void column_generator::on_primary_key(const char *id, std::string &pk, size_t size)
|
||||
{
|
||||
on_attribute(id, pk, { size, utils::constraints::PRIMARY_KEY });
|
||||
}
|
||||
|
||||
void column_generator::on_revision(const char *id, unsigned long long int &x)
|
||||
{
|
||||
on_attribute(id, x);
|
||||
}
|
||||
|
||||
void column_generator::on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void column_generator::on_has_one(const char *id, utils::identifiable &x, utils::cascade_type)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -143,7 +143,12 @@ query_builder& query_builder::remove() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::table(const std::string &table, std::initializer_list<column> columns) {
|
||||
query_builder& query_builder::table(const std::string &table, std::initializer_list<column> columns)
|
||||
{
|
||||
return this->table(table, std::vector<column>{columns});
|
||||
}
|
||||
|
||||
query_builder &query_builder::table(const std::string &table, const std::vector<column> &columns) {
|
||||
transition_to(state_t::QUERY_TABLE_CREATE);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(table) + " ");
|
||||
|
|
@ -151,16 +156,16 @@ query_builder& query_builder::table(const std::string &table, std::initializer_l
|
|||
std::string result = "(";
|
||||
|
||||
if (columns.size() < 2) {
|
||||
for (const auto &col : columns) {
|
||||
result.append(build_create_column(col, dialect_));
|
||||
}
|
||||
for (const auto &col : columns) {
|
||||
result.append(build_create_column(col, dialect_));
|
||||
}
|
||||
} else {
|
||||
auto it = columns.begin();
|
||||
result.append(build_create_column(*it++, dialect_));
|
||||
for (; it != columns.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(build_create_column(*it, dialect_));
|
||||
}
|
||||
auto it = columns.begin();
|
||||
result.append(build_create_column(*it++, dialect_));
|
||||
for (; it != columns.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(build_create_column(*it, dialect_));
|
||||
}
|
||||
}
|
||||
|
||||
result += ")";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
#include "matador/utils/identifier.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <ostream>
|
||||
|
||||
namespace matador::utils {
|
||||
|
||||
identifier::base::base(const std::type_index &ti, detail::identifier_type_t id_type)
|
||||
: type_index_(ti)
|
||||
, identifier_type_(id_type)
|
||||
{}
|
||||
|
||||
bool identifier::base::is_similar_type(const identifier::base &x) const
|
||||
{
|
||||
return identifier_type_ == x.type();
|
||||
}
|
||||
|
||||
detail::identifier_type_t identifier::base::type() const
|
||||
{
|
||||
return identifier_type_;
|
||||
}
|
||||
|
||||
identifier::null_pk::null_pk()
|
||||
: base(std::type_index(typeid(null_type_t)), detail::identifier_type_traits<null_type_t>::type())
|
||||
{}
|
||||
|
||||
identifier::base* identifier::null_pk::copy() const
|
||||
{
|
||||
return new null_pk;
|
||||
}
|
||||
|
||||
bool identifier::null_pk::equal_to(const identifier::base &x) const
|
||||
{
|
||||
return type_index_ == x.type_index_;
|
||||
}
|
||||
|
||||
bool identifier::null_pk::less(const identifier::base &x) const
|
||||
{
|
||||
return type_index_ == x.type_index_;
|
||||
}
|
||||
|
||||
bool identifier::null_pk::is_valid() const
|
||||
{
|
||||
return detail::identifier_type_traits<null_type_t>::is_valid();
|
||||
}
|
||||
|
||||
std::string identifier::null_pk::str() const
|
||||
{
|
||||
return detail::identifier_type_traits<null_type_t>::to_string();
|
||||
}
|
||||
|
||||
void identifier::null_pk::serialize(identifier_serializer &s)
|
||||
{
|
||||
s.serialize(null_, {});
|
||||
}
|
||||
|
||||
size_t identifier::null_pk::hash() const
|
||||
{
|
||||
throw std::runtime_error("hash for null_pk not allowed");
|
||||
}
|
||||
|
||||
identifier::identifier()
|
||||
: id_(std::make_shared<null_pk>()) {}
|
||||
|
||||
identifier::identifier(const identifier &x)
|
||||
: id_(x.id_->copy()) {}
|
||||
|
||||
identifier &identifier::operator=(const identifier &x) {
|
||||
if (this == &x) {
|
||||
return *this;
|
||||
}
|
||||
id_.reset(x.id_->copy());
|
||||
return *this;
|
||||
}
|
||||
|
||||
identifier::identifier(identifier &&x) noexcept
|
||||
: id_(std::move(x.id_)) {}
|
||||
|
||||
identifier &identifier::operator=(identifier &&x) noexcept {
|
||||
id_ = std::move(x.id_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool identifier::operator==(const identifier &x) const {
|
||||
return id_->equal_to(*x.id_);
|
||||
}
|
||||
|
||||
bool identifier::operator!=(const identifier &x) const {
|
||||
return !operator==(x);
|
||||
}
|
||||
|
||||
bool identifier::operator<(const identifier &x) const {
|
||||
return id_->less(*x.id_);
|
||||
}
|
||||
|
||||
bool identifier::operator<=(const identifier &x) const {
|
||||
return operator==(x) || operator<(x);
|
||||
}
|
||||
|
||||
bool identifier::operator>(const identifier &x) const {
|
||||
return !operator<=(x);
|
||||
}
|
||||
|
||||
bool identifier::operator>=(const identifier &x) const {
|
||||
return !operator<(x);
|
||||
}
|
||||
|
||||
bool identifier::is_similar_type(const identifier &x) const
|
||||
{
|
||||
return id_->is_similar_type(*x.id_);
|
||||
}
|
||||
|
||||
std::string identifier::str() const {
|
||||
return id_->str();
|
||||
}
|
||||
|
||||
const std::type_index &identifier::type_index() const {
|
||||
return id_->type_index_;
|
||||
}
|
||||
|
||||
identifier identifier::share() const
|
||||
{
|
||||
return identifier(id_);
|
||||
}
|
||||
|
||||
size_t identifier::use_count() const
|
||||
{
|
||||
return id_.use_count();
|
||||
}
|
||||
|
||||
bool identifier::is_null() const
|
||||
{
|
||||
return type_index() == null_identifier.type_index();
|
||||
}
|
||||
|
||||
bool identifier::is_valid() const
|
||||
{
|
||||
return id_->is_valid();
|
||||
}
|
||||
|
||||
void identifier::clear()
|
||||
{
|
||||
id_ = std::make_unique<null_pk>();
|
||||
}
|
||||
|
||||
void identifier::serialize(identifier_serializer &s)
|
||||
{
|
||||
id_->serialize(s);
|
||||
}
|
||||
|
||||
size_t identifier::hash() const
|
||||
{
|
||||
return id_->hash();
|
||||
}
|
||||
|
||||
identifier::identifier(const std::shared_ptr<base> &id)
|
||||
: id_(id)
|
||||
{}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const identifier &id)
|
||||
{
|
||||
out << id.str();
|
||||
return out;
|
||||
}
|
||||
|
||||
size_t id_pk_hash::operator()(const identifier &id) const
|
||||
{
|
||||
return id.hash();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,10 @@ add_executable(tests builder.cpp
|
|||
record.cpp
|
||||
connection_pool.cpp
|
||||
query.cpp
|
||||
backend_provider.cpp)
|
||||
backend_provider.cpp
|
||||
connection.cpp
|
||||
product.hpp
|
||||
column_generator.cpp)
|
||||
target_link_libraries(tests PRIVATE
|
||||
Catch2::Catch2WithMain
|
||||
matador
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "matador/sql/column_generator.hpp"
|
||||
|
||||
#include "product.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("Generate columns from object", "[column generator]") {
|
||||
|
||||
auto columns = column_generator::generate<matador::test::product>();
|
||||
|
||||
const std::vector<std::string> expected_columns = {
|
||||
"product_name",
|
||||
"supplier_id",
|
||||
"category_id",
|
||||
"quantity_per_unit",
|
||||
"unit_price",
|
||||
"units_in_stock",
|
||||
"units_in_order",
|
||||
"reorder_level",
|
||||
"discontinued"
|
||||
};
|
||||
REQUIRE(!columns.empty());
|
||||
REQUIRE(columns.size() == expected_columns.size());
|
||||
|
||||
for (size_t i = 0; i != expected_columns.size(); ++i) {
|
||||
REQUIRE(expected_columns[i] == columns[i].name());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "matador/sql/connection.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("Create connection", "[connection]") {
|
||||
connection c("sqlite://test.db");
|
||||
REQUIRE(!c.is_open());
|
||||
|
||||
c.open();
|
||||
REQUIRE(c.is_open());
|
||||
|
||||
c.close();
|
||||
REQUIRE(!c.is_open());
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef QUERY_PRODUCT_HPP
|
||||
#define QUERY_PRODUCT_HPP
|
||||
|
||||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::test {
|
||||
|
||||
struct product
|
||||
{
|
||||
std::string product_name;
|
||||
unsigned long supplier_id;
|
||||
unsigned long category_id;
|
||||
std::string quantity_per_unit;
|
||||
unsigned int unit_price;
|
||||
unsigned int units_in_stock;
|
||||
unsigned int units_in_order;
|
||||
unsigned int reorder_level;
|
||||
bool discontinued;
|
||||
|
||||
template<class Operator>
|
||||
void process(Operator &op) {
|
||||
namespace field = matador::utils::access;
|
||||
using namespace matador::utils;
|
||||
field::primary_key(op, "product_name", product_name, 255);
|
||||
field::attribute(op, "supplier_id", supplier_id, { constraints::FOREIGN_KEY | constraints::NOT_NULL });
|
||||
field::attribute(op, "category_id", category_id, { constraints::FOREIGN_KEY | constraints::NOT_NULL });
|
||||
field::attribute(op, "quantity_per_unit", quantity_per_unit, 255);
|
||||
field::attribute(op, "unit_price", unit_price);
|
||||
field::attribute(op, "units_in_stock", units_in_stock);
|
||||
field::attribute(op, "units_in_order", units_in_order);
|
||||
field::attribute(op, "reorder_level", reorder_level);
|
||||
field::attribute(op, "discontinued", discontinued);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //QUERY_PRODUCT_HPP
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "catch2/generators/catch_generators.hpp"
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
|
||||
TEST_CASE("Query test", "[query]") {
|
||||
auto dns = GENERATE(as<std::string>{}, "mssql", "sqlite", "postgres" );
|
||||
|
|
|
|||
|
|
@ -4,21 +4,24 @@
|
|||
#include <matador/sql/condition.hpp>
|
||||
#include <matador/sql/session.hpp>
|
||||
|
||||
#include "product.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("Execute create table statement", "[connection]") {
|
||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||
session s(pool);
|
||||
|
||||
const auto res = s.create()
|
||||
auto res = s.create()
|
||||
.table("person", {
|
||||
make_pk_column<unsigned long>("id"),
|
||||
make_column<std::string>("name", 255),
|
||||
make_column<unsigned short>("age")
|
||||
}).execute();
|
||||
|
||||
REQUIRE(true);
|
||||
REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL PRIMARY KEY, "name" VARCHAR(255), "age" INTEGER))");
|
||||
|
||||
res = s.create().table<matador::test::product>("product").execute();
|
||||
}
|
||||
|
||||
TEST_CASE("Execute drop table statement", "[connection]") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue