Просмотр исходного кода

* refactored mariadb driver internal context processing

master
bergmann 7 лет назад
Родитель
Сommit
42867058b0
23 измененных файлов: 594 добавлений и 552 удалений
  1. +0
    -1
      include/cpphibernate/driver/mariadb/helper.h
  2. +117
    -9
      include/cpphibernate/driver/mariadb/helper/context.h
  3. +0
    -76
      include/cpphibernate/driver/mariadb/helper/reference_stack.h
  4. +0
    -1
      include/cpphibernate/driver/mariadb/impl.h
  5. +31
    -22
      include/cpphibernate/driver/mariadb/impl/create_update.h
  6. +0
    -30
      include/cpphibernate/driver/mariadb/impl/init.h
  7. +4
    -16
      include/cpphibernate/driver/mariadb/mariadb.h
  8. +5
    -1
      include/cpphibernate/driver/mariadb/schema.h
  9. +0
    -53
      include/cpphibernate/driver/mariadb/schema/attributes.h
  10. +62
    -0
      include/cpphibernate/driver/mariadb/schema/attributes.inl
  11. +7
    -100
      include/cpphibernate/driver/mariadb/schema/field.h
  12. +109
    -11
      include/cpphibernate/driver/mariadb/schema/field.inl
  13. +0
    -46
      include/cpphibernate/driver/mariadb/schema/fields.h
  14. +55
    -0
      include/cpphibernate/driver/mariadb/schema/fields.inl
  15. +0
    -31
      include/cpphibernate/driver/mariadb/schema/schema.h
  16. +40
    -0
      include/cpphibernate/driver/mariadb/schema/schema.inl
  17. +0
    -88
      include/cpphibernate/driver/mariadb/schema/table.h
  18. +93
    -8
      include/cpphibernate/driver/mariadb/schema/table.inl
  19. +0
    -46
      include/cpphibernate/driver/mariadb/schema/tables.h
  20. +55
    -0
      include/cpphibernate/driver/mariadb/schema/tables.inl
  21. +3
    -3
      src/driver/mariadb/schema/field.cpp
  22. +12
    -9
      src/driver/mariadb/schema/table.cpp
  23. +1
    -1
      test/mariadb_mock.cpp

+ 0
- 1
include/cpphibernate/driver/mariadb/helper.h Просмотреть файл

@@ -2,6 +2,5 @@

#include <cpphibernate/driver/mariadb/helper/context.h>
#include <cpphibernate/driver/mariadb/helper/key_properties.h>
#include <cpphibernate/driver/mariadb/helper/reference_stack.h>
#include <cpphibernate/driver/mariadb/helper/transaction_lock.h>
#include <cpphibernate/driver/mariadb/helper/type_properties.h>

+ 117
- 9
include/cpphibernate/driver/mariadb/helper/context.h Просмотреть файл

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

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/schema/field.fwd.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
@@ -10,25 +11,132 @@
beg_namespace_cpphibernate_driver_mariadb
{

/* init_context */
/* base_context */

struct init_context
struct base_context
{
const schema_t& schema;
::cppmariadb::connection& connection;
bool recreate;

inline base_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: schema (p_schema)
, connection(p_connection)
{ }
};


/* init_context */

struct init_context
: public base_context
{
bool recreate;

inline init_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
bool p_recreate)
: base_context (p_schema, p_connection)
, recreate (p_recreate)
{ }
};

namespace __impl
{
struct change_context_impl
{
template<typename T_context, typename T_data>
constexpr decltype(auto) operator()(const T_context& context, T_data& data) const
{
auto new_context = context;
new_context.data_id = misc::get_type_id(hana::type_c<mp::decay_t<T_data>>);
new_context.data = &data;
return new_context;
}
};
}

constexpr decltype(auto) change_context = __impl::change_context_impl { };

/* data_context */

struct data_context
: public base_context
{
private:
friend __impl::change_context_impl;

size_t data_id;
void* data;

public:
template<typename T>
inline decltype(auto) get() const
{
if (!data)
throw misc::hibernate_exception("no data assigned!");
auto type_id = misc::get_type_id(hana::type_c<mp::decay_t<T>>);
if (type_id != data_id)
{
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "invalid type! expected " << data_id << ", got " << type_id).str());
}
return *static_cast<T*>(data);
}

template<typename T_data>
inline data_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: base_context (p_schema, p_connection)
, data_id (misc::get_type_id(hana::type_c<mp::decay_t<T_data>>))
, data (&p_data)
{ }
};

/* filter_context */

struct filter_context
: public data_context
{
const filter_t& filter;

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

/* create_update_context */

struct create_update_context
: public filter_context
{
bool is_update;
const schema_t& schema;
const filter_t& filter;
const table_t* derived_table;
const field_t* owner_field;
::cppmariadb::connection& connection;
bool is_update;
const table_t* derived_table;
const field_t* owner_field;
std::string owner_key;

template<typename T_data>
inline create_update_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter,
bool p_is_update)
: filter_context(p_data, p_schema, p_connection, p_filter)
, is_update (p_is_update)
, derived_table (nullptr)
, owner_field (nullptr)
{ }
};

}

+ 0
- 76
include/cpphibernate/driver/mariadb/helper/reference_stack.h Просмотреть файл

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

#include <stack>

#include <cpphibernate/config.h>
#include <cpputils/misc/type_helper.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* reference_lock */

struct reference_lock
{
virtual ~reference_lock() = default;
};

using reference_lock_ptr = std::unique_ptr<reference_lock>;

/* reference_stack */

template<typename T_dataset>
struct reference_stack
{
private:
struct lock
: public reference_lock
{
private:
T_dataset& dataset;

public:
inline lock(T_dataset& p_dataset)
: dataset(p_dataset)
{ push_impl(dataset); }

virtual ~lock() override
{ pop_impl(dataset); }
};

private:
using stack_type = std::stack<T_dataset*>;

static inline stack_type& stack()
{
static stack_type value;
return value;
}

static inline void push_impl(T_dataset& dataset)
{ stack().push(&dataset); }

static inline void pop_impl(T_dataset& dataset)
{
if (stack().empty() || stack().top() != &dataset)
throw misc::hibernate_exception(std::string("reference_stack<") + utl::type_helper<T_dataset>::name() + ">: poped element is not the top element!");
stack().pop();
}

public:
static inline decltype(auto) push(T_dataset& dataset)
{ return std::make_unique<lock>(dataset); }

static inline T_dataset& top()
{
if (stack().empty())
throw misc::hibernate_exception(std::string("reference_stack<") + utl::type_helper<T_dataset>::name() + ">: does not have stored a dataset!");
return *stack().top();
}

static inline size_t size()
{ return stack().size(); }
};

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 1
include/cpphibernate/driver/mariadb/impl.h Просмотреть файл

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

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

+ 31
- 22
include/cpphibernate/driver/mariadb/impl/create_update.h Просмотреть файл

@@ -3,6 +3,8 @@
#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
{
@@ -12,34 +14,39 @@ beg_namespace_cpphibernate_driver_mariadb
template<typename T_dataset, typename = void>
struct create_update_impl_t
{
using dataset_type = T_dataset;
using reference_stack_type = reference_stack<dataset_type>;
using dataset_type = T_dataset;

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

auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
auto& connection = context.connection;
auto& schema = context.schema;
auto& table = schema.table(dataset_id);
auto ref_lock = reference_stack_type::push(dataset);
auto dataset_id = misc::get_type_id(hana::type_c<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())
{
ret = table.create_update(context);
}
else if (strict)
if (table.primary_key_field->is_default(context) == context.is_update)
{
throw misc::hibernate_exception("dataset have already a primary key assigned!");
if (!strict)
{
auto update_context = context;
update_context.is_update = true;
ret = table.create_update(update_context);
}
else if (context.is_update)
{
throw misc::hibernate_exception("can not update dataset with no primary key assigned!");
}
else
{
throw misc::hibernate_exception("can not create dataset with primary key assigned!");
}
}
else
{
auto update_context = context;
update_context.is_update = true;
ret = table.create_update(update_context);
ret = table.create_update(context);
}
trans.commit();
return ret;
@@ -56,16 +63,17 @@ beg_namespace_cpphibernate_driver_mariadb
using dataset_type = T_dataset;
using nullable_helper_type = misc::nullable_helper<dataset_type>;

static inline value_t apply(dataset_type& dataset, const create_update_context& context, bool strict = true)
static inline value_t apply(const create_update_context& context, bool strict = true)
{
value_t ret;
auto* value = nullable_helper_type::get(dataset);
auto& dataset = context.get<dataset_type>();
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);
ret = new_create_update_impl_type::apply(change_context(context, *value), strict);
}
else if (strict)
{
@@ -84,17 +92,18 @@ beg_namespace_cpphibernate_driver_mariadb
{
using dataset_type = T_dataset;

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

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);
new_create_update_impl_type::apply(change_context(context, x), strict);
}
trans.commit();
return ret;


+ 0
- 30
include/cpphibernate/driver/mariadb/impl/init.h Просмотреть файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{

/* init_impl_t */

template<typename T_context, typename = void>
struct init_impl_t
{
using context_type = T_context;

static inline void apply(const context_type& context)
{
auto& schema = context.schema;
auto& connection = context.connection;

transaction_lock trans(connection);
schema.init(context);
trans.commit();
}
};

}
end_namespace_cpphibernate_driver_mariadb

+ 4
- 16
include/cpphibernate/driver/mariadb/mariadb.h Просмотреть файл

@@ -29,28 +29,16 @@ beg_namespace_cpphibernate_driver_mariadb
protected:
inline void init_impl(bool recreate) const
{
init_impl_t<init_context>::apply(init_context
{
_schema,
_connection,
recreate
});
transaction_lock trans(_connection);
_schema.init(init_context(_schema, _connection, recreate));
trans.commit();
}

template<typename T_dataset>
inline void create_impl(T_dataset& dataset) const
{
create_update_impl_t<T_dataset>::apply(
dataset,
create_update_context
{
true,
_schema,
_filter,
nullptr,
nullptr,
_connection
});
create_update_context(dataset, _schema, _connection, _filter, false));
}
};



+ 5
- 1
include/cpphibernate/driver/mariadb/schema.h Просмотреть файл

@@ -14,5 +14,9 @@
#include <cpphibernate/driver/mariadb/schema/table.h>
#include <cpphibernate/driver/mariadb/schema/tables.h>

#include <cpphibernate/driver/mariadb/schema/attributes.inl>
#include <cpphibernate/driver/mariadb/schema/field.inl>
#include <cpphibernate/driver/mariadb/schema/table.inl>
#include <cpphibernate/driver/mariadb/schema/fields.inl>
#include <cpphibernate/driver/mariadb/schema/table.inl>
#include <cpphibernate/driver/mariadb/schema/tables.inl>
#include <cpphibernate/driver/mariadb/schema/schema.inl>

+ 0
- 53
include/cpphibernate/driver/mariadb/schema/attributes.h Просмотреть файл

@@ -19,58 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type::base_type;
};

namespace __impl
{

/* attribute_converter */

template<typename T_attribute>
struct attribute_converter;

template<>
struct attribute_converter<schema::attribute::hex_type>
{ static constexpr decltype(auto) value = attribute_t::hex; };

template<>
struct attribute_converter<schema::attribute::compress_type>
{ static constexpr decltype(auto) value = attribute_t::compress; };

template<>
struct attribute_converter<schema::attribute::primary_key_type>
{ static constexpr decltype(auto) value = attribute_t::primary_key; };

/* make_attributes_impl */

template<typename T, typename>
struct make_attributes_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); }
};

template<typename T_attributes>
struct make_attributes_impl<
mp::list<T_attributes>,
mp::enable_if_c<
schema::is_attributes<mp::decay_t<T_attributes>>::value>>
{
template<size_t... I>
static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&)
{
return attributes_t({
attribute_converter<mp::decay_t<decltype(std::declval<T_attributes>()[hana::size_c<I>])>>::value...
});
}

static constexpr decltype(auto) apply(const T_attributes& attributes)
{
using size = mp::decay_t<decltype(hana::size(attributes))>;
return helper(attributes, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 62
- 0
include/cpphibernate/driver/mariadb/schema/attributes.inl Просмотреть файл

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

#include <cpphibernate/driver/mariadb/schema/attributes.h>

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* attribute_converter */

template<typename T_attribute>
struct attribute_converter;

template<>
struct attribute_converter<schema::attribute::hex_type>
{ static constexpr decltype(auto) value = attribute_t::hex; };

template<>
struct attribute_converter<schema::attribute::compress_type>
{ static constexpr decltype(auto) value = attribute_t::compress; };

template<>
struct attribute_converter<schema::attribute::primary_key_type>
{ static constexpr decltype(auto) value = attribute_t::primary_key; };

/* make_attributes_impl */

template<typename T, typename>
struct make_attributes_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); }
};

template<typename T_attributes>
struct make_attributes_impl<
mp::list<T_attributes>,
mp::enable_if_c<
schema::is_attributes<mp::decay_t<T_attributes>>::value>>
{
template<size_t... I>
static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&)
{
return attributes_t({
attribute_converter<mp::decay_t<decltype(std::declval<T_attributes>()[hana::size_c<I>])>>::value...
});
}

static constexpr decltype(auto) apply(const T_attributes& attributes)
{
using size = mp::decay_t<decltype(hana::size(attributes))>;
return helper(attributes, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 7
- 100
include/cpphibernate/driver/mariadb/schema/field.h Просмотреть файл

@@ -55,13 +55,13 @@ beg_namespace_cpphibernate_driver_mariadb
virtual std::string create_table_arguments () const;
virtual std::string generate_value (::cppmariadb::connection& connection) const;
virtual bool is_auto_generated () const;
virtual bool is_default () const;
virtual bool is_default (const data_context& context) const;
virtual std::string convert_to_open () const;
virtual std::string convert_to_close () const;
virtual std::string convert_from_open () const;
virtual std::string convert_from_close () const;
virtual value_t get () const;
virtual void set (const value_t&) const;
virtual value_t get (const data_context& context) const;
virtual void set (const data_context& context, const value_t&) const;
};

/* simple_field_t */
@@ -75,7 +75,6 @@ beg_namespace_cpphibernate_driver_mariadb
using getter_type = typename mp::decay_t<field_type>::getter_type;
using dataset_type = typename getter_type::dataset_type;
using value_type = typename getter_type::value_type;
using ref_stack = reference_stack<dataset_type>;

const schema_type& schema;
const field_type& field;
@@ -99,14 +98,13 @@ beg_namespace_cpphibernate_driver_mariadb
using getter_type = typename base_type::getter_type;
using dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
using ref_stack = typename base_type::ref_stack;
using type_props = type_properties<value_type>;

using base_type::base_type;

virtual std::string type() const override;
virtual value_t get () const override;
virtual void set (const value_t&) const override;
virtual value_t get (const data_context& context) const override;
virtual void set (const data_context& context, const value_t&) const override;
};

/* primary_key_field_t */
@@ -118,8 +116,8 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type = value_field_t<T_schema, T_field>;
using schema_type = typename base_type::schema_type;
using field_type = typename base_type::field_type;
using dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
using ref_stack = typename base_type::ref_stack;
using key_props = key_properties<value_type>;

using base_type::base_type;
@@ -127,7 +125,7 @@ beg_namespace_cpphibernate_driver_mariadb
virtual std::string create_table_arguments () const override;
virtual std::string generate_value (::cppmariadb::connection& connection) const override;
virtual bool is_auto_generated () const override;
virtual bool is_default () const override;
virtual bool is_default (const data_context& context) const override;
virtual std::string convert_to_open () const override;
virtual std::string convert_to_close () const override;
virtual std::string convert_from_open () const override;
@@ -154,7 +152,6 @@ beg_namespace_cpphibernate_driver_mariadb
public:
using base_type = simple_field_t<T_schema, T_field>;
using dataset_type = typename base_type::dataset_type;
using ref_stack = typename base_type::ref_stack;

using base_type::base_type;

@@ -162,95 +159,5 @@ beg_namespace_cpphibernate_driver_mariadb
virtual value_t foreign_create_update(const create_update_context& context) const override;
};

namespace __impl
{

/* is_primary_key_field */

template<typename T_field>
struct is_primary_key_field
: public mp::decay_t<decltype(
hana::contains(
std::declval<T_field>().attributes,
schema::attribute::primary_key))>
{ };

/* is_foreign_table_field */

template<typename T_schema, typename T_field>
struct is_foreign_table_field
: public mp::decay_t<decltype(
hana::contains(
hana::transform(
std::declval<T_schema>().tables,
schema::table::get_wrapped_dataset),
hana::type_c<misc::real_dataset_t<typename T_field::getter_type::value_type>>))>
{ };

/* field_type */

template<typename T_schema, typename T_field, typename = void>
struct field_type
{ using type = data_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_primary_key_field<T_field>>>
{ using type = primary_key_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_foreign_table_field<T_schema, T_field>>>
{ using type = foreign_table_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
using field_type_t = typename field_type<T_schema, T_field>::type;

/* make_field_impl */

template<typename T, typename>
struct make_field_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); }
};

template<typename T_schema, typename T_table, typename T_field>
struct make_field_impl<
mp::list<T_schema, T_table, T_field>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value
&& schema::is_field <mp::decay_t<T_field >>::value>>
{
static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table, const T_field& field)
{
using schema_type = mp::decay_t<T_schema>;
using field_type = mp::decay_t<T_field>;
using getter_type = mp::decay_t<typename field_type::getter_type>;
using value_type = mp::decay_t<typename getter_type::value_type>;
using dataset_type = mp::decay_t<typename getter_type::dataset_type>;
using value_dataset_type = misc::real_dataset_t<value_type>;
using return_type = field_type_t<schema_type, field_type>;
using primary_key_type = primary_key_field_t<schema_type, field_type>;
return_type ret(schema, field);
ret.table_dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
ret.value_dataset_id = misc::get_type_id(hana::type_c<value_dataset_type>);
ret.value_is_nullable = misc::is_nullable<value_type>::value;
ret.value_is_container = misc::is_container<value_type>::value;
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.field_name = field.name;
ret.attributes = make_attributes(field.attributes);
hana::eval_if(
hana::equal(hana::type_c<return_type>, hana::type_c<primary_key_type>),
[&ret](){
ret.field_name = ret.table_name + "_" + ret.field_name;
}, [](){ });
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 109
- 11
include/cpphibernate/driver/mariadb/schema/field.inl Просмотреть файл

@@ -13,12 +13,18 @@ beg_namespace_cpphibernate_driver_mariadb
{ return type_props::type(); }

template<typename T_schema, typename T_field>
value_t value_field_t<T_schema, T_field>::get() const
{ return type_props::convert_from(this->field.getter(ref_stack::top())); }
value_t value_field_t<T_schema, T_field>::get(const data_context& context) const
{
auto& dataset = context.get<dataset_type>();
return type_props::convert_from(this->field.getter(dataset));
}

template<typename T_schema, typename T_field>
void value_field_t<T_schema, T_field>::set(const value_t& value) const
{ this->field.setter(ref_stack::top(), type_props::convert_to(value)); }
void value_field_t<T_schema, T_field>::set(const data_context& context, const value_t& value) const
{
auto& dataset = context.get<dataset_type>();
this->field.setter(dataset, type_props::convert_to(value));
}

/* primary_key_field_t */

@@ -41,8 +47,11 @@ beg_namespace_cpphibernate_driver_mariadb
{ return key_props::auto_generated::value; }

template<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())); }
bool primary_key_field_t<T_schema, T_field>::is_default(const data_context& context) const
{
auto& dataset = context.get<dataset_type>();
return key_props::is_default(this->field.getter(dataset));
}

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_to_open() const
@@ -66,16 +75,105 @@ beg_namespace_cpphibernate_driver_mariadb
value_t foreign_table_field_t<T_schema, T_field>
::foreign_create_update(const create_update_context& context) const
{
auto& ref = ref_stack::top();
auto& foreign = this->field.getter(ref);
auto& dataset = context.get<dataset_type>();
auto& foreign = this->field.getter(dataset);
auto next_context = change_context(context, foreign);

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

return create_update_impl_t<foreign_dataset_type>::apply(
foreign,
context,
next_context,
false);
}

namespace __impl
{

/* is_primary_key_field */

template<typename T_field>
struct is_primary_key_field
: public mp::decay_t<decltype(
hana::contains(
std::declval<T_field>().attributes,
schema::attribute::primary_key))>
{ };

/* is_foreign_table_field */

template<typename T_schema, typename T_field>
struct is_foreign_table_field
: public mp::decay_t<decltype(
hana::contains(
hana::transform(
std::declval<T_schema>().tables,
schema::table::get_wrapped_dataset),
hana::type_c<misc::real_dataset_t<typename T_field::getter_type::value_type>>))>
{ };

/* field_type */

template<typename T_schema, typename T_field, typename = void>
struct field_type
{ using type = data_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_primary_key_field<T_field>>>
{ using type = primary_key_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_foreign_table_field<T_schema, T_field>>>
{ using type = foreign_table_field_t<T_schema, T_field>; };

template<typename T_schema, typename T_field>
using field_type_t = typename field_type<T_schema, T_field>::type;

/* make_field_impl */

template<typename T, typename>
struct make_field_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); }
};

template<typename T_schema, typename T_table, typename T_field>
struct make_field_impl<
mp::list<T_schema, T_table, T_field>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value
&& schema::is_field <mp::decay_t<T_field >>::value>>
{
static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table, const T_field& field)
{
using schema_type = mp::decay_t<T_schema>;
using field_type = mp::decay_t<T_field>;
using getter_type = mp::decay_t<typename field_type::getter_type>;
using value_type = mp::decay_t<typename getter_type::value_type>;
using dataset_type = mp::decay_t<typename getter_type::dataset_type>;
using value_dataset_type = misc::real_dataset_t<value_type>;
using return_type = field_type_t<schema_type, field_type>;
using primary_key_type = primary_key_field_t<schema_type, field_type>;
return_type ret(schema, field);
ret.table_dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
ret.value_dataset_id = misc::get_type_id(hana::type_c<value_dataset_type>);
ret.value_is_nullable = misc::is_nullable<value_type>::value;
ret.value_is_container = misc::is_container<value_type>::value;
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.field_name = field.name;
ret.attributes = make_attributes(field.attributes);
hana::eval_if(
hana::equal(hana::type_c<return_type>, hana::type_c<primary_key_type>),
[&ret](){
ret.field_name = ret.table_name + "_" + ret.field_name;
}, [](){ });
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 46
include/cpphibernate/driver/mariadb/schema/fields.h Просмотреть файл

@@ -21,51 +21,5 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type::base_type;
};

namespace __impl
{

/* make_fields_impl */

template<typename T, typename>
struct make_fields_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); }
};

template<typename T_schema, typename T_table>
struct make_fields_impl<
mp::list<T_schema, T_table>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value>>
{
template<typename T_index>
static constexpr void emplace(fields_t& fields, const T_schema& schema, const T_table& table, T_index&& index)
{
decltype(auto) field = make_field(schema, table, table.fields[index]);
using field_type = mp::decay_t<decltype(field)>;
fields.emplace_back(new field_type(std::move(field)));
}

template<size_t... I>
static auto helper(const T_schema& schema, const T_table& table, std::index_sequence<I...>&&)
{
fields_t fields;
int dummy[] = {0, (emplace(fields, schema, table, hana::size_c<I>), void(), 0)...};
(void) dummy;
return fields;
}

static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table)
{
using size = decltype(hana::size(table.fields));
return helper(schema, table, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 55
- 0
include/cpphibernate/driver/mariadb/schema/fields.inl Просмотреть файл

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

#include <cpphibernate/driver/mariadb/schema/fields.h>

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_fields_impl */

template<typename T, typename>
struct make_fields_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); }
};

template<typename T_schema, typename T_table>
struct make_fields_impl<
mp::list<T_schema, T_table>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value>>
{
template<typename T_index>
static constexpr void emplace(fields_t& fields, const T_schema& schema, const T_table& table, T_index&& index)
{
decltype(auto) field = make_field(schema, table, table.fields[index]);
using field_type = mp::decay_t<decltype(field)>;
fields.emplace_back(new field_type(std::move(field)));
}

template<size_t... I>
static auto helper(const T_schema& schema, const T_table& table, std::index_sequence<I...>&&)
{
fields_t fields;
int dummy[] = {0, (emplace(fields, schema, table, hana::size_c<I>), void(), 0)...};
(void) dummy;
return fields;
}

static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table)
{
using size = decltype(hana::size(table.fields));
return helper(schema, table, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 31
include/cpphibernate/driver/mariadb/schema/schema.h Просмотреть файл

@@ -32,36 +32,5 @@ beg_namespace_cpphibernate_driver_mariadb
void init(const init_context& context) const;
};

namespace __impl
{

/* make_schema_impl */

template<typename T, typename>
struct make_schema_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); }
};

template<typename T_schema>
struct make_schema_impl<
mp::list<T_schema>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value>>
{
static decltype(auto) apply(const T_schema& schema)
{
schema_t ret;
ret.schema_name = schema.name;
ret.tables = make_tables(schema);
ret.update();
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 40
- 0
include/cpphibernate/driver/mariadb/schema/schema.inl Просмотреть файл

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

#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_schema_impl */

template<typename T, typename>
struct make_schema_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); }
};

template<typename T_schema>
struct make_schema_impl<
mp::list<T_schema>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value>>
{
static decltype(auto) apply(const T_schema& schema)
{
schema_t ret;
ret.schema_name = schema.name;
ret.tables = make_tables(schema);
ret.update();
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 88
include/cpphibernate/driver/mariadb/schema/table.h Просмотреть файл

@@ -166,93 +166,5 @@ beg_namespace_cpphibernate_driver_mariadb
virtual std::string create_update_base(const create_update_context& context) const override;
};

namespace __impl
{

/* make_dataset_id_vector */

struct make_dataset_id_vector_impl
{
template<typename T_wrapped_datasets, size_t... I>
static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence<I...>)
{
return std::vector<size_t>({
misc::get_type_id(wrapped_datasets[hana::size_c<I>])...
});
}

template<typename T_wrapped_datasets>
constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const
{
using size = mp::decay_t<decltype(hana::size(wrapped_datasets))>;
return helper(std::forward<T_wrapped_datasets>(wrapped_datasets), std::make_index_sequence<size::value> { });
}
};

static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { };

/* make_table_impl */

template<typename T, typename>
struct make_table_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); }
};

template<typename T_schema, typename T_table>
struct make_table_impl<
mp::list<T_schema, T_table>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table>>::value>>
{

/* table_type */

template<typename T_dataset, typename T_base_dataset, typename = void>
struct table_type
{ using type = table_simple_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; };

template<typename T_dataset, typename T_base_dataset>
struct table_type<T_dataset, T_base_dataset, mp::enable_if_c<
std::is_polymorphic<T_dataset>::value>>
{ using type = table_polymorphic_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; };

template<typename T_dataset, typename T_base_dataset>
using table_type_t = typename table_type<T_dataset, T_base_dataset>::type;

/* apply */

static decltype(auto) apply(const T_schema& schema, const T_table& table)
{
using wrapped_base_type = mp::decay_t<decltype(
schema::get_base_type(
std::declval<T_schema>(),
std::declval<T_table>().wrapped_dataset))>;
using base_type = misc::unwrap_t<wrapped_base_type>;
using derived_wrapped_types_type = mp::decay_t<decltype(
schema::get_derived_types(
std::declval<T_schema>(),
std::declval<T_table>().wrapped_dataset))>;
using wrapped_dataset_type = typename mp::decay_t<T_table>::wrapped_dataset_type;
using dataset_type = misc::unwrap_t<wrapped_dataset_type>;
using table_type = table_type_t<dataset_type, base_type>;

table_type ret(schema, table);
ret.dataset_id = misc::get_type_id(table.wrapped_dataset);
ret.base_dataset_id = misc::get_type_id(wrapped_base_type { });
ret.derived_dataset_ids = make_dataset_id_vector(derived_wrapped_types_type { });
ret.table_id = hana::value(table.table_id);
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.fields = make_fields(schema, table);
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 93
- 8
include/cpphibernate/driver/mariadb/schema/table.inl Просмотреть файл

@@ -36,12 +36,11 @@ beg_namespace_cpphibernate_driver_mariadb
::create_update_intern(const create_update_context& context) const
{
bool done = false;
auto& dataset = reference_stack<dataset_type>::top();
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)>;
using reference_stack_type = reference_stack<derived_dataset_type>;
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)
@@ -50,14 +49,13 @@ beg_namespace_cpphibernate_driver_mariadb
<< "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_update(context);
derived_table->create_update(change_context(context, derived_dataset));
done = true;
}
});

return done
? *this->primary_key_field->get()
? *this->primary_key_field->get(context)
: this->create_update_exec(context);
}

@@ -74,12 +72,99 @@ beg_namespace_cpphibernate_driver_mariadb
[this, &context](auto _)->std::string {
using tmp_type = misc::decay_unwrap_t<decltype(_(hana::type_c<base_dataset_type>))>;
assert(base_table);
auto& dataset = reference_stack<dataset_type>::top();
auto& dataset = context.get<dataset_type>();
auto& base = static_cast<tmp_type&>(dataset);
auto lock = reference_stack<tmp_type>::push(base);
return this->base_table->create_update_exec(context);
return this->base_table->create_update_exec(change_context(context, base));
});
}

namespace __impl
{

/* make_dataset_id_vector */

struct make_dataset_id_vector_impl
{
template<typename T_wrapped_datasets, size_t... I>
static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence<I...>)
{
return std::vector<size_t>({
misc::get_type_id(wrapped_datasets[hana::size_c<I>])...
});
}

template<typename T_wrapped_datasets>
constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const
{
using size = mp::decay_t<decltype(hana::size(wrapped_datasets))>;
return helper(std::forward<T_wrapped_datasets>(wrapped_datasets), std::make_index_sequence<size::value> { });
}
};

static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { };

/* make_table_impl */

template<typename T, typename>
struct make_table_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); }
};

template<typename T_schema, typename T_table>
struct make_table_impl<
mp::list<T_schema, T_table>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table>>::value>>
{

/* table_type */

template<typename T_dataset, typename T_base_dataset, typename = void>
struct table_type
{ using type = table_simple_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; };

template<typename T_dataset, typename T_base_dataset>
struct table_type<T_dataset, T_base_dataset, mp::enable_if_c<
std::is_polymorphic<T_dataset>::value>>
{ using type = table_polymorphic_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset>; };

template<typename T_dataset, typename T_base_dataset>
using table_type_t = typename table_type<T_dataset, T_base_dataset>::type;

/* apply */

static decltype(auto) apply(const T_schema& schema, const T_table& table)
{
using wrapped_base_type = mp::decay_t<decltype(
schema::get_base_type(
std::declval<T_schema>(),
std::declval<T_table>().wrapped_dataset))>;
using base_type = misc::unwrap_t<wrapped_base_type>;
using derived_wrapped_types_type = mp::decay_t<decltype(
schema::get_derived_types(
std::declval<T_schema>(),
std::declval<T_table>().wrapped_dataset))>;
using wrapped_dataset_type = typename mp::decay_t<T_table>::wrapped_dataset_type;
using dataset_type = misc::unwrap_t<wrapped_dataset_type>;
using table_type = table_type_t<dataset_type, base_type>;

table_type ret(schema, table);
ret.dataset_id = misc::get_type_id(table.wrapped_dataset);
ret.base_dataset_id = misc::get_type_id(wrapped_base_type { });
ret.derived_dataset_ids = make_dataset_id_vector(derived_wrapped_types_type { });
ret.table_id = hana::value(table.table_id);
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.fields = make_fields(schema, table);
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 46
include/cpphibernate/driver/mariadb/schema/tables.h Просмотреть файл

@@ -19,51 +19,5 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type::base_type;
};

namespace __impl
{

/* make_tables_impl */

template<typename T, typename>
struct make_tables_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); }
};

template<typename T_schema>
struct make_tables_impl<
mp::list<T_schema>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value>>
{
template<typename T_index>
static constexpr void emplace(tables_t& tables, const T_schema& schema, T_index&& index)
{
decltype(auto) table = make_table(schema, schema.tables[index]);
using table_type = mp::clean_type<decltype(table)>;
auto key = table.dataset_id;
tables.emplace(key, std::make_unique<table_type>(std::move(table)));
}

template<size_t... I>
static decltype(auto) helper(const T_schema& schema, std::index_sequence<I...>)
{
tables_t tables;
int dummy[] = {0, (emplace(tables, schema, hana::size_c<I>), void(), 0)...};
(void) dummy;
return tables;
}

static constexpr decltype(auto) apply(const T_schema& schema)
{
using size = decltype(hana::size(schema.tables));
return helper(schema, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 55
- 0
include/cpphibernate/driver/mariadb/schema/tables.inl Просмотреть файл

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

#include <cpphibernate/driver/mariadb/schema/tables.h>

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_tables_impl */

template<typename T, typename>
struct make_tables_impl
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); }
};

template<typename T_schema>
struct make_tables_impl<
mp::list<T_schema>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value>>
{
template<typename T_index>
static constexpr void emplace(tables_t& tables, const T_schema& schema, T_index&& index)
{
decltype(auto) table = make_table(schema, schema.tables[index]);
using table_type = mp::clean_type<decltype(table)>;
auto key = table.dataset_id;
tables.emplace(key, std::make_unique<table_type>(std::move(table)));
}

template<size_t... I>
static decltype(auto) helper(const T_schema& schema, std::index_sequence<I...>)
{
tables_t tables;
int dummy[] = {0, (emplace(tables, schema, hana::size_c<I>), void(), 0)...};
(void) dummy;
return tables;
}

static constexpr decltype(auto) apply(const T_schema& schema)
{
using size = decltype(hana::size(schema.tables));
return helper(schema, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 3
- 3
src/driver/mariadb/schema/field.cpp Просмотреть файл

@@ -45,12 +45,12 @@ throw_not_implemented(value_t, foreign_create_update, const create_update_conte

/* properties */

throw_not_implemented(bool, is_default)
throw_not_implemented(bool, is_default, const data_context& context)
throw_not_implemented(string, type)
throw_not_implemented(string, create_table_arguments)
throw_not_implemented(string, generate_value, ::cppmariadb::connection&)
throw_not_implemented(value_t, get)
throw_not_implemented(void, set, const value_t&)
throw_not_implemented(value_t, get, const data_context& context)
throw_not_implemented(void, set, const data_context& context, const value_t&)

bool field_t::is_auto_generated() const
{ return false; }


+ 12
- 9
src/driver/mariadb/schema/table.cpp Просмотреть файл

@@ -512,7 +512,7 @@ std::string table_t::execute_create_update(
}
else
{
primary_key = *primary_key_field->get();
primary_key = *primary_key_field->get(context);
}

/* base_key */
@@ -546,16 +546,15 @@ std::string table_t::execute_create_update(
/* foreign fields */
for (auto& ptr : foreign_key_fields)
{
assert(ptr);
if (is_update && ptr != context.owner_field)
continue;

if ( context.owner_field
&& ptr == context.owner_field)
{
auto& field_info = *ptr;
assert(field_info.table);
assert(field_info.table->primary_key_field);
statement.set(index, field_info.table->primary_key_field->get());
assert(!context.owner_key.empty());
statement.set(index, context.owner_key);
}
else
statement.set_null(index);
@@ -568,8 +567,10 @@ std::string table_t::execute_create_update(
if (is_update && !filter->contains(ptr))
continue;
assert(ptr);

auto& field_info = *ptr;
auto value = field_info.get();
auto value = field_info.get(context);

if (value.has_value()) statement.set(index, *value);
else statement.set_null(index);
++index;
@@ -589,7 +590,7 @@ std::string table_t::execute_create_update(
if (is_update)
{
assert(primary_key_field);
statement.set(index, *primary_key_field->get());
statement.set(index, *primary_key_field->get(context));
++index;
}

@@ -614,7 +615,7 @@ std::string table_t::execute_create_update(
auto count = connection.execute_rows(statement);
cpphibernate_debug_log(count << " rows inserted/updated");
}
primary_key_field->set(primary_key);
primary_key_field->set(context, primary_key);

/* foreign table many fields */
for (auto& ptr : foreign_table_many_fields)
@@ -626,7 +627,9 @@ std::string table_t::execute_create_update(
continue;

auto next_context = context;
next_context.owner_field = ptr;
next_context.owner_field = ptr;
next_context.owner_key = primary_key;
next_context.derived_table = nullptr;
ptr->foreign_create_update(next_context);
}



+ 1
- 1
test/mariadb_mock.cpp Просмотреть файл

@@ -41,7 +41,7 @@ MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res)
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_fields(res) : nullptr); }

int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length)
{ std::cout << std::string(q, length) << ";" << std::endl; return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); }
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); }

unsigned int STDCALL mysql_errno (MYSQL *mysql)
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); }


Загрузка…
Отмена
Сохранить