| @@ -1,6 +1,7 @@ | |||
| #pragma once | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/context.h> | |||
| #include <cpphibernate/misc.h> | |||
| #include <cpphibernate/modifier.h> | |||
| #include <cpphibernate/schema.h> | |||
| @@ -40,14 +40,20 @@ | |||
| #define beg_namespace_cpphibernate namespace cpphibernate | |||
| #define end_namespace_cpphibernate | |||
| #define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema) | |||
| #define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema) | |||
| #define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc) | |||
| #define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc) | |||
| #define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_modifier cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, modifier) | |||
| #define end_namespace_cpphibernate_modifier cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_modifier cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, modifier) | |||
| #define end_namespace_cpphibernate_modifier cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_driver cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, driver) | |||
| #define end_namespace_cpphibernate_driver cpphibernate_define_namespace_end(end_namespace_cpphibernate) | |||
| #define beg_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_beg(beg_namespace_cpphibernate_driver, mariadb_impl) | |||
| #define end_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_end(end_namespace_cpphibernate_driver) | |||
| beg_namespace_cpphibernate | |||
| { | |||
| @@ -0,0 +1,122 @@ | |||
| #pragma once | |||
| #include <memory> | |||
| #include <cpphibernate/misc.h> | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/schema/table.h> | |||
| #include <cpphibernate/schema/tables.h> | |||
| #include <cpphibernate/modifier/where.h> | |||
| #include <cpphibernate/modifier/modifier.h> | |||
| beg_namespace_cpphibernate | |||
| { | |||
| namespace __impl | |||
| { | |||
| template<typename T_driver, typename T_schema> | |||
| struct context_t | |||
| : 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: | |||
| template<typename... T_args> | |||
| constexpr context_t(const schema_type& p_schema, T_args&&... args) | |||
| : base_type (p_schema, std::forward<T_args>(args)...) | |||
| , _schema (p_schema) | |||
| { } | |||
| cpphibernate_copyable(context_t, delete); | |||
| cpphibernate_moveable(context_t, default); | |||
| /* init */ | |||
| inline void init(bool recreate) | |||
| { this->init_impl(recreate); } | |||
| /* create */ | |||
| template<typename T_dataset> | |||
| constexpr void create(T_dataset& dataset) | |||
| { this->create_impl(dataset); } | |||
| /* read */ | |||
| template<typename T_dataset, typename... T_modifiers> | |||
| constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers) | |||
| -> mp::enable_if< | |||
| modifier::all_are_modifier<mp::decay_t<T_modifiers>...>> | |||
| { | |||
| 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, hana::make_tuple(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, hana::make_tuple(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, hana::make_tuple()); | |||
| } | |||
| /* update */ | |||
| template<typename T_dataset> | |||
| constexpr void update(T_dataset& dataset) | |||
| { this->update_impl(dataset); } | |||
| /* destroy */ | |||
| template<typename T_dataset> | |||
| constexpr void destroy(T_dataset& dataset) | |||
| { this->destroy_impl(dataset); } | |||
| }; | |||
| } | |||
| /* make */ | |||
| template<typename T_driver, typename T_schema, typename... T_args> | |||
| constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args) | |||
| { | |||
| using context_type = __impl::context_t<T_driver, T_schema>; | |||
| return context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...); | |||
| } | |||
| 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 = __impl::context_t<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)...)); | |||
| } | |||
| } | |||
| end_namespace_cpphibernate | |||
| @@ -0,0 +1,12 @@ | |||
| #pragma once | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/driver/mariadb/mariadb.h> | |||
| beg_namespace_cpphibernate_driver | |||
| { | |||
| using mariadb = mariadb_impl::mariadb_driver_t; | |||
| } | |||
| end_namespace_cpphibernate_driver | |||
| @@ -0,0 +1,34 @@ | |||
| #pragma once | |||
| #include <cppmariadb.h> | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/driver/mariadb/schema.h> | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| struct mariadb_driver_t | |||
| { | |||
| private: | |||
| ::cppmariadb::connection& _connection; | |||
| schema_t _schema; | |||
| 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))) | |||
| { } | |||
| cpphibernate_copyable(mariadb_driver_t, delete); | |||
| cpphibernate_moveable(mariadb_driver_t, default); | |||
| inline decltype(auto) connection() | |||
| { return _connection; } | |||
| inline auto& schema() | |||
| { return _schema; } | |||
| }; | |||
| } | |||
| end_namespace_cpphibernate_driver_mariadb | |||
| @@ -0,0 +1,15 @@ | |||
| #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/schema.h> | |||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||
| #include <cpphibernate/driver/mariadb/schema/tables.h> | |||
| @@ -0,0 +1,34 @@ | |||
| #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 | |||
| @@ -0,0 +1,76 @@ | |||
| #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; | |||
| }; | |||
| namespace __impl | |||
| { | |||
| /* attribute_converter */ | |||
| template<typename T_attribute> | |||
| struct attribute_converter; | |||
| template<> | |||
| struct attribute_converter<schema::attribute::hex_type> | |||
| { static constexpr decltype(auto) value = attribute_t::hex; }; | |||
| template<> | |||
| struct attribute_converter<schema::attribute::compress_type> | |||
| { static constexpr decltype(auto) value = attribute_t::compress; }; | |||
| template<> | |||
| struct attribute_converter<schema::attribute::primary_key_type> | |||
| { static constexpr decltype(auto) value = attribute_t::primary_key; }; | |||
| /* make_attributes_impl */ | |||
| template<typename T, typename> | |||
| struct make_attributes_impl | |||
| { | |||
| template<typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); } | |||
| }; | |||
| template<typename T_attributes> | |||
| struct make_attributes_impl< | |||
| mp::list<T_attributes>, | |||
| mp::enable_if_c< | |||
| schema::is_attributes<mp::decay_t<T_attributes>>::value>> | |||
| { | |||
| template<size_t... I> | |||
| static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&) | |||
| { | |||
| return attributes_t({ | |||
| attribute_converter<mp::decay_t<decltype(std::declval<T_attributes>()[hana::size_c<I>])>>::value... | |||
| }); | |||
| } | |||
| static constexpr decltype(auto) apply(const T_attributes& attributes) | |||
| { | |||
| using size = mp::decay_t<decltype(hana::size(attributes))>; | |||
| return helper(attributes, std::make_index_sequence<size::value> { }); | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_driver_mariadb | |||
| @@ -0,0 +1,31 @@ | |||
| #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 | |||
| @@ -0,0 +1,193 @@ | |||
| #pragma once | |||
| #include <cpphibernate/misc.h> | |||
| #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/attributes.h> | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| /* field_t */ | |||
| struct field_t | |||
| { | |||
| size_t table_dataset_id { 0 }; | |||
| size_t value_dataset_id { 0 }; | |||
| bool value_is_nullable { false }; | |||
| bool value_is_container { false }; | |||
| std::string schema_name; | |||
| std::string table_name; | |||
| std::string field_name; | |||
| attributes_t attributes; | |||
| const table_t* table { nullptr }; | |||
| const table_t* referenced_table { nullptr }; | |||
| inline field_t() = default; | |||
| inline field_t(const field_t&) = delete; | |||
| inline field_t(field_t&& other) | |||
| : table_dataset_id (std::move(other).table_dataset_id) | |||
| , value_dataset_id (std::move(other).value_dataset_id) | |||
| , value_is_nullable (std::move(other).value_is_nullable) | |||
| , value_is_container(std::move(other).value_is_container) | |||
| , schema_name (std::move(other).schema_name) | |||
| , table_name (std::move(other).table_name) | |||
| , field_name (std::move(other).field_name) | |||
| , attributes (std::move(other).attributes) | |||
| , table (nullptr) | |||
| , referenced_table (nullptr) | |||
| { } | |||
| virtual ~field_t() = default; | |||
| }; | |||
| /* simple_field_t */ | |||
| template<typename T_schema, typename T_field> | |||
| struct simple_field_t | |||
| : public field_t | |||
| { | |||
| using schema_type = T_schema; | |||
| using field_type = T_field; | |||
| const schema_type& schema; | |||
| const field_type& field; | |||
| inline simple_field_t(const schema_type& p_schema, const field_type& p_field) | |||
| : field_t () | |||
| , schema (p_schema) | |||
| , field (p_field) | |||
| { } | |||
| }; | |||
| /* value_field_t */ | |||
| template<typename T_schema, typename T_field> | |||
| struct value_field_t | |||
| : public simple_field_t<T_schema, T_field> | |||
| { | |||
| using base_type = simple_field_t<T_schema, T_field>; | |||
| using base_type::base_type; | |||
| }; | |||
| /* primary_key_field_t */ | |||
| template<typename T_schema, typename T_field> | |||
| struct primary_key_field_t | |||
| : public value_field_t<T_schema, T_field> | |||
| { | |||
| using base_type = value_field_t<T_schema, T_field>; | |||
| using base_type::base_type; | |||
| }; | |||
| /* data_field_t */ | |||
| template<typename T_schema, typename T_field> | |||
| struct data_field_t | |||
| : public value_field_t<T_schema, T_field> | |||
| { | |||
| using base_type = value_field_t<T_schema, T_field>; | |||
| using base_type::base_type; | |||
| }; | |||
| /* foreign_table_field_t */ | |||
| template<typename T_schema, typename T_field> | |||
| struct foreign_table_field_t | |||
| : public simple_field_t<T_schema, T_field> | |||
| { | |||
| using base_type = simple_field_t<T_schema, T_field>; | |||
| using base_type::base_type; | |||
| }; | |||
| 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_schema, 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_schema, 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_schema, 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 getter_type = mp::decay_t<typename field_type::getter_type>; | |||
| using value_type = mp::decay_t<typename getter_type::value_type>; | |||
| using dataset_type = mp::decay_t<typename getter_type::dataset_type>; | |||
| using value_dataset_type = misc::real_dataset_t<value_type>; | |||
| using return_type = field_type_t<schema_type, field_type>; | |||
| return_type ret(schema, field); | |||
| ret.table_dataset_id = misc::get_type_id(hana::type_c<dataset_type>), | |||
| ret.value_dataset_id = misc::get_type_id(hana::type_c<value_dataset_type>), | |||
| ret.value_is_nullable = misc::is_nullable<value_type>::value, | |||
| ret.value_is_container = misc::is_container<value_type>::value, | |||
| ret.schema_name = schema.name, | |||
| ret.table_name = table.name, | |||
| ret.field_name = field.name, | |||
| ret.attributes = make_attributes(field.attributes); | |||
| return ret; | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_driver_mariadb | |||
| @@ -0,0 +1,29 @@ | |||
| #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 | |||
| @@ -0,0 +1,71 @@ | |||
| #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; | |||
| }; | |||
| 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 | |||
| @@ -0,0 +1,27 @@ | |||
| #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 | |||
| @@ -0,0 +1,61 @@ | |||
| #pragma once | |||
| #include <cpphibernate/misc.h> | |||
| #include <cpphibernate/config.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; | |||
| }; | |||
| 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 | |||
| @@ -0,0 +1,31 @@ | |||
| #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 | |||
| @@ -0,0 +1,194 @@ | |||
| #pragma once | |||
| #include <memory> | |||
| #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/fields.h> | |||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| /* table_t */ | |||
| struct table_t | |||
| { | |||
| size_t dataset_id { 0 }; | |||
| size_t base_dataset_id { 0 }; | |||
| size_t table_id { 0 }; | |||
| 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() = default; | |||
| }; | |||
| /* table_simple_t */ | |||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||
| struct table_simple_t | |||
| : public table_t | |||
| { | |||
| using schema_type = T_schema; | |||
| using table_type = T_table; | |||
| using base_dataset_type = T_base_dataset; | |||
| 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> | |||
| { | |||
| using base_type = table_simple_t<T_schema, T_table, T_base_dataset>; | |||
| using schema_type = T_schema; | |||
| using table_type = T_table; | |||
| using base_dataset_type = T_base_dataset; | |||
| using base_type::base_type; | |||
| const schema_type& schema; | |||
| const table_type& table; | |||
| }; | |||
| 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 table_type = table_type_t<dataset_type, base_type>; | |||
| 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 | |||
| @@ -0,0 +1,29 @@ | |||
| #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 | |||
| @@ -0,0 +1,69 @@ | |||
| #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; | |||
| }; | |||
| 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 | |||
| @@ -1,6 +1,7 @@ | |||
| #pragma once | |||
| #include <cpphibernate/config.h> | |||
| #include <cpputils/misc/type_helper.h> | |||
| beg_namespace_cpphibernate_misc | |||
| { | |||
| @@ -15,5 +16,17 @@ beg_namespace_cpphibernate_misc | |||
| { return T_builder<mp::list<T_args...>>::apply(std::forward<T_args>(args)...); } | |||
| }; | |||
| /* get_dataset_id */ | |||
| namespace __impl | |||
| { | |||
| struct counter_type_id | |||
| { }; | |||
| } | |||
| template<typename T_type> | |||
| constexpr decltype(auto) get_type_id(T_type&&) | |||
| { return utl::get_unique_id<__impl::counter_type_id, mp::decay_t<T_type>>(); } | |||
| } | |||
| end_namespace_cpphibernate_misc | |||
| @@ -96,14 +96,6 @@ beg_namespace_cpphibernate_misc | |||
| struct real_dataset_impl<std::list<T>, void> | |||
| { using type = typename real_dataset_impl<T>::type; }; | |||
| template<typename T_from, typename T_to, typename = void> | |||
| struct change_dataset_type_impl | |||
| { using type = T_to; }; | |||
| template<template<typename...> class X, typename T_from, typename T_to> | |||
| struct change_dataset_type_impl<X<T_from>, T_to, void> | |||
| { using type = X<T_to>; }; | |||
| } | |||
| /* meta */ | |||
| @@ -15,7 +15,7 @@ beg_namespace_cpphibernate_modifier | |||
| struct where_clause_and_t | |||
| : public where_clause_t | |||
| { | |||
| using clauses_type = hana::basic_tuple<T_clauses...>; | |||
| using clauses_type = hana::tuple<T_clauses...>; | |||
| clauses_type clauses; | |||
| @@ -15,7 +15,7 @@ beg_namespace_cpphibernate_modifier | |||
| struct where_clause_or_t | |||
| : public where_clause_t | |||
| { | |||
| using clauses_type = hana::basic_tuple<T_clauses...>; | |||
| using clauses_type = hana::tuple<T_clauses...>; | |||
| clauses_type clauses; | |||
| @@ -13,7 +13,7 @@ beg_namespace_cpphibernate_schema | |||
| /* attributes_t */ | |||
| template<typename... T_attributes> | |||
| using attributes_t = hana::basic_tuple<T_attributes...>; | |||
| using attributes_t = hana::tuple<T_attributes...>; | |||
| /* is_attributes_impl */ | |||
| @@ -27,37 +27,47 @@ beg_namespace_cpphibernate_schema | |||
| : mp::c_true_t | |||
| { }; | |||
| /* attributes_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_attributes | |||
| : public __impl::is_attributes_impl<T> | |||
| { }; | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* attributes_make_impl */ | |||
| template<typename T, typename = void> | |||
| struct attributes_builder | |||
| struct attributes_make_impl | |||
| { | |||
| template<typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&...) | |||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::make_attributes(...)!"); } | |||
| { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::attributes::make(...)!"); } | |||
| }; | |||
| template<typename... T> | |||
| struct attributes_builder<mp::list<T...>, mp::enable_if_c< | |||
| struct attributes_make_impl<mp::list<T...>, mp::enable_if_c< | |||
| all_are_attribures<mp::decay_t<T>...>::value>> | |||
| { | |||
| template<typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&...) | |||
| { return attributes_t<mp::decay_t<T_args>...> { }; } | |||
| }; | |||
| }; | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_attributes | |||
| : public __impl::is_attributes_impl<T> | |||
| { }; | |||
| namespace attributes | |||
| { | |||
| /* make */ | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::attributes_make_impl> { }; | |||
| constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::attributes_builder> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -72,18 +72,37 @@ beg_namespace_cpphibernate_schema | |||
| } | |||
| }; | |||
| /* field_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_field | |||
| : public mp::is_specialization_of<T, __impl::field_t> | |||
| { }; | |||
| template<typename... T> | |||
| struct all_are_fields | |||
| : public mp::all_true<is_field<T>::value...> | |||
| { }; | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* field_make_impl */ | |||
| template<typename X, typename = void> | |||
| struct field_builder | |||
| struct field_make_impl | |||
| { | |||
| template <typename ...T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_field(...)!"); } | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::field::make(...)!"); } | |||
| }; | |||
| template<typename T_name, typename T_getter, typename T_setter, typename T_attributes> | |||
| struct field_builder<mp::list<T_name, T_getter, T_setter, T_attributes>, mp::enable_if_c< | |||
| struct field_make_impl<mp::list<T_name, T_getter, T_setter, T_attributes>, mp::enable_if_c< | |||
| is_getter<mp::decay_t<T_getter>>::value | |||
| && is_setter<mp::decay_t<T_setter>>::value | |||
| && is_attributes<mp::decay_t<T_attributes>>::value>> | |||
| @@ -96,21 +115,12 @@ beg_namespace_cpphibernate_schema | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_field | |||
| : public mp::is_specialization_of<T, __impl::field_t> | |||
| { }; | |||
| template<typename... T> | |||
| struct all_are_fields | |||
| : public mp::all_true<is_field<T>::value...> | |||
| { }; | |||
| namespace field | |||
| { | |||
| /* make */ | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::field_make_impl> { }; | |||
| constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::field_builder> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -13,7 +13,7 @@ beg_namespace_cpphibernate_schema | |||
| /* fields_t */ | |||
| template<typename... T_fields> | |||
| using fields_t = hana::basic_tuple<T_fields...>; | |||
| using fields_t = hana::tuple<T_fields...>; | |||
| /* is_fields_impl */ | |||
| @@ -27,18 +27,32 @@ beg_namespace_cpphibernate_schema | |||
| : public mp::c_true_t | |||
| { }; | |||
| /* fields_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_fields : | |||
| public __impl::is_fields_impl<T> | |||
| { }; | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* fields_make_impl */ | |||
| template <typename T, typename = void> | |||
| struct fields_builder | |||
| struct fields_make_impl | |||
| { | |||
| template <typename ...T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_fields(...)!"); } | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::fields::make(...)!"); } | |||
| }; | |||
| template<typename... T> | |||
| struct fields_builder<mp::list<T...>, mp::enable_if<all_are_fields<T...>>> | |||
| struct fields_make_impl<mp::list<T...>, mp::enable_if<all_are_fields<T...>>> | |||
| { | |||
| template <typename ...T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| @@ -47,16 +61,12 @@ beg_namespace_cpphibernate_schema | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_fields : | |||
| public __impl::is_fields_impl<T> | |||
| { }; | |||
| namespace fields | |||
| { | |||
| /* constructors */ | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::fields_make_impl> { }; | |||
| constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::fields_builder> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -11,35 +11,22 @@ beg_namespace_cpphibernate_schema | |||
| /* getter_t */ | |||
| template<typename T_value> | |||
| template<typename T_dataset, typename T_value> | |||
| struct getter_t | |||
| { | |||
| using value_type = T_value; | |||
| }; | |||
| /* getter_none_t */ | |||
| struct getter_none_t | |||
| : public getter_t<void> | |||
| { | |||
| using base_type = getter_t<void>; | |||
| using value_type = typename base_type::value_type; | |||
| cpphibernate_constructable(getter_none_t, default); | |||
| cpphibernate_copyable (getter_none_t, delete); | |||
| cpphibernate_moveable (getter_none_t, default); | |||
| using dataset_type = T_dataset; | |||
| using value_type = T_value; | |||
| }; | |||
| /* getter_member_var_t */ | |||
| template<typename T_dataset, typename T_value, typename T_member> | |||
| struct getter_member_var_t | |||
| : public getter_t<T_value> | |||
| : public getter_t<T_dataset, T_value> | |||
| { | |||
| using base_type = getter_t<T_value>; | |||
| using base_type = getter_t<T_dataset, T_value>; | |||
| using dataset_type = typename base_type::dataset_type; | |||
| using value_type = typename base_type::value_type; | |||
| using dataset_type = T_dataset; | |||
| using member_type = T_member; | |||
| member_type member; | |||
| @@ -61,11 +48,11 @@ beg_namespace_cpphibernate_schema | |||
| template<typename T_dataset, typename T_value, typename T_member> | |||
| struct getter_member_func_t | |||
| : public getter_t<T_value> | |||
| : public getter_t<T_dataset, T_value> | |||
| { | |||
| using base_type = getter_t<T_value>; | |||
| using base_type = getter_t<T_dataset, T_value>; | |||
| using dataset_type = typename base_type::dataset_type; | |||
| using value_type = typename base_type::value_type; | |||
| using dataset_type = T_dataset; | |||
| using member_type = T_member; | |||
| member_type member; | |||
| @@ -87,11 +74,11 @@ beg_namespace_cpphibernate_schema | |||
| template<typename T_dataset, typename T_lambda> | |||
| struct getter_lambda_t | |||
| : public getter_t<decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))> | |||
| : public getter_t<T_dataset, decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))> | |||
| { | |||
| using base_type = getter_t<decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))>; | |||
| using base_type = getter_t<T_dataset, decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))>; | |||
| using dataset_type = typename base_type::dataset_type; | |||
| using value_type = typename base_type::value_type; | |||
| using dataset_type = T_dataset; | |||
| using lambda_type = T_lambda; | |||
| lambda_type lambda; | |||
| @@ -118,7 +105,7 @@ beg_namespace_cpphibernate_schema | |||
| template<typename T> | |||
| struct is_getter_impl<T, mp::enable_if_c< | |||
| mp::is_base_of<getter_t<typename T::value_type>, T>::value>> | |||
| mp::is_base_of<getter_t<typename T::dataset_type, typename T::value_type>, T>::value>> | |||
| : public mp::c_true_t | |||
| { }; | |||
| @@ -133,9 +120,6 @@ beg_namespace_cpphibernate_schema | |||
| /* make */ | |||
| constexpr decltype(auto) make_getter_none() | |||
| { return __impl::getter_none_t(); } | |||
| template<typename T_dataset, typename T_value> | |||
| constexpr decltype(auto) make_getter_member_var(T_value T_dataset::* member) | |||
| { return __impl::getter_member_var_t<T_dataset, T_value, T_value T_dataset::*>(member); } | |||
| @@ -152,55 +136,59 @@ beg_namespace_cpphibernate_schema | |||
| constexpr decltype(auto) make_getter_lambda(T_lambda&& lambda, boost::hana::basic_type<T_dataset>) | |||
| { return __impl::getter_lambda_t<T_dataset, T_lambda>(std::forward<T_lambda>(lambda)); } | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* getter_buildser */ | |||
| /* getter_make_impl */ | |||
| template<typename X, typename = void> | |||
| struct getter_builder | |||
| struct getter_make_impl | |||
| { | |||
| template<typename... Args> | |||
| static constexpr decltype(auto) apply(Args&&...) | |||
| { return make_getter_none(); } | |||
| static constexpr decltype(auto) apply(Args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid arguments to schema::getter::make(...)!"); } | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct getter_builder<mp::list<T_value T_dataset::*>, void> | |||
| struct getter_make_impl<mp::list<T_value T_dataset::*>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value T_dataset::*member) | |||
| { return make_getter_member_var(member); } | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct getter_builder<mp::list<T_value (T_dataset::*)(void)>, void> | |||
| struct getter_make_impl<mp::list<T_value (T_dataset::*)(void)>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) | |||
| { return make_getter_member_func(member); } | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct getter_builder<mp::list<T_value (T_dataset::*)(void) const>, void> | |||
| struct getter_make_impl<mp::list<T_value (T_dataset::*)(void) const>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) | |||
| { return make_getter_member_func(member); } | |||
| }; | |||
| template<typename T_func, typename T_dataset_type, typename T_value_type> | |||
| struct getter_builder<mp::list<T_func, T_dataset_type, T_value_type>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, mp::decay_t<T_dataset_type>> | |||
| template<typename T_func, typename T_wrapped_dataset, typename T_value_type> | |||
| struct getter_make_impl<mp::list<T_func, T_wrapped_dataset, T_value_type>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, mp::decay_t<T_wrapped_dataset>> | |||
| && hana::is_a<hana::type_tag, mp::decay_t<T_value_type>>>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) | |||
| { return make_getter_lambda(std::forward<T_func>(func), std::forward<T_dataset_type>(dataset_type), std::forward<T_value_type>(value_type)); } | |||
| static constexpr decltype(auto) apply(T_func&& func, T_wrapped_dataset&& wrapped_dataset, T_value_type&& value_type) | |||
| { return make_getter_lambda(std::forward<T_func>(func), std::forward<T_wrapped_dataset>(wrapped_dataset), std::forward<T_value_type>(value_type)); } | |||
| }; | |||
| } | |||
| /* make */ | |||
| namespace getter | |||
| { | |||
| constexpr decltype(auto) make_getter = misc::make_generic_predicate<__impl::getter_builder> { }; | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::getter_make_impl> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -6,38 +6,38 @@ | |||
| #define cpphibernate_make_string(str) \ | |||
| #str | |||
| #define cpphibernate_make_schema(name, ...) \ | |||
| cpphibernate::schema::make_schema( \ | |||
| cpphibernate_make_string(name), \ | |||
| cpphibernate::schema::make_tables(__VA_ARGS__)) | |||
| #define cpphibernate_make_table_name(name, type, id, ...) \ | |||
| cpphibernate::schema::make_table( \ | |||
| cpphibernate_make_string(name), \ | |||
| boost::hana::type_c<type>, \ | |||
| boost::hana::size_c<id>, \ | |||
| cpphibernate::schema::make_fields(__VA_ARGS__)) | |||
| #define cpphibernate_make_table(name, id, ...) \ | |||
| cpphibernate_make_table_name(name, name, id, __VA_ARGS__) | |||
| #define cpphibernate_make_field_custom(name, getter, setter, ...) \ | |||
| cpphibernate::schema::make_field( \ | |||
| cpphibernate_make_string(name), \ | |||
| cpphibernate::schema::make_getter(getter), \ | |||
| cpphibernate::schema::make_setter(setter), \ | |||
| cpphibernate::schema::make_attributes(__VA_ARGS__)) | |||
| #define cpphibernate_make_field_name(name, member_ptr, ...) \ | |||
| #define cpphibernate_make_schema(p_name, ...) \ | |||
| cpphibernate::schema::make( \ | |||
| cpphibernate_make_string(p_name), \ | |||
| cpphibernate::schema::tables::make(__VA_ARGS__)) | |||
| #define cpphibernate_make_table_name(p_name, p_type, p_id, ...) \ | |||
| cpphibernate::schema::table::make( \ | |||
| cpphibernate_make_string(p_name), \ | |||
| boost::hana::type_c<p_type>, \ | |||
| boost::hana::size_c<p_id>, \ | |||
| cpphibernate::schema::fields::make(__VA_ARGS__)) | |||
| #define cpphibernate_make_table(p_name, p_id, ...) \ | |||
| cpphibernate_make_table_name(p_name, p_name, p_id, __VA_ARGS__) | |||
| #define cpphibernate_make_field_custom(p_name, p_getter, p_setter, ...) \ | |||
| cpphibernate::schema::field::make( \ | |||
| cpphibernate_make_string(p_name), \ | |||
| cpphibernate::schema::getter::make(p_getter), \ | |||
| cpphibernate::schema::setter::make(p_setter), \ | |||
| cpphibernate::schema::attributes::make(__VA_ARGS__)) | |||
| #define cpphibernate_make_field_name(p_name, p_member_ptr, ...) \ | |||
| cpphibernate_make_field_custom( \ | |||
| name, member_ptr, member_ptr, __VA_ARGS__) | |||
| p_name, p_member_ptr, p_member_ptr, __VA_ARGS__) | |||
| #define cpphibernate_make_field(type, member, ...) \ | |||
| #define cpphibernate_make_field(p_type, p_member, ...) \ | |||
| cpphibernate_make_field_name( \ | |||
| member, &type::member, __VA_ARGS__) | |||
| p_member, &p_type::p_member, __VA_ARGS__) | |||
| #define cpphibernate_make_id(member_ptr) \ | |||
| #define cpphibernate_make_id(p_member_ptr) \ | |||
| cpphibernate_make_field_name( \ | |||
| null, \ | |||
| member_ptr, \ | |||
| "p_id", \ | |||
| p_member_ptr, \ | |||
| cpphibernate::schema::attribute::primary_key) | |||
| @@ -52,34 +52,201 @@ beg_namespace_cpphibernate_schema | |||
| } | |||
| }; | |||
| /* schema_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_schema : mp::is_specialization_of<T, __impl::schema_t> { }; | |||
| /* schema::make */ | |||
| namespace __impl | |||
| { | |||
| template <typename X, typename = void> | |||
| struct schema_builder | |||
| struct schema_make_impl | |||
| { | |||
| template <typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_schema(...)!"); } | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make(...)!"); } | |||
| }; | |||
| template<typename T_name, typename T_tables> | |||
| struct schema_builder<mp::list<T_name, T_tables>, mp::enable_if_c< | |||
| is_tables<mp::clean_type<T_tables>>::value>> | |||
| struct schema_make_impl<mp::list<T_name, T_tables>, mp::enable_if_c< | |||
| is_tables<mp::decay_t<T_tables>>::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_name&& name, T_tables&& tables) | |||
| { return schema_t<T_name, T_tables>(std::forward<T_name>(name), std::forward<T_tables>(tables)); } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::schema_make_impl> { }; | |||
| /* schema::get_base_type */ | |||
| namespace __impl | |||
| { | |||
| struct schema_get_base_type_impl | |||
| { | |||
| static constexpr decltype(auto) is_base_of_pred = hana::integral(hana::metafunction<mp::is_base_of>); | |||
| 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_pred(type_1, type_2), is_base_of_pred(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_pred(type_1, type_2), type_2, type_1); | |||
| } | |||
| }; | |||
| static constexpr decltype(auto) do_fold = do_fold_impl { }; | |||
| template<typename T_wrapped_datasets, typename T_wrapped_dataset> | |||
| static constexpr decltype(auto) get_base_types(T_wrapped_datasets&& wrapped_datasets, T_wrapped_dataset&& wrapped_dataset) | |||
| { | |||
| return hana::filter( | |||
| std::forward<T_wrapped_datasets>(wrapped_datasets), | |||
| [&](auto type){ | |||
| return hana::and_( | |||
| is_base_of_pred(type, wrapped_dataset), | |||
| hana::not_equal(type, wrapped_dataset)); | |||
| }); | |||
| } | |||
| template<typename T_schema, typename T_wrapped_dataset> | |||
| constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const | |||
| { | |||
| using wrapped_datasets_type = mp::decay_t<decltype( | |||
| hana::transform( | |||
| std::declval<T_schema>().tables, | |||
| schema::table::get_wrapped_dataset))>; | |||
| auto base_types = get_base_types(wrapped_datasets_type { }, std::forward<T_wrapped_dataset>(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); }); | |||
| } | |||
| }; | |||
| } | |||
| /* meta */ | |||
| constexpr decltype(auto) get_base_type = __impl::schema_get_base_type_impl { }; | |||
| template<typename T> | |||
| struct is_schema : mp::is_specialization_of<T, __impl::schema_t> { }; | |||
| /* schema::get_root_base_type */ | |||
| namespace __impl | |||
| { | |||
| struct schema_get_root_base_type_impl | |||
| { | |||
| template<typename T_wrapped_dataset> | |||
| struct is_base_pred | |||
| { | |||
| using dataset_type = misc::decay_unwrap_t<T_wrapped_dataset>; | |||
| template<typename T_type> | |||
| constexpr decltype(auto) operator()(T_type&&) const | |||
| { | |||
| using type = misc::unwrap_t<T_type>; | |||
| return hana::bool_c< | |||
| std::is_base_of<type, dataset_type>::value | |||
| && !std::is_same <type, dataset_type>::value>; | |||
| } | |||
| }; | |||
| template<typename T_schema, typename T_wrapped_dataset> | |||
| constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const | |||
| { | |||
| auto all_types = hana::transform( | |||
| schema.tables, | |||
| table::get_wrapped_dataset); | |||
| auto base_type = hana::find_if( | |||
| all_types, | |||
| is_base_pred<T_wrapped_dataset> { }); | |||
| return hana::eval_if( | |||
| base_type != hana::nothing, | |||
| [&](auto _){ | |||
| return schema_get_root_base_type_impl { }(schema, _(base_type).value()); | |||
| }, | |||
| [&]{ | |||
| return wrapped_dataset; | |||
| }); | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) get_root_base_type = __impl::schema_get_root_base_type_impl { }; | |||
| /* schema::get_all_derived_types */ | |||
| namespace __impl | |||
| { | |||
| struct schema_get_all_derived_types_impl | |||
| { | |||
| template<typename T_wrapped_dataset> | |||
| struct is_derived_pred | |||
| { | |||
| using dataset_type = misc::decay_unwrap_t<T_wrapped_dataset>; | |||
| template<typename T_type> | |||
| constexpr decltype(auto) operator()(T_type&&) const | |||
| { | |||
| return hana::bool_c< | |||
| std::is_base_of<dataset_type, misc::unwrap_t<T_type>>::value>; | |||
| } | |||
| }; | |||
| template<typename T_schema, typename T_wrapped_dataset> | |||
| constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&&) const | |||
| { | |||
| auto all_types = hana::transform( | |||
| schema.tables, | |||
| table::get_wrapped_dataset); | |||
| auto derived_types = hana::filter( | |||
| all_types, | |||
| is_derived_pred<T_wrapped_dataset> { }); | |||
| return derived_types; | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) get_all_derived_types = __impl::schema_get_all_derived_types_impl { }; | |||
| /* schema::get_derived_types */ | |||
| namespace __impl | |||
| { | |||
| struct schema_get_derived_types_impl | |||
| { | |||
| struct has_base_impl | |||
| { | |||
| template<typename T_schema, typename T_base_type, typename T_type> | |||
| constexpr decltype(auto) operator()(T_schema&& schema, T_base_type& base_type, T_type&& type) const | |||
| { return get_base_type(schema, type) == base_type; } | |||
| }; | |||
| /* make */ | |||
| static constexpr decltype(auto) has_base = has_base_impl { }; | |||
| constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::schema_builder> { }; | |||
| template<typename T_schema, typename T_wrapped_dataset> | |||
| constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const | |||
| { | |||
| using wrapped_datasets_type = mp::decay_t<decltype( | |||
| hana::transform( | |||
| std::declval<T_schema>().tables, | |||
| schema::table::get_wrapped_dataset))>; | |||
| using derived_wrapped_datasets_type = mp::decay_t<decltype( | |||
| hana::filter( | |||
| std::declval<wrapped_datasets_type>(), | |||
| hana::partial( | |||
| has_base, | |||
| std::declval<T_schema>(), | |||
| wrapped_dataset)))>; | |||
| return derived_wrapped_datasets_type { }; | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) get_derived_types = __impl::schema_get_derived_types_impl { }; | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -152,14 +152,15 @@ beg_namespace_cpphibernate_schema | |||
| constexpr decltype(auto) make_setter_lambda(T_lambda&& lambda, boost::hana::basic_type<T_dataset>, boost::hana::basic_type<T_value>) | |||
| { return __impl::setter_lambda_t<T_dataset, T_value, T_lambda>(std::forward<T_lambda>(lambda)); } | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* setter_buildser */ | |||
| /* setter_make_impl */ | |||
| template<typename X, typename = void> | |||
| struct setter_builder | |||
| struct setter_make_impl | |||
| { | |||
| template<typename... Args> | |||
| static constexpr decltype(auto) apply(Args&&...) | |||
| @@ -167,40 +168,43 @@ beg_namespace_cpphibernate_schema | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct setter_builder<mp::list<T_value T_dataset::*>, void> | |||
| struct setter_make_impl<mp::list<T_value T_dataset::*>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value T_dataset::*member) | |||
| { return make_setter_member_var(member); } | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct setter_builder<mp::list<T_value (T_dataset::*)(void)>, void> | |||
| struct setter_make_impl<mp::list<T_value (T_dataset::*)(void)>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) | |||
| { return make_setter_member_func(member); } | |||
| }; | |||
| template<typename T_dataset, typename T_value> | |||
| struct setter_builder<mp::list<T_value (T_dataset::*)(void) const>, void> | |||
| struct setter_make_impl<mp::list<T_value (T_dataset::*)(void) const>, void> | |||
| { | |||
| static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) | |||
| { return make_setter_member_func(member); } | |||
| }; | |||
| template<typename T_func, typename T_dataset_type, typename T_value_type> | |||
| struct setter_builder<mp::list<T_func, T_dataset_type, T_value_type>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, mp::clean_type<T_dataset_type>> | |||
| && hana::is_a<hana::type_tag, mp::clean_type<T_value_type>>>> | |||
| template<typename T_func, typename T_wrapped_dataset, typename T_value_type> | |||
| struct setter_make_impl<mp::list<T_func, T_wrapped_dataset, T_value_type>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, mp::decay_t<T_wrapped_dataset>> | |||
| && hana::is_a<hana::type_tag, mp::decay_t<T_value_type>>>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) | |||
| { return make_setter_lambda(std::forward<T_func>(func), std::forward<T_dataset_type>(dataset_type), std::forward<T_value_type>(value_type)); } | |||
| static constexpr decltype(auto) apply(T_func&& func, T_wrapped_dataset&& wrapped_dataset, T_value_type&& value_type) | |||
| { return make_setter_lambda(std::forward<T_func>(func), std::forward<T_wrapped_dataset>(wrapped_dataset), std::forward<T_value_type>(value_type)); } | |||
| }; | |||
| } | |||
| /* make */ | |||
| namespace setter | |||
| { | |||
| constexpr decltype(auto) make_setter = misc::make_generic_predicate<__impl::setter_builder> { }; | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::setter_make_impl> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -4,6 +4,7 @@ | |||
| #include <cpphibernate/misc/wrap.h> | |||
| #include <cpphibernate/misc/general.h> | |||
| #include <cpphibernate/schema/fields.h> | |||
| #include <cpphibernate/schema/attribute.h> | |||
| beg_namespace_cpphibernate_schema | |||
| { | |||
| @@ -13,27 +14,27 @@ beg_namespace_cpphibernate_schema | |||
| /* table_t */ | |||
| template<typename T_name, typename T_dataset_wrapped, typename T_table_id, typename T_fields> | |||
| template<typename T_name, typename T_wrapped_dataset, typename T_table_id, typename T_fields> | |||
| struct table_t | |||
| { | |||
| using name_type = T_name; | |||
| using dataset_wrapped_type = mp::decay_t<T_dataset_wrapped>; | |||
| using wrapped_dataset_type = mp::decay_t<T_wrapped_dataset>; | |||
| using table_id_type = T_table_id; | |||
| using fields_type = T_fields; | |||
| using this_type = table_t<name_type, dataset_wrapped_type, table_id_type, fields_type>; | |||
| using this_type = table_t<name_type, wrapped_dataset_type, table_id_type, fields_type>; | |||
| name_type name; | |||
| dataset_wrapped_type dataset_wrapped; | |||
| wrapped_dataset_type wrapped_dataset; | |||
| table_id_type table_id; | |||
| fields_type fields; | |||
| constexpr table_t( | |||
| T_name p_name, | |||
| T_dataset_wrapped p_dataset_wrapped, | |||
| T_wrapped_dataset p_wrapped_dataset, | |||
| T_table_id p_table_id, | |||
| T_fields p_fields) | |||
| : name (std::forward<T_name> (p_name)) | |||
| , dataset_wrapped (std::forward<T_dataset_wrapped>(p_dataset_wrapped)) | |||
| , wrapped_dataset (std::forward<T_wrapped_dataset>(p_wrapped_dataset)) | |||
| , table_id (std::forward<T_table_id> (p_table_id)) | |||
| , fields (std::forward<T_fields> (p_fields)) | |||
| { } | |||
| @@ -50,7 +51,7 @@ beg_namespace_cpphibernate_schema | |||
| os << indent << '{' | |||
| << incindent | |||
| << indent << "\"name\": \"" << name << "\"," | |||
| << indent << "\"dataset_wrapped\": \"" << utl::type_helper<misc::decay_unwrap_t<dataset_wrapped_type>>::name() << "\"" | |||
| << indent << "\"wrapped_dataset\": \"" << utl::type_helper<misc::decay_unwrap_t<wrapped_dataset_type>>::name() << "\"" | |||
| << indent << "\"table_id\": \"" << hana::value(table_id) << "\"" | |||
| << indent << "\"fields\": " | |||
| << indent << '[' | |||
| @@ -66,44 +67,123 @@ beg_namespace_cpphibernate_schema | |||
| } | |||
| }; | |||
| /* table_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_table | |||
| : public mp::is_specialization_of<T, __impl::table_t> | |||
| { }; | |||
| template<typename... T> | |||
| struct all_are_tables | |||
| : mp::all_true<is_table<T>::value...> | |||
| { }; | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* table_make_impl */ | |||
| template <typename X, typename = void> | |||
| struct table_builder | |||
| struct table_make_impl | |||
| { | |||
| template <typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_table(...)!"); } | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::table::make(...)!"); } | |||
| }; | |||
| template<typename T_name, typename T_dataset_wrapped, typename T_id, typename T_fields> | |||
| struct table_builder<mp::list<T_name, T_dataset_wrapped, T_id, T_fields>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, T_dataset_wrapped> | |||
| template<typename T_name, typename T_wrapped_dataset, typename T_id, typename T_fields> | |||
| struct table_make_impl<mp::list<T_name, T_wrapped_dataset, T_id, T_fields>, mp::enable_if_c< | |||
| hana::is_a<hana::type_tag, T_wrapped_dataset> | |||
| && is_fields<mp::decay_t<T_fields>>::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_name&& name, T_dataset_wrapped&& dataset_wrapped, T_id&& id, T_fields&& fields) | |||
| static constexpr decltype(auto) apply(T_name&& name, T_wrapped_dataset&& wrapped_dataset, T_id&& id, T_fields&& fields) | |||
| { | |||
| return table_t<T_name, T_dataset_wrapped, T_id, T_fields>( | |||
| return table_t<T_name, T_wrapped_dataset, T_id, T_fields>( | |||
| std::forward<T_name> (name), | |||
| std::forward<T_dataset_wrapped> (dataset_wrapped), | |||
| std::forward<T_wrapped_dataset> (wrapped_dataset), | |||
| std::forward<T_id> (id), | |||
| std::forward<T_fields> (fields)); | |||
| } | |||
| }; | |||
| /* table_get_wrapped_dataset_impl */ | |||
| struct table_get_wrapped_dataset_impl | |||
| { | |||
| template<typename T_table> | |||
| constexpr decltype(auto) operator()(T_table&& table) const | |||
| { return table.wrapped_dataset; } | |||
| }; | |||
| /* table_get_primary_key_field_impl */ | |||
| template<typename X, typename = void> | |||
| struct table_get_primary_key_field_impl | |||
| { | |||
| template <typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::table::get_primary_key_field(...)!"); } | |||
| }; | |||
| template<typename T_table> | |||
| struct table_get_primary_key_field_impl< | |||
| mp::list<T_table>, | |||
| mp::enable_if_c< | |||
| is_table<mp::decay_t<T_table>>::value>> | |||
| { | |||
| template<size_t I> | |||
| using is_primary_key_field = decltype(hana::contains( | |||
| std::declval<T_table>().fields[hana::size_c<I>].attributes, | |||
| attribute::primary_key)); | |||
| template<size_t I, size_t N, typename = void> | |||
| struct helper; | |||
| template<size_t N> | |||
| struct helper<N, N, void> | |||
| { static_assert(N != N, "Unable to find primary key field for table!"); }; | |||
| template<size_t I, size_t N> | |||
| struct helper<I, N, mp::enable_if_c< | |||
| !is_primary_key_field<I>::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_table&& table) | |||
| { return helper<I+1, N>::apply(std::forward<T_table>(table)); } | |||
| }; | |||
| template<size_t I, size_t N> | |||
| struct helper<I, N, mp::enable_if_c< | |||
| is_primary_key_field<I>::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_table&& table) | |||
| { return std::forward<T_table>(table).fields[hana::size_c<I>]; } | |||
| }; | |||
| static constexpr decltype(auto) apply(T_table&& table) | |||
| { | |||
| using count = mp::decay_t<decltype(hana::size(std::declval<T_table>().fields))>; | |||
| return helper<0, count::value>::apply( | |||
| std::forward<T_table>(table)); | |||
| } | |||
| }; | |||
| } | |||
| /* meta */ | |||
| namespace table | |||
| { | |||
| template<typename T> | |||
| struct is_table : mp::is_specialization_of<T, __impl::table_t> { }; | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::table_make_impl> { }; | |||
| template<typename... T> | |||
| struct all_are_tables : mp::all_true<is_table<T>::value...> { }; | |||
| constexpr decltype(auto) get_wrapped_dataset = __impl::table_get_wrapped_dataset_impl { }; | |||
| /* make */ | |||
| constexpr decltype(auto) get_primary_key_field = misc::make_generic_predicate<__impl::table_get_primary_key_field_impl> { }; | |||
| constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::table_builder> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -27,36 +27,94 @@ beg_namespace_cpphibernate_schema | |||
| : mp::c_true_t | |||
| { }; | |||
| /* tables_builder */ | |||
| } | |||
| /* meta */ | |||
| template<typename T> | |||
| struct is_tables | |||
| : public __impl::is_tables_impl<T> | |||
| { }; | |||
| /* operations */ | |||
| namespace __impl | |||
| { | |||
| /* tables_make_impl */ | |||
| template <typename X, typename = void> | |||
| struct tables_builder | |||
| struct tables_make_impl | |||
| { | |||
| template <typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_tables(...)!"); } | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::tables::make(...)!"); } | |||
| }; | |||
| template<typename... T> | |||
| struct tables_builder<mp::list<T...>, mp::enable_if<all_are_tables<T...>>> | |||
| struct tables_make_impl<mp::list<T...>, mp::enable_if<all_are_tables<T...>>> | |||
| { | |||
| template <typename ...T_tables> | |||
| static constexpr decltype(auto) apply(T_tables&&... tables) | |||
| { return tables_t<T_tables...>(std::forward<T_tables>(tables)...); } | |||
| }; | |||
| /* tables_find_impl */ | |||
| template<typename X, typename = void> | |||
| struct tables_find_impl | |||
| { | |||
| template<typename... T_args> | |||
| static constexpr decltype(auto) apply(T_args&&... args) | |||
| { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::tables::find(...)!"); } | |||
| }; | |||
| template<typename T_tables, typename T_wrapped_dataset> | |||
| struct tables_find_impl< | |||
| mp::list<T_tables, T_wrapped_dataset>, | |||
| mp::enable_if_c< | |||
| is_tables<mp::decay_t<T_tables>>::value>> | |||
| { | |||
| template<size_t I, size_t N, typename = void> | |||
| struct helper; | |||
| template<size_t N> | |||
| struct helper<N, N, void> | |||
| { static_assert(N != N, "Table for given datatype does not exist!"); }; | |||
| template<size_t I, size_t N> | |||
| struct helper<I, N, mp::enable_if_c< | |||
| decltype(hana::not_equal(std::declval<T_tables>()[hana::size_c<I>].wrapped_dataset, T_wrapped_dataset { }))::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_tables&& tables) | |||
| { return helper<I+1, N>::apply(std::forward<T_tables>(tables)); } | |||
| }; | |||
| template<size_t I, size_t N> | |||
| struct helper<I, N, mp::enable_if_c< | |||
| decltype(hana::equal(std::declval<T_tables>()[hana::size_c<I>].wrapped_dataset, T_wrapped_dataset { }))::value>> | |||
| { | |||
| static constexpr decltype(auto) apply(T_tables&& tables) | |||
| { return std::forward<T_tables>(tables)[hana::size_c<I>]; } | |||
| }; | |||
| static constexpr decltype(auto) apply(T_tables&& tables, T_wrapped_dataset&&) | |||
| { | |||
| using count_type = mp::decay_t<decltype(hana::size(std::declval<T_tables>()))>; | |||
| return helper<0, count_type::value>::apply(std::forward<T_tables>(tables)); | |||
| } | |||
| }; | |||
| } | |||
| /* meta */ | |||
| namespace tables | |||
| { | |||
| template<typename T> | |||
| struct is_tables | |||
| : public __impl::is_tables_impl<T> | |||
| { }; | |||
| constexpr decltype(auto) make = misc::make_generic_predicate<__impl::tables_make_impl> { }; | |||
| /* make */ | |||
| constexpr decltype(auto) find = misc::make_generic_predicate<__impl::tables_find_impl> { }; | |||
| constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::tables_builder> { }; | |||
| } | |||
| } | |||
| end_namespace_cpphibernate_schema | |||
| @@ -14,6 +14,7 @@ Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX | |||
| # Dependencies #################################################################################### | |||
| Find_Package ( cpputils REQUIRED ) | |||
| Find_Package ( cppmariadb REQUIRED ) | |||
| # Project: cpphibernate ############################################################################### | |||
| @@ -27,6 +28,7 @@ Target_Include_Directories ( | |||
| Target_Link_Libraries ( | |||
| cpphibernate | |||
| cpputils | |||
| cppmariadb | |||
| ) | |||
| If ( __COTIRE_INCLUDED ) | |||
| Cotire ( cpphibernate ) | |||
| @@ -0,0 +1,15 @@ | |||
| #include <string> | |||
| #include <iostream> | |||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||
| using namespace ::cpphibernate::driver::mariadb_impl; | |||
| void schema_t::update() | |||
| { | |||
| } | |||
| void schema_t::print(std::ostream& os) const | |||
| { | |||
| os << "fuu" << std::endl; | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <cpphibernate.h> | |||
| #include <cpphibernate/driver/mariadb.h> | |||
| using namespace ::cpphibernate; | |||
| @@ -124,5 +125,7 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema( | |||
| TEST(CppHibernateTests, fuuu) | |||
| { | |||
| std::cout << test_schema << std::endl; | |||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1234)); | |||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||
| std::cout << context.schema() << std::endl; | |||
| } | |||
| @@ -0,0 +1,77 @@ | |||
| #include "mariadb_mock.h" | |||
| MariaDbMock* mariadb_mock_instance; | |||
| void MariaDbMock::setInstance(MariaDbMock* value) | |||
| { | |||
| mariadb_mock_instance = value; | |||
| } | |||
| void MariaDbMock::clearInstance(MariaDbMock* value) | |||
| { | |||
| if (mariadb_mock_instance == value) | |||
| mariadb_mock_instance = nullptr; | |||
| } | |||
| my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_rows(res) : 0); } | |||
| unsigned int STDCALL mysql_num_fields (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_fields(res) : 0); } | |||
| MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_tell(res) : nullptr); } | |||
| void STDCALL mysql_free_result (MYSQL_RES *res) | |||
| { if (mariadb_mock_instance) mariadb_mock_instance->mysql_free_result(res); } | |||
| MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET offset) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_seek(res, offset) : nullptr); } | |||
| void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset) | |||
| { if (mariadb_mock_instance) mariadb_mock_instance->mysql_data_seek(res, offset); } | |||
| unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_lengths(res) : nullptr); } | |||
| MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_row(res) : nullptr); } | |||
| MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_fields(res) : nullptr); } | |||
| int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); } | |||
| unsigned int STDCALL mysql_errno (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); } | |||
| const char* STDCALL mysql_error (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_error(mysql) : nullptr); } | |||
| MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_store_result(mysql) : nullptr); } | |||
| MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_use_result(mysql) : nullptr); } | |||
| unsigned int STDCALL mysql_field_count (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_field_count(mysql) : 0); } | |||
| my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_affected_rows(mysql) : 0); } | |||
| my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_insert_id(mysql) : 0); } | |||
| unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_escape_string(mysql, to, from, length) : 0); } | |||
| void STDCALL mysql_close (MYSQL *mysql) | |||
| { if (mariadb_mock_instance) mariadb_mock_instance->mysql_close(mysql); } | |||
| MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag) : nullptr); } | |||
| MYSQL* STDCALL mysql_init (MYSQL *mysql) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_init(mysql) : nullptr); } | |||
| @@ -0,0 +1,121 @@ | |||
| #pragma once | |||
| #include <gmock/gmock.h> | |||
| #include <mariadb/errmsg.h> | |||
| #include <mariadb/mysqld_error.h> | |||
| #include <mariadb/mysql.h> | |||
| #define MARIADB_MOCK | |||
| #if !defined(_WIN32) | |||
| #define STDCALL | |||
| #else | |||
| #define STDCALL __stdcall | |||
| #endif | |||
| #define NOT_NULL_FLAG 1 /* field can't be NULL */ | |||
| #define PRI_KEY_FLAG 2 /* field is part of a primary key */ | |||
| #define UNIQUE_KEY_FLAG 4 /* field is part of a unique key */ | |||
| #define MULTIPLE_KEY_FLAG 8 /* field is part of a key */ | |||
| #define BLOB_FLAG 16 /* field is a blob */ | |||
| #define UNSIGNED_FLAG 32 /* field is unsigned */ | |||
| #define ZEROFILL_FLAG 64 /* field is zerofill */ | |||
| #define BINARY_FLAG 128 | |||
| #define ENUM_FLAG 256 /* field is an enum */ | |||
| #define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ | |||
| #define TIMESTAMP_FLAG 1024 /* field is a timestamp */ | |||
| #define SET_FLAG 2048 /* field is a set */ | |||
| #define NO_DEFAULT_VALUE_FLAG 4096 /* field doesn't have default value */ | |||
| #define ON_UPDATE_NOW_FLAG 8192 /* field is set to NOW on UPDATE */ | |||
| #define NUM_FLAG 32768 /* field is num (for clients) */ | |||
| #define PART_KEY_FLAG 16384 /* Intern; Part of some key */ | |||
| #define GROUP_FLAG 32768 /* Intern: Group field */ | |||
| #define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ | |||
| #define CLIENT_MYSQL 1 | |||
| #define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ | |||
| #define CLIENT_LONG_FLAG 4 /* Get all column flags */ | |||
| #define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ | |||
| #define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ | |||
| #define CLIENT_COMPRESS 32 /* Can use compression protocol */ | |||
| #define CLIENT_ODBC 64 /* Odbc client */ | |||
| #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ | |||
| #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ | |||
| #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ | |||
| #define CLIENT_SSL 2048 /* Switch to SSL after handshake */ | |||
| #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ | |||
| #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ | |||
| #define CLIENT_PROTOCOL_41 512 | |||
| #define CLIENT_RESERVED 16384 | |||
| #define CLIENT_SECURE_CONNECTION 32768 | |||
| #define CLIENT_MULTI_STATEMENTS (1UL << 16) | |||
| #define CLIENT_MULTI_RESULTS (1UL << 17) | |||
| #define CLIENT_PS_MULTI_RESULTS (1UL << 18) | |||
| #define CLIENT_PLUGIN_AUTH (1UL << 19) | |||
| #define CLIENT_CONNECT_ATTRS (1UL << 20) | |||
| #define CLIENT_SESSION_TRACKING (1UL << 23) | |||
| #define CLIENT_PROGRESS (1UL << 29) | |||
| #define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS | |||
| #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) | |||
| #define CLIENT_REMEMBER_OPTIONS (1UL << 31) | |||
| struct MariaDbMock | |||
| { | |||
| private: | |||
| static void setInstance(MariaDbMock* value); | |||
| static void clearInstance(MariaDbMock* value); | |||
| public: | |||
| MOCK_METHOD1(mysql_num_rows, my_ulonglong (MYSQL_RES *res)); | |||
| MOCK_METHOD1(mysql_num_fields, unsigned int (MYSQL_RES *res)); | |||
| MOCK_METHOD1(mysql_row_tell, MYSQL_ROWS* (MYSQL_RES *res)); | |||
| MOCK_METHOD1(mysql_free_result, void (MYSQL_RES *res)); | |||
| MOCK_METHOD2(mysql_row_seek, MYSQL_ROW_OFFSET(MYSQL_RES *res, MYSQL_ROW_OFFSET)); | |||
| MOCK_METHOD2(mysql_data_seek, void (MYSQL_RES *res, unsigned long long offset)); | |||
| MOCK_METHOD1(mysql_fetch_lengths, unsigned long* (MYSQL_RES *res)); | |||
| MOCK_METHOD1(mysql_fetch_row, MYSQL_ROW (MYSQL_RES *res)); | |||
| MOCK_METHOD1(mysql_fetch_fields, MYSQL_FIELD* (MYSQL_RES *res)); | |||
| MOCK_METHOD3(mysql_real_query, int (MYSQL *mysql, const char *q, unsigned long length)); | |||
| MOCK_METHOD1(mysql_errno, unsigned int (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_error, const char* (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_store_result, MYSQL_RES* (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_use_result, MYSQL_RES* (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_field_count, unsigned int (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_affected_rows, my_ulonglong (MYSQL *mysql)); | |||
| MOCK_METHOD1(mysql_insert_id, my_ulonglong (MYSQL *mysql)); | |||
| MOCK_METHOD4(mysql_real_escape_string, unsigned long (MYSQL *mysql, char *to, const char *from, unsigned long length)); | |||
| MOCK_METHOD1(mysql_close, void (MYSQL *mysql)); | |||
| MOCK_METHOD8(mysql_real_connect, MYSQL* (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag)); | |||
| MOCK_METHOD1(mysql_init, MYSQL* (MYSQL *mysql)); | |||
| MariaDbMock() | |||
| { setInstance(this); } | |||
| ~MariaDbMock() | |||
| { clearInstance(this); } | |||
| }; | |||
| my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res); | |||
| unsigned int STDCALL mysql_num_fields (MYSQL_RES *res); | |||
| MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res); | |||
| void STDCALL mysql_free_result (MYSQL_RES *res); | |||
| MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET); | |||
| void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset); | |||
| unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res); | |||
| MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res); | |||
| MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res); | |||
| int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length); | |||
| unsigned int STDCALL mysql_errno (MYSQL *mysql); | |||
| const char* STDCALL mysql_error (MYSQL *mysql); | |||
| MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql); | |||
| MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql); | |||
| unsigned int STDCALL mysql_field_count (MYSQL *mysql); | |||
| my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql); | |||
| my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql); | |||
| unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); | |||
| void STDCALL mysql_close (MYSQL *mysql); | |||
| MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); | |||
| MYSQL* STDCALL mysql_init (MYSQL *mysql); | |||