From 42867058b0270a73852a4fefd657e3eef521b2b1 Mon Sep 17 00:00:00 2001 From: bergmann Date: Wed, 29 Aug 2018 22:33:05 +0200 Subject: [PATCH] * refactored mariadb driver internal context processing --- include/cpphibernate/driver/mariadb/helper.h | 1 - .../driver/mariadb/helper/context.h | 126 ++++++++++++++++-- .../driver/mariadb/helper/reference_stack.h | 76 ----------- include/cpphibernate/driver/mariadb/impl.h | 1 - .../driver/mariadb/impl/create_update.h | 53 +++++--- .../cpphibernate/driver/mariadb/impl/init.h | 30 ----- include/cpphibernate/driver/mariadb/mariadb.h | 20 +-- include/cpphibernate/driver/mariadb/schema.h | 6 +- .../driver/mariadb/schema/attributes.h | 53 -------- .../driver/mariadb/schema/attributes.inl | 62 +++++++++ .../driver/mariadb/schema/field.h | 107 +-------------- .../driver/mariadb/schema/field.inl | 120 +++++++++++++++-- .../driver/mariadb/schema/fields.h | 46 ------- .../driver/mariadb/schema/fields.inl | 55 ++++++++ .../driver/mariadb/schema/schema.h | 31 ----- .../driver/mariadb/schema/schema.inl | 40 ++++++ .../driver/mariadb/schema/table.h | 88 ------------ .../driver/mariadb/schema/table.inl | 101 ++++++++++++-- .../driver/mariadb/schema/tables.h | 46 ------- .../driver/mariadb/schema/tables.inl | 55 ++++++++ src/driver/mariadb/schema/field.cpp | 6 +- src/driver/mariadb/schema/table.cpp | 21 +-- test/mariadb_mock.cpp | 2 +- 23 files changed, 594 insertions(+), 552 deletions(-) delete mode 100644 include/cpphibernate/driver/mariadb/helper/reference_stack.h delete mode 100644 include/cpphibernate/driver/mariadb/impl/init.h create mode 100644 include/cpphibernate/driver/mariadb/schema/attributes.inl create mode 100644 include/cpphibernate/driver/mariadb/schema/fields.inl create mode 100644 include/cpphibernate/driver/mariadb/schema/schema.inl create mode 100644 include/cpphibernate/driver/mariadb/schema/tables.inl diff --git a/include/cpphibernate/driver/mariadb/helper.h b/include/cpphibernate/driver/mariadb/helper.h index 8ed0b9e..322dbe8 100644 --- a/include/cpphibernate/driver/mariadb/helper.h +++ b/include/cpphibernate/driver/mariadb/helper.h @@ -2,6 +2,5 @@ #include #include -#include #include #include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/helper/context.h b/include/cpphibernate/driver/mariadb/helper/context.h index 35e4d1c..e9859a1 100644 --- a/include/cpphibernate/driver/mariadb/helper/context.h +++ b/include/cpphibernate/driver/mariadb/helper/context.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -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 + 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>); + 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 + inline decltype(auto) get() const + { + if (!data) + throw misc::hibernate_exception("no data assigned!"); + auto type_id = misc::get_type_id(hana::type_c>); + if (type_id != data_id) + { + throw misc::hibernate_exception(static_cast(std::ostringstream { } + << "invalid type! expected " << data_id << ", got " << type_id).str()); + } + return *static_cast(data); + } + + template + 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>)) + , data (&p_data) + { } + }; + + /* filter_context */ + + struct filter_context + : public data_context + { + const filter_t& filter; + + template + 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 + 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) + { } }; } diff --git a/include/cpphibernate/driver/mariadb/helper/reference_stack.h b/include/cpphibernate/driver/mariadb/helper/reference_stack.h deleted file mode 100644 index 8728331..0000000 --- a/include/cpphibernate/driver/mariadb/helper/reference_stack.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include - -#include -#include - -beg_namespace_cpphibernate_driver_mariadb -{ - - /* reference_lock */ - - struct reference_lock - { - virtual ~reference_lock() = default; - }; - - using reference_lock_ptr = std::unique_ptr; - - /* reference_stack */ - - template - 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; - - 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::name() + ">: poped element is not the top element!"); - stack().pop(); - } - - public: - static inline decltype(auto) push(T_dataset& dataset) - { return std::make_unique(dataset); } - - static inline T_dataset& top() - { - if (stack().empty()) - throw misc::hibernate_exception(std::string("reference_stack<") + utl::type_helper::name() + ">: does not have stored a dataset!"); - return *stack().top(); - } - - static inline size_t size() - { return stack().size(); } - }; - -} -end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/impl.h b/include/cpphibernate/driver/mariadb/impl.h index c5de8d9..a82fa8f 100644 --- a/include/cpphibernate/driver/mariadb/impl.h +++ b/include/cpphibernate/driver/mariadb/impl.h @@ -1,4 +1,3 @@ #pragma once -#include #include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/impl/create_update.h b/include/cpphibernate/driver/mariadb/impl/create_update.h index 35d0a86..e2d7f48 100644 --- a/include/cpphibernate/driver/mariadb/impl/create_update.h +++ b/include/cpphibernate/driver/mariadb/impl/create_update.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include beg_namespace_cpphibernate_driver_mariadb { @@ -12,34 +14,39 @@ beg_namespace_cpphibernate_driver_mariadb template struct create_update_impl_t { - using dataset_type = T_dataset; - using reference_stack_type = reference_stack; + 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); - 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); + 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; - 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(); + auto* value = nullable_helper_type::get(dataset); if (value) { using new_dataset_type = mp::decay_t; using new_create_update_impl_type = create_update_impl_t; - 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(); transaction_lock trans(connection); for (auto& x : dataset) { using new_dataset_type = mp::decay_t; using new_create_update_impl_type = create_update_impl_t; - new_create_update_impl_type::apply(x, context, strict); + new_create_update_impl_type::apply(change_context(context, x), strict); } trans.commit(); return ret; diff --git a/include/cpphibernate/driver/mariadb/impl/init.h b/include/cpphibernate/driver/mariadb/impl/init.h deleted file mode 100644 index b3d2743..0000000 --- a/include/cpphibernate/driver/mariadb/impl/init.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -beg_namespace_cpphibernate_driver_mariadb -{ - - /* init_impl_t */ - - template - 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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/mariadb.h b/include/cpphibernate/driver/mariadb/mariadb.h index eb3d818..49243d4 100644 --- a/include/cpphibernate/driver/mariadb/mariadb.h +++ b/include/cpphibernate/driver/mariadb/mariadb.h @@ -29,28 +29,16 @@ beg_namespace_cpphibernate_driver_mariadb protected: inline void init_impl(bool recreate) const { - init_impl_t::apply(init_context - { - _schema, - _connection, - recreate - }); + transaction_lock trans(_connection); + _schema.init(init_context(_schema, _connection, recreate)); + trans.commit(); } template inline void create_impl(T_dataset& dataset) const { create_update_impl_t::apply( - dataset, - create_update_context - { - true, - _schema, - _filter, - nullptr, - nullptr, - _connection - }); + create_update_context(dataset, _schema, _connection, _filter, false)); } }; diff --git a/include/cpphibernate/driver/mariadb/schema.h b/include/cpphibernate/driver/mariadb/schema.h index e1feffb..0010a5a 100644 --- a/include/cpphibernate/driver/mariadb/schema.h +++ b/include/cpphibernate/driver/mariadb/schema.h @@ -14,5 +14,9 @@ #include #include +#include #include -#include \ No newline at end of file +#include +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/attributes.h b/include/cpphibernate/driver/mariadb/schema/attributes.h index a4e072c..3b1ca22 100644 --- a/include/cpphibernate/driver/mariadb/schema/attributes.h +++ b/include/cpphibernate/driver/mariadb/schema/attributes.h @@ -19,58 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb using base_type::base_type; }; - namespace __impl - { - - /* attribute_converter */ - - template - struct attribute_converter; - - template<> - struct attribute_converter - { static constexpr decltype(auto) value = attribute_t::hex; }; - - template<> - struct attribute_converter - { static constexpr decltype(auto) value = attribute_t::compress; }; - - template<> - struct attribute_converter - { static constexpr decltype(auto) value = attribute_t::primary_key; }; - - /* make_attributes_impl */ - - template - struct make_attributes_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); } - }; - - template - struct make_attributes_impl< - mp::list, - mp::enable_if_c< - schema::is_attributes>::value>> - { - template - static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence&) - { - return attributes_t({ - attribute_converter()[hana::size_c])>>::value... - }); - } - - static constexpr decltype(auto) apply(const T_attributes& attributes) - { - using size = mp::decay_t; - return helper(attributes, std::make_index_sequence { }); - } - }; - - } - } end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/attributes.inl b/include/cpphibernate/driver/mariadb/schema/attributes.inl new file mode 100644 index 0000000..87a7ae0 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/attributes.inl @@ -0,0 +1,62 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + namespace __impl + { + + /* attribute_converter */ + + template + struct attribute_converter; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::hex; }; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::compress; }; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::primary_key; }; + + /* make_attributes_impl */ + + template + struct make_attributes_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); } + }; + + template + struct make_attributes_impl< + mp::list, + mp::enable_if_c< + schema::is_attributes>::value>> + { + template + static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence&) + { + return attributes_t({ + attribute_converter()[hana::size_c])>>::value... + }); + } + + static constexpr decltype(auto) apply(const T_attributes& attributes) + { + using size = mp::decay_t; + return helper(attributes, std::make_index_sequence { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/field.h b/include/cpphibernate/driver/mariadb/schema/field.h index 9ffc48b..e7947ee 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.h +++ b/include/cpphibernate/driver/mariadb/schema/field.h @@ -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::getter_type; using dataset_type = typename getter_type::dataset_type; using value_type = typename getter_type::value_type; - using ref_stack = reference_stack; 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; 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; 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; 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; 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 - struct is_primary_key_field - : public mp::decay_t().attributes, - schema::attribute::primary_key))> - { }; - - /* is_foreign_table_field */ - - template - struct is_foreign_table_field - : public mp::decay_t().tables, - schema::table::get_wrapped_dataset), - hana::type_c>))> - { }; - - /* field_type */ - - template - struct field_type - { using type = data_field_t; }; - - template - struct field_type>> - { using type = primary_key_field_t; }; - - template - struct field_type>> - { using type = foreign_table_field_t; }; - - template - using field_type_t = typename field_type::type; - - /* make_field_impl */ - - template - struct make_field_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); } - }; - - template - struct make_field_impl< - mp::list, - mp::enable_if_c< - schema::is_schema>::value - && schema::is_table >::value - && schema::is_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; - using field_type = mp::decay_t; - using getter_type = mp::decay_t; - using value_type = mp::decay_t; - using dataset_type = mp::decay_t; - using value_dataset_type = misc::real_dataset_t; - using return_type = field_type_t; - using primary_key_type = primary_key_field_t; - return_type ret(schema, field); - ret.table_dataset_id = misc::get_type_id(hana::type_c); - ret.value_dataset_id = misc::get_type_id(hana::type_c); - ret.value_is_nullable = misc::is_nullable::value; - ret.value_is_container = misc::is_container::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, hana::type_c), - [&ret](){ - ret.field_name = ret.table_name + "_" + ret.field_name; - }, [](){ }); - return ret; - } - }; - - } - } end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/field.inl b/include/cpphibernate/driver/mariadb/schema/field.inl index 4f820d4..2820537 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.inl +++ b/include/cpphibernate/driver/mariadb/schema/field.inl @@ -13,12 +13,18 @@ beg_namespace_cpphibernate_driver_mariadb { return type_props::type(); } template - value_t value_field_t::get() const - { return type_props::convert_from(this->field.getter(ref_stack::top())); } + value_t value_field_t::get(const data_context& context) const + { + auto& dataset = context.get(); + return type_props::convert_from(this->field.getter(dataset)); + } template - void value_field_t::set(const value_t& value) const - { this->field.setter(ref_stack::top(), type_props::convert_to(value)); } + void value_field_t::set(const data_context& context, const value_t& value) const + { + auto& dataset = context.get(); + 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 - bool primary_key_field_t::is_default() const - { return key_props::is_default(this->field.getter(ref_stack::top())); } + bool primary_key_field_t::is_default(const data_context& context) const + { + auto& dataset = context.get(); + return key_props::is_default(this->field.getter(dataset)); + } template std::string primary_key_field_t::convert_to_open() const @@ -66,16 +75,105 @@ beg_namespace_cpphibernate_driver_mariadb value_t foreign_table_field_t ::foreign_create_update(const create_update_context& context) const { - auto& ref = ref_stack::top(); - auto& foreign = this->field.getter(ref); + auto& dataset = context.get(); + auto& foreign = this->field.getter(dataset); + auto next_context = change_context(context, foreign); using foreign_dataset_type = mp::decay_t; - return create_update_impl_t::apply( - foreign, - context, + next_context, false); } + namespace __impl + { + + /* is_primary_key_field */ + + template + struct is_primary_key_field + : public mp::decay_t().attributes, + schema::attribute::primary_key))> + { }; + + /* is_foreign_table_field */ + + template + struct is_foreign_table_field + : public mp::decay_t().tables, + schema::table::get_wrapped_dataset), + hana::type_c>))> + { }; + + /* field_type */ + + template + struct field_type + { using type = data_field_t; }; + + template + struct field_type>> + { using type = primary_key_field_t; }; + + template + struct field_type>> + { using type = foreign_table_field_t; }; + + template + using field_type_t = typename field_type::type; + + /* make_field_impl */ + + template + struct make_field_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); } + }; + + template + struct make_field_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value + && schema::is_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; + using field_type = mp::decay_t; + using getter_type = mp::decay_t; + using value_type = mp::decay_t; + using dataset_type = mp::decay_t; + using value_dataset_type = misc::real_dataset_t; + using return_type = field_type_t; + using primary_key_type = primary_key_field_t; + return_type ret(schema, field); + ret.table_dataset_id = misc::get_type_id(hana::type_c); + ret.value_dataset_id = misc::get_type_id(hana::type_c); + ret.value_is_nullable = misc::is_nullable::value; + ret.value_is_container = misc::is_container::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, hana::type_c), + [&ret](){ + ret.field_name = ret.table_name + "_" + ret.field_name; + }, [](){ }); + return ret; + } + }; + + } + } end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/fields.h b/include/cpphibernate/driver/mariadb/schema/fields.h index fda7825..8eb5400 100644 --- a/include/cpphibernate/driver/mariadb/schema/fields.h +++ b/include/cpphibernate/driver/mariadb/schema/fields.h @@ -21,51 +21,5 @@ beg_namespace_cpphibernate_driver_mariadb using base_type::base_type; }; - namespace __impl - { - - /* make_fields_impl */ - - template - struct make_fields_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); } - }; - - template - struct make_fields_impl< - mp::list, - mp::enable_if_c< - schema::is_schema>::value - && schema::is_table >::value>> - { - template - 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; - fields.emplace_back(new field_type(std::move(field))); - } - - template - static auto helper(const T_schema& schema, const T_table& table, std::index_sequence&&) - { - fields_t fields; - int dummy[] = {0, (emplace(fields, schema, table, hana::size_c), 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 { }); - } - }; - - } - } end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/fields.inl b/include/cpphibernate/driver/mariadb/schema/fields.inl new file mode 100644 index 0000000..e5b044a --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/fields.inl @@ -0,0 +1,55 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + namespace __impl + { + + /* make_fields_impl */ + + template + struct make_fields_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); } + }; + + template + struct make_fields_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value>> + { + template + 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; + fields.emplace_back(new field_type(std::move(field))); + } + + template + static auto helper(const T_schema& schema, const T_table& table, std::index_sequence&&) + { + fields_t fields; + int dummy[] = {0, (emplace(fields, schema, table, hana::size_c), 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 { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/schema.h b/include/cpphibernate/driver/mariadb/schema/schema.h index 8c48556..ad8abd1 100644 --- a/include/cpphibernate/driver/mariadb/schema/schema.h +++ b/include/cpphibernate/driver/mariadb/schema/schema.h @@ -32,36 +32,5 @@ beg_namespace_cpphibernate_driver_mariadb void init(const init_context& context) const; }; - namespace __impl - { - - /* make_schema_impl */ - - template - struct make_schema_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); } - }; - - template - struct make_schema_impl< - mp::list, - mp::enable_if_c< - schema::is_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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/schema.inl b/include/cpphibernate/driver/mariadb/schema/schema.inl new file mode 100644 index 0000000..8c1b6ed --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/schema.inl @@ -0,0 +1,40 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + namespace __impl + { + + /* make_schema_impl */ + + template + struct make_schema_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); } + }; + + template + struct make_schema_impl< + mp::list, + mp::enable_if_c< + schema::is_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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/table.h b/include/cpphibernate/driver/mariadb/schema/table.h index cbef31e..3a4c83c 100644 --- a/include/cpphibernate/driver/mariadb/schema/table.h +++ b/include/cpphibernate/driver/mariadb/schema/table.h @@ -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 - static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence) - { - return std::vector({ - misc::get_type_id(wrapped_datasets[hana::size_c])... - }); - } - - template - constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const - { - using size = mp::decay_t; - return helper(std::forward(wrapped_datasets), std::make_index_sequence { }); - } - }; - - static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { }; - - /* make_table_impl */ - - template - struct make_table_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); } - }; - - template - struct make_table_impl< - mp::list, - mp::enable_if_c< - schema::is_schema>::value - && schema::is_table >::value>> - { - - /* table_type */ - - template - struct table_type - { using type = table_simple_t, mp::decay_t, T_base_dataset>; }; - - template - struct table_type::value>> - { using type = table_polymorphic_t, mp::decay_t, T_base_dataset>; }; - - template - using table_type_t = typename table_type::type; - - /* apply */ - - static decltype(auto) apply(const T_schema& schema, const T_table& table) - { - using wrapped_base_type = mp::decay_t(), - std::declval().wrapped_dataset))>; - using base_type = misc::unwrap_t; - using derived_wrapped_types_type = mp::decay_t(), - std::declval().wrapped_dataset))>; - using wrapped_dataset_type = typename mp::decay_t::wrapped_dataset_type; - using dataset_type = misc::unwrap_t; - using table_type = table_type_t; - - 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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/table.inl b/include/cpphibernate/driver/mariadb/schema/table.inl index b339720..bfb4b4b 100644 --- a/include/cpphibernate/driver/mariadb/schema/table.inl +++ b/include/cpphibernate/driver/mariadb/schema/table.inl @@ -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::top(); + auto& dataset = context.get(); for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ if (!done) { using derived_dataset_type = mp::decay_t; - using reference_stack_type = reference_stack; auto derived_dataset_id = misc::get_type_id(hana::type_c); 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::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))>; assert(base_table); - auto& dataset = reference_stack::top(); + auto& dataset = context.get(); auto& base = static_cast(dataset); - auto lock = reference_stack::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 + static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence) + { + return std::vector({ + misc::get_type_id(wrapped_datasets[hana::size_c])... + }); + } + + template + constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const + { + using size = mp::decay_t; + return helper(std::forward(wrapped_datasets), std::make_index_sequence { }); + } + }; + + static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { }; + + /* make_table_impl */ + + template + struct make_table_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); } + }; + + template + struct make_table_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value>> + { + + /* table_type */ + + template + struct table_type + { using type = table_simple_t, mp::decay_t, T_base_dataset>; }; + + template + struct table_type::value>> + { using type = table_polymorphic_t, mp::decay_t, T_base_dataset>; }; + + template + using table_type_t = typename table_type::type; + + /* apply */ + + static decltype(auto) apply(const T_schema& schema, const T_table& table) + { + using wrapped_base_type = mp::decay_t(), + std::declval().wrapped_dataset))>; + using base_type = misc::unwrap_t; + using derived_wrapped_types_type = mp::decay_t(), + std::declval().wrapped_dataset))>; + using wrapped_dataset_type = typename mp::decay_t::wrapped_dataset_type; + using dataset_type = misc::unwrap_t; + using table_type = table_type_t; + + 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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/tables.h b/include/cpphibernate/driver/mariadb/schema/tables.h index 5706e94..c127cfb 100644 --- a/include/cpphibernate/driver/mariadb/schema/tables.h +++ b/include/cpphibernate/driver/mariadb/schema/tables.h @@ -19,51 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb using base_type::base_type; }; - namespace __impl - { - - /* make_tables_impl */ - - template - struct make_tables_impl - { - template - static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); } - }; - - template - struct make_tables_impl< - mp::list, - mp::enable_if_c< - schema::is_schema>::value>> - { - template - 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; - auto key = table.dataset_id; - tables.emplace(key, std::make_unique(std::move(table))); - } - - template - static decltype(auto) helper(const T_schema& schema, std::index_sequence) - { - tables_t tables; - int dummy[] = {0, (emplace(tables, schema, hana::size_c), 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 { }); - } - }; - - } - } end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/tables.inl b/include/cpphibernate/driver/mariadb/schema/tables.inl new file mode 100644 index 0000000..acabb9e --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/tables.inl @@ -0,0 +1,55 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + namespace __impl + { + + /* make_tables_impl */ + + template + struct make_tables_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); } + }; + + template + struct make_tables_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value>> + { + template + 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; + auto key = table.dataset_id; + tables.emplace(key, std::make_unique(std::move(table))); + } + + template + static decltype(auto) helper(const T_schema& schema, std::index_sequence) + { + tables_t tables; + int dummy[] = {0, (emplace(tables, schema, hana::size_c), 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 { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/src/driver/mariadb/schema/field.cpp b/src/driver/mariadb/schema/field.cpp index c179b70..cea41c3 100644 --- a/src/driver/mariadb/schema/field.cpp +++ b/src/driver/mariadb/schema/field.cpp @@ -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; } diff --git a/src/driver/mariadb/schema/table.cpp b/src/driver/mariadb/schema/table.cpp index 7878523..8a8ef0d 100644 --- a/src/driver/mariadb/schema/table.cpp +++ b/src/driver/mariadb/schema/table.cpp @@ -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); } diff --git a/test/mariadb_mock.cpp b/test/mariadb_mock.cpp index c0146e0..82c5e39 100644 --- a/test/mariadb_mock.cpp +++ b/test/mariadb_mock.cpp @@ -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); }