From 2fcb504b9a1e1a8d740a7a778457cd3ec6008263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 7 Dec 2025 22:18:01 +0100 Subject: [PATCH] schema creation progress --- .../matador/object/foreign_node_completer.hpp | 246 ++++++++++++------ .../object/internal/shadow_repository.hpp | 4 + include/matador/object/relation_completer.hpp | 30 +-- include/matador/object/relation_endpoint.hpp | 14 +- include/matador/object/repository.hpp | 11 +- .../object/internal/shadow_repository.cpp | 14 +- source/core/object/relation_endpoint.cpp | 6 +- source/core/object/repository.cpp | 4 + source/orm/orm/schema.cpp | 38 +++ test/backends/SchemaTest.cpp | 62 ++--- test/core/object/SchemaTest.cpp | 75 ++++-- 11 files changed, 336 insertions(+), 168 deletions(-) diff --git a/include/matador/object/foreign_node_completer.hpp b/include/matador/object/foreign_node_completer.hpp index 3ad1cc6..0eb965a 100644 --- a/include/matador/object/foreign_node_completer.hpp +++ b/include/matador/object/foreign_node_completer.hpp @@ -2,6 +2,7 @@ #define FOREIGN_NODE_COMPLETER_HPP #include "matador/object/internal/shadow_repository.hpp" +#include "matador/object/many_to_many_relation.hpp" #include "matador/object/repository_node.hpp" #include "matador/object/join_columns_collector.hpp" #include "matador/object/object_ptr.hpp" @@ -12,125 +13,214 @@ #include -namespace matador::object { +#include "repository.hpp" +namespace matador::object { /** * Processes the given node and ensures * that all foreign nodes needed by the given node * relations are attached in schema. */ -template < typename NodeType > +template class foreign_node_completer final { private: - using node_ptr = std::shared_ptr; + using node_ptr = std::shared_ptr; public: - template - static void complete(const std::shared_ptr &node) { - internal::shadow_repository shadow(node->repo_); - foreign_node_completer completer(shadow); + template + static void complete(const std::shared_ptr &node) { + internal::shadow_repository shadow(node->repo_); + foreign_node_completer completer(shadow); - completer.complete_node(node); - } + completer.complete_node(node); + } - template - static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {} - static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} - template - static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} - template - static void on_attribute(const char * /*id*/, std::optional &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + template + static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, const utils::primary_key_attribute & /*attr*/ = utils::default_pk_attributes) {} + static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} + template + static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + template + static void on_attribute(const char * /*id*/, std::optional &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + template + void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/); + template + void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/); + template + void on_has_many(const char *id, CollectionType &, + const char *join_column, + const utils::foreign_attributes &attr, + std::enable_if_t::value> * = nullptr); - template - void on_belongs_to(const char *id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/); - template - void on_has_one(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/); + template + void on_has_many(const char * /*id*/, + CollectionType &, + const char * /*join_column*/, + const utils::foreign_attributes & /*attr*/, + std::enable_if_t::value> * = nullptr) { + } - template - void on_has_many(const char *id, CollectionType &, const char *join_column, const utils::foreign_attributes &attr, std::enable_if_t::value> * = nullptr); - template - void on_has_many(const char * /*id*/, CollectionType &, const char * /*join_column*/, const utils::foreign_attributes & /*attr*/, std::enable_if_t::value> * = nullptr) {} - - template - void on_has_many_to_many(const char *id, CollectionType &collection, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr); - template - void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr); + template + void on_has_many_to_many(const char *id, + CollectionType &collection, + const char *join_column, + const char *inverse_join_column, + const utils::foreign_attributes &attr); + template + void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr); private: - explicit foreign_node_completer(internal::shadow_repository &shadow) - : repo_(shadow) - , log_(logger::create_logger("node_completer")) {} + explicit foreign_node_completer(internal::shadow_repository &shadow) + : repo_(shadow) + , log_(logger::create_logger("node_completer")) {} - void complete_node(const std::shared_ptr &node) { - nodes_.push(node); + void complete_node(const std::shared_ptr &node) { + nodes_.push(node); - NodeType obj; - access::process(*this, obj); - nodes_.pop(); + NodeType obj; + access::process(*this, obj); + nodes_.pop(); + } + + template + void attach_node(const std::string &name = "") { + if (repo_.contains(typeid(Type))) { + return; + } + const auto node = repository_node::make_node(repo_.repo(), name); + if (auto result = repo_.attach_node(node)) { + complete(result.value()); + } + } + + template + void attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) { + using relation_value_type = many_to_many_relation; + using value_type = Type; + + // Check if the object_ptr type is already inserted in the schema (by id) + auto result = repo_.find_node(typeid(value_type)); + if (!result) { + // Todo: throw internal error or attach node + return; } - template - void attach_node(const std::string &name = "") { - if (repo_.contains(typeid(Type))) { - return; - } - const auto node = repository_node::make_node(repo_.repo(), name); - if (auto result = repo_.attach_node(node)) { - complete(result.value()); - } + const auto foreign_node = result.value(); + result = repo_.find_node(name); + if (result) { + return; + } + // Relation does not exist. Create it. + auto creator = [join_column, inverse_join_column] { + return std::make_unique(join_column, inverse_join_column); + }; + + result = repository_node::make_relation_node(repo_.repo(), name, std::move(creator)); + if (!result) { + // Todo: throw internal error + return; } - template - void attach_relation_node(const std::string &name) { - if (repo_.contains(typeid(Type))) { - return; - } - const auto node = repository_node::make_node(repo_.repo(), ""); - if (auto result = repo_.attach_node(node)) { - complete(result.value()); - } - } -private: - template< typename Type > - friend class foreign_node_completer; + auto& node = result.value(); + complete(result.value()); + + // auto& node = result.value(); + const auto local_endpoint = std::make_shared(name, relation_type::HasMany, node); + const auto join_endpoint = std::make_shared(join_column, relation_type::BelongsTo, nodes_.top()); + const auto inverse_join_endpoint = std::make_shared(inverse_join_column, relation_type::BelongsTo, foreign_node); + const auto foreign_endpoint = std::make_shared(name, relation_type::HasMany, node); + // register relation endpoint in local node + nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); + // register relation endpoint in foreign node + foreign_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint); + // register endpoints in relation node + node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint); + node->info_->register_relation_endpoint(typeid(value_type), inverse_join_endpoint); + // link endpoints + link_relation_endpoints(local_endpoint, join_endpoint); + link_relation_endpoints(foreign_endpoint, inverse_join_endpoint); + } private: - std::stack nodes_; - internal::shadow_repository &repo_; - logger::logger log_; - join_columns_collector join_columns_collector_{}; + using endpoint_ptr = std::shared_ptr; + static void register_relation_endpoints(const endpoint_ptr &endpoint, + const endpoint_ptr &other_endpoint); + static void link_relation_endpoints(const endpoint_ptr &endpoint, + const endpoint_ptr &other_endpoint); + +private: + template + friend class foreign_node_completer; + +private: + std::stack nodes_; + internal::shadow_repository &repo_; + logger::logger log_; + join_columns_collector join_columns_collector_{}; }; -template < typename NodeType > +template template -void foreign_node_completer::on_belongs_to( const char* /*id*/, ForeignPointerType&, const utils::foreign_attributes& ) { - attach_node(); +void foreign_node_completer::on_belongs_to(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) { + attach_node(); } -template < typename NodeType > +template template -void foreign_node_completer::on_has_one( const char*, ForeignPointerType&, const utils::foreign_attributes& ) { - attach_node(); +void foreign_node_completer::on_has_one(const char *, ForeignPointerType &, const utils::foreign_attributes &) { + attach_node(); } -template < typename NodeType > +template template -void foreign_node_completer::on_has_many( const char* /*id*/, CollectionType&, const char* /*join_column*/, const utils::foreign_attributes& /*attr*/, std::enable_if_t::value>* ) { - attach_node(); +void foreign_node_completer::on_has_many(const char * /*id*/, + CollectionType &, const char * /*join_column*/, + const utils::foreign_attributes & /*attr*/, + std::enable_if_t::value> *) { + attach_node(); } -template < typename NodeType > +template template -void foreign_node_completer::on_has_many_to_many( const char* id, CollectionType& /*collection*/, const char* /*join_column*/, const char* /*inverse_join_column*/, const utils::foreign_attributes& /*attr*/ ) { - attach_relation_node(id); +void foreign_node_completer::on_has_many_to_many(const char *id, CollectionType & /*collection*/, + const char *join_column, + const char *inverse_join_column, + const utils::foreign_attributes & /*attr*/) { + if (!repo_.expecting_relation_node(id)) { + repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type)); + } else { + attach_relation_node(id, join_column, inverse_join_column); + repo_.remove_expected_relation_node(id); + } } -template < typename NodeType > +template template -void foreign_node_completer::on_has_many_to_many( const char* id, CollectionType& /*collection*/, const utils::foreign_attributes& /*attr*/ ) { - attach_relation_node(id); +void foreign_node_completer::on_has_many_to_many(const char *id, + CollectionType & /*collection*/, + const utils::foreign_attributes & /*attr*/) { + if (!repo_.expecting_relation_node(id)) { + repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type)); + } else { + const auto join_columns = join_columns_collector_.collect(); + attach_relation_node(id, join_columns.join_column, join_columns.inverse_join_column); + repo_.remove_expected_relation_node(id); + } } +template +void foreign_node_completer::register_relation_endpoints(const endpoint_ptr &endpoint, + const endpoint_ptr &other_endpoint) { + endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), endpoint); + other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint); + link_relation_endpoints(endpoint, other_endpoint); +} + +template +void foreign_node_completer::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) { + endpoint->link_foreign_endpoint(other_endpoint); + other_endpoint->link_foreign_endpoint(endpoint); +} } #endif //FOREIGN_NODE_COMPLETER_HPP diff --git a/include/matador/object/internal/shadow_repository.hpp b/include/matador/object/internal/shadow_repository.hpp index 472fe89..8647756 100644 --- a/include/matador/object/internal/shadow_repository.hpp +++ b/include/matador/object/internal/shadow_repository.hpp @@ -27,6 +27,10 @@ public: [[nodiscard]] utils::result attach_node(const std::shared_ptr &node) const; [[nodiscard]] utils::result detach_node(const std::shared_ptr &node) const; + [[nodiscard]] bool expecting_relation_node(const std::string &name) const; + void expect_relation_node(const std::string &name, const std::type_index &ti) const; + void remove_expected_relation_node(const std::string &name) const; + private: repository& repo_; }; diff --git a/include/matador/object/relation_completer.hpp b/include/matador/object/relation_completer.hpp index 38aedac..3e38fe8 100644 --- a/include/matador/object/relation_completer.hpp +++ b/include/matador/object/relation_completer.hpp @@ -177,13 +177,13 @@ void relation_completer::on_has_many(const char *id, CollectionType &, if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) { // corresponding belongs_to is available and was called (has_many <-> belongs_to) // complete the relation - const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, foreign_node); + const auto local_endpoint = std::make_shared(id, relation_type::HasMany, foreign_node); nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); link_relation_endpoints(local_endpoint, it->second); } else if (join_column_finder::has_join_column(join_column)) { // corresponding belongs_to is available but was not called (has_many <-> belongs_to) // prepare the relation - const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, foreign_node); + const auto local_endpoint = std::make_shared(id, relation_type::HasMany, foreign_node); nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); } else { // A relation table is necessary @@ -200,13 +200,13 @@ void relation_completer::on_has_many(const char *id, CollectionType &, // Todo: throw internal error return; } - const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, result.value()); - const auto foreign_endpoint = std::make_shared("id", relation_type::BELONGS_TO, nodes_.top()); + const auto local_endpoint = std::make_shared(id, relation_type::HasMany, result.value()); + const auto foreign_endpoint = std::make_shared("id", relation_type::BelongsTo, nodes_.top()); nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint); link_relation_endpoints(local_endpoint, foreign_endpoint); - const auto foreign_value_endpoint = std::make_shared(join_column, relation_type::BELONGS_TO, foreign_node); + const auto foreign_value_endpoint = std::make_shared(join_column, relation_type::BelongsTo, foreign_node); result.value()->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint); } } @@ -230,8 +230,8 @@ void relation_completer::on_has_many(const char *id, CollectionType &, con return; } - const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, result.value()); - const auto foreign_endpoint = std::make_shared(join_column, relation_type::BELONGS_TO, nodes_.top()); + const auto local_endpoint = std::make_shared(id, relation_type::HasMany, result.value()); + const auto foreign_endpoint = std::make_shared(join_column, relation_type::BelongsTo, nodes_.top()); nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint); @@ -272,10 +272,10 @@ void relation_completer::on_has_many_to_many(const char *id, } auto& node = result.value(); - const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, node); - const auto join_endpoint = std::make_shared(join_column, relation_type::BELONGS_TO, nodes_.top()); - const auto inverse_join_endpoint = std::make_shared(inverse_join_column, relation_type::BELONGS_TO, foreign_node); - const auto foreign_endpoint = std::make_shared(id, relation_type::HAS_MANY, node); + const auto local_endpoint = std::make_shared(id, relation_type::HasMany, node); + const auto join_endpoint = std::make_shared(join_column, relation_type::BelongsTo, nodes_.top()); + const auto inverse_join_endpoint = std::make_shared(inverse_join_column, relation_type::BelongsTo, foreign_node); + const auto foreign_endpoint = std::make_shared(id, relation_type::HasMany, node); // register relation endpoint in local node nodes_.top()->info_->register_relation_endpoint(typeid(typename CollectionType::value_type::value_type), local_endpoint); // register relation endpoint in foreign node @@ -318,7 +318,7 @@ void relation_completer::on_has_one(const char *id, auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type)); if (local_it == nodes_.top()->info().endpoint_end()) { - const auto local_endpoint = std::make_shared(id, relation_type::HAS_ONE, result.value()); + const auto local_endpoint = std::make_shared(id, relation_type::HasOne, result.value()); local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint); } if (const auto foreign_it = result.value()->info().find_relation_endpoint(typeid(Type)); foreign_it != result.value()->info().endpoint_end()) { @@ -346,11 +346,11 @@ void relation_completer::on_belongs_to(const char *id, if (const auto it = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index()); it != foreign_node->info().endpoint_end()) { // Found corresponding relation endpoint in the foreign node if (it->second->is_has_one()) { - const auto endpoint = std::make_shared(id, relation_type::BELONGS_TO, foreign_node); + const auto endpoint = std::make_shared(id, relation_type::BelongsTo, foreign_node); nodes_.top()->info_->register_relation_endpoint(ti, endpoint); link_relation_endpoints(endpoint, it->second); } else if (it->second->is_has_many()) { - const auto endpoint = std::make_shared(id, relation_type::BELONGS_TO, foreign_node); + const auto endpoint = std::make_shared(id, relation_type::BelongsTo, foreign_node); nodes_.top()->info_->register_relation_endpoint(ti, endpoint); link_relation_endpoints(endpoint, it->second); } else if (it->second->foreign_endpoint()->node().type_index() == typeid(many_to_many_relation)) { @@ -368,7 +368,7 @@ void relation_completer::on_belongs_to(const char *id, } } else { // Relation node was not found, create only endpoint. - const auto endpoint = std::make_shared(id, relation_type::BELONGS_TO, foreign_node); + const auto endpoint = std::make_shared(id, relation_type::BelongsTo, foreign_node); nodes_.top()->info_->register_relation_endpoint(ti, endpoint); } } diff --git a/include/matador/object/relation_endpoint.hpp b/include/matador/object/relation_endpoint.hpp index 05c1812..4db8bc1 100644 --- a/include/matador/object/relation_endpoint.hpp +++ b/include/matador/object/relation_endpoint.hpp @@ -11,15 +11,15 @@ namespace matador::object { class repository_node; enum class relation_type : uint8_t { - BELONGS_TO, - HAS_ONE, - HAS_MANY + BelongsTo, + HasOne, + HasMany }; static const utils::enum_mapper relation_type_enum({ - { relation_type::BELONGS_TO, "belongs_to" }, - { relation_type::HAS_ONE, "has_one" }, - { relation_type::HAS_MANY, "has_many" }, + { relation_type::BelongsTo, "belongs_to" }, + { relation_type::HasOne, "has_one" }, + { relation_type::HasMany, "has_many" }, }); class relation_endpoint { @@ -43,6 +43,8 @@ public: private: template friend class relation_completer; + template + friend class foreign_node_completer; std::string field_name_; relation_type type_; diff --git a/include/matador/object/repository.hpp b/include/matador/object/repository.hpp index f20e4d9..cb55be2 100644 --- a/include/matador/object/repository.hpp +++ b/include/matador/object/repository.hpp @@ -46,7 +46,7 @@ public: return utils::failure(result.err()); } foreign_node_completer::template complete(node); - relation_completer::complete(node); + // relation_completer::complete(node); } else if (!has_node(name)) { it->second->update_name(name); nodes_by_name_[name] = it->second; @@ -177,12 +177,9 @@ private: static void insert_node(const node_ptr &parent, const node_ptr &child); void remove_node(const node_ptr &node); - bool expecting_relation_node(const std::string &name) const; - template - void expect_relation_node(const std::string &name) { - expected_relation_nodes_[name] = std::type_index(typeid(NodeType)); - } - void remove_expected_relation_node(const std::string &name); + bool expecting_relation_node(const std::string &name) const; + void expect_relation_node(const std::string &name, const std::type_index &ti); + void remove_expected_relation_node(const std::string &name); private: friend class internal::shadow_repository; diff --git a/source/core/object/internal/shadow_repository.cpp b/source/core/object/internal/shadow_repository.cpp index e25d451..a2ce3b5 100644 --- a/source/core/object/internal/shadow_repository.cpp +++ b/source/core/object/internal/shadow_repository.cpp @@ -30,4 +30,16 @@ utils::result shadow_repository::atta utils::result shadow_repository::detach_node( const std::shared_ptr& node ) const { return repo_.detach(node); } -} \ No newline at end of file + +bool shadow_repository::expecting_relation_node(const std::string &name) const { + return repo_.expecting_relation_node(name); +} + +void shadow_repository::expect_relation_node(const std::string &name, const std::type_index &ti) const { + repo_.expect_relation_node(name, ti); +} + +void shadow_repository::remove_expected_relation_node(const std::string &name) const { + repo_.remove_expected_relation_node(name); +} +} diff --git a/source/core/object/relation_endpoint.cpp b/source/core/object/relation_endpoint.cpp index 9da5689..060fdfc 100644 --- a/source/core/object/relation_endpoint.cpp +++ b/source/core/object/relation_endpoint.cpp @@ -30,15 +30,15 @@ std::shared_ptr relation_endpoint::node_ptr() const { } bool relation_endpoint::is_has_one() const { - return type_ == relation_type::HAS_ONE; + return type_ == relation_type::HasOne; } bool relation_endpoint::is_has_many() const { - return type_ == relation_type::HAS_MANY; + return type_ == relation_type::HasMany; } bool relation_endpoint::is_belongs_to() const { - return type_ == relation_type::BELONGS_TO; + return type_ == relation_type::BelongsTo; } std::shared_ptr relation_endpoint::foreign_endpoint() const { diff --git a/source/core/object/repository.cpp b/source/core/object/repository.cpp index 5a78b3b..dba97ee 100644 --- a/source/core/object/repository.cpp +++ b/source/core/object/repository.cpp @@ -206,6 +206,10 @@ bool repository::expecting_relation_node( const std::string& name ) const { return expected_relation_nodes_.count(name) > 0; } +void repository::expect_relation_node(const std::string &name, const std::type_index &ti) { + expected_relation_nodes_.insert({name, ti}); +} + void repository::remove_expected_relation_node( const std::string& name ) { expected_relation_nodes_.erase(name); } diff --git a/source/orm/orm/schema.cpp b/source/orm/orm/schema.cpp index 5711811..a2b34f9 100644 --- a/source/orm/orm/schema.cpp +++ b/source/orm/orm/schema.cpp @@ -69,9 +69,26 @@ utils::result schema::create() const { } } + // create primary key constraints + for (const auto &node: repo_) { + for (const auto& cons : node->info().constraints()) { + if (!cons.is_primary_key_constraint()) { + continue; + } + auto ctx = build_add_constraint_context(*node, cons); + + std::cout << ctx.sql << std::endl; + if (auto result = c->execute(ctx.sql); !result) { + return utils::failure(result.err()); + } + } + } // create table constraints for (const auto &node: repo_) { for (const auto& cons : node->info().constraints()) { + if (cons.is_primary_key_constraint()) { + continue; + } auto ctx = build_add_constraint_context(*node, cons); std::cout << ctx.sql << std::endl; @@ -85,9 +102,30 @@ utils::result schema::create() const { utils::result schema::drop() const { auto c = pool_.acquire(); + // drop table primary key constraints + for (const auto &node: repo_) { + for (const auto& cons : node->info().constraints()) { + if (cons.is_primary_key_constraint()) { + continue; + } + auto ctx = query::query::alter() + .table(node->name()) + .drop_constraint(cons.name()) + .compile(*c); + + std::cout << ctx.sql << std::endl; + if (auto result = c->execute(ctx.sql); !result) { + return utils::failure(result.err()); + } + } + } + // drop table constraints for (const auto &node: repo_) { for (const auto& cons : node->info().constraints()) { + if (!cons.is_primary_key_constraint()) { + continue; + } auto ctx = query::query::alter() .table(node->name()) .drop_constraint(cons.name()) diff --git a/test/backends/SchemaTest.cpp b/test/backends/SchemaTest.cpp index 81ba5a2..07ffe58 100644 --- a/test/backends/SchemaTest.cpp +++ b/test/backends/SchemaTest.cpp @@ -14,47 +14,47 @@ using namespace matador; using namespace matador::test; TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-many]") { - using namespace matador::test; - orm::schema repo(pool/*, "NoopSchema"*/); + using namespace matador::test; + orm::schema repo(pool/*, "NoopSchema"*/); - auto result = repo.attach("departments") - .and_then( [&repo] { return repo.attach("employees"); } ); - REQUIRE(result); + auto result = repo.attach("departments") + .and_then([&repo] { return repo.attach("employees"); }); + REQUIRE(result); - result = repo.create(); - REQUIRE(result); + result = repo.create(); + REQUIRE(result); - auto exists_result = repo.table_exists("departments"); - REQUIRE(exists_result.is_ok()); - REQUIRE(exists_result.value()); + auto exists_result = repo.table_exists("departments"); + REQUIRE(exists_result.is_ok()); + REQUIRE(exists_result.value()); - result = repo.drop(); - REQUIRE(result); + result = repo.drop(); + REQUIRE(result); - exists_result = repo.table_exists("departments"); - REQUIRE(exists_result.is_ok()); - REQUIRE(!exists_result.value()); + exists_result = repo.table_exists("departments"); + REQUIRE(exists_result.is_ok()); + REQUIRE(!exists_result.value()); } TEST_CASE_METHOD(SchemaFixture, "Test schema many-to-many", "[schema][many-to-many]") { - using namespace matador::test; - orm::schema repo(pool/*, "NoopSchema"*/); + using namespace matador::test; + orm::schema repo(pool/*, "NoopSchema"*/); - auto result = repo.attach("recipes") - .and_then( [&repo] { return repo.attach("ingredients"); } ); - REQUIRE(result); + auto result = repo.attach("recipes") + .and_then([&repo] { return repo.attach("ingredients"); }); + REQUIRE(result); - result = repo.create(); - REQUIRE(result); + result = repo.create(); + REQUIRE(result); - auto exists_result = repo.table_exists("recipes"); - REQUIRE(exists_result.is_ok()); - REQUIRE(exists_result.value()); + auto exists_result = repo.table_exists("recipes"); + REQUIRE(exists_result.is_ok()); + REQUIRE(exists_result.value()); - result = repo.drop(); - REQUIRE(result); + result = repo.drop(); + REQUIRE(result); - exists_result = repo.table_exists("recipes"); - REQUIRE(exists_result.is_ok()); - REQUIRE(!exists_result.value()); -} \ No newline at end of file + exists_result = repo.table_exists("recipes"); + REQUIRE(exists_result.is_ok()); + REQUIRE(!exists_result.value()); +} diff --git a/test/core/object/SchemaTest.cpp b/test/core/object/SchemaTest.cpp index e748078..7495e84 100644 --- a/test/core/object/SchemaTest.cpp +++ b/test/core/object/SchemaTest.cpp @@ -5,18 +5,24 @@ #include "../../models/department.hpp" #include "../../models/recipe.hpp" -struct node {}; +struct node { +}; using namespace matador; struct person { virtual ~person() = default; - template < typename Operator > - void process(Operator &/*op*/) {} + + template + void process(Operator &/*op*/) { + } }; -struct student final : person {}; -struct teacher final : person {}; +struct student final : person { +}; + +struct teacher final : person { +}; struct names { unsigned int id{}; @@ -33,68 +39,81 @@ struct names { TEST_CASE("Test empty prototype tree", "[schema_node][empty]") { const object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); } TEST_CASE("Test add type to prototype tree", "[schema_node][add]") { object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); auto res = repo.attach("person"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); res = repo.attach("student"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); res = repo.attach("teacher"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); - REQUIRE( !repo.empty() ); - REQUIRE( repo.size() == 3 ); + REQUIRE(!repo.empty()); + REQUIRE(repo.size() == 3); } TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous]") { object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); auto res = repo.attach("person"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); - REQUIRE( repo.size() == 1 ); + REQUIRE(repo.size() == 1); auto it = repo.begin(); - REQUIRE( it->name() == "person" ); - REQUIRE( (--it)->name() == "person" ); - REQUIRE( ++it == repo.end() ); + REQUIRE(it->name() == "person"); + REQUIRE((--it)->name() == "person"); + REQUIRE(++it == repo.end()); } TEST_CASE("Test automatic creating of a relation table with foreign key", "[schema][relation_table][foreign_key]") { object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); auto res = repo.attach("department"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); REQUIRE(repo.size() == 2); } TEST_CASE("Test automatic creating of a relation table with values", "[schema][relation_table][values]") { object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); auto res = repo.attach("names"); - REQUIRE( res.is_ok() ); + REQUIRE(res.is_ok()); } TEST_CASE("Test one to many", "[relation][one-to-many]") { object::repository repo; - REQUIRE( repo.empty() ); + REQUIRE(repo.empty()); auto res = repo.attach("departments") - .and_then( [&repo] { return repo.attach("employees"); } ); - REQUIRE( res.is_ok() ); + .and_then([&repo] { return repo.attach("employees"); }); + REQUIRE(res.is_ok()); + REQUIRE(repo.size() == 2); + REQUIRE(repo.contains("departments")); + REQUIRE(repo.contains("employees")); +} + +TEST_CASE("Test one to many reverse", "[relation][one-to-many][reverse]") { + object::repository repo; + + REQUIRE(repo.empty()); + + auto res = repo.attach("employees") + .and_then([&repo] { return repo.attach("departments"); }); + REQUIRE(res.is_ok()); REQUIRE(repo.size() == 2); REQUIRE(repo.contains("departments")); REQUIRE(repo.contains("employees")); @@ -106,11 +125,13 @@ TEST_CASE("Test many to many relation", "[relation][many-to-many]") { REQUIRE(repo.empty()); auto result = repo.attach("recipes") - .and_then( [&repo] { return repo.attach("ingredients"); } ); + .and_then([&repo] { return repo.attach("ingredients"); }); REQUIRE(result); REQUIRE(repo.size() == 3); REQUIRE(repo.contains("ingredients")); REQUIRE(repo.contains("recipes")); REQUIRE(repo.contains("recipe_ingredients")); -} \ No newline at end of file + + auto info = repo.basic_info("ingredients"); +}