Browse Source

* implemented destroy method for mariadb driver

master
bergmann 5 years ago
parent
commit
981f6eea2e
12 changed files with 738 additions and 41 deletions
  1. +19
    -0
      include/cpphibernate/driver/mariadb/helper/context.h
  2. +1
    -0
      include/cpphibernate/driver/mariadb/impl.h
  3. +96
    -0
      include/cpphibernate/driver/mariadb/impl/destroy.h
  4. +15
    -0
      include/cpphibernate/driver/mariadb/mariadb.h
  5. +15
    -1
      include/cpphibernate/driver/mariadb/schema/table.h
  6. +30
    -0
      include/cpphibernate/driver/mariadb/schema/table.inl
  7. +14
    -10
      src/driver/mariadb/schema/field.cpp
  8. +262
    -12
      src/driver/mariadb/schema/table.cpp
  9. +250
    -0
      test/cpphibernate_destroy.cpp
  10. +7
    -7
      test/cpphibernate_init.cpp
  11. +27
    -9
      test/cpphibernate_update.cpp
  12. +2
    -2
      test/test_helper.h

+ 19
- 0
include/cpphibernate/driver/mariadb/helper/context.h View File

@@ -195,5 +195,24 @@ beg_namespace_cpphibernate_driver_mariadb

using read_context_ptr = std::unique_ptr<read_context>;

/* destroy_context */

struct destroy_context
: public data_context
{
std::string where;

template<typename T_data>
inline destroy_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: data_context(
p_data,
p_schema,
p_connection)
{ }
};

}
end_namespace_cpphibernate_driver_mariadb

+ 1
- 0
include/cpphibernate/driver/mariadb/impl.h View File

@@ -1,6 +1,7 @@
#pragma once

#include <cpphibernate/driver/mariadb/impl/create_update.h>
#include <cpphibernate/driver/mariadb/impl/destroy.h>
#include <cpphibernate/driver/mariadb/impl/limit.h>
#include <cpphibernate/driver/mariadb/impl/order_by.h>
#include <cpphibernate/driver/mariadb/impl/read.h>


+ 96
- 0
include/cpphibernate/driver/mariadb/impl/destroy.h View File

@@ -0,0 +1,96 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* destroy_impl_t */

template<typename T_dataset, typename = void>
struct destroy_impl_t
{
using dataset_type = T_dataset;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
auto& connection = context.connection;
auto& schema = context.schema;
auto& table = schema.table(dataset_id);

assert(table.primary_key_field);
transaction_lock trans(connection);
if (!table.primary_key_field->is_default(context))
{
table.destroy(context);
}
else if (strict)
{
throw misc::hibernate_exception("can not destroy dataset with no primary key assigned!");
}
trans.commit();
}
};

/* destroy_impl_t - nullable */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if<misc::is_nullable<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = misc::nullable_helper<dataset_type>;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& dataset = context.get<dataset_type>();
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, *value);
new_destroy_impl_type::apply(new_context, strict);
}
else if (strict)
{
throw misc::hibernate_exception("can not destroy nullable type with no value!");
}
}
};

/* destroy_impl_t - container */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if<misc::is_container<T_dataset>>>
{
using dataset_type = T_dataset;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& connection = context.connection;
auto& dataset = context.get<dataset_type>();

transaction_lock trans(connection);
for (auto& x : dataset)
{
using new_dataset_type = mp::decay_t<decltype(x)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, x);
new_destroy_impl_type::apply(new_context, strict);
}
trans.commit();
}
};

}
end_namespace_cpphibernate_driver_mariadb

+ 15
- 0
include/cpphibernate/driver/mariadb/mariadb.h View File

@@ -65,6 +65,21 @@ beg_namespace_cpphibernate_driver_mariadb
create_update_impl_t<T_dataset>::apply(
create_update_context(dataset, _schema, _connection, _filter, true));
}

template<typename T_dataset>
inline void destroy_impl(T_dataset& dataset) const
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;

auto dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
auto& table = _schema.table(dataset_id);

destroy_context context(dataset, _schema, _connection);
context.where = table.get_where_primary_key(context);

destroy_impl_t<T_dataset>::apply(context);
}
};

}

+ 15
- 1
include/cpphibernate/driver/mariadb/schema/table.h View File

@@ -67,7 +67,9 @@ beg_namespace_cpphibernate_driver_mariadb
const table_t* get_derived_by_table_id(size_t id) const;
const table_t* get_derived_by_dataset_id(size_t id) const;

virtual void emplace(const read_context& context) const;
virtual void emplace (const read_context& context) const;
std::string get_where_primary_key(const data_context& context) const;
std::string build_delete_query (const std::string* where) const;

/* CRUD */
inline void init_stage1(const init_context& context) const
@@ -82,6 +84,9 @@ beg_namespace_cpphibernate_driver_mariadb
inline void read(const read_context& context) const
{ return read_exec(context); }

inline void destroy(const destroy_context& context) const
{ return destroy_intern(context); }

private:
template<typename T_schema, typename T_table, typename T_base_dataset>
friend struct table_simple_t;
@@ -100,6 +105,7 @@ beg_namespace_cpphibernate_driver_mariadb
mutable statement_map _statement_select_dynamic;
mutable statement_map _statement_update;
mutable statement_ptr _statement_foreign_many_delete;
mutable statement_ptr _statement_delete;

::cppmariadb::statement& get_statement_create_table() const;
::cppmariadb::statement* get_statement_alter_table() const;
@@ -107,6 +113,9 @@ beg_namespace_cpphibernate_driver_mariadb
::cppmariadb::statement& get_statement_select(const read_context& context) const;
::cppmariadb::statement& get_statement_update(const filter_t& filter, const field_t* owner) const;
::cppmariadb::statement& get_statement_foreign_many_delete() const;
::cppmariadb::statement& get_statement_delete() const;

void execute_foreign_many_delete(const base_context& context) const;

std::string execute_create_update(
const create_update_context& context,
@@ -122,6 +131,10 @@ beg_namespace_cpphibernate_driver_mariadb
std::string create_update_exec (const create_update_context& context) const;

void read_exec (const read_context& context) const;

virtual void destroy_intern (const destroy_context& context) const;
void destroy_exec (const destroy_context& context) const;
void destroy_cleanup (const base_context& context, bool check_derived, bool check_base) const;
};

/* table_simple_t */
@@ -177,6 +190,7 @@ beg_namespace_cpphibernate_driver_mariadb

protected:
virtual std::string create_update_intern(const create_update_context& context) const override;
virtual void destroy_intern (const destroy_context& context) const override;

private:
virtual std::string create_update_base(const create_update_context& context) const override;


+ 30
- 0
include/cpphibernate/driver/mariadb/schema/table.inl View File

@@ -64,6 +64,36 @@ beg_namespace_cpphibernate_driver_mariadb
: this->create_update_exec(context);
}

template<typename T_schema, typename T_table, typename T_base_dataset>
void table_polymorphic_t<T_schema, T_table, T_base_dataset>
::destroy_intern(const destroy_context& context) const
{
bool done = false;
auto& dataset = context.get<dataset_type>();
for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){
if (!done)
{
using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>;
auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>);
auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id);
if (!derived_table)
{
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "unable to find derived table info for dataset '"
<< utl::type_helper<derived_dataset_type>::name() << "'!").str());
}
auto new_context = change_context(context, derived_dataset);
derived_table->destroy(new_context);
done = true;
}
});

if (!done)
{
this->destroy_exec(context);
}
}

template<typename T_schema, typename T_table, typename T_base_dataset>
std::string table_polymorphic_t<T_schema, T_table, T_base_dataset>
::create_update_base(const create_update_context& context) const


+ 14
- 10
src/driver/mariadb/schema/field.cpp View File

@@ -176,13 +176,12 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat
{
if (!known)
{
auto& ref_table = *referenced_table;
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *referenced_table->primary_key_field;
auto& ref_key_info = *ref_table.primary_key_field;

std::ostringstream os;
os << "DELETE FROM `"
<< ref_key_info.table_name
<< "` WHERE `"
os << "WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
@@ -205,7 +204,10 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat
<< "?\?"
<< ref_key_info.convert_to_close
<< ")";
known.reset(new ::cppmariadb::statement(os.str()));

auto where = os.str();
auto query = ref_table.build_delete_query(&where);
known.reset(new ::cppmariadb::statement(query));
}
return *known;
}
@@ -213,13 +215,12 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat
{
if (!unknown)
{
auto& ref_table = *referenced_table;
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *referenced_table->primary_key_field;
auto& ref_key_info = *ref_table.primary_key_field;

std::ostringstream os;
os << "DELETE FROM `"
<< ref_key_info.table_name
<< "` WHERE `"
os << "WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
@@ -234,7 +235,10 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat
<< "?\?"
<< key_info.convert_to_close
<< ")";
unknown.reset(new ::cppmariadb::statement(os.str()));

auto where = os.str();
auto query = ref_table.build_delete_query(&where);
unknown.reset(new ::cppmariadb::statement(query));
}
return *unknown;
}


+ 262
- 12
src/driver/mariadb/schema/table.cpp View File

@@ -443,6 +443,160 @@ struct select_query_builder_t
}
};

/* delete_query_builder_t */

struct delete_query_builder_t
{
const table_t& _table;

size_t alias_id { 0 };
std::ostringstream os;
std::list<std::string> names;

delete_query_builder_t(
const table_t& p_table)
: _table (p_table)
{ }

inline std::string make_alias()
{ return std::string("T") + std::to_string(alias_id++); }

inline void add_table(const table_t& table, const std::string& alias, bool add_base, bool add_derived)
{
auto has_alias = !alias.empty();
auto real_alias = has_alias ? alias : table.table_name;

if (table.base_table && add_base)
{
assert(table.base_table->primary_key_field);

auto& base_table = *table.base_table;
auto& base_key = *base_table.primary_key_field;
auto base_alias = has_alias ? make_alias() : std::string();
auto real_base_alias = has_alias ? base_alias : base_table.table_name;

os << " LEFT JOIN `"
<< base_table.table_name;
if (has_alias)
{
os << "` AS `"
<< base_alias;
}
os << "` ON `"
<< real_alias
<< "`.`"
<< base_key.field_name
<< "`=`"
<< real_base_alias
<< "`.`"
<< base_key.field_name
<< "`";

add_table(base_table, base_alias, true, false);
}

names.emplace_back(real_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;
auto new_alias = make_alias();

os << " LEFT JOIN `"
<< ref_table.table_name
<< "` AS `"
<< new_alias
<< "` ON `"
<< real_alias
<< "`.`"
<< ref_key.table_name
<< "_id_"
<< field.field_name
<< "`=`"
<< new_alias
<< "`.`"
<< ref_key.field_name
<< "`";

add_table(ref_table, new_alias, true, true);
}

/* derived tables */
if (add_derived)
{
for (auto& ptr : table.derived_tables)
{
assert(ptr);
assert(ptr->primary_key_field);

auto& derived_table = *ptr;
auto& primary_key = *table.primary_key_field;
auto derived_alias = has_alias ? make_alias() : std::string();
auto real_derived_alias = has_alias ? derived_alias : derived_table.table_name;

os << " LEFT JOIN `"
<< derived_table.table_name;
if (has_alias)
{
os << "` AS `"
<< derived_alias;
}
os << "` ON `"
<< real_alias
<< "`.`"
<< primary_key.field_name
<< "`=`"
<< real_derived_alias
<< "`.`"
<< primary_key.field_name
<< "`";

add_table(derived_table, derived_alias, false, true);
}
}
}

inline std::string operator()(const std::string* where)
{
os << " FROM `"
<< _table.table_name
<< "`";
add_table(_table, "", true, true);
if (where)
{
os << " " << *where;
}
else
{
os << " ?where!";
}

std::ostringstream ss;
ss << "DELETE ";
bool first = true;
for (auto& name : names)
{
if (first)
first = false;
else
ss << ", ";
ss << "`"
<< name
<< "`";
}
ss << os.str();

return ss.str();
}
};

/* build queries */

std::string build_init_stage1_query(const table_t& table)
@@ -686,7 +840,7 @@ std::string build_init_stage2_query(const table_t& table)
<< indent
<< "ON DELETE CASCADE"
<< indent
<< "ON UPDATE NO ACTION"
<< "ON UPDATE CASCADE"
<< decindent;
}

@@ -723,7 +877,7 @@ std::string build_init_stage2_query(const table_t& table)
<< ref_key_info.field_name
<< "`)"
<< indent
<< "ON DELETE CASCADE"
<< "ON DELETE SET NULL"
<< indent
<< "ON UPDATE NO ACTION"
<< decindent;
@@ -1143,9 +1297,7 @@ std::string table_t::execute_create_update(
/* delete non referenced elements */
if (context.is_update)
{
auto& delete_statement = ref_table.get_statement_foreign_many_delete();
cpphibernate_debug_log("execute DELETE old foreign many query: " << delete_statement.query(connection));
connection.execute(delete_statement);
ref_table.execute_foreign_many_delete(context);
}
}

@@ -1220,6 +1372,31 @@ const table_t* table_t::get_derived_by_dataset_id(size_t id) const
void table_t::emplace(const read_context& context) const
{ throw misc::hibernate_exception(std::string("'") + table_name + "' does not implement the emplace() method!"); }

std::string table_t::get_where_primary_key(const data_context& context) const
{
assert(primary_key_field);

auto& field = *primary_key_field;
auto primary_key = *field.get(context);

std::ostringstream os;
os << "WHERE `"
<< field.table_name
<< "`.`"
<< field.field_name
<< "`="
<< field.convert_to_open
<< "'"
<< context.connection.escape(primary_key)
<< "'"
<< field.convert_to_close;

return os.str();
}

std::string table_t::build_delete_query(const std::string* where) const
{ return delete_query_builder_t(*this)(where); }

::cppmariadb::statement& table_t::get_statement_create_table() const
{
if (_statement_create_table)
@@ -1282,10 +1459,8 @@ void table_t::emplace(const read_context& context) const
if (!_statement_foreign_many_delete)
{
std::ostringstream os;
os << "DELETE FROM `"
<< table_name
<< "` WHERE";
auto first = true;
os << "WHERE";
for (auto ptr : foreign_key_fields)
{
assert(ptr);
@@ -1300,11 +1475,32 @@ void table_t::emplace(const read_context& context) const
<< field.field_name
<< "` IS NULL)";
}
_statement_foreign_many_delete.reset(new ::cppmariadb::statement(os.str()));
std::string where = os.str();

auto query = delete_query_builder_t(*this)(&where);
_statement_foreign_many_delete.reset(new ::cppmariadb::statement(query));
}
return *_statement_foreign_many_delete;
}

::cppmariadb::statement& table_t::get_statement_delete() const
{
if (!_statement_delete)
{
auto query = delete_query_builder_t(*this)(nullptr);
_statement_delete.reset(new ::cppmariadb::statement(query));
}
return *_statement_delete;
}

void table_t::execute_foreign_many_delete(const base_context& context) const
{
auto& connection = context.connection;
auto& statement = get_statement_foreign_many_delete();
cpphibernate_debug_log("execute DELETE old foreign many query: " << statement.query(connection));
connection.execute(statement);
}

std::string table_t::create_update_base(const create_update_context& context) const
{
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
@@ -1328,6 +1524,9 @@ void table_t::init_stage2_exec(const init_context& context) const
connection.execute(*statement);
}

std::string table_t::create_update_intern(const create_update_context& context) const
{ return create_update_exec(context); }

std::string table_t::create_update_exec(const create_update_context& context) const
{
auto& statement = context.is_update
@@ -1336,9 +1535,6 @@ std::string table_t::create_update_exec(const create_update_context& context) co
return execute_create_update(context, statement);
}

std::string table_t::create_update_intern(const create_update_context& context) const
{ return create_update_exec(context); }

void table_t::read_exec(const read_context& context) const
{
auto& statement = get_statement_select(context);
@@ -1401,4 +1597,58 @@ void table_t::read_exec(const read_context& context) const

ref_table.read(next_context);
}
}

void table_t::destroy_intern(const destroy_context& context) const
{ return destroy_exec(context); }

void table_t::destroy_exec(const destroy_context& context) const
{
assert(primary_key_field);

auto& connection = context.connection;
auto& statement = get_statement_delete();

statement.set(0, context.where);
cpphibernate_debug_log("execute DELETE query: " << statement.query(connection));
connection.execute(statement);

destroy_cleanup(context, false, true);
}

void table_t::destroy_cleanup(const base_context& context, bool check_derived, bool check_base) const
{
for (auto ptr : foreign_table_many_fields)
{
assert(ptr);
assert(ptr->referenced_table);

auto& ref_table = *ptr->referenced_table;

ref_table.execute_foreign_many_delete(context);
}

for (auto ptr : foreign_table_fields)
{
assert(ptr);
assert(ptr->referenced_table);

auto& ref_table = *ptr->referenced_table;

ref_table.destroy_cleanup(context, true, true);
}

if (check_base && base_table)
{
base_table->destroy_cleanup(context, false, true);
}

if (check_derived)
{
for (auto ptr : derived_tables)
{
assert(ptr);
ptr->destroy_cleanup(context, true, false);
}
}
}

+ 250
- 0
test/cpphibernate_destroy.cpp View File

@@ -0,0 +1,250 @@
#include <cpphibernate/driver/mariadb.h>

#include "test_helper.h"
#include "test_schema.h"
#include "mariadb_mock.h"

using namespace ::testing;
using namespace ::cpphibernate;

TEST(CppHibernateTests, destroy_test1)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_test1` "
"FROM "
"`tbl_test1` "
"WHERE "
"`tbl_test1`.`tbl_test1_id`=UuidToBin('X3d12697a-abb9-11e8-98d0-529269fb1459X')");
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)));

test1 t1;
t1.id = uuid("3d12697a-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(t1);
}

TEST(CppHibernateTests, destroy_test2)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2`.`tbl_test2_id`=UuidToBin('X3d1270dc-abb9-11e8-98d0-529269fb1459X')");
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)));

test2 t2;
t2.id = uuid("3d1270dc-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(t2);
}

TEST(CppHibernateTests, destroy_test3)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_test3` "
"FROM "
"`tbl_test3` "
"WHERE "
"`tbl_test3`.`tbl_test3_id`=UuidToBin('X3d12737a-abb9-11e8-98d0-529269fb1459X')");
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)));

test3 t3;
t3.id = uuid("3d12737a-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(t3);
}

TEST(CppHibernateTests, destroy_derived1)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_base`, "
"`tbl_derived1`, "
"`T0` "
"FROM "
"`tbl_derived1` "
"LEFT JOIN "
"`tbl_base` ON `tbl_derived1`.`tbl_base_id`=`tbl_base`.`tbl_base_id` "
"LEFT JOIN "
"`tbl_test1` AS `T0` ON `tbl_derived1`.`tbl_test1_id_test1_data`=`T0`.`tbl_test1_id` "
"WHERE "
"`tbl_base`.`tbl_base_id`=UuidToBin('X3d12778a-abb9-11e8-98d0-529269fb1459X')");
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)));

derived1 d1;
d1.id = uuid("3d12778a-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(static_cast<base&>(d1));
}

TEST(CppHibernateTests, destroy_derived2)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_base`, "
"`tbl_derived2`, "
"`T0`, "
"`T1`, "
"`T2`, "
"`tbl_derived3` "
"FROM "
"`tbl_derived2` "
"LEFT JOIN "
"`tbl_base` ON `tbl_derived2`.`tbl_base_id`=`tbl_base`.`tbl_base_id` "
"LEFT JOIN "
"`tbl_test2` AS `T0` ON `tbl_derived2`.`tbl_test2_id_test2_nullable`=`T0`.`tbl_test2_id` "
"LEFT JOIN "
"`tbl_test2` AS `T1` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_u`=`T1`.`tbl_test2_id` "
"LEFT JOIN "
"`tbl_test2` AS `T2` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_s`=`T2`.`tbl_test2_id` "
"LEFT JOIN "
"`tbl_derived3` ON `tbl_derived2`.`tbl_derived2_id`=`tbl_derived3`.`tbl_derived2_id` "
"WHERE "
"`tbl_base`.`tbl_base_id`=UuidToBin('X3d127db6-abb9-11e8-98d0-529269fb1459X')");
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)));

derived2 d2;
d2.id = uuid("3d127db6-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(static_cast<base&>(d2));
}

TEST(CppHibernateTests, destroy_derived3)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "DELETE "
"`tbl_base`, "
"`tbl_derived2`, "
"`T0`, "
"`T1`, "
"`T2`, "
"`tbl_derived3` "
"FROM "
"`tbl_derived3` "
"LEFT JOIN "
"`tbl_derived2` ON `tbl_derived3`.`tbl_derived2_id`=`tbl_derived2`.`tbl_derived2_id` "
"LEFT JOIN "
"`tbl_base` ON `tbl_derived2`.`tbl_base_id`=`tbl_base`.`tbl_base_id` "
"LEFT JOIN "
"`tbl_test2` AS `T0` ON `tbl_derived2`.`tbl_test2_id_test2_nullable`=`T0`.`tbl_test2_id` "
"LEFT JOIN "
"`tbl_test2` AS `T1` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_u`=`T1`.`tbl_test2_id` "
"LEFT JOIN "
"`tbl_test2` AS `T2` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_s`=`T2`.`tbl_test2_id` "
"WHERE "
"`tbl_derived2`.`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')");
expect_query(mock, "DELETE "
"`tbl_test3` "
"FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "
"(`tbl_derived3_id_test3_vector` IS NULL)");
expect_query(mock, "DELETE "
"`tbl_test3` "
"FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "
"(`tbl_derived3_id_test3_vector` IS NULL)");
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)));

derived3 d3;
d3.derived2_id = uuid("3d1287a2-abb9-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(static_cast<derived2&>(d3));
}

+ 7
- 7
test/cpphibernate_init.cpp View File

@@ -168,11 +168,11 @@ TEST(CppHibernateTests, init)
" FOREIGN KEY (`tbl_base_id`)\n"
" REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION,\n"
" ON UPDATE CASCADE,\n"
" ADD CONSTRAINT `fk_tbl_derived1_to_tbl_test1_id_test1_data`\n"
" FOREIGN KEY (`tbl_test1_id_test1_data`)\n"
" REFERENCES `test`.`tbl_test1` (`tbl_test1_id`)\n"
" ON DELETE CASCADE\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION");

expect_query(mock, "ALTER TABLE `tbl_derived2`\n"
@@ -180,21 +180,21 @@ TEST(CppHibernateTests, init)
" FOREIGN KEY (`tbl_base_id`)\n"
" REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION,\n"
" ON UPDATE CASCADE,\n"
" ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_nullable`\n"
" FOREIGN KEY (`tbl_test2_id_test2_nullable`)\n"
" REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n"
" ON DELETE CASCADE\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION,\n"
" ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_u`\n"
" FOREIGN KEY (`tbl_test2_id_test2_ptr_u`)\n"
" REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n"
" ON DELETE CASCADE\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION,\n"
" ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_s`\n"
" FOREIGN KEY (`tbl_test2_id_test2_ptr_s`)\n"
" REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n"
" ON DELETE CASCADE\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION");

expect_query(mock, "ALTER TABLE `tbl_derived3`\n"
@@ -202,7 +202,7 @@ TEST(CppHibernateTests, init)
" FOREIGN KEY (`tbl_derived2_id`)\n"
" REFERENCES `test`.`tbl_derived2` (`tbl_derived2_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION");
" ON UPDATE CASCADE");

expect_query(mock, "COMMIT");



+ 27
- 9
test/cpphibernate_update.cpp View File

@@ -153,7 +153,9 @@ TEST(CppHibernateTests, update_derived1)
"`u32_ptr_u`=null, "
"`u32_ptr_s`='X789X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test1` "
"FROM "
"`tbl_test1` "
"WHERE "
"`tbl_test1_id` IN ("
@@ -224,7 +226,9 @@ TEST(CppHibernateTests, update_derived2)
"WHERE "
"`tbl_test2_id`=UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -249,7 +253,9 @@ TEST(CppHibernateTests, update_derived2)
"`u16_data`='X22X', "
"`i16_data`='X23X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -261,7 +267,9 @@ TEST(CppHibernateTests, update_derived2)
"`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X') AND "
"`tbl_test2_id_test2_ptr_u`!= UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -328,7 +336,9 @@ TEST(CppHibernateTests, update_derived3)
"WHERE "
"`tbl_base_id`=UuidToBin('X3d1288ce-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -339,7 +349,9 @@ TEST(CppHibernateTests, update_derived3)
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -350,7 +362,9 @@ TEST(CppHibernateTests, update_derived3)
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test2` "
"FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
@@ -414,7 +428,9 @@ TEST(CppHibernateTests, update_derived3)
"`u64_data`='X112X', "
"`i64_data`='X113X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test3` "
"FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "
@@ -467,7 +483,9 @@ TEST(CppHibernateTests, update_derived3)
"WHERE "
"`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
expect_query(mock, "DELETE "
"`tbl_test3` "
"FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "


+ 2
- 2
test/test_helper.h View File

@@ -64,8 +64,8 @@ struct result_data

inline MYSQL_RES* next_result()
{
static MYSQL_RES* value = reinterpret_cast<MYSQL_RES*>(0x1000);
return ++value;
static size_t value = 0x2000;
return reinterpret_cast<MYSQL_RES*>(value++);
}

inline const result_data::data_type& empty_result_data()


Loading…
Cancel
Save