| @@ -2,6 +2,5 @@ | |||||
| #include <cpphibernate/driver/mariadb/helper/context.h> | #include <cpphibernate/driver/mariadb/helper/context.h> | ||||
| #include <cpphibernate/driver/mariadb/helper/key_properties.h> | #include <cpphibernate/driver/mariadb/helper/key_properties.h> | ||||
| #include <cpphibernate/driver/mariadb/helper/reference_stack.h> | |||||
| #include <cpphibernate/driver/mariadb/helper/transaction_lock.h> | #include <cpphibernate/driver/mariadb/helper/transaction_lock.h> | ||||
| #include <cpphibernate/driver/mariadb/helper/type_properties.h> | #include <cpphibernate/driver/mariadb/helper/type_properties.h> | ||||
| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cppmariadb.h> | #include <cppmariadb.h> | ||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | ||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | ||||
| @@ -10,25 +11,132 @@ | |||||
| beg_namespace_cpphibernate_driver_mariadb | beg_namespace_cpphibernate_driver_mariadb | ||||
| { | { | ||||
| /* init_context */ | |||||
| /* base_context */ | |||||
| struct init_context | |||||
| struct base_context | |||||
| { | { | ||||
| const schema_t& schema; | const schema_t& schema; | ||||
| ::cppmariadb::connection& connection; | ::cppmariadb::connection& connection; | ||||
| bool recreate; | |||||
| inline base_context( | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection) | |||||
| : schema (p_schema) | |||||
| , connection(p_connection) | |||||
| { } | |||||
| }; | |||||
| /* init_context */ | |||||
| struct init_context | |||||
| : public base_context | |||||
| { | |||||
| bool recreate; | |||||
| inline init_context( | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection, | |||||
| bool p_recreate) | |||||
| : base_context (p_schema, p_connection) | |||||
| , recreate (p_recreate) | |||||
| { } | |||||
| }; | |||||
| namespace __impl | |||||
| { | |||||
| struct change_context_impl | |||||
| { | |||||
| template<typename T_context, typename T_data> | |||||
| constexpr decltype(auto) operator()(const T_context& context, T_data& data) const | |||||
| { | |||||
| auto new_context = context; | |||||
| new_context.data_id = misc::get_type_id(hana::type_c<mp::decay_t<T_data>>); | |||||
| new_context.data = &data; | |||||
| return new_context; | |||||
| } | |||||
| }; | |||||
| } | |||||
| constexpr decltype(auto) change_context = __impl::change_context_impl { }; | |||||
| /* data_context */ | |||||
| struct data_context | |||||
| : public base_context | |||||
| { | |||||
| private: | |||||
| friend __impl::change_context_impl; | |||||
| size_t data_id; | |||||
| void* data; | |||||
| public: | |||||
| template<typename T> | |||||
| inline decltype(auto) get() const | |||||
| { | |||||
| if (!data) | |||||
| throw misc::hibernate_exception("no data assigned!"); | |||||
| auto type_id = misc::get_type_id(hana::type_c<mp::decay_t<T>>); | |||||
| if (type_id != data_id) | |||||
| { | |||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||||
| << "invalid type! expected " << data_id << ", got " << type_id).str()); | |||||
| } | |||||
| return *static_cast<T*>(data); | |||||
| } | |||||
| template<typename T_data> | |||||
| inline data_context( | |||||
| T_data& p_data, | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection) | |||||
| : base_context (p_schema, p_connection) | |||||
| , data_id (misc::get_type_id(hana::type_c<mp::decay_t<T_data>>)) | |||||
| , data (&p_data) | |||||
| { } | |||||
| }; | |||||
| /* filter_context */ | |||||
| struct filter_context | |||||
| : public data_context | |||||
| { | |||||
| const filter_t& filter; | |||||
| template<typename T_data> | |||||
| inline filter_context( | |||||
| T_data& p_data, | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection, | |||||
| const filter_t& p_filter) | |||||
| : data_context (p_data, p_schema, p_connection) | |||||
| , filter (p_filter) | |||||
| { } | |||||
| }; | }; | ||||
| /* create_update_context */ | /* create_update_context */ | ||||
| struct create_update_context | struct create_update_context | ||||
| : public filter_context | |||||
| { | { | ||||
| bool is_update; | |||||
| const schema_t& schema; | |||||
| const filter_t& filter; | |||||
| const table_t* derived_table; | |||||
| const field_t* owner_field; | |||||
| ::cppmariadb::connection& connection; | |||||
| bool is_update; | |||||
| const table_t* derived_table; | |||||
| const field_t* owner_field; | |||||
| std::string owner_key; | |||||
| template<typename T_data> | |||||
| inline create_update_context( | |||||
| T_data& p_data, | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection, | |||||
| const filter_t& p_filter, | |||||
| bool p_is_update) | |||||
| : filter_context(p_data, p_schema, p_connection, p_filter) | |||||
| , is_update (p_is_update) | |||||
| , derived_table (nullptr) | |||||
| , owner_field (nullptr) | |||||
| { } | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -1,76 +0,0 @@ | |||||
| #pragma once | |||||
| #include <stack> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpputils/misc/type_helper.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* reference_lock */ | |||||
| struct reference_lock | |||||
| { | |||||
| virtual ~reference_lock() = default; | |||||
| }; | |||||
| using reference_lock_ptr = std::unique_ptr<reference_lock>; | |||||
| /* reference_stack */ | |||||
| template<typename T_dataset> | |||||
| struct reference_stack | |||||
| { | |||||
| private: | |||||
| struct lock | |||||
| : public reference_lock | |||||
| { | |||||
| private: | |||||
| T_dataset& dataset; | |||||
| public: | |||||
| inline lock(T_dataset& p_dataset) | |||||
| : dataset(p_dataset) | |||||
| { push_impl(dataset); } | |||||
| virtual ~lock() override | |||||
| { pop_impl(dataset); } | |||||
| }; | |||||
| private: | |||||
| using stack_type = std::stack<T_dataset*>; | |||||
| static inline stack_type& stack() | |||||
| { | |||||
| static stack_type value; | |||||
| return value; | |||||
| } | |||||
| static inline void push_impl(T_dataset& dataset) | |||||
| { stack().push(&dataset); } | |||||
| static inline void pop_impl(T_dataset& dataset) | |||||
| { | |||||
| if (stack().empty() || stack().top() != &dataset) | |||||
| throw misc::hibernate_exception(std::string("reference_stack<") + utl::type_helper<T_dataset>::name() + ">: poped element is not the top element!"); | |||||
| stack().pop(); | |||||
| } | |||||
| public: | |||||
| static inline decltype(auto) push(T_dataset& dataset) | |||||
| { return std::make_unique<lock>(dataset); } | |||||
| static inline T_dataset& top() | |||||
| { | |||||
| if (stack().empty()) | |||||
| throw misc::hibernate_exception(std::string("reference_stack<") + utl::type_helper<T_dataset>::name() + ">: does not have stored a dataset!"); | |||||
| return *stack().top(); | |||||
| } | |||||
| static inline size_t size() | |||||
| { return stack().size(); } | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -1,4 +1,3 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/driver/mariadb/impl/init.h> | |||||
| #include <cpphibernate/driver/mariadb/impl/create_update.h> | #include <cpphibernate/driver/mariadb/impl/create_update.h> | ||||
| @@ -3,6 +3,8 @@ | |||||
| #include <cppmariadb.h> | #include <cppmariadb.h> | ||||
| #include <cpphibernate/misc.h> | #include <cpphibernate/misc.h> | ||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpphibernate/driver/mariadb/helper.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | beg_namespace_cpphibernate_driver_mariadb | ||||
| { | { | ||||
| @@ -12,34 +14,39 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_dataset, typename = void> | template<typename T_dataset, typename = void> | ||||
| struct create_update_impl_t | struct create_update_impl_t | ||||
| { | { | ||||
| using dataset_type = T_dataset; | |||||
| using reference_stack_type = reference_stack<dataset_type>; | |||||
| using dataset_type = T_dataset; | |||||
| static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true) | |||||
| static inline value_t apply(const create_update_context& context, bool strict = true) | |||||
| { | { | ||||
| value_t ret; | value_t ret; | ||||
| auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>); | |||||
| auto& connection = context.connection; | |||||
| auto& schema = context.schema; | |||||
| auto& table = schema.table(dataset_id); | |||||
| auto ref_lock = reference_stack_type::push(dataset); | |||||
| auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>); | |||||
| auto& connection = context.connection; | |||||
| auto& schema = context.schema; | |||||
| auto& table = schema.table(dataset_id); | |||||
| assert(table.primary_key_field); | assert(table.primary_key_field); | ||||
| transaction_lock trans(connection); | transaction_lock trans(connection); | ||||
| if (table.primary_key_field->is_default()) | |||||
| { | |||||
| ret = table.create_update(context); | |||||
| } | |||||
| else if (strict) | |||||
| if (table.primary_key_field->is_default(context) == context.is_update) | |||||
| { | { | ||||
| throw misc::hibernate_exception("dataset have already a primary key assigned!"); | |||||
| if (!strict) | |||||
| { | |||||
| auto update_context = context; | |||||
| update_context.is_update = true; | |||||
| ret = table.create_update(update_context); | |||||
| } | |||||
| else if (context.is_update) | |||||
| { | |||||
| throw misc::hibernate_exception("can not update dataset with no primary key assigned!"); | |||||
| } | |||||
| else | |||||
| { | |||||
| throw misc::hibernate_exception("can not create dataset with primary key assigned!"); | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| auto update_context = context; | |||||
| update_context.is_update = true; | |||||
| ret = table.create_update(update_context); | |||||
| ret = table.create_update(context); | |||||
| } | } | ||||
| trans.commit(); | trans.commit(); | ||||
| return ret; | return ret; | ||||
| @@ -56,16 +63,17 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using dataset_type = T_dataset; | using dataset_type = T_dataset; | ||||
| using nullable_helper_type = misc::nullable_helper<dataset_type>; | using nullable_helper_type = misc::nullable_helper<dataset_type>; | ||||
| static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true) | |||||
| static inline value_t apply(const create_update_context& context, bool strict = true) | |||||
| { | { | ||||
| value_t ret; | value_t ret; | ||||
| auto* value = nullable_helper_type::get(dataset); | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto* value = nullable_helper_type::get(dataset); | |||||
| if (value) | if (value) | ||||
| { | { | ||||
| using new_dataset_type = mp::decay_t<decltype(*value)>; | using new_dataset_type = mp::decay_t<decltype(*value)>; | ||||
| using new_create_update_impl_type = create_update_impl_t<new_dataset_type>; | using new_create_update_impl_type = create_update_impl_t<new_dataset_type>; | ||||
| ret = new_create_update_impl_type::apply(*value, context, strict); | |||||
| ret = new_create_update_impl_type::apply(change_context(context, *value), strict); | |||||
| } | } | ||||
| else if (strict) | else if (strict) | ||||
| { | { | ||||
| @@ -84,17 +92,18 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { | { | ||||
| using dataset_type = T_dataset; | using dataset_type = T_dataset; | ||||
| static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true) | |||||
| static inline value_t apply(const create_update_context& context, bool strict = true) | |||||
| { | { | ||||
| value_t ret; | value_t ret; | ||||
| auto& connection = context.connection; | auto& connection = context.connection; | ||||
| auto& dataset = context.get<dataset_type>(); | |||||
| transaction_lock trans(connection); | transaction_lock trans(connection); | ||||
| for (auto& x : dataset) | for (auto& x : dataset) | ||||
| { | { | ||||
| using new_dataset_type = mp::decay_t<decltype(x)>; | using new_dataset_type = mp::decay_t<decltype(x)>; | ||||
| using new_create_update_impl_type = create_update_impl_t<new_dataset_type>; | using new_create_update_impl_type = create_update_impl_t<new_dataset_type>; | ||||
| new_create_update_impl_type::apply(x, context, strict); | |||||
| new_create_update_impl_type::apply(change_context(context, x), strict); | |||||
| } | } | ||||
| trans.commit(); | trans.commit(); | ||||
| return ret; | return ret; | ||||
| @@ -1,30 +0,0 @@ | |||||
| #pragma once | |||||
| #include <cppmariadb.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/helper.h> | |||||
| #include <cpphibernate/driver/mariadb/schema.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* init_impl_t */ | |||||
| template<typename T_context, typename = void> | |||||
| struct init_impl_t | |||||
| { | |||||
| using context_type = T_context; | |||||
| static inline void apply(const context_type& context) | |||||
| { | |||||
| auto& schema = context.schema; | |||||
| auto& connection = context.connection; | |||||
| transaction_lock trans(connection); | |||||
| schema.init(context); | |||||
| trans.commit(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -29,28 +29,16 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| protected: | protected: | ||||
| inline void init_impl(bool recreate) const | inline void init_impl(bool recreate) const | ||||
| { | { | ||||
| init_impl_t<init_context>::apply(init_context | |||||
| { | |||||
| _schema, | |||||
| _connection, | |||||
| recreate | |||||
| }); | |||||
| transaction_lock trans(_connection); | |||||
| _schema.init(init_context(_schema, _connection, recreate)); | |||||
| trans.commit(); | |||||
| } | } | ||||
| template<typename T_dataset> | template<typename T_dataset> | ||||
| inline void create_impl(T_dataset& dataset) const | inline void create_impl(T_dataset& dataset) const | ||||
| { | { | ||||
| create_update_impl_t<T_dataset>::apply( | create_update_impl_t<T_dataset>::apply( | ||||
| dataset, | |||||
| create_update_context | |||||
| { | |||||
| true, | |||||
| _schema, | |||||
| _filter, | |||||
| nullptr, | |||||
| nullptr, | |||||
| _connection | |||||
| }); | |||||
| create_update_context(dataset, _schema, _connection, _filter, false)); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -14,5 +14,9 @@ | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | #include <cpphibernate/driver/mariadb/schema/table.h> | ||||
| #include <cpphibernate/driver/mariadb/schema/tables.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/field.inl> | ||||
| #include <cpphibernate/driver/mariadb/schema/table.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/fields.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/tables.inl> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.inl> | |||||
| @@ -19,58 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using base_type::base_type; | 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -0,0 +1,62 @@ | |||||
| #pragma once | |||||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| 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 | |||||
| @@ -55,13 +55,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual std::string create_table_arguments () const; | virtual std::string create_table_arguments () const; | ||||
| virtual std::string generate_value (::cppmariadb::connection& connection) const; | virtual std::string generate_value (::cppmariadb::connection& connection) const; | ||||
| virtual bool is_auto_generated () const; | virtual bool is_auto_generated () const; | ||||
| virtual bool is_default () const; | |||||
| virtual bool is_default (const data_context& context) const; | |||||
| virtual std::string convert_to_open () const; | virtual std::string convert_to_open () const; | ||||
| virtual std::string convert_to_close () const; | virtual std::string convert_to_close () const; | ||||
| virtual std::string convert_from_open () const; | virtual std::string convert_from_open () const; | ||||
| virtual std::string convert_from_close () const; | virtual std::string convert_from_close () const; | ||||
| virtual value_t get () const; | |||||
| virtual void set (const value_t&) const; | |||||
| virtual value_t get (const data_context& context) const; | |||||
| virtual void set (const data_context& context, const value_t&) const; | |||||
| }; | }; | ||||
| /* simple_field_t */ | /* simple_field_t */ | ||||
| @@ -75,7 +75,6 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using getter_type = typename mp::decay_t<field_type>::getter_type; | using getter_type = typename mp::decay_t<field_type>::getter_type; | ||||
| using dataset_type = typename getter_type::dataset_type; | using dataset_type = typename getter_type::dataset_type; | ||||
| using value_type = typename getter_type::value_type; | using value_type = typename getter_type::value_type; | ||||
| using ref_stack = reference_stack<dataset_type>; | |||||
| const schema_type& schema; | const schema_type& schema; | ||||
| const field_type& field; | const field_type& field; | ||||
| @@ -99,14 +98,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using getter_type = typename base_type::getter_type; | using getter_type = typename base_type::getter_type; | ||||
| using dataset_type = typename base_type::dataset_type; | using dataset_type = typename base_type::dataset_type; | ||||
| using value_type = typename base_type::value_type; | using value_type = typename base_type::value_type; | ||||
| using ref_stack = typename base_type::ref_stack; | |||||
| using type_props = type_properties<value_type>; | using type_props = type_properties<value_type>; | ||||
| using base_type::base_type; | using base_type::base_type; | ||||
| virtual std::string type() const override; | virtual std::string type() const override; | ||||
| virtual value_t get () const override; | |||||
| virtual void set (const value_t&) const override; | |||||
| virtual value_t get (const data_context& context) const override; | |||||
| virtual void set (const data_context& context, const value_t&) const override; | |||||
| }; | }; | ||||
| /* primary_key_field_t */ | /* primary_key_field_t */ | ||||
| @@ -118,8 +116,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using base_type = value_field_t<T_schema, T_field>; | using base_type = value_field_t<T_schema, T_field>; | ||||
| using schema_type = typename base_type::schema_type; | using schema_type = typename base_type::schema_type; | ||||
| using field_type = typename base_type::field_type; | 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 value_type = typename base_type::value_type; | ||||
| using ref_stack = typename base_type::ref_stack; | |||||
| using key_props = key_properties<value_type>; | using key_props = key_properties<value_type>; | ||||
| using base_type::base_type; | using base_type::base_type; | ||||
| @@ -127,7 +125,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual std::string create_table_arguments () const override; | virtual std::string create_table_arguments () const override; | ||||
| virtual std::string generate_value (::cppmariadb::connection& connection) const override; | virtual std::string generate_value (::cppmariadb::connection& connection) const override; | ||||
| virtual bool is_auto_generated () const override; | virtual bool is_auto_generated () const override; | ||||
| virtual bool is_default () const override; | |||||
| virtual bool is_default (const data_context& context) const override; | |||||
| virtual std::string convert_to_open () const override; | virtual std::string convert_to_open () const override; | ||||
| virtual std::string convert_to_close () const override; | virtual std::string convert_to_close () const override; | ||||
| virtual std::string convert_from_open () const override; | virtual std::string convert_from_open () const override; | ||||
| @@ -154,7 +152,6 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| public: | public: | ||||
| using base_type = simple_field_t<T_schema, T_field>; | using base_type = simple_field_t<T_schema, T_field>; | ||||
| using dataset_type = typename base_type::dataset_type; | using dataset_type = typename base_type::dataset_type; | ||||
| using ref_stack = typename base_type::ref_stack; | |||||
| using base_type::base_type; | using base_type::base_type; | ||||
| @@ -162,95 +159,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual value_t foreign_create_update(const create_update_context& context) const override; | virtual value_t foreign_create_update(const create_update_context& context) const override; | ||||
| }; | }; | ||||
| 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>; | |||||
| using primary_key_type = primary_key_field_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); | |||||
| 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -13,12 +13,18 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { return type_props::type(); } | { return type_props::type(); } | ||||
| template<typename T_schema, typename T_field> | template<typename T_schema, typename T_field> | ||||
| value_t value_field_t<T_schema, T_field>::get() const | |||||
| { return type_props::convert_from(this->field.getter(ref_stack::top())); } | |||||
| value_t value_field_t<T_schema, 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_schema, typename T_field> | template<typename T_schema, typename T_field> | ||||
| void value_field_t<T_schema, T_field>::set(const value_t& value) const | |||||
| { this->field.setter(ref_stack::top(), type_props::convert_to(value)); } | |||||
| void value_field_t<T_schema, 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 */ | /* primary_key_field_t */ | ||||
| @@ -41,8 +47,11 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { return key_props::auto_generated::value; } | { return key_props::auto_generated::value; } | ||||
| template<typename T_schema, typename T_field> | template<typename T_schema, typename T_field> | ||||
| bool primary_key_field_t<T_schema, T_field>::is_default() const | |||||
| { return key_props::is_default(this->field.getter(ref_stack::top())); } | |||||
| bool primary_key_field_t<T_schema, 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_schema, typename T_field> | template<typename T_schema, typename T_field> | ||||
| std::string primary_key_field_t<T_schema, T_field>::convert_to_open() const | std::string primary_key_field_t<T_schema, T_field>::convert_to_open() const | ||||
| @@ -66,16 +75,105 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| value_t foreign_table_field_t<T_schema, T_field> | value_t foreign_table_field_t<T_schema, T_field> | ||||
| ::foreign_create_update(const create_update_context& context) const | ::foreign_create_update(const create_update_context& context) const | ||||
| { | { | ||||
| auto& ref = ref_stack::top(); | |||||
| auto& foreign = this->field.getter(ref); | |||||
| 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)>; | using foreign_dataset_type = mp::decay_t<decltype(foreign)>; | ||||
| return create_update_impl_t<foreign_dataset_type>::apply( | return create_update_impl_t<foreign_dataset_type>::apply( | ||||
| foreign, | |||||
| context, | |||||
| next_context, | |||||
| false); | false); | ||||
| } | } | ||||
| 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>; | |||||
| using primary_key_type = primary_key_field_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); | |||||
| 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -21,51 +21,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using base_type::base_type; | 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -0,0 +1,55 @@ | |||||
| #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 | |||||
| @@ -32,36 +32,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| void init(const init_context& context) const; | void init(const init_context& context) 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -0,0 +1,40 @@ | |||||
| #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 | |||||
| @@ -166,93 +166,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual std::string create_update_base(const create_update_context& context) const override; | virtual std::string create_update_base(const create_update_context& context) const override; | ||||
| }; | }; | ||||
| 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -36,12 +36,11 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| ::create_update_intern(const create_update_context& context) const | ::create_update_intern(const create_update_context& context) const | ||||
| { | { | ||||
| bool done = false; | bool done = false; | ||||
| auto& dataset = reference_stack<dataset_type>::top(); | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ | for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ | ||||
| if (!done) | if (!done) | ||||
| { | { | ||||
| using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>; | using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>; | ||||
| using reference_stack_type = reference_stack<derived_dataset_type>; | |||||
| auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>); | auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>); | ||||
| auto derived_table = this->get_derived(derived_dataset_id); | auto derived_table = this->get_derived(derived_dataset_id); | ||||
| if (!derived_table) | if (!derived_table) | ||||
| @@ -50,14 +49,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| << "unable to find derived table info for dataset '" | << "unable to find derived table info for dataset '" | ||||
| << utl::type_helper<derived_dataset_type>::name() << "'!").str()); | << utl::type_helper<derived_dataset_type>::name() << "'!").str()); | ||||
| } | } | ||||
| auto ref_lock = reference_stack_type::push(derived_dataset); | |||||
| derived_table->create_update(context); | |||||
| derived_table->create_update(change_context(context, derived_dataset)); | |||||
| done = true; | done = true; | ||||
| } | } | ||||
| }); | }); | ||||
| return done | return done | ||||
| ? *this->primary_key_field->get() | |||||
| ? *this->primary_key_field->get(context) | |||||
| : this->create_update_exec(context); | : this->create_update_exec(context); | ||||
| } | } | ||||
| @@ -74,12 +72,99 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| [this, &context](auto _)->std::string { | [this, &context](auto _)->std::string { | ||||
| using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>; | using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>; | ||||
| assert(base_table); | assert(base_table); | ||||
| auto& dataset = reference_stack<dataset_type>::top(); | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto& base = static_cast<tmp_type&>(dataset); | auto& base = static_cast<tmp_type&>(dataset); | ||||
| auto lock = reference_stack<tmp_type>::push(base); | |||||
| return this->base_table->create_update_exec(context); | |||||
| 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 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -19,51 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using base_type::base_type; | 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 | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -0,0 +1,55 @@ | |||||
| #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 | |||||
| @@ -45,12 +45,12 @@ throw_not_implemented(value_t, foreign_create_update, const create_update_conte | |||||
| /* properties */ | /* properties */ | ||||
| throw_not_implemented(bool, is_default) | |||||
| throw_not_implemented(bool, is_default, const data_context& context) | |||||
| throw_not_implemented(string, type) | throw_not_implemented(string, type) | ||||
| throw_not_implemented(string, create_table_arguments) | throw_not_implemented(string, create_table_arguments) | ||||
| throw_not_implemented(string, generate_value, ::cppmariadb::connection&) | throw_not_implemented(string, generate_value, ::cppmariadb::connection&) | ||||
| throw_not_implemented(value_t, get) | |||||
| throw_not_implemented(void, set, const value_t&) | |||||
| throw_not_implemented(value_t, get, const data_context& context) | |||||
| throw_not_implemented(void, set, const data_context& context, const value_t&) | |||||
| bool field_t::is_auto_generated() const | bool field_t::is_auto_generated() const | ||||
| { return false; } | { return false; } | ||||
| @@ -512,7 +512,7 @@ std::string table_t::execute_create_update( | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| primary_key = *primary_key_field->get(); | |||||
| primary_key = *primary_key_field->get(context); | |||||
| } | } | ||||
| /* base_key */ | /* base_key */ | ||||
| @@ -546,16 +546,15 @@ std::string table_t::execute_create_update( | |||||
| /* foreign fields */ | /* foreign fields */ | ||||
| for (auto& ptr : foreign_key_fields) | for (auto& ptr : foreign_key_fields) | ||||
| { | { | ||||
| assert(ptr); | |||||
| if (is_update && ptr != context.owner_field) | if (is_update && ptr != context.owner_field) | ||||
| continue; | continue; | ||||
| if ( context.owner_field | if ( context.owner_field | ||||
| && ptr == context.owner_field) | && ptr == context.owner_field) | ||||
| { | { | ||||
| auto& field_info = *ptr; | |||||
| assert(field_info.table); | |||||
| assert(field_info.table->primary_key_field); | |||||
| statement.set(index, field_info.table->primary_key_field->get()); | |||||
| assert(!context.owner_key.empty()); | |||||
| statement.set(index, context.owner_key); | |||||
| } | } | ||||
| else | else | ||||
| statement.set_null(index); | statement.set_null(index); | ||||
| @@ -568,8 +567,10 @@ std::string table_t::execute_create_update( | |||||
| if (is_update && !filter->contains(ptr)) | if (is_update && !filter->contains(ptr)) | ||||
| continue; | continue; | ||||
| assert(ptr); | assert(ptr); | ||||
| auto& field_info = *ptr; | auto& field_info = *ptr; | ||||
| auto value = field_info.get(); | |||||
| auto value = field_info.get(context); | |||||
| if (value.has_value()) statement.set(index, *value); | if (value.has_value()) statement.set(index, *value); | ||||
| else statement.set_null(index); | else statement.set_null(index); | ||||
| ++index; | ++index; | ||||
| @@ -589,7 +590,7 @@ std::string table_t::execute_create_update( | |||||
| if (is_update) | if (is_update) | ||||
| { | { | ||||
| assert(primary_key_field); | assert(primary_key_field); | ||||
| statement.set(index, *primary_key_field->get()); | |||||
| statement.set(index, *primary_key_field->get(context)); | |||||
| ++index; | ++index; | ||||
| } | } | ||||
| @@ -614,7 +615,7 @@ std::string table_t::execute_create_update( | |||||
| auto count = connection.execute_rows(statement); | auto count = connection.execute_rows(statement); | ||||
| cpphibernate_debug_log(count << " rows inserted/updated"); | cpphibernate_debug_log(count << " rows inserted/updated"); | ||||
| } | } | ||||
| primary_key_field->set(primary_key); | |||||
| primary_key_field->set(context, primary_key); | |||||
| /* foreign table many fields */ | /* foreign table many fields */ | ||||
| for (auto& ptr : foreign_table_many_fields) | for (auto& ptr : foreign_table_many_fields) | ||||
| @@ -626,7 +627,9 @@ std::string table_t::execute_create_update( | |||||
| continue; | continue; | ||||
| auto next_context = context; | auto next_context = context; | ||||
| next_context.owner_field = ptr; | |||||
| next_context.owner_field = ptr; | |||||
| next_context.owner_key = primary_key; | |||||
| next_context.derived_table = nullptr; | |||||
| ptr->foreign_create_update(next_context); | ptr->foreign_create_update(next_context); | ||||
| } | } | ||||
| @@ -41,7 +41,7 @@ MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res) | |||||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_fields(res) : nullptr); } | { 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) | int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length) | ||||
| { std::cout << std::string(q, length) << ";" << std::endl; return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); } | |||||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); } | |||||
| unsigned int STDCALL mysql_errno (MYSQL *mysql) | unsigned int STDCALL mysql_errno (MYSQL *mysql) | ||||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); } | { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); } | ||||