diff --git a/include/cpphibernate/driver/mariadb/schema/attributes.h b/include/cpphibernate/driver/mariadb/schema/attributes.h index 16db25b..a4e072c 100644 --- a/include/cpphibernate/driver/mariadb/schema/attributes.h +++ b/include/cpphibernate/driver/mariadb/schema/attributes.h @@ -9,7 +9,7 @@ beg_namespace_cpphibernate_driver_mariadb { - + /* attributes_t */ struct attributes_t : diff --git a/include/cpphibernate/driver/mariadb/schema/field.h b/include/cpphibernate/driver/mariadb/schema/field.h index 3f852d7..0274f1d 100644 --- a/include/cpphibernate/driver/mariadb/schema/field.h +++ b/include/cpphibernate/driver/mariadb/schema/field.h @@ -2,6 +2,9 @@ #include #include +#include +#include +#include #include #include #include @@ -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 */ diff --git a/include/cpphibernate/driver/mariadb/schema/table.h b/include/cpphibernate/driver/mariadb/schema/table.h index d39953c..c758d9a 100644 --- a/include/cpphibernate/driver/mariadb/schema/table.h +++ b/include/cpphibernate/driver/mariadb/schema/table.h @@ -57,6 +57,8 @@ beg_namespace_cpphibernate_driver_mariadb , data_fields () { } virtual ~table_t() = default; + + void print(std::ostream& os) const; }; /* table_simple_t */ diff --git a/include/cpphibernate/misc.h b/include/cpphibernate/misc.h index ae02dec..c556322 100644 --- a/include/cpphibernate/misc.h +++ b/include/cpphibernate/misc.h @@ -2,4 +2,5 @@ #include #include +#include #include \ No newline at end of file diff --git a/include/cpphibernate/misc/meta.h b/include/cpphibernate/misc/meta.h index 9ea58da..2821f37 100644 --- a/include/cpphibernate/misc/meta.h +++ b/include/cpphibernate/misc/meta.h @@ -6,6 +6,7 @@ #include +#include #include beg_namespace_cpphibernate_misc @@ -118,5 +119,13 @@ beg_namespace_cpphibernate_misc template using real_dataset_t = typename __impl::real_dataset_impl::type; + /* hibernate_exception */ + + struct hibernate_exception + : public utl::exception + { + using utl::exception::exception; + }; + } end_namespace_cpphibernate_misc \ No newline at end of file diff --git a/include/cpphibernate/misc/print.h b/include/cpphibernate/misc/print.h new file mode 100644 index 0000000..dcf7c06 --- /dev/null +++ b/include/cpphibernate/misc/print.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace std +{ + + template + inline auto operator <<(basic_ostream& os, X&& x) + -> ::utl::mp::enable_if< + utl::mp::is_valid(x).print(os))>, + basic_ostream&> + { + std::forward(x).print(os); + return os; + } + +} + +beg_namespace_cpphibernate_misc +{ + + template + 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 + constexpr decltype(auto) operator()(T_container&& container, bool do_indent, T_func&& func) const + { + return container_printer + { + std::forward(container), + do_indent, + std::forward(func) + }; + } + + template + constexpr decltype(auto) operator()(T_container&& container, bool do_indent) const + { + return this->operator()( + std::forward(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 \ No newline at end of file diff --git a/include/cpphibernate/schema.h b/include/cpphibernate/schema.h index 19d699c..cebb0f4 100644 --- a/include/cpphibernate/schema.h +++ b/include/cpphibernate/schema.h @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/include/cpphibernate/schema/macros.h b/include/cpphibernate/schema/macros.h index b4e514c..bd778f9 100644 --- a/include/cpphibernate/schema/macros.h +++ b/include/cpphibernate/schema/macros.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) \ No newline at end of file diff --git a/include/cpphibernate/schema/print.h b/include/cpphibernate/schema/print.h deleted file mode 100644 index 322ab42..0000000 --- a/include/cpphibernate/schema/print.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -namespace std -{ - - template - inline auto operator <<(basic_ostream& os, X&& x) - -> ::utl::mp::enable_if< - utl::mp::is_valid(x).print(os))>, - basic_ostream&> - { - std::forward(x).print(os); - return os; - } - -} \ No newline at end of file diff --git a/src/driver/mariadb/schema/field.cpp b/src/driver/mariadb/schema/field.cpp new file mode 100644 index 0000000..3c27579 --- /dev/null +++ b/src/driver/mariadb/schema/field.cpp @@ -0,0 +1,31 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include + +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 << '}'; +} \ No newline at end of file diff --git a/src/driver/mariadb/schema/schema.cpp b/src/driver/mariadb/schema/schema.cpp index 372e5d2..f790180 100644 --- a/src/driver/mariadb/schema/schema.cpp +++ b/src/driver/mariadb/schema/schema.cpp @@ -1,15 +1,112 @@ #include #include + +#include +#include +#include + +#include #include +using namespace ::utl; using namespace ::cpphibernate::driver::mariadb_impl; void schema_t::update() { +// clear everything + for (auto& kvp : tables) + { + assert(static_cast(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(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(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(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(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 << '}'; } \ No newline at end of file diff --git a/src/driver/mariadb/schema/table.cpp b/src/driver/mariadb/schema/table.cpp new file mode 100644 index 0000000..30eca9f --- /dev/null +++ b/src/driver/mariadb/schema/table.cpp @@ -0,0 +1,49 @@ +#include +#include + +#include +#include +#include + +#include +#include + +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 << '}'; +} \ No newline at end of file