94 lines
4.0 KiB
C++
94 lines
4.0 KiB
C++
#ifndef REPOSITORY_HPP
|
|
#define REPOSITORY_HPP
|
|
|
|
#include "matador/object/basic_repository.hpp"
|
|
|
|
#include "matador/object/foreign_node_completer.hpp"
|
|
#include "matador/object/observer.hpp"
|
|
#include "matador/object/relation_completer.hpp"
|
|
|
|
#include "matador/utils/result.hpp"
|
|
#include "matador/utils/error.hpp"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
|
|
namespace matador::object {
|
|
class repository : public basic_repository {
|
|
public:
|
|
using basic_repository::basic_repository;
|
|
|
|
template<typename Type, template<typename> typename... Observers>
|
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
|
return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers<Type>>(observers)...);
|
|
}
|
|
|
|
template<typename Type, typename SuperType, template<typename> typename... Observers>
|
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
|
|
const auto ti = std::type_index(typeid(SuperType));
|
|
const auto it = find_node(ti);
|
|
if (it == end()) {
|
|
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
|
|
}
|
|
|
|
return attach_type<Type, Observers...>(name, it->name(), std::forward<Observers<Type>>(observers)...);
|
|
}
|
|
|
|
template<typename Type, template<typename> typename... Observers>
|
|
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
|
|
return attach_type<Type, Observers...>(name, parent, std::forward<Observers<Type>>(observers)...);
|
|
}
|
|
template<typename Type, template<typename> typename... Observers>
|
|
[[nodiscard]] utils::result<void, utils::error> attach_type(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
|
|
if (const auto it = nodes_by_type_.find(typeid(Type)); it == nodes_by_type_.end() ) {
|
|
std::vector<std::unique_ptr<observer<Type>>> obs;
|
|
obs.reserve(sizeof...(Observers));
|
|
(obs.push_back(std::unique_ptr<observer<Type>>(new Observers<Type>(std::forward<Observers<Type>>(observers)))), ...);
|
|
// if the type was not found
|
|
std::unique_ptr<repository_node> node;
|
|
if (is_node_announced(typeid(Type))) {
|
|
node = pop_announce_node(typeid(Type));
|
|
node->update_name(name);
|
|
} else {
|
|
node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::move(obs));
|
|
}
|
|
auto result = attach_node(node.release(), parent);
|
|
if (!result) {
|
|
return utils::failure(result.err());
|
|
}
|
|
|
|
repository_node* attached_node = result.value();
|
|
const auto info = attached_node->template info<Type>();
|
|
foreign_node_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
|
relation_completer<Type, Observers...>::complete(attached_node, info.get().observers());
|
|
} else if (!has_node(name)) {
|
|
it->second->update_name(name);
|
|
nodes_by_name_[name] = it->second;
|
|
if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) {
|
|
nodes_by_name_.erase(i);
|
|
}
|
|
const auto info = it->second->info<Type>();
|
|
relation_completer<Type, Observers...>::complete(it->second, info.get().observers());
|
|
log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name());
|
|
} else {
|
|
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists"));
|
|
}
|
|
|
|
return utils::ok<void>();
|
|
}
|
|
|
|
template<typename Type>
|
|
[[nodiscard]] utils::result<object_info_ref<Type>, utils::error> info() const {
|
|
const auto it = find_node(std::type_index(typeid(Type)));
|
|
if (it == end()) {
|
|
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(typeid(Type).name()) + "' not found"));
|
|
}
|
|
|
|
return utils::ok(it->info<Type>());
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif //REPOSITORY_HPP
|