| @@ -9,7 +9,7 @@ | |||
| beg_namespace_cpphibernate_driver_mariadb | |||
| { | |||
| /* attributes_t */ | |||
| struct attributes_t : | |||
| @@ -2,6 +2,9 @@ | |||
| #include <cpphibernate/misc.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/table.fwd.h> | |||
| #include <cpphibernate/driver/mariadb/schema/attributes.h> | |||
| @@ -40,6 +43,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| , referenced_table (nullptr) | |||
| { } | |||
| virtual ~field_t() = default; | |||
| void print(std::ostream& os) const; | |||
| }; | |||
| /* simple_field_t */ | |||
| @@ -57,6 +57,8 @@ beg_namespace_cpphibernate_driver_mariadb | |||
| , data_fields () | |||
| { } | |||
| virtual ~table_t() = default; | |||
| void print(std::ostream& os) const; | |||
| }; | |||
| /* table_simple_t */ | |||
| @@ -2,4 +2,5 @@ | |||
| #include <cpphibernate/misc/general.h> | |||
| #include <cpphibernate/misc/meta.h> | |||
| #include <cpphibernate/misc/print.h> | |||
| #include <cpphibernate/misc/wrap.h> | |||
| @@ -6,6 +6,7 @@ | |||
| #include <cpphibernate/config.h> | |||
| #include <cpputils/misc/exception.h> | |||
| #include <cpputils/container/nullable.h> | |||
| beg_namespace_cpphibernate_misc | |||
| @@ -118,5 +119,13 @@ beg_namespace_cpphibernate_misc | |||
| template<typename T> | |||
| 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 | |||
| @@ -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/getter.h> | |||
| #include <cpphibernate/schema/macros.h> | |||
| #include <cpphibernate/schema/print.h> | |||
| #include <cpphibernate/schema/schema.h> | |||
| #include <cpphibernate/schema/setter.h> | |||
| #include <cpphibernate/schema/table.h> | |||
| @@ -38,6 +38,6 @@ | |||
| #define cpphibernate_make_id(p_member_ptr) \ | |||
| cpphibernate_make_field_name( \ | |||
| "p_id", \ | |||
| id, \ | |||
| p_member_ptr, \ | |||
| 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 <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> | |||
| using namespace ::utl; | |||
| using namespace ::cpphibernate::driver::mariadb_impl; | |||
| 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 | |||
| { | |||
| 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 << '}'; | |||
| } | |||