| @@ -1,5 +1,6 @@ | |||
| #pragma once | |||
| #include "cpphibernate/context.h" | |||
| #include "cpphibernate/misc.h" | |||
| #include "cpphibernate/modifier.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 | |||
| #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 | |||
| #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 | |||
| { | |||
| @@ -25,10 +30,10 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| struct attribute_converter<schema::attribute::primary_key_type> | |||
| { static constexpr decltype(auto) value = attribute_t::primary_key; }; | |||
| /* make_attributes_impl */ | |||
| /* attributes_builder */ | |||
| template<typename T, typename> | |||
| struct make_attributes_impl | |||
| struct attributes_builder | |||
| { | |||
| template<typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| @@ -36,10 +41,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| }; | |||
| template<typename T_attributes> | |||
| struct make_attributes_impl< | |||
| struct attributes_builder< | |||
| 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> | |||
| 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 | |||
| #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: | |||
| using lock_type = std::unique_ptr<transaction_lock>; | |||
| @@ -21,9 +42,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| public: | |||
| 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); | |||
| @@ -114,7 +134,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| 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 | |||
| #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 | |||
| #include <cpphibernate/types.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> | |||
| 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 | |||
| #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 <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> | |||
| 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 __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. | |||
| * | |||
| * @tparam T_group Type used for groupig different types. | |||
| */ | |||
| 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 | |||
| */ | |||
| 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 | |||
| */ | |||
| 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 | |||
| #include <cppcore/misc/indent.h> | |||
| #include <cppcore/conversion/string.h> | |||
| #include "print_container.h" | |||
| @@ -77,8 +78,10 @@ namespace cpphibernate | |||
| { 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) | |||
| { | |||
| @@ -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) | |||
| { | |||
| using namespace ::cppcore; | |||
| make_print_container( | |||
| return make_print_container( | |||
| std::forward<T_container>(container), | |||
| do_indent, | |||
| [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> | |||
| 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" | |||
| @@ -50,4 +50,79 @@ namespace cpphibernate | |||
| : 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 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"; }; | |||
| @@ -1,6 +1,7 @@ | |||
| #pragma once | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/misc/type_helper.h> | |||
| namespace cpphibernate { | |||
| namespace schema { | |||
| @@ -8,6 +9,85 @@ namespace schema { | |||
| 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. | |||
| */ | |||
| @@ -3,9 +3,8 @@ | |||
| #include <cppcore/misc/indent.h> | |||
| #include <cppcore/misc/type_helper.h> | |||
| #include <cpphibernate/misc/type_helper.h> | |||
| #include "field.h" | |||
| #include "attributes.h" | |||
| namespace cpphibernate { | |||
| namespace schema { | |||
| @@ -13,30 +12,11 @@ namespace schema { | |||
| namespace __impl | |||
| { | |||
| /* tag_field */ | |||
| struct tag_field | |||
| { }; | |||
| /* field_t */ | |||
| 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_getter&& p_getter, | |||
| T_setter&& p_setter, | |||
| @@ -47,38 +27,30 @@ namespace schema { | |||
| , 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 */ | |||
| @@ -95,10 +67,9 @@ namespace schema { | |||
| mp::list<T_name, T_getter, T_setter, T_attributes>, | |||
| mp::enable_if_t< | |||
| 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 getter_type = T_getter; | |||
| @@ -8,12 +8,83 @@ namespace schema { | |||
| 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. | |||
| */ | |||
| template<typename X, typename = void> | |||
| 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> { }; | |||
| /** | |||
| * @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" | |||
| @@ -1,5 +1,8 @@ | |||
| #pragma once | |||
| #include <cppcore/misc/indent.h> | |||
| #include "tables.h" | |||
| #include "schema.h" | |||
| namespace cpphibernate { | |||
| @@ -8,57 +11,39 @@ namespace schema { | |||
| namespace __impl | |||
| { | |||
| /* tag_schema */ | |||
| struct tag_schema | |||
| { }; | |||
| /* schema_t */ | |||
| 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, | |||
| tables_type&& p_tables) | |||
| : name (std::forward<name_type> (p_name)) | |||
| , 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 */ | |||
| @@ -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 */ | |||
| @@ -8,12 +8,93 @@ namespace schema { | |||
| 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. | |||
| */ | |||
| template<typename X, typename = void> | |||
| 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> { }; | |||
| /** | |||
| * @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" | |||
| @@ -1,5 +1,8 @@ | |||
| #pragma once | |||
| #include <cpphibernate/misc/type_helper.h> | |||
| #include "fields.h" | |||
| #include "table.h" | |||
| namespace cpphibernate { | |||
| @@ -8,35 +11,11 @@ namespace schema { | |||
| namespace __impl | |||
| { | |||
| /* tag_table */ | |||
| struct tag_table | |||
| { }; | |||
| /* 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, | |||
| wrapped_dataset_type p_wrapped_dataset, | |||
| table_id_type p_table_id, | |||
| @@ -47,34 +26,29 @@ namespace schema { | |||
| , 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 */ | |||
| @@ -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 */ | |||
| @@ -5,10 +5,20 @@ | |||
| #include <iostream> | |||
| #include <cpphibernate/config.h> | |||
| #include <cppcore/misc/exception.h> | |||
| namespace cpphibernate | |||
| { | |||
| /** | |||
| * @brief Hibernate exception class. | |||
| */ | |||
| struct exception | |||
| : public cppcore::exception | |||
| { | |||
| using cppcore::exception::exception; | |||
| }; | |||
| /** | |||
| * @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 ( cppmp REQUIRED ) | |||
| Find_Package ( cppcore REQUIRED ) | |||
| Find_Package ( cppmariadb REQUIRED ) | |||
| If ( cppmariadb_FOUND ) | |||
| Set ( CPPHIBERNATE_HAS_CPPMARIADB true ) | |||
| EndIf ( ) | |||
| # Object Library ################################################################################## | |||
| @@ -29,6 +33,11 @@ Target_Link_Libraries ( cpphibernate-objects | |||
| hana | |||
| cppmp::cppmp | |||
| cppcore::cppcore ) | |||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||
| Target_Link_Libraries ( cpphibernate-objects | |||
| PUBLIC | |||
| cppmariadb::cppmariadb-shared ) | |||
| EndIf ( ) | |||
| # Static Library ################################################################################## | |||
| @@ -41,6 +50,11 @@ Target_Include_Directories ( cpphibernate-static | |||
| PUBLIC | |||
| $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | |||
| $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | |||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||
| Target_Link_Libraries ( cpphibernate-static | |||
| PUBLIC | |||
| cppmariadb::cppmariadb-static ) | |||
| EndIf ( ) | |||
| # Shared Library ################################################################################## | |||
| @@ -54,6 +68,11 @@ Target_Include_Directories ( cpphibernate-shared | |||
| PUBLIC | |||
| $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | |||
| $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | |||
| If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||
| Target_Link_Libraries ( cpphibernate-shared | |||
| PUBLIC | |||
| cppmariadb::cppmariadb-shared ) | |||
| EndIf ( ) | |||
| # 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 | |||
| PUBLIC | |||
| cpphibernate-objects | |||
| GTest::Main ) | |||
| GMock::Main ) | |||
| # pedantic | |||
| If ( HAS_PEDANTIC ) | |||
| @@ -7,8 +7,11 @@ | |||
| using namespace ::testing; | |||
| using namespace ::cpphibernate; | |||
| namespace hana = ::boost::hana; | |||
| TEST(CppHibernateTests, init) | |||
| { | |||
| /* | |||
| StrictMock<mariadb_mock> mock; | |||
| expect_query(mock, "START TRANSACTION"); | |||
| @@ -293,8 +296,11 @@ TEST(CppHibernateTests, init) | |||
| mock, | |||
| mysql_close( | |||
| 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> | |||
| inline void expect_query(T_mock& mock, const std::string& query) | |||
| { expect_query(mock, query, result_stored()); } | |||
| { expect_query(mock, query, result_stored()); } | |||