Browse Source

* implemented init methods of mariadb driver

master
bergmann 5 years ago
parent
commit
1459b6be19
21 changed files with 1435 additions and 64 deletions
  1. +8
    -0
      include/cpphibernate/config.h
  2. +6
    -0
      include/cpphibernate/driver/mariadb/helper.h
  3. +20
    -0
      include/cpphibernate/driver/mariadb/helper/context.h
  4. +50
    -0
      include/cpphibernate/driver/mariadb/helper/key_properties.h
  5. +93
    -0
      include/cpphibernate/driver/mariadb/helper/transaction_lock.h
  6. +346
    -0
      include/cpphibernate/driver/mariadb/helper/type_properties.h
  7. +3
    -0
      include/cpphibernate/driver/mariadb/impl.h
  8. +44
    -0
      include/cpphibernate/driver/mariadb/impl/init.h
  9. +12
    -6
      include/cpphibernate/driver/mariadb/mariadb.h
  10. +3
    -1
      include/cpphibernate/driver/mariadb/schema.h
  11. +36
    -11
      include/cpphibernate/driver/mariadb/schema/field.h
  12. +21
    -0
      include/cpphibernate/driver/mariadb/schema/field.inl
  13. +5
    -1
      include/cpphibernate/driver/mariadb/schema/schema.h
  14. +21
    -5
      include/cpphibernate/driver/mariadb/schema/table.h
  15. +1
    -0
      include/cpphibernate/misc.h
  16. +76
    -0
      include/cpphibernate/misc/nullable_helper.h
  17. +13
    -1
      src/driver/mariadb/schema/field.cpp
  18. +81
    -2
      src/driver/mariadb/schema/schema.cpp
  19. +307
    -0
      src/driver/mariadb/schema/table.cpp
  20. +226
    -0
      test/cpphibernate_init.cpp
  21. +63
    -37
      test/test_schema.h

+ 8
- 0
include/cpphibernate/config.h View File

@@ -3,6 +3,14 @@
#include <boost/hana.hpp>
#include <cpputils/mp/core.h>

#define cpphibernate_debug
#ifdef cpphibernate_debug
# include <cpputils/logging/global.h>
# define cpphibernate_debug_log(...) log_global_message(debug) << __VA_ARGS__
#else
# define cpphibernate_debug_log(...) do { } while(0)
#endif

#define cpphibernate_equality_comparable() \
template<typename T_other> \
constexpr decltype(auto) operator==(T_other&&) const \


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

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

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

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

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

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

beg_namespace_cpphibernate_driver_mariadb
{

/* init_context */

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

}
end_namespace_cpphibernate_driver_mariadb

+ 50
- 0
include/cpphibernate/driver/mariadb/helper/key_properties.h View File

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

#include <cpphibernate/types.h>
#include <cpphibernate/config.h>
#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* key_properties */

template<typename T_key, typename = void>
struct key_properties;

template<>
struct key_properties<uuid, void>
{
using auto_generated = mp::c_false_t;
using key_type = uuid;

static constexpr decltype(auto) create_table_argument = "";
static constexpr decltype(auto) create_key_query = "SELECT Uuid()";
static constexpr decltype(auto) convert_to_open = "UuidToBin(";
static constexpr decltype(auto) convert_to_close = ")";
static constexpr decltype(auto) convert_from_open = "BinToUuid(";
static constexpr decltype(auto) convert_from_close = ")";

static bool is_default(const key_type& key)
{ return key == key_type(); }
};

template<typename T_key>
struct key_properties<T_key, mp::enable_if<mp::is_integral<T_key>>>
{
using auto_generated = mp::c_true_t;
using key_type = T_key;

static constexpr decltype(auto) create_table_argument = "AUTO_INCREMENT";
static constexpr decltype(auto) create_key_query = "";
static constexpr decltype(auto) convert_to_open = "";
static constexpr decltype(auto) convert_to_close = "";
static constexpr decltype(auto) convert_from_open = "";
static constexpr decltype(auto) convert_from_close = "";

static bool is_default(const key_type& key)
{ return key == key_type(); }
};

}
end_namespace_cpphibernate_driver_mariadb

+ 93
- 0
include/cpphibernate/driver/mariadb/helper/transaction_lock.h View File

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

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

beg_namespace_cpphibernate_driver_mariadb
{

struct transaction_lock final
{
public:
inline transaction_lock(::cppmariadb::connection& con)
{ begin_transaction(*this, con); }

inline ~transaction_lock()
{ close_transaction(*this); }

inline bool commit()
{ return commit_transaction(*this); }

private:
using transaction_ptr_type = std::unique_ptr<::cppmariadb::transaction>;

#ifdef cpphibernate_debug
# define debug_log(str) cpphibernate_debug_log( \
"transaction (id=" << std::setw(8) << std::setfill(' ') << lock.id << \
", counter=" << std::setw(2) << std::setfill(' ') << counter << ") " str)
struct counter { };
size_t id { utl::unique_counter<counter>::next() };
#else
# define debug_log(str) do { } while(0)
#endif

static size_t& ref_counter()
{
static size_t value = 0;
return value;
}

static transaction_ptr_type& ref_transaction_ptr()
{
static transaction_ptr_type value;
return value;
}

static void begin_transaction(const transaction_lock& lock, ::cppmariadb::connection& con)
{
auto& counter = ref_counter();
++counter;
debug_log("+++");
if (counter == 1)
{
debug_log("begin");
ref_transaction_ptr().reset(new ::cppmariadb::transaction(con));
}
}

static bool commit_transaction(const transaction_lock& lock)
{
auto& counter = ref_counter();
if (counter == 1)
{
debug_log("commit");
ref_transaction_ptr()->commit();
return true;
}
return false;
}

static void close_transaction(const transaction_lock& lock)
{
auto& counter = ref_counter();
debug_log("---");
if (counter <= 1)
{
debug_log("close");
counter = 0;
ref_transaction_ptr().reset();
}
else
{
--counter;
}
}
};

#undef debug_log

}
end_namespace_cpphibernate_driver_mariadb

+ 346
- 0
include/cpphibernate/driver/mariadb/helper/type_properties.h View File

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

#include <cpphibernate/misc.h>
#include <cpphibernate/types.h>
#include <cpphibernate/config.h>
#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* value_t */

using value_t = utl::nullable<std::string>;

/* type_properties */

template<typename T, typename = void>
struct type_properties
{
static constexpr void type() = delete;
static T convert_to(const value_t&) = delete;
static value_t convert_from(const T&) = delete;
};

template<>
struct type_properties<bool, void>
{
static constexpr decltype(auto) type()
{ return "BOOLEAN"; }

static inline bool convert_to(const value_t& value)
{ return utl::from_string<int>(*value); }

static inline value_t convert_from(const bool& value)
{ return utl::to_string(static_cast<int>(value)); }
};

template<>
struct type_properties<uint8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT UNSIGNED"; }

static inline uint8_t convert_to(const value_t& value)
{ return static_cast<uint8_t>(utl::from_string<int>(*value)); }

static inline value_t convert_from(const uint8_t& value)
{ return utl::to_string(static_cast<int>(value)); }
};

template<>
struct type_properties<int8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT"; }

static inline int8_t convert_to(const value_t& value)
{ return static_cast<int8_t>(utl::from_string<int>(*value)); }

static inline value_t convert_from(const int8_t& value)
{ return utl::to_string(static_cast<int>(value)); }
};

template<>
struct type_properties<uint16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT UNSIGNED"; }

static inline uint16_t convert_to(const value_t& value)
{ return utl::from_string<uint16_t>(*value); }

static inline value_t convert_from(const uint16_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<int16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT"; }

static inline int16_t convert_to(const value_t& value)
{ return utl::from_string<int16_t>(*value); }

static inline value_t convert_from(const int16_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<uint32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT UNSIGNED"; }

static inline uint32_t convert_to(const value_t& value)
{ return utl::from_string<uint32_t>(*value); }

static inline value_t convert_from(const uint32_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<int32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT"; }

static inline int32_t convert_to(const value_t& value)
{ return utl::from_string<int32_t>(*value); }

static inline value_t convert_from(const int32_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<uint64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT UNSIGNED"; }

static inline uint64_t convert_to(const value_t& value)
{ return utl::from_string<uint64_t>(*value); }

static inline value_t convert_from(const uint64_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<int64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT"; }

static inline int64_t convert_to(const value_t& value)
{ return utl::from_string<int64_t>(*value); }

static inline value_t convert_from(const int64_t& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<float, void>
{
static constexpr decltype(auto) type()
{ return "FLOAT"; }

static inline float convert_to(const value_t& value)
{ return utl::from_string<float>(*value); }

static inline value_t convert_from(const float& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<double, void>
{
static constexpr decltype(auto) type()
{ return "DOUBLE"; }

static inline double convert_to(const value_t& value)
{ return utl::from_string<double>(*value); }

static inline value_t convert_from(const double& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<uuid, void>
{
static constexpr decltype(auto) type()
{ return "BINARY(16)"; }

static inline uuid convert_to(const value_t& value)
{ return utl::from_string<uuid>(*value); }

static inline value_t convert_from(const uuid& value)
{ return utl::to_string(value); }
};

template<>
struct type_properties<std::string, void>
{
static constexpr decltype(auto) type()
{ return "VARCHAR(100)"; }

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }
};

template<size_t N>
struct type_properties<string<N>, void>
{
static inline std::string make_type()
{ return std::string("VARCHAR(") + utl::to_string(N) + ")"; }

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }
};

template<typename T>
struct type_properties<T, mp::enable_if<misc::is_nullable<mp::clean_type<T>>>>
{
using nullable_type = T;
using nullable_helper_type = misc::nullable_helper<nullable_type>;
using value_type = typename nullable_helper_type::value_type;
using value_type_props = type_properties<value_type>;

static constexpr decltype(auto) type()
{ return value_type_props::type(); }

static inline nullable_type convert_to(const value_t& value)
{
auto ret = nullable_helper_type::make();
if (value.has_value())
nullable_helper_type::fill(ret, value_type_props::convert_to(value));
return ret;
}

static inline value_t convert_from(const nullable_type& value)
{
value_t ret;
auto v = nullable_helper_type::get(value);
if (v)
ret = value_type_props::convert_from(*v);
return ret;
}
};

template<typename T>
struct type_properties<T, mp::enable_if<std::is_enum<mp::clean_type<T>>>>
{
using enum_type = T;
using base_type = typename std::underlying_type<enum_type>::type;

static std::string make_type()
{
std::ostringstream os;
os << "ENUM ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << utl::enum_conversion<enum_type>::to_string(e, false) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline enum_type convert_to(const value_t& value)
{
enum_type ret;
if (!utl::enum_conversion<enum_type>::try_to_enum(*value, ret, false))
throw misc::hibernate_exception("unable to convert enum value!");
return ret;
}

static inline value_t convert_from(const enum_type& value)
{ return utl::enum_conversion<enum_type>::to_string(value, false); }
};

template<typename T>
struct type_properties<T, mp::enable_if<mp::is_specialization_of<mp::clean_type<T>, utl::flags>>>
{
using flags_type = T;
using enum_type = typename flags_type::enum_type;
using base_type = typename std::underlying_type<enum_type>::type;

static inline std::string make_type()
{
std::ostringstream os;
os << "SET ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << utl::to_string(e) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline flags_type convert_to(const value_t& value)
{
auto s = *value;
auto c = s.c_str();
auto e = c + s.size();
auto p = c;
flags_type ret;
while (c <= e)
{
if (c == e || *c == ',')
{
if (c - p > 0)
ret.set(utl::enum_conversion<enum_type>::to_enum(std::string(p, static_cast<size_t>(c - p)), true));
p = c + 1;
}
++c;
}
return ret;
}

static inline value_t convert_from(const flags_type& value)
{
std::ostringstream os;
bool first = true;
for (auto e : value)
{
if (first) first = false;
else os << ",";
utl::to_string(os, static_cast<int>(e));
}
return os.str();
}
};

}
end_namespace_cpphibernate_driver_mariadb

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

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

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

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

@@ -0,0 +1,44 @@
#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 */

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

context_type context;

constexpr init_impl(T_context&& p_context)
: context(std::forward<T_context>(p_context))
{ }

/* operator() */

inline void operator()() const
{
auto& schema = context.schema;
auto& connection = context.connection;

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

/* make_init_impl */

template<typename T_context>
constexpr decltype(auto) make_init_impl(T_context&& context)
{ return init_impl<T_context>(std::forward<T_context>(context)); }

}
end_namespace_cpphibernate_driver_mariadb

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

@@ -2,11 +2,12 @@

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

beg_namespace_cpphibernate_driver_mariadb
{
struct mariadb_driver_t
{
private:
@@ -23,11 +24,16 @@ beg_namespace_cpphibernate_driver_mariadb
cpphibernate_copyable(mariadb_driver_t, delete);
cpphibernate_moveable(mariadb_driver_t, default);

inline decltype(auto) connection()
{ return _connection; }

inline auto& schema()
{ return _schema; }
protected:
inline void init_impl(bool recreate) const
{
make_init_impl(init_context
{
_schema,
_connection,
recreate
})();
}
};

}

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

@@ -12,4 +12,6 @@
#include <cpphibernate/driver/mariadb/schema/fields.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>
#include <cpphibernate/driver/mariadb/schema/table.h>
#include <cpphibernate/driver/mariadb/schema/tables.h>
#include <cpphibernate/driver/mariadb/schema/tables.h>

#include <cpphibernate/driver/mariadb/schema/field.inl>

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

@@ -5,13 +5,14 @@
#include <cpphibernate/schema/field.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/field.fwd.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
#include <cpphibernate/driver/mariadb/schema/attributes.h>

beg_namespace_cpphibernate_driver_mariadb
{
/* field_t */

struct field_t
@@ -42,9 +43,13 @@ beg_namespace_cpphibernate_driver_mariadb
, table (nullptr)
, referenced_table (nullptr)
{ }
virtual ~field_t() = default;
virtual ~field_t() { };

void print(std::ostream& os) const;

/* properties */
virtual std::string type () const;
virtual std::string create_table_arguments () const;
};

/* simple_field_t */
@@ -72,9 +77,17 @@ beg_namespace_cpphibernate_driver_mariadb
struct value_field_t
: public simple_field_t<T_schema, T_field>
{
using base_type = simple_field_t<T_schema, T_field>;
using base_type = simple_field_t<T_schema, T_field>;
using schema_type = T_schema;
using field_type = T_field;
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 type_props = type_properties<value_type>;

using base_type::base_type;

virtual std::string type() const override;
};

/* primary_key_field_t */
@@ -83,9 +96,15 @@ beg_namespace_cpphibernate_driver_mariadb
struct primary_key_field_t
: public value_field_t<T_schema, T_field>
{
using base_type = value_field_t<T_schema, T_field>;
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 value_type = typename base_type::value_type;
using key_props = key_properties<value_type>;

using base_type::base_type;

virtual std::string create_table_arguments() const override;
};

/* data_field_t */
@@ -179,15 +198,21 @@ beg_namespace_cpphibernate_driver_mariadb
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.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;
}
};


+ 21
- 0
include/cpphibernate/driver/mariadb/schema/field.inl View File

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

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

beg_namespace_cpphibernate_driver_mariadb
{

/* value_field_t */

template<typename T_schema, typename T_field>
std::string value_field_t<T_schema, T_field>::type() const
{ return type_props::type(); }

/* primary_key_field_t */

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::create_table_arguments() const
{ return key_props::create_table_argument; }

}
end_namespace_cpphibernate_driver_mariadb

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

@@ -2,12 +2,13 @@

#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/helper/context.h>
#include <cpphibernate/driver/mariadb/schema/tables.h>
#include <cpphibernate/driver/mariadb/schema/schema.fwd.h>

beg_namespace_cpphibernate_driver_mariadb
{
/* schema_t */

struct schema_t
@@ -24,6 +25,9 @@ beg_namespace_cpphibernate_driver_mariadb

void update ();
void print (std::ostream& os) const;

/* CRUD */
void init(const init_context& context) const;
};

namespace __impl


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

@@ -3,16 +3,18 @@
#include <memory>
#include <vector>

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>
#include <cpphibernate/driver/mariadb/schema/fields.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
#include <cpphibernate/driver/mariadb/helper/context.h>

beg_namespace_cpphibernate_driver_mariadb
{
/* table_t */

struct table_t
@@ -56,9 +58,23 @@ beg_namespace_cpphibernate_driver_mariadb
, foreign_table_many_fields ()
, data_fields ()
{ }
virtual ~table_t() = default;
virtual ~table_t() { };

void print(std::ostream& os) const;

/* CRUD */
inline void init(const init_context& context) const
{ return init_intern(context); }

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

mutable statement_ptr _statement_create_table;

::cppmariadb::statement& get_statement_create_table() const;

protected:
void init_intern(const init_context& context) const;
};

/* table_simple_t */
@@ -70,7 +86,7 @@ beg_namespace_cpphibernate_driver_mariadb
using schema_type = T_schema;
using table_type = T_table;
using base_dataset_type = T_base_dataset;
const schema_type& schema;
const table_type& table;

@@ -98,9 +114,9 @@ beg_namespace_cpphibernate_driver_mariadb
using schema_type = T_schema;
using table_type = T_table;
using base_dataset_type = T_base_dataset;
using base_type::base_type;
const schema_type& schema;
const table_type& table;
};


+ 1
- 0
include/cpphibernate/misc.h View File

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

#include <cpphibernate/misc/general.h>
#include <cpphibernate/misc/meta.h>
#include <cpphibernate/misc/nullable_helper.h>
#include <cpphibernate/misc/print.h>
#include <cpphibernate/misc/wrap.h>

+ 76
- 0
include/cpphibernate/misc/nullable_helper.h View File

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

#include <memory>

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

#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_misc
{

/* nullable_helper */

template<typename T_nullable, typename = void>
struct nullable_helper
{
using nullable_type = T_nullable;
using value_type = real_dataset_t<nullable_type>;

static value_type* get (nullable_type&) = delete;
static void reset (nullable_type&, value_type* value = nullptr) = delete;
};

/* nullable_helper - utl::nullable */

template<typename T_value>
struct nullable_helper<utl::nullable<T_value>, void>
{
using nullable_type = utl::nullable<T_value>;
using value_type = T_value;

static inline value_type* get(nullable_type& x)
{
return x.has_value() ? &x.value() : nullptr;
}

static void reset(nullable_type& x, value_type* value = nullptr)
{
if (value) x.reset();
else x = *value;
}
};

/* nullable_helper - std::unique_ptr */

template<typename T_value>
struct nullable_helper<std::unique_ptr<T_value>, void>
{
using nullable_type = std::unique_ptr<T_value>;
using value_type = T_value;

static inline value_type* get(nullable_type& x)
{ return x.get(); }

static void reset(nullable_type& x, value_type* value = nullptr)
{ return x.reset(value); }
};

/* nullable_helper - std::shared_ptr */

template<typename T_value>
struct nullable_helper<std::shared_ptr<T_value>, void>
{
using nullable_type = std::shared_ptr<T_value>;
using value_type = T_value;

static inline value_type* get(nullable_type& x)
{ return x.get(); }

static void reset(nullable_type& x, value_type* value = nullptr)
{ return x.reset(value); }
};

}
end_namespace_cpphibernate_misc

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

@@ -9,6 +9,7 @@
#include <cpphibernate/driver/mariadb/schema/field.h>
#include <cpphibernate/driver/mariadb/schema/table.h>

using namespace ::std;
using namespace ::utl;
using namespace ::cpphibernate::driver::mariadb_impl;

@@ -28,4 +29,15 @@ void field_t::print(std::ostream& os) const
<< indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null")
<< decindent
<< indent << '}';
}
}

#define throw_not_implemented(p_ret, p_name) \
p_ret field_t::p_name() const \
{ \
throw misc::hibernate_exception( \
std::string("'") + table_name + "." + field_name + \
"' does not implement the " #p_name "() method!"); \
}

throw_not_implemented(string, type)
throw_not_implemented(string, create_table_arguments)

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

@@ -1,5 +1,5 @@
#include <string>
#include <iostream>
#include <sstream>

#include <cpputils/misc/enum.h>
#include <cpputils/misc/string.h>
@@ -109,4 +109,83 @@ void schema_t::print(std::ostream& os) const
})
<< decindent
<< indent << '}';
}
}

#define exec_query() \
do { \
cpphibernate_debug_log("execute init query: " << ss.str()); \
connection.execute(ss.str()); \
ss.str(std::string()); \
ss.clear(); \
} while(0)

void schema_t::init(const init_context& context) const
{
std::ostringstream ss;
auto& connection = context.connection;

if (context.recreate)
{
ss << "DROP DATABASE IF EXISTS `"
<< schema_name
<< "`";
exec_query();
}

/* create schema */
ss << "CREATE SCHEMA IF NOT EXISTS `"
<< schema_name
<< "` DEFAULT CHARACTER SET utf8";
exec_query();

/* use schema */
ss << "USE `"
<< schema_name
<< "`";
exec_query();

/* UuidToBin */
ss << "CREATE FUNCTION IF NOT EXISTS UuidToBin(_uuid CHAR(36))\n"
" RETURNS BINARY(16)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" UNHEX(CONCAT(\n"
" SUBSTR(_uuid, 25, 12),\n" // node id
" SUBSTR(_uuid, 20, 4),\n" // clock sequence
" SUBSTR(_uuid, 15, 4),\n" // time high and version
" SUBSTR(_uuid, 10, 4),\n" // time mid
" SUBSTR(_uuid, 1, 8)\n" // time low
" )\n"
")";
exec_query();

/* BinToUuid */
ss << "CREATE FUNCTION IF NOT EXISTS BinToUuid(_bin BINARY(16))\n"
" RETURNS CHAR(36)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" LCASE(CONCAT_WS('-',\n"
" HEX(SUBSTR(_bin, 13, 4)),\n" // time low
" HEX(SUBSTR(_bin, 11, 2)),\n" // time mid
" HEX(SUBSTR(_bin, 9, 2)),\n" // time high and version
" HEX(SUBSTR(_bin, 7, 2)),\n" // clock sequence
" HEX(SUBSTR(_bin, 1, 6))\n" // node id
" )\n"
")";
exec_query();

/* initialize tables */
for (auto& kvp : tables)
{
assert(kvp.second);
kvp.second->init(context);
}
}

#undef exec_query

+ 307
- 0
src/driver/mariadb/schema/table.cpp View File

@@ -46,4 +46,311 @@ void table_t::print(std::ostream& os) const
})
<< decindent
<< indent << '}';
}

::cppmariadb::statement& table_t::get_statement_create_table() const
{
if (_statement_create_table)
return *_statement_create_table;

std::ostringstream os;

/* CREATE TABLE */
os << "CREATE TABLE IF NOT EXISTS `"
<< table_name
<< "`"
<< indent
<< "("
<< incindent;

/* primary key */
{
assert(primary_key_field);
auto& key_info = *primary_key_field;
auto args = key_info.create_table_arguments();
os << indent
<< "`"
<< key_info.field_name
<< "` "
<< key_info.type()
<< " NOT NULL"
<< (args.empty() ? "" : " ")
<< args
<< ",";
}

/* base table key fields */
if (static_cast<bool>(base_table))
{
auto& base_table_info = *base_table;
assert(base_table_info.primary_key_field);
auto& key_info = *base_table_info.primary_key_field;
os << indent
<< "`"
<< key_info.field_name
<< "` "
<< key_info.type()
<< " NOT NULL,";
}

/* foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
assert(field_info.referenced_table);
assert(field_info.referenced_table->primary_key_field);
auto& ref_key_info = *field_info.referenced_table->primary_key_field;
os << indent
<< "`"
<< ref_key_info.table_name
<< "_id_"
<< field_info.field_name
<< "` "
<< ref_key_info.type()
<< (field_info.value_is_nullable
? " NULL DEFAULT NULL,"
: " NOT NULL,");
}

/* foreign fields */
for (auto& ptr : foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
assert(field_info.table);
assert(field_info.table->primary_key_field);
auto& ref_key_info = *field_info.table->primary_key_field;
os << indent
<< "`"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "` "
<< ref_key_info.type()
<< " NULL DEFAULT NULL,";
}

/* data fields */
for (auto& ptr : data_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
os << indent
<< "`"
<< field_info.field_name
<< "` "
<< field_info.type()
<< (field_info.value_is_nullable
? " NULL DEFAULT NULL,"
: " NOT NULL,");
}

/* type field for derived tables */
if (!derived_tables.empty() &&
!base_table)
{
os << indent
<< "`__type` INT UNSIGNED NOT NULL,";
}

/* PRIMARY KEY */
{
os << indent
<< "PRIMARY KEY ( `"
<< primary_key_field->field_name
<< "` )";
}

/* UNIQUE INDEX primary key */
os << ','
<< indent
<< "UNIQUE INDEX `index_"
<< primary_key_field->field_name
<< "` ( `"
<< primary_key_field->field_name
<< "` ASC )";

/* UNIQUE INDEX base table keys */
if (base_table)
{
auto& table_info = *base_table;
auto& key_info = *table_info.primary_key_field;
os << ','
<< indent
<< "UNIQUE INDEX `index_"
<< key_info.field_name
<< "` ( `"
<< key_info.field_name
<< "` ASC )";
}

/* INDEX foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
assert(field_info.referenced_table);
assert(field_info.referenced_table->primary_key_field);
auto& ref_key_info = *field_info.referenced_table->primary_key_field;
os << ","
<< indent
<< "INDEX `index_"
<< ref_key_info.table_name
<< "_id_"
<< field_info.field_name
<< "` ( `"
<< ref_key_info.table_name
<< "_id_"
<< field_info.field_name
<< "` ASC )";
}

/* INDEX foreign fields */
for (auto& ptr : foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
os << ","
<< indent
<< "INDEX `index_"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "` ( `"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "` ASC )";
}

/* CONSTRAINT base table */
if (base_table)
{
assert(base_table->primary_key_field);
auto& ref_key_info = *base_table->primary_key_field;
os << ","
<< indent
<< "CONSTRAINT `fk_"
<< table_name
<< "_to_"
<< ref_key_info.field_name
<< "`"
<< incindent
<< indent
<< "FOREIGN KEY (`"
<< ref_key_info.field_name
<< "`)"
<< indent
<< "REFERENCES `"
<< ref_key_info.schema_name
<< "`.`"
<< ref_key_info.table_name
<< "` (`"
<< ref_key_info.field_name
<< "`)"
<< indent
<< "ON DELETE CASCADE"
<< indent
<< "ON UPDATE NO ACTION"
<< decindent;
}

/* CONSTRAINT foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
assert(field_info.referenced_table);
assert(field_info.referenced_table->primary_key_field);
auto& ref_key_info = *field_info.referenced_table->primary_key_field;
os << ","
<< indent
<< "CONSTRAINT `fk_"
<< table_name
<< "_to_"
<< ref_key_info.table_name
<< "_id_"
<< field_info.field_name
<< "`"
<< incindent
<< indent
<< "FOREIGN KEY (`"
<< ref_key_info.table_name
<< "_id_"
<< field_info.field_name
<< "`)"
<< indent
<< "REFERENCES `"
<< ref_key_info.schema_name
<< "`.`"
<< ref_key_info.table_name
<< "` (`"
<< ref_key_info.field_name
<< "`)"
<< indent
<< "ON DELETE CASCADE"
<< indent
<< "ON UPDATE NO ACTION"
<< decindent;
}

/* CONSTRAINT foreign fields */
for (auto& ptr : foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
assert(field_info.table);
assert(field_info.table->primary_key_field);
auto& ref_key_info = *field_info.table->primary_key_field;
os << ","
<< indent
<< "CONSTRAINT `fk_"
<< table_name
<< "_"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "`"
<< incindent
<< indent
<< "FOREIGN KEY (`"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "`)"
<< indent
<< "REFERENCES `"
<< ref_key_info.schema_name
<< "`.`"
<< ref_key_info.table_name
<< "` (`"
<< ref_key_info.field_name
<< "`)"
<< indent
<< "ON DELETE SET NULL"
<< indent
<< "ON UPDATE NO ACTION"
<< decindent;
}

/* CREATE TABLE end */
os << decindent
<< indent
<< ")"
<< indent
<< "ENGINE = InnoDB"
<< indent
<< "DEFAULT CHARACTER SET = utf8";

_statement_create_table.reset(new ::cppmariadb::statement(os.str()));
return *_statement_create_table;
}

void table_t::init_intern(const init_context& context) const
{
auto& statement = get_statement_create_table();
auto& connection = context.connection;
cpphibernate_debug_log("execute init query: " << statement.query(connection));
connection.execute(statement);
}

+ 226
- 0
test/cpphibernate_init.cpp View File

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

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

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

template<typename T_mock>
inline void expect_query(T_mock& mock, const std::string& query)
{
EXPECT_CALL(
mock,
mysql_real_query(
reinterpret_cast<MYSQL*>(0x1111),
StrEq(query),
query.size()));

EXPECT_CALL(
mock,
mysql_store_result(
reinterpret_cast<MYSQL*>(0x1111)))
.WillOnce(Return(reinterpret_cast<MYSQL_RES*>(0x2222)));

EXPECT_CALL(
mock,
mysql_free_result(
reinterpret_cast<MYSQL_RES*>(0x2222)));
}

TEST(CppHibernateTests, init)
{
StrictMock<MariaDbMock> mock;

InSequence seq;
expect_query(mock, "START TRANSACTION");
expect_query(mock, "DROP DATABASE IF EXISTS `test`");
expect_query(mock, "CREATE SCHEMA IF NOT EXISTS `test` DEFAULT CHARACTER SET utf8");
expect_query(mock, "USE `test`");

expect_query(mock, "CREATE FUNCTION IF NOT EXISTS UuidToBin(_uuid CHAR(36))\n"
" RETURNS BINARY(16)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" UNHEX(CONCAT(\n"
" SUBSTR(_uuid, 25, 12),\n"
" SUBSTR(_uuid, 20, 4),\n"
" SUBSTR(_uuid, 15, 4),\n"
" SUBSTR(_uuid, 10, 4),\n"
" SUBSTR(_uuid, 1, 8)\n"
" )\n"
")");

expect_query(mock, "CREATE FUNCTION IF NOT EXISTS BinToUuid(_bin BINARY(16))\n"
" RETURNS CHAR(36)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" LCASE(CONCAT_WS('-',\n"
" HEX(SUBSTR(_bin, 13, 4)),\n"
" HEX(SUBSTR(_bin, 11, 2)),\n"
" HEX(SUBSTR(_bin, 9, 2)),\n"
" HEX(SUBSTR(_bin, 7, 2)),\n"
" HEX(SUBSTR(_bin, 1, 6))\n"
" )\n"
")");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_test1`\n"
"(\n"
" `tbl_test1_id` BINARY(16) NOT NULL,\n"
" `str_data` VARCHAR(100) NOT NULL,\n"
" `str64_data` VARCHAR(64) NOT NULL,\n"
" `u32_nullable` INT UNSIGNED NULL DEFAULT NULL,\n"
" `u32_ptr_u` INT UNSIGNED NULL DEFAULT NULL,\n"
" `u32_ptr_s` INT UNSIGNED NULL DEFAULT NULL,\n"
" PRIMARY KEY ( `tbl_test1_id` ),\n"
" UNIQUE INDEX `index_tbl_test1_id` ( `tbl_test1_id` ASC )\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_test2`\n"
"(\n"
" `tbl_test2_id` BINARY(16) NOT NULL,\n"
" `u8_data` TINYINT UNSIGNED NOT NULL,\n"
" `i8_data` TINYINT NOT NULL,\n"
" `u16_data` SMALLINT UNSIGNED NOT NULL,\n"
" `i16_data` SMALLINT NOT NULL,\n"
" PRIMARY KEY ( `tbl_test2_id` ),\n"
" UNIQUE INDEX `index_tbl_test2_id` ( `tbl_test2_id` ASC )\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_test3`\n"
"(\n"
" `tbl_test3_id` BINARY(16) NOT NULL,\n"
" `tbl_derived3_id_test3_list` BINARY(16) NULL DEFAULT NULL,\n"
" `tbl_derived3_id_test3_vector` BINARY(16) NULL DEFAULT NULL,\n"
" `u32_data` INT UNSIGNED NOT NULL,\n"
" `i32_data` INT NOT NULL,\n"
" `u64_data` BIGINT UNSIGNED NOT NULL,\n"
" `i64_data` BIGINT NOT NULL,\n"
" PRIMARY KEY ( `tbl_test3_id` ),\n"
" UNIQUE INDEX `index_tbl_test3_id` ( `tbl_test3_id` ASC ),\n"
" INDEX `index_tbl_derived3_id_test3_list` ( `tbl_derived3_id_test3_list` ASC ),\n"
" INDEX `index_tbl_derived3_id_test3_vector` ( `tbl_derived3_id_test3_vector` ASC ),\n"
" CONSTRAINT `fk_tbl_test3_tbl_derived3_id_test3_list`\n"
" FOREIGN KEY (`tbl_derived3_id_test3_list`)\n"
" REFERENCES `test`.`tbl_derived3` (`tbl_derived3_id`)\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION,\n"
" CONSTRAINT `fk_tbl_test3_tbl_derived3_id_test3_vector`\n"
" FOREIGN KEY (`tbl_derived3_id_test3_vector`)\n"
" REFERENCES `test`.`tbl_derived3` (`tbl_derived3_id`)\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_base`\n"
"(\n"
" `tbl_base_id` BINARY(16) NOT NULL,\n"
" `name` VARCHAR(100) NOT NULL,\n"
" `__type` INT UNSIGNED NOT NULL,\n"
" PRIMARY KEY ( `tbl_base_id` ),\n"
" UNIQUE INDEX `index_tbl_base_id` ( `tbl_base_id` ASC )\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_derived1`\n"
"(\n"
" `tbl_derived1_id` BINARY(16) NOT NULL,\n"
" `tbl_base_id` BINARY(16) NOT NULL,\n"
" `tbl_test1_id_test1_data` BINARY(16) NOT NULL,\n"
" `enum_data` ENUM ( 'test0', 'test1', 'test2', 'test3' ) NOT NULL,\n"
" PRIMARY KEY ( `tbl_derived1_id` ),\n"
" UNIQUE INDEX `index_tbl_derived1_id` ( `tbl_derived1_id` ASC ),\n"
" UNIQUE INDEX `index_tbl_base_id` ( `tbl_base_id` ASC ),\n"
" INDEX `index_tbl_test1_id_test1_data` ( `tbl_test1_id_test1_data` ASC ),\n"
" CONSTRAINT `fk_tbl_derived1_to_tbl_base_id`\n"
" FOREIGN KEY (`tbl_base_id`)\n"
" REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION,\n"
" 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 UPDATE NO ACTION\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_derived2`\n"
"(\n"
" `tbl_derived2_id` BINARY(16) NOT NULL,\n"
" `tbl_base_id` BINARY(16) NOT NULL,\n"
" `tbl_test2_id_test2_nullable` BINARY(16) NULL DEFAULT NULL,\n"
" `tbl_test2_id_test2_ptr_u` BINARY(16) NULL DEFAULT NULL,\n"
" `tbl_test2_id_test2_ptr_s` BINARY(16) NULL DEFAULT NULL,\n"
" PRIMARY KEY ( `tbl_derived2_id` ),\n"
" UNIQUE INDEX `index_tbl_derived2_id` ( `tbl_derived2_id` ASC ),\n"
" UNIQUE INDEX `index_tbl_base_id` ( `tbl_base_id` ASC ),\n"
" INDEX `index_tbl_test2_id_test2_nullable` ( `tbl_test2_id_test2_nullable` ASC ),\n"
" INDEX `index_tbl_test2_id_test2_ptr_u` ( `tbl_test2_id_test2_ptr_u` ASC ),\n"
" INDEX `index_tbl_test2_id_test2_ptr_s` ( `tbl_test2_id_test2_ptr_s` ASC ),\n"
" CONSTRAINT `fk_tbl_derived2_to_tbl_base_id`\n"
" FOREIGN KEY (`tbl_base_id`)\n"
" REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION,\n"
" 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 UPDATE NO ACTION,\n"
" 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 UPDATE NO ACTION,\n"
" 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 UPDATE NO ACTION\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_derived3`\n"
"(\n"
" `tbl_derived3_id` BINARY(16) NOT NULL,\n"
" `tbl_derived1_id` BINARY(16) NOT NULL,\n"
" PRIMARY KEY ( `tbl_derived3_id` ),\n"
" UNIQUE INDEX `index_tbl_derived3_id` ( `tbl_derived3_id` ASC ),\n"
" UNIQUE INDEX `index_tbl_derived1_id` ( `tbl_derived1_id` ASC ),\n"
" CONSTRAINT `fk_tbl_derived3_to_tbl_derived1_id`\n"
" FOREIGN KEY (`tbl_derived1_id`)\n"
" REFERENCES `test`.`tbl_derived1` (`tbl_derived1_id`)\n"
" ON DELETE CASCADE\n"
" ON UPDATE NO ACTION\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

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

test/cpphibernate.cpp → test/test_schema.h View File

@@ -1,62 +1,91 @@
#include <gtest/gtest.h>
#include <cpphibernate.h>
#include <cpphibernate/driver/mariadb.h>

using namespace ::cpphibernate;
enum class test_enum
{
test0,
test1,
test2,
test3,

first = test0,
last = test3,
};

DEFINE_ENUM_TO_STRING_MAP(
test_enum,
{ test_enum::test0, "test0" },
{ test_enum::test1, "test1" },
{ test_enum::test2, "test2" },
{ test_enum::test3, "test3" }
);

DEFINE_STRING_TO_ENUM_MAP(
test_enum,
invariant_string_less,
{ "test0", test_enum::test0 },
{ "test1", test_enum::test1 },
{ "test2", test_enum::test2 },
{ "test3", test_enum::test3 }
);

struct test1
{
uuid id;
std::string str_data;
string<64> str64_data;
::cpphibernate::uuid id;
std::string str_data;
::cpphibernate::string<64> str64_data;

utl::nullable<uint32_t> u32_nullable;
std::unique_ptr<uint32_t> u32_ptr_u;
std::shared_ptr<uint32_t> u32_ptr_s;
};

struct test2
{
uuid id;
uint8_t u8_data;
int8_t i8_data;
uint16_t u16_data;
int16_t i16_data;
::cpphibernate::uuid id;
uint8_t u8_data;
int8_t i8_data;
uint16_t u16_data;
int16_t i16_data;
};

struct test3
{
uuid id;
uint32_t u32_data;
int32_t i32_data;
uint64_t u64_data;
int64_t i64_data;
::cpphibernate::uuid id;
uint32_t u32_data;
int32_t i32_data;
uint64_t u64_data;
int64_t i64_data;
};

struct base
{
uuid id;
std::string name;
::cpphibernate::uuid id;
std::string name;
};

struct derived1
: public base
{
uuid derived1_id;
test1 test1_data;
::cpphibernate::uuid derived1_id;
test1 test1_data;
test_enum enum_data;
};

struct derived2
: public base
{
uuid derived2_id;
utl::nullable<test2> test2_nullable;
std::unique_ptr<test2> test2_ptr_u;
std::shared_ptr<test2> test2_ptr_s;
::cpphibernate::uuid derived2_id;
utl::nullable<test2> test2_nullable;
std::unique_ptr<test2> test2_ptr_u;
std::shared_ptr<test2> test2_ptr_s;
};

struct derived3
: public derived1
{
uuid derived3_id;
std::list<test3> test3_list;
std::vector<test3> test3_vector;
::cpphibernate::uuid derived3_id;
std::list<test3> test3_list;
std::vector<test3> test3_vector;
};

constexpr decltype(auto) test_schema = cpphibernate_make_schema(
@@ -67,7 +96,10 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema(
1,
cpphibernate_make_id (&test1::id),
cpphibernate_make_field (test1, str_data),
cpphibernate_make_field (test1, str64_data)
cpphibernate_make_field (test1, str64_data),
cpphibernate_make_field (test1, u32_nullable),
cpphibernate_make_field (test1, u32_ptr_u),
cpphibernate_make_field (test1, u32_ptr_s)
),
cpphibernate_make_table_name(
tbl_test2,
@@ -102,7 +134,8 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema(
derived1,
11,
cpphibernate_make_id (&derived1::derived1_id),
cpphibernate_make_field (derived1, test1_data)
cpphibernate_make_field (derived1, test1_data),
cpphibernate_make_field (derived1, enum_data)
),
cpphibernate_make_table_name(
tbl_derived2,
@@ -121,11 +154,4 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema(
cpphibernate_make_field (derived3, test3_list),
cpphibernate_make_field (derived3, test3_vector)
)
);

TEST(CppHibernateTests, fuuu)
{
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1234));
auto context = make_context<driver::mariadb>(test_schema, connection);
std::cout << context.schema() << std::endl;
}
);

Loading…
Cancel
Save