Browse Source

* refactored create/update methods for mariadb driver

master
bergmann 5 years ago
parent
commit
54060455d0
13 changed files with 210 additions and 262 deletions
  1. +4
    -61
      include/cpphibernate/driver/mariadb/helper/context.h
  2. +2
    -0
      include/cpphibernate/driver/mariadb/helper/reference_stack.h
  3. +1
    -1
      include/cpphibernate/driver/mariadb/impl.h
  4. +0
    -95
      include/cpphibernate/driver/mariadb/impl/create.h
  5. +105
    -0
      include/cpphibernate/driver/mariadb/impl/create_update.h
  6. +8
    -6
      include/cpphibernate/driver/mariadb/mariadb.h
  7. +5
    -5
      include/cpphibernate/driver/mariadb/schema/field.h
  8. +10
    -23
      include/cpphibernate/driver/mariadb/schema/field.inl
  9. +20
    -15
      include/cpphibernate/driver/mariadb/schema/table.h
  10. +29
    -6
      include/cpphibernate/driver/mariadb/schema/table.inl
  11. +2
    -2
      src/driver/mariadb/schema/field.cpp
  12. +20
    -44
      src/driver/mariadb/schema/table.cpp
  13. +4
    -4
      test/cpphibernate_create.cpp

+ 4
- 61
include/cpphibernate/driver/mariadb/helper/context.h View File

@@ -19,74 +19,17 @@ beg_namespace_cpphibernate_driver_mariadb
bool recreate;
};

/* create context */
/* create_update_context */

struct create_context
struct create_update_context
{
bool is_update;
const schema_t& schema;
const filter_t& filter;
const table_t* derived_table;
const field_t* owner_field;
::cppmariadb::connection& connection;
};

template<typename T_dataset>
struct generic_create_context
: public create_context
{
using dataset_type = mp::decay_t<T_dataset>;

dataset_type& dataset;

template<typename T_new_dataset>
constexpr decltype(auto) change(T_new_dataset& new_dataset, const field_t* owner = nullptr) const
{
return generic_create_context<T_new_dataset>
{
{
schema,
nullptr,
owner,
connection
},
new_dataset
};
}
};

/* update context */

struct update_context
: public create_context
{
const filter_t& filter;
};

template<typename T_dataset>
struct generic_update_context
: public update_context
{
using dataset_type = mp::decay_t<T_dataset>;

dataset_type& dataset;

template<typename T_new_dataset>
constexpr decltype(auto) change(T_new_dataset& new_dataset, const field_t* owner = nullptr) const
{
return generic_update_context<T_new_dataset>
{
{
{
schema,
nullptr,
owner,
connection
},
filter,
},
new_dataset
};
}
};

}
end_namespace_cpphibernate_driver_mariadb

+ 2
- 0
include/cpphibernate/driver/mariadb/helper/reference_stack.h View File

@@ -15,6 +15,8 @@ beg_namespace_cpphibernate_driver_mariadb
virtual ~reference_lock() = default;
};

using reference_lock_ptr = std::unique_ptr<reference_lock>;

/* reference_stack */

template<typename T_dataset>


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

@@ -1,4 +1,4 @@
#pragma once

#include <cpphibernate/driver/mariadb/impl/init.h>
#include <cpphibernate/driver/mariadb/impl/create.h>
#include <cpphibernate/driver/mariadb/impl/create_update.h>

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

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

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* create_impl_t */

template<typename T_context, typename = void>
struct create_impl_t
{
using context_type = T_context;
using dataset_type = typename context_type::dataset_type;
using reference_stack_type = reference_stack<dataset_type>;

static inline value_t apply(const context_type& context, bool strict = true)
{
value_t ret;
auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
auto& connection = context.connection;
auto& schema = context.schema;
auto& table = schema.table(dataset_id);
auto& dataset = context.dataset;
auto ref_lock = reference_stack_type::push(dataset);

transaction_lock trans(connection);
ret = table.create(context);
trans.commit();
return ret;
}
};

/* create_impl_t - nullable */

template<typename T_context>
struct create_impl_t<
T_context,
mp::enable_if<misc::is_nullable<typename T_context::dataset_type>>>
{
using context_type = T_context;
using dataset_type = typename context_type::dataset_type;
using nullable_helper_type = misc::nullable_helper<dataset_type>;

static inline value_t apply(const context_type& context, bool strict = true)
{
value_t ret;
auto& dataset = context.dataset;
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_context_type = mp::decay_t<decltype(context.change(*value))>;
using new_create_impl_type = create_impl_t<new_context_type>;
ret = new_create_impl_type::apply(context.change(*value));
}
else if (strict)
{
throw misc::hibernate_exception("can not create nullable type with no value!");
}
return ret;
}
};

/* create_impl_t - container */

template<typename T_context>
struct create_impl_t<
T_context,
mp::enable_if<misc::is_container<typename T_context::dataset_type>>>
{
using context_type = T_context;

static inline value_t apply(const context_type& context, bool strict = true)
{
value_t ret;
auto& connection = context.connection;
auto& dataset = context.dataset;

transaction_lock trans(connection);
for (auto& x : dataset)
{
using new_context_type = mp::decay_t<decltype(context.change(x))>;
using new_create_impl_type = create_impl_t<new_context_type>;
new_create_impl_type::apply(context.change(x, context.owner_field));
}
trans.commit();
return ret;
}
};

}
end_namespace_cpphibernate_driver_mariadb

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

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

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* create_update_impl_t */

template<typename T_dataset, typename = void>
struct create_update_impl_t
{
using dataset_type = T_dataset;
using reference_stack_type = reference_stack<dataset_type>;

static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true)
{
value_t ret;

auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
auto& connection = context.connection;
auto& schema = context.schema;
auto& table = schema.table(dataset_id);
auto ref_lock = reference_stack_type::push(dataset);

assert(table.primary_key_field);
transaction_lock trans(connection);
if (table.primary_key_field->is_default())
{
ret = table.create_update(context);
}
else if (strict)
{
throw misc::hibernate_exception("dataset have already a primary key assigned!");
}
else
{
auto update_context = context;
update_context.is_update = true;
ret = table.create_update(update_context);
}
trans.commit();
return ret;
}
};

/* create_update_impl_t - nullable */

template<typename T_dataset>
struct create_update_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 value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true)
{
value_t ret;
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_create_update_impl_type = create_update_impl_t<new_dataset_type>;
ret = new_create_update_impl_type::apply(*value, context, strict);
}
else if (strict)
{
throw misc::hibernate_exception("can not create nullable type with no value!");
}
return ret;
}
};

/* create_update_impl_t - container */

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

static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true)
{
value_t ret;
auto& connection = context.connection;

transaction_lock trans(connection);
for (auto& x : dataset)
{
using new_dataset_type = mp::decay_t<decltype(x)>;
using new_create_update_impl_type = create_update_impl_t<new_dataset_type>;
new_create_update_impl_type::apply(x, context, strict);
}
trans.commit();
return ret;
}
};

}
end_namespace_cpphibernate_driver_mariadb

+ 8
- 6
include/cpphibernate/driver/mariadb/mariadb.h View File

@@ -4,6 +4,7 @@
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/impl.h>
#include <cpphibernate/driver/mariadb/schema.h>
#include <cpphibernate/driver/mariadb/schema/filter.h>

beg_namespace_cpphibernate_driver_mariadb
{
@@ -13,6 +14,7 @@ beg_namespace_cpphibernate_driver_mariadb
private:
::cppmariadb::connection& _connection;
schema_t _schema;
filter_t _filter;

public:
template<typename T_schema>
@@ -38,17 +40,17 @@ beg_namespace_cpphibernate_driver_mariadb
template<typename T_dataset>
inline void create_impl(T_dataset& dataset) const
{
using create_context_type = generic_create_context<T_dataset>;
create_impl_t<create_context_type>::apply(create_context_type
{
create_update_impl_t<T_dataset>::apply(
dataset,
create_update_context
{
true,
_schema,
_filter,
nullptr,
nullptr,
_connection
},
dataset
});
});
}
};



+ 5
- 5
include/cpphibernate/driver/mariadb/schema/field.h View File

@@ -48,14 +48,14 @@ beg_namespace_cpphibernate_driver_mariadb
void print(std::ostream& os) const;

/* CRUD */
virtual value_t foreign_create(const create_context& context) const;
virtual value_t foreign_update(const 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;
virtual std::string convert_to_open () const;
virtual std::string convert_to_close () const;
virtual std::string convert_from_open () const;
@@ -102,7 +102,6 @@ beg_namespace_cpphibernate_driver_mariadb
using ref_stack = typename base_type::ref_stack;
using type_props = type_properties<value_type>;


using base_type::base_type;

virtual std::string type() const override;
@@ -120,6 +119,7 @@ beg_namespace_cpphibernate_driver_mariadb
using schema_type = typename base_type::schema_type;
using field_type = typename base_type::field_type;
using value_type = typename base_type::value_type;
using ref_stack = typename base_type::ref_stack;
using key_props = key_properties<value_type>;

using base_type::base_type;
@@ -127,6 +127,7 @@ beg_namespace_cpphibernate_driver_mariadb
virtual std::string create_table_arguments () const override;
virtual std::string generate_value (::cppmariadb::connection& connection) const override;
virtual bool is_auto_generated () const override;
virtual bool is_default () const override;
virtual std::string convert_to_open () const override;
virtual std::string convert_to_close () const override;
virtual std::string convert_from_open () const override;
@@ -158,8 +159,7 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type::base_type;

public:
virtual value_t foreign_create(const create_context& context) const override;
virtual value_t foreign_update(const update_context& context) const override;
virtual value_t foreign_create_update(const create_update_context& context) const override;
};

namespace __impl


+ 10
- 23
include/cpphibernate/driver/mariadb/schema/field.inl View File

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

#include <cpphibernate/driver/mariadb/impl/create.h>
#include <cpphibernate/driver/mariadb/schema/field.h>
#include <cpphibernate/driver/mariadb/impl/create_update.h>

beg_namespace_cpphibernate_driver_mariadb
{
@@ -40,6 +40,10 @@ beg_namespace_cpphibernate_driver_mariadb
bool primary_key_field_t<T_schema, T_field>::is_auto_generated() const
{ return key_props::auto_generated::value; }

template<typename T_schema, typename T_field>
bool primary_key_field_t<T_schema, T_field>::is_default() const
{ return key_props::is_default(this->field.getter(ref_stack::top())); }

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_to_open() const
{ return key_props::convert_to_open; }
@@ -60,34 +64,17 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_schema, typename T_field>
value_t foreign_table_field_t<T_schema, T_field>
::foreign_create(const create_context& context) const
::foreign_create_update(const create_update_context& context) const
{
auto& ref = ref_stack::top();
auto& foreign = this->field.getter(ref);

using foreign_dataset_type = mp::decay_t<decltype(foreign)>;
using create_context_type = generic_create_context<foreign_dataset_type>;

return create_impl_t<create_context_type>::apply(
create_context_type
{
context,
foreign,
},
false);
}

template<typename T_schema, typename T_field>
value_t foreign_table_field_t<T_schema, T_field>
::foreign_update(const update_context& ctx) const
{
/*
auto& context = static_cast<const generic_create_context<dataset_type>&>(ctx);
auto& ref = ref_stack::top();
auto& foreign = this->field.getter(ref);
return foreign_create_update_helper<update_impl_t>(context.change(foreign));
*/
return value_t { };
return create_update_impl_t<foreign_dataset_type>::apply(
foreign,
context,
false);
}

}

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

@@ -70,16 +70,19 @@ beg_namespace_cpphibernate_driver_mariadb
inline void init(const init_context& context) const
{ return init_exec(context); }

inline decltype(auto) create(const create_context& context) const
{ return create_intern(context); }
inline decltype(auto) create_update(const create_update_context& context) const
{ return create_update_intern(context); }

inline void read() const
{ }

inline void update(const update_context& context) const
{ update_intern(context); }

private:
template<typename T_schema, typename T_table, typename T_base_dataset>
friend struct table_simple_t;

template<typename T_schema, typename T_table, typename T_base_dataset>
friend struct table_polymorphic_t;

using statement_ptr = std::unique_ptr<::cppmariadb::statement>;

mutable statement_ptr _statement_create_table;
@@ -89,18 +92,17 @@ beg_namespace_cpphibernate_driver_mariadb
::cppmariadb::statement& get_statement_insert_into() const;

std::string execute_insert_update(
const create_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const;
const create_update_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const;

protected:
void init_exec (const init_context& context) const;
virtual std::string create_update_base(const create_update_context& context) const;

virtual std::string create_intern (const create_context& context) const;
std::string create_exec (const create_context& context) const;
protected:
void init_exec (const init_context& context) const;

virtual std::string update_intern (const update_context& context) const;
std::string update_exec (const update_context& context) const;
virtual std::string create_update_intern(const create_update_context& context) const;
std::string create_update_exec (const create_update_context& context) const;
};

/* table_simple_t */
@@ -152,7 +154,10 @@ beg_namespace_cpphibernate_driver_mariadb
constexpr void for_each_derived(T_dataset& dataset, const T_include_self& include_self, const T_pred& pred) const;

protected:
virtual std::string create_intern(const create_context& context) const override;
virtual std::string create_update_intern(const create_update_context& context) const override;

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

namespace __impl


+ 29
- 6
include/cpphibernate/driver/mariadb/schema/table.inl View File

@@ -33,11 +33,10 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_schema, typename T_table, typename T_base_dataset>
std::string table_polymorphic_t<T_schema, T_table, T_base_dataset>
::create_intern(const create_context& ctx) const
::create_update_intern(const create_update_context& context) const
{
bool done = false;
auto& context = static_cast<const generic_create_context<dataset_type>&>(ctx);
auto& dataset = context.dataset;
auto& dataset = reference_stack<dataset_type>::top();
for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){
if (!done)
{
@@ -46,16 +45,40 @@ beg_namespace_cpphibernate_driver_mariadb
auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>);
auto derived_table = this->get_derived(derived_dataset_id);
if (!derived_table)
throw misc::hibernate_exception(std::string("unable to find derived table info for dataset '") + utl::type_helper<derived_dataset_type>::name() + "'!");
{
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 ref_lock = reference_stack_type::push(derived_dataset);
derived_table->create(context.change(derived_dataset, context.owner_field));
derived_table->create_update(context);
done = true;
}
});

return done
? *this->primary_key_field->get()
: this->create_exec(context);
: this->create_update_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
{
return hana::eval_if(
mp::is_same<base_dataset_type, void> { },
[this]()->std::string {
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "'" << this->table_name << "' does not have a base table").str());
},
[this, &context](auto _)->std::string {
using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>;
assert(base_table);
auto& dataset = reference_stack<dataset_type>::top();
auto& base = static_cast<tmp_type&>(dataset);
auto lock = reference_stack<tmp_type>::push(base);
return this->base_table->create_update_exec(context);
});
}

}

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

@@ -41,11 +41,11 @@ void field_t::print(std::ostream& os) const

/* CRUD */

throw_not_implemented(value_t, foreign_create, const create_context&)
throw_not_implemented(value_t, foreign_update, const update_context&)
throw_not_implemented(value_t, foreign_create_update, const create_update_context&)

/* properties */

throw_not_implemented(bool, is_default)
throw_not_implemented(string, type)
throw_not_implemented(string, create_table_arguments)
throw_not_implemented(string, generate_value, ::cppmariadb::connection&)


+ 20
- 44
src/driver/mariadb/schema/table.cpp View File

@@ -472,9 +472,9 @@ std::string build_insert_update_query(const table_t& table, const filter_t* filt
/* execute_insert_update */

std::string table_t::execute_insert_update(
const create_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const
const create_update_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const
{
auto& connection = context.connection;

@@ -503,21 +503,10 @@ std::string table_t::execute_insert_update(
&& ( !is_update
|| filter->contains(base_table, true)))
{
std::string key;
if (is_update)
{
auto new_context = static_cast<const update_context&>(context);
if (!new_context.derived_table)
new_context.derived_table = this;
key = base_table->update_exec(new_context);
}
else
{
auto new_context = context;
if (!new_context.derived_table)
new_context.derived_table = this;
key = base_table->create_exec(new_context);
}
auto new_context = context;
if (!new_context.derived_table)
new_context.derived_table = this;
std::string key = create_update_base(new_context);
statement.set(index, std::move(key));
++index;
}
@@ -531,9 +520,7 @@ std::string table_t::execute_insert_update(
assert(ptr);
if (is_update && !filter->contains(ptr))
continue;
value_t key = !is_update
? ptr->foreign_create(context)
: ptr->foreign_update(static_cast<const update_context&>(context));
value_t key = ptr->foreign_create_update(context);
if (key.has_value()) statement.set(index, std::move(key));
else statement.set_null(index);
++index;
@@ -621,18 +608,9 @@ std::string table_t::execute_insert_update(
|| !filter->contains(ptr->referenced_table, true)))
continue;

if (!is_update)
{
auto next_context = context;
next_context.owner_field = ptr;
ptr->foreign_create(next_context);
}
else
{
auto next_context = static_cast<const update_context&>(context);
next_context.owner_field = ptr;
ptr->foreign_update(next_context);
}
auto next_context = context;
next_context.owner_field = ptr;
ptr->foreign_create_update(next_context);
}

return primary_key;
@@ -708,6 +686,12 @@ const table_t* table_t::get_derived(size_t id) const
return *_statement_create_table;
}

std::string table_t::create_update_base(const create_update_context& context) const
{
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "'" << this->table_name << "' does not implement create_update_base!").str());
}

void table_t::init_exec(const init_context& context) const
{
auto& statement = get_statement_create_table();
@@ -716,19 +700,11 @@ void table_t::init_exec(const init_context& context) const
connection.execute(statement);
}

std::string table_t::create_exec(const create_context& context) const
std::string table_t::create_update_exec(const create_update_context& context) const
{
auto& statement = get_statement_insert_into();
return execute_insert_update(context, statement, nullptr);
}

std::string table_t::update_exec(const update_context& context) const
{
return std::string();
}

std::string table_t::create_intern(const create_context& context) const
{ return create_exec(context); }

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

+ 4
- 4
test/cpphibernate_create.cpp View File

@@ -6,7 +6,7 @@

using namespace ::testing;
using namespace ::cpphibernate;
/*
TEST(CppHibernateTests, create_test1)
{
StrictMock<mariadb_mock> mock;
@@ -279,7 +279,7 @@ TEST(CppHibernateTests, create_derived2)
auto context = make_context<driver::mariadb>(test_schema, connection);
context.create(static_cast<base&>(d2));
}
*/
TEST(CppHibernateTests, create_derived3)
{
StrictMock<mariadb_mock> mock;
@@ -435,5 +435,5 @@ TEST(CppHibernateTests, create_derived3)

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

Loading…
Cancel
Save