diff --git a/include/cpphibernate.h b/include/cpphibernate.h index 08780d6..d0bdf75 100644 --- a/include/cpphibernate.h +++ b/include/cpphibernate.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include diff --git a/include/cpphibernate/config.h b/include/cpphibernate/config.h index 59ec49a..3e724da 100644 --- a/include/cpphibernate/config.h +++ b/include/cpphibernate/config.h @@ -40,14 +40,20 @@ #define beg_namespace_cpphibernate namespace cpphibernate #define end_namespace_cpphibernate -#define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema) -#define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate) +#define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema) +#define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate) -#define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc) -#define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate) +#define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc) +#define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate) -#define beg_namespace_cpphibernate_modifier cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, modifier) -#define end_namespace_cpphibernate_modifier cpphibernate_define_namespace_end(end_namespace_cpphibernate) +#define beg_namespace_cpphibernate_modifier cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, modifier) +#define end_namespace_cpphibernate_modifier cpphibernate_define_namespace_end(end_namespace_cpphibernate) + +#define beg_namespace_cpphibernate_driver cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, driver) +#define end_namespace_cpphibernate_driver cpphibernate_define_namespace_end(end_namespace_cpphibernate) + +#define beg_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_beg(beg_namespace_cpphibernate_driver, mariadb_impl) +#define end_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_end(end_namespace_cpphibernate_driver) beg_namespace_cpphibernate { diff --git a/include/cpphibernate/context.h b/include/cpphibernate/context.h new file mode 100644 index 0000000..02f10e7 --- /dev/null +++ b/include/cpphibernate/context.h @@ -0,0 +1,122 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +beg_namespace_cpphibernate +{ + + namespace __impl + { + + template + struct context_t + : public T_driver + { + public: + using base_type = T_driver; + using driver_type = T_driver; + using schema_type = T_schema; + + private: + const schema_type& _schema; + + public: + template + constexpr context_t(const schema_type& p_schema, T_args&&... args) + : base_type (p_schema, std::forward(args)...) + , _schema (p_schema) + { } + + cpphibernate_copyable(context_t, delete); + cpphibernate_moveable(context_t, default); + + /* init */ + + inline void init(bool recreate) + { this->init_impl(recreate); } + + /* create */ + + template + constexpr void create(T_dataset& dataset) + { this->create_impl(dataset); } + + /* read */ + + template + constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers) + -> mp::enable_if< + modifier::all_are_modifier...>> + { + using real_dataset_type = misc::real_dataset_t>; + schema::tables::find(_schema.tables, hana::type_c); + this->read_impl(dataset, hana::make_tuple(std::forward(modifiers)...)); + } + + template + constexpr auto read(T_dataset& dataset) + -> mp::enable_if_c< + !misc::is_container>::value + && !misc::is_nullable>::value> + { + using namespace modifier; + using real_dataset_type = misc::real_dataset_t>; + auto& table = schema::tables::find(_schema.tables, hana::type_c); + auto& primary_key = schema::table::get_primary_key_field(table); + this->read_impl(dataset, hana::make_tuple(where(equal(primary_key, primary_key.getter(dataset))))); + } + + template + constexpr auto read(T_dataset& dataset) + -> mp::enable_if_c< + misc::is_container>::value + || misc::is_nullable>::value> + { + using namespace modifier; + using real_dataset_type = misc::real_dataset_t>; + schema::tables::find(_schema.tables, hana::type_c); + this->read_impl(dataset, hana::make_tuple()); + } + + /* update */ + + template + constexpr void update(T_dataset& dataset) + { this->update_impl(dataset); } + + /* destroy */ + + template + constexpr void destroy(T_dataset& dataset) + { this->destroy_impl(dataset); } + }; + + } + + /* make */ + + template + constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args) + { + using context_type = __impl::context_t; + return context_type(std::forward(schema), std::forward(args)...); + } + + template + constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args) + { + using context_type = __impl::context_t; + using pointer_type = std::unique_ptr; + return pointer_type(new context_type(std::forward(schema), std::forward(args)...)); + } + + +} +end_namespace_cpphibernate \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb.h b/include/cpphibernate/driver/mariadb.h new file mode 100644 index 0000000..3eb45e9 --- /dev/null +++ b/include/cpphibernate/driver/mariadb.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +beg_namespace_cpphibernate_driver +{ + + using mariadb = mariadb_impl::mariadb_driver_t; + +} +end_namespace_cpphibernate_driver \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/mariadb.h b/include/cpphibernate/driver/mariadb/mariadb.h new file mode 100644 index 0000000..4bd6da5 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/mariadb.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + struct mariadb_driver_t + { + private: + ::cppmariadb::connection& _connection; + schema_t _schema; + + public: + template + mariadb_driver_t(T_schema&& p_schema, ::cppmariadb::connection& p_connection) + : _connection (p_connection) + , _schema (make_schema(std::forward(p_schema))) + { } + + cpphibernate_copyable(mariadb_driver_t, delete); + cpphibernate_moveable(mariadb_driver_t, default); + + inline decltype(auto) connection() + { return _connection; } + + inline auto& schema() + { return _schema; } + }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema.h b/include/cpphibernate/driver/mariadb/schema.h new file mode 100644 index 0000000..17d8626 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/attributes.fwd.h b/include/cpphibernate/driver/mariadb/schema/attributes.fwd.h new file mode 100644 index 0000000..259a091 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/attributes.fwd.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* attribute_t */ + + enum class attribute_t + { + hex, + compress, + primary_key, + }; + + /* attributes_t */ + + struct attributes_t; + + /* make_attributes */ + + namespace __impl + { + + template + struct make_attributes_impl; + + } + + constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::make_attributes_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/attributes.h b/include/cpphibernate/driver/mariadb/schema/attributes.h new file mode 100644 index 0000000..16db25b --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/attributes.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* attributes_t */ + + struct attributes_t : + public std::set + { + using base_type = std::set; + using base_type::base_type; + }; + + namespace __impl + { + + /* attribute_converter */ + + template + struct attribute_converter; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::hex; }; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::compress; }; + + template<> + struct attribute_converter + { static constexpr decltype(auto) value = attribute_t::primary_key; }; + + /* make_attributes_impl */ + + template + struct make_attributes_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_attributes(...)!"); } + }; + + template + struct make_attributes_impl< + mp::list, + mp::enable_if_c< + schema::is_attributes>::value>> + { + template + static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence&) + { + return attributes_t({ + attribute_converter()[hana::size_c])>>::value... + }); + } + + static constexpr decltype(auto) apply(const T_attributes& attributes) + { + using size = mp::decay_t; + return helper(attributes, std::make_index_sequence { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/field.fwd.h b/include/cpphibernate/driver/mariadb/schema/field.fwd.h new file mode 100644 index 0000000..505d088 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/field.fwd.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* field_t */ + + struct field_t; + + /* field_ptr_t */ + + using field_ptr_t = std::unique_ptr; + + /* make_field */ + + namespace __impl + { + + template + struct make_field_impl; + + } + + constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::make_field_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/field.h b/include/cpphibernate/driver/mariadb/schema/field.h new file mode 100644 index 0000000..3f852d7 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/field.h @@ -0,0 +1,193 @@ +#pragma once + +#include +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* field_t */ + + struct field_t + { + size_t table_dataset_id { 0 }; + size_t value_dataset_id { 0 }; + bool value_is_nullable { false }; + bool value_is_container { false }; + std::string schema_name; + std::string table_name; + std::string field_name; + attributes_t attributes; + + const table_t* table { nullptr }; + const table_t* referenced_table { nullptr }; + + inline field_t() = default; + inline field_t(const field_t&) = delete; + inline field_t(field_t&& other) + : table_dataset_id (std::move(other).table_dataset_id) + , value_dataset_id (std::move(other).value_dataset_id) + , value_is_nullable (std::move(other).value_is_nullable) + , value_is_container(std::move(other).value_is_container) + , schema_name (std::move(other).schema_name) + , table_name (std::move(other).table_name) + , field_name (std::move(other).field_name) + , attributes (std::move(other).attributes) + , table (nullptr) + , referenced_table (nullptr) + { } + virtual ~field_t() = default; + }; + + /* simple_field_t */ + + template + struct simple_field_t + : public field_t + { + using schema_type = T_schema; + using field_type = T_field; + + const schema_type& schema; + const field_type& field; + + inline simple_field_t(const schema_type& p_schema, const field_type& p_field) + : field_t () + , schema (p_schema) + , field (p_field) + { } + }; + + /* value_field_t */ + + template + struct value_field_t + : public simple_field_t + { + using base_type = simple_field_t; + + using base_type::base_type; + }; + + /* primary_key_field_t */ + + template + struct primary_key_field_t + : public value_field_t + { + using base_type = value_field_t; + + using base_type::base_type; + }; + + /* data_field_t */ + + template + struct data_field_t + : public value_field_t + { + using base_type = value_field_t; + + using base_type::base_type; + }; + + /* foreign_table_field_t */ + + template + struct foreign_table_field_t + : public simple_field_t + { + using base_type = simple_field_t; + + using base_type::base_type; + }; + + namespace __impl + { + + /* is_primary_key_field */ + + template + struct is_primary_key_field + : public mp::decay_t().attributes, + schema::attribute::primary_key))> + { }; + + /* is_foreign_table_field */ + + template + struct is_foreign_table_field + : public mp::decay_t().tables, + schema::table::get_wrapped_dataset), + hana::type_c>))> + { }; + + /* field_type */ + + template + struct field_type + { using type = data_field_t; }; + + template + struct field_type>> + { using type = primary_key_field_t; }; + + template + struct field_type>> + { using type = foreign_table_field_t; }; + + template + using field_type_t = typename field_type::type; + + /* make_field_impl */ + + template + struct make_field_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_field(...)!"); } + }; + + template + struct make_field_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value + && schema::is_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; + using field_type = mp::decay_t; + using getter_type = mp::decay_t; + using value_type = mp::decay_t; + using dataset_type = mp::decay_t; + using value_dataset_type = misc::real_dataset_t; + using return_type = field_type_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.attributes = make_attributes(field.attributes); + return ret; + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/fields.fwd.h b/include/cpphibernate/driver/mariadb/schema/fields.fwd.h new file mode 100644 index 0000000..f2411a8 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/fields.fwd.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* fields_t */ + + struct fields_t; + + /* make_fields */ + + namespace __impl + { + + template + struct make_fields_impl; + + } + + constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::make_fields_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/fields.h b/include/cpphibernate/driver/mariadb/schema/fields.h new file mode 100644 index 0000000..fda7825 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/fields.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* fields_t */ + + struct fields_t + : public std::vector + { + using base_type = std::vector; + using base_type::base_type; + }; + + namespace __impl + { + + /* make_fields_impl */ + + template + struct make_fields_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_fields(...)!"); } + }; + + template + struct make_fields_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value>> + { + template + 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; + fields.emplace_back(new field_type(std::move(field))); + } + + template + static auto helper(const T_schema& schema, const T_table& table, std::index_sequence&&) + { + fields_t fields; + int dummy[] = {0, (emplace(fields, schema, table, hana::size_c), 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 { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/schema.fwd.h b/include/cpphibernate/driver/mariadb/schema/schema.fwd.h new file mode 100644 index 0000000..87217aa --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/schema.fwd.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* schema_t */ + + struct schema_t; + + /* make_schema */ + + namespace __impl + { + + template + struct make_schema_impl; + + } + + constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::make_schema_impl> { }; + +} +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 new file mode 100644 index 0000000..a59c559 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/schema.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* schema_t */ + + struct schema_t + { + std::string schema_name; + tables_t tables; + + inline schema_t() = default; + inline schema_t(const schema_t&) = delete; + inline schema_t(schema_t&& other) + : schema_name(std::move(other).schema_name) + , tables (std::move(other).tables) + { update(); } + + void update (); + void print (std::ostream& os) const; + }; + + namespace __impl + { + + /* make_schema_impl */ + + template + struct make_schema_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_schema(...)!"); } + }; + + template + struct make_schema_impl< + mp::list, + mp::enable_if_c< + schema::is_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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/table.fwd.h b/include/cpphibernate/driver/mariadb/schema/table.fwd.h new file mode 100644 index 0000000..67dea6e --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/table.fwd.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* table_t */ + + struct table_t; + + /* table_ptr_t */ + + using table_ptr_t = std::unique_ptr; + + /* make_table */ + + namespace __impl + { + + template + struct make_table_impl; + + } + + constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::make_table_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/table.h b/include/cpphibernate/driver/mariadb/schema/table.h new file mode 100644 index 0000000..d39953c --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/table.h @@ -0,0 +1,194 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* table_t */ + + struct table_t + { + size_t dataset_id { 0 }; + size_t base_dataset_id { 0 }; + size_t table_id { 0 }; + + std::vector derived_dataset_ids; + std::string table_name; + std::string schema_name; + + fields_t fields; + + const table_t* base_table { nullptr }; + std::vector derived_tables; + + const field_t* primary_key_field { nullptr }; + std::vector foreign_key_fields; + std::vector foreign_table_fields; + std::vector foreign_table_one_fields; + std::vector foreign_table_many_fields; + std::vector data_fields; + + inline table_t() = default; + inline table_t(const table_t&) = delete; + inline table_t(table_t&& other) + : dataset_id (std::move(other).dataset_id) + , base_dataset_id (std::move(other).base_dataset_id) + , table_id (std::move(other).table_id) + , derived_dataset_ids (std::move(other).derived_dataset_ids) + , table_name (std::move(other).table_name) + , schema_name (std::move(other).schema_name) + , fields (std::move(other).fields) + , base_table (nullptr) + , derived_tables () + , primary_key_field (nullptr) + , foreign_key_fields () + , foreign_table_fields () + , foreign_table_one_fields () + , foreign_table_many_fields () + , data_fields () + { } + virtual ~table_t() = default; + }; + + /* table_simple_t */ + + template + struct table_simple_t + : public table_t + { + 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; + + inline table_simple_t(const schema_type& p_schema, const table_type& p_table) + : schema(p_schema) + , table (p_table) + { } + + inline table_simple_t(const table_simple_t&) = delete; + + inline table_simple_t(table_simple_t&& other) + : table_t(std::move(other)) + , schema (std::move(other).schema) + , table (std::move(other).table) + { } + }; + + /* table_polymorphic_t */ + + template + struct table_polymorphic_t + : public table_simple_t + { + using base_type = table_simple_t; + 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; + }; + + namespace __impl + { + + /* make_dataset_id_vector */ + + struct make_dataset_id_vector_impl + { + template + static constexpr decltype(auto) helper(const T_wrapped_datasets& wrapped_datasets, std::index_sequence) + { + return std::vector({ + misc::get_type_id(wrapped_datasets[hana::size_c])... + }); + } + + template + constexpr decltype(auto) operator()(T_wrapped_datasets&& wrapped_datasets) const + { + using size = mp::decay_t; + return helper(std::forward(wrapped_datasets), std::make_index_sequence { }); + } + }; + + static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { }; + + /* make_table_impl */ + + template + struct make_table_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == 0, "Invalid parameters for mariadb::make_table(...)!"); } + }; + + template + struct make_table_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value + && schema::is_table >::value>> + { + + /* table_type */ + + template + struct table_type + { using type = table_simple_t, mp::decay_t, T_base_dataset>; }; + + template + struct table_type::value>> + { using type = table_polymorphic_t, mp::decay_t, T_base_dataset>; }; + + template + using table_type_t = typename table_type::type; + + /* apply */ + + static decltype(auto) apply(const T_schema& schema, const T_table& table) + { + using wrapped_base_type = mp::decay_t(), + std::declval().wrapped_dataset))>; + using base_type = misc::unwrap_t; + using derived_wrapped_types_type = mp::decay_t(), + std::declval().wrapped_dataset))>; + using wrapped_dataset_type = typename mp::decay_t::wrapped_dataset_type; + using dataset_type = misc::unwrap_t; + using table_type = table_type_t; + 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 \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/tables.fwd.h b/include/cpphibernate/driver/mariadb/schema/tables.fwd.h new file mode 100644 index 0000000..78e0ebd --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/tables.fwd.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* tables_t */ + + struct tables_t; + + /* make_tables */ + + namespace __impl + { + + template + struct make_tables_impl; + + } + + constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::make_tables_impl> { }; + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/driver/mariadb/schema/tables.h b/include/cpphibernate/driver/mariadb/schema/tables.h new file mode 100644 index 0000000..5706e94 --- /dev/null +++ b/include/cpphibernate/driver/mariadb/schema/tables.h @@ -0,0 +1,69 @@ +#pragma once + +#include + +#include +#include +#include +#include + +beg_namespace_cpphibernate_driver_mariadb +{ + + /* tables_t */ + + struct tables_t + : public std::map + { + using base_type = std::map; + using base_type::base_type; + }; + + namespace __impl + { + + /* make_tables_impl */ + + template + struct make_tables_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_tables(...)!"); } + }; + + template + struct make_tables_impl< + mp::list, + mp::enable_if_c< + schema::is_schema>::value>> + { + template + 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; + auto key = table.dataset_id; + tables.emplace(key, std::make_unique(std::move(table))); + } + + template + static decltype(auto) helper(const T_schema& schema, std::index_sequence) + { + tables_t tables; + int dummy[] = {0, (emplace(tables, schema, hana::size_c), 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 { }); + } + }; + + } + +} +end_namespace_cpphibernate_driver_mariadb \ No newline at end of file diff --git a/include/cpphibernate/misc/general.h b/include/cpphibernate/misc/general.h index c79ff0d..037db6c 100644 --- a/include/cpphibernate/misc/general.h +++ b/include/cpphibernate/misc/general.h @@ -1,6 +1,7 @@ #pragma once #include +#include beg_namespace_cpphibernate_misc { @@ -15,5 +16,17 @@ beg_namespace_cpphibernate_misc { return T_builder>::apply(std::forward(args)...); } }; + /* get_dataset_id */ + + namespace __impl + { + struct counter_type_id + { }; + } + + template + constexpr decltype(auto) get_type_id(T_type&&) + { return utl::get_unique_id<__impl::counter_type_id, mp::decay_t>(); } + } end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/misc/meta.h b/include/cpphibernate/misc/meta.h index c4e8dde..9ea58da 100644 --- a/include/cpphibernate/misc/meta.h +++ b/include/cpphibernate/misc/meta.h @@ -96,14 +96,6 @@ beg_namespace_cpphibernate_misc struct real_dataset_impl, void> { using type = typename real_dataset_impl::type; }; - template - struct change_dataset_type_impl - { using type = T_to; }; - - template class X, typename T_from, typename T_to> - struct change_dataset_type_impl, T_to, void> - { using type = X; }; - } /* meta */ diff --git a/include/cpphibernate/modifier/where/clauses/and.h b/include/cpphibernate/modifier/where/clauses/and.h index 9daf021..942fc3b 100644 --- a/include/cpphibernate/modifier/where/clauses/and.h +++ b/include/cpphibernate/modifier/where/clauses/and.h @@ -15,7 +15,7 @@ beg_namespace_cpphibernate_modifier struct where_clause_and_t : public where_clause_t { - using clauses_type = hana::basic_tuple; + using clauses_type = hana::tuple; clauses_type clauses; diff --git a/include/cpphibernate/modifier/where/clauses/or.h b/include/cpphibernate/modifier/where/clauses/or.h index edac57d..79dd497 100644 --- a/include/cpphibernate/modifier/where/clauses/or.h +++ b/include/cpphibernate/modifier/where/clauses/or.h @@ -15,7 +15,7 @@ beg_namespace_cpphibernate_modifier struct where_clause_or_t : public where_clause_t { - using clauses_type = hana::basic_tuple; + using clauses_type = hana::tuple; clauses_type clauses; diff --git a/include/cpphibernate/schema/attributes.h b/include/cpphibernate/schema/attributes.h index 78ca0a4..1dcd0c0 100644 --- a/include/cpphibernate/schema/attributes.h +++ b/include/cpphibernate/schema/attributes.h @@ -13,7 +13,7 @@ beg_namespace_cpphibernate_schema /* attributes_t */ template - using attributes_t = hana::basic_tuple; + using attributes_t = hana::tuple; /* is_attributes_impl */ @@ -27,37 +27,47 @@ beg_namespace_cpphibernate_schema : mp::c_true_t { }; - /* attributes_builder */ + } + + /* meta */ + + template + struct is_attributes + : public __impl::is_attributes_impl + { }; + + /* operations */ + + namespace __impl + { + + /* attributes_make_impl */ template - struct attributes_builder + struct attributes_make_impl { template static constexpr decltype(auto) apply(T_args&&...) - { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::make_attributes(...)!"); } + { static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::attributes::make(...)!"); } }; template - struct attributes_builder, mp::enable_if_c< + struct attributes_make_impl, mp::enable_if_c< all_are_attribures...>::value>> { template static constexpr decltype(auto) apply(T_args&&...) { return attributes_t...> { }; } - }; + }; } - /* meta */ - - template - struct is_attributes - : public __impl::is_attributes_impl - { }; + namespace attributes + { - /* make */ + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::attributes_make_impl> { }; - constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::attributes_builder> { }; + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/field.h b/include/cpphibernate/schema/field.h index 976af98..2e994d2 100644 --- a/include/cpphibernate/schema/field.h +++ b/include/cpphibernate/schema/field.h @@ -72,18 +72,37 @@ beg_namespace_cpphibernate_schema } }; - /* field_builder */ + } + + /* meta */ + + template + struct is_field + : public mp::is_specialization_of + { }; + + template + struct all_are_fields + : public mp::all_true::value...> + { }; + + /* operations */ + + namespace __impl + { + + /* field_make_impl */ template - struct field_builder + struct field_make_impl { template static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_field(...)!"); } + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::field::make(...)!"); } }; template - struct field_builder, mp::enable_if_c< + struct field_make_impl, mp::enable_if_c< is_getter>::value && is_setter>::value && is_attributes>::value>> @@ -96,21 +115,12 @@ beg_namespace_cpphibernate_schema } - /* meta */ - - template - struct is_field - : public mp::is_specialization_of - { }; - - template - struct all_are_fields - : public mp::all_true::value...> - { }; + namespace field + { - /* make */ + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::field_make_impl> { }; - constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::field_builder> { }; + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/fields.h b/include/cpphibernate/schema/fields.h index 8944a9d..61e06a3 100644 --- a/include/cpphibernate/schema/fields.h +++ b/include/cpphibernate/schema/fields.h @@ -13,7 +13,7 @@ beg_namespace_cpphibernate_schema /* fields_t */ template - using fields_t = hana::basic_tuple; + using fields_t = hana::tuple; /* is_fields_impl */ @@ -27,18 +27,32 @@ beg_namespace_cpphibernate_schema : public mp::c_true_t { }; - /* fields_builder */ + } + + /* meta */ + + template + struct is_fields : + public __impl::is_fields_impl + { }; + + /* operations */ + + namespace __impl + { + + /* fields_make_impl */ template - struct fields_builder + struct fields_make_impl { template static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_fields(...)!"); } + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::fields::make(...)!"); } }; template - struct fields_builder, mp::enable_if>> + struct fields_make_impl, mp::enable_if>> { template static constexpr decltype(auto) apply(T_args&&... args) @@ -47,16 +61,12 @@ beg_namespace_cpphibernate_schema } - /* meta */ - - template - struct is_fields : - public __impl::is_fields_impl - { }; + namespace fields + { - /* constructors */ + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::fields_make_impl> { }; - constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::fields_builder> { }; + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/getter.h b/include/cpphibernate/schema/getter.h index b0e3759..6b421e0 100644 --- a/include/cpphibernate/schema/getter.h +++ b/include/cpphibernate/schema/getter.h @@ -11,35 +11,22 @@ beg_namespace_cpphibernate_schema /* getter_t */ - template + template struct getter_t { - using value_type = T_value; - }; - - - /* getter_none_t */ - - struct getter_none_t - : public getter_t - { - using base_type = getter_t; - using value_type = typename base_type::value_type; - - cpphibernate_constructable(getter_none_t, default); - cpphibernate_copyable (getter_none_t, delete); - cpphibernate_moveable (getter_none_t, default); + using dataset_type = T_dataset; + using value_type = T_value; }; /* getter_member_var_t */ template struct getter_member_var_t - : public getter_t + : public getter_t { - using base_type = getter_t; + using base_type = getter_t; + using dataset_type = typename base_type::dataset_type; using value_type = typename base_type::value_type; - using dataset_type = T_dataset; using member_type = T_member; member_type member; @@ -61,11 +48,11 @@ beg_namespace_cpphibernate_schema template struct getter_member_func_t - : public getter_t + : public getter_t { - using base_type = getter_t; + using base_type = getter_t; + using dataset_type = typename base_type::dataset_type; using value_type = typename base_type::value_type; - using dataset_type = T_dataset; using member_type = T_member; member_type member; @@ -87,11 +74,11 @@ beg_namespace_cpphibernate_schema template struct getter_lambda_t - : public getter_t()(std::declval()))> + : public getter_t()(std::declval()))> { - using base_type = getter_t()(std::declval()))>; + using base_type = getter_t()(std::declval()))>; + using dataset_type = typename base_type::dataset_type; using value_type = typename base_type::value_type; - using dataset_type = T_dataset; using lambda_type = T_lambda; lambda_type lambda; @@ -118,7 +105,7 @@ beg_namespace_cpphibernate_schema template struct is_getter_impl, T>::value>> + mp::is_base_of, T>::value>> : public mp::c_true_t { }; @@ -133,9 +120,6 @@ beg_namespace_cpphibernate_schema /* make */ - constexpr decltype(auto) make_getter_none() - { return __impl::getter_none_t(); } - template constexpr decltype(auto) make_getter_member_var(T_value T_dataset::* member) { return __impl::getter_member_var_t(member); } @@ -152,55 +136,59 @@ beg_namespace_cpphibernate_schema constexpr decltype(auto) make_getter_lambda(T_lambda&& lambda, boost::hana::basic_type) { return __impl::getter_lambda_t(std::forward(lambda)); } + /* operations */ namespace __impl { - /* getter_buildser */ + /* getter_make_impl */ template - struct getter_builder + struct getter_make_impl { template - static constexpr decltype(auto) apply(Args&&...) - { return make_getter_none(); } + static constexpr decltype(auto) apply(Args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid arguments to schema::getter::make(...)!"); } }; template - struct getter_builder, void> + struct getter_make_impl, void> { static constexpr decltype(auto) apply(T_value T_dataset::*member) { return make_getter_member_var(member); } }; template - struct getter_builder, void> + struct getter_make_impl, void> { static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) { return make_getter_member_func(member); } }; template - struct getter_builder, void> + struct getter_make_impl, void> { static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) { return make_getter_member_func(member); } }; - template - struct getter_builder, mp::enable_if_c< - hana::is_a> + template + struct getter_make_impl, mp::enable_if_c< + hana::is_a> && hana::is_a>>> { - static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) - { return make_getter_lambda(std::forward(func), std::forward(dataset_type), std::forward(value_type)); } + static constexpr decltype(auto) apply(T_func&& func, T_wrapped_dataset&& wrapped_dataset, T_value_type&& value_type) + { return make_getter_lambda(std::forward(func), std::forward(wrapped_dataset), std::forward(value_type)); } }; } - /* make */ + namespace getter + { - constexpr decltype(auto) make_getter = misc::make_generic_predicate<__impl::getter_builder> { }; + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::getter_make_impl> { }; + + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/macros.h b/include/cpphibernate/schema/macros.h index 0f4d720..b4e514c 100644 --- a/include/cpphibernate/schema/macros.h +++ b/include/cpphibernate/schema/macros.h @@ -6,38 +6,38 @@ #define cpphibernate_make_string(str) \ #str -#define cpphibernate_make_schema(name, ...) \ - cpphibernate::schema::make_schema( \ - cpphibernate_make_string(name), \ - cpphibernate::schema::make_tables(__VA_ARGS__)) - -#define cpphibernate_make_table_name(name, type, id, ...) \ - cpphibernate::schema::make_table( \ - cpphibernate_make_string(name), \ - boost::hana::type_c, \ - boost::hana::size_c, \ - cpphibernate::schema::make_fields(__VA_ARGS__)) - -#define cpphibernate_make_table(name, id, ...) \ - cpphibernate_make_table_name(name, name, id, __VA_ARGS__) - -#define cpphibernate_make_field_custom(name, getter, setter, ...) \ - cpphibernate::schema::make_field( \ - cpphibernate_make_string(name), \ - cpphibernate::schema::make_getter(getter), \ - cpphibernate::schema::make_setter(setter), \ - cpphibernate::schema::make_attributes(__VA_ARGS__)) - -#define cpphibernate_make_field_name(name, member_ptr, ...) \ +#define cpphibernate_make_schema(p_name, ...) \ + cpphibernate::schema::make( \ + cpphibernate_make_string(p_name), \ + cpphibernate::schema::tables::make(__VA_ARGS__)) + +#define cpphibernate_make_table_name(p_name, p_type, p_id, ...) \ + cpphibernate::schema::table::make( \ + cpphibernate_make_string(p_name), \ + boost::hana::type_c, \ + boost::hana::size_c, \ + cpphibernate::schema::fields::make(__VA_ARGS__)) + +#define cpphibernate_make_table(p_name, p_id, ...) \ + cpphibernate_make_table_name(p_name, p_name, p_id, __VA_ARGS__) + +#define cpphibernate_make_field_custom(p_name, p_getter, p_setter, ...) \ + cpphibernate::schema::field::make( \ + cpphibernate_make_string(p_name), \ + cpphibernate::schema::getter::make(p_getter), \ + cpphibernate::schema::setter::make(p_setter), \ + cpphibernate::schema::attributes::make(__VA_ARGS__)) + +#define cpphibernate_make_field_name(p_name, p_member_ptr, ...) \ cpphibernate_make_field_custom( \ - name, member_ptr, member_ptr, __VA_ARGS__) + p_name, p_member_ptr, p_member_ptr, __VA_ARGS__) -#define cpphibernate_make_field(type, member, ...) \ +#define cpphibernate_make_field(p_type, p_member, ...) \ cpphibernate_make_field_name( \ - member, &type::member, __VA_ARGS__) + p_member, &p_type::p_member, __VA_ARGS__) -#define cpphibernate_make_id(member_ptr) \ +#define cpphibernate_make_id(p_member_ptr) \ cpphibernate_make_field_name( \ - null, \ - member_ptr, \ + "p_id", \ + p_member_ptr, \ cpphibernate::schema::attribute::primary_key) \ No newline at end of file diff --git a/include/cpphibernate/schema/schema.h b/include/cpphibernate/schema/schema.h index ce49b5b..fe18b57 100644 --- a/include/cpphibernate/schema/schema.h +++ b/include/cpphibernate/schema/schema.h @@ -52,34 +52,201 @@ beg_namespace_cpphibernate_schema } }; - /* schema_builder */ + } + + /* meta */ + + template + struct is_schema : mp::is_specialization_of { }; + + /* schema::make */ + namespace __impl + { template - struct schema_builder + struct schema_make_impl { template static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_schema(...)!"); } + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make(...)!"); } }; template - struct schema_builder, mp::enable_if_c< - is_tables>::value>> + struct schema_make_impl, mp::enable_if_c< + is_tables>::value>> { static constexpr decltype(auto) apply(T_name&& name, T_tables&& tables) { return schema_t(std::forward(name), std::forward(tables)); } }; + } + + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::schema_make_impl> { }; + + /* schema::get_base_type */ + + namespace __impl + { + struct schema_get_base_type_impl + { + static constexpr decltype(auto) is_base_of_pred = hana::integral(hana::metafunction); + struct do_fold_impl + { + template + constexpr decltype(auto) operator()(T_type_1&& type_1, T_type_2&& type_2) const + { + auto check = hana::or_(is_base_of_pred(type_1, type_2), is_base_of_pred(type_2, type_1)); + static_assert(decltype(check)::value, "A dataset must not have more than one base class!"); + return hana::if_(is_base_of_pred(type_1, type_2), type_2, type_1); + } + }; + + static constexpr decltype(auto) do_fold = do_fold_impl { }; + + template + static constexpr decltype(auto) get_base_types(T_wrapped_datasets&& wrapped_datasets, T_wrapped_dataset&& wrapped_dataset) + { + return hana::filter( + std::forward(wrapped_datasets), + [&](auto type){ + return hana::and_( + is_base_of_pred(type, wrapped_dataset), + hana::not_equal(type, wrapped_dataset)); + }); + } + + template + constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const + { + using wrapped_datasets_type = mp::decay_t().tables, + schema::table::get_wrapped_dataset))>; + auto base_types = get_base_types(wrapped_datasets_type { }, std::forward(wrapped_dataset)); + return hana::eval_if( + hana::size(base_types) <= hana::size_c<0>, + [&](auto _){ return hana::type_c; }, + [&](auto _){ return hana::fold(_(base_types), do_fold); }); + } + }; } - /* meta */ + constexpr decltype(auto) get_base_type = __impl::schema_get_base_type_impl { }; - template - struct is_schema : mp::is_specialization_of { }; + /* schema::get_root_base_type */ + + namespace __impl + { + struct schema_get_root_base_type_impl + { + template + struct is_base_pred + { + using dataset_type = misc::decay_unwrap_t; + + template + constexpr decltype(auto) operator()(T_type&&) const + { + using type = misc::unwrap_t; + return hana::bool_c< + std::is_base_of::value + && !std::is_same ::value>; + } + }; + + template + constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const + { + auto all_types = hana::transform( + schema.tables, + table::get_wrapped_dataset); + auto base_type = hana::find_if( + all_types, + is_base_pred { }); + return hana::eval_if( + base_type != hana::nothing, + [&](auto _){ + return schema_get_root_base_type_impl { }(schema, _(base_type).value()); + }, + [&]{ + return wrapped_dataset; + }); + } + }; + } + + constexpr decltype(auto) get_root_base_type = __impl::schema_get_root_base_type_impl { }; + + /* schema::get_all_derived_types */ + + namespace __impl + { + struct schema_get_all_derived_types_impl + { + template + struct is_derived_pred + { + using dataset_type = misc::decay_unwrap_t; + + template + constexpr decltype(auto) operator()(T_type&&) const + { + return hana::bool_c< + std::is_base_of>::value>; + } + }; + + template + constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&&) const + { + auto all_types = hana::transform( + schema.tables, + table::get_wrapped_dataset); + auto derived_types = hana::filter( + all_types, + is_derived_pred { }); + return derived_types; + } + }; + } + + constexpr decltype(auto) get_all_derived_types = __impl::schema_get_all_derived_types_impl { }; + + /* schema::get_derived_types */ + + namespace __impl + { + struct schema_get_derived_types_impl + { + struct has_base_impl + { + template + constexpr decltype(auto) operator()(T_schema&& schema, T_base_type& base_type, T_type&& type) const + { return get_base_type(schema, type) == base_type; } + }; - /* make */ + static constexpr decltype(auto) has_base = has_base_impl { }; - constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::schema_builder> { }; + template + constexpr decltype(auto) operator()(T_schema&& schema, T_wrapped_dataset&& wrapped_dataset) const + { + using wrapped_datasets_type = mp::decay_t().tables, + schema::table::get_wrapped_dataset))>; + using derived_wrapped_datasets_type = mp::decay_t(), + hana::partial( + has_base, + std::declval(), + wrapped_dataset)))>; + return derived_wrapped_datasets_type { }; + } + }; + } + + constexpr decltype(auto) get_derived_types = __impl::schema_get_derived_types_impl { }; } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/setter.h b/include/cpphibernate/schema/setter.h index 6f26af9..17784e4 100644 --- a/include/cpphibernate/schema/setter.h +++ b/include/cpphibernate/schema/setter.h @@ -152,14 +152,15 @@ beg_namespace_cpphibernate_schema constexpr decltype(auto) make_setter_lambda(T_lambda&& lambda, boost::hana::basic_type, boost::hana::basic_type) { return __impl::setter_lambda_t(std::forward(lambda)); } + /* operations */ namespace __impl { - /* setter_buildser */ + /* setter_make_impl */ template - struct setter_builder + struct setter_make_impl { template static constexpr decltype(auto) apply(Args&&...) @@ -167,40 +168,43 @@ beg_namespace_cpphibernate_schema }; template - struct setter_builder, void> + struct setter_make_impl, void> { static constexpr decltype(auto) apply(T_value T_dataset::*member) { return make_setter_member_var(member); } }; template - struct setter_builder, void> + struct setter_make_impl, void> { static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void)) { return make_setter_member_func(member); } }; template - struct setter_builder, void> + struct setter_make_impl, void> { static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const) { return make_setter_member_func(member); } }; - template - struct setter_builder, mp::enable_if_c< - hana::is_a> - && hana::is_a>>> + template + struct setter_make_impl, mp::enable_if_c< + hana::is_a> + && hana::is_a>>> { - static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type) - { return make_setter_lambda(std::forward(func), std::forward(dataset_type), std::forward(value_type)); } + static constexpr decltype(auto) apply(T_func&& func, T_wrapped_dataset&& wrapped_dataset, T_value_type&& value_type) + { return make_setter_lambda(std::forward(func), std::forward(wrapped_dataset), std::forward(value_type)); } }; } - /* make */ + namespace setter + { - constexpr decltype(auto) make_setter = misc::make_generic_predicate<__impl::setter_builder> { }; + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::setter_make_impl> { }; + + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/table.h b/include/cpphibernate/schema/table.h index 47a7aa5..4ca1050 100644 --- a/include/cpphibernate/schema/table.h +++ b/include/cpphibernate/schema/table.h @@ -4,6 +4,7 @@ #include #include #include +#include beg_namespace_cpphibernate_schema { @@ -13,27 +14,27 @@ beg_namespace_cpphibernate_schema /* table_t */ - template + template struct table_t { using name_type = T_name; - using dataset_wrapped_type = mp::decay_t; + using wrapped_dataset_type = mp::decay_t; using table_id_type = T_table_id; using fields_type = T_fields; - using this_type = table_t; + using this_type = table_t; name_type name; - dataset_wrapped_type dataset_wrapped; + wrapped_dataset_type wrapped_dataset; table_id_type table_id; fields_type fields; constexpr table_t( T_name p_name, - T_dataset_wrapped p_dataset_wrapped, + T_wrapped_dataset p_wrapped_dataset, T_table_id p_table_id, T_fields p_fields) : name (std::forward (p_name)) - , dataset_wrapped (std::forward(p_dataset_wrapped)) + , wrapped_dataset (std::forward(p_wrapped_dataset)) , table_id (std::forward (p_table_id)) , fields (std::forward (p_fields)) { } @@ -50,7 +51,7 @@ beg_namespace_cpphibernate_schema os << indent << '{' << incindent << indent << "\"name\": \"" << name << "\"," - << indent << "\"dataset_wrapped\": \"" << utl::type_helper>::name() << "\"" + << indent << "\"wrapped_dataset\": \"" << utl::type_helper>::name() << "\"" << indent << "\"table_id\": \"" << hana::value(table_id) << "\"" << indent << "\"fields\": " << indent << '[' @@ -66,44 +67,123 @@ beg_namespace_cpphibernate_schema } }; - /* table_builder */ + } + + /* meta */ + + template + struct is_table + : public mp::is_specialization_of + { }; + + template + struct all_are_tables + : mp::all_true::value...> + { }; + + /* operations */ + + namespace __impl + { + + /* table_make_impl */ template - struct table_builder + struct table_make_impl { template static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_table(...)!"); } + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::table::make(...)!"); } }; - template - struct table_builder, mp::enable_if_c< - hana::is_a + template + struct table_make_impl, mp::enable_if_c< + hana::is_a && is_fields>::value>> { - static constexpr decltype(auto) apply(T_name&& name, T_dataset_wrapped&& dataset_wrapped, T_id&& id, T_fields&& fields) + static constexpr decltype(auto) apply(T_name&& name, T_wrapped_dataset&& wrapped_dataset, T_id&& id, T_fields&& fields) { - return table_t( + return table_t( std::forward (name), - std::forward (dataset_wrapped), + std::forward (wrapped_dataset), std::forward (id), std::forward (fields)); } }; + /* table_get_wrapped_dataset_impl */ + + struct table_get_wrapped_dataset_impl + { + template + constexpr decltype(auto) operator()(T_table&& table) const + { return table.wrapped_dataset; } + }; + + /* table_get_primary_key_field_impl */ + + template + struct table_get_primary_key_field_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::table::get_primary_key_field(...)!"); } + }; + + template + struct table_get_primary_key_field_impl< + mp::list, + mp::enable_if_c< + is_table>::value>> + { + template + using is_primary_key_field = decltype(hana::contains( + std::declval().fields[hana::size_c].attributes, + attribute::primary_key)); + + template + struct helper; + + template + struct helper + { static_assert(N != N, "Unable to find primary key field for table!"); }; + + template + struct helper::value>> + { + static constexpr decltype(auto) apply(T_table&& table) + { return helper::apply(std::forward(table)); } + }; + + template + struct helper::value>> + { + static constexpr decltype(auto) apply(T_table&& table) + { return std::forward(table).fields[hana::size_c]; } + }; + + static constexpr decltype(auto) apply(T_table&& table) + { + using count = mp::decay_t().fields))>; + return helper<0, count::value>::apply( + std::forward(table)); + } + }; + } - /* meta */ + namespace table + { - template - struct is_table : mp::is_specialization_of { }; + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::table_make_impl> { }; - template - struct all_are_tables : mp::all_true::value...> { }; + constexpr decltype(auto) get_wrapped_dataset = __impl::table_get_wrapped_dataset_impl { }; - /* make */ + constexpr decltype(auto) get_primary_key_field = misc::make_generic_predicate<__impl::table_get_primary_key_field_impl> { }; - constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::table_builder> { }; + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/include/cpphibernate/schema/tables.h b/include/cpphibernate/schema/tables.h index 98df6a4..184fca2 100644 --- a/include/cpphibernate/schema/tables.h +++ b/include/cpphibernate/schema/tables.h @@ -27,36 +27,94 @@ beg_namespace_cpphibernate_schema : mp::c_true_t { }; - /* tables_builder */ + } + + /* meta */ + + template + struct is_tables + : public __impl::is_tables_impl + { }; + + /* operations */ + + namespace __impl + { + + /* tables_make_impl */ template - struct tables_builder + struct tables_make_impl { template static constexpr decltype(auto) apply(T_args&&... args) - { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_tables(...)!"); } + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::tables::make(...)!"); } }; template - struct tables_builder, mp::enable_if>> + struct tables_make_impl, mp::enable_if>> { template static constexpr decltype(auto) apply(T_tables&&... tables) { return tables_t(std::forward(tables)...); } }; + /* tables_find_impl */ + + template + struct tables_find_impl + { + template + static constexpr decltype(auto) apply(T_args&&... args) + { static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::tables::find(...)!"); } + }; + + template + struct tables_find_impl< + mp::list, + mp::enable_if_c< + is_tables>::value>> + { + template + struct helper; + + template + struct helper + { static_assert(N != N, "Table for given datatype does not exist!"); }; + + template + struct helper()[hana::size_c].wrapped_dataset, T_wrapped_dataset { }))::value>> + { + static constexpr decltype(auto) apply(T_tables&& tables) + { return helper::apply(std::forward(tables)); } + }; + + template + struct helper()[hana::size_c].wrapped_dataset, T_wrapped_dataset { }))::value>> + { + static constexpr decltype(auto) apply(T_tables&& tables) + { return std::forward(tables)[hana::size_c]; } + }; + + static constexpr decltype(auto) apply(T_tables&& tables, T_wrapped_dataset&&) + { + using count_type = mp::decay_t()))>; + return helper<0, count_type::value>::apply(std::forward(tables)); + } + }; + } - /* meta */ + namespace tables + { - template - struct is_tables - : public __impl::is_tables_impl - { }; + constexpr decltype(auto) make = misc::make_generic_predicate<__impl::tables_make_impl> { }; - /* make */ + constexpr decltype(auto) find = misc::make_generic_predicate<__impl::tables_find_impl> { }; - constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::tables_builder> { }; + } } end_namespace_cpphibernate_schema \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a66730d..191bcaf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX # Dependencies #################################################################################### Find_Package ( cpputils REQUIRED ) +Find_Package ( cppmariadb REQUIRED ) # Project: cpphibernate ############################################################################### @@ -27,6 +28,7 @@ Target_Include_Directories ( Target_Link_Libraries ( cpphibernate cpputils + cppmariadb ) If ( __COTIRE_INCLUDED ) Cotire ( cpphibernate ) diff --git a/src/driver/mariadb/schema/schema.cpp b/src/driver/mariadb/schema/schema.cpp new file mode 100644 index 0000000..372e5d2 --- /dev/null +++ b/src/driver/mariadb/schema/schema.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +using namespace ::cpphibernate::driver::mariadb_impl; + +void schema_t::update() +{ + +} + +void schema_t::print(std::ostream& os) const +{ + os << "fuu" << std::endl; +} \ No newline at end of file diff --git a/test/cpphibernate.cpp b/test/cpphibernate.cpp index 4292225..5aed937 100644 --- a/test/cpphibernate.cpp +++ b/test/cpphibernate.cpp @@ -1,5 +1,6 @@ #include #include +#include using namespace ::cpphibernate; @@ -124,5 +125,7 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema( TEST(CppHibernateTests, fuuu) { - std::cout << test_schema << std::endl; + ::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 diff --git a/test/mariadb_mock.cpp b/test/mariadb_mock.cpp new file mode 100644 index 0000000..1792b1e --- /dev/null +++ b/test/mariadb_mock.cpp @@ -0,0 +1,77 @@ +#include "mariadb_mock.h" + +MariaDbMock* mariadb_mock_instance; + +void MariaDbMock::setInstance(MariaDbMock* value) +{ + mariadb_mock_instance = value; +} + +void MariaDbMock::clearInstance(MariaDbMock* value) +{ + if (mariadb_mock_instance == value) + mariadb_mock_instance = nullptr; +} + +my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_rows(res) : 0); } + +unsigned int STDCALL mysql_num_fields (MYSQL_RES *res) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_fields(res) : 0); } + +MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_tell(res) : nullptr); } + +void STDCALL mysql_free_result (MYSQL_RES *res) + { if (mariadb_mock_instance) mariadb_mock_instance->mysql_free_result(res); } + +MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET offset) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_seek(res, offset) : nullptr); } + +void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset) + { if (mariadb_mock_instance) mariadb_mock_instance->mysql_data_seek(res, offset); } + +unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_lengths(res) : nullptr); } + +MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_row(res) : nullptr); } + +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) + { 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); } + +const char* STDCALL mysql_error (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_error(mysql) : nullptr); } + +MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_store_result(mysql) : nullptr); } + +MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_use_result(mysql) : nullptr); } + +unsigned int STDCALL mysql_field_count (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_field_count(mysql) : 0); } + +my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_affected_rows(mysql) : 0); } + +my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_insert_id(mysql) : 0); } + +unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_escape_string(mysql, to, from, length) : 0); } + +void STDCALL mysql_close (MYSQL *mysql) + { if (mariadb_mock_instance) mariadb_mock_instance->mysql_close(mysql); } + +MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag) : nullptr); } + +MYSQL* STDCALL mysql_init (MYSQL *mysql) + { return (mariadb_mock_instance ? mariadb_mock_instance->mysql_init(mysql) : nullptr); } \ No newline at end of file diff --git a/test/mariadb_mock.h b/test/mariadb_mock.h new file mode 100644 index 0000000..b0cdbe1 --- /dev/null +++ b/test/mariadb_mock.h @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include +#include + +#define MARIADB_MOCK + +#if !defined(_WIN32) + #define STDCALL +#else + #define STDCALL __stdcall +#endif + +#define NOT_NULL_FLAG 1 /* field can't be NULL */ +#define PRI_KEY_FLAG 2 /* field is part of a primary key */ +#define UNIQUE_KEY_FLAG 4 /* field is part of a unique key */ +#define MULTIPLE_KEY_FLAG 8 /* field is part of a key */ +#define BLOB_FLAG 16 /* field is a blob */ +#define UNSIGNED_FLAG 32 /* field is unsigned */ +#define ZEROFILL_FLAG 64 /* field is zerofill */ +#define BINARY_FLAG 128 +#define ENUM_FLAG 256 /* field is an enum */ +#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ +#define TIMESTAMP_FLAG 1024 /* field is a timestamp */ +#define SET_FLAG 2048 /* field is a set */ +#define NO_DEFAULT_VALUE_FLAG 4096 /* field doesn't have default value */ +#define ON_UPDATE_NOW_FLAG 8192 /* field is set to NOW on UPDATE */ +#define NUM_FLAG 32768 /* field is num (for clients) */ +#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ +#define GROUP_FLAG 32768 /* Intern: Group field */ +#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ + + +#define CLIENT_MYSQL 1 +#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +#define CLIENT_LONG_FLAG 4 /* Get all column flags */ +#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ +#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ +#define CLIENT_COMPRESS 32 /* Can use compression protocol */ +#define CLIENT_ODBC 64 /* Odbc client */ +#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ +#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ +#define CLIENT_PROTOCOL_41 512 +#define CLIENT_RESERVED 16384 +#define CLIENT_SECURE_CONNECTION 32768 +#define CLIENT_MULTI_STATEMENTS (1UL << 16) +#define CLIENT_MULTI_RESULTS (1UL << 17) +#define CLIENT_PS_MULTI_RESULTS (1UL << 18) +#define CLIENT_PLUGIN_AUTH (1UL << 19) +#define CLIENT_CONNECT_ATTRS (1UL << 20) +#define CLIENT_SESSION_TRACKING (1UL << 23) +#define CLIENT_PROGRESS (1UL << 29) +#define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS +#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) +#define CLIENT_REMEMBER_OPTIONS (1UL << 31) + +struct MariaDbMock +{ +private: + static void setInstance(MariaDbMock* value); + static void clearInstance(MariaDbMock* value); + +public: + MOCK_METHOD1(mysql_num_rows, my_ulonglong (MYSQL_RES *res)); + MOCK_METHOD1(mysql_num_fields, unsigned int (MYSQL_RES *res)); + MOCK_METHOD1(mysql_row_tell, MYSQL_ROWS* (MYSQL_RES *res)); + MOCK_METHOD1(mysql_free_result, void (MYSQL_RES *res)); + MOCK_METHOD2(mysql_row_seek, MYSQL_ROW_OFFSET(MYSQL_RES *res, MYSQL_ROW_OFFSET)); + MOCK_METHOD2(mysql_data_seek, void (MYSQL_RES *res, unsigned long long offset)); + MOCK_METHOD1(mysql_fetch_lengths, unsigned long* (MYSQL_RES *res)); + MOCK_METHOD1(mysql_fetch_row, MYSQL_ROW (MYSQL_RES *res)); + MOCK_METHOD1(mysql_fetch_fields, MYSQL_FIELD* (MYSQL_RES *res)); + + MOCK_METHOD3(mysql_real_query, int (MYSQL *mysql, const char *q, unsigned long length)); + MOCK_METHOD1(mysql_errno, unsigned int (MYSQL *mysql)); + MOCK_METHOD1(mysql_error, const char* (MYSQL *mysql)); + MOCK_METHOD1(mysql_store_result, MYSQL_RES* (MYSQL *mysql)); + MOCK_METHOD1(mysql_use_result, MYSQL_RES* (MYSQL *mysql)); + MOCK_METHOD1(mysql_field_count, unsigned int (MYSQL *mysql)); + MOCK_METHOD1(mysql_affected_rows, my_ulonglong (MYSQL *mysql)); + MOCK_METHOD1(mysql_insert_id, my_ulonglong (MYSQL *mysql)); + MOCK_METHOD4(mysql_real_escape_string, unsigned long (MYSQL *mysql, char *to, const char *from, unsigned long length)); + MOCK_METHOD1(mysql_close, void (MYSQL *mysql)); + MOCK_METHOD8(mysql_real_connect, MYSQL* (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag)); + MOCK_METHOD1(mysql_init, MYSQL* (MYSQL *mysql)); + + MariaDbMock() + { setInstance(this); } + + ~MariaDbMock() + { clearInstance(this); } +}; + +my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res); +unsigned int STDCALL mysql_num_fields (MYSQL_RES *res); +MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res); +void STDCALL mysql_free_result (MYSQL_RES *res); +MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET); +void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset); +unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res); +MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res); +MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res); + +int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length); +unsigned int STDCALL mysql_errno (MYSQL *mysql); +const char* STDCALL mysql_error (MYSQL *mysql); +MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql); +MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql); +unsigned int STDCALL mysql_field_count (MYSQL *mysql); +my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql); +my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql); +unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); +void STDCALL mysql_close (MYSQL *mysql); +MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); +MYSQL* STDCALL mysql_init (MYSQL *mysql); \ No newline at end of file