| @@ -171,5 +171,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { throw misc::hibernate_exception("read_context::finish_intern is not implemented!"); } | { throw misc::hibernate_exception("read_context::finish_intern is not implemented!"); } | ||||
| }; | }; | ||||
| using read_context_ptr = std::unique_ptr<read_context>; | |||||
| } | } | ||||
| end_namespace_cpphibernate_driver_mariadb | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -74,7 +74,10 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual void update (); | virtual void update (); | ||||
| /* CRUD */ | /* CRUD */ | ||||
| virtual value_t foreign_create_update (const create_update_context& context) const; | |||||
| using read_context_ptr = std::unique_ptr<read_context>; | |||||
| virtual value_t foreign_create_update (const create_update_context& context) const; | |||||
| virtual read_context_ptr foreign_read (const read_context& context, const value_t& value) const; | |||||
| /* properties */ | /* properties */ | ||||
| virtual value_t get (const data_context& context) const; | virtual value_t get (const data_context& context) const; | ||||
| @@ -129,7 +132,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| virtual void update () override; | virtual void update () override; | ||||
| virtual value_t get (const data_context& context) const override; | virtual value_t get (const data_context& context) const override; | ||||
| virtual void set (const data_context& context, const value_t&) const override; | |||||
| virtual void set (const data_context& context, const value_t& value) const override; | |||||
| }; | }; | ||||
| /* primary_key_field_t */ | /* primary_key_field_t */ | ||||
| @@ -168,13 +171,16 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| : public simple_field_t<T_field> | : public simple_field_t<T_field> | ||||
| { | { | ||||
| public: | public: | ||||
| using base_type = simple_field_t<T_field>; | |||||
| using dataset_type = typename base_type::dataset_type; | |||||
| using base_type = simple_field_t<T_field>; | |||||
| using value_type = typename base_type::value_type; | |||||
| using real_value_type = typename base_type::real_value_type; | |||||
| using dataset_type = typename base_type::dataset_type; | |||||
| using base_type::base_type; | using base_type::base_type; | ||||
| public: | public: | ||||
| virtual value_t foreign_create_update(const create_update_context& context) const override; | |||||
| virtual value_t foreign_create_update(const create_update_context& context) const override; | |||||
| virtual read_context_ptr foreign_read (const read_context& context, const value_t& value) const override; | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -87,6 +87,42 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| false); | false); | ||||
| } | } | ||||
| template<typename T_field> | |||||
| read_context_ptr foreign_table_field_t<T_field> | |||||
| ::foreign_read(const read_context& context, const value_t& value) const | |||||
| { | |||||
| using is_nullable_type = misc::is_nullable<value_type>; | |||||
| return hana::eval_if( | |||||
| is_nullable_type { }, | |||||
| [&](auto _) { | |||||
| auto& dataset = _(context).template get<dataset_type>(); | |||||
| auto& member = this->field.getter(dataset); | |||||
| using nullable_helper_type = misc::nullable_helper<mp::decay_t<decltype(member)>>; | |||||
| if (value.has_value()) | |||||
| { | |||||
| auto& new_dataset = nullable_helper_type::set(member, real_value_type { }); | |||||
| auto new_context = change_context(context, new_dataset); | |||||
| return std::make_unique<read_context>(new_context); | |||||
| } | |||||
| else | |||||
| { | |||||
| nullable_helper_type::clear(member); | |||||
| return read_context_ptr { }; | |||||
| } | |||||
| }, | |||||
| [&](auto _) { | |||||
| if (!value.has_value()) | |||||
| { | |||||
| throw misc::hibernate_exception(std::string("excepted value for field ") + | |||||
| this->table_name + "." + this->field_name + " but received null!"); | |||||
| } | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto& member = this->field.getter(dataset); | |||||
| auto new_context = change_context(context, member); | |||||
| return std::make_unique<read_context>(new_context); | |||||
| }); | |||||
| } | |||||
| namespace __impl | namespace __impl | ||||
| { | { | ||||
| @@ -149,7 +149,8 @@ void field_t::update() | |||||
| /* CRUD */ | /* CRUD */ | ||||
| throw_not_implemented(value_t, foreign_create_update, const create_update_context&) | |||||
| throw_not_implemented(value_t, foreign_create_update, const create_update_context&) | |||||
| throw_not_implemented(read_context_ptr, foreign_read, const read_context&, const value_t&) | |||||
| /* properties */ | /* properties */ | ||||
| @@ -203,13 +203,17 @@ void schema_t::init(const init_context& context) const | |||||
| " CONTAINS SQL\n" | " CONTAINS SQL\n" | ||||
| " SQL SECURITY INVOKER\n" | " SQL SECURITY INVOKER\n" | ||||
| "RETURN\n" | "RETURN\n" | ||||
| " LCASE(CONCAT_WS('-',\n" | |||||
| " HEX(SUBSTR(_bin, 13, 4)),\n" // time low | |||||
| " HEX(SUBSTR(_bin, 11, 2)),\n" // time mid | |||||
| " HEX(SUBSTR(_bin, 9, 2)),\n" // time high and version | |||||
| " HEX(SUBSTR(_bin, 7, 2)),\n" // clock sequence | |||||
| " HEX(SUBSTR(_bin, 1, 6))\n" // node id | |||||
| " )\n" | |||||
| " IF(\n" | |||||
| " _bin IS NULL,\n" | |||||
| " NULL,\n" | |||||
| " LCASE(CONCAT_WS('-',\n" | |||||
| " HEX(SUBSTR(_bin, 13, 4)),\n" // time low | |||||
| " HEX(SUBSTR(_bin, 11, 2)),\n" // time mid | |||||
| " HEX(SUBSTR(_bin, 9, 2)),\n" // time high and version | |||||
| " HEX(SUBSTR(_bin, 7, 2)),\n" // clock sequence | |||||
| " HEX(SUBSTR(_bin, 1, 6))\n" // node id | |||||
| " )\n" | |||||
| " )\n" | |||||
| ")"; | ")"; | ||||
| exec_query(); | exec_query(); | ||||
| @@ -10,6 +10,7 @@ | |||||
| #include <cpphibernate/driver/mariadb/schema/filter.h> | #include <cpphibernate/driver/mariadb/schema/filter.h> | ||||
| using namespace ::utl; | using namespace ::utl; | ||||
| using namespace ::cpphibernate; | |||||
| using namespace ::cpphibernate::driver::mariadb_impl; | using namespace ::cpphibernate::driver::mariadb_impl; | ||||
| /* data_extractor_t */ | /* data_extractor_t */ | ||||
| @@ -20,6 +21,7 @@ struct data_extractor_t | |||||
| const read_context& _context; | const read_context& _context; | ||||
| const ::cppmariadb::row& _row; | const ::cppmariadb::row& _row; | ||||
| const filter_t& _filter; | |||||
| mutable size_t _index; | mutable size_t _index; | ||||
| data_extractor_t( | data_extractor_t( | ||||
| @@ -29,6 +31,8 @@ struct data_extractor_t | |||||
| : _table (p_table) | : _table (p_table) | ||||
| , _context (p_context) | , _context (p_context) | ||||
| , _row (p_row) | , _row (p_row) | ||||
| , _filter (p_context.filter) | |||||
| , _index (0) | |||||
| { } | { } | ||||
| inline value_t get_value() const | inline value_t get_value() const | ||||
| @@ -40,23 +44,26 @@ struct data_extractor_t | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| inline void read_field(const field_t& field) const | |||||
| inline void read_field(const field_t& field, const read_context* context) const | |||||
| { | { | ||||
| field.set(_context, get_value()); | |||||
| if (context) | |||||
| { | |||||
| field.set(*context, get_value()); | |||||
| } | |||||
| ++_index; | ++_index; | ||||
| } | } | ||||
| inline void read_table(const table_t& table) const | |||||
| inline void read_table(const table_t& table, const read_context* context) const | |||||
| { | { | ||||
| if (table.base_table) | if (table.base_table) | ||||
| read_table(*table.base_table); | |||||
| read_table(*table.base_table, context); | |||||
| if (_context.filter.is_excluded(table)) | if (_context.filter.is_excluded(table)) | ||||
| return; | return; | ||||
| /* primary key */ | /* primary key */ | ||||
| assert(table.primary_key_field); | assert(table.primary_key_field); | ||||
| read_field(*table.primary_key_field); | |||||
| read_field(*table.primary_key_field, context); | |||||
| /* data fields */ | /* data fields */ | ||||
| for (auto& ptr : table.data_fields) | for (auto& ptr : table.data_fields) | ||||
| @@ -64,7 +71,27 @@ struct data_extractor_t | |||||
| assert(ptr); | assert(ptr); | ||||
| auto& field = *ptr; | auto& field = *ptr; | ||||
| if (!_context.filter.is_excluded(field)) | if (!_context.filter.is_excluded(field)) | ||||
| read_field(field); | |||||
| read_field(field, context); | |||||
| } | |||||
| /* foreign table one */ | |||||
| for (auto& ptr : table.foreign_table_one_fields) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->referenced_table); | |||||
| auto& field = *ptr; | |||||
| auto& ref_table = *field.referenced_table; | |||||
| if ( _filter.is_excluded(field) | |||||
| || _filter.is_excluded(ref_table)) | |||||
| continue; | |||||
| read_context_ptr next_context; | |||||
| if (context) | |||||
| next_context = field.foreign_read(*context, get_value()); | |||||
| read_table(ref_table, next_context.get()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -72,7 +99,9 @@ struct data_extractor_t | |||||
| { | { | ||||
| _index = 0; | _index = 0; | ||||
| _context.emplace(); | _context.emplace(); | ||||
| read_table(_table); | |||||
| read_table(_table, &_context); | |||||
| if (_index != _row.size()) | |||||
| throw misc::hibernate_exception("result was not completely read!"); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -84,7 +113,8 @@ struct select_query_builder_t | |||||
| const filter_t& _filter; | const filter_t& _filter; | ||||
| bool _is_dynamic; | bool _is_dynamic; | ||||
| size_t index { 0 }; | |||||
| size_t alias_id { 0 }; | |||||
| size_t index { 0 }; | |||||
| std::ostringstream os; | std::ostringstream os; | ||||
| std::ostringstream join; | std::ostringstream join; | ||||
| @@ -97,36 +127,45 @@ struct select_query_builder_t | |||||
| , _is_dynamic(p_is_dynamic) | , _is_dynamic(p_is_dynamic) | ||||
| { } | { } | ||||
| inline void add_field(const field_t& field) | |||||
| inline std::string make_alias(const table_t& table) | |||||
| { return std::string("T") + std::to_string(alias_id++); } | |||||
| inline void add_field(const field_t& field, const std::string& alias) | |||||
| { | { | ||||
| if (index++) os << ", "; | if (index++) os << ", "; | ||||
| os << "`" | |||||
| << field.table_name | |||||
| os << field.convert_from_open | |||||
| << "`" | |||||
| << alias | |||||
| << "`.`" | << "`.`" | ||||
| << field.field_name | << field.field_name | ||||
| << "`"; | |||||
| << "`" | |||||
| << field.convert_from_close; | |||||
| } | } | ||||
| inline bool add_table(const table_t& table, const std::string& prefix) | |||||
| inline bool add_table(const table_t& table, const std::string& alias) | |||||
| { | { | ||||
| bool ret = false; | bool ret = false; | ||||
| if (table.base_table) | if (table.base_table) | ||||
| { | { | ||||
| auto tmp = add_table(*table.base_table, ""); | |||||
| auto& base_table = *table.base_table; | |||||
| auto base_alias = make_alias(base_table); | |||||
| auto tmp = add_table(base_table, base_alias); | |||||
| if (tmp) | if (tmp) | ||||
| { | { | ||||
| assert(table.base_table->primary_key_field); | |||||
| auto& base_key = *table.base_table->primary_key_field; | |||||
| assert(base_table.primary_key_field); | |||||
| auto& base_key = *base_table.primary_key_field; | |||||
| ret = true; | ret = true; | ||||
| join << " LEFT JOIN `" | join << " LEFT JOIN `" | ||||
| << table.table_name | |||||
| << base_table.table_name | |||||
| << "` AS `" | |||||
| << base_alias | |||||
| << "` ON `" | << "` ON `" | ||||
| << table.table_name | |||||
| << alias | |||||
| << "`.`" | << "`.`" | ||||
| << base_key.field_name | << base_key.field_name | ||||
| << "`=`" | << "`=`" | ||||
| << base_key.table_name | |||||
| << base_alias | |||||
| << "`.`" | << "`.`" | ||||
| << base_key.field_name | << base_key.field_name | ||||
| << "`"; | << "`"; | ||||
| @@ -152,7 +191,7 @@ struct select_query_builder_t | |||||
| /* primary key */ | /* primary key */ | ||||
| assert(table.primary_key_field); | assert(table.primary_key_field); | ||||
| add_field(*table.primary_key_field); | |||||
| add_field(*table.primary_key_field, alias); | |||||
| /* data fields */ | /* data fields */ | ||||
| for (auto& ptr : table.data_fields) | for (auto& ptr : table.data_fields) | ||||
| @@ -160,7 +199,41 @@ struct select_query_builder_t | |||||
| assert(ptr); | assert(ptr); | ||||
| auto& field = *ptr; | auto& field = *ptr; | ||||
| if (!_filter.is_excluded(field)) | if (!_filter.is_excluded(field)) | ||||
| add_field(field); | |||||
| add_field(field, alias); | |||||
| } | |||||
| /* foreign table one */ | |||||
| for (auto& ptr : table.foreign_table_one_fields) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->referenced_table); | |||||
| assert(ptr->referenced_table->primary_key_field); | |||||
| auto& field = *ptr; | |||||
| auto& ref_table = *field.referenced_table; | |||||
| auto& ref_key = *ref_table.primary_key_field; | |||||
| if ( _filter.is_excluded(field) | |||||
| || _filter.is_excluded(ref_table)) | |||||
| continue; | |||||
| auto new_alias = make_alias(ref_table); | |||||
| add_table(ref_table, new_alias); | |||||
| join << " LEFT JOIN `" | |||||
| << ref_table.table_name | |||||
| << "` AS `" | |||||
| << new_alias | |||||
| << "` ON `" | |||||
| << alias | |||||
| << "`.`" | |||||
| << ref_key.table_name | |||||
| << "_id_" | |||||
| << field.field_name | |||||
| << "`=`" | |||||
| << new_alias | |||||
| << "`.`" | |||||
| << ref_key.field_name | |||||
| << "`"; | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| @@ -169,9 +242,12 @@ struct select_query_builder_t | |||||
| inline std::string operator()() | inline std::string operator()() | ||||
| { | { | ||||
| os << "SELECT "; | os << "SELECT "; | ||||
| add_table(_table, ""); | |||||
| auto alias = make_alias(_table); | |||||
| add_table(_table, alias); | |||||
| os << " FROM `" | os << " FROM `" | ||||
| << _table.table_name | << _table.table_name | ||||
| << "` AS `" | |||||
| << alias | |||||
| << "`" | << "`" | ||||
| << join.str() | << join.str() | ||||
| << " ?where! ?order! ?limit!"; | << " ?where! ?order! ?limit!"; | ||||
| @@ -39,13 +39,17 @@ TEST(CppHibernateTests, init) | |||||
| " CONTAINS SQL\n" | " CONTAINS SQL\n" | ||||
| " SQL SECURITY INVOKER\n" | " SQL SECURITY INVOKER\n" | ||||
| "RETURN\n" | "RETURN\n" | ||||
| " LCASE(CONCAT_WS('-',\n" | |||||
| " HEX(SUBSTR(_bin, 13, 4)),\n" | |||||
| " HEX(SUBSTR(_bin, 11, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 9, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 7, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 1, 6))\n" | |||||
| " )\n" | |||||
| " IF(\n" | |||||
| " _bin IS NULL,\n" | |||||
| " NULL,\n" | |||||
| " LCASE(CONCAT_WS('-',\n" | |||||
| " HEX(SUBSTR(_bin, 13, 4)),\n" | |||||
| " HEX(SUBSTR(_bin, 11, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 9, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 7, 2)),\n" | |||||
| " HEX(SUBSTR(_bin, 1, 6))\n" | |||||
| " )\n" | |||||
| " )\n" | |||||
| ")"); | ")"); | ||||
| expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_test1`\n" | expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_test1`\n" | ||||
| @@ -15,14 +15,14 @@ TEST(CppHibernateTests, read_test1) | |||||
| expect_query(mock, "START TRANSACTION"); | expect_query(mock, "START TRANSACTION"); | ||||
| expect_query(mock, "SELECT " | expect_query(mock, "SELECT " | ||||
| "`tbl_test1`.`tbl_test1_id`, " | |||||
| "`tbl_test1`.`str_data`, " | |||||
| "`tbl_test1`.`str64_data`, " | |||||
| "`tbl_test1`.`u32_nullable`, " | |||||
| "`tbl_test1`.`u32_ptr_u`, " | |||||
| "`tbl_test1`.`u32_ptr_s` " | |||||
| "BinToUuid(`T0`.`tbl_test1_id`), " | |||||
| "`T0`.`str_data`, " | |||||
| "`T0`.`str64_data`, " | |||||
| "`T0`.`u32_nullable`, " | |||||
| "`T0`.`u32_ptr_u`, " | |||||
| "`T0`.`u32_ptr_s` " | |||||
| "FROM " | "FROM " | ||||
| "`tbl_test1` ", | |||||
| "`tbl_test1` AS `T0` ", | |||||
| result_used({ | result_used({ | ||||
| { "3d12697a-abb9-11e8-98d0-529269fb1459", "str_data of class `test1` object `t1`", "str64_data of class `test1` object `t1`", nullptr, "123", "456" } | { "3d12697a-abb9-11e8-98d0-529269fb1459", "str_data of class `test1` object `t1`", "str64_data of class `test1` object `t1`", nullptr, "123", "456" } | ||||
| })); | })); | ||||
| @@ -48,6 +48,7 @@ TEST(CppHibernateTests, read_test1) | |||||
| using namespace modifier; | using namespace modifier; | ||||
| context.read(t1); | context.read(t1); | ||||
| EXPECT_EQ (t1.id, uuid("3d12697a-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ (t1.str_data, "str_data of class `test1` object `t1`"); | EXPECT_EQ (t1.str_data, "str_data of class `test1` object `t1`"); | ||||
| EXPECT_EQ (t1.str64_data, "str64_data of class `test1` object `t1`"); | EXPECT_EQ (t1.str64_data, "str64_data of class `test1` object `t1`"); | ||||
| EXPECT_FALSE(static_cast<bool>(t1.u32_nullable)); | EXPECT_FALSE(static_cast<bool>(t1.u32_nullable)); | ||||
| @@ -63,13 +64,13 @@ TEST(CppHibernateTests, read_test2) | |||||
| expect_query(mock, "START TRANSACTION"); | expect_query(mock, "START TRANSACTION"); | ||||
| expect_query(mock, "SELECT " | expect_query(mock, "SELECT " | ||||
| "`tbl_test2`.`tbl_test2_id`, " | |||||
| "`tbl_test2`.`u8_data`, " | |||||
| "`tbl_test2`.`i8_data`, " | |||||
| "`tbl_test2`.`u16_data`, " | |||||
| "`tbl_test2`.`i16_data` " | |||||
| "BinToUuid(`T0`.`tbl_test2_id`), " | |||||
| "`T0`.`u8_data`, " | |||||
| "`T0`.`i8_data`, " | |||||
| "`T0`.`u16_data`, " | |||||
| "`T0`.`i16_data` " | |||||
| "FROM " | "FROM " | ||||
| "`tbl_test2` ", | |||||
| "`tbl_test2` AS `T0` ", | |||||
| result_used({ | result_used({ | ||||
| { "3d1270dc-abb9-11e8-98d0-529269fb1459", "1", "2", "3", "4" } | { "3d1270dc-abb9-11e8-98d0-529269fb1459", "1", "2", "3", "4" } | ||||
| })); | })); | ||||
| @@ -94,10 +95,11 @@ TEST(CppHibernateTests, read_test2) | |||||
| test2 t2; | test2 t2; | ||||
| context.read(t2, where(equal(test2_key_field, "3d1270dc-abb9-11e8-98d0-529269fb1459"))); | context.read(t2, where(equal(test2_key_field, "3d1270dc-abb9-11e8-98d0-529269fb1459"))); | ||||
| EXPECT_EQ(1, t2.u8_data); | |||||
| EXPECT_EQ(2, t2.i8_data); | |||||
| EXPECT_EQ(3, t2.u16_data); | |||||
| EXPECT_EQ(4, t2.i16_data); | |||||
| EXPECT_EQ(t2.id, uuid("3d1270dc-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ(t2.u8_data, 1); | |||||
| EXPECT_EQ(t2.i8_data, 2); | |||||
| EXPECT_EQ(t2.u16_data, 3); | |||||
| EXPECT_EQ(t2.i16_data, 4); | |||||
| } | } | ||||
| TEST(CppHibernateTests, read_test3) | TEST(CppHibernateTests, read_test3) | ||||
| @@ -106,13 +108,13 @@ TEST(CppHibernateTests, read_test3) | |||||
| expect_query(mock, "START TRANSACTION"); | expect_query(mock, "START TRANSACTION"); | ||||
| expect_query(mock, "SELECT " | expect_query(mock, "SELECT " | ||||
| "`tbl_test3`.`tbl_test3_id`, " | |||||
| "`tbl_test3`.`u32_data`, " | |||||
| "`tbl_test3`.`i32_data`, " | |||||
| "`tbl_test3`.`u64_data`, " | |||||
| "`tbl_test3`.`i64_data` " | |||||
| "BinToUuid(`T0`.`tbl_test3_id`), " | |||||
| "`T0`.`u32_data`, " | |||||
| "`T0`.`i32_data`, " | |||||
| "`T0`.`u64_data`, " | |||||
| "`T0`.`i64_data` " | |||||
| "FROM " | "FROM " | ||||
| "`tbl_test3` ", | |||||
| "`tbl_test3` AS `T0` ", | |||||
| result_used({ | result_used({ | ||||
| { "3d12737a-abb9-11e8-98d0-529269fb1459", "5", "6", "7", "8" } | { "3d12737a-abb9-11e8-98d0-529269fb1459", "5", "6", "7", "8" } | ||||
| })); | })); | ||||
| @@ -137,8 +139,142 @@ TEST(CppHibernateTests, read_test3) | |||||
| context.read(t3); | context.read(t3); | ||||
| EXPECT_EQ(5, t3.u32_data); | |||||
| EXPECT_EQ(6, t3.i32_data); | |||||
| EXPECT_EQ(7, t3.u64_data); | |||||
| EXPECT_EQ(8, t3.i64_data); | |||||
| EXPECT_EQ(t3.id, uuid("3d12737a-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ(t3.u32_data, 5); | |||||
| EXPECT_EQ(t3.i32_data, 6); | |||||
| EXPECT_EQ(t3.u64_data, 7); | |||||
| EXPECT_EQ(t3.i64_data, 8); | |||||
| } | |||||
| TEST(CppHibernateTests, read_derived1_static) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "SELECT " | |||||
| "BinToUuid(`T1`.`tbl_base_id`), " | |||||
| "`T1`.`name`, " | |||||
| "BinToUuid(`T0`.`tbl_derived1_id`), " | |||||
| "`T0`.`enum_data`, " | |||||
| "BinToUuid(`T2`.`tbl_test1_id`), " | |||||
| "`T2`.`str_data`, " | |||||
| "`T2`.`str64_data`, " | |||||
| "`T2`.`u32_nullable`, " | |||||
| "`T2`.`u32_ptr_u`, " | |||||
| "`T2`.`u32_ptr_s` " | |||||
| "FROM " | |||||
| "`tbl_derived1` AS `T0` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_base` AS `T1` ON `T0`.`tbl_base_id`=`T1`.`tbl_base_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test1` AS `T2` ON `T0`.`tbl_test1_id_test1_data`=`T2`.`tbl_test1_id` ", | |||||
| result_used({ | |||||
| { "3d12778a-abb9-11e8-98d0-529269fb1459", "derived1", "3d12758c-abb9-11e8-98d0-529269fb1459", "test2", "3d127988-abb9-11e8-98d0-529269fb1459", "str_data of class `test1` object `d1.test1_data`", "str64_data of class `test1` object `d1.test1_data`", "32", nullptr, "789" } | |||||
| })); | |||||
| expect_query(mock, "COMMIT"); | |||||
| EXPECT_CALL( | |||||
| mock, | |||||
| mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _)) | |||||
| .Times(AnyNumber()) | |||||
| .WillRepeatedly(WithArgs<1, 2, 3>(EscapeString())); | |||||
| EXPECT_CALL( | |||||
| mock, | |||||
| mysql_close( | |||||
| reinterpret_cast<MYSQL*>(0x1111))); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| derived1 d1; | |||||
| d1.derived1_id = uuid("3d12758c-abb9-11e8-98d0-529269fb1459"); | |||||
| context.read(d1); | |||||
| EXPECT_EQ (d1.id, uuid("3d12778a-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ (d1.derived1_id, uuid("3d12758c-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ (d1.name, "derived1"); | |||||
| EXPECT_EQ (d1.enum_data, test_enum::test2); | |||||
| EXPECT_EQ (d1.test1_data.str_data, "str_data of class `test1` object `d1.test1_data`"); | |||||
| EXPECT_EQ (d1.test1_data.str64_data, "str64_data of class `test1` object `d1.test1_data`"); | |||||
| ASSERT_TRUE (static_cast<bool>(d1.test1_data.u32_nullable)); | |||||
| EXPECT_EQ (*d1.test1_data.u32_nullable, 32); | |||||
| ASSERT_TRUE (static_cast<bool>(d1.test1_data.u32_ptr_s)); | |||||
| EXPECT_EQ (*d1.test1_data.u32_ptr_s, 789); | |||||
| EXPECT_FALSE(static_cast<bool>(d1.test1_data.u32_ptr_u)); | |||||
| } | |||||
| TEST(CppHibernateTests, read_derived2_static) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "SELECT " | |||||
| "BinToUuid(`T1`.`tbl_base_id`), " | |||||
| "`T1`.`name`, " | |||||
| "BinToUuid(`T0`.`tbl_derived2_id`), " | |||||
| "BinToUuid(`T2`.`tbl_test2_id`), " | |||||
| "`T2`.`u8_data`, " | |||||
| "`T2`.`i8_data`, " | |||||
| "`T2`.`u16_data`, " | |||||
| "`T2`.`i16_data`, " | |||||
| "BinToUuid(`T3`.`tbl_test2_id`), " | |||||
| "`T3`.`u8_data`, " | |||||
| "`T3`.`i8_data`, " | |||||
| "`T3`.`u16_data`, " | |||||
| "`T3`.`i16_data`, " | |||||
| "BinToUuid(`T4`.`tbl_test2_id`), " | |||||
| "`T4`.`u8_data`, " | |||||
| "`T4`.`i8_data`, " | |||||
| "`T4`.`u16_data`, " | |||||
| "`T4`.`i16_data` " | |||||
| "FROM " | |||||
| "`tbl_derived2` AS `T0` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_base` AS `T1` ON `T0`.`tbl_base_id`=`T1`.`tbl_base_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T2` ON `T0`.`tbl_test2_id_test2_nullable`=`T2`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T3` ON `T0`.`tbl_test2_id_test2_ptr_u`=`T3`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T4` ON `T0`.`tbl_test2_id_test2_ptr_s`=`T4`.`tbl_test2_id` ", | |||||
| result_used({ | |||||
| { "3d127db6-abb9-11e8-98d0-529269fb1459", "derived2", "3d127bcc-abb9-11e8-98d0-529269fb1459", "3d1283a6-abb9-11e8-98d0-529269fb1459", "10", "11", "12", "13", "3d128522-abb9-11e8-98d0-529269fb1459", "20", "21", "22", "23", nullptr, nullptr, nullptr, nullptr, nullptr } | |||||
| })); | |||||
| expect_query(mock, "COMMIT"); | |||||
| EXPECT_CALL( | |||||
| mock, | |||||
| mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _)) | |||||
| .Times(AnyNumber()) | |||||
| .WillRepeatedly(WithArgs<1, 2, 3>(EscapeString())); | |||||
| EXPECT_CALL( | |||||
| mock, | |||||
| mysql_close( | |||||
| reinterpret_cast<MYSQL*>(0x1111))); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| derived2 d2; | |||||
| d2.derived2_id = uuid("3d127bcc-abb9-11e8-98d0-529269fb1459"); | |||||
| context.read(d2); | |||||
| EXPECT_EQ (d2.id, uuid("3d127db6-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ (d2.derived2_id, uuid("3d127bcc-abb9-11e8-98d0-529269fb1459")); | |||||
| EXPECT_EQ (d2.name, "derived2"); | |||||
| ASSERT_TRUE (static_cast<bool>(d2.test2_nullable)); | |||||
| EXPECT_EQ (d2.test2_nullable->u8_data, 10); | |||||
| EXPECT_EQ (d2.test2_nullable->i8_data, 11); | |||||
| EXPECT_EQ (d2.test2_nullable->u16_data, 12); | |||||
| EXPECT_EQ (d2.test2_nullable->i16_data, 13); | |||||
| ASSERT_TRUE (static_cast<bool>(d2.test2_ptr_u)); | |||||
| EXPECT_EQ (d2.test2_ptr_u->u8_data, 20); | |||||
| EXPECT_EQ (d2.test2_ptr_u->i8_data, 21); | |||||
| EXPECT_EQ (d2.test2_ptr_u->u16_data, 22); | |||||
| EXPECT_EQ (d2.test2_ptr_u->i16_data, 23); | |||||
| EXPECT_FALSE(static_cast<bool>(d2.test2_ptr_s)); | |||||
| } | } | ||||