| @@ -9,7 +9,7 @@ | |||||
| beg_namespace_cpphibernate_driver_mariadb | beg_namespace_cpphibernate_driver_mariadb | ||||
| { | { | ||||
| /* attributes_t */ | /* attributes_t */ | ||||
| struct attributes_t : | struct attributes_t : | ||||
| @@ -2,6 +2,9 @@ | |||||
| #include <cpphibernate/misc.h> | #include <cpphibernate/misc.h> | ||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpphibernate/schema/field.h> | |||||
| #include <cpphibernate/schema/table.h> | |||||
| #include <cpphibernate/schema/schema.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | #include <cpphibernate/driver/mariadb/schema/field.fwd.h> | ||||
| #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | #include <cpphibernate/driver/mariadb/schema/table.fwd.h> | ||||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | #include <cpphibernate/driver/mariadb/schema/attributes.h> | ||||
| @@ -40,6 +43,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| , referenced_table (nullptr) | , referenced_table (nullptr) | ||||
| { } | { } | ||||
| virtual ~field_t() = default; | virtual ~field_t() = default; | ||||
| void print(std::ostream& os) const; | |||||
| }; | }; | ||||
| /* simple_field_t */ | /* simple_field_t */ | ||||
| @@ -57,6 +57,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| , data_fields () | , data_fields () | ||||
| { } | { } | ||||
| virtual ~table_t() = default; | virtual ~table_t() = default; | ||||
| void print(std::ostream& os) const; | |||||
| }; | }; | ||||
| /* table_simple_t */ | /* table_simple_t */ | ||||
| @@ -2,4 +2,5 @@ | |||||
| #include <cpphibernate/misc/general.h> | #include <cpphibernate/misc/general.h> | ||||
| #include <cpphibernate/misc/meta.h> | #include <cpphibernate/misc/meta.h> | ||||
| #include <cpphibernate/misc/print.h> | |||||
| #include <cpphibernate/misc/wrap.h> | #include <cpphibernate/misc/wrap.h> | ||||
| @@ -6,6 +6,7 @@ | |||||
| #include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
| #include <cpputils/misc/exception.h> | |||||
| #include <cpputils/container/nullable.h> | #include <cpputils/container/nullable.h> | ||||
| beg_namespace_cpphibernate_misc | beg_namespace_cpphibernate_misc | ||||
| @@ -118,5 +119,13 @@ beg_namespace_cpphibernate_misc | |||||
| template<typename T> | template<typename T> | ||||
| using real_dataset_t = typename __impl::real_dataset_impl<T>::type; | using real_dataset_t = typename __impl::real_dataset_impl<T>::type; | ||||
| /* hibernate_exception */ | |||||
| struct hibernate_exception | |||||
| : public utl::exception | |||||
| { | |||||
| using utl::exception::exception; | |||||
| }; | |||||
| } | } | ||||
| end_namespace_cpphibernate_misc | end_namespace_cpphibernate_misc | ||||
| @@ -0,0 +1,112 @@ | |||||
| #pragma once | |||||
| #include <list> | |||||
| #include <vector> | |||||
| #include <memory> | |||||
| #include <iostream> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpputils/misc/indent.h> | |||||
| namespace std | |||||
| { | |||||
| template<typename T_char, typename T_traits, typename X> | |||||
| inline auto operator <<(basic_ostream<T_char, T_traits>& os, X&& x) | |||||
| -> ::utl::mp::enable_if< | |||||
| utl::mp::is_valid<decltype(std::forward<X>(x).print(os))>, | |||||
| basic_ostream<T_char, T_traits>&> | |||||
| { | |||||
| std::forward<X>(x).print(os); | |||||
| return os; | |||||
| } | |||||
| } | |||||
| beg_namespace_cpphibernate_misc | |||||
| { | |||||
| template<typename T_container, typename T_func> | |||||
| struct container_printer | |||||
| { | |||||
| T_container container; | |||||
| bool do_indent; | |||||
| T_func func; | |||||
| inline void print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::utl; | |||||
| auto beg = std::begin(container); | |||||
| auto end = std::end (container); | |||||
| if (beg != end) | |||||
| { | |||||
| if (do_indent) | |||||
| { | |||||
| os << indent << "[" | |||||
| << incindent; | |||||
| } | |||||
| else | |||||
| { | |||||
| os << "["; | |||||
| } | |||||
| size_t index = 0; | |||||
| for (auto it = beg; it != end; ++it) | |||||
| { | |||||
| if (index++) | |||||
| os << ","; | |||||
| if (!do_indent) | |||||
| os << " "; | |||||
| func(os, *it); | |||||
| } | |||||
| if (do_indent) | |||||
| { | |||||
| os << decindent | |||||
| << indent << "]"; | |||||
| } | |||||
| else | |||||
| { | |||||
| os << " ]"; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| os << "[ ]"; | |||||
| } | |||||
| } | |||||
| }; | |||||
| struct print_container_builder | |||||
| { | |||||
| template<typename T_container, typename T_func> | |||||
| constexpr decltype(auto) operator()(T_container&& container, bool do_indent, T_func&& func) const | |||||
| { | |||||
| return container_printer<T_container, T_func> | |||||
| { | |||||
| std::forward<T_container>(container), | |||||
| do_indent, | |||||
| std::forward<T_func>(func) | |||||
| }; | |||||
| } | |||||
| template<typename T_container> | |||||
| constexpr decltype(auto) operator()(T_container&& container, bool do_indent) const | |||||
| { | |||||
| return this->operator()( | |||||
| std::forward<T_container>(container), | |||||
| do_indent, | |||||
| [do_indent](auto& os, auto& value) | |||||
| { | |||||
| using namespace ::utl; | |||||
| if (do_indent) | |||||
| os << indent; | |||||
| os << utl::to_string(value); | |||||
| }); | |||||
| } | |||||
| }; | |||||
| constexpr decltype(auto) print_container = print_container_builder { }; | |||||
| } | |||||
| end_namespace_cpphibernate_misc | |||||
| @@ -6,7 +6,6 @@ | |||||
| #include <cpphibernate/schema/fields.h> | #include <cpphibernate/schema/fields.h> | ||||
| #include <cpphibernate/schema/getter.h> | #include <cpphibernate/schema/getter.h> | ||||
| #include <cpphibernate/schema/macros.h> | #include <cpphibernate/schema/macros.h> | ||||
| #include <cpphibernate/schema/print.h> | |||||
| #include <cpphibernate/schema/schema.h> | #include <cpphibernate/schema/schema.h> | ||||
| #include <cpphibernate/schema/setter.h> | #include <cpphibernate/schema/setter.h> | ||||
| #include <cpphibernate/schema/table.h> | #include <cpphibernate/schema/table.h> | ||||
| @@ -38,6 +38,6 @@ | |||||
| #define cpphibernate_make_id(p_member_ptr) \ | #define cpphibernate_make_id(p_member_ptr) \ | ||||
| cpphibernate_make_field_name( \ | cpphibernate_make_field_name( \ | ||||
| "p_id", \ | |||||
| id, \ | |||||
| p_member_ptr, \ | p_member_ptr, \ | ||||
| cpphibernate::schema::attribute::primary_key) | cpphibernate::schema::attribute::primary_key) | ||||
| @@ -1,19 +0,0 @@ | |||||
| #pragma once | |||||
| #include <iostream> | |||||
| #include <cpphibernate/config.h> | |||||
| namespace std | |||||
| { | |||||
| template<typename T_char, typename T_traits, typename X> | |||||
| inline auto operator <<(basic_ostream<T_char, T_traits>& os, X&& x) | |||||
| -> ::utl::mp::enable_if< | |||||
| utl::mp::is_valid<decltype(std::forward<X>(x).print(os))>, | |||||
| basic_ostream<T_char, T_traits>&> | |||||
| { | |||||
| std::forward<X>(x).print(os); | |||||
| return os; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| #include <string> | |||||
| #include <iostream> | |||||
| #include <cpputils/misc/enum.h> | |||||
| #include <cpputils/misc/string.h> | |||||
| #include <cpputils/misc/indent.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/field.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||||
| using namespace ::utl; | |||||
| using namespace ::cpphibernate::driver::mariadb_impl; | |||||
| void field_t::print(std::ostream& os) const | |||||
| { | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"table_dataset_id\": " << table_dataset_id << "," | |||||
| << indent << "\"value_dataset_id\": " << value_dataset_id << "," | |||||
| << indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << "," | |||||
| << indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << "," | |||||
| << indent << "\"schema_name\": \"" << schema_name << "\"," | |||||
| << indent << "\"table_name\": \"" << table_name << "\"," | |||||
| << indent << "\"field_name\": \"" << field_name << "\"," | |||||
| << indent << "\"attributes\": " << misc::print_container(attributes, false) << "," | |||||
| << indent << "\"table\": " << (table ? std::string("\"") + table->table_name + "\"" : "null") << "," | |||||
| << indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null") | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||
| @@ -1,15 +1,112 @@ | |||||
| #include <string> | #include <string> | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <cpputils/misc/enum.h> | |||||
| #include <cpputils/misc/string.h> | |||||
| #include <cpputils/misc/indent.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | #include <cpphibernate/driver/mariadb/schema/schema.h> | ||||
| using namespace ::utl; | |||||
| using namespace ::cpphibernate::driver::mariadb_impl; | using namespace ::cpphibernate::driver::mariadb_impl; | ||||
| void schema_t::update() | void schema_t::update() | ||||
| { | { | ||||
| // clear everything | |||||
| for (auto& kvp : tables) | |||||
| { | |||||
| assert(static_cast<bool>(kvp.second)); | |||||
| auto& table = *kvp.second; | |||||
| table.primary_key_field = nullptr; | |||||
| table.derived_tables.clear(); | |||||
| table.foreign_key_fields.clear(); | |||||
| table.foreign_table_fields.clear(); | |||||
| table.foreign_table_one_fields.clear(); | |||||
| table.foreign_table_many_fields.clear(); | |||||
| table.data_fields.clear(); | |||||
| } | |||||
| // update references | |||||
| for (auto& kvp : tables) | |||||
| { | |||||
| assert(static_cast<bool>(kvp.second)); | |||||
| auto& table = *kvp.second; | |||||
| // base table | |||||
| auto it = tables.find(table.base_dataset_id); | |||||
| table.base_table = (it != tables.end() | |||||
| ? it->second.get() | |||||
| : nullptr); | |||||
| // derived tables | |||||
| for (auto& id : table.derived_dataset_ids) | |||||
| { | |||||
| it = tables.find(id); | |||||
| if (it == tables.end()) | |||||
| throw misc::hibernate_exception(std::string("unable to find derived table for dataset id ") + std::to_string(id)); | |||||
| table.derived_tables.emplace_back(it->second.get()); | |||||
| } | |||||
| // update fields | |||||
| for (auto& ptr : table.fields) | |||||
| { | |||||
| auto& field = *ptr; | |||||
| // table | |||||
| if (table.dataset_id != field.table_dataset_id) | |||||
| throw misc::hibernate_exception(std::string("dataset id of field '") + field.table_name + '.' + field.field_name + "' does not match!"); | |||||
| field.table = &table; | |||||
| // referenced table | |||||
| it = tables.find(field.value_dataset_id); | |||||
| auto referenced_table = (it != tables.end() | |||||
| ? it->second.get() | |||||
| : nullptr); | |||||
| field.referenced_table = referenced_table; | |||||
| // is primary key field | |||||
| if (field.attributes.count(attribute_t::primary_key)) | |||||
| { | |||||
| if (static_cast<bool>(table.primary_key_field)) | |||||
| throw misc::hibernate_exception(std::string("Table '") + table.table_name + "' can not have more then one primary key!"); | |||||
| table.primary_key_field = &field; | |||||
| } | |||||
| // is foreign table field | |||||
| else if (static_cast<bool>(referenced_table)) | |||||
| { | |||||
| table.foreign_table_fields.emplace_back(&field); | |||||
| if (field.value_is_container) | |||||
| { | |||||
| table.foreign_table_many_fields.emplace_back(&field); | |||||
| referenced_table->foreign_key_fields.push_back(&field); | |||||
| } | |||||
| else | |||||
| { | |||||
| table.foreign_table_one_fields.emplace_back(&field); | |||||
| } | |||||
| } | |||||
| // is data field | |||||
| else | |||||
| { | |||||
| table.data_fields.emplace_back(&field); | |||||
| } | |||||
| } | |||||
| if (!static_cast<bool>(table.primary_key_field)) | |||||
| throw misc::hibernate_exception(std::string("Table '") + table.table_name + "' does not have a primary key!"); | |||||
| } | |||||
| } | } | ||||
| void schema_t::print(std::ostream& os) const | void schema_t::print(std::ostream& os) const | ||||
| { | { | ||||
| os << "fuu" << std::endl; | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"schema_name\": \"" << schema_name << "\"," | |||||
| << indent << "\"tables\": " << misc::print_container(tables, true, [](auto& os, auto& kvp) { | |||||
| kvp.second->print(os); | |||||
| }) | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | } | ||||
| @@ -0,0 +1,49 @@ | |||||
| #include <string> | |||||
| #include <iostream> | |||||
| #include <cpputils/misc/enum.h> | |||||
| #include <cpputils/misc/string.h> | |||||
| #include <cpputils/misc/indent.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/table.h> | |||||
| using namespace ::utl; | |||||
| using namespace ::cpphibernate::driver::mariadb_impl; | |||||
| void table_t::print(std::ostream& os) const | |||||
| { | |||||
| os << indent << '{' | |||||
| << incindent | |||||
| << indent << "\"dataset_id\": " << dataset_id << "," | |||||
| << indent << "\"base_dataset_id\": " << base_dataset_id << "," | |||||
| << indent << "\"table_id\": " << table_id << "," | |||||
| << indent << "\"derived_dataset_ids\": " << misc::print_container(derived_dataset_ids, false) << "," | |||||
| << indent << "\"schema_name\": \"" << schema_name << "\"," | |||||
| << indent << "\"table_name\": \"" << table_name << "\"," | |||||
| << indent << "\"fields\":" << misc::print_container(fields, true, [](auto& os, auto& field) { | |||||
| field->print(os); | |||||
| }) << "," | |||||
| << indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->table_name + "\"" : "null") << "," | |||||
| << indent << "\"derived_tables\":" << misc::print_container(derived_tables, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->table_name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"primary_key_field\": " << (primary_key_field ? std::string("\"") + primary_key_field->field_name + "\"" : "null") << "," | |||||
| << indent << "\"foreign_key_fields\": " << misc::print_container(foreign_key_fields, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->table_name << '.' << ptr->field_name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_fields\": " << misc::print_container(foreign_table_fields, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->field_name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_one_fields\": " << misc::print_container(foreign_table_one_fields, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->field_name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"foreign_table_many_fields\": " << misc::print_container(foreign_table_many_fields, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->field_name << '"'; | |||||
| }) << "," | |||||
| << indent << "\"data_fields\": " << misc::print_container(data_fields, true, [](auto& os, auto& ptr){ | |||||
| os << indent << '"' << ptr->field_name << '"'; | |||||
| }) | |||||
| << decindent | |||||
| << indent << '}'; | |||||
| } | |||||