#ifndef FOREIGN_NODE_COMPLETER_HPP #define FOREIGN_NODE_COMPLETER_HPP #include "matador/object/internal/shadow_repository.hpp" #include "matador/object/internal/observer_list_copy_creator.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" #include "matador/utils/primary_key_attribute.hpp" #include "matador/logger/log_manager.hpp" #include #include namespace matador::object { template typename... Observers> class completer { public: template void foo(Observers&&... observers) { (std::unique_ptr>(new Observers(std::forward(observers))), ...); } }; /** * Processes the given node and ensures * that all foreign nodes needed by the given node * relations are attached in schema. */ template typename ...Observers> class foreign_node_completer final { private: using node_ptr = std::shared_ptr; public: static void complete(const std::shared_ptr &node, const std::vector>> &observers) { internal::shadow_repository shadow(node->repo_); foreign_node_completer completer(shadow, observers); 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 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 static 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 static 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, const std::vector>> &observers) : repo_(shadow) , log_(logger::create_logger("node_completer")) , observers_(observers) {} void complete_node(const std::shared_ptr &node) { nodes_.push(node); NodeType obj; access::process(*this, obj); nodes_.pop(); } template void attach_node() { if (repo_.contains(typeid(Type))) { return; } auto observers = internal::observer_list_copy_creator::copy_create(observers_); if (repo_.is_node_announced(typeid(Type))) { return; } const auto node = repository_node::make_node(repo_.repo(), "", []{ return std::make_unique(); }, std::move(observers)); repo_.push_announce_node(typeid(Type), node); // if (auto result = repo_.attach_node(node)) { // foreign_node_completer::complete(result.value(), {}); // } } private: 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 typename ...OtherObservers> friend class foreign_node_completer; private: std::stack nodes_; internal::shadow_repository &repo_; logger::logger log_; join_columns_collector join_columns_collector_{}; const std::vector>>& observers_; }; template typename ...Observers> template void foreign_node_completer::on_belongs_to(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) { attach_node(); } template typename ...Observers> template void foreign_node_completer::on_has_one(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) { attach_node(); } template typename ...Observers> 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(); } template typename ...Observers> 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 typename ...Observers> 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