diff --git a/include/cpphibernate/context.h b/include/cpphibernate/context.h index 02f10e7..2df4d92 100644 --- a/include/cpphibernate/context.h +++ b/include/cpphibernate/context.h @@ -53,13 +53,14 @@ beg_namespace_cpphibernate template constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers) -> mp::enable_if< - modifier::all_are_modifier...>> + modifier::all_are_modifiers...>> { + using namespace modifier; using real_dataset_type = misc::real_dataset_t>; schema::tables::find(_schema.tables, hana::type_c); - this->read_impl(dataset, hana::make_tuple(std::forward(modifiers)...)); + this->read_impl(dataset, modifier::make_list(std::forward(modifiers)...)); } - + template constexpr auto read(T_dataset& dataset) -> mp::enable_if_c< @@ -70,7 +71,7 @@ beg_namespace_cpphibernate using real_dataset_type = misc::real_dataset_t>; auto& table = schema::tables::find(_schema.tables, hana::type_c); auto& primary_key = schema::table::get_primary_key_field(table); - this->read_impl(dataset, hana::make_tuple(where(equal(primary_key, primary_key.getter(dataset))))); + this->read_impl(dataset, modifier::make_list(where(equal(primary_key, primary_key.getter(dataset))))); } template @@ -82,7 +83,7 @@ beg_namespace_cpphibernate using namespace modifier; using real_dataset_type = misc::real_dataset_t>; schema::tables::find(_schema.tables, hana::type_c); - this->read_impl(dataset, hana::make_tuple()); + this->read_impl(dataset, modifier::make_list()); } /* update */ diff --git a/include/cpphibernate/driver/mariadb/helper/context.h b/include/cpphibernate/driver/mariadb/helper/context.h index e9859a1..561bea6 100644 --- a/include/cpphibernate/driver/mariadb/helper/context.h +++ b/include/cpphibernate/driver/mariadb/helper/context.h @@ -124,6 +124,7 @@ beg_namespace_cpphibernate_driver_mariadb const table_t* derived_table; const field_t* owner_field; std::string owner_key; + ssize_t index; template inline create_update_context( @@ -136,6 +137,7 @@ beg_namespace_cpphibernate_driver_mariadb , is_update (p_is_update) , derived_table (nullptr) , owner_field (nullptr) + , index (-1) { } }; diff --git a/include/cpphibernate/driver/mariadb/helper/type_properties.h b/include/cpphibernate/driver/mariadb/helper/type_properties.h index c7df09d..45ff6b6 100644 --- a/include/cpphibernate/driver/mariadb/helper/type_properties.h +++ b/include/cpphibernate/driver/mariadb/helper/type_properties.h @@ -211,7 +211,7 @@ beg_namespace_cpphibernate_driver_mariadb }; template - struct type_properties>>> + struct type_properties>>> { using nullable_type = T; using nullable_helper_type = misc::nullable_helper; diff --git a/include/cpphibernate/driver/mariadb/impl.h b/include/cpphibernate/driver/mariadb/impl.h index a82fa8f..b990d17 100644 --- a/include/cpphibernate/driver/mariadb/impl.h +++ b/include/cpphibernate/driver/mariadb/impl.h @@ -1,3 +1,5 @@ #pragma once -#include \ No newline at end of file +#include +#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 e2d7f48..a51e6fe 100644 --- a/include/cpphibernate/driver/mariadb/impl/create_update.h +++ b/include/cpphibernate/driver/mariadb/impl/create_update.h @@ -99,11 +99,14 @@ beg_namespace_cpphibernate_driver_mariadb auto& dataset = context.get(); transaction_lock trans(connection); + ssize_t index = 0; 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(change_context(context, x), strict); + auto new_context = change_context(context, x); + new_context.index = index++; + new_create_update_impl_type::apply(new_context, strict); } trans.commit(); return ret; diff --git a/include/cpphibernate/driver/mariadb/impl/limit.h b/include/cpphibernate/driver/mariadb/impl/limit.h new file mode 100644 index 0000000..7e502c6 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/impl/limit.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* limit_builder */ + + template + struct limit_builder + { + ::cppmariadb::statement statement; + + limit_builder(const T_modifiers& modifier) + { + ssize_t limit = -1; + ssize_t offset = -1; + + hana::for_each(modifier, [&limit, &offset](auto& modifier){ + using modifier_type = mp::decay_t; + using is_limit_type = modifier::is_limit_modifier; + using is_offset_type = modifier::is_offset_modifier; + hana::eval_if( + is_limit_type { }, + [&limit, &modifier](auto _){ + limit = hana::value(_(modifier).value); + }, + [&offset, &modifier](){ + hana::eval_if( + is_offset_type { }, + [&offset, &modifier](auto _){ + offset = hana::value(_(modifier).value); + }, + []{ + /* no-op */ + }); + }); + }); + + if (offset >= 0 && limit < 0) + limit = 1000000; + + if (limit >= 0) + { + std::ostringstream ss; + ss << "LIMIT " << limit; + if (offset >= 0) + ss << " OFFSET" << offset; + statement.assign(ss.str()); + } + } + }; + + template + inline ::cppmariadb::statement& build_limit(const T_modifiers& modifiers) + { + static limit_builder builder(modifiers); + return builder.statement; + } + +} +end_namespace_cpphibernate_driver_mariadb diff --git a/include/cpphibernate/driver/mariadb/impl/modifier_tags.h b/include/cpphibernate/driver/mariadb/impl/modifier_tags.h new file mode 100644 index 0000000..f1c6a9b --- /dev/null +++ b/include/cpphibernate/driver/mariadb/impl/modifier_tags.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + namespace __impl + { + + /* make_modifier_tags_impl */ + + template + struct make_modifier_tag_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for make_modifier_tag(...)!"); } + }; + + template + struct make_modifier_tag_impl< + mp::list, + mp::enable_if_c< + modifier::is_limit_modifier>::value + || modifier::is_offset_modifier>::value>> + { + static constexpr decltype(auto) apply(T_modifier&&) + { return T_modifier { }; } + }; + + } + + constexpr decltype(auto) make_modifier_tag = misc::make_generic_predicate<__impl::make_modifier_tag_impl> { }; + + namespace __impl + { + + /* make_modifier_tags_impl */ + + template + struct make_modifier_tags_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for make_modifier_tags(...)!"); } + }; + + template + struct make_modifier_tags_impl< + mp::list, + mp::enable_if_c< + modifier::is_modifiers>::value>> + { + static constexpr decltype(auto) apply(T_modifiers&& modifiers) + { + return hana::transform( + modifiers, + make_modifier_tag); + } + }; + + } + + constexpr decltype(auto) make_modifier_tags = misc::make_generic_predicate<__impl::make_modifier_tags_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb diff --git a/include/cpphibernate/driver/mariadb/impl/where.h b/include/cpphibernate/driver/mariadb/impl/where.h new file mode 100644 index 0000000..324a4b5 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/impl/where.h @@ -0,0 +1,183 @@ +#pragma once + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* where_builder */ + + template + struct where_builder + { + private: + struct build_t + { + const schema_t& schema; + const T_modifiers& modifiers; + std::ostringstream os; + + inline build_t(const schema_t& p_schema, const T_modifiers& p_modifiers) + : schema (p_schema) + , modifiers (p_modifiers) + { } + + template + inline auto build_clause(T_clause&& clause) + -> mp::enable_if>> + { + os << "("; + build_clause(os, clause.clauses[hana::size_c<0>]); + os << ")"; + hana::for_each( + hana::remove_at(clause.clauses, hana::size_c<0>), + [&](auto& clause) { + os << " AND ("; + build_clause(os, clause); + os << ")"; + }); + } + + template + inline auto build_clause(T_clause&& clause) + -> mp::enable_if>> + { + os << "("; + build_clause(os, clause.clauses[hana::size_c<0>]); + os << ")"; + hana::for_each( + hana::remove_at(clause.clauses, hana::size_c<0>), + [&](auto& clause) { + os << " OR ("; + build_clause(os, clause); + os << ")"; + }); + } + + template + inline auto build_clause(T_clause&& clause) + -> mp::enable_if>> + { + os << "NOT ("; + build_clause(os, clause.clause); + os << ")"; + } + + template + inline auto build_clause(T_clause&& clause) + -> mp::enable_if>> + { + auto field_id = misc::get_type_id(hana::type_c>); + auto& field = schema.field(field_id); + os << "`" + << field.table_name + << "`.`" + << field.field_name + << "`=" + << field.convert_to_open + << "?\?" + << field.convert_to_close; + } + + inline void build(::cppmariadb::statement& statement) + { + size_t index = 0; + hana::for_each(modifiers, [&](auto& modifier){ + using modifier_type = mp::decay_t; + using is_where_type = modifier::is_where_modifier; + hana::eval_if( + is_where_type { }, + [&](auto _){ + if (index++ == 0) os << "WHERE ("; + else os << " AND ("; + build_clause(_(modifier).clause); + os << ")"; + }, + []{ }); + }); + os << ")"; + statement.assign(os.str()); + } + }; + + struct assign_t + { + ::cppmariadb::statement& statement; + const T_modifiers& modifiers; + size_t index { 0 }; + + inline assign_t(::cppmariadb::statement& p_statement, const T_modifiers& p_modifiers) + : statement(p_statement) + , modifiers(p_modifiers) + { } + + template + inline auto assign_clause(T_clause&& clause) + -> mp::enable_if_c< + modifier::is_where_clause_and>::value + || modifier::is_where_clause_or >::value> + { + hana::for_each([&](auto& clause) { + assign_clause(clause); + }); + } + + template + inline auto assign_clause(T_clause&& clause) + -> mp::enable_if>> + { + assign_clause(clause.clause); + } + + template + inline auto assign_clause(T_clause&& clause) + -> mp::enable_if>> + { + statement.set(index, clause.value); + ++index; + } + + inline void assign() + { + hana::for_each(modifiers, [&](auto& modifier){ + using modifier_type = mp::decay_t; + using is_where_type = modifier::is_where_modifier; + hana::eval_if( + is_where_type { }, + [&](auto _){ + assign_clause(_(modifier).clause); + }, + []{ }); + }); + } + }; + + private: + const schema_t* _schema { nullptr }; + ::cppmariadb::statement _statement; + + public: + inline ::cppmariadb::statement& assign(const schema_t& schema, const T_modifiers& modifiers) + { + if (_schema != &schema) + { + build_t(schema, modifiers).build(_statement); + _schema = &schema; + } + assign_t(_statement, modifiers).assign(); + return _statement; + } + }; + + template + inline decltype(auto) build_where(const schema_t& schema, const T_modifiers& modifiers) + { + static where_builder builder; + return builder.assign(schema, modifiers); + } + +} +end_namespace_cpphibernate_driver_mariadb diff --git a/include/cpphibernate/driver/mariadb/mariadb.h b/include/cpphibernate/driver/mariadb/mariadb.h index 49243d4..2e7fe06 100644 --- a/include/cpphibernate/driver/mariadb/mariadb.h +++ b/include/cpphibernate/driver/mariadb/mariadb.h @@ -40,6 +40,15 @@ beg_namespace_cpphibernate_driver_mariadb create_update_impl_t::apply( create_update_context(dataset, _schema, _connection, _filter, false)); } + + template + inline void read_impl(T_dataset& dataset, T_modifiers&& modifiers) const + { + auto& where = build_where(_schema, modifiers); + auto& limit = build_limit(modifiers); + std::cout << "WHERE = " << where.query(_connection) << std::endl; + std::cout << "LIMIT = " << limit.query(_connection) << std::endl; + } }; } diff --git a/include/cpphibernate/driver/mariadb/schema/field.h b/include/cpphibernate/driver/mariadb/schema/field.h index e7947ee..87869b7 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.h +++ b/include/cpphibernate/driver/mariadb/schema/field.h @@ -17,104 +17,128 @@ beg_namespace_cpphibernate_driver_mariadb struct field_t { - size_t table_dataset_id { 0 }; - size_t value_dataset_id { 0 }; - bool value_is_nullable { false }; - bool value_is_container { false }; - std::string schema_name; - std::string table_name; - std::string field_name; - attributes_t attributes; - - const table_t* table { nullptr }; - const table_t* referenced_table { nullptr }; + size_t id { 0 }; // unique id of the field + size_t dataset_id { 0 }; // unique id of the dataset type + size_t real_dataset_id { 0 }; // unique id of the real/unwrapped dataset type + size_t value_id { 0 }; // unique id of the value type + size_t real_value_id { 0 }; // unique id of the real/unwrapped value type + + bool value_is_nullable { false }; // value is stored in a nullable container + bool value_is_container { false }; // value is stored in a container + bool value_is_ordered { false }; // value is stored in a ordered container (vector, list, ...) + bool value_is_auto_incremented { false }; // value is a auto incremented field + + const table_t* table { nullptr }; // table this field belongs to + const table_t* referenced_table { nullptr }; // table that belongs to the value (if exists) + + std::string schema_name; // name of the SQL schema + std::string table_name; // name of the SQL table + std::string field_name; // name of the SQL field + std::string type; // SQL type name + std::string create_arguments; // additional arguments for CREATE TABLE command + + std::string convert_to_open; // SQL code to open the "convert to" operation + std::string convert_to_close; // SQL code to close the "convert to" operation + std::string convert_from_open; // SQL code to open the "convert from" operation + std::string convert_from_close; // SQL code to close the "convert from" operation + + attributes_t attributes; // attributes for the field inline field_t() = default; inline field_t(const field_t&) = delete; inline field_t(field_t&& other) - : table_dataset_id (std::move(other).table_dataset_id) - , value_dataset_id (std::move(other).value_dataset_id) - , value_is_nullable (std::move(other).value_is_nullable) - , value_is_container(std::move(other).value_is_container) - , schema_name (std::move(other).schema_name) - , table_name (std::move(other).table_name) - , field_name (std::move(other).field_name) - , attributes (std::move(other).attributes) - , table (nullptr) - , referenced_table (nullptr) + : id (std::move(other).id) + , dataset_id (std::move(other).dataset_id) + , real_dataset_id (std::move(other).real_dataset_id) + , value_id (std::move(other).value_id) + , real_value_id (std::move(other).real_value_id) + , value_is_nullable (std::move(other).value_is_nullable) + , value_is_container (std::move(other).value_is_container) + , value_is_auto_incremented (std::move(other).value_is_auto_incremented) + , table (nullptr) + , referenced_table (nullptr) + , schema_name (std::move(other).schema_name) + , table_name (std::move(other).table_name) + , field_name (std::move(other).field_name) + , type (std::move(other).type) + , create_arguments (std::move(other).create_arguments) + , convert_to_open (std::move(other).convert_to_open) + , convert_to_close (std::move(other).convert_to_close) + , convert_from_open (std::move(other).convert_from_open) + , convert_from_close (std::move(other).convert_from_close) + , attributes (std::move(other).attributes) { } virtual ~field_t() { }; - void print(std::ostream& os) const; + void print (std::ostream& os) const; + virtual void update (); /* CRUD */ - virtual value_t foreign_create_update(const create_update_context& context) const; + virtual value_t foreign_create_update (const create_update_context& context) const; /* properties */ - virtual std::string type () const; - 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 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 data_context& context) const; virtual void set (const data_context& context, const value_t&) const; + virtual bool is_default (const data_context& context) const; + virtual std::string generate_value (::cppmariadb::connection& connection) const; }; /* simple_field_t */ - template + template struct simple_field_t : public field_t { - using schema_type = T_schema; - using field_type = T_field; - 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; - - const schema_type& schema; - const field_type& field; - - inline simple_field_t(const schema_type& p_schema, const field_type& p_field) + using base_type = field_t; + using field_type = T_field; + using getter_type = typename mp::decay_t::getter_type; + using dataset_type = typename getter_type::dataset_type; + using real_dataset_type = misc::real_dataset_t; + using value_type = typename getter_type::value_type; + using real_value_type = misc::real_dataset_t; + using type_props = type_properties; + + const field_type& field; + + inline simple_field_t(const field_type& p_field) : field_t () - , schema (p_schema) , field (p_field) { } + + virtual void update() override; }; /* value_field_t */ - template + template struct value_field_t - : public simple_field_t + : public simple_field_t { - using base_type = simple_field_t; - using schema_type = T_schema; - using field_type = T_field; - 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 type_props = type_properties; + using base_type = simple_field_t; + using field_type = typename base_type::field_type; + using getter_type = typename base_type::getter_type; + using dataset_type = typename base_type::dataset_type; + using real_dataset_type = typename base_type::dataset_type; + using value_type = typename base_type::value_type; + using real_value_type = typename base_type::real_value_type; + using type_props = typename base_type::type_props; using base_type::base_type; - virtual std::string type() const override; - virtual value_t get (const data_context& context) const override; - virtual void set (const data_context& context, const value_t&) const override; + static_assert(mp::is_same::value, "internal error: dataset type mismatch!"); + + virtual void update () override; + virtual value_t get (const data_context& context) const override; + virtual void set (const data_context& context, const value_t&) const override; }; /* primary_key_field_t */ - template + template struct primary_key_field_t - : public value_field_t + : public value_field_t { - using base_type = value_field_t; - using schema_type = typename base_type::schema_type; + using base_type = value_field_t; using field_type = typename base_type::field_type; using dataset_type = typename base_type::dataset_type; using value_type = typename base_type::value_type; @@ -122,35 +146,29 @@ beg_namespace_cpphibernate_driver_mariadb using base_type::base_type; - 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 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; - virtual std::string convert_from_close () const override; + virtual bool is_default (const data_context& context) const override; + virtual std::string generate_value(::cppmariadb::connection& connection) const override; }; /* data_field_t */ - template + template struct data_field_t - : public value_field_t + : public value_field_t { - using base_type = value_field_t; + using base_type = value_field_t; using base_type::base_type; }; /* foreign_table_field_t */ - template + template struct foreign_table_field_t - : public simple_field_t + : public simple_field_t { public: - using base_type = simple_field_t; + using base_type = simple_field_t; using dataset_type = typename base_type::dataset_type; using base_type::base_type; diff --git a/include/cpphibernate/driver/mariadb/schema/field.inl b/include/cpphibernate/driver/mariadb/schema/field.inl index 2820537..1901a72 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.inl +++ b/include/cpphibernate/driver/mariadb/schema/field.inl @@ -6,21 +6,46 @@ beg_namespace_cpphibernate_driver_mariadb { + /* simple_field_t */ + + template + void simple_field_t + ::update() + { + base_type::update(); + + id = misc::get_type_id(hana::type_c); + dataset_id = misc::get_type_id(hana::type_c); + real_dataset_id = misc::get_type_id(hana::type_c); + value_id = misc::get_type_id(hana::type_c); + real_value_id = misc::get_type_id(hana::type_c); + + value_is_nullable = misc::is_nullable::value; + value_is_container = misc::is_container::value; + value_is_ordered = misc::is_ordered::value; + } + /* value_field_t */ - template - std::string value_field_t::type() const - { return type_props::type(); } + template + void value_field_t + ::update() + { + base_type::update(); + this->type = type_props::type(); + } - template - value_t value_field_t::get(const data_context& context) const + template + 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 data_context& context, const value_t& value) const + template + 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)); @@ -28,12 +53,16 @@ beg_namespace_cpphibernate_driver_mariadb /* primary_key_field_t */ - template - std::string primary_key_field_t::create_table_arguments() const - { return key_props::create_table_argument; } + template + 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 + template + std::string primary_key_field_t ::generate_value(::cppmariadb::connection& connection) const { auto ret = connection.execute_used(key_props::create_key_query); @@ -42,37 +71,10 @@ beg_namespace_cpphibernate_driver_mariadb return ret->current()->at(0).template get(); } - template - bool primary_key_field_t::is_auto_generated() const - { return key_props::auto_generated::value; } - - template - 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 - { return key_props::convert_to_open; } - - template - std::string primary_key_field_t::convert_to_close() const - { return key_props::convert_to_close; } - - template - std::string primary_key_field_t::convert_from_open() const - { return key_props::convert_from_open; } - - template - std::string primary_key_field_t::convert_from_close() const - { return key_props::convert_from_close; } - /* foreign_table_field_t */ - template - value_t foreign_table_field_t + template + value_t foreign_table_field_t ::foreign_create_update(const create_update_context& context) const { auto& dataset = context.get(); @@ -114,15 +116,15 @@ beg_namespace_cpphibernate_driver_mariadb template struct field_type - { using type = data_field_t; }; + { using type = data_field_t; }; template struct field_type>> - { using type = primary_key_field_t; }; + { using type = primary_key_field_t; }; template struct field_type>> - { using type = foreign_table_field_t; }; + { using type = foreign_table_field_t; }; template using field_type_t = typename field_type::type; @@ -149,17 +151,9 @@ beg_namespace_cpphibernate_driver_mariadb { 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; + using primary_key_type = primary_key_field_t; + return_type ret(field); ret.schema_name = schema.name; ret.table_name = table.name; ret.field_name = field.name; diff --git a/include/cpphibernate/driver/mariadb/schema/schema.h b/include/cpphibernate/driver/mariadb/schema/schema.h index ad8abd1..2b3498b 100644 --- a/include/cpphibernate/driver/mariadb/schema/schema.h +++ b/include/cpphibernate/driver/mariadb/schema/schema.h @@ -27,6 +27,7 @@ beg_namespace_cpphibernate_driver_mariadb void print (std::ostream& os) const; const table_t& table(size_t dataset_id) const; + const field_t& field(size_t field_id) const; /* CRUD */ void init(const init_context& context) const; diff --git a/include/cpphibernate/driver/mariadb/schema/table.inl b/include/cpphibernate/driver/mariadb/schema/table.inl index bfb4b4b..812bb64 100644 --- a/include/cpphibernate/driver/mariadb/schema/table.inl +++ b/include/cpphibernate/driver/mariadb/schema/table.inl @@ -150,8 +150,11 @@ beg_namespace_cpphibernate_driver_mariadb std::declval().wrapped_dataset))>; using wrapped_dataset_type = typename mp::decay_t::wrapped_dataset_type; using dataset_type = misc::unwrap_t; + using real_dataset_type = misc::real_dataset_t; using table_type = table_type_t; + static_assert(mp::is_same::value, "table cn only be created for simple dataset types (not for containers)!"); + table_type ret(schema, table); ret.dataset_id = misc::get_type_id(table.wrapped_dataset); ret.base_dataset_id = misc::get_type_id(wrapped_base_type { }); diff --git a/include/cpphibernate/misc/container_helper.h b/include/cpphibernate/misc/container_helper.h new file mode 100644 index 0000000..7f64153 --- /dev/null +++ b/include/cpphibernate/misc/container_helper.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include + +beg_namespace_cpphibernate_misc +{ + + /* container_helper */ + + template + struct container_helper + { + using container_type = T_container; + using value_type = real_dataset_t; + }; + +} +end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/misc/meta.h b/include/cpphibernate/misc/meta.h index 2821f37..df78aff 100644 --- a/include/cpphibernate/misc/meta.h +++ b/include/cpphibernate/misc/meta.h @@ -22,13 +22,13 @@ beg_namespace_cpphibernate_misc : public mp::c_false_t { }; - template - struct is_container_impl> + template + struct is_container_impl> : public mp::c_true_t { }; - template - struct is_container_impl> + template + struct is_container_impl> : public mp::c_true_t { }; @@ -71,6 +71,23 @@ beg_namespace_cpphibernate_misc : public mp::c_true_t { }; + /* is_ordered_impl */ + + template + struct is_ordered_impl + : public mp::c_false_t + { }; + + template + struct is_ordered_impl> + : public mp::c_true_t + { }; + + template + struct is_ordered_impl> + : public mp::c_true_t + { }; + /* real_dataset_impl */ template @@ -81,22 +98,21 @@ beg_namespace_cpphibernate_misc struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; - template - struct real_dataset_impl, void> + template + struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; template struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; - template - struct real_dataset_impl, void> + template + struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; - template - struct real_dataset_impl, void> + template + struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; - } /* meta */ @@ -111,6 +127,11 @@ beg_namespace_cpphibernate_misc : public __impl::is_nullable_impl { }; + template + struct is_ordered + : public __impl::is_ordered_impl + { }; + template struct is_pointer : public __impl::is_pointer_impl diff --git a/include/cpphibernate/modifier.h b/include/cpphibernate/modifier.h index 32b12a1..474cf89 100644 --- a/include/cpphibernate/modifier.h +++ b/include/cpphibernate/modifier.h @@ -2,5 +2,6 @@ #include #include +#include #include #include \ No newline at end of file diff --git a/include/cpphibernate/modifier/modifier.h b/include/cpphibernate/modifier/modifier.h index 766b202..5e24e90 100644 --- a/include/cpphibernate/modifier/modifier.h +++ b/include/cpphibernate/modifier/modifier.h @@ -23,7 +23,7 @@ beg_namespace_cpphibernate_modifier { }; template - struct all_are_modifier + struct all_are_modifiers : public mp::all_true::value...> { }; diff --git a/include/cpphibernate/modifier/modifiers.h b/include/cpphibernate/modifier/modifiers.h new file mode 100644 index 0000000..f1b5782 --- /dev/null +++ b/include/cpphibernate/modifier/modifiers.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_modifier +{ + + namespace __impl + { + + /* is_modifiers_impl */ + + template + struct is_modifiers_impl + : mp::c_false_t + { }; + + template + struct is_modifiers_impl, mp::enable_if>> + : mp::c_true_t + { }; + + } + + /* meta */ + + template + struct is_modifiers + : public __impl::is_modifiers_impl + { }; + + /* operations */ + + namespace __impl + { + + /* make_modifiers_impl */ + + template + struct make_modifiers_impl + { + template + static constexpr decltype(auto) apply(T_args&&...) + { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::modifier::make(...)!"); } + }; + + template + struct make_modifiers_impl< + mp::list, + mp::enable_if_c< + all_are_modifiers...>::value>> + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { return hana::make_basic_tuple(std::forward(args)...); } + }; + + } + + constexpr decltype(auto) make_list = misc::make_generic_predicate<__impl::make_modifiers_impl> { }; + +} +end_namespace_cpphibernate_modifier \ No newline at end of file diff --git a/include/cpphibernate/modifier/where/clauses.h b/include/cpphibernate/modifier/where/clauses.h index db63fbb..f716bce 100644 --- a/include/cpphibernate/modifier/where/clauses.h +++ b/include/cpphibernate/modifier/where/clauses.h @@ -3,4 +3,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/src/driver/mariadb/schema/field.cpp b/src/driver/mariadb/schema/field.cpp index cea41c3..771cef2 100644 --- a/src/driver/mariadb/schema/field.cpp +++ b/src/driver/mariadb/schema/field.cpp @@ -17,111 +17,143 @@ void field_t::print(std::ostream& os) const { os << indent << '{' << incindent - << indent << "\"table_dataset_id\": " << table_dataset_id << "," - << indent << "\"value_dataset_id\": " << value_dataset_id << "," - << indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << "," - << indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << "," - << indent << "\"schema_name\": \"" << schema_name << "\"," - << indent << "\"table_name\": \"" << table_name << "\"," - << indent << "\"field_name\": \"" << field_name << "\"," - << indent << "\"attributes\": " << misc::print_container(attributes, false) << "," - << indent << "\"table\": " << (table ? std::string("\"") + table->table_name + "\"" : "null") << "," - << indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null") - << decindent - << indent << '}'; -} - -#define throw_not_implemented(p_ret, p_name, ...) \ - p_ret field_t::p_name(__VA_ARGS__) const \ - { \ - throw misc::hibernate_exception( \ - std::string("'") + table_name + "." + field_name + \ - "' does not implement the " #p_name "() method!"); \ - } -/* CRUD */ + << indent << "\"id\": " << id << "," + << indent << "\"dataset_id\": " << dataset_id << "," + << indent << "\"real_dataset_id\": " << real_dataset_id << "," + << indent << "\"value_id\": " << value_id << "," + << indent << "\"real_value_id\": " << real_value_id << "," + << indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << "," + << indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << "," + << indent << "\"value_is_auto_incremented\": " << (value_is_auto_incremented ? "true" : "false") << "," + << indent << "\"table\": " << (table ? std::string("\"") + table->table_name + "\"" : "null") << "," + << indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null") << "," -throw_not_implemented(value_t, foreign_create_update, const create_update_context&) + << indent << "\"schema_name\": \"" << schema_name << "\"," + << indent << "\"table_name\": \"" << table_name << "\"," + << indent << "\"field_name\": \"" << field_name << "\"," + << indent << "\"type\": \"" << type << "\"," + << indent << "\"create_arguments\": \"" << create_arguments << "\"," -/* properties */ + << indent << "\"convert_to_open\": \"" << convert_to_open << "\"," + << indent << "\"convert_to_close\": \"" << convert_to_close << "\"," + << indent << "\"convert_from_open\": \"" << convert_from_open << "\"," + << indent << "\"convert_from_close\": \"" << convert_from_close << "\"," -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, const data_context& context) -throw_not_implemented(void, set, const data_context& context, const value_t&) + << indent << "\"attributes\": " << misc::print_container(attributes, false) -bool field_t::is_auto_generated() const - { return false; } + << decindent + << indent << '}'; +} -std::string field_t::convert_to_open() const +void field_t::update() { - std::ostringstream ss; - for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it) + id = 0; + dataset_id = 0; + real_dataset_id = 0; + value_id = 0; + real_value_id = 0; + value_is_nullable = false; + value_is_container = false; + value_is_auto_incremented = false; + table = nullptr; + referenced_table = nullptr; + + type.clear(); + create_arguments.clear(); + + /* conver_to_open */ { - switch(*it) + std::ostringstream ss; + for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it) { - case attribute_t::hex: ss << "HEX("; break; - case attribute_t::compress: ss << "COMPRESS("; break; - case attribute_t::primary_key: break; + switch(*it) + { + case attribute_t::hex: + ss << "HEX("; + break; + case attribute_t::compress: + ss << "COMPRESS("; + break; + case attribute_t::primary_key: + ss << "UuidToBin("; + break; + } } + convert_to_open = ss.str(); } - return ss.str(); -} -std::string field_t::convert_to_close() const -{ - std::ostringstream ss; - for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it) + /* convert_to_close */ { - switch(*it) + std::ostringstream ss; + for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it) { - case attribute_t::hex: - case attribute_t::compress: - ss << ')'; - break; - case attribute_t::primary_key: - break; + switch(*it) + { + case attribute_t::hex: + case attribute_t::compress: + case attribute_t::primary_key: + ss << ')'; + break; + } } + convert_to_close = ss.str(); } - return ss.str(); -} -std::string field_t::convert_from_open() const -{ - std::ostringstream ss; - for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it) + /* convert_from_open */ { - switch(*it) + std::ostringstream ss; + for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it) { - case attribute_t::hex: - ss << "UNHEX("; - break; - case attribute_t::compress: - ss << "UNCOMPRESS("; - break; - case attribute_t::primary_key: - break; + switch(*it) + { + case attribute_t::hex: + ss << "UNHEX("; + break; + case attribute_t::compress: + ss << "UNCOMPRESS("; + break; + case attribute_t::primary_key: + ss << "BinToUuid("; + break; + } } + convert_from_open = ss.str(); } - return ss.str(); -} -std::string field_t::convert_from_close() const -{ - std::ostringstream ss; - for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it) + /* convert_from_close */ { - switch(*it) + std::ostringstream ss; + for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it) { - case attribute_t::hex: - case attribute_t::compress: - ss << ')'; - break; - case attribute_t::primary_key: - break; + switch(*it) + { + case attribute_t::hex: + case attribute_t::compress: + case attribute_t::primary_key: + ss << ')'; + break; + } } + convert_from_close = ss.str(); } - return ss.str(); -} \ No newline at end of file +} + +#define throw_not_implemented(p_ret, p_name, ...) \ + p_ret field_t::p_name(__VA_ARGS__) const \ + { \ + throw misc::hibernate_exception( \ + std::string("'") + table_name + "." + field_name + \ + "' does not implement the " #p_name "() method!"); \ + } + +/* CRUD */ + +throw_not_implemented(value_t, foreign_create_update, const create_update_context&) + +/* properties */ + +throw_not_implemented(bool, is_default, const data_context& context) +throw_not_implemented(string, generate_value, ::cppmariadb::connection&) +throw_not_implemented(value_t, get, const data_context& context) +throw_not_implemented(void, set, const data_context& context, const value_t&) \ No newline at end of file diff --git a/src/driver/mariadb/schema/schema.cpp b/src/driver/mariadb/schema/schema.cpp index 74358ed..a4a891b 100644 --- a/src/driver/mariadb/schema/schema.cpp +++ b/src/driver/mariadb/schema/schema.cpp @@ -13,7 +13,7 @@ using namespace ::cpphibernate::driver::mariadb_impl; void schema_t::update() { -// clear everything + // clear everything for (auto& kvp : tables) { assert(static_cast(kvp.second)); @@ -25,6 +25,13 @@ void schema_t::update() table.foreign_table_one_fields.clear(); table.foreign_table_many_fields.clear(); table.data_fields.clear(); + + for (auto& ptr : table.fields) + { + assert(ptr); + auto& field = *ptr; + field.update(); + } } // update references @@ -54,12 +61,12 @@ void schema_t::update() auto& field = *ptr; // table - if (table.dataset_id != field.table_dataset_id) + if (table.dataset_id != field.dataset_id) throw misc::hibernate_exception(std::string("dataset id of field '") + field.table_name + '.' + field.field_name + "' does not match!"); field.table = &table; // referenced table - it = tables.find(field.value_dataset_id); + it = tables.find(field.real_value_id); auto referenced_table = (it != tables.end() ? it->second.get() : nullptr); @@ -120,6 +127,23 @@ const table_t& schema_t::table(size_t dataset_id) const return *it->second; } +const field_t& schema_t::field(size_t field_id) const +{ + for (auto& kvp : tables) + { + assert(kvp.second); + auto& table = *kvp.second; + for (auto& ptr : table.fields) + { + assert(ptr); + auto& field = *ptr; + if (field.id == field_id) + return field; + } + } + throw misc::hibernate_exception(std::string("unable to find field with id ") + std::to_string(field_id)); +} + #define exec_query() \ do { \ cpphibernate_debug_log("execute init query: " << ss.str()); \ diff --git a/src/driver/mariadb/schema/table.cpp b/src/driver/mariadb/schema/table.cpp index 8a8ef0d..4135e8a 100644 --- a/src/driver/mariadb/schema/table.cpp +++ b/src/driver/mariadb/schema/table.cpp @@ -30,12 +30,12 @@ std::string build_init_stage1_query(const table_t& table) { assert(table.primary_key_field); auto& key_info = *table.primary_key_field; - auto args = key_info.create_table_arguments(); + auto args = key_info.create_arguments; os << indent << "`" << key_info.field_name << "` " - << key_info.type() + << key_info.type << " NOT NULL" << (args.empty() ? "" : " ") << args @@ -52,7 +52,7 @@ std::string build_init_stage1_query(const table_t& table) << "`" << key_info.field_name << "` " - << key_info.type() + << key_info.type << " NOT NULL,"; } @@ -70,7 +70,7 @@ std::string build_init_stage1_query(const table_t& table) << "_id_" << field_info.field_name << "` " - << ref_key_info.type() + << ref_key_info.type << (field_info.value_is_nullable ? " NULL DEFAULT NULL," : " NOT NULL,"); @@ -90,8 +90,17 @@ std::string build_init_stage1_query(const table_t& table) << "_id_" << field_info.field_name << "` " - << ref_key_info.type() + << ref_key_info.type << " NULL DEFAULT NULL,"; + if (field_info.value_is_ordered) + { + os << indent + << "`" + << field_info.table_name + << "_index_" + << field_info.field_name + << "` UNSIGNED INT NOT NULL,"; + } } /* data fields */ @@ -103,7 +112,7 @@ std::string build_init_stage1_query(const table_t& table) << "`" << field_info.field_name << "` " - << field_info.type() + << field_info.type << (field_info.value_is_nullable ? " NULL DEFAULT NULL," : " NOT NULL,"); @@ -353,18 +362,18 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt { assert(table.primary_key_field); auto& key_info = *table.primary_key_field; - if (!key_info.is_auto_generated()) + if (!key_info.value_is_auto_incremented) { if (index++) os << ", "; os << "`" << key_info.field_name << "`=" - << key_info.convert_to_open() + << key_info.convert_to_open << "?" << key_info.field_name << "?" - << key_info.convert_to_close(); + << key_info.convert_to_close; } } @@ -381,11 +390,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt os << "`" << key_info.field_name << "`=" - << key_info.convert_to_open() + << key_info.convert_to_open << "?" << key_info.field_name << "?" - << key_info.convert_to_close(); + << key_info.convert_to_close; } /* foreign table one fields */ @@ -405,13 +414,13 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt << "_id_" << field_info.field_name << "`=" - << key_info.convert_to_open() + << key_info.convert_to_open << "?" << key_info.table_name << "_id_" << field_info.field_name << "?" - << key_info.convert_to_close(); + << key_info.convert_to_close; } /* foreign fields */ @@ -431,13 +440,23 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt << "_id_" << field_info.field_name << "`=" - << key_info.convert_to_open() + << key_info.convert_to_open << "?" << field_info.table_name << "_id_" << field_info.field_name << "?" - << key_info.convert_to_close(); + << key_info.convert_to_close; + if (field_info.value_is_ordered) + { + if (index++) + os << ", "; + os << "`" + << field_info.table_name + << "_index_" + << field_info.field_name + << "`=?\?"; + } } /* data fields */ @@ -452,11 +471,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt os << "`" << field_info.field_name << "`=" - << field_info.convert_to_open() + << field_info.convert_to_open << "?" << field_info.field_name << "?" - << field_info.convert_to_close(); + << field_info.convert_to_close; } /* type field for derived tables */ @@ -476,11 +495,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt os << " WHERE `" << key_info.field_name << "`=" - << key_info.convert_to_open() + << key_info.convert_to_open << "?" << key_info.field_name << "?" - << key_info.convert_to_close(); + << key_info.convert_to_close; } return os.str(); @@ -503,7 +522,7 @@ std::string table_t::execute_create_update( /* primary key */ assert(primary_key_field); - if ( !primary_key_field->is_auto_generated() + if ( !primary_key_field->value_is_auto_incremented && !is_update) { primary_key = primary_key_field->generate_value(context.connection); @@ -550,15 +569,28 @@ std::string table_t::execute_create_update( if (is_update && ptr != context.owner_field) continue; - if ( context.owner_field - && ptr == context.owner_field) + auto& field_info = *ptr; + bool set_value = + context.owner_field + && ptr == context.owner_field; + + if (set_value) { assert(!context.owner_key.empty()); statement.set(index, context.owner_key); } else + { statement.set_null(index); + } ++index; + + if (field_info.value_is_ordered) + { + if (set_value) statement.set(index, context.index); + else statement.set(index, 0); + ++index; + } } /* data fields */ @@ -604,7 +636,7 @@ std::string table_t::execute_create_update( cpphibernate_debug_log("execute UPDATE query: " << statement.query(connection)); } - if ( primary_key_field->is_auto_generated() + if ( primary_key_field->value_is_auto_incremented && !is_update) { auto id = connection.execute_id(statement); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b995878..9205f24 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,6 +12,7 @@ Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX Project ( test_cpphibernate ) File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) +List ( FILTER SOURCE_FILES EXCLUDE REGEX "/_[A-Za-z0-9_-]*\.cpp$" ) Add_Executable ( test_cpphibernate EXCLUDE_FROM_ALL ${SOURCE_FILES} ) Target_Link_Libraries ( test_cpphibernate diff --git a/test/cpphibernate_create.cpp b/test/cpphibernate_create.cpp index a864dc9..a100dca 100644 --- a/test/cpphibernate_create.cpp +++ b/test/cpphibernate_create.cpp @@ -103,7 +103,9 @@ TEST(CppHibernateTests, create_test3) "SET " "`tbl_test3_id`=UuidToBin('X3d12737a-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin(null), " + "`tbl_derived3_index_test3_list`='X0X', " "`tbl_derived3_id_test3_vector`=UuidToBin(null), " + "`tbl_derived3_index_test3_vector`='X0X', " "`u32_data`='X5X', " "`i32_data`='X6X', " "`u64_data`='X7X', " @@ -325,7 +327,9 @@ TEST(CppHibernateTests, create_derived3) "SET " "`tbl_test3_id`=UuidToBin('X3d1289f0-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), " + "`tbl_derived3_index_test3_list`='X0X', " "`tbl_derived3_id_test3_vector`=UuidToBin(null), " + "`tbl_derived3_index_test3_vector`='X0X', " "`u32_data`='X100X', " "`i32_data`='X101X', " "`u64_data`='X102X', " @@ -340,7 +344,9 @@ TEST(CppHibernateTests, create_derived3) "SET " "`tbl_test3_id`=UuidToBin('X3d128b26-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), " + "`tbl_derived3_index_test3_list`='X1X', " "`tbl_derived3_id_test3_vector`=UuidToBin(null), " + "`tbl_derived3_index_test3_vector`='X0X', " "`u32_data`='X110X', " "`i32_data`='X111X', " "`u64_data`='X112X', " @@ -355,11 +361,13 @@ TEST(CppHibernateTests, create_derived3) "SET " "`tbl_test3_id`=UuidToBin('X3d128eb4-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin(null), " + "`tbl_derived3_index_test3_list`='X0X', " "`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), " - "`u32_data`='X120X', " - "`i32_data`='X121X', " - "`u64_data`='X122X', " - "`i64_data`='X123X'", + "`tbl_derived3_index_test3_vector`='X0X', " + "`u32_data`='X200X', " + "`i32_data`='X201X', " + "`u64_data`='X202X', " + "`i64_data`='X203X'", result_affected_rows(1)); expect_query(mock, "SELECT Uuid()", result_used({ @@ -370,11 +378,13 @@ TEST(CppHibernateTests, create_derived3) "SET " "`tbl_test3_id`=UuidToBin('X3d128ffe-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin(null), " + "`tbl_derived3_index_test3_list`='X0X', " "`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), " - "`u32_data`='X130X', " - "`i32_data`='X131X', " - "`u64_data`='X132X', " - "`i64_data`='X133X'", + "`tbl_derived3_index_test3_vector`='X1X', " + "`u32_data`='X210X', " + "`i32_data`='X211X', " + "`u64_data`='X212X', " + "`i64_data`='X213X'", result_affected_rows(1)); expect_query(mock, "SELECT Uuid()", result_used({ @@ -385,11 +395,13 @@ TEST(CppHibernateTests, create_derived3) "SET " "`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X'), " "`tbl_derived3_id_test3_list`=UuidToBin(null), " + "`tbl_derived3_index_test3_list`='X0X', " "`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), " - "`u32_data`='X140X', " - "`i32_data`='X141X', " - "`u64_data`='X142X', " - "`i64_data`='X143X'", + "`tbl_derived3_index_test3_vector`='X2X', " + "`u32_data`='X220X', " + "`i32_data`='X221X', " + "`u64_data`='X222X', " + "`i64_data`='X223X'", result_affected_rows(1)); expect_query(mock, "COMMIT"); @@ -418,20 +430,20 @@ TEST(CppHibernateTests, create_derived3) d3.test3_list.back().u64_data = 112; d3.test3_list.back().i64_data = 113; d3.test3_vector.emplace_back(); - d3.test3_vector.back().u32_data = 120; - d3.test3_vector.back().i32_data = 121; - d3.test3_vector.back().u64_data = 122; - d3.test3_vector.back().i64_data = 123; + d3.test3_vector.back().u32_data = 200; + d3.test3_vector.back().i32_data = 201; + d3.test3_vector.back().u64_data = 202; + d3.test3_vector.back().i64_data = 203; d3.test3_vector.emplace_back(); - d3.test3_vector.back().u32_data = 130; - d3.test3_vector.back().i32_data = 131; - d3.test3_vector.back().u64_data = 132; - d3.test3_vector.back().i64_data = 133; + d3.test3_vector.back().u32_data = 210; + d3.test3_vector.back().i32_data = 211; + d3.test3_vector.back().u64_data = 212; + d3.test3_vector.back().i64_data = 213; d3.test3_vector.emplace_back(); - d3.test3_vector.back().u32_data = 140; - d3.test3_vector.back().i32_data = 141; - d3.test3_vector.back().u64_data = 142; - d3.test3_vector.back().i64_data = 143; + d3.test3_vector.back().u32_data = 220; + d3.test3_vector.back().i32_data = 221; + d3.test3_vector.back().u64_data = 222; + d3.test3_vector.back().i64_data = 223; ::cppmariadb::connection connection(reinterpret_cast(0x1111)); auto context = make_context(test_schema, connection); diff --git a/test/cpphibernate_init.cpp b/test/cpphibernate_init.cpp index 866660d..48f0fce 100644 --- a/test/cpphibernate_init.cpp +++ b/test/cpphibernate_init.cpp @@ -79,7 +79,9 @@ TEST(CppHibernateTests, init) "(\n" " `tbl_test3_id` BINARY(16) NOT NULL,\n" " `tbl_derived3_id_test3_list` BINARY(16) NULL DEFAULT NULL,\n" + " `tbl_derived3_index_test3_list` UNSIGNED INT NOT NULL,\n" " `tbl_derived3_id_test3_vector` BINARY(16) NULL DEFAULT NULL,\n" + " `tbl_derived3_index_test3_vector` UNSIGNED INT NOT NULL,\n" " `u32_data` INT UNSIGNED NOT NULL,\n" " `i32_data` INT NOT NULL,\n" " `u64_data` BIGINT UNSIGNED NOT NULL,\n" diff --git a/test/cpphibernate_read.cpp b/test/cpphibernate_read.cpp new file mode 100644 index 0000000..5aa523e --- /dev/null +++ b/test/cpphibernate_read.cpp @@ -0,0 +1,34 @@ +#include + +#include "test_helper.h" +#include "test_schema.h" +#include "mariadb_mock.h" + +using namespace ::testing; +using namespace ::cpphibernate; + +TEST(CppHibernateTests, read_test1) +{ + StrictMock mock; + + // expect_query(mock, "START TRANSACTION"); + // expect_query(mock, "COMMIT"); + + EXPECT_CALL( + mock, + mysql_close( + reinterpret_cast(0x1111))); + + EXPECT_CALL( + mock, + mysql_real_escape_string(reinterpret_cast(0x1111), _, _, _)) + .Times(AnyNumber()) + .WillRepeatedly(WithArgs<1, 2, 3>(EscapeString())); + + test1 t1; + t1.id = uuid("1e133ad8-ad2e-11e8-98d0-529269fb1459"); + + ::cppmariadb::connection connection(reinterpret_cast(0x1111)); + auto context = make_context(test_schema, connection); + context.read(t1); +} \ No newline at end of file