query/include/matador/object/foreign_node_completer.hpp

168 lines
7.2 KiB
C++

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