From 1459b6be19bb7a12c2a6cf86de1d33839e29a5c2 Mon Sep 17 00:00:00 2001 From: bergmann Date: Thu, 23 Aug 2018 23:10:14 +0200 Subject: [PATCH] * implemented init methods of mariadb driver --- include/cpphibernate/config.h | 8 + include/cpphibernate/driver/mariadb/helper.h | 6 + .../driver/mariadb/helper/context.h | 20 + .../driver/mariadb/helper/key_properties.h | 50 +++ .../driver/mariadb/helper/transaction_lock.h | 93 +++++ .../driver/mariadb/helper/type_properties.h | 346 ++++++++++++++++++ include/cpphibernate/driver/mariadb/impl.h | 3 + .../cpphibernate/driver/mariadb/impl/init.h | 44 +++ include/cpphibernate/driver/mariadb/mariadb.h | 18 +- include/cpphibernate/driver/mariadb/schema.h | 4 +- .../driver/mariadb/schema/field.h | 47 ++- .../driver/mariadb/schema/field.inl | 21 ++ .../driver/mariadb/schema/schema.h | 6 +- .../driver/mariadb/schema/table.h | 26 +- include/cpphibernate/misc.h | 1 + include/cpphibernate/misc/nullable_helper.h | 76 ++++ src/driver/mariadb/schema/field.cpp | 14 +- src/driver/mariadb/schema/schema.cpp | 83 ++++- src/driver/mariadb/schema/table.cpp | 307 ++++++++++++++++ test/cpphibernate_init.cpp | 226 ++++++++++++ test/{cpphibernate.cpp => test_schema.h} | 100 +++-- 21 files changed, 1435 insertions(+), 64 deletions(-) create mode 100644 include/cpphibernate/driver/mariadb/helper.h create mode 100644 include/cpphibernate/driver/mariadb/helper/context.h create mode 100644 include/cpphibernate/driver/mariadb/helper/key_properties.h create mode 100644 include/cpphibernate/driver/mariadb/helper/transaction_lock.h create mode 100644 include/cpphibernate/driver/mariadb/helper/type_properties.h create mode 100644 include/cpphibernate/driver/mariadb/impl.h create mode 100644 include/cpphibernate/driver/mariadb/impl/init.h create mode 100644 include/cpphibernate/driver/mariadb/schema/field.inl create mode 100644 include/cpphibernate/misc/nullable_helper.h create mode 100644 test/cpphibernate_init.cpp rename test/{cpphibernate.cpp => test_schema.h} (51%) diff --git a/include/cpphibernate/config.h b/include/cpphibernate/config.h index 3e724da..e2092b6 100644 --- a/include/cpphibernate/config.h +++ b/include/cpphibernate/config.h @@ -3,6 +3,14 @@ #include #include +#define cpphibernate_debug +#ifdef cpphibernate_debug +# include +# define cpphibernate_debug_log(...) log_global_message(debug) << __VA_ARGS__ +#else +# define cpphibernate_debug_log(...) do { } while(0) +#endif + #define cpphibernate_equality_comparable() \ template \ constexpr decltype(auto) operator==(T_other&&) const \ diff --git a/include/cpphibernate/driver/mariadb/helper.h b/include/cpphibernate/driver/mariadb/helper.h new file mode 100644 index 0000000..322dbe8 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/helper.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/helper/context.h b/include/cpphibernate/driver/mariadb/helper/context.h new file mode 100644 index 0000000..9308e5f --- /dev/null +++ b/include/cpphibernate/driver/mariadb/helper/context.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* init_context */ + + struct init_context + { + const schema_t& schema; + ::cppmariadb::connection& connection; + bool recreate; + }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/helper/key_properties.h b/include/cpphibernate/driver/mariadb/helper/key_properties.h new file mode 100644 index 0000000..87498b4 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/helper/key_properties.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* key_properties */ + + template + struct key_properties; + + template<> + struct key_properties + { + 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 + struct key_properties>> + { + 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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/helper/transaction_lock.h b/include/cpphibernate/driver/mariadb/helper/transaction_lock.h new file mode 100644 index 0000000..8df9148 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/helper/transaction_lock.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include +#include +#include + +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::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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/helper/type_properties.h b/include/cpphibernate/driver/mariadb/helper/type_properties.h new file mode 100644 index 0000000..33d1221 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/helper/type_properties.h @@ -0,0 +1,346 @@ +#pragma once + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* value_t */ + + using value_t = utl::nullable; + + /* type_properties */ + + template + 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 + { + static constexpr decltype(auto) type() + { return "BOOLEAN"; } + + static inline bool convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const bool& value) + { return utl::to_string(static_cast(value)); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "TINYINT UNSIGNED"; } + + static inline uint8_t convert_to(const value_t& value) + { return static_cast(utl::from_string(*value)); } + + static inline value_t convert_from(const uint8_t& value) + { return utl::to_string(static_cast(value)); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "TINYINT"; } + + static inline int8_t convert_to(const value_t& value) + { return static_cast(utl::from_string(*value)); } + + static inline value_t convert_from(const int8_t& value) + { return utl::to_string(static_cast(value)); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "SMALLINT UNSIGNED"; } + + static inline uint16_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const uint16_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "SMALLINT"; } + + static inline int16_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const int16_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "INT UNSIGNED"; } + + static inline uint32_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const uint32_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "INT"; } + + static inline int32_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const int32_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "BIGINT UNSIGNED"; } + + static inline uint64_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const uint64_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "BIGINT"; } + + static inline int64_t convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const int64_t& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "FLOAT"; } + + static inline float convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const float& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "DOUBLE"; } + + static inline double convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const double& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + static constexpr decltype(auto) type() + { return "BINARY(16)"; } + + static inline uuid convert_to(const value_t& value) + { return utl::from_string(*value); } + + static inline value_t convert_from(const uuid& value) + { return utl::to_string(value); } + }; + + template<> + struct type_properties + { + 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 + struct type_properties, 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 + struct type_properties>>> + { + using nullable_type = T; + using nullable_helper_type = misc::nullable_helper; + using value_type = typename nullable_helper_type::value_type; + using value_type_props = type_properties; + + 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 + struct type_properties>>> + { + using enum_type = T; + using base_type = typename std::underlying_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::to_string(e, false) << "'"; + e = static_cast(static_cast(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::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::to_string(value, false); } + }; + + template + struct type_properties, utl::flags>>> + { + using flags_type = T; + using enum_type = typename flags_type::enum_type; + using base_type = typename std::underlying_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(static_cast(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::to_enum(std::string(p, static_cast(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(e)); + } + return os.str(); + } + }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/impl.h b/include/cpphibernate/driver/mariadb/impl.h new file mode 100644 index 0000000..a1d6c8a --- /dev/null +++ b/include/cpphibernate/driver/mariadb/impl.h @@ -0,0 +1,3 @@ +#pragma once + +#include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/impl/init.h b/include/cpphibernate/driver/mariadb/impl/init.h new file mode 100644 index 0000000..af23e78 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/impl/init.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* init_impl */ + + template + struct init_impl + { + using context_type = T_context; + + context_type context; + + constexpr init_impl(T_context&& p_context) + : context(std::forward(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 + constexpr decltype(auto) make_init_impl(T_context&& context) + { return init_impl(std::forward(context)); } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/mariadb.h b/include/cpphibernate/driver/mariadb/mariadb.h index 4bd6da5..ea503e3 100644 --- a/include/cpphibernate/driver/mariadb/mariadb.h +++ b/include/cpphibernate/driver/mariadb/mariadb.h @@ -2,11 +2,12 @@ #include #include +#include #include 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 + })(); + } }; } diff --git a/include/cpphibernate/driver/mariadb/schema.h b/include/cpphibernate/driver/mariadb/schema.h index 17d8626..6eee3d8 100644 --- a/include/cpphibernate/driver/mariadb/schema.h +++ b/include/cpphibernate/driver/mariadb/schema.h @@ -12,4 +12,6 @@ #include #include #include -#include \ No newline at end of file +#include + +#include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/field.h b/include/cpphibernate/driver/mariadb/schema/field.h index 0274f1d..a6e9775 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.h +++ b/include/cpphibernate/driver/mariadb/schema/field.h @@ -5,13 +5,14 @@ #include #include #include +#include #include #include #include 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 { - using base_type = simple_field_t; + using base_type = simple_field_t; + using schema_type = T_schema; + using field_type = T_field; + using getter_type = typename mp::decay_t::getter_type; + using dataset_type = typename getter_type::dataset_type; + using value_type = typename getter_type::value_type; + using type_props = type_properties; 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 { - using base_type = value_field_t; + using base_type = value_field_t; + 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; 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; using value_dataset_type = misc::real_dataset_t; using return_type = field_type_t; + using primary_key_type = primary_key_field_t; return_type ret(schema, field); - ret.table_dataset_id = misc::get_type_id(hana::type_c), - ret.value_dataset_id = misc::get_type_id(hana::type_c), - ret.value_is_nullable = misc::is_nullable::value, - ret.value_is_container = misc::is_container::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); + ret.value_dataset_id = misc::get_type_id(hana::type_c); + ret.value_is_nullable = misc::is_nullable::value; + ret.value_is_container = misc::is_container::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, hana::type_c), + [&ret](){ + ret.field_name = ret.table_name + "_" + ret.field_name; + }, [](){ }); return ret; } }; diff --git a/include/cpphibernate/driver/mariadb/schema/field.inl b/include/cpphibernate/driver/mariadb/schema/field.inl new file mode 100644 index 0000000..999703c --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/field.inl @@ -0,0 +1,21 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* value_field_t */ + + template + std::string value_field_t::type() const + { return type_props::type(); } + + /* primary_key_field_t */ + + template + std::string primary_key_field_t::create_table_arguments() const + { return key_props::create_table_argument; } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/schema.h b/include/cpphibernate/driver/mariadb/schema/schema.h index a59c559..317ab64 100644 --- a/include/cpphibernate/driver/mariadb/schema/schema.h +++ b/include/cpphibernate/driver/mariadb/schema/schema.h @@ -2,12 +2,13 @@ #include #include +#include #include #include 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 diff --git a/include/cpphibernate/driver/mariadb/schema/table.h b/include/cpphibernate/driver/mariadb/schema/table.h index c758d9a..e675b24 100644 --- a/include/cpphibernate/driver/mariadb/schema/table.h +++ b/include/cpphibernate/driver/mariadb/schema/table.h @@ -3,16 +3,18 @@ #include #include +#include #include #include #include #include #include #include +#include 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; }; diff --git a/include/cpphibernate/misc.h b/include/cpphibernate/misc.h index c556322..2d226d2 100644 --- a/include/cpphibernate/misc.h +++ b/include/cpphibernate/misc.h @@ -2,5 +2,6 @@ #include #include +#include #include #include \ No newline at end of file diff --git a/include/cpphibernate/misc/nullable_helper.h b/include/cpphibernate/misc/nullable_helper.h new file mode 100644 index 0000000..8b4a73c --- /dev/null +++ b/include/cpphibernate/misc/nullable_helper.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include +#include + +#include + +beg_namespace_cpphibernate_misc +{ + + /* nullable_helper */ + + template + struct nullable_helper + { + using nullable_type = T_nullable; + using value_type = real_dataset_t; + + static value_type* get (nullable_type&) = delete; + static void reset (nullable_type&, value_type* value = nullptr) = delete; + }; + + /* nullable_helper - utl::nullable */ + + template + struct nullable_helper, void> + { + using nullable_type = utl::nullable; + 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 + struct nullable_helper, void> + { + using nullable_type = std::unique_ptr; + 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 + struct nullable_helper, void> + { + using nullable_type = std::shared_ptr; + 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 \ No newline at end of file diff --git a/src/driver/mariadb/schema/field.cpp b/src/driver/mariadb/schema/field.cpp index 3c27579..f56ca81 100644 --- a/src/driver/mariadb/schema/field.cpp +++ b/src/driver/mariadb/schema/field.cpp @@ -9,6 +9,7 @@ #include #include +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 << '}'; -} \ No newline at end of file +} + +#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) diff --git a/src/driver/mariadb/schema/schema.cpp b/src/driver/mariadb/schema/schema.cpp index f790180..5273a07 100644 --- a/src/driver/mariadb/schema/schema.cpp +++ b/src/driver/mariadb/schema/schema.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -109,4 +109,83 @@ void schema_t::print(std::ostream& os) const }) << decindent << indent << '}'; -} \ No newline at end of file +} + +#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 \ No newline at end of file diff --git a/src/driver/mariadb/schema/table.cpp b/src/driver/mariadb/schema/table.cpp index 30eca9f..d50dc5e 100644 --- a/src/driver/mariadb/schema/table.cpp +++ b/src/driver/mariadb/schema/table.cpp @@ -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(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(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(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(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(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(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(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(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); } \ No newline at end of file diff --git a/test/cpphibernate_init.cpp b/test/cpphibernate_init.cpp new file mode 100644 index 0000000..1b61078 --- /dev/null +++ b/test/cpphibernate_init.cpp @@ -0,0 +1,226 @@ +#include +#include + +#include "test_schema.h" +#include "mariadb_mock.h" + +using namespace ::testing; +using namespace ::cpphibernate; + +template +inline void expect_query(T_mock& mock, const std::string& query) +{ + EXPECT_CALL( + mock, + mysql_real_query( + reinterpret_cast(0x1111), + StrEq(query), + query.size())); + + EXPECT_CALL( + mock, + mysql_store_result( + reinterpret_cast(0x1111))) + .WillOnce(Return(reinterpret_cast(0x2222))); + + EXPECT_CALL( + mock, + mysql_free_result( + reinterpret_cast(0x2222))); +} + +TEST(CppHibernateTests, init) +{ + StrictMock 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(0x1111))); + + ::cppmariadb::connection connection(reinterpret_cast(0x1111)); + auto context = make_context(test_schema, connection); + context.init(true); +} \ No newline at end of file diff --git a/test/cpphibernate.cpp b/test/test_schema.h similarity index 51% rename from test/cpphibernate.cpp rename to test/test_schema.h index 5aed937..ef75bfe 100644 --- a/test/cpphibernate.cpp +++ b/test/test_schema.h @@ -1,62 +1,91 @@ -#include #include -#include -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 u32_nullable; + std::unique_ptr u32_ptr_u; + std::shared_ptr 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_nullable; - std::unique_ptr test2_ptr_u; - std::shared_ptr test2_ptr_s; + ::cpphibernate::uuid derived2_id; + utl::nullable test2_nullable; + std::unique_ptr test2_ptr_u; + std::shared_ptr test2_ptr_s; }; struct derived3 : public derived1 { - uuid derived3_id; - std::list test3_list; - std::vector test3_vector; + ::cpphibernate::uuid derived3_id; + std::list test3_list; + std::vector 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(0x1234)); - auto context = make_context(test_schema, connection); - std::cout << context.schema() << std::endl; -} \ No newline at end of file +); \ No newline at end of file