| @@ -1,5 +1,6 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "cpphibernate/context.h" | |||||
| #include "cpphibernate/misc.h" | #include "cpphibernate/misc.h" | ||||
| #include "cpphibernate/modifier.h" | #include "cpphibernate/modifier.h" | ||||
| #include "cpphibernate/schema.h" | #include "cpphibernate/schema.h" | ||||
| @@ -0,0 +1,3 @@ | |||||
| #pragma once | |||||
| #include "context/context.h" | |||||
| @@ -0,0 +1,106 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| namespace cpphibernate | |||||
| { | |||||
| /** | |||||
| * @brief Context class for cpphibernate. | |||||
| */ | |||||
| template<typename T_driver, typename T_schema> | |||||
| struct context | |||||
| : public T_driver | |||||
| { | |||||
| public: | |||||
| using base_type = T_driver; | |||||
| using driver_type = T_driver; | |||||
| using schema_type = T_schema; | |||||
| private: | |||||
| const schema_type& _schema; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Create a new context object. | |||||
| * | |||||
| * @param p_schema Database schema to use. | |||||
| * @param p_args Arguments to pass to underlying driver. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr context(const schema_type& p_schema, T_args&&... p_args); | |||||
| /** | |||||
| * @brief Nove constructor. | |||||
| */ | |||||
| constexpr context(context&&) = default; | |||||
| /** | |||||
| * @brief Copy constrcutor. | |||||
| */ | |||||
| constexpr context(const context&) = default; | |||||
| /** | |||||
| * @brief Initialize the database. This will create all non exsitsing tables. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) init(T_args&&... args); | |||||
| /** | |||||
| * @brief Create the passed object in the database. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) create(T_args&&... args); | |||||
| /** | |||||
| * @brief Read an object from the database. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) read(T_args&&... args); | |||||
| /** | |||||
| * @brief Update the passed object in the database. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) update(T_args&&... args); | |||||
| /** | |||||
| * @brief Destroy the passed object in the database. | |||||
| */ | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) destroy(T_args&&... args); | |||||
| }; | |||||
| /** | |||||
| * @brief Create a new cpphibernate context. | |||||
| * | |||||
| * @tparam T_driver Hibernate driver to use. | |||||
| * @tparam T_schema Database schema to use. | |||||
| * @tparam T_args Arguments to pass to underlying driver implementation. | |||||
| * | |||||
| * @param schema Database schema to use. | |||||
| * @param args Arguments to pass to underlying driver implementation. | |||||
| * | |||||
| * @return Created hibernate context. | |||||
| */ | |||||
| template<typename T_driver, typename T_schema, typename... T_args> | |||||
| constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args); | |||||
| /** | |||||
| * @brief Create a new cpphibernate context as a unique pointer. | |||||
| * | |||||
| * @tparam T_driver Hibernate driver to use. | |||||
| * @tparam T_schema Database schema to use. | |||||
| * @tparam T_args Arguments to pass to underlying driver implementation. | |||||
| * | |||||
| * @param schema Database schema to use. | |||||
| * @param args Arguments to pass to underlying driver implementation. | |||||
| * | |||||
| * @return Unique pointer of the created hibernate context. | |||||
| */ | |||||
| template<typename T_driver, typename T_schema, typename... T_args> | |||||
| constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args); | |||||
| } | |||||
| #include "context.inl" | |||||
| @@ -0,0 +1,203 @@ | |||||
| #pragma once | |||||
| #include "context.h" | |||||
| namespace cpphibernate | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* init_builder */ | |||||
| template<typename X, typename = void> | |||||
| struct init_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::init(...)!"); } | |||||
| }; | |||||
| constexpr decltype(auto) init = mp::generic_predicate<init_builder> { }; | |||||
| #if 0 | |||||
| template<typename T_impl> | |||||
| struct init_builder<mp::list<T_impl, bool>, void> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_impl& impl, bool recreate) | |||||
| { return impl.init(recreate); } | |||||
| }; | |||||
| #endif | |||||
| /* create_builder */ | |||||
| template<typename X, typename = void> | |||||
| struct create_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::create(...)!"); } | |||||
| }; | |||||
| constexpr decltype(auto) create = mp::generic_predicate<create_builder> { }; | |||||
| #if 0 | |||||
| template<typename T_impl, typename T_dataset> | |||||
| struct create_impl<mp::list<T_impl, T_dataset>, void> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset) | |||||
| { return impl.create(dataset); } | |||||
| }; | |||||
| #endif | |||||
| /* read_builder */ | |||||
| template<typename X, typename = void> | |||||
| struct read_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::read(...)!"); } | |||||
| }; | |||||
| constexpr decltype(auto) read = mp::generic_predicate<read_builder> { }; | |||||
| #if 0 | |||||
| template<typename T_impl, typename T_dataset, typename... T_modifiers> | |||||
| struct create_impl< | |||||
| mp::list<T_impl, T_dataset, T_modifiers...>, | |||||
| mp::enable_if_t<mp::is_true_v<is_modifier_v<mp::decay_t<T_modifiers>>...>>> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset, T_modifiers&&... modifiers) | |||||
| { return impl.read(dataset, make_modifiers(std::forward<T_modifiers>(modifiers)...)); } | |||||
| }; | |||||
| #endif | |||||
| /* update_builder */ | |||||
| template<typename X, typename = void> | |||||
| struct update_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::update(...)!"); } | |||||
| }; | |||||
| constexpr decltype(auto) update = mp::generic_predicate<update_builder> { }; | |||||
| #if 0 | |||||
| template<typename T_impl, typename T_dataset> | |||||
| struct update_impl<mp::list<T_impl, T_dataset>, void> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset) | |||||
| { return impl.update(dataset); } | |||||
| }; | |||||
| #endif | |||||
| /* destroy_builder */ | |||||
| template<typename X, typename = void> | |||||
| struct destroy_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::destroy(...)!"); } | |||||
| }; | |||||
| constexpr decltype(auto) destroy = mp::generic_predicate<destroy_builder> { }; | |||||
| #if 0 | |||||
| template<typename T_impl, typename T_dataset> | |||||
| struct destroy_impl<mp::list<T_impl, T_dataset>, void> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset) | |||||
| { return impl.create(dataset); } | |||||
| }; | |||||
| #endif | |||||
| } | |||||
| /* context */ | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr context<T_driver, T_schema>::context(const schema_type& p_schema, T_args&&... p_args) | |||||
| : base_type (p_schema, std::forward<T_args>(p_args)...) | |||||
| , _schema (p_schema) | |||||
| { } | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) context<T_driver, T_schema>::init(T_args&&... args) | |||||
| { return __impl::init(*this, std::forward<T_args>(args)...); } | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) context<T_driver, T_schema>::create(T_args&&... args) | |||||
| { return __impl::create(*this, std::forward<T_args>(args)...); } | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) context<T_driver, T_schema>::read(T_args&&... args) | |||||
| { return __impl::read(*this, std::forward<T_args>(args)...); } | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) context<T_driver, T_schema>::update(T_args&&... args) | |||||
| { return __impl::update(*this, std::forward<T_args>(args)...); } | |||||
| template<typename T_driver, typename T_schema> | |||||
| template<typename... T_args> | |||||
| constexpr decltype(auto) context<T_driver, T_schema>::destroy(T_args&&... args) | |||||
| { return __impl::destroy(*this, std::forward<T_args>(args)...); } | |||||
| #if 0 | |||||
| template<typename T_dataset, typename... T_modifiers> | |||||
| constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers) | |||||
| -> mp::enable_if< | |||||
| modifier::all_are_modifiers<mp::decay_t<T_modifiers>...>> | |||||
| { | |||||
| using namespace modifier; | |||||
| using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>; | |||||
| schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>); | |||||
| this->read_impl(dataset, modifier::make_list(std::forward<T_modifiers>(modifiers)...)); | |||||
| } | |||||
| template<typename T_dataset> | |||||
| constexpr auto read(T_dataset& dataset) | |||||
| -> mp::enable_if_c< | |||||
| !misc::is_container<mp::decay_t<T_dataset>>::value | |||||
| && !misc::is_nullable<mp::decay_t<T_dataset>>::value> | |||||
| { | |||||
| using namespace modifier; | |||||
| using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>; | |||||
| auto& table = schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>); | |||||
| auto& primary_key = schema::table::get_primary_key_field(table); | |||||
| this->read_impl(dataset, modifier::make_list(where(equal(primary_key, primary_key.getter(dataset))))); | |||||
| } | |||||
| template<typename T_dataset> | |||||
| constexpr auto read(T_dataset& dataset) | |||||
| -> mp::enable_if_c< | |||||
| misc::is_container<mp::decay_t<T_dataset>>::value | |||||
| || misc::is_nullable<mp::decay_t<T_dataset>>::value> | |||||
| { | |||||
| using namespace modifier; | |||||
| using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>; | |||||
| schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>); | |||||
| this->read_impl(dataset, modifier::make_list()); | |||||
| } | |||||
| #endif | |||||
| /* make_context */ | |||||
| template<typename T_driver, typename T_schema, typename... T_args> | |||||
| constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args) | |||||
| { | |||||
| using context_type = context<T_driver, T_schema>; | |||||
| return context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...); | |||||
| } | |||||
| /* make_context_ptr */ | |||||
| template<typename T_driver, typename T_schema, typename... T_args> | |||||
| constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args) | |||||
| { | |||||
| using context_type = context<T_driver, T_schema>; | |||||
| using pointer_type = std::unique_ptr<context_type>; | |||||
| return pointer_type(new context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...)); | |||||
| } | |||||
| } | |||||
| @@ -1,12 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/mariadb.h> | |||||
| #include <cpphibernate/driver/mariadb/driver.h> | |||||
| beg_namespace_cpphibernate_driver | |||||
| namespace cpphibernate | |||||
| { | { | ||||
| using mariadb = mariadb_impl::mariadb_driver_t; | |||||
| using mariadb_driver = ::cpphibernate::mariadb::driver_t; | |||||
| } | } | ||||
| end_namespace_cpphibernate_driver | |||||
| @@ -0,0 +1,6 @@ | |||||
| #pragma once | |||||
| #include "classes/attributes.h" | |||||
| #include "classes/fields.h" | |||||
| #include "classes/tables.h" | |||||
| #include "classes/schema.h" | |||||
| @@ -0,0 +1,3 @@ | |||||
| #pragma once | |||||
| #include "attributes/attributes.h" | |||||
| @@ -0,0 +1,43 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| #include "../forward.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper class to create attributes type. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct attributes_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Attributes enumeration | |||||
| */ | |||||
| enum class attribute_t | |||||
| { | |||||
| hex, //!< The field is stored hex encoded. | |||||
| compress, //!< The field is stored compressed. | |||||
| primary_key, //!< The field is the primary key. | |||||
| }; | |||||
| /** | |||||
| * @brief Set of attributes. | |||||
| */ | |||||
| struct attributes_t; | |||||
| /** | |||||
| * @brief Predicate to create attributes set from attributes schema. | |||||
| */ | |||||
| constexpr decltype(auto) make_attributes = mp::generic_predicate<__impl::attributes_builder> { }; | |||||
| } } | |||||
| #include "attributes.inl" | |||||
| @@ -1,9 +1,14 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | |||||
| #include <set> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| #include <cpphibernate/schema/attribute.h> | |||||
| #include <cpphibernate/schema/attributes.h> | |||||
| #include "attributes.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| @@ -25,10 +30,10 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| struct attribute_converter<schema::attribute::primary_key_type> | struct attribute_converter<schema::attribute::primary_key_type> | ||||
| { static constexpr decltype(auto) value = attribute_t::primary_key; }; | { static constexpr decltype(auto) value = attribute_t::primary_key; }; | ||||
| /* make_attributes_impl */ | |||||
| /* attributes_builder */ | |||||
| template<typename T, typename> | template<typename T, typename> | ||||
| struct make_attributes_impl | |||||
| struct attributes_builder | |||||
| { | { | ||||
| template<typename... T_args> | template<typename... T_args> | ||||
| static constexpr decltype(auto) apply(T_args&&... args) | static constexpr decltype(auto) apply(T_args&&... args) | ||||
| @@ -36,10 +41,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| }; | }; | ||||
| template<typename T_attributes> | template<typename T_attributes> | ||||
| struct make_attributes_impl< | |||||
| struct attributes_builder< | |||||
| mp::list<T_attributes>, | mp::list<T_attributes>, | ||||
| mp::enable_if_c< | |||||
| schema::is_attributes<mp::decay_t<T_attributes>>::value>> | |||||
| mp::enable_if_t<schema::is_attributes_v<mp::decay_t<T_attributes>>>> | |||||
| { | { | ||||
| template<size_t... I> | template<size_t... I> | ||||
| static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&) | static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&) | ||||
| @@ -58,5 +62,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| } | } | ||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| /* attributes_t */ | |||||
| struct attributes_t : | |||||
| public std::set<attribute_t> | |||||
| { | |||||
| using base_type = std::set<attribute_t>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| } } | |||||
| @@ -0,0 +1,4 @@ | |||||
| #pragma once | |||||
| #include "fields/field.h" | |||||
| #include "fields/fields.h" | |||||
| @@ -0,0 +1,106 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cpphibernate/config.h> | |||||
| #include "../forward.h" | |||||
| #include "../attributes.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Abstract field class. | |||||
| */ | |||||
| struct field_t | |||||
| { | |||||
| public: | |||||
| size_t id { 0 }; //!< unique id of the field | |||||
| size_t value_id { 0 }; //!< unique id of the value type | |||||
| size_t real_value_id { 0 }; //!< unique id of the real/unwrapped value type | |||||
| bool value_is_nullable { false }; //!< value is stored in a nullable container | |||||
| bool value_is_pointer { false }; //!< value is stored in a pointer container | |||||
| bool value_is_container { false }; //!< value is stored in a container | |||||
| bool value_is_ordered { false }; //!< value is stored in a ordered container (vector, list, ...) | |||||
| bool value_is_auto_incremented { false }; //!< value is a auto incremented field | |||||
| const table_t& table; //!< table this field belongs to | |||||
| const table_t* referenced_table { nullptr }; //!< table that belongs to the value (if exists) | |||||
| std::string name; //!< name of the SQL field | |||||
| std::string type; //!< SQL type name | |||||
| std::string create_arguments; //!< additional arguments for CREATE TABLE command | |||||
| std::string convert_to_open; //!< SQL code to open the "convert to" operation | |||||
| std::string convert_to_close; //!< SQL code to close the "convert to" operation | |||||
| std::string convert_from_open; //!< SQL code to open the "convert from" operation | |||||
| std::string convert_from_close; //!< SQL code to close the "convert from" operation | |||||
| attributes_t attributes; //!< attributes for the field | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_field> | |||||
| inline field_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| inline field_t(field_t&& other) = delete; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| inline field_t(const field_t&) = delete; | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~field_t() = 0; | |||||
| /** | |||||
| * @brief Print the field values to the passed stream. | |||||
| */ | |||||
| std::ostream& print(std::ostream& os) const; | |||||
| private: | |||||
| /** | |||||
| * @brief Initialize the field. | |||||
| */ | |||||
| void init(); | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper type to build table. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct field_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Predicate to create mariadb table class. | |||||
| */ | |||||
| constexpr decltype(auto) make_field = mp::generic_predicate<__impl::field_builder> { }; | |||||
| } } | |||||
| #include "field.inl" | |||||
| @@ -0,0 +1,126 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/schema/field.h> | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include "field.h" | |||||
| #include "field_data.h" | |||||
| #include "field_primary_key.h" | |||||
| #include "field_foreign_table.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_field> | |||||
| field_t::field_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : id (get_type_id(hana::type_c<mp::decay_t<T_field>>)) | |||||
| , value_id (get_type_id(hana::type_c<typename T_field::value_type>)) | |||||
| , real_value_id (get_type_id(hana::type_c<real_dataset_t<typename T_field::value_type>>)) | |||||
| , value_is_nullable (is_nullable_v <typename T_field::value_type>) | |||||
| , value_is_pointer (is_pointer_v <typename T_field::value_type>) | |||||
| , value_is_container (is_container_v<typename T_field::value_type>) | |||||
| , value_is_ordered (is_ordered_v <typename T_field::value_type>) | |||||
| , value_is_auto_incremented (false) | |||||
| , table (p_owner) | |||||
| , referenced_table (nullptr) | |||||
| , name (p_field.name) | |||||
| , type () | |||||
| , create_arguments () | |||||
| , convert_to_open () | |||||
| , convert_to_close () | |||||
| , convert_from_open () | |||||
| , convert_from_close () | |||||
| , attributes (make_attributes(p_field.attributes)) | |||||
| { } | |||||
| namespace __impl | |||||
| { | |||||
| /* field_builder */ | |||||
| template<typename X, typename> | |||||
| struct field_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_field(...)!"); } | |||||
| }; | |||||
| template<typename T_owner, typename T_schema, typename T_table, typename T_field> | |||||
| struct field_builder< | |||||
| mp::list<T_owner, T_schema, T_table, T_field>, | |||||
| mp::enable_if_t< | |||||
| mp::is_base_of_v<table_t, mp::decay_t<T_owner>> | |||||
| && schema::is_schema_v<mp::decay_t<T_schema>> | |||||
| && schema::is_table_v<mp::decay_t<T_table>> | |||||
| && schema::is_field_v<mp::decay_t<T_field>>>> | |||||
| { | |||||
| /* is_primary_key_field */ | |||||
| template<typename X_field> | |||||
| struct is_primary_key_field | |||||
| : public decltype( | |||||
| hana::contains( | |||||
| std::declval<mp::decay_t<X_field>>().attributes, | |||||
| schema::attribute::primary_key)) | |||||
| { }; | |||||
| /* is_foreign_table_field */ | |||||
| template<typename X_schema, typename X_field> | |||||
| struct is_foreign_table_field | |||||
| : public decltype( | |||||
| hana::contains( | |||||
| hana::transform( | |||||
| std::declval<X_schema>().tables, | |||||
| schema::get_wrapped_dataset), | |||||
| std::declval<X_field>().wrapped_real_value_type)) | |||||
| { }; | |||||
| /* field_type */ | |||||
| template<typename X_schema, typename X_field, typename = void> | |||||
| struct field_type | |||||
| { using type = field_data_t<T_field>; }; | |||||
| template<typename X_schema, typename X_field> | |||||
| struct field_type< | |||||
| X_schema, | |||||
| X_field, | |||||
| mp::enable_if_t<is_primary_key_field<X_field>::value>> | |||||
| { using type = field_primary_key_t<X_field>; }; | |||||
| template<typename X_schema, typename X_field> | |||||
| struct field_type< | |||||
| X_schema, | |||||
| X_field, | |||||
| mp::enable_if_t<is_foreign_table_field<X_schema, X_field>::value>> | |||||
| { using type = field_foreign_table_t<X_field>; }; | |||||
| template<typename X_schema, typename X_field> | |||||
| using field_type_t = typename field_type<X_schema, X_field>::type; | |||||
| /* apply */ | |||||
| static constexpr decltype(auto) apply(const table_t& owner, const T_schema& schema, const T_table& table, const T_field& field) | |||||
| { | |||||
| using schema_type = mp::decay_t<T_schema>; | |||||
| using field_type = mp::decay_t<T_field>; | |||||
| using return_type = field_type_t<schema_type, field_type>; | |||||
| return std::make_unique<return_type>(owner, schema, table, field); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include "field_value.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Field that represents a data field. | |||||
| */ | |||||
| template<typename T_field> | |||||
| struct field_data_t | |||||
| : public field_value_t<T_field> | |||||
| { | |||||
| private: | |||||
| using base_type = field_value_t<T_field>; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline field_data_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| }; | |||||
| } } | |||||
| #include "field_data.inl" | |||||
| @@ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include "field_data.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* field_data_t */ | |||||
| template< | |||||
| typename T_field> | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| field_data_t<T_field>::field_data_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : field_value_t<T_field>::field_value_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table, | |||||
| p_field) | |||||
| { } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include "field_simple.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Field that represents a foreign table. | |||||
| */ | |||||
| template<typename T_field> | |||||
| struct field_foreign_table_t | |||||
| : public field_simple_t<T_field> | |||||
| { | |||||
| private: | |||||
| using base_type = field_simple_t<T_field>; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline field_foreign_table_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| }; | |||||
| } } | |||||
| #include "field_foreign_table.inl" | |||||
| @@ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include "field_foreign_table.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* field_foreign_table_t */ | |||||
| template< | |||||
| typename T_field> | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| field_foreign_table_t<T_field>::field_foreign_table_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : field_simple_t<T_field>::field_simple_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table, | |||||
| p_field) | |||||
| { } | |||||
| } } | |||||
| @@ -0,0 +1,44 @@ | |||||
| #pragma once | |||||
| #include "field_value.h" | |||||
| #include "../../helper/key_properties.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Field that represents a primary key field. | |||||
| */ | |||||
| template<typename T_field> | |||||
| struct field_primary_key_t | |||||
| : public field_value_t<T_field> | |||||
| { | |||||
| private: | |||||
| using base_type = field_value_t<T_field>; | |||||
| public: | |||||
| static constexpr decltype(auto) key_props = | |||||
| key_properties<typename decltype(+base_type::value_type)::type> { }; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline field_primary_key_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| }; | |||||
| } } | |||||
| #include "field_primary_key.inl" | |||||
| @@ -0,0 +1,33 @@ | |||||
| #pragma once | |||||
| #include "field_primary_key.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* field_primary_key_t */ | |||||
| template< | |||||
| typename T_field> | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| field_primary_key_t<T_field>::field_primary_key_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : field_value_t<T_field>::field_value_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table, | |||||
| p_field) | |||||
| { | |||||
| this->value_is_auto_incremented = key_props.is_auto_generated(); | |||||
| auto args = key_props.create_table_argument(); | |||||
| if (args) | |||||
| this->create_arguments = args; | |||||
| this->name = this->table.name + '_' + this->name; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include "field.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Field that completely implementes the abstract field_t | |||||
| */ | |||||
| template<typename T_field> | |||||
| struct field_simple_t | |||||
| : public field_t | |||||
| { | |||||
| private: | |||||
| using base_type = field_t; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline field_simple_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| }; | |||||
| } } | |||||
| #include "field_simple.inl" | |||||
| @@ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include "field_simple.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* field_simple_t */ | |||||
| template< | |||||
| typename T_field> | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| field_simple_t<T_field>::field_simple_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : field_t::field_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table, | |||||
| p_field) | |||||
| { } | |||||
| } } | |||||
| @@ -0,0 +1,48 @@ | |||||
| #pragma once | |||||
| #include "field_simple.h" | |||||
| #include "../../helper/type_properties.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Field that represents a simple value. | |||||
| */ | |||||
| template<typename T_field> | |||||
| struct field_value_t | |||||
| : public field_simple_t<T_field> | |||||
| { | |||||
| private: | |||||
| using base_type = field_simple_t<T_field>; | |||||
| public: | |||||
| static constexpr decltype(auto) field_type = | |||||
| hana::type_c<mp::decay_t<T_field>>; | |||||
| static constexpr decltype(auto) value_type = | |||||
| hana::type_c<typename decltype(+field_type)::type::value_type>; | |||||
| static constexpr decltype(auto) value_props = | |||||
| type_properties<typename decltype(+value_type)::type> { }; | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb field from the cpphibernate field. | |||||
| * | |||||
| * @param[in] p_owner Owner of the field. | |||||
| * @param[in] p_schema Cpphibernate schema the mariadb field belongs to. | |||||
| * @param[in] p_table Cpphibernate table the mariadb field belongs to. | |||||
| * @param[in] p_field Cpphibernate field to create mariadb field for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline field_value_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field); | |||||
| }; | |||||
| } } | |||||
| #include "field_value.inl" | |||||
| @@ -0,0 +1,37 @@ | |||||
| #pragma once | |||||
| #include "field_value.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* field_value_t */ | |||||
| template< | |||||
| typename T_field> | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| field_value_t<T_field>::field_value_t( | |||||
| const table_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_field& p_field) | |||||
| : field_simple_t<T_field>::field_simple_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table, | |||||
| p_field) | |||||
| { | |||||
| this->type = value_props.type(); | |||||
| if (value_props.convert_to_open()) | |||||
| this->convert_to_open = this->convert_to_open + value_props.convert_to_open(); | |||||
| if (value_props.convert_to_close()) | |||||
| this->convert_to_close = value_props.convert_to_close() + this->convert_to_close; | |||||
| if (value_props.convert_from_open()) | |||||
| this->convert_from_open = this->convert_from_open + value_props.convert_from_open(); | |||||
| if (value_props.convert_from_close()) | |||||
| this->convert_from_close = value_props.convert_from_close() + this->convert_from_close; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include "../forward.h" | |||||
| #include "field.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Vector of fields. | |||||
| */ | |||||
| struct fields_t | |||||
| : public std::vector<field_ptr_u> | |||||
| { | |||||
| using base_type = std::vector<field_ptr_u>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper class to create table vector. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct fields_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Predicate to create table vector. | |||||
| */ | |||||
| constexpr decltype(auto) make_fields = mp::generic_predicate<__impl::fields_builder> { }; | |||||
| } } | |||||
| #include "fields.inl" | |||||
| @@ -0,0 +1,67 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include "field.h" | |||||
| #include "fields.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| namespace __impl | |||||
| { | |||||
| /* fields_builder */ | |||||
| template<typename X, typename> | |||||
| struct fields_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); } | |||||
| }; | |||||
| template<typename T_owner, typename T_schema, typename T_table> | |||||
| struct fields_builder< | |||||
| mp::list<T_owner, T_schema, T_table>, | |||||
| mp::enable_if_t< | |||||
| mp::is_same_v<table_t, mp::decay_t<T_owner>> | |||||
| && schema::is_schema_v<mp::decay_t<T_schema>> | |||||
| && schema::is_table_v<mp::decay_t<T_table>>>> | |||||
| { | |||||
| template<typename T_index> | |||||
| static constexpr void emplace( | |||||
| fields_t& result, | |||||
| const table_t& owner, | |||||
| const T_schema& schema, | |||||
| const T_table& table, | |||||
| T_index&& index) | |||||
| { | |||||
| result.emplace_back(make_field(owner, schema, table, table.fields[index])); | |||||
| } | |||||
| template<size_t... I> | |||||
| static auto helper( | |||||
| const table_t& owner, | |||||
| const T_schema& schema, | |||||
| const T_table& table, | |||||
| std::index_sequence<I...>&&) | |||||
| { | |||||
| fields_t ret; | |||||
| int dummy[] = { 0, (emplace(ret, owner, schema, table, hana::size_c<I>), void(), 0)... }; | |||||
| (void) dummy; | |||||
| return ret; | |||||
| } | |||||
| static constexpr decltype(auto) apply( | |||||
| const table_t& owner, const T_schema& schema, const T_table& table) | |||||
| { | |||||
| using size = decltype(hana::size(table.fields)); | |||||
| return helper(owner, schema, table, std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,21 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cpphibernate/config.h> | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| enum class attribute_t; | |||||
| struct attributes_t; | |||||
| struct field_t; | |||||
| struct fields_t; | |||||
| struct table_t; | |||||
| struct tables_t; | |||||
| struct schema_t; | |||||
| using field_ptr_u = std::unique_ptr<const field_t>; | |||||
| using table_ptr_u = std::unique_ptr<const table_t>; | |||||
| using schema_ptr_u = std::unique_ptr<schema_t>; | |||||
| } } | |||||
| @@ -0,0 +1,3 @@ | |||||
| #pragma once | |||||
| #include "schema/schema.h" | |||||
| @@ -0,0 +1,80 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| #include "../forward.h" | |||||
| #include "../tables/tables.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Class to wrapp all values needed by the maraidb schema. | |||||
| */ | |||||
| struct schema_t | |||||
| { | |||||
| public: | |||||
| using table_map = std::map<size_t, const table_t *>; | |||||
| private: | |||||
| table_map _lookup; //!< dataset id to table pointer map | |||||
| public: | |||||
| std::string name; //!< name of the schema | |||||
| tables_t tables; //!< tables that are managed by this schema. | |||||
| public: | |||||
| /** | |||||
| * @brief Default constructor. | |||||
| */ | |||||
| inline schema_t() = default; | |||||
| /** | |||||
| * @brief Value constructor. | |||||
| * | |||||
| * @param[in] p_schema Cpphibernate schema to create mariadb schema from. | |||||
| */ | |||||
| template<typename T_schema> | |||||
| inline schema_t(const T_schema& p_schema); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| inline schema_t(schema_t&&) = delete; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| inline schema_t(const schema_t&) = delete; | |||||
| /** | |||||
| * @brief Print the schema to the passed stream. | |||||
| */ | |||||
| std::ostream& print(std::ostream& os) const; | |||||
| private: | |||||
| /** | |||||
| * @brief Initialize the field. | |||||
| */ | |||||
| void init(); | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper type to build schema. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct schema_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Predicate to create mariadb schema class. | |||||
| */ | |||||
| constexpr decltype(auto) make_schema = mp::generic_predicate<__impl::schema_builder> { }; | |||||
| } } | |||||
| #include "schema.inl" | |||||
| @@ -0,0 +1,43 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include "schema.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* schema_t */ | |||||
| template<typename T_schema> | |||||
| schema_t::schema_t(const T_schema& p_schema) | |||||
| : name (p_schema.name) | |||||
| , tables(make_tables(*this, p_schema)) | |||||
| { init(); } | |||||
| namespace __impl | |||||
| { | |||||
| /* schema_builder */ | |||||
| template<typename T, typename> | |||||
| struct schema_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); } | |||||
| }; | |||||
| template<typename T_schema> | |||||
| struct schema_builder< | |||||
| mp::list<T_schema>, | |||||
| mp::enable_if_t< | |||||
| schema::is_schema_v<mp::decay_t<T_schema>>>> | |||||
| { | |||||
| static decltype(auto) apply(const T_schema& p_schema) | |||||
| { return std::make_unique<schema_t>(p_schema); } | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,4 @@ | |||||
| #pragma once | |||||
| #include "tables/table.h" | |||||
| #include "tables/tables.h" | |||||
| @@ -0,0 +1,115 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include <memory> | |||||
| #include <cpphibernate/config.h> | |||||
| #include "../forward.h" | |||||
| #include "../fields/fields.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Abstract table class. | |||||
| */ | |||||
| struct table_t | |||||
| { | |||||
| public: | |||||
| using size_vector = std::vector<size_t>; //!< vector of size_t | |||||
| using table_vector = std::vector<const table_t *>; //!< vector of constant field pointers | |||||
| using field_vector = std::vector<const field_t *>; //!< vector of constant field pointers | |||||
| using field_map = std::map<size_t, const field_t *>; //!< map of field id to field | |||||
| private: | |||||
| field_map _lookup; //!< field id to field pointer map | |||||
| public: | |||||
| size_t id { 0 }; //!< unique id of the table assigned by the user | |||||
| size_t dataset_id { 0 }; //!< unique id of the dataset type | |||||
| size_t base_dataset_id { 0 }; //!< unique id of the dataset type | |||||
| size_vector derived_dataset_ids; //!< vector of ids of all derived dataset | |||||
| bool is_used_in_container { false }; //!< indicates if this table is used inside a container | |||||
| std::string name; //!< name of the table | |||||
| const schema_t& schema; //!< schema this table is owned by | |||||
| fields_t fields; //!< vector of fields managed by this table | |||||
| const table_t * base_table { nullptr }; //!< base table (if has one) | |||||
| table_vector derived_tables; //!< vector of pointers of all derived tables | |||||
| const field_t * primary_key_field { nullptr }; //!< primary key field | |||||
| field_vector foreign_key_fields; //!< vector of pointers of all foreign key fields | |||||
| field_vector foreign_table_fields; //!< vector of pointers of all foreign table fields | |||||
| field_vector foreign_table_one_fields; //!< vector of pointers of all foreign table one fields | |||||
| field_vector foreign_table_many_fields; //!< vector of pointers of all foreign table many fields | |||||
| field_vector data_fields; //!< vector of pointers of all normal data fields | |||||
| public: | |||||
| /** | |||||
| * @brief Default constructor. | |||||
| */ | |||||
| inline table_t() = default; | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb table from the cpphibernate table. | |||||
| * | |||||
| * @param[in] p_owner Owner of the table. | |||||
| * @param[in] p_schema Cpphibernate schema the table belongs to. | |||||
| * @param[in] p_table Cpphibernate table to create mariadb table for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| inline table_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| inline table_t(table_t&& other) = delete; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| inline table_t(const table_t&) = delete; | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~table_t() = 0; | |||||
| /** | |||||
| * @brief Print the table to the passed stream. | |||||
| */ | |||||
| std::ostream& print(std::ostream& os) const; | |||||
| private: | |||||
| /** | |||||
| * @brief Initialize the field. | |||||
| */ | |||||
| void init(); | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper type to build table. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct table_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Predicate to create mariadb table class. | |||||
| */ | |||||
| constexpr decltype(auto) make_table = mp::generic_predicate<__impl::table_builder> { }; | |||||
| } } | |||||
| #include "table.inl" | |||||
| @@ -0,0 +1,99 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include "table.h" | |||||
| #include "table_simple.h" | |||||
| #include "table_polymorphic.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* table_t */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table> | |||||
| table_t::table_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table) | |||||
| : id (hana::value(p_table.table_id)) | |||||
| , dataset_id(get_type_id(p_table.wrapped_dataset)) | |||||
| , name (p_table.name) | |||||
| , schema (p_owner) | |||||
| , fields (make_fields(*this, p_schema, p_table)) | |||||
| { init(); } | |||||
| namespace __impl | |||||
| { | |||||
| /* table_builder */ | |||||
| template<typename X, typename> | |||||
| struct table_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); } | |||||
| }; | |||||
| template<typename T_owner, typename T_schema, typename T_table> | |||||
| struct table_builder< | |||||
| mp::list<T_owner, T_schema, T_table>, | |||||
| mp::enable_if_t< | |||||
| mp::is_same_v<schema_t, mp::decay_t<T_owner>> | |||||
| && schema::is_schema_v<mp::decay_t<T_schema>> | |||||
| && schema::is_table_v<mp::decay_t<T_table>>>> | |||||
| { | |||||
| /* table_type */ | |||||
| template< | |||||
| typename T_dataset, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets, | |||||
| typename = void> | |||||
| struct table_type | |||||
| { using type = table_simple_t /* table_simple_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset> */; }; | |||||
| template< | |||||
| typename T_dataset, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| struct table_type< | |||||
| T_dataset, | |||||
| T_base_dataset, | |||||
| T_derived_datasets, | |||||
| mp::enable_if_t< | |||||
| decltype(hana::size(std::declval<T_derived_datasets>()) != hana::size_c<0>)::value | |||||
| || decltype(hana::not_equal(std::declval<T_base_dataset>(), hana::type_c<void>))::value>> | |||||
| { using type = table_polymorphic_t /* table_polymorphic_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset> */; }; | |||||
| template< | |||||
| typename T_dataset, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| using table_type_t = typename table_type<T_dataset, T_base_dataset, T_derived_datasets>::type; | |||||
| /* apply */ | |||||
| static decltype(auto) apply(const schema_t& owner, const T_schema& schema, const T_table& table) | |||||
| { | |||||
| using dataset_type = decltype(+table.wrapped_dataset); | |||||
| using base_dataset_type = mp::decay_t<decltype(schema::get_base_type(schema, table.wrapped_dataset))>; | |||||
| using derived_datasets_type = mp::decay_t<decltype(schema::get_derived_types(schema, table.wrapped_dataset))>; | |||||
| using table_type = table_type_t<dataset_type, base_dataset_type, derived_datasets_type>; | |||||
| return std::make_unique<table_type>( | |||||
| owner, schema, table, | |||||
| base_dataset_type { }, derived_datasets_type { }); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| #include "table.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Table for polymorphic data types. | |||||
| */ | |||||
| struct table_polymorphic_t | |||||
| : public table_t | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb table from the cpphibernate table. | |||||
| * | |||||
| * @param[in] p_owner Owner of the table. | |||||
| * @param[in] p_schema Cpphibernate schema the table belongs to. | |||||
| * @param[in] p_table Cpphibernate table to create mariadb table for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| inline table_polymorphic_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_base_dataset&&, | |||||
| const T_derived_datasets&&); | |||||
| }; | |||||
| } } | |||||
| #include "table_polymorphic.inl" | |||||
| @@ -0,0 +1,60 @@ | |||||
| #pragma once | |||||
| #include "table_polymorphic.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| namespace __impl | |||||
| { | |||||
| /* make_dataset_id_vector */ | |||||
| struct make_dataset_id_vector_impl | |||||
| { | |||||
| template<typename T_datasets, size_t... I> | |||||
| static constexpr decltype(auto) helper(const T_datasets& datasets, std::index_sequence<I...>) | |||||
| { | |||||
| return std::vector<size_t>({ | |||||
| get_type_id(datasets[hana::size_c<I>])... | |||||
| }); | |||||
| } | |||||
| template<typename T_datasets> | |||||
| constexpr decltype(auto) operator()(const T_datasets& datasets) const | |||||
| { | |||||
| using size = mp::decay_t<decltype(hana::size(datasets))>; | |||||
| return helper(datasets, std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { }; | |||||
| } | |||||
| /* table_polymorphic_t */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| table_polymorphic_t::table_polymorphic_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_base_dataset&&, | |||||
| const T_derived_datasets&&) | |||||
| : table_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table) | |||||
| { | |||||
| this->base_dataset_id = hana::if_( | |||||
| hana::equal(T_base_dataset { }, hana::type_c<void>), | |||||
| static_cast<size_t>(0), | |||||
| get_type_id(T_base_dataset { })); | |||||
| this->derived_dataset_ids = __impl::make_dataset_id_vector(T_derived_datasets { }); | |||||
| } | |||||
| } } | |||||
| @@ -0,0 +1,39 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| #include "table.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Table for non polymorphic datatypes. | |||||
| */ | |||||
| struct table_simple_t | |||||
| : public table_t | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Value constructor. Creates a mariadb table from the cpphibernate table. | |||||
| * | |||||
| * @param[in] p_owner Owner of the table. | |||||
| * @param[in] p_schema Cpphibernate schema the table belongs to. | |||||
| * @param[in] p_table Cpphibernate table to create mariadb table for. | |||||
| */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| inline table_simple_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_base_dataset&&, | |||||
| const T_derived_datasets&&); | |||||
| }; | |||||
| } } | |||||
| #include "table_simple.inl" | |||||
| @@ -0,0 +1,27 @@ | |||||
| #pragma once | |||||
| #include "table_simple.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* table_simple_t */ | |||||
| template< | |||||
| typename T_schema, | |||||
| typename T_table, | |||||
| typename T_base_dataset, | |||||
| typename T_derived_datasets> | |||||
| table_simple_t::table_simple_t( | |||||
| const schema_t& p_owner, | |||||
| const T_schema& p_schema, | |||||
| const T_table& p_table, | |||||
| const T_base_dataset&&, | |||||
| const T_derived_datasets&&) | |||||
| : table_t( | |||||
| p_owner, | |||||
| p_schema, | |||||
| p_table) | |||||
| { } | |||||
| } } | |||||
| @@ -0,0 +1,38 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include "table.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Vector of tables. | |||||
| */ | |||||
| struct tables_t | |||||
| : public std::vector<table_ptr_u> | |||||
| { | |||||
| using base_type = std::vector<table_ptr_u>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| /** | |||||
| * @brief Helper class to create table vector. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct tables_builder; | |||||
| } | |||||
| /** | |||||
| * @brief Predicate to create table vector. | |||||
| */ | |||||
| constexpr decltype(auto) make_tables = mp::generic_predicate<__impl::tables_builder> { }; | |||||
| } } | |||||
| #include "tables.inl" | |||||
| @@ -0,0 +1,67 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/schema/tables.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include "tables.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| namespace __impl | |||||
| { | |||||
| /* tables_builder */ | |||||
| template<typename X, typename> | |||||
| struct tables_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); } | |||||
| }; | |||||
| template< | |||||
| typename T_owner, | |||||
| typename T_schema> | |||||
| struct tables_builder< | |||||
| mp::list<T_owner, T_schema>, | |||||
| mp::enable_if_t< | |||||
| mp::is_same_v<schema_t, mp::decay_t<T_owner>> | |||||
| && schema::is_schema_v<mp::decay_t<T_schema>>>> | |||||
| { | |||||
| template<typename T_index> | |||||
| static constexpr void emplace( | |||||
| tables_t& result, | |||||
| const schema_t& owner, | |||||
| const T_schema& schema, | |||||
| T_index&& index) | |||||
| { | |||||
| result.emplace_back(make_table(owner, schema, schema.tables[index])); | |||||
| } | |||||
| template<size_t... I> | |||||
| static decltype(auto) helper( | |||||
| const schema_t& owner, | |||||
| const T_schema& schema, | |||||
| std::index_sequence<I...> seq) | |||||
| { | |||||
| tables_t ret; | |||||
| ret.reserve(sizeof...(I)); | |||||
| int dummy[] = { 0, (emplace(ret, owner, schema, hana::size_c<I>), void(), 0)... }; | |||||
| (void) dummy; | |||||
| return ret; | |||||
| } | |||||
| static constexpr decltype(auto) apply( | |||||
| const schema_t& owner, | |||||
| const T_schema& schema) | |||||
| { | |||||
| using size = decltype(hana::size(schema.tables)); | |||||
| return helper(owner, schema, std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } } | |||||
| @@ -1,16 +1,37 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppmariadb.h> | #include <cppmariadb.h> | ||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/impl.h> | |||||
| #include <cpphibernate/driver/mariadb/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| #include "classes.h" | |||||
| // #include <cpphibernate/config.h> | |||||
| // #include <cpphibernate/driver/mariadb/impl.h> | |||||
| // #include <cpphibernate/driver/mariadb/schema.h> | |||||
| // #include <cpphibernate/driver/mariadb/schema/filter.h> | |||||
| struct mariadb_driver_t | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Mariadb driver. | |||||
| */ | |||||
| struct driver_t | |||||
| { | { | ||||
| private: | |||||
| schema_ptr_u _schema; | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. Initializes the driver with the passed schema. | |||||
| */ | |||||
| template<typename T_schema> | |||||
| inline driver_t(T_schema&& p_schema); | |||||
| /** | |||||
| * @brief Print the schema of the driver to the passed stream. | |||||
| */ | |||||
| inline std::ostream& print(std::ostream& os) const; | |||||
| /* | |||||
| public: | public: | ||||
| using lock_type = std::unique_ptr<transaction_lock>; | using lock_type = std::unique_ptr<transaction_lock>; | ||||
| @@ -21,9 +42,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| public: | public: | ||||
| template<typename T_schema> | template<typename T_schema> | ||||
| mariadb_driver_t(T_schema&& p_schema, ::cppmariadb::connection& p_connection) | |||||
| : _connection (&p_connection) | |||||
| , _schema (make_schema(std::forward<T_schema>(p_schema))) | |||||
| mariadb_driver_t(T_schema&& p_schema) | |||||
| : _schema(make_schema(std::forward<T_schema>(p_schema))) | |||||
| { } | { } | ||||
| cpphibernate_copyable(mariadb_driver_t, delete); | cpphibernate_copyable(mariadb_driver_t, delete); | ||||
| @@ -114,7 +134,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| destroy_impl_t<T_dataset>::apply(context); | destroy_impl_t<T_dataset>::apply(context); | ||||
| } | } | ||||
| */ | |||||
| }; | }; | ||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| } } | |||||
| #include "driver.inl" | |||||
| @@ -0,0 +1,16 @@ | |||||
| #pragma once | |||||
| #include "driver.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| template<typename T_schema> | |||||
| driver_t::driver_t(T_schema&& p_schema) | |||||
| : _schema(make_schema(std::forward<T_schema>(p_schema))) | |||||
| { } | |||||
| std::ostream& driver_t::print(std::ostream& os) const | |||||
| { return _schema->print(os); } | |||||
| } } | |||||
| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/driver/mariadb/helper/context.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/key_properties.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/transaction_lock.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/type_properties.h> | |||||
| #include "helper/key_properties.h" | |||||
| #include "helper/type_properties.h" | |||||
| #include "helper/key_properties.h" | |||||
| #include "helper/transaction_lock.h" | |||||
| #include "helper/type_properties.h" | |||||
| @@ -1,42 +1,41 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/types.h> | |||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpputils/container/nullable.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* key_properties */ | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Key type properties for the passed type. | |||||
| * | |||||
| * @tparam T_key Type to get key properties for. | |||||
| */ | |||||
| template<typename T_key, typename = void> | template<typename T_key, typename = void> | ||||
| struct key_properties; | |||||
| template<> | |||||
| struct key_properties<uuid, void> | |||||
| struct key_properties | |||||
| { | { | ||||
| using auto_generated = mp::c_false_t; | |||||
| using key_type = uuid; | |||||
| static constexpr decltype(auto) create_table_argument = ""; | |||||
| static constexpr decltype(auto) create_key_query = "SELECT Uuid()"; | |||||
| static bool is_default(const key_type& key) | |||||
| { return key == key_type(); } | |||||
| using key_type = T_key; | |||||
| /** | |||||
| * @brief Check if the passed key value is the default value. | |||||
| */ | |||||
| static bool is_default(const key_type& key) = delete; | |||||
| /** | |||||
| * @brief Returns true if the key type is auto generated, false otherwise. | |||||
| */ | |||||
| static constexpr bool is_auto_generated() = delete; | |||||
| /** | |||||
| * @brief Returns extra arguments to use for creating the table. | |||||
| */ | |||||
| static constexpr const char * create_table_argument() = delete; | |||||
| /** | |||||
| * @brief Return the query to create a new key value. | |||||
| */ | |||||
| static constexpr const char * create_key_query() = delete; | |||||
| }; | }; | ||||
| template<typename T_key> | |||||
| struct key_properties<T_key, mp::enable_if<mp::is_integral<T_key>>> | |||||
| { | |||||
| using auto_generated = mp::c_true_t; | |||||
| using key_type = T_key; | |||||
| static constexpr decltype(auto) create_table_argument = "AUTO_INCREMENT"; | |||||
| static constexpr decltype(auto) create_key_query = ""; | |||||
| static bool is_default(const key_type& key) | |||||
| { return key == key_type(); } | |||||
| }; | |||||
| } } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| #include "key_properties.inl" | |||||
| @@ -0,0 +1,50 @@ | |||||
| #pragma once | |||||
| #include "key_properties.h" | |||||
| #include <cpphibernate/types.h> | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* key_properties */ | |||||
| template<> | |||||
| struct key_properties<uuid, void> | |||||
| { | |||||
| using key_type = uuid; | |||||
| static bool is_default(const key_type& key) | |||||
| { return key == key_type(); } | |||||
| static constexpr bool is_auto_generated() | |||||
| { return false; } | |||||
| static constexpr const char * create_table_argument() | |||||
| { return nullptr; } | |||||
| static constexpr const char * create_key_query() | |||||
| { return "SELECT Uuid()"; } | |||||
| }; | |||||
| template<typename T_key> | |||||
| struct key_properties< | |||||
| T_key, | |||||
| mp::enable_if_t<mp::is_integral_v<mp::decay_t<T_key>>>> | |||||
| { | |||||
| using key_type = mp::decay_t<T_key>; | |||||
| static bool is_default(const key_type& key) | |||||
| { return key == key_type(); } | |||||
| static constexpr bool is_auto_generated() | |||||
| { return true; } | |||||
| static constexpr const char * create_table_argument() | |||||
| { return "AUTO_INCREMENT"; } | |||||
| static constexpr const char * create_key_query() | |||||
| { return nullptr; } | |||||
| }; | |||||
| } } | |||||
| @@ -0,0 +1,35 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /** | |||||
| * @brief Helper class to manage operations on nullable types. | |||||
| */ | |||||
| template<typename T_nullable, typename = void> | |||||
| struct nullable_helper | |||||
| { | |||||
| using nullable_type = T_nullable; | |||||
| using value_type = real_dataset_t<nullable_type>; | |||||
| /** | |||||
| * @brief Get a pointer to the stored value of the nullable object. | |||||
| */ | |||||
| static value_type* get(const nullable_type&) = delete; | |||||
| /** | |||||
| * @brief Set the new value of the nullable object. | |||||
| */ | |||||
| static value_type& set(nullable_type&, const value_type&) = delete; | |||||
| /** | |||||
| * @brief Destroy the stored value of a nullable objec (clear the nullable object). | |||||
| */ | |||||
| static void clear(nullable_type&) = delete; | |||||
| }; | |||||
| } } | |||||
| #include "nullable_helper.inl" | |||||
| @@ -0,0 +1,75 @@ | |||||
| #include "nullable_helper.h" | |||||
| #include <memory> | |||||
| #include <cppcore/misc/nullable.h> | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* nullable_helper - cppcore::nullable */ | |||||
| template<typename T_value> | |||||
| struct nullable_helper<cppcore::nullable<T_value>, void> | |||||
| { | |||||
| using nullable_type = cppcore::nullable<T_value>; | |||||
| using value_type = T_value; | |||||
| static inline value_type* get(nullable_type& x) | |||||
| { return x.has_value() ? &x.value() : nullptr; } | |||||
| static inline const value_type* get(const nullable_type& x) | |||||
| { return x.has_value() ? &x.value() : nullptr; } | |||||
| static inline value_type& set(nullable_type& x, const value_type* value) | |||||
| { return *(x = *value); } | |||||
| static inline value_type& set(nullable_type& x, const value_type& value) | |||||
| { return *(x = value); } | |||||
| static inline value_type& set(nullable_type& x, value_type&& value) | |||||
| { return *(x = std::move(value)); } | |||||
| static void clear(nullable_type& x) | |||||
| { x.reset(); } | |||||
| }; | |||||
| /* nullable_helper - std::unique_ptr/std::shared_ptr */ | |||||
| template<typename T> | |||||
| struct nullable_helper< | |||||
| T, | |||||
| mp::enable_if_t< | |||||
| mp::is_specialization_of_v<T, std::unique_ptr> | |||||
| || mp::is_specialization_of_v<T, std::shared_ptr>>> | |||||
| { | |||||
| using nullable_type = T; | |||||
| using value_type = typename nullable_type::element_type; | |||||
| static inline value_type* get(const nullable_type& x) | |||||
| { return x.get(); } | |||||
| static inline value_type& set(nullable_type& x, value_type* value) | |||||
| { | |||||
| x.reset(value); | |||||
| return *x; | |||||
| } | |||||
| static inline value_type& set(nullable_type& x, const value_type& value) | |||||
| { | |||||
| x.reset(new value_type(value)); | |||||
| return *x; | |||||
| } | |||||
| static inline value_type& set(nullable_type& x, value_type&& value) | |||||
| { | |||||
| x.reset(new value_type(std::move(value))); | |||||
| return *x; | |||||
| } | |||||
| static void clear(nullable_type& x) | |||||
| { return x.reset(); } | |||||
| }; | |||||
| } } | |||||
| @@ -1,583 +1,60 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpputils/misc/enum.h> | |||||
| #include <cpputils/misc/flags.h> | |||||
| #include <cpputils/misc/string.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/types.h> | |||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpputils/container/nullable.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* value_t */ | |||||
| #include <cppcore/misc/nullable.h> | |||||
| using value_t = utl::nullable<std::string>; | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| /* type_properties */ | |||||
| /** | |||||
| * @brief Value received from the database. | |||||
| */ | |||||
| using value_t = cppcore::nullable<std::string>; | |||||
| /** | |||||
| * @brief Type properties for the passed type. | |||||
| * | |||||
| * @tparam T Type to get properties for. | |||||
| */ | |||||
| template<typename T, typename = void> | template<typename T, typename = void> | ||||
| struct type_properties | struct type_properties | ||||
| { | { | ||||
| static constexpr void type () = delete; | |||||
| static T convert_to (const value_t&) = delete; | |||||
| static value_t convert_from (const T&) = delete; | |||||
| static constexpr const char* convert_to_open () = delete; | |||||
| static constexpr const char* convert_to_close () = delete; | |||||
| static constexpr const char* convert_from_open () = delete; | |||||
| static constexpr const char* convert_from_close() = delete; | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<bool, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BOOLEAN"; } | |||||
| static inline bool convert_to(const value_t& value) | |||||
| { return utl::from_string<int>(*value); } | |||||
| static inline value_t convert_from(const bool& value) | |||||
| { return utl::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint8_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "TINYINT UNSIGNED"; } | |||||
| static inline uint8_t convert_to(const value_t& value) | |||||
| { return static_cast<uint8_t>(utl::from_string<int>(*value)); } | |||||
| static inline value_t convert_from(const uint8_t& value) | |||||
| { return utl::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int8_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "TINYINT"; } | |||||
| static inline int8_t convert_to(const value_t& value) | |||||
| { return static_cast<int8_t>(utl::from_string<int>(*value)); } | |||||
| static inline value_t convert_from(const int8_t& value) | |||||
| { return utl::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint16_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "SMALLINT UNSIGNED"; } | |||||
| static inline uint16_t convert_to(const value_t& value) | |||||
| { return utl::from_string<uint16_t>(*value); } | |||||
| static inline value_t convert_from(const uint16_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int16_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "SMALLINT"; } | |||||
| static inline int16_t convert_to(const value_t& value) | |||||
| { return utl::from_string<int16_t>(*value); } | |||||
| static inline value_t convert_from(const int16_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint32_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "INT UNSIGNED"; } | |||||
| static inline uint32_t convert_to(const value_t& value) | |||||
| { return utl::from_string<uint32_t>(*value); } | |||||
| static inline value_t convert_from(const uint32_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int32_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "INT"; } | |||||
| static inline int32_t convert_to(const value_t& value) | |||||
| { return utl::from_string<int32_t>(*value); } | |||||
| static inline value_t convert_from(const int32_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint64_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT UNSIGNED"; } | |||||
| static inline uint64_t convert_to(const value_t& value) | |||||
| { return utl::from_string<uint64_t>(*value); } | |||||
| static inline value_t convert_from(const uint64_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int64_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT"; } | |||||
| static inline int64_t convert_to(const value_t& value) | |||||
| { return utl::from_string<int64_t>(*value); } | |||||
| static inline value_t convert_from(const int64_t& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<float, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "FLOAT"; } | |||||
| static inline float convert_to(const value_t& value) | |||||
| { return utl::from_string<float>(*value); } | |||||
| static inline value_t convert_from(const float& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<double, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "DOUBLE"; } | |||||
| static inline double convert_to(const value_t& value) | |||||
| { return utl::from_string<double>(*value); } | |||||
| static inline value_t convert_from(const double& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uuid, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BINARY(16)"; } | |||||
| static inline uuid convert_to(const value_t& value) | |||||
| { return utl::from_string<uuid>(*value); } | |||||
| static inline value_t convert_from(const uuid& value) | |||||
| { return utl::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return "UuidToBin("; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return ")"; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return "BinToUuid("; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return ")"; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<timestamp, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT"; } | |||||
| static inline timestamp convert_to(const value_t& value) | |||||
| { return timestamp(utl::from_string<uint64_t>(*value)); } | |||||
| static inline value_t convert_from(const timestamp& value) | |||||
| { return utl::to_string(static_cast<uint64_t>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<std::string, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "VARCHAR(100)"; } | |||||
| /** | |||||
| * @brief Get the mariadb type. | |||||
| */ | |||||
| static constexpr const char * type() = delete; | |||||
| static inline std::string convert_to(const value_t& value) | |||||
| { return *value; } | |||||
| /** | |||||
| * @brief Convert a value from the database to its actual type. | |||||
| */ | |||||
| static T convert_to(const value_t&) = delete; | |||||
| static inline value_t convert_from(const std::string& value) | |||||
| { return value; } | |||||
| /** | |||||
| * @brief Convert the actual value to a database value. | |||||
| */ | |||||
| static value_t convert_from(const T&) = delete; | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| /** | |||||
| * @brief Get the string to start the "convert to" operation. | |||||
| */ | |||||
| static constexpr const char * convert_to_open() = delete; | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| /** | |||||
| * @brief Get the string to end the "convert to" operation. | |||||
| */ | |||||
| static constexpr const char * convert_to_close() = delete; | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| /** | |||||
| * @brief Get the string to start the "convert from" operation. | |||||
| */ | |||||
| static constexpr const char * convert_from_open() = delete; | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| /** | |||||
| * @brief Get the string to end the "convert from" operation. | |||||
| */ | |||||
| static constexpr const char * convert_from_close() = delete; | |||||
| }; | }; | ||||
| template<size_t N> | |||||
| struct type_properties<string<N>, void> | |||||
| { | |||||
| static inline std::string make_type() | |||||
| { return std::string("VARCHAR(") + utl::to_string(N) + ")"; } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline std::string convert_to(const value_t& value) | |||||
| { return *value; } | |||||
| static inline value_t convert_from(const std::string& value) | |||||
| { return value; } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if<misc::is_nullable<mp::decay_t<T>>>> | |||||
| { | |||||
| using nullable_type = T; | |||||
| using nullable_helper_type = misc::nullable_helper<nullable_type>; | |||||
| using value_type = typename nullable_helper_type::value_type; | |||||
| using value_type_props = type_properties<value_type>; | |||||
| static constexpr decltype(auto) type() | |||||
| { return value_type_props::type(); } | |||||
| static inline nullable_type convert_to(const value_t& value) | |||||
| { | |||||
| nullable_type ret; | |||||
| if (value.has_value()) | |||||
| nullable_helper_type::set(ret, value_type_props::convert_to(value)); | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const nullable_type& value) | |||||
| { | |||||
| value_t ret; | |||||
| auto v = nullable_helper_type::get(value); | |||||
| if (v) | |||||
| ret = value_type_props::convert_from(*v); | |||||
| return ret; | |||||
| } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if<std::is_enum<mp::clean_type<T>>>> | |||||
| { | |||||
| using enum_type = T; | |||||
| using base_type = typename std::underlying_type<enum_type>::type; | |||||
| static std::string make_type() | |||||
| { | |||||
| std::ostringstream os; | |||||
| os << "ENUM ( "; | |||||
| auto e = enum_type::first; | |||||
| while (e <= enum_type::last) | |||||
| { | |||||
| if (e != enum_type::first) | |||||
| os << ", "; | |||||
| os << "'" << utl::enum_conversion<enum_type>::to_string(e, false) << "'"; | |||||
| e = static_cast<enum_type>(static_cast<base_type>(e) + 1); | |||||
| } | |||||
| os << " )"; | |||||
| return os.str(); | |||||
| } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline enum_type convert_to(const value_t& value) | |||||
| { | |||||
| enum_type ret; | |||||
| if (!utl::enum_conversion<enum_type>::try_to_enum(*value, ret, false)) | |||||
| throw misc::hibernate_exception("unable to convert enum value!"); | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const enum_type& value) | |||||
| { return utl::enum_conversion<enum_type>::to_string(value, false); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if<mp::is_specialization_of<mp::clean_type<T>, utl::flags>>> | |||||
| { | |||||
| using flags_type = T; | |||||
| using enum_type = typename flags_type::enum_type; | |||||
| using base_type = typename std::underlying_type<enum_type>::type; | |||||
| static inline std::string make_type() | |||||
| { | |||||
| std::ostringstream os; | |||||
| os << "SET ( "; | |||||
| auto e = enum_type::first; | |||||
| while (e <= enum_type::last) | |||||
| { | |||||
| if (e != enum_type::first) | |||||
| os << ", "; | |||||
| os << "'" << utl::to_string(e) << "'"; | |||||
| e = static_cast<enum_type>(static_cast<base_type>(e) + 1); | |||||
| } | |||||
| os << " )"; | |||||
| return os.str(); | |||||
| } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline flags_type convert_to(const value_t& value) | |||||
| { | |||||
| auto s = *value; | |||||
| auto c = s.c_str(); | |||||
| auto e = c + s.size(); | |||||
| auto p = c; | |||||
| flags_type ret; | |||||
| while (c <= e) | |||||
| { | |||||
| if (c == e || *c == ',') | |||||
| { | |||||
| if (c - p > 0) | |||||
| ret.set(utl::enum_conversion<enum_type>::to_enum(std::string(p, static_cast<size_t>(c - p)), true)); | |||||
| p = c + 1; | |||||
| } | |||||
| ++c; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const flags_type& value) | |||||
| { | |||||
| std::ostringstream os; | |||||
| bool first = true; | |||||
| for (auto e : value) | |||||
| { | |||||
| if (first) first = false; | |||||
| else os << ","; | |||||
| os << utl::enum_conversion<enum_type>::to_string(e, false); | |||||
| } | |||||
| return os.str(); | |||||
| } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| } } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| #include "type_properties.inl" | |||||
| @@ -0,0 +1,563 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/types.h> | |||||
| #include <cppcore/conversion/string.h> | |||||
| #include "type_properties.h" | |||||
| #include "nullable_helper.h" | |||||
| namespace cpphibernate { | |||||
| namespace mariadb { | |||||
| template<> | |||||
| struct type_properties<bool, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BOOLEAN"; } | |||||
| static inline bool convert_to(const value_t& value) | |||||
| { return cppcore::from_string<int>(*value); } | |||||
| static inline value_t convert_from(const bool& value) | |||||
| { return cppcore::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint8_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "TINYINT UNSIGNED"; } | |||||
| static inline uint8_t convert_to(const value_t& value) | |||||
| { return static_cast<uint8_t>(cppcore::from_string<int>(*value)); } | |||||
| static inline value_t convert_from(const uint8_t& value) | |||||
| { return cppcore::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int8_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "TINYINT"; } | |||||
| static inline int8_t convert_to(const value_t& value) | |||||
| { return static_cast<int8_t>(cppcore::from_string<int>(*value)); } | |||||
| static inline value_t convert_from(const int8_t& value) | |||||
| { return cppcore::to_string(static_cast<int>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint16_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "SMALLINT UNSIGNED"; } | |||||
| static inline uint16_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<uint16_t>(*value); } | |||||
| static inline value_t convert_from(const uint16_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int16_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "SMALLINT"; } | |||||
| static inline int16_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<int16_t>(*value); } | |||||
| static inline value_t convert_from(const int16_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint32_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "INT UNSIGNED"; } | |||||
| static inline uint32_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<uint32_t>(*value); } | |||||
| static inline value_t convert_from(const uint32_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int32_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "INT"; } | |||||
| static inline int32_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<int32_t>(*value); } | |||||
| static inline value_t convert_from(const int32_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uint64_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT UNSIGNED"; } | |||||
| static inline uint64_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<uint64_t>(*value); } | |||||
| static inline value_t convert_from(const uint64_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<int64_t, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT"; } | |||||
| static inline int64_t convert_to(const value_t& value) | |||||
| { return cppcore::from_string<int64_t>(*value); } | |||||
| static inline value_t convert_from(const int64_t& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<float, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "FLOAT"; } | |||||
| static inline float convert_to(const value_t& value) | |||||
| { return cppcore::from_string<float>(*value); } | |||||
| static inline value_t convert_from(const float& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<double, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "DOUBLE"; } | |||||
| static inline double convert_to(const value_t& value) | |||||
| { return cppcore::from_string<double>(*value); } | |||||
| static inline value_t convert_from(const double& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<uuid, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BINARY(16)"; } | |||||
| static inline uuid convert_to(const value_t& value) | |||||
| { return cppcore::from_string<uuid>(*value); } | |||||
| static inline value_t convert_from(const uuid& value) | |||||
| { return cppcore::to_string(value); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return "UuidToBin("; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return ")"; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return "BinToUuid("; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return ")"; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<timestamp, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "BIGINT"; } | |||||
| static inline timestamp convert_to(const value_t& value) | |||||
| { return timestamp(cppcore::from_string<uint64_t>(*value)); } | |||||
| static inline value_t convert_from(const timestamp& value) | |||||
| { return cppcore::to_string(static_cast<uint64_t>(value)); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<> | |||||
| struct type_properties<std::string, void> | |||||
| { | |||||
| static constexpr decltype(auto) type() | |||||
| { return "VARCHAR(100)"; } | |||||
| static inline std::string convert_to(const value_t& value) | |||||
| { return *value; } | |||||
| static inline value_t convert_from(const std::string& value) | |||||
| { return value; } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<size_t N> | |||||
| struct type_properties<string<N>, void> | |||||
| { | |||||
| static inline std::string make_type() | |||||
| { return std::string("VARCHAR(") + cppcore::to_string(N) + ")"; } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline std::string convert_to(const value_t& value) | |||||
| { return *value; } | |||||
| static inline value_t convert_from(const std::string& value) | |||||
| { return value; } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if_t<is_nullable_v<mp::decay_t<T>>>> | |||||
| { | |||||
| using nullable_type = T; | |||||
| using nullable_helper_type = nullable_helper<nullable_type>; | |||||
| using value_type = typename nullable_helper_type::value_type; | |||||
| static constexpr decltype(auto) nullable = nullable_helper_type { }; | |||||
| static constexpr decltype(auto) value_props = type_properties<value_type> { }; | |||||
| static constexpr decltype(auto) type() | |||||
| { return value_props.type(); } | |||||
| static inline decltype(auto) convert_to(const value_t& value) | |||||
| { | |||||
| nullable_type ret; | |||||
| if (value.has_value()) | |||||
| nullable.set(ret, value_props.convert_to(value)); | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const nullable_type& value) | |||||
| { | |||||
| value_t ret; | |||||
| auto v = nullable.get(value); | |||||
| if (v) | |||||
| ret = value_props.convert_from(*v); | |||||
| return ret; | |||||
| } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return value_props.convert_to_open(); } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return value_props.convert_to_close(); } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return value_props.convert_from_open(); } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return value_props.convert_from_close(); } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if_t<mp::is_enum_v<mp::decay_t<T>>>> | |||||
| { | |||||
| using enum_type = T; | |||||
| using base_type = typename std::underlying_type<enum_type>::type; | |||||
| static std::string make_type() | |||||
| { | |||||
| std::ostringstream os; | |||||
| os << "ENUM ( "; | |||||
| auto e = enum_type::first; | |||||
| while (e <= enum_type::last) | |||||
| { | |||||
| if (e != enum_type::first) | |||||
| os << ", "; | |||||
| os << "'" << cppcore::enum_conversion<enum_type>::to_string(e, false) << "'"; | |||||
| e = static_cast<enum_type>(static_cast<base_type>(e) + 1); | |||||
| } | |||||
| os << " )"; | |||||
| return os.str(); | |||||
| } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline enum_type convert_to(const value_t& value) | |||||
| { | |||||
| enum_type ret; | |||||
| if (!cppcore::enum_conversion<enum_type>::try_to_enum(*value, ret, false)) | |||||
| throw exception("unable to convert enum value!"); | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const enum_type& value) | |||||
| { return cppcore::enum_conversion<enum_type>::to_string(value, false); } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct type_properties<T, mp::enable_if_t<mp::is_specialization_of_v<mp::decay_t<T>, cppcore::flags>>> | |||||
| { | |||||
| using flags_type = T; | |||||
| using enum_type = typename flags_type::enum_type; | |||||
| using base_type = typename std::underlying_type<enum_type>::type; | |||||
| static inline std::string make_type() | |||||
| { | |||||
| std::ostringstream os; | |||||
| os << "SET ( "; | |||||
| auto e = enum_type::first; | |||||
| while (e <= enum_type::last) | |||||
| { | |||||
| if (e != enum_type::first) | |||||
| os << ", "; | |||||
| os << "'" << cppcore::to_string(e) << "'"; | |||||
| e = static_cast<enum_type>(static_cast<base_type>(e) + 1); | |||||
| } | |||||
| os << " )"; | |||||
| return os.str(); | |||||
| } | |||||
| static inline decltype(auto) type() | |||||
| { | |||||
| static const std::string v = make_type(); | |||||
| return v; | |||||
| } | |||||
| static inline flags_type convert_to(const value_t& value) | |||||
| { | |||||
| auto s = *value; | |||||
| auto c = s.c_str(); | |||||
| auto e = c + s.size(); | |||||
| auto p = c; | |||||
| flags_type ret; | |||||
| while (c <= e) | |||||
| { | |||||
| if (c == e || *c == ',') | |||||
| { | |||||
| if (c - p > 0) | |||||
| ret.set(cppcore::enum_conversion<enum_type>::to_enum(std::string(p, static_cast<size_t>(c - p)), true)); | |||||
| p = c + 1; | |||||
| } | |||||
| ++c; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| static inline value_t convert_from(const flags_type& value) | |||||
| { | |||||
| std::ostringstream os; | |||||
| bool first = true; | |||||
| for (auto e : value) | |||||
| { | |||||
| if (first) first = false; | |||||
| else os << ","; | |||||
| os << cppcore::enum_conversion<enum_type>::to_string(e, false); | |||||
| } | |||||
| return os.str(); | |||||
| } | |||||
| static constexpr const char* convert_to_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_to_close() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_open() | |||||
| { return nullptr; } | |||||
| static constexpr const char* convert_from_close() | |||||
| { return nullptr; } | |||||
| }; | |||||
| } } | |||||
| @@ -1,24 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.inl> | |||||
| @@ -1,34 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* attribute_t */ | |||||
| enum class attribute_t | |||||
| { | |||||
| hex, | |||||
| compress, | |||||
| primary_key, | |||||
| }; | |||||
| /* attributes_t */ | |||||
| struct attributes_t; | |||||
| /* make_attributes */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_attributes_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::make_attributes_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,23 +0,0 @@ | |||||
| #pragma once | |||||
| #include <set> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/schema/attributes.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* attributes_t */ | |||||
| struct attributes_t : | |||||
| public std::set<attribute_t> | |||||
| { | |||||
| using base_type = std::set<attribute_t>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,31 +0,0 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* field_t */ | |||||
| struct field_t; | |||||
| /* field_ptr_t */ | |||||
| using field_ptr_t = std::unique_ptr<field_t>; | |||||
| /* make_field */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_field_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::make_field_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,213 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/schema/field.h> | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/helper.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* field_t */ | |||||
| struct field_t | |||||
| { | |||||
| public: | |||||
| size_t id { 0 }; // unique id of the field | |||||
| size_t dataset_id { 0 }; // unique id of the dataset type | |||||
| size_t real_dataset_id { 0 }; // unique id of the real/unwrapped dataset type | |||||
| size_t value_id { 0 }; // unique id of the value type | |||||
| size_t real_value_id { 0 }; // unique id of the real/unwrapped value type | |||||
| bool value_is_nullable { false }; // value is stored in a nullable container | |||||
| bool value_is_pointer { false }; // value is stored in a pointer container | |||||
| bool value_is_container { false }; // value is stored in a container | |||||
| bool value_is_ordered { false }; // value is stored in a ordered container (vector, list, ...) | |||||
| bool value_is_auto_incremented { false }; // value is a auto incremented field | |||||
| table_t* table { nullptr }; // table this field belongs to | |||||
| table_t* referenced_table { nullptr }; // table that belongs to the value (if exists) | |||||
| std::string schema_name; // name of the SQL schema | |||||
| std::string table_name; // name of the SQL table | |||||
| std::string field_name; // name of the SQL field | |||||
| std::string type; // SQL type name | |||||
| std::string create_arguments; // additional arguments for CREATE TABLE command | |||||
| std::string convert_to_open; // SQL code to open the "convert to" operation | |||||
| std::string convert_to_close; // SQL code to close the "convert to" operation | |||||
| std::string convert_from_open; // SQL code to open the "convert from" operation | |||||
| std::string convert_from_close; // SQL code to close the "convert from" operation | |||||
| attributes_t attributes; // attributes for the field | |||||
| inline field_t() = default; | |||||
| inline field_t(const field_t&) = delete; | |||||
| inline field_t(field_t&& other) | |||||
| : id (std::move(other).id) | |||||
| , dataset_id (std::move(other).dataset_id) | |||||
| , real_dataset_id (std::move(other).real_dataset_id) | |||||
| , value_id (std::move(other).value_id) | |||||
| , real_value_id (std::move(other).real_value_id) | |||||
| , value_is_nullable (std::move(other).value_is_nullable) | |||||
| , value_is_pointer (std::move(other).value_is_pointer) | |||||
| , value_is_container (std::move(other).value_is_container) | |||||
| , value_is_auto_incremented (std::move(other).value_is_auto_incremented) | |||||
| , table (nullptr) | |||||
| , referenced_table (nullptr) | |||||
| , schema_name (std::move(other).schema_name) | |||||
| , table_name (std::move(other).table_name) | |||||
| , field_name (std::move(other).field_name) | |||||
| , type (std::move(other).type) | |||||
| , create_arguments (std::move(other).create_arguments) | |||||
| , convert_to_open (std::move(other).convert_to_open) | |||||
| , convert_to_close (std::move(other).convert_to_close) | |||||
| , convert_from_open (std::move(other).convert_from_open) | |||||
| , convert_from_close (std::move(other).convert_from_close) | |||||
| , attributes (std::move(other).attributes) | |||||
| { } | |||||
| virtual ~field_t() { }; | |||||
| void print (std::ostream& os) const; | |||||
| virtual void update (); | |||||
| /* CRUD */ | |||||
| using read_context_ptr = std::unique_ptr<read_context>; | |||||
| virtual value_t foreign_create_update (const create_update_context& context) const; | |||||
| virtual read_context_ptr foreign_read (const read_context& context, bool fake_context) const; | |||||
| /* properties */ | |||||
| virtual value_t get (const data_context& context) const; | |||||
| virtual void set (const data_context& context, const value_t&) const; | |||||
| virtual bool is_default (const data_context& context) const; | |||||
| virtual std::string generate_value (::cppmariadb::connection& connection) const; | |||||
| /* statements */ | |||||
| virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const; | |||||
| virtual ::cppmariadb::statement& get_statement_foreign_many_update() const; | |||||
| protected: | |||||
| using statement_ptr = std::unique_ptr<::cppmariadb::statement>; | |||||
| ::cppmariadb::statement& get_statement_foreign_one_delete_impl(bool key_known, statement_ptr& known, statement_ptr& unknown) const; | |||||
| ::cppmariadb::statement& get_statement_foreign_many_update_impl(statement_ptr& statement) const; | |||||
| }; | |||||
| /* simple_field_t */ | |||||
| template<typename T_field> | |||||
| struct simple_field_t | |||||
| : public field_t | |||||
| { | |||||
| using base_type = field_t; | |||||
| using field_type = mp::decay_t<T_field>; | |||||
| using getter_type = typename field_type::getter_type; | |||||
| using dataset_type = mp::decay_t<typename getter_type::dataset_type>; | |||||
| using real_dataset_type = misc::real_dataset_t<dataset_type>; | |||||
| using value_type = mp::decay_t<typename getter_type::value_type>; | |||||
| using real_value_type = misc::real_dataset_t<value_type>; | |||||
| using type_props = type_properties<value_type>; | |||||
| const field_type& field; | |||||
| inline simple_field_t(const field_type& p_field) | |||||
| : field_t () | |||||
| , field (p_field) | |||||
| { } | |||||
| virtual void update() override; | |||||
| }; | |||||
| /* value_field_t */ | |||||
| template<typename T_field> | |||||
| struct value_field_t | |||||
| : public simple_field_t<T_field> | |||||
| { | |||||
| using base_type = simple_field_t<T_field>; | |||||
| using field_type = typename base_type::field_type; | |||||
| using getter_type = typename base_type::getter_type; | |||||
| using dataset_type = typename base_type::dataset_type; | |||||
| using real_dataset_type = typename base_type::dataset_type; | |||||
| using value_type = typename base_type::value_type; | |||||
| using real_value_type = typename base_type::real_value_type; | |||||
| using type_props = typename base_type::type_props; | |||||
| using base_type::base_type; | |||||
| static_assert(mp::is_same<dataset_type, real_dataset_type>::value, "internal error: dataset type mismatch!"); | |||||
| virtual void update () override; | |||||
| virtual value_t get (const data_context& context) const override; | |||||
| virtual void set (const data_context& context, const value_t& value) const override; | |||||
| }; | |||||
| /* primary_key_field_t */ | |||||
| template<typename T_field> | |||||
| struct primary_key_field_t | |||||
| : public value_field_t<T_field> | |||||
| { | |||||
| using base_type = value_field_t<T_field>; | |||||
| using field_type = typename base_type::field_type; | |||||
| using dataset_type = typename base_type::dataset_type; | |||||
| using value_type = typename base_type::value_type; | |||||
| using key_props = key_properties<value_type>; | |||||
| using base_type::base_type; | |||||
| virtual void update () override; | |||||
| virtual bool is_default (const data_context& context) const override; | |||||
| virtual std::string generate_value(::cppmariadb::connection& connection) const override; | |||||
| }; | |||||
| /* data_field_t */ | |||||
| template<typename T_field> | |||||
| struct data_field_t | |||||
| : public value_field_t<T_field> | |||||
| { | |||||
| using base_type = value_field_t<T_field>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| /* foreign_table_field_t */ | |||||
| template<typename T_field> | |||||
| struct foreign_table_field_t | |||||
| : public simple_field_t<T_field> | |||||
| { | |||||
| public: | |||||
| using base_type = simple_field_t<T_field>; | |||||
| using value_type = typename base_type::value_type; | |||||
| using real_value_type = typename base_type::real_value_type; | |||||
| using dataset_type = typename base_type::dataset_type; | |||||
| using base_type::base_type; | |||||
| public: | |||||
| /* CRUD */ | |||||
| virtual value_t foreign_create_update(const create_update_context& context) const override; | |||||
| virtual read_context_ptr foreign_read (const read_context& context, bool fake_context) const override; | |||||
| /* statements */ | |||||
| virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const override; | |||||
| virtual ::cppmariadb::statement& get_statement_foreign_many_update() const override; | |||||
| private: | |||||
| using statement_ptr = std::unique_ptr<::cppmariadb::statement>; | |||||
| mutable statement_ptr _statement_foreign_one_delete_key_known; | |||||
| mutable statement_ptr _statement_foreign_one_delete_key_unknown; | |||||
| mutable statement_ptr _statement_foreign_many_update; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,228 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/field.h> | |||||
| #include <cpphibernate/driver/mariadb/impl/create_update.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* simple_field_t */ | |||||
| template<typename T_field> | |||||
| void simple_field_t<T_field> | |||||
| ::update() | |||||
| { | |||||
| base_type::update(); | |||||
| id = misc::get_type_id(hana::type_c<field_type>); | |||||
| dataset_id = misc::get_type_id(hana::type_c<dataset_type>); | |||||
| real_dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>); | |||||
| value_id = misc::get_type_id(hana::type_c<value_type>); | |||||
| real_value_id = misc::get_type_id(hana::type_c<real_value_type>); | |||||
| value_is_nullable = misc::is_nullable<value_type>::value; | |||||
| value_is_pointer = misc::is_pointer<value_type>::value; | |||||
| value_is_container = misc::is_container<value_type>::value; | |||||
| value_is_ordered = misc::is_ordered<value_type>::value; | |||||
| } | |||||
| /* value_field_t */ | |||||
| template<typename T_field> | |||||
| void value_field_t<T_field> | |||||
| ::update() | |||||
| { | |||||
| base_type::update(); | |||||
| this->type = type_props::type(); | |||||
| if (type_props::convert_to_open()) | |||||
| this->convert_to_open = this->convert_to_open + type_props::convert_to_open(); | |||||
| if (type_props::convert_to_close()) | |||||
| this->convert_to_close = type_props::convert_to_close() + this->convert_to_close; | |||||
| if (type_props::convert_from_open()) | |||||
| this->convert_from_open = this->convert_from_open + type_props::convert_from_open(); | |||||
| if (type_props::convert_from_close()) | |||||
| this->convert_from_close = type_props::convert_from_close() + this->convert_from_close; | |||||
| } | |||||
| template<typename T_field> | |||||
| value_t value_field_t<T_field> | |||||
| ::get(const data_context& context) const | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| return type_props::convert_from(this->field.getter(dataset)); | |||||
| } | |||||
| template<typename T_field> | |||||
| void value_field_t<T_field> | |||||
| ::set(const data_context& context, const value_t& value) const | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| this->field.setter(dataset, type_props::convert_to(value)); | |||||
| } | |||||
| /* primary_key_field_t */ | |||||
| template<typename T_field> | |||||
| void primary_key_field_t<T_field> | |||||
| ::update() | |||||
| { | |||||
| base_type::update(); | |||||
| this->value_is_auto_incremented = key_props::auto_generated::value; | |||||
| } | |||||
| template<typename T_field> | |||||
| bool primary_key_field_t<T_field> | |||||
| ::is_default(const data_context& context) const | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| return key_props::is_default(this->field.getter(dataset)); | |||||
| } | |||||
| template<typename T_field> | |||||
| std::string primary_key_field_t<T_field> | |||||
| ::generate_value(::cppmariadb::connection& connection) const | |||||
| { | |||||
| auto ret = connection.execute_used(key_props::create_key_query); | |||||
| if (!ret || !ret->next()) | |||||
| throw misc::hibernate_exception("unable to generate key value!"); | |||||
| return ret->current()->at(0).template get<std::string>(); | |||||
| } | |||||
| /* foreign_table_field_t */ | |||||
| template<typename T_field> | |||||
| value_t foreign_table_field_t<T_field> | |||||
| ::foreign_create_update(const create_update_context& context) const | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto& foreign = this->field.getter(dataset); | |||||
| auto next_context = change_context(context, foreign); | |||||
| using foreign_dataset_type = mp::decay_t<decltype(foreign)>; | |||||
| return create_update_impl_t<foreign_dataset_type>::apply( | |||||
| next_context, | |||||
| false); | |||||
| } | |||||
| template<typename T_field> | |||||
| read_context_ptr foreign_table_field_t<T_field> | |||||
| ::foreign_read(const read_context& context, bool fake_context) const | |||||
| { | |||||
| if (!fake_context) | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto& member = this->field.getter(dataset); | |||||
| auto new_context = make_read_context(member, context.schema, context.connection, context.filter); | |||||
| using context_type = mp::decay_t<decltype(new_context)>; | |||||
| return std::make_unique<context_type>(new_context); | |||||
| } | |||||
| else | |||||
| { | |||||
| auto new_context = make_fake_context(hana::type_c<value_type>, context.schema, context.connection, context.filter); | |||||
| using context_type = mp::decay_t<decltype(new_context)>; | |||||
| return std::make_unique<context_type>(new_context); | |||||
| } | |||||
| } | |||||
| template<typename T_field> | |||||
| ::cppmariadb::statement& foreign_table_field_t<T_field> | |||||
| ::get_statement_foreign_one_delete(bool key_known) const | |||||
| { | |||||
| return base_type::get_statement_foreign_one_delete_impl( | |||||
| key_known, | |||||
| _statement_foreign_one_delete_key_known, | |||||
| _statement_foreign_one_delete_key_unknown); | |||||
| } | |||||
| template<typename T_field> | |||||
| ::cppmariadb::statement& foreign_table_field_t<T_field> | |||||
| ::get_statement_foreign_many_update() const | |||||
| { return base_type::get_statement_foreign_many_update_impl(_statement_foreign_many_update); } | |||||
| namespace __impl | |||||
| { | |||||
| /* is_primary_key_field */ | |||||
| template<typename T_field> | |||||
| struct is_primary_key_field | |||||
| : public mp::decay_t<decltype( | |||||
| hana::contains( | |||||
| std::declval<T_field>().attributes, | |||||
| schema::attribute::primary_key))> | |||||
| { }; | |||||
| /* is_foreign_table_field */ | |||||
| template<typename T_schema, typename T_field> | |||||
| struct is_foreign_table_field | |||||
| : public mp::decay_t<decltype( | |||||
| hana::contains( | |||||
| hana::transform( | |||||
| std::declval<T_schema>().tables, | |||||
| schema::table::get_wrapped_dataset), | |||||
| hana::type_c<misc::real_dataset_t<typename T_field::getter_type::value_type>>))> | |||||
| { }; | |||||
| /* field_type */ | |||||
| template<typename T_schema, typename T_field, typename = void> | |||||
| struct field_type | |||||
| { using type = data_field_t<T_field>; }; | |||||
| template<typename T_schema, typename T_field> | |||||
| struct field_type<T_schema, T_field, mp::enable_if<is_primary_key_field<T_field>>> | |||||
| { using type = primary_key_field_t<T_field>; }; | |||||
| template<typename T_schema, typename T_field> | |||||
| struct field_type<T_schema, T_field, mp::enable_if<is_foreign_table_field<T_schema, T_field>>> | |||||
| { using type = foreign_table_field_t<T_field>; }; | |||||
| template<typename T_schema, typename T_field> | |||||
| using field_type_t = typename field_type<T_schema, T_field>::type; | |||||
| /* make_field_impl */ | |||||
| template<typename T, typename> | |||||
| struct make_field_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); } | |||||
| }; | |||||
| template<typename T_schema, typename T_table, typename T_field> | |||||
| struct make_field_impl< | |||||
| mp::list<T_schema, T_table, T_field>, | |||||
| mp::enable_if_c< | |||||
| schema::is_schema<mp::decay_t<T_schema>>::value | |||||
| && schema::is_table <mp::decay_t<T_table >>::value | |||||
| && schema::is_field <mp::decay_t<T_field >>::value>> | |||||
| { | |||||
| static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table, const T_field& field) | |||||
| { | |||||
| using schema_type = mp::decay_t<T_schema>; | |||||
| using field_type = mp::decay_t<T_field>; | |||||
| using return_type = field_type_t<schema_type, field_type>; | |||||
| using primary_key_type = primary_key_field_t<field_type>; | |||||
| return_type ret(field); | |||||
| ret.schema_name = schema.name; | |||||
| ret.table_name = table.name; | |||||
| ret.field_name = field.name; | |||||
| ret.attributes = make_attributes(field.attributes); | |||||
| hana::eval_if( | |||||
| hana::equal(hana::type_c<return_type>, hana::type_c<primary_key_type>), | |||||
| [&ret](){ | |||||
| ret.field_name = ret.table_name + "_" + ret.field_name; | |||||
| }, [](){ }); | |||||
| return ret; | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,29 +0,0 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* fields_t */ | |||||
| struct fields_t; | |||||
| /* make_fields */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_fields_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::make_fields_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,25 +0,0 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* fields_t */ | |||||
| struct fields_t | |||||
| : public std::vector<field_ptr_t> | |||||
| { | |||||
| using base_type = std::vector<field_ptr_t>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,55 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* make_fields_impl */ | |||||
| template<typename T, typename> | |||||
| struct make_fields_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); } | |||||
| }; | |||||
| template<typename T_schema, typename T_table> | |||||
| struct make_fields_impl< | |||||
| mp::list<T_schema, T_table>, | |||||
| mp::enable_if_c< | |||||
| schema::is_schema<mp::decay_t<T_schema>>::value | |||||
| && schema::is_table <mp::decay_t<T_table >>::value>> | |||||
| { | |||||
| template<typename T_index> | |||||
| static constexpr void emplace(fields_t& fields, const T_schema& schema, const T_table& table, T_index&& index) | |||||
| { | |||||
| decltype(auto) field = make_field(schema, table, table.fields[index]); | |||||
| using field_type = mp::decay_t<decltype(field)>; | |||||
| fields.emplace_back(new field_type(std::move(field))); | |||||
| } | |||||
| template<size_t... I> | |||||
| static auto helper(const T_schema& schema, const T_table& table, std::index_sequence<I...>&&) | |||||
| { | |||||
| fields_t fields; | |||||
| int dummy[] = {0, (emplace(fields, schema, table, hana::size_c<I>), void(), 0)...}; | |||||
| (void) dummy; | |||||
| return fields; | |||||
| } | |||||
| static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table) | |||||
| { | |||||
| using size = decltype(hana::size(table.fields)); | |||||
| return helper(schema, table, std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,13 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* filter_t */ | |||||
| struct filter_t; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,54 +0,0 @@ | |||||
| #pragma once | |||||
| #include <set> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* filter_add_element */ | |||||
| template<typename T, typename = void> | |||||
| struct filter_add_element_impl; | |||||
| constexpr decltype(auto) filter_add_element = misc::make_generic_predicate<__impl::filter_add_element_impl> { }; | |||||
| } | |||||
| /* filter_t */ | |||||
| struct filter_t | |||||
| { | |||||
| public: | |||||
| using field_set_type = std::set<const field_t*>; | |||||
| using table_set_type = std::set<const table_t*>; | |||||
| size_t cache_id { 0 }; | |||||
| bool exclusive { true }; | |||||
| field_set_type fields; | |||||
| table_set_type tables; | |||||
| inline bool is_excluded(const table_t& table) const; | |||||
| inline bool is_excluded(const field_t& field) const; | |||||
| template<typename... T_args> | |||||
| inline void set_inclusive(const schema_t& schema, T_args&&... args); | |||||
| template<typename... T_args> | |||||
| inline void set_exclusive(const schema_t& schema, T_args&&... args); | |||||
| inline void clear(); | |||||
| private: | |||||
| void update_tables(); | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,122 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.inl> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* filter_add_element_impl */ | |||||
| template<typename T, typename> | |||||
| struct filter_add_element_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::filter_add_element(...)!"); } | |||||
| }; | |||||
| template<typename T_table> | |||||
| struct filter_add_element_impl< | |||||
| mp::list<filter_t&, const schema_t&, T_table>, | |||||
| mp::enable_if_c< | |||||
| schema::is_table<mp::decay_t<T_table>>::value>> | |||||
| { | |||||
| static constexpr decltype(auto) apply(filter_t& filter, const schema_t& schema, const T_table& table) | |||||
| { | |||||
| auto dataset_id = misc::get_type_id(table.wrapped_dataset); | |||||
| auto& t = schema.table(dataset_id); | |||||
| filter.tables.emplace(&t); | |||||
| for (auto& ptr : t.fields) | |||||
| { | |||||
| filter.fields.emplace(ptr.get()); | |||||
| } | |||||
| } | |||||
| }; | |||||
| template<typename T_field> | |||||
| struct filter_add_element_impl< | |||||
| mp::list<filter_t&, const schema_t&, T_field>, | |||||
| mp::enable_if_c< | |||||
| schema::is_field<mp::decay_t<T_field>>::value>> | |||||
| { | |||||
| static constexpr decltype(auto) apply(filter_t& filter, const schema_t& schema, const T_field& field) | |||||
| { | |||||
| auto field_id = misc::get_type_id(hana::type_c<mp::decay_t<T_field>>); | |||||
| auto& f = schema.field(field_id); | |||||
| filter.fields.emplace(&f); | |||||
| filter.tables.emplace(f.table); | |||||
| } | |||||
| }; | |||||
| } | |||||
| /* filter_t */ | |||||
| bool filter_t::is_excluded(const table_t& table) const | |||||
| { | |||||
| auto ret = static_cast<bool>(tables.count(&table)); | |||||
| if (!exclusive) | |||||
| ret = !ret; | |||||
| return ret; | |||||
| } | |||||
| bool filter_t::is_excluded(const field_t& field) const | |||||
| { | |||||
| auto ret = static_cast<bool>(fields.count(&field)); | |||||
| if (!exclusive) | |||||
| ret = !ret; | |||||
| return ret; | |||||
| } | |||||
| template<typename... T_args> | |||||
| void filter_t::set_inclusive(const schema_t& schema, T_args&&... args) | |||||
| { | |||||
| clear(); | |||||
| exclusive = false; | |||||
| cache_id = static_cast<size_t>(utl::get_unique_id<filter_t, mp::decay_t<T_args>...>()); | |||||
| int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... }; | |||||
| (void)dummy; | |||||
| } | |||||
| template<typename... T_args> | |||||
| void filter_t::set_exclusive(const schema_t& schema, T_args&&... args) | |||||
| { | |||||
| clear(); | |||||
| exclusive = true; | |||||
| cache_id = static_cast<size_t>(utl::get_unique_id<filter_t, mp::decay_t<T_args>...>()); | |||||
| int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... }; | |||||
| (void)dummy; | |||||
| // remove excluded tables if not all fields are excluded | |||||
| auto it = tables.begin(); | |||||
| while (it != tables.end()) | |||||
| { | |||||
| bool removed = false; | |||||
| for (auto& field : (*it)->fields) | |||||
| { | |||||
| if (fields.count(field.get())) | |||||
| { | |||||
| it = tables.erase(it); | |||||
| removed = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!removed) | |||||
| ++it; | |||||
| } | |||||
| } | |||||
| void filter_t::clear() | |||||
| { | |||||
| cache_id = 0; | |||||
| exclusive = true; | |||||
| fields.clear(); | |||||
| tables.clear(); | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,27 +0,0 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* schema_t */ | |||||
| struct schema_t; | |||||
| /* make_schema */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_schema_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::make_schema_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,37 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/context.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* schema_t */ | |||||
| struct schema_t | |||||
| { | |||||
| std::string schema_name; | |||||
| tables_t tables; | |||||
| inline schema_t() = default; | |||||
| inline schema_t(const schema_t&) = delete; | |||||
| inline schema_t(schema_t&& other) | |||||
| : schema_name(std::move(other).schema_name) | |||||
| , tables (std::move(other).tables) | |||||
| { update(); } | |||||
| void update (); | |||||
| void print (std::ostream& os) const; | |||||
| const table_t& table(size_t dataset_id) const; | |||||
| const field_t& field(size_t field_id) const; | |||||
| /* CRUD */ | |||||
| void init(const init_context& context) const; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,40 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* make_schema_impl */ | |||||
| template<typename T, typename> | |||||
| struct make_schema_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); } | |||||
| }; | |||||
| template<typename T_schema> | |||||
| struct make_schema_impl< | |||||
| mp::list<T_schema>, | |||||
| mp::enable_if_c< | |||||
| schema::is_schema<mp::decay_t<T_schema>>::value>> | |||||
| { | |||||
| static decltype(auto) apply(const T_schema& schema) | |||||
| { | |||||
| schema_t ret; | |||||
| ret.schema_name = schema.name; | |||||
| ret.tables = make_tables(schema); | |||||
| ret.update(); | |||||
| return ret; | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,31 +0,0 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* table_t */ | |||||
| struct table_t; | |||||
| /* table_ptr_t */ | |||||
| using table_ptr_t = std::unique_ptr<table_t>; | |||||
| /* make_table */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_table_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::make_table_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,208 +0,0 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <vector> | |||||
| #include <cppmariadb.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.fwd.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/context.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* table_t */ | |||||
| struct table_t | |||||
| { | |||||
| public: | |||||
| size_t dataset_id { 0 }; | |||||
| size_t base_dataset_id { 0 }; | |||||
| size_t table_id { 0 }; | |||||
| bool is_used_in_container { false }; | |||||
| std::vector<size_t> derived_dataset_ids; | |||||
| std::string table_name; | |||||
| std::string schema_name; | |||||
| fields_t fields; | |||||
| const table_t* base_table { nullptr }; | |||||
| std::vector<const table_t*> derived_tables; | |||||
| const field_t* primary_key_field { nullptr }; | |||||
| std::vector<const field_t*> foreign_key_fields; | |||||
| std::vector<const field_t*> foreign_table_fields; | |||||
| std::vector<const field_t*> foreign_table_one_fields; | |||||
| std::vector<const field_t*> foreign_table_many_fields; | |||||
| std::vector<const field_t*> data_fields; | |||||
| inline table_t() = default; | |||||
| inline table_t(const table_t&) = delete; | |||||
| inline table_t(table_t&& other) | |||||
| : dataset_id (std::move(other).dataset_id) | |||||
| , base_dataset_id (std::move(other).base_dataset_id) | |||||
| , table_id (std::move(other).table_id) | |||||
| , derived_dataset_ids (std::move(other).derived_dataset_ids) | |||||
| , table_name (std::move(other).table_name) | |||||
| , schema_name (std::move(other).schema_name) | |||||
| , fields (std::move(other).fields) | |||||
| , base_table (nullptr) | |||||
| , derived_tables () | |||||
| , primary_key_field (nullptr) | |||||
| , foreign_key_fields () | |||||
| , foreign_table_fields () | |||||
| , foreign_table_one_fields () | |||||
| , foreign_table_many_fields () | |||||
| , data_fields () | |||||
| { } | |||||
| virtual ~table_t() { }; | |||||
| void print(std::ostream& os) const; | |||||
| const table_t* get_derived_by_table_id(size_t id) const; | |||||
| const table_t* get_derived_by_dataset_id(size_t id) const; | |||||
| virtual void emplace (const read_context& context) const; | |||||
| std::string get_where_primary_key(const data_context& context) const; | |||||
| std::string build_delete_query (const std::string* where) const; | |||||
| /* CRUD */ | |||||
| inline void init_stage1(const init_context& context) const | |||||
| { return init_stage1_exec(context); } | |||||
| inline void init_stage2(const init_context& context) const | |||||
| { return init_stage2_exec(context); } | |||||
| inline decltype(auto) create_update(const create_update_context& context) const | |||||
| { return create_update_intern(context); } | |||||
| inline void read(const read_context& context) const | |||||
| { return read_exec(context); } | |||||
| inline void destroy(const destroy_context& context) const | |||||
| { return destroy_intern(context); } | |||||
| private: | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| friend struct table_simple_t; | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| friend struct table_polymorphic_t; | |||||
| using statement_ptr = std::unique_ptr<::cppmariadb::statement>; | |||||
| using map_key = std::tuple<size_t, const field_t*>; | |||||
| using statement_map = std::map<map_key, ::cppmariadb::statement>; | |||||
| mutable statement_ptr _statement_key_from_base; | |||||
| mutable statement_ptr _statement_create_table; | |||||
| mutable statement_ptr _statement_alter_table; | |||||
| mutable statement_ptr _statement_insert_into; | |||||
| mutable statement_map _statement_select_static; | |||||
| mutable statement_map _statement_select_dynamic; | |||||
| mutable statement_map _statement_update; | |||||
| mutable statement_ptr _statement_foreign_many_delete; | |||||
| mutable statement_ptr _statement_delete; | |||||
| ::cppmariadb::statement& get_statement_key_from_base() const; | |||||
| ::cppmariadb::statement& get_statement_create_table() const; | |||||
| ::cppmariadb::statement* get_statement_alter_table() const; | |||||
| ::cppmariadb::statement* get_statement_insert_into() const; | |||||
| ::cppmariadb::statement& get_statement_select(const read_context& context) const; | |||||
| ::cppmariadb::statement* get_statement_update(const filter_t& filter, const field_t* owner) const; | |||||
| ::cppmariadb::statement& get_statement_foreign_many_delete() const; | |||||
| ::cppmariadb::statement& get_statement_delete() const; | |||||
| void execute_foreign_many_delete(const base_context& context) const; | |||||
| std::string execute_create_update( | |||||
| const create_update_context& context, | |||||
| ::cppmariadb::statement* statement) const; | |||||
| std::string get_primary_key(const data_context& context) const; | |||||
| std::string get_key_from_base(const data_context& context) const; | |||||
| virtual std::string create_update_base(const create_update_context& context) const; | |||||
| protected: | |||||
| using table_set = std::set<const table_t*>; | |||||
| void init_stage1_exec (const init_context& context) const; | |||||
| void init_stage2_exec (const init_context& context) const; | |||||
| virtual std::string create_update_intern(const create_update_context& context) const; | |||||
| std::string create_update_exec (const create_update_context& context) const; | |||||
| void read_exec (const read_context& context) const; | |||||
| virtual void destroy_intern (const destroy_context& context) const; | |||||
| void destroy_exec (const destroy_context& context) const; | |||||
| void destroy_cleanup (const base_context& context, table_set& processed, bool check_derived, bool check_base) const; | |||||
| }; | |||||
| /* table_simple_t */ | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| struct table_simple_t | |||||
| : public table_t | |||||
| { | |||||
| public: | |||||
| using schema_type = T_schema; | |||||
| using table_type = T_table; | |||||
| using base_dataset_type = T_base_dataset; | |||||
| using dataset_type = typename table_type::dataset_type; | |||||
| const schema_type& schema; | |||||
| const table_type& table; | |||||
| inline table_simple_t(const schema_type& p_schema, const table_type& p_table) | |||||
| : schema(p_schema) | |||||
| , table (p_table) | |||||
| { } | |||||
| inline table_simple_t(const table_simple_t&) = delete; | |||||
| inline table_simple_t(table_simple_t&& other) | |||||
| : table_t(std::move(other)) | |||||
| , schema (std::move(other).schema) | |||||
| , table (std::move(other).table) | |||||
| { } | |||||
| }; | |||||
| /* table_polymorphic_t */ | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| struct table_polymorphic_t | |||||
| : public table_simple_t<T_schema, T_table, T_base_dataset> | |||||
| { | |||||
| public: | |||||
| using base_type = table_simple_t<T_schema, T_table, T_base_dataset>; | |||||
| using schema_type = typename base_type::schema_type; | |||||
| using table_type = typename base_type::table_type; | |||||
| using base_dataset_type = typename base_type::base_dataset_type; | |||||
| using dataset_type = typename table_type::dataset_type; | |||||
| using real_dataset_type = misc::real_dataset_t<dataset_type>; | |||||
| using base_type::base_type; | |||||
| virtual void emplace(const read_context& context) const override; | |||||
| private: | |||||
| template<typename T_dataset, typename T_pred, typename T_include_self> | |||||
| constexpr void for_each_derived(T_dataset& dataset, const T_include_self& include_self, const T_pred& pred) const; | |||||
| protected: | |||||
| virtual std::string create_update_intern(const create_update_context& context) const override; | |||||
| virtual void destroy_intern (const destroy_context& context) const override; | |||||
| private: | |||||
| virtual std::string create_update_base(const create_update_context& context) const override; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,218 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* table_polymorphic_t */ | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| void table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::emplace(const read_context& context) const | |||||
| { | |||||
| hana::eval_if( | |||||
| std::is_abstract<real_dataset_type> { }, | |||||
| [](){ | |||||
| throw misc::hibernate_exception(std::string("can not create dataset of abstract type: ") | |||||
| + utl::type_helper<real_dataset_type>::name()); | |||||
| }, | |||||
| [&context, this](auto _){ | |||||
| _(context).template emplace<real_dataset_type>(this); | |||||
| }); | |||||
| } | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| template<typename T_dataset, typename T_pred, typename T_include_self> | |||||
| constexpr void table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::for_each_derived(T_dataset& dataset, const T_include_self& include_self, const T_pred& pred) const | |||||
| { | |||||
| auto derived_types = hana::filter( | |||||
| schema::get_all_derived_types(this->schema, hana::type_c<dataset_type>), | |||||
| [&](auto type){ | |||||
| return hana::and_( | |||||
| hana::not_(hana::trait<std::is_abstract>(type)), | |||||
| hana::or_( | |||||
| type != hana::type_c<dataset_type>, | |||||
| include_self)); | |||||
| }); | |||||
| hana::for_each(derived_types, [&](auto& type){ | |||||
| using derived_type = misc::decay_unwrap_t<decltype(type)>; | |||||
| auto* derived = dynamic_cast<derived_type*>(&dataset); | |||||
| if (derived) | |||||
| pred(*derived); | |||||
| }); | |||||
| } | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| std::string table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::create_update_intern(const create_update_context& context) const | |||||
| { | |||||
| bool done = false; | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ | |||||
| if (!done) | |||||
| { | |||||
| using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>; | |||||
| auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>); | |||||
| auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id); | |||||
| if (!derived_table) | |||||
| { | |||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||||
| << "unable to find derived table info for dataset '" | |||||
| << utl::type_helper<derived_dataset_type>::name() << "'!").str()); | |||||
| } | |||||
| derived_table->create_update(change_context(context, derived_dataset)); | |||||
| done = true; | |||||
| } | |||||
| }); | |||||
| return done | |||||
| ? *this->primary_key_field->get(context) | |||||
| : this->create_update_exec(context); | |||||
| } | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| void table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::destroy_intern(const destroy_context& context) const | |||||
| { | |||||
| bool done = false; | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ | |||||
| if (!done) | |||||
| { | |||||
| using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>; | |||||
| auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>); | |||||
| auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id); | |||||
| if (!derived_table) | |||||
| { | |||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||||
| << "unable to find derived table info for dataset '" | |||||
| << utl::type_helper<derived_dataset_type>::name() << "'!").str()); | |||||
| } | |||||
| auto new_context = change_context(context, derived_dataset); | |||||
| derived_table->destroy(new_context); | |||||
| done = true; | |||||
| } | |||||
| }); | |||||
| if (!done) | |||||
| { | |||||
| this->destroy_exec(context); | |||||
| } | |||||
| } | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| std::string table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::create_update_base(const create_update_context& context) const | |||||
| { | |||||
| return hana::eval_if( | |||||
| mp::is_same<base_dataset_type, void> { }, | |||||
| [this]()->std::string { | |||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||||
| << "'" << this->table_name << "' does not have a base table").str()); | |||||
| }, | |||||
| [this, &context](auto _)->std::string { | |||||
| using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>; | |||||
| assert(this->base_table); | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto& base = static_cast<tmp_type&>(dataset); | |||||
| return this->base_table->create_update_exec(change_context(context, base)); | |||||
| }); | |||||
| } | |||||
| namespace __impl | |||||
| { | |||||
| /* make_dataset_id_vector */ | |||||
| struct make_dataset_id_vector_impl | |||||
| { | |||||
| template<typename T_wrapped_datasets, size_t... I> | |||||
| static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence<I...>) | |||||
| { | |||||
| return std::vector<size_t>({ | |||||
| misc::get_type_id(wrapped_datasets[hana::size_c<I>])... | |||||
| }); | |||||
| } | |||||
| template<typename T_wrapped_datasets> | |||||
| constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const | |||||
| { | |||||
| using size = mp::decay_t<decltype(hana::size(wrapped_datasets))>; | |||||
| return helper(std::forward<T_wrapped_datasets>(wrapped_datasets), std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { }; | |||||
| /* make_table_impl */ | |||||
| template<typename T, typename> | |||||
| struct make_table_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); } | |||||
| }; | |||||
| template<typename T_schema, typename T_table> | |||||
| struct make_table_impl< | |||||
| mp::list<T_schema, T_table>, | |||||
| mp::enable_if_c< | |||||
| schema::is_schema<mp::decay_t<T_schema>>::value | |||||
| && schema::is_table <mp::decay_t<T_table>>::value>> | |||||
| { | |||||
| /* table_type */ | |||||
| template<typename T_dataset, typename T_base_dataset, typename = void> | |||||
| struct table_type | |||||
| { using type = table_simple_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; }; | |||||
| template<typename T_dataset, typename T_base_dataset> | |||||
| struct table_type<T_dataset, T_base_dataset, mp::enable_if_c< | |||||
| std::is_polymorphic<T_dataset>::value>> | |||||
| { using type = table_polymorphic_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; }; | |||||
| template<typename T_dataset, typename T_base_dataset> | |||||
| using table_type_t = typename table_type<T_dataset, T_base_dataset>::type; | |||||
| /* apply */ | |||||
| static decltype(auto) apply(const T_schema& schema, const T_table& table) | |||||
| { | |||||
| using wrapped_base_type = mp::decay_t<decltype( | |||||
| schema::get_base_type( | |||||
| std::declval<T_schema>(), | |||||
| std::declval<T_table>().wrapped_dataset))>; | |||||
| using base_type = misc::unwrap_t<wrapped_base_type>; | |||||
| using derived_wrapped_types_type = mp::decay_t<decltype( | |||||
| schema::get_derived_types( | |||||
| std::declval<T_schema>(), | |||||
| std::declval<T_table>().wrapped_dataset))>; | |||||
| using wrapped_dataset_type = typename mp::decay_t<T_table>::wrapped_dataset_type; | |||||
| using dataset_type = misc::unwrap_t<wrapped_dataset_type>; | |||||
| using real_dataset_type = misc::real_dataset_t<dataset_type>; | |||||
| using table_type = table_type_t<dataset_type, base_type>; | |||||
| static_assert(mp::is_same<dataset_type, real_dataset_type>::value, "table cn only be created for simple dataset types (not for containers)!"); | |||||
| table_type ret(schema, table); | |||||
| ret.dataset_id = misc::get_type_id(table.wrapped_dataset); | |||||
| ret.base_dataset_id = misc::get_type_id(wrapped_base_type { }); | |||||
| ret.derived_dataset_ids = make_dataset_id_vector(derived_wrapped_types_type { }); | |||||
| ret.table_id = hana::value(table.table_id); | |||||
| ret.schema_name = schema.name; | |||||
| ret.table_name = table.name; | |||||
| ret.fields = make_fields(schema, table); | |||||
| return ret; | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,29 +0,0 @@ | |||||
| #pragma once | |||||
| #include <vector> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* tables_t */ | |||||
| struct tables_t; | |||||
| /* make_tables */ | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T, typename = void> | |||||
| struct make_tables_impl; | |||||
| } | |||||
| constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::make_tables_impl> { }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,23 +0,0 @@ | |||||
| #pragma once | |||||
| #include <map> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* tables_t */ | |||||
| struct tables_t | |||||
| : public std::map<size_t, table_ptr_t> | |||||
| { | |||||
| using base_type = std::map<size_t, table_ptr_t>; | |||||
| using base_type::base_type; | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,55 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| /* make_tables_impl */ | |||||
| template<typename T, typename> | |||||
| struct make_tables_impl | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&... args) | |||||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); } | |||||
| }; | |||||
| template<typename T_schema> | |||||
| struct make_tables_impl< | |||||
| mp::list<T_schema>, | |||||
| mp::enable_if_c< | |||||
| schema::is_schema<mp::decay_t<T_schema>>::value>> | |||||
| { | |||||
| template<typename T_index> | |||||
| static constexpr void emplace(tables_t& tables, const T_schema& schema, T_index&& index) | |||||
| { | |||||
| decltype(auto) table = make_table(schema, schema.tables[index]); | |||||
| using table_type = mp::clean_type<decltype(table)>; | |||||
| auto key = table.dataset_id; | |||||
| tables.emplace(key, std::make_unique<table_type>(std::move(table))); | |||||
| } | |||||
| template<size_t... I> | |||||
| static decltype(auto) helper(const T_schema& schema, std::index_sequence<I...>) | |||||
| { | |||||
| tables_t tables; | |||||
| int dummy[] = {0, (emplace(tables, schema, hana::size_c<I>), void(), 0)...}; | |||||
| (void) dummy; | |||||
| return tables; | |||||
| } | |||||
| static constexpr decltype(auto) apply(const T_schema& schema) | |||||
| { | |||||
| using size = decltype(hana::size(schema.tables)); | |||||
| return helper(schema, std::make_index_sequence<size::value> { }); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -5,26 +5,58 @@ | |||||
| namespace cpphibernate | namespace cpphibernate | ||||
| { | { | ||||
| namespace __impl | |||||
| { | |||||
| template<typename T_lhs, typename T_rhs> | |||||
| using equality_compare_equal = mp::bool_t<hana::value(hana::equal( | |||||
| hana::type_c<mp::decay_t<T_lhs>>, | |||||
| hana::type_c<mp::decay_t<T_rhs>>))>; | |||||
| template<typename T_lhs, typename T_rhs> | |||||
| using equality_compare_not_equal = mp::bool_t<hana::value(hana::not_equal( | |||||
| hana::type_c<mp::decay_t<T_lhs>>, | |||||
| hana::type_c<mp::decay_t<T_rhs>>))>; | |||||
| } | |||||
| /** | /** | ||||
| * @brief Tag all objects that are equality comparable to each other. | * @brief Tag all objects that are equality comparable to each other. | ||||
| * | * | ||||
| * @tparam T_group Type used for groupig different types. | * @tparam T_group Type used for groupig different types. | ||||
| */ | */ | ||||
| template<typename T_group> | template<typename T_group> | ||||
| struct tag_equality_comparable; | |||||
| struct tag_equality_comparable | |||||
| { | |||||
| static constexpr decltype(auto) equality_compare_group = hana::type_c<T_group>; | |||||
| }; | |||||
| /** | /** | ||||
| * @brief Equality compare for all objects that has the quality compare tag | * @brief Equality compare for all objects that has the quality compare tag | ||||
| */ | */ | ||||
| template<typename T_lhs, typename T_rhs> | template<typename T_lhs, typename T_rhs> | ||||
| constexpr decltype(auto) operator == (T_lhs&& lhs, T_rhs&& rhs); | |||||
| constexpr auto operator == (T_lhs&&, T_rhs&&) | |||||
| -> mp::enable_if_t< | |||||
| mp::is_valid_v<decltype(std::declval<T_lhs>().equality_compare_group)> | |||||
| && mp::is_valid_v<decltype(std::declval<T_rhs>().equality_compare_group)> | |||||
| && mp::is_same_v< | |||||
| typename decltype(+std::declval<T_lhs>().equality_compare_group)::type, | |||||
| typename decltype(+std::declval<T_rhs>().equality_compare_group)::type>, | |||||
| __impl::equality_compare_equal<T_lhs, T_rhs>> | |||||
| { return __impl::equality_compare_equal<T_lhs, T_rhs> { }; } | |||||
| /** | /** | ||||
| * @brief Equality compare for all objects that has the quality compare tag | * @brief Equality compare for all objects that has the quality compare tag | ||||
| */ | */ | ||||
| template<typename T_lhs, typename T_rhs> | template<typename T_lhs, typename T_rhs> | ||||
| constexpr decltype(auto) operator != (T_lhs&& lhs, T_rhs&& rhs); | |||||
| constexpr auto operator != (T_lhs&&, T_rhs&&) | |||||
| -> mp::enable_if_t< | |||||
| mp::is_valid_v<decltype(std::declval<T_lhs>().equality_compare_group)> | |||||
| && mp::is_valid_v<decltype(std::declval<T_rhs>().equality_compare_group)> | |||||
| && mp::is_same_v< | |||||
| typename decltype(+std::declval<T_lhs>().equality_compare_group)::type, | |||||
| typename decltype(+std::declval<T_rhs>().equality_compare_group)::type>, | |||||
| __impl::equality_compare_not_equal<T_lhs, T_rhs>> | |||||
| { return __impl::equality_compare_not_equal<T_lhs, T_rhs> { }; } | |||||
| } | } | ||||
| #include "equality_compare.inl" | |||||
| @@ -1,61 +0,0 @@ | |||||
| #pragma once | |||||
| #include "equality_compare.h" | |||||
| namespace cpphibernate | |||||
| { | |||||
| namespace __impl | |||||
| { | |||||
| template<typename T_lhs, typename T_rhs, typename = void> | |||||
| struct equality_compare_impl | |||||
| { | |||||
| static constexpr decltype(auto) equal(T_lhs&&, T_rhs&&) | |||||
| { static_assert(sizeof(T_lhs) == -1, "Unable to equality compare these two types."); } | |||||
| static constexpr decltype(auto) not_equal(T_lhs&&, T_rhs&&) | |||||
| { static_assert(sizeof(T_lhs) == -1, "Unable to equality compare these two types."); } | |||||
| }; | |||||
| template<typename T_lhs, typename T_rhs> | |||||
| struct equality_compare_impl< | |||||
| T_lhs, | |||||
| T_rhs, | |||||
| mp::enable_if_t< | |||||
| mp::is_valid_v<typename T_lhs::equality_compare_group_type> | |||||
| && mp::is_valid_v<typename T_rhs::equality_compare_group_type> | |||||
| && mp::is_same_v< | |||||
| typename T_lhs::equality_compare_group_type, | |||||
| typename T_rhs::equality_compare_group_type>>> | |||||
| { | |||||
| static constexpr decltype(auto) equal(T_lhs&&, T_rhs&&) | |||||
| { return hana::type_c<mp::decay_t<T_lhs>> == hana::type_c<mp::decay_t<T_rhs>>; } | |||||
| static constexpr decltype(auto) not_equal(T_lhs&&, T_rhs&&) | |||||
| { return hana::type_c<mp::decay_t<T_lhs>> != hana::type_c<mp::decay_t<T_rhs>>; } | |||||
| }; | |||||
| }; | |||||
| template<typename T_group> | |||||
| struct tag_equality_comparable | |||||
| { | |||||
| using equality_compare_group_type = T_group; | |||||
| }; | |||||
| template<typename T_lhs, typename T_rhs> | |||||
| constexpr decltype(auto) operator == (T_lhs&& lhs, T_rhs&& rhs) | |||||
| { | |||||
| using equality_compare_type = __impl::equality_compare_impl<T_lhs, T_rhs>; | |||||
| return equality_compare_type::equal(std::forward<T_lhs>(lhs), std::forward<T_rhs>(rhs)); | |||||
| } | |||||
| template<typename T_lhs, typename T_rhs> | |||||
| constexpr decltype(auto) operator != (T_lhs&& lhs, T_rhs&& rhs) | |||||
| { | |||||
| using equality_compare_type = __impl::equality_compare_impl<T_lhs, T_rhs>; | |||||
| return equality_compare_type::not_equal(std::forward<T_lhs>(lhs), std::forward<T_rhs>(rhs)); | |||||
| } | |||||
| } | |||||
| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppcore/misc/indent.h> | #include <cppcore/misc/indent.h> | ||||
| #include <cppcore/conversion/string.h> | |||||
| #include "print_container.h" | #include "print_container.h" | ||||
| @@ -77,8 +78,10 @@ namespace cpphibernate | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_print_container(...)!"); } | { static_assert(sizeof...(T_args) == -1, "Invalid parameters for make_print_container(...)!"); } | ||||
| }; | }; | ||||
| template<typename T_container, typename T_func> | |||||
| struct print_container_builder<mp::list<T_container, bool, T_func>, void> | |||||
| template<typename T_container, typename T_bool, typename T_func> | |||||
| struct print_container_builder< | |||||
| mp::list<T_container, T_bool, T_func>, | |||||
| mp::enable_if_t<mp::is_same_v<bool, mp::decay_t<T_bool>>>> | |||||
| { | { | ||||
| static constexpr decltype(auto) apply(T_container&& container, bool do_indent, T_func&& func) | static constexpr decltype(auto) apply(T_container&& container, bool do_indent, T_func&& func) | ||||
| { | { | ||||
| @@ -91,14 +94,16 @@ namespace cpphibernate | |||||
| } | } | ||||
| }; | }; | ||||
| template<typename T_container> | |||||
| struct print_container_builder<mp::list<T_container, bool>, void> | |||||
| template<typename T_container, typename T_bool> | |||||
| struct print_container_builder< | |||||
| mp::list<T_container, T_bool>, | |||||
| mp::enable_if_t<mp::is_same_v<bool, mp::decay_t<T_bool>>>> | |||||
| { | { | ||||
| static constexpr decltype(auto) apply(T_container&& container, bool do_indent) | static constexpr decltype(auto) apply(T_container&& container, bool do_indent) | ||||
| { | { | ||||
| using namespace ::cppcore; | using namespace ::cppcore; | ||||
| make_print_container( | |||||
| return make_print_container( | |||||
| std::forward<T_container>(container), | std::forward<T_container>(container), | ||||
| do_indent, | do_indent, | ||||
| [do_indent](auto& os, auto& value) | [do_indent](auto& os, auto& value) | ||||
| @@ -114,3 +119,26 @@ namespace cpphibernate | |||||
| } | } | ||||
| } | } | ||||
| namespace std | |||||
| { | |||||
| template< | |||||
| typename T_print_container, | |||||
| typename T_char, | |||||
| typename T_traits> | |||||
| inline auto | |||||
| operator << ( | |||||
| basic_ostream<T_char, T_traits>& os, | |||||
| const T_print_container& ctnr) | |||||
| -> ::cppmp::enable_if_t< | |||||
| ::cppmp::is_specialization_of_v< | |||||
| ::cppmp::decay_t<T_print_container>, | |||||
| ::cpphibernate::__impl::print_container>, | |||||
| basic_ostream<T_char, T_traits>&> | |||||
| { | |||||
| ctnr.print(os); | |||||
| return os; | |||||
| } | |||||
| } | |||||
| @@ -29,6 +29,67 @@ namespace cpphibernate | |||||
| template<typename T> | template<typename T> | ||||
| using decay_unwrap_t = typename mp::decay_t<T>::type; | using decay_unwrap_t = typename mp::decay_t<T>::type; | ||||
| /** | |||||
| * @brief Unwrap the passed hana::type and return an object of the inner type. | |||||
| */ | |||||
| template<typename T> | |||||
| constexpr decltype(auto) unwrap(T&& t) | |||||
| { return typename decltype(+t)::type { }; } | |||||
| /** | |||||
| * @brief Get a unique ID for the passed type | |||||
| */ | |||||
| template<typename T_type> | |||||
| constexpr decltype(auto) get_type_id(T_type&&); | |||||
| /** | |||||
| * @brief Evaluates to true_t if the passed type is a container, false_t otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| struct is_container; | |||||
| /** | |||||
| * @brief Is true if the passed type is a container, false otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| constexpr decltype(auto) is_container_v = is_container<T>::value; | |||||
| /** | |||||
| * @brief Evaluates to true_t if the passed type is an ordered container type, false_t otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| struct is_ordered; | |||||
| /** | |||||
| * @brief Is true if the passed type is an ordered container type, false otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| constexpr decltype(auto) is_ordered_v = is_ordered<T>::value; | |||||
| /** | |||||
| * @brief Evaluates to true_t if the passed type is a nullable type, false_t otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| struct is_pointer; | |||||
| /** | |||||
| * @brief Is true if the passed type is a pointer type, false otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| constexpr decltype(auto) is_pointer_v = is_pointer<T>::value; | |||||
| /** | |||||
| * @brief Evaluates to true_t if the passed type is a pointer type, false_t otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| struct is_nullable; | |||||
| /** | |||||
| * @brief Is true if the passed type is a nullable type, false otherwise. | |||||
| */ | |||||
| template<typename T> | |||||
| constexpr decltype(auto) is_nullable_v = is_nullable<T>::value; | |||||
| } | } | ||||
| #include "type_helper.inl" | #include "type_helper.inl" | ||||
| @@ -50,4 +50,79 @@ namespace cpphibernate | |||||
| : public __impl::real_dataset_impl<T> | : public __impl::real_dataset_impl<T> | ||||
| { }; | { }; | ||||
| /* get_dataset_id */ | |||||
| namespace __impl | |||||
| { | |||||
| struct counter_type_id | |||||
| { }; | |||||
| } | |||||
| template<typename T_type> | |||||
| constexpr decltype(auto) get_type_id(T_type&&) | |||||
| { return cppcore::get_unique_id<__impl::counter_type_id, mp::decay_t<T_type>>(); } | |||||
| /* is_container */ | |||||
| template<typename T> | |||||
| struct is_container | |||||
| : public mp::false_t | |||||
| { }; | |||||
| template<typename T, typename... T_args> | |||||
| struct is_container<std::list<T, T_args...>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| template<typename T, typename... T_args> | |||||
| struct is_container<std::vector<T, T_args...>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| /* is_ordered */ | |||||
| template<typename T> | |||||
| struct is_ordered | |||||
| : public mp::false_t | |||||
| { }; | |||||
| template<typename T, typename... T_args> | |||||
| struct is_ordered<std::list<T, T_args...>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| template<typename T, typename... T_args> | |||||
| struct is_ordered<std::vector<T, T_args...>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| /* is_pointer */ | |||||
| template<typename T> | |||||
| struct is_pointer | |||||
| : public mp::false_t | |||||
| { }; | |||||
| template<typename T, typename... T_args> | |||||
| struct is_pointer<std::unique_ptr<T, T_args...>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| template<typename T> | |||||
| struct is_pointer<std::shared_ptr<T>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| /* is_nullable */ | |||||
| template<typename T> | |||||
| struct is_nullable | |||||
| : public is_pointer<T> | |||||
| { }; | |||||
| template<typename T> | |||||
| struct is_nullable<cppcore::nullable<T>> | |||||
| : public mp::true_t | |||||
| { }; | |||||
| } | } | ||||
| @@ -26,6 +26,22 @@ namespace schema { | |||||
| { | { | ||||
| using inner_type = T_inner; | using inner_type = T_inner; | ||||
| using this_type = attribute_t<inner_type>; | using this_type = attribute_t<inner_type>; | ||||
| /* | |||||
| template<typename T_other> | |||||
| constexpr decltype(auto) operator==(T_other&&) const | |||||
| { | |||||
| return ::boost::hana::type<mp::decay_t<decltype(*this)>> { } == | |||||
| ::boost::hana::type<mp::decay_t<T_other>> { }; | |||||
| } | |||||
| template<typename T_other> | |||||
| constexpr decltype(auto) operator!=(T_other&&) const | |||||
| { | |||||
| return ::boost::hana::type<mp::decay_t<decltype(*this)>> { } != | |||||
| ::boost::hana::type<mp::decay_t<T_other>> { }; | |||||
| } | |||||
| */ | |||||
| }; | }; | ||||
| struct hex_t { static constexpr decltype(auto) name = "hex"; }; | struct hex_t { static constexpr decltype(auto) name = "hex"; }; | ||||
| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpphibernate/misc/type_helper.h> | |||||
| namespace cpphibernate { | namespace cpphibernate { | ||||
| namespace schema { | namespace schema { | ||||
| @@ -8,6 +9,85 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /** | |||||
| * @brief Tag class to mark field types. | |||||
| */ | |||||
| struct tag_field | |||||
| { }; | |||||
| /** | |||||
| * @brief Represents a data field in the schema. | |||||
| * | |||||
| * @tparam T_name Type of the name of the field. | |||||
| * @tparam T_getter Type of the getter of the field. | |||||
| * @tparam T_setter Type of the setter of the field. | |||||
| * @tparam T_attributes Type of the attributes of the field. | |||||
| */ | |||||
| template<typename T_name, typename T_getter, typename T_setter, typename T_attributes> | |||||
| struct field_t | |||||
| : public tag_field | |||||
| , public tag_equality_comparable<tag_field> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using getter_type = T_getter; | |||||
| using setter_type = T_setter; | |||||
| using dataset_type = typename mp::decay_t<getter_type>::object_type; | |||||
| using real_dataset_type = real_dataset_t<dataset_type>; | |||||
| using value_type = typename mp::decay_t<getter_type>::value_type; | |||||
| using real_value_type = real_dataset_t<value_type>; | |||||
| using attributes_type = T_attributes; | |||||
| using this_type = field_t<name_type, getter_type, setter_type, attributes_type>; | |||||
| name_type name; //!< Name of the field. | |||||
| getter_type getter; //!< Getter of the field, to get values from the dataset. | |||||
| setter_type setter; //!< Setter of the field, to set values of the dataset. | |||||
| attributes_type attributes; //!< List of attributes for this field. | |||||
| hana::type<value_type> wrapped_value_type; //!< Type of the stoed value. | |||||
| hana::type<dataset_type> wrapped_dataset_type; //!< Type of the real stored value (containers are removed). | |||||
| hana::type<real_value_type> wrapped_real_value_type; //!< Type of the dataset this fields uses. | |||||
| hana::type<real_dataset_type> wrapped_real_dataset_type; //!< Type of the read dataset (contaiers are removed). | |||||
| /** | |||||
| * @brief Constrcutor. | |||||
| * | |||||
| * @param[in] p_name Name of the field. | |||||
| * @param[in] p_getter Getter to receive the represented value from the dataset. | |||||
| * @param[in] p_setter Setter to set the represented value at the dataset. | |||||
| * @param[in] p_attributes List of attributes of the field. | |||||
| */ | |||||
| constexpr field_t( | |||||
| T_name&& p_name, | |||||
| T_getter&& p_getter, | |||||
| T_setter&& p_setter, | |||||
| T_attributes&& p_attributes); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| constexpr field_t(field_t&&) = default; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| constexpr field_t(const field_t&) = delete; | |||||
| /** | |||||
| * @brief Move assignment constructor. | |||||
| */ | |||||
| constexpr field_t& operator = (field_t&&) = default; | |||||
| /** | |||||
| * @brief Copy assignment constructor. | |||||
| */ | |||||
| constexpr field_t& operator = (const field_t&) = delete; | |||||
| /** | |||||
| * @brief Print the field to the passed stream. | |||||
| */ | |||||
| inline void print(std::ostream& os) const; | |||||
| }; | |||||
| /** | /** | ||||
| * @brief Helper type to build field objects. | * @brief Helper type to build field objects. | ||||
| */ | */ | ||||
| @@ -3,9 +3,8 @@ | |||||
| #include <cppcore/misc/indent.h> | #include <cppcore/misc/indent.h> | ||||
| #include <cppcore/misc/type_helper.h> | #include <cppcore/misc/type_helper.h> | ||||
| #include <cpphibernate/misc/type_helper.h> | |||||
| #include "field.h" | #include "field.h" | ||||
| #include "attributes.h" | |||||
| namespace cpphibernate { | namespace cpphibernate { | ||||
| namespace schema { | namespace schema { | ||||
| @@ -13,30 +12,11 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /* tag_field */ | |||||
| struct tag_field | |||||
| { }; | |||||
| /* field_t */ | /* field_t */ | ||||
| template<typename T_name, typename T_getter, typename T_setter, typename T_attributes> | template<typename T_name, typename T_getter, typename T_setter, typename T_attributes> | ||||
| struct field_t | |||||
| : public tag_field | |||||
| , public tag_equality_comparable<tag_field> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using getter_type = T_getter; | |||||
| using setter_type = T_setter; | |||||
| using attributes_type = T_attributes; | |||||
| using this_type = field_t<name_type, getter_type, setter_type, attributes_type>; | |||||
| name_type name; | |||||
| getter_type getter; | |||||
| setter_type setter; | |||||
| attributes_type attributes; | |||||
| constexpr field_t( | |||||
| constexpr field_t<T_name, T_getter, T_setter, T_attributes> | |||||
| ::field_t( | |||||
| T_name&& p_name, | T_name&& p_name, | ||||
| T_getter&& p_getter, | T_getter&& p_getter, | ||||
| T_setter&& p_setter, | T_setter&& p_setter, | ||||
| @@ -47,38 +27,30 @@ namespace schema { | |||||
| , attributes (std::forward<T_attributes>(p_attributes)) | , attributes (std::forward<T_attributes>(p_attributes)) | ||||
| { } | { } | ||||
| constexpr field_t(field_t&&) = default; | |||||
| constexpr field_t(const field_t&) = delete; | |||||
| constexpr field_t& operator = (field_t&&) = default; | |||||
| constexpr field_t& operator = (const field_t&) = delete; | |||||
| inline void print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| using value_type = typename mp::decay_t<getter_type>::value_type; | |||||
| using dataset_type = real_dataset_t<value_type>; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"value_type\": \"" << type_helper<value_type>::name() << "\"" | |||||
| << indent << "\"dataset_type\": \"" << type_helper<dataset_type>::name() << "\"" | |||||
| << indent << "\"attributes\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(attributes, [&](auto& attrib){ | |||||
| if (index++ > 0) os << ","; | |||||
| os << indent << '"' << attrib.name << '"'; | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| }; | |||||
| template<typename T_name, typename T_getter, typename T_setter, typename T_attributes> | |||||
| void field_t<T_name, T_getter, T_setter, T_attributes> | |||||
| ::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"value_type\": \"" << type_helper<value_type>::name() << "\"" | |||||
| << indent << "\"dataset_type\": \"" << type_helper<dataset_type>::name() << "\"" | |||||
| << indent << "\"attributes\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(attributes, [&](auto& attrib){ | |||||
| if (index++ > 0) os << ","; | |||||
| os << indent << '"' << attrib.name << '"'; | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| /* field_builder */ | /* field_builder */ | ||||
| @@ -95,10 +67,9 @@ namespace schema { | |||||
| mp::list<T_name, T_getter, T_setter, T_attributes>, | mp::list<T_name, T_getter, T_setter, T_attributes>, | ||||
| mp::enable_if_t< | mp::enable_if_t< | ||||
| true | true | ||||
| // && mp::is_getter_v<mp::decay_t<T_getter>> | |||||
| // && mp::is_setter_v<mp::decay_t<T_setter>> | |||||
| // && is_attributes_v<mp::decay_t<T_attributes>> | |||||
| >> | |||||
| && mp::is_getter_v<mp::decay_t<T_getter>> | |||||
| && mp::is_setter_v<mp::decay_t<T_setter>> | |||||
| && is_attributes_v<mp::decay_t<T_attributes>>>> | |||||
| { | { | ||||
| using name_type = T_name; | using name_type = T_name; | ||||
| using getter_type = T_getter; | using getter_type = T_getter; | ||||
| @@ -8,12 +8,83 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /** | |||||
| * @brief Tag class to mark schema objects. | |||||
| */ | |||||
| struct tag_schema | |||||
| { }; | |||||
| /** | |||||
| * @brief Schema type with all tables and fields for a database layout. | |||||
| * | |||||
| * @tparam T_name Name of the schema. | |||||
| * @tparam T_tables List of all tables that belong to this schema. | |||||
| */ | |||||
| template<typename T_name, typename T_tables> | |||||
| struct schema_t | |||||
| : public tag_schema | |||||
| , public tag_equality_comparable<tag_schema> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using tables_type = T_tables; | |||||
| name_type name; //!< Name of the schema. | |||||
| tables_type tables; //!< List of all tables that belongs to the schema. | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_name Name of the schema. | |||||
| * @param[in] p_tables List of all tables that belongs to the schema. | |||||
| */ | |||||
| constexpr schema_t( | |||||
| name_type&& p_name, | |||||
| tables_type&& p_tables); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| constexpr schema_t(schema_t&&) = default; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| constexpr schema_t(const schema_t&) = delete; | |||||
| /** | |||||
| * @brief Move assignment constructor. | |||||
| */ | |||||
| constexpr schema_t& operator = (schema_t&&) = default; | |||||
| /** | |||||
| * @brief Copy assignment constructor. | |||||
| */ | |||||
| constexpr schema_t& operator = (const schema_t&) = delete; | |||||
| /** | |||||
| * @brief Print the whole schema to the passed stream. | |||||
| */ | |||||
| inline void print(std::ostream& os) const; | |||||
| }; | |||||
| /** | /** | ||||
| * @brief Helper type to build schema objects. | * @brief Helper type to build schema objects. | ||||
| */ | */ | ||||
| template<typename X, typename = void> | template<typename X, typename = void> | ||||
| struct schema_builder; | struct schema_builder; | ||||
| /** | |||||
| * @brief Helper type to get the base type of the passed dataset type. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct get_base_type_builder; | |||||
| /** | |||||
| * @brief Helper type to get the derived types of the passed dataset type. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct get_derived_types_builder; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -33,6 +104,16 @@ namespace schema { | |||||
| */ | */ | ||||
| constexpr decltype(auto) make_schema = mp::generic_predicate<__impl::schema_builder> { }; | constexpr decltype(auto) make_schema = mp::generic_predicate<__impl::schema_builder> { }; | ||||
| /** | |||||
| * @brief Predicate to get the base type of the passed dataset type. | |||||
| */ | |||||
| constexpr decltype(auto) get_base_type = mp::generic_predicate<__impl::get_base_type_builder> { }; | |||||
| /** | |||||
| * @brief Predicate to get the derived types of the passed dataset type. | |||||
| */ | |||||
| constexpr decltype(auto) get_derived_types = mp::generic_predicate<__impl::get_derived_types_builder> { }; | |||||
| } } | } } | ||||
| #include "schema.inl" | #include "schema.inl" | ||||
| @@ -1,5 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppcore/misc/indent.h> | |||||
| #include "tables.h" | |||||
| #include "schema.h" | #include "schema.h" | ||||
| namespace cpphibernate { | namespace cpphibernate { | ||||
| @@ -8,57 +11,39 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /* tag_schema */ | |||||
| struct tag_schema | |||||
| { }; | |||||
| /* schema_t */ | /* schema_t */ | ||||
| template<typename T_name, typename T_tables> | template<typename T_name, typename T_tables> | ||||
| struct schema_t | |||||
| : public tag_schema | |||||
| , public tag_equality_comparable<tag_schema> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using tables_type = T_tables; | |||||
| name_type name; | |||||
| tables_type tables; | |||||
| constexpr schema_t( | |||||
| constexpr schema_t<T_name, T_tables> | |||||
| ::schema_t( | |||||
| name_type&& p_name, | name_type&& p_name, | ||||
| tables_type&& p_tables) | tables_type&& p_tables) | ||||
| : name (std::forward<name_type> (p_name)) | : name (std::forward<name_type> (p_name)) | ||||
| , tables(std::forward<tables_type>(p_tables)) | , tables(std::forward<tables_type>(p_tables)) | ||||
| { } | { } | ||||
| constexpr schema_t(schema_t&&) = default; | |||||
| constexpr schema_t(const schema_t&) = delete; | |||||
| constexpr schema_t& operator = (schema_t&&) = default; | |||||
| constexpr schema_t& operator = (const schema_t&) = delete; | |||||
| inline void print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"tables\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(tables, [&](auto& table){ | |||||
| if (index++ > 0) os << ","; | |||||
| table.print(os); | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| }; | |||||
| template<typename T_name, typename T_tables> | |||||
| void schema_t<T_name, T_tables> | |||||
| ::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"tables\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(tables, [&](auto& table){ | |||||
| if (index++ > 0) os << ","; | |||||
| table.print(os); | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| /* schema_builder */ | /* schema_builder */ | ||||
| @@ -90,6 +75,115 @@ namespace schema { | |||||
| } | } | ||||
| }; | }; | ||||
| /* get_base_type_builder */ | |||||
| template<typename X, typename> | |||||
| struct get_base_type_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for get_base_type(...)!"); } | |||||
| }; | |||||
| template<typename T_schema, typename T_wrapped_dataset> | |||||
| struct get_base_type_builder< | |||||
| mp::list<T_schema, T_wrapped_dataset>, | |||||
| mp::enable_if_t<is_schema_v<mp::decay_t<T_schema>>>> | |||||
| { | |||||
| /* is_base_of */ | |||||
| static constexpr decltype(auto) is_base_of = hana::integral(hana::metafunction<mp::is_base_of>); | |||||
| /* do_fold */ | |||||
| struct do_fold_impl | |||||
| { | |||||
| template<typename T_type_1, typename T_type_2> | |||||
| constexpr decltype(auto) operator()(T_type_1&& type_1, T_type_2&& type_2) const | |||||
| { | |||||
| auto check = hana::or_(is_base_of(type_1, type_2), is_base_of(type_2, type_1)); | |||||
| static_assert(decltype(check)::value, "A dataset must not have more than one base class!"); | |||||
| return hana::if_(is_base_of(type_1, type_2), type_2, type_1); | |||||
| } | |||||
| }; | |||||
| static constexpr decltype(auto) do_fold = do_fold_impl { }; | |||||
| /* get_base_types */ | |||||
| template<typename T_datasets, typename T_dataset> | |||||
| static constexpr decltype(auto) get_base_types(T_datasets datasets, T_dataset dataset) | |||||
| { | |||||
| return hana::filter( | |||||
| datasets, | |||||
| [&](auto type){ | |||||
| return hana::and_( | |||||
| is_base_of(type, dataset), | |||||
| hana::not_equal(type, dataset)); | |||||
| }); | |||||
| } | |||||
| /* apply */ | |||||
| static constexpr decltype(auto) apply( | |||||
| const T_schema& schema, | |||||
| const T_wrapped_dataset& wrapped_dataset) | |||||
| { | |||||
| decltype(auto) wrapped_datasets = hana::transform( | |||||
| schema.tables, | |||||
| schema::get_wrapped_dataset); | |||||
| decltype(auto) base_types = get_base_types(wrapped_datasets, wrapped_dataset); | |||||
| return hana::eval_if( | |||||
| hana::size(base_types) <= hana::size_c<0>, | |||||
| [&](auto _){ return hana::type_c<void>; }, | |||||
| [&](auto _){ return hana::fold(_(base_types), do_fold); }); | |||||
| } | |||||
| }; | |||||
| /* get_derived_types_builder */ | |||||
| template<typename X, typename> | |||||
| struct get_derived_types_builder | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for get_derived_types(...)!"); } | |||||
| }; | |||||
| template<typename T_schema, typename T_dataset> | |||||
| struct get_derived_types_builder< | |||||
| mp::list<T_schema, T_dataset>, | |||||
| mp::enable_if_t< | |||||
| schema::is_schema_v<mp::decay_t<T_schema>> | |||||
| && mp::is_same_v<hana::type_tag, hana::tag_of_t<T_dataset>> | |||||
| >> | |||||
| { | |||||
| struct has_base_impl | |||||
| { | |||||
| template<typename T_type> | |||||
| constexpr decltype(auto) operator()(T_type&&) const | |||||
| { | |||||
| return decltype(hana::equal( | |||||
| get_base_type( | |||||
| std::declval<T_schema>(), | |||||
| std::declval<T_type>()), | |||||
| std::declval<T_dataset>())) { }; | |||||
| } | |||||
| }; | |||||
| static constexpr decltype(auto) has_base = has_base_impl { }; | |||||
| static constexpr decltype(auto) apply(T_schema&& schema, T_dataset&& dataset) | |||||
| { | |||||
| constexpr decltype(auto) dataset_types = | |||||
| decltype(hana::transform(schema.tables, schema::get_wrapped_dataset)) { }; | |||||
| constexpr decltype(auto) derived_types = | |||||
| decltype(hana::filter(dataset_types, has_base)) { }; | |||||
| return derived_types; | |||||
| } | |||||
| }; | |||||
| } | } | ||||
| /* is_schema */ | /* is_schema */ | ||||
| @@ -8,12 +8,93 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /** | |||||
| * @brief Tag class to mark table objects. | |||||
| */ | |||||
| struct tag_table | |||||
| { }; | |||||
| /** | |||||
| * @brief Represents a data field in the schema. | |||||
| * | |||||
| * @tparam T_name Name of the table. | |||||
| * @tparam T_wrapped_dataset Dataset type the table represents. | |||||
| * @tparam T_table_id Unique ID assigned by the user. | |||||
| * @tparam T_fields List of field that belongs to the table. | |||||
| */ | |||||
| template< | |||||
| typename T_name, | |||||
| typename T_wrapped_dataset, | |||||
| typename T_table_id, | |||||
| typename T_fields> | |||||
| struct table_t | |||||
| : public tag_table | |||||
| , public tag_equality_comparable<tag_table> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using wrapped_dataset_type = mp::decay_t<T_wrapped_dataset>; | |||||
| using dataset_type = decay_unwrap_t<wrapped_dataset_type>; | |||||
| using table_id_type = T_table_id; | |||||
| using fields_type = T_fields; | |||||
| using this_type = table_t<name_type, wrapped_dataset_type, table_id_type, fields_type>; | |||||
| name_type name; //!< Name of the table. | |||||
| wrapped_dataset_type wrapped_dataset; //!< Dataset type this table represents. | |||||
| table_id_type table_id; //!< Unique ID of the table, assigned by the user. | |||||
| fields_type fields; //!< List of fields that belongs to the table. | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_name Name of the table. | |||||
| * @param[in] p_wrapped_dataset Dataset type this table represents. | |||||
| * @param[in] p_table_id Unique ID of the table assigned by the user. | |||||
| * @param[in] p_fields List of fields that belongs to the table. | |||||
| */ | |||||
| constexpr table_t( | |||||
| name_type p_name, | |||||
| wrapped_dataset_type p_wrapped_dataset, | |||||
| table_id_type p_table_id, | |||||
| fields_type p_fields); | |||||
| /** | |||||
| * @brief Move constructor. | |||||
| */ | |||||
| constexpr table_t(table_t&&) = default; | |||||
| /** | |||||
| * @brief Copy constructor. | |||||
| */ | |||||
| constexpr table_t(const table_t&) = delete; | |||||
| /** | |||||
| * @brief Move assignment constructor. | |||||
| */ | |||||
| constexpr table_t& operator = (table_t&&) = default; | |||||
| /** | |||||
| * @brief Copy assignment constructor. | |||||
| */ | |||||
| constexpr table_t& operator = (const table_t&) = delete; | |||||
| /** | |||||
| * @brief Print the table to the passed stream. | |||||
| */ | |||||
| inline void print(std::ostream& os) const; | |||||
| }; | |||||
| /** | /** | ||||
| * @brief Helper type to build table objects. | * @brief Helper type to build table objects. | ||||
| */ | */ | ||||
| template<typename X, typename = void> | template<typename X, typename = void> | ||||
| struct table_builder; | struct table_builder; | ||||
| /** | |||||
| * @brief Helper type to get the wrapped dataset of the passed table. | |||||
| */ | |||||
| template<typename X, typename = void> | |||||
| struct table_get_wrapped_dataset; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -33,6 +114,11 @@ namespace schema { | |||||
| */ | */ | ||||
| constexpr decltype(auto) make_table = mp::generic_predicate<__impl::table_builder> { }; | constexpr decltype(auto) make_table = mp::generic_predicate<__impl::table_builder> { }; | ||||
| /** | |||||
| * @brief Predicate to get the wrapped dataset of the passed table. | |||||
| */ | |||||
| constexpr decltype(auto) get_wrapped_dataset = mp::generic_predicate<__impl::table_get_wrapped_dataset> { }; | |||||
| } } | } } | ||||
| #include "table.inl" | #include "table.inl" | ||||
| @@ -1,5 +1,8 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/misc/type_helper.h> | |||||
| #include "fields.h" | |||||
| #include "table.h" | #include "table.h" | ||||
| namespace cpphibernate { | namespace cpphibernate { | ||||
| @@ -8,35 +11,11 @@ namespace schema { | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| /* tag_table */ | |||||
| struct tag_table | |||||
| { }; | |||||
| /* table_t */ | /* table_t */ | ||||
| template< | |||||
| typename T_name, | |||||
| typename T_wrapped_dataset, | |||||
| typename T_table_id, | |||||
| typename T_fields> | |||||
| struct table_t | |||||
| : public tag_table | |||||
| , public tag_equality_comparable<tag_table> | |||||
| { | |||||
| using name_type = T_name; | |||||
| using wrapped_dataset_type = mp::decay_t<T_wrapped_dataset>; | |||||
| using dataset_type = decay_unwrap_t<wrapped_dataset_type>; | |||||
| using table_id_type = T_table_id; | |||||
| using fields_type = T_fields; | |||||
| using this_type = table_t<name_type, wrapped_dataset_type, table_id_type, fields_type>; | |||||
| name_type name; | |||||
| wrapped_dataset_type wrapped_dataset; | |||||
| table_id_type table_id; | |||||
| fields_type fields; | |||||
| constexpr table_t( | |||||
| template<typename T_name, typename T_wrapped_dataset, typename T_table_id, typename T_fields> | |||||
| constexpr table_t<T_name, T_wrapped_dataset, T_table_id, T_fields> | |||||
| ::table_t( | |||||
| name_type p_name, | name_type p_name, | ||||
| wrapped_dataset_type p_wrapped_dataset, | wrapped_dataset_type p_wrapped_dataset, | ||||
| table_id_type p_table_id, | table_id_type p_table_id, | ||||
| @@ -47,34 +26,29 @@ namespace schema { | |||||
| , fields (std::forward<fields_type> (p_fields)) | , fields (std::forward<fields_type> (p_fields)) | ||||
| { } | { } | ||||
| constexpr table_t(table_t&&) = default; | |||||
| constexpr table_t(const table_t&) = delete; | |||||
| constexpr table_t& operator = (table_t&&) = default; | |||||
| constexpr table_t& operator = (const table_t&) = delete; | |||||
| inline void print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"wrapped_dataset\": \"" << type_helper<dataset_type>::name() << "\"" | |||||
| << indent << "\"table_id\": \"" << hana::value(table_id) << "\"" | |||||
| << indent << "\"fields\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(fields, [&](auto& table){ | |||||
| if (index++ > 0) os << ","; | |||||
| table.print(os); | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| }; | |||||
| template<typename T_name, typename T_wrapped_dataset, typename T_table_id, typename T_fields> | |||||
| void table_t<T_name, T_wrapped_dataset, T_table_id, T_fields> | |||||
| ::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| size_t index = 0; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"wrapped_dataset\": \"" << type_helper<dataset_type>::name() << "\"" | |||||
| << indent << "\"table_id\": \"" << hana::value(table_id) << "\"" | |||||
| << indent << "\"fields\": " | |||||
| << indent << '[' | |||||
| << incindent; | |||||
| hana::for_each(fields, [&](auto& table){ | |||||
| if (index++ > 0) os << ","; | |||||
| table.print(os); | |||||
| }); | |||||
| os << decindent | |||||
| << indent << ']' | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| /* table_builder */ | /* table_builder */ | ||||
| @@ -117,6 +91,25 @@ namespace schema { | |||||
| } | } | ||||
| }; | }; | ||||
| /* table_get_wrapped_dataset */ | |||||
| template<typename X, typename> | |||||
| struct table_get_wrapped_dataset | |||||
| { | |||||
| template<typename... T_args> | |||||
| static constexpr decltype(auto) apply(T_args&&...) | |||||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for get_wrapped_dataset(...)!"); } | |||||
| }; | |||||
| template<typename T_table> | |||||
| struct table_get_wrapped_dataset< | |||||
| mp::list<T_table>, | |||||
| mp::enable_if_t<is_table_v<mp::decay_t<T_table>>>> | |||||
| { | |||||
| static constexpr decltype(auto) apply(T_table&& table) | |||||
| { return std::forward<T_table>(table).wrapped_dataset; } | |||||
| }; | |||||
| } | } | ||||
| /* is_table */ | /* is_table */ | ||||
| @@ -5,10 +5,20 @@ | |||||
| #include <iostream> | #include <iostream> | ||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cppcore/misc/exception.h> | |||||
| namespace cpphibernate | namespace cpphibernate | ||||
| { | { | ||||
| /** | |||||
| * @brief Hibernate exception class. | |||||
| */ | |||||
| struct exception | |||||
| : public cppcore::exception | |||||
| { | |||||
| using cppcore::exception::exception; | |||||
| }; | |||||
| /** | /** | ||||
| * @brief Represents a string with an fixed length. | * @brief Represents a string with an fixed length. | ||||
| */ | */ | ||||
| @@ -7,6 +7,10 @@ Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_S | |||||
| Find_Package ( Hana REQUIRED ) | Find_Package ( Hana REQUIRED ) | ||||
| Find_Package ( cppmp REQUIRED ) | Find_Package ( cppmp REQUIRED ) | ||||
| Find_Package ( cppcore REQUIRED ) | Find_Package ( cppcore REQUIRED ) | ||||
| Find_Package ( cppmariadb REQUIRED ) | |||||
| If ( cppmariadb_FOUND ) | |||||
| Set ( CPPHIBERNATE_HAS_CPPMARIADB true ) | |||||
| EndIf ( ) | |||||
| # Object Library ################################################################################## | # Object Library ################################################################################## | ||||
| @@ -29,6 +33,11 @@ Target_Link_Libraries ( cpphibernate-objects | |||||
| hana | hana | ||||
| cppmp::cppmp | cppmp::cppmp | ||||
| cppcore::cppcore ) | cppcore::cppcore ) | ||||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||||
| Target_Link_Libraries ( cpphibernate-objects | |||||
| PUBLIC | |||||
| cppmariadb::cppmariadb-shared ) | |||||
| EndIf ( ) | |||||
| # Static Library ################################################################################## | # Static Library ################################################################################## | ||||
| @@ -41,6 +50,11 @@ Target_Include_Directories ( cpphibernate-static | |||||
| PUBLIC | PUBLIC | ||||
| $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | ||||
| $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | ||||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||||
| Target_Link_Libraries ( cpphibernate-static | |||||
| PUBLIC | |||||
| cppmariadb::cppmariadb-static ) | |||||
| EndIf ( ) | |||||
| # Shared Library ################################################################################## | # Shared Library ################################################################################## | ||||
| @@ -54,6 +68,11 @@ Target_Include_Directories ( cpphibernate-shared | |||||
| PUBLIC | PUBLIC | ||||
| $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | ||||
| $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | ||||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||||
| Target_Link_Libraries ( cpphibernate-shared | |||||
| PUBLIC | |||||
| cppmariadb::cppmariadb-shared ) | |||||
| EndIf ( ) | |||||
| # Optimization #################################################################################### | # Optimization #################################################################################### | ||||
| @@ -0,0 +1,135 @@ | |||||
| #include <cpphibernate/misc/print_container.h> | |||||
| #include <cpphibernate/driver/mariadb/classes/fields/field.h> | |||||
| #include <cpphibernate/driver/mariadb/classes/tables/table.h> | |||||
| #include <cppcore/misc/indent.h> | |||||
| using namespace ::cpphibernate; | |||||
| using namespace ::cpphibernate::mariadb; | |||||
| /* field_t */ | |||||
| field_t::~field_t() | |||||
| { } | |||||
| std::ostream& field_t::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"id\": " << id << "," | |||||
| // TODO | |||||
| // << indent << "\"dataset_id\": " << dataset_id << "," | |||||
| // << indent << "\"real_dataset_id\": " << real_dataset_id << "," | |||||
| << indent << "\"value_id\": " << value_id << "," | |||||
| << indent << "\"real_value_id\": " << real_value_id << "," | |||||
| << indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << "," | |||||
| << indent << "\"value_is_pointer\": " << (value_is_pointer ? "true" : "false") << "," | |||||
| << indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << "," | |||||
| << indent << "\"value_is_auto_incremented\": " << (value_is_auto_incremented ? "true" : "false") << "," | |||||
| << indent << "\"table\": " << '"' << table.name << "\"," | |||||
| << indent << "\"referenced_table\": " << (referenced_table | |||||
| ? std::string("\"") + referenced_table->name + "\"" | |||||
| : "null") << "," | |||||
| // TODO | |||||
| // << indent << "\"schema_name\": \"" << schema_name << "\"," | |||||
| // << indent << "\"table_name\": \"" << table_name << "\"," | |||||
| // << indent << "\"field_name\": \"" << field_name << "\"," | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"type\": \"" << type << "\"," | |||||
| << indent << "\"create_arguments\": \"" << create_arguments << "\"," | |||||
| << indent << "\"convert_to_open\": \"" << convert_to_open << "\"," | |||||
| << indent << "\"convert_to_close\": \"" << convert_to_close << "\"," | |||||
| << indent << "\"convert_from_open\": \"" << convert_from_open << "\"," | |||||
| << indent << "\"convert_from_close\": \"" << convert_from_close << "\"," | |||||
| << indent << "\"attributes\": " << make_print_container(attributes, false) | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| return os; | |||||
| } | |||||
| void field_t::init() | |||||
| { | |||||
| /* conver_to_open */ | |||||
| { | |||||
| std::ostringstream ss; | |||||
| for (auto& attrib : attributes) | |||||
| { | |||||
| switch(attrib) | |||||
| { | |||||
| case attribute_t::hex: | |||||
| ss << "HEX("; | |||||
| break; | |||||
| case attribute_t::compress: | |||||
| ss << "COMPRESS("; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| convert_to_open = ss.str(); | |||||
| } | |||||
| /* convert_to_close */ | |||||
| { | |||||
| std::ostringstream ss; | |||||
| for (auto& attrib : attributes) | |||||
| { | |||||
| switch(attrib) | |||||
| { | |||||
| case attribute_t::hex: | |||||
| case attribute_t::compress: | |||||
| ss << ')'; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| convert_to_close = ss.str(); | |||||
| } | |||||
| /* convert_from_open */ | |||||
| { | |||||
| std::ostringstream ss; | |||||
| for (auto& attrib : attributes) | |||||
| { | |||||
| switch(attrib) | |||||
| { | |||||
| case attribute_t::hex: | |||||
| ss << "UNHEX("; | |||||
| break; | |||||
| case attribute_t::compress: | |||||
| ss << "UNCOMPRESS("; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| convert_from_open = ss.str(); | |||||
| } | |||||
| /* convert_from_close */ | |||||
| { | |||||
| std::ostringstream ss; | |||||
| for (auto& attrib : attributes) | |||||
| { | |||||
| switch(attrib) | |||||
| { | |||||
| case attribute_t::hex: | |||||
| case attribute_t::compress: | |||||
| ss << ')'; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| convert_from_close = ss.str(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,127 @@ | |||||
| #include <cpphibernate/misc/print_container.h> | |||||
| #include <cpphibernate/driver/mariadb/classes/schema/schema.h> | |||||
| #include <cppcore/misc/indent.h> | |||||
| using namespace ::cpphibernate; | |||||
| using namespace ::cpphibernate::mariadb; | |||||
| /* schema_t */ | |||||
| std::ostream& schema_t::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"schema_name\": \"" << name << "\"," | |||||
| << indent << "\"tables\": " << make_print_container(tables, true, [](auto& s, auto& table) { | |||||
| table->print(s); | |||||
| }) | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| return os; | |||||
| } | |||||
| void schema_t::init() | |||||
| { | |||||
| /* build lookup */ | |||||
| for (auto& t : tables) | |||||
| { | |||||
| assert(static_cast<bool>(t)); | |||||
| _lookup.emplace(t->dataset_id, t.get()); | |||||
| } | |||||
| /* update table referencs */ | |||||
| for (auto& t : tables) | |||||
| { | |||||
| assert(static_cast<bool>(t)); | |||||
| auto& table = const_cast<table_t&>(*t); | |||||
| /* get base table */ | |||||
| auto it = _lookup.find(table.base_dataset_id); | |||||
| table.base_table = (it != _lookup.end() | |||||
| ? it->second | |||||
| : nullptr); | |||||
| /* dereived tables */ | |||||
| for (auto& id : table.derived_dataset_ids) | |||||
| { | |||||
| it = _lookup.find(id); | |||||
| if (it == _lookup.end()) | |||||
| throw exception(std::string("unable to find derived table for dataset id ") + std::to_string(id)); | |||||
| table.derived_tables.emplace_back(it->second); | |||||
| } | |||||
| /* update fields */ | |||||
| for (auto& f : table.fields) | |||||
| { | |||||
| assert(static_cast<bool>(f)); | |||||
| auto& field = const_cast<field_t&>(*f); | |||||
| /* referenced_table */ | |||||
| it = _lookup.find(field.real_value_id); | |||||
| auto * referenced_table = (it != _lookup.end() | |||||
| ? const_cast<table_t*>(it->second) | |||||
| : nullptr); | |||||
| field.referenced_table = referenced_table; | |||||
| /* primary key field */ | |||||
| if (field.attributes.count(attribute_t::primary_key)) | |||||
| { | |||||
| if (static_cast<bool>(table.primary_key_field)) | |||||
| throw exception(std::string("Table '") + table.name + "' can not have more then one primary key!"); | |||||
| table.primary_key_field = &field; | |||||
| } | |||||
| /* foreign table field */ | |||||
| else if (static_cast<bool>(referenced_table)) | |||||
| { | |||||
| table.foreign_table_fields.emplace_back(&field); | |||||
| if (field.value_is_container) | |||||
| { | |||||
| referenced_table->is_used_in_container = true; | |||||
| } | |||||
| } | |||||
| /* normal data field */ | |||||
| else | |||||
| { | |||||
| table.data_fields.emplace_back(&field); | |||||
| } | |||||
| } | |||||
| if (!static_cast<bool>(table.primary_key_field)) | |||||
| throw exception(std::string("Table '") + table.name + "' does not have a primary key!"); | |||||
| } | |||||
| /* update foreign fields (one, many, key) */ | |||||
| for (auto& t : tables) | |||||
| { | |||||
| assert(static_cast<bool>(t)); | |||||
| auto& table = const_cast<table_t&>(*t); | |||||
| for (auto& f : table.foreign_table_fields) | |||||
| { | |||||
| assert(static_cast<bool>(f)); | |||||
| assert(static_cast<bool>(f->referenced_table)); | |||||
| auto& field = *f; | |||||
| auto& referenced_table = const_cast<table_t&>(*field.referenced_table); | |||||
| if (field.value_is_container) | |||||
| { | |||||
| table.foreign_table_many_fields.emplace_back(&field); | |||||
| referenced_table.foreign_key_fields.emplace_back(&field); | |||||
| } | |||||
| else | |||||
| { | |||||
| table.foreign_table_one_fields.emplace_back(&field); | |||||
| if (referenced_table.is_used_in_container) | |||||
| { | |||||
| referenced_table.foreign_key_fields.push_back(&field); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,66 @@ | |||||
| #include <cpphibernate/misc/print_container.h> | |||||
| #include <cpphibernate/driver/mariadb/classes/tables/table.h> | |||||
| #include <cppcore/misc/indent.h> | |||||
| using namespace ::cpphibernate; | |||||
| using namespace ::cpphibernate::mariadb; | |||||
| /* table_t */ | |||||
| table_t::~table_t() | |||||
| { } | |||||
| std::ostream& table_t::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::cppcore; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"id\": " << id << "," | |||||
| // TODO | |||||
| << indent << "\"dataset_id\": " << dataset_id << "," | |||||
| << indent << "\"base_dataset_id\": " << base_dataset_id << "," | |||||
| << indent << "\"derived_dataset_ids\": " << make_print_container(derived_dataset_ids, false) << "," | |||||
| // TODO | |||||
| // << indent << "\"schema_name\": \"" << schema_name << "\"," | |||||
| // << indent << "\"table_name\": \"" << table_name << "\"," | |||||
| << indent << "\"name\": \"" << name << "\"," | |||||
| << indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->name + "\"" : "null") << "," | |||||
| << indent << "\"derived_tables\":" << make_print_container(derived_tables, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"primary_key_field\": " << (primary_key_field ? std::string("\"") + primary_key_field->name + "\"" : "null") << "," | |||||
| << indent << "\"foreign_key_fields\": " << make_print_container(foreign_key_fields, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '.' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_fields\": " << make_print_container(foreign_table_fields, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_one_fields\": " << make_print_container(foreign_table_one_fields, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_many_fields\": " << make_print_container(foreign_table_many_fields, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"data_fields\": " << make_print_container(data_fields, true, [](auto& s, auto& ptr){ | |||||
| s << indent << '"' << ptr->name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"fields\":" << make_print_container(fields, true, [](auto& s, auto& field) { | |||||
| field->print(s); | |||||
| }) | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| return os; | |||||
| } | |||||
| void table_t::init() | |||||
| { | |||||
| /* build field lookup */ | |||||
| for (auto& f : fields) | |||||
| { | |||||
| assert(static_cast<bool>(f)); | |||||
| _lookup.emplace(f->id, f.get()); | |||||
| } | |||||
| } | |||||
| @@ -23,7 +23,7 @@ Add_Executable ( cpphibernate-test | |||||
| Target_Link_Libraries ( cpphibernate-test | Target_Link_Libraries ( cpphibernate-test | ||||
| PUBLIC | PUBLIC | ||||
| cpphibernate-objects | cpphibernate-objects | ||||
| GTest::Main ) | |||||
| GMock::Main ) | |||||
| # pedantic | # pedantic | ||||
| If ( HAS_PEDANTIC ) | If ( HAS_PEDANTIC ) | ||||
| @@ -7,8 +7,11 @@ | |||||
| using namespace ::testing; | using namespace ::testing; | ||||
| using namespace ::cpphibernate; | using namespace ::cpphibernate; | ||||
| namespace hana = ::boost::hana; | |||||
| TEST(CppHibernateTests, init) | TEST(CppHibernateTests, init) | ||||
| { | { | ||||
| /* | |||||
| StrictMock<mariadb_mock> mock; | StrictMock<mariadb_mock> mock; | ||||
| expect_query(mock, "START TRANSACTION"); | expect_query(mock, "START TRANSACTION"); | ||||
| @@ -293,8 +296,11 @@ TEST(CppHibernateTests, init) | |||||
| mock, | mock, | ||||
| mysql_close( | mysql_close( | ||||
| reinterpret_cast<MYSQL*>(0x1111))); | reinterpret_cast<MYSQL*>(0x1111))); | ||||
| */ | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | ||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.init(true); | |||||
| auto context = make_context<mariadb_driver>(test_schema); | |||||
| (void)context; | |||||
| context.print(std::cout) << std::endl << std::endl; | |||||
| // context.init(true); | |||||
| } | } | ||||
| @@ -1,29 +0,0 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <cpphibernate.h> | |||||
| #include "test_schema.h" | |||||
| using namespace ::testing; | |||||
| using namespace ::cpphibernate; | |||||
| using namespace ::cpphibernate::schema; | |||||
| using namespace hana::literals; | |||||
| constexpr decltype(auto) tmp_table = test_schema.tables[0_c]; | |||||
| constexpr decltype(auto) tmp_field = tmp_table.fields[0_c]; | |||||
| constexpr decltype(auto) mod = make_modifiers( | |||||
| limit(5_c), | |||||
| offset(3_c), | |||||
| order_by( | |||||
| ascending(tmp_field), | |||||
| descending(tmp_field)), | |||||
| where( | |||||
| or_( | |||||
| negation(equal(tmp_field, 1)), | |||||
| negation(equal(tmp_field, 1))))); | |||||
| TEST(cpphibernate_tests, dummy) | |||||
| { | |||||
| (void)mod; | |||||
| } | |||||
| @@ -180,4 +180,4 @@ inline void expect_query(T_mock& mock, const std::string& query, T_result&& resu | |||||
| template<typename T_mock> | template<typename T_mock> | ||||
| inline void expect_query(T_mock& mock, const std::string& query) | inline void expect_query(T_mock& mock, const std::string& query) | ||||
| { expect_query(mock, query, result_stored()); } | |||||
| { expect_query(mock, query, result_stored()); } | |||||