| @@ -2,6 +2,5 @@ | |||
| #include <cpphibernate/driver/mariadb/helper/context.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/type_properties.h> | |||
| @@ -1,6 +1,7 @@ | |||
| #pragma once | |||
| #include <cppmariadb.h> | |||
| #include <cpphibernate/misc.h> | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||
| @@ -10,25 +11,132 @@ | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| /* init_context */ | |||
| /* base_context */ | |||
| struct init_context | |||
| struct base_context | |||
| { | |||
| const schema_t& schema; | |||
| ::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 */ | |||
| 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 | |||
| #include <cpphibernate/driver/mariadb/impl/init.h> | |||
| #include <cpphibernate/driver/mariadb/impl/create_update.h> | |||
| @@ -3,6 +3,8 @@ | |||
| #include <cppmariadb.h> | |||
| #include <cpphibernate/misc.h> | |||
| #include <cpphibernate/config.h> | |||
| #include <cpphibernate/driver/mariadb/helper.h> | |||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| @@ -12,34 +14,39 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| template<typename T_dataset, typename = void> | |||
| 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; | |||
| 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); | |||
| 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 | |||
| { | |||
| auto update_context = context; | |||
| update_context.is_update = true; | |||
| ret = table.create_update(update_context); | |||
| ret = table.create_update(context); | |||
| } | |||
| trans.commit(); | |||
| return ret; | |||
| @@ -56,16 +63,17 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| using dataset_type = T_dataset; | |||
| 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; | |||
| auto* value = nullable_helper_type::get(dataset); | |||
| auto& dataset = context.get<dataset_type>(); | |||
| auto* value = nullable_helper_type::get(dataset); | |||
| if (value) | |||
| { | |||
| using new_dataset_type = mp::decay_t<decltype(*value)>; | |||
| 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) | |||
| { | |||
| @@ -84,17 +92,18 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| 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; | |||
| auto& connection = context.connection; | |||
| auto& dataset = context.get<dataset_type>(); | |||
| transaction_lock trans(connection); | |||
| for (auto& x : dataset) | |||
| { | |||
| using new_dataset_type = mp::decay_t<decltype(x)>; | |||
| 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(); | |||
| 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: | |||
| 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> | |||
| inline void create_impl(T_dataset& dataset) const | |||
| { | |||
| 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/tables.h> | |||
| #include <cpphibernate/driver/mariadb/schema/attributes.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; | |||
| }; | |||
| 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,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 generate_value (::cppmariadb::connection& connection) 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_close () const; | |||
| virtual std::string convert_from_open () 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 */ | |||
| @@ -75,7 +75,6 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| using getter_type = typename mp::decay_t<field_type>::getter_type; | |||
| using dataset_type = typename getter_type::dataset_type; | |||
| using value_type = typename getter_type::value_type; | |||
| using ref_stack = reference_stack<dataset_type>; | |||
| const schema_type& schema; | |||
| const field_type& field; | |||
| @@ -99,14 +98,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| using getter_type = typename base_type::getter_type; | |||
| using dataset_type = typename base_type::dataset_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 base_type::base_type; | |||
| 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 */ | |||
| @@ -118,8 +116,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| using base_type = value_field_t<T_schema, T_field>; | |||
| using schema_type = typename base_type::schema_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 ref_stack = typename base_type::ref_stack; | |||
| using key_props = key_properties<value_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 generate_value (::cppmariadb::connection& connection) 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_close () const override; | |||
| virtual std::string convert_from_open () const override; | |||
| @@ -154,7 +152,6 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| public: | |||
| using base_type = simple_field_t<T_schema, T_field>; | |||
| using dataset_type = typename base_type::dataset_type; | |||
| using ref_stack = typename base_type::ref_stack; | |||
| 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; | |||
| }; | |||
| 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 | |||
| @@ -13,12 +13,18 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| { return type_props::type(); } | |||
| 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> | |||
| 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 */ | |||
| @@ -41,8 +47,11 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| { return key_props::auto_generated::value; } | |||
| 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> | |||
| 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> | |||
| ::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)>; | |||
| return create_update_impl_t<foreign_dataset_type>::apply( | |||
| foreign, | |||
| context, | |||
| next_context, | |||
| 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 | |||
| @@ -21,51 +21,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| 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,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; | |||
| }; | |||
| 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,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; | |||
| }; | |||
| 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 | |||
| @@ -36,12 +36,11 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| ::create_update_intern(const create_update_context& context) const | |||
| { | |||
| 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){ | |||
| if (!done) | |||
| { | |||
| 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_table = this->get_derived(derived_dataset_id); | |||
| if (!derived_table) | |||
| @@ -50,14 +49,13 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| << "unable to find derived table info for dataset '" | |||
| << 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; | |||
| } | |||
| }); | |||
| return done | |||
| ? *this->primary_key_field->get() | |||
| ? *this->primary_key_field->get(context) | |||
| : this->create_update_exec(context); | |||
| } | |||
| @@ -74,12 +72,99 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| [this, &context](auto _)->std::string { | |||
| using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>; | |||
| assert(base_table); | |||
| auto& dataset = reference_stack<dataset_type>::top(); | |||
| auto& dataset = context.get<dataset_type>(); | |||
| 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 | |||
| @@ -19,51 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| 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 | |||
| @@ -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 */ | |||
| 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, create_table_arguments) | |||
| 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 | |||
| { return false; } | |||
| @@ -512,7 +512,7 @@ std::string table_t::execute_create_update( | |||
| } | |||
| else | |||
| { | |||
| primary_key = *primary_key_field->get(); | |||
| primary_key = *primary_key_field->get(context); | |||
| } | |||
| /* base_key */ | |||
| @@ -546,16 +546,15 @@ std::string table_t::execute_create_update( | |||
| /* foreign fields */ | |||
| for (auto& ptr : foreign_key_fields) | |||
| { | |||
| assert(ptr); | |||
| if (is_update && ptr != context.owner_field) | |||
| continue; | |||
| if ( 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 | |||
| statement.set_null(index); | |||
| @@ -568,8 +567,10 @@ std::string table_t::execute_create_update( | |||
| if (is_update && !filter->contains(ptr)) | |||
| continue; | |||
| assert(ptr); | |||
| auto& field_info = *ptr; | |||
| auto value = field_info.get(); | |||
| auto value = field_info.get(context); | |||
| if (value.has_value()) statement.set(index, *value); | |||
| else statement.set_null(index); | |||
| ++index; | |||
| @@ -589,7 +590,7 @@ std::string table_t::execute_create_update( | |||
| if (is_update) | |||
| { | |||
| assert(primary_key_field); | |||
| statement.set(index, *primary_key_field->get()); | |||
| statement.set(index, *primary_key_field->get(context)); | |||
| ++index; | |||
| } | |||
| @@ -614,7 +615,7 @@ std::string table_t::execute_create_update( | |||
| auto count = connection.execute_rows(statement); | |||
| cpphibernate_debug_log(count << " rows inserted/updated"); | |||
| } | |||
| primary_key_field->set(primary_key); | |||
| primary_key_field->set(context, primary_key); | |||
| /* foreign table many fields */ | |||
| for (auto& ptr : foreign_table_many_fields) | |||
| @@ -626,7 +627,9 @@ std::string table_t::execute_create_update( | |||
| continue; | |||
| 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); | |||
| } | |||
| @@ -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); } | |||
| 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) | |||
| { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); } | |||