schema progress (does not compile)
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#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"
|
||||
@@ -35,9 +36,9 @@ private:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
|
||||
public:
|
||||
static void complete(const std::shared_ptr<repository_node> &node, Observers<NodeType>... observers) {
|
||||
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...);
|
||||
foreign_node_completer completer(shadow, observers);
|
||||
|
||||
completer.complete_node(node);
|
||||
}
|
||||
@@ -77,11 +78,10 @@ public:
|
||||
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, Observers<NodeType>... observers)
|
||||
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_.emplace_back(observers...);
|
||||
}
|
||||
, log_(logger::create_logger("node_completer"))
|
||||
, observers_(observers) {}
|
||||
|
||||
void complete_node(const std::shared_ptr<repository_node> &node) {
|
||||
nodes_.push(node);
|
||||
@@ -91,75 +91,22 @@ private:
|
||||
nodes_.pop();
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void attach_node(const std::string &name) {
|
||||
if (repo_.contains(typeid(Type))) {
|
||||
return;
|
||||
}
|
||||
const auto node = repository_node::make_node<Type>(repo_.repo(), name);
|
||||
if (auto result = repo_.attach_node(node)) {
|
||||
foreign_node_completer<Type>::complete(result.value());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void attach_node() {
|
||||
if (repo_.contains(typeid(Type))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); });
|
||||
if (auto result = repo_.attach_node(node)) {
|
||||
foreign_node_completer<Type>::complete(result.value());
|
||||
}
|
||||
}
|
||||
auto observers = internal::observer_list_copy_creator<NodeType, Type, Observers...>::copy_create(observers_);
|
||||
|
||||
template<typename Type>
|
||||
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<Type, NodeType>;
|
||||
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
|
||||
if (repo_.is_node_announced(typeid(Type))) {
|
||||
return;
|
||||
}
|
||||
|
||||
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<relation_value_type>(join_column, inverse_join_column);
|
||||
};
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(repo_.repo(), name, std::move(creator));
|
||||
result = repo_.attach_node(node);
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
}
|
||||
|
||||
foreign_node_completer<relation_value_type>::complete(result.value());
|
||||
|
||||
// auto& node = result.value();
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
|
||||
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
|
||||
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BelongsTo, foreign_node);
|
||||
const auto foreign_endpoint = std::make_shared<relation_endpoint>(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);
|
||||
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:
|
||||
@@ -178,7 +125,7 @@ private:
|
||||
internal::shadow_repository &repo_;
|
||||
logger::logger log_;
|
||||
join_columns_collector join_columns_collector_{};
|
||||
// const std::vector<Observers<NodeType>...> observers_;
|
||||
const std::vector<std::unique_ptr<observer<NodeType>>>& observers_;
|
||||
};
|
||||
|
||||
|
||||
@@ -190,7 +137,7 @@ void foreign_node_completer<NodeType, Observers...>::on_belongs_to(const char *
|
||||
|
||||
template<typename NodeType, template<typename> typename ...Observers>
|
||||
template<class ForeignPointerType>
|
||||
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char *, ForeignPointerType &, const utils::foreign_attributes &) {
|
||||
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) {
|
||||
attach_node<typename ForeignPointerType::value_type>();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||
#define MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||
|
||||
#include "matador/object/observer.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace matador::object::internal {
|
||||
template <typename SourceType, typename DestType, template <typename> class... ObserverType>
|
||||
class observer_list_copy_creator
|
||||
{
|
||||
public:
|
||||
using source_observer_vector = std::vector<std::unique_ptr<observer<SourceType>>>;
|
||||
using observer_vector = std::vector<std::unique_ptr<observer<DestType>>>;
|
||||
using iterator = typename observer_vector::iterator;
|
||||
|
||||
static observer_vector copy_create(const source_observer_vector &source_observers) {
|
||||
observer_list_copy_creator creator(source_observers);
|
||||
|
||||
return std::move(creator.observers_);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit observer_list_copy_creator(const source_observer_vector &source_observers)
|
||||
: source_observers_(source_observers) {
|
||||
if constexpr (sizeof...(ObserverType) != 0) {
|
||||
copy_observer<ObserverType...>();
|
||||
}
|
||||
}
|
||||
|
||||
template <template <typename> class FirstObserverType>
|
||||
void copy_observer() {
|
||||
try_copy_observer<FirstObserverType>();
|
||||
}
|
||||
|
||||
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
|
||||
void copy_observer() {
|
||||
try_copy_observer<FirstObserverType>();
|
||||
copy_observer<NextObserverType, RestObserverType...>();
|
||||
}
|
||||
|
||||
template <template <typename> class CurrentObserverType>
|
||||
void try_copy_observer() {
|
||||
for ( const auto &obs : source_observers_ ) {;
|
||||
if (const auto *casted_observer = dynamic_cast<const CurrentObserverType<SourceType>*>(obs.get()); casted_observer != nullptr) {
|
||||
observers_.emplace_back(std::make_unique<CurrentObserverType<DestType>>(*casted_observer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
const source_observer_vector &source_observers_;
|
||||
observer_vector observers_;
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||
#define MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||
|
||||
#include "matador/object/observer.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace matador::object::internal {
|
||||
template <typename Type, template <typename> class... ObserverType>
|
||||
class observer_list_creator
|
||||
{
|
||||
public:
|
||||
using observer_vector = std::vector<std::unique_ptr<observer<Type>>>;
|
||||
|
||||
static void create_missing(observer_vector &observers) {
|
||||
observer_list_creator creator(observers);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit observer_list_creator(observer_vector &observers)
|
||||
: observers_(observers) {
|
||||
if constexpr (sizeof...(ObserverType) != 0) {
|
||||
build_observer<ObserverType...>();
|
||||
}
|
||||
}
|
||||
|
||||
template <template <typename> class FirstObserverType>
|
||||
void build_observer() {
|
||||
try_copy_on_missing<FirstObserverType>();
|
||||
}
|
||||
|
||||
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
|
||||
void build_observer() {
|
||||
try_copy_on_missing<FirstObserverType>();
|
||||
build_observer<NextObserverType, RestObserverType...>();
|
||||
}
|
||||
|
||||
template <template <typename> class CurrentObserverType>
|
||||
void try_copy_on_missing() {
|
||||
bool is_missing{true};
|
||||
for ( const auto &obs : observers_ ) {;
|
||||
if (dynamic_cast<const CurrentObserverType<Type>*>(obs.get())) {
|
||||
is_missing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_missing) {
|
||||
append<CurrentObserverType<Type>>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class CurrentObserverType>
|
||||
void append(std::enable_if_t<std::is_default_constructible_v<CurrentObserverType> || std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
|
||||
observers_.emplace_back(std::make_unique<CurrentObserverType>());
|
||||
}
|
||||
|
||||
template <class CurrentObserverType>
|
||||
void append(std::enable_if_t<!std::is_default_constructible_v<CurrentObserverType> && !std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
|
||||
static_assert("no default constructor");
|
||||
}
|
||||
|
||||
private:
|
||||
observer_vector &observers_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //MATADOR_OBSERVER_LIST_CREATOR_HPP
|
||||
@@ -40,6 +40,11 @@ public:
|
||||
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||
void remove_object_for_type(const std::type_index &ti) const;
|
||||
|
||||
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||
void push_announce_node(const std::type_index &ti, const node_ptr &node) const;
|
||||
[[nodiscard]] node_ptr announce_node(const std::type_index &ti) const;
|
||||
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti) const;
|
||||
|
||||
private:
|
||||
repository& repo_;
|
||||
};
|
||||
|
||||
@@ -51,17 +51,17 @@ private:
|
||||
|
||||
class object_generator {
|
||||
private:
|
||||
explicit object_generator(repository& repo, const std::shared_ptr<object> &object);
|
||||
explicit object_generator(const repository& repo, const std::shared_ptr<object> &object);
|
||||
|
||||
public:
|
||||
template < class Type >
|
||||
static std::shared_ptr<object> generate(repository &repo, const std::string &name) {
|
||||
static std::shared_ptr<object> generate(const repository &repo, const std::string &name) {
|
||||
return generate(std::make_unique<Type>(), repo, name);
|
||||
}
|
||||
|
||||
template < class Type >
|
||||
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, repository &repo, const std::string &name) {
|
||||
const internal::shadow_repository shadow_repo(repo);
|
||||
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, const repository &repo, const std::string &name) {
|
||||
const internal::shadow_repository shadow_repo(const_cast<repository&>(repo));
|
||||
const std::type_index ti(typeid(Type));
|
||||
if (shadow_repo.has_object_for_type(ti)) {
|
||||
auto obj = shadow_repo.object_for_type(ti);
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
|
||||
static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name);
|
||||
private:
|
||||
repository &repo_;
|
||||
const repository &repo_;
|
||||
std::shared_ptr<object> object_;
|
||||
};
|
||||
|
||||
@@ -167,7 +167,7 @@ void object_generator::create_fk_constraint(const std::string& name) const {
|
||||
template<typename Type>
|
||||
std::shared_ptr<object> object_generator::fk_object() const {
|
||||
const auto ti = std::type_index(typeid(Type));
|
||||
const internal::shadow_repository shadow_repo(repo_);
|
||||
const internal::shadow_repository shadow_repo(const_cast<repository &>(repo_));
|
||||
if (const auto result = shadow_repo.basic_info(ti)) {
|
||||
return result->get().object();
|
||||
}
|
||||
|
||||
@@ -9,21 +9,21 @@
|
||||
namespace matador::object {
|
||||
class repository_node;
|
||||
|
||||
template<typename Type>
|
||||
class observer_ptr {
|
||||
public:
|
||||
explicit observer_ptr(std::unique_ptr<observer<Type>> &&observer)
|
||||
: observer(std::move(observer)) {}
|
||||
|
||||
operator bool() const { return observer != nullptr; }
|
||||
|
||||
observer<Type> *get() const { return observer.get(); }
|
||||
observer<Type> &operator*() const { return *observer; }
|
||||
observer<Type> *operator->() const { return observer.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<observer<Type>> observer;
|
||||
};
|
||||
// template<typename Type>
|
||||
// class observer_ptr {
|
||||
// public:
|
||||
// explicit observer_ptr(std::unique_ptr<observer<Type>> &&o)
|
||||
// : observer_(std::move(o)) {}
|
||||
//
|
||||
// operator bool() const { return observer_ != nullptr; }
|
||||
//
|
||||
// observer<Type> *get() const { return observer_.get(); }
|
||||
// observer<Type> &operator*() const { return *observer_; }
|
||||
// observer<Type> *operator->() const { return observer_.get(); }
|
||||
//
|
||||
// private:
|
||||
// std::unique_ptr<observer<Type>> observer_;
|
||||
// };
|
||||
template<typename Type>
|
||||
class object_info final : public basic_object_info {
|
||||
public:
|
||||
@@ -31,10 +31,11 @@ public:
|
||||
|
||||
object_info(const std::shared_ptr<repository_node>& node,
|
||||
std::shared_ptr<class object> &&obj,
|
||||
std::vector<std::unique_ptr<observer<Type>>>&& observers,
|
||||
create_func&& creator)
|
||||
: basic_object_info(node, std::move(obj))
|
||||
, creator_(std::move(creator)){
|
||||
}
|
||||
, creator_(std::move(creator))
|
||||
, observers_(std::move(observers)){}
|
||||
|
||||
explicit object_info(const std::shared_ptr<repository_node>& node)
|
||||
: basic_object_info(node, {}) {
|
||||
@@ -55,13 +56,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void register_observer(observer_ptr<Type> observer) {
|
||||
void register_observer(std::unique_ptr<observer<Type>>&& observer) {
|
||||
observers_.push_back(std::move(observer));
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<observer<Type>>>& observers() const {
|
||||
return observers_;
|
||||
}
|
||||
|
||||
private:
|
||||
Type prototype_;
|
||||
create_func creator_{[]{ return std::make_unique<Type>(); }};
|
||||
std::vector<observer_ptr<Type>> observers_;
|
||||
std::vector<std::unique_ptr<observer<Type>>> observers_;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
* @param node The attached repository_node
|
||||
* @param prototype The prototype object of the attached node
|
||||
*/
|
||||
virtual void on_attach(repository_node &node, const Type &prototype) = 0;
|
||||
virtual void on_attach(const repository_node &node, const Type &prototype) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Called on repository_node detached
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
* @param node The to be detached repository_node
|
||||
* @param prototype The prototype object of the detached node
|
||||
*/
|
||||
virtual void on_detach(repository_node &node, const Type &prototype) = 0;
|
||||
virtual void on_detach(const repository_node &node, const Type &prototype) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Called on object insertion.
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
*
|
||||
* @param obj The proxy of the inserted object.
|
||||
*/
|
||||
virtual void on_insert(Type &obj) = 0;
|
||||
virtual void on_insert(const Type &obj) = 0;
|
||||
|
||||
/**
|
||||
* @brief Called on object update.
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
*
|
||||
* @param obj The proxy of the updated object.
|
||||
*/
|
||||
virtual void on_update(Type &obj) = 0;
|
||||
virtual void on_update(const Type &obj) = 0;
|
||||
|
||||
/**
|
||||
* @brief Called on object deletion.
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
*
|
||||
* @param obj The proxy of the deleted object.
|
||||
*/
|
||||
virtual void on_delete(Type &obj) = 0;
|
||||
virtual void on_delete(const Type &obj) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
* no has_many or belongs_to
|
||||
* invalid relation -> error
|
||||
*/
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
class relation_completer final {
|
||||
private:
|
||||
using node_ptr = std::shared_ptr<repository_node>;
|
||||
@@ -100,9 +100,9 @@ private:
|
||||
public:
|
||||
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
|
||||
|
||||
static void complete(const std::shared_ptr<repository_node> &node) {
|
||||
static void complete(const std::shared_ptr<repository_node> &node, const std::vector<std::unique_ptr<observer<Type>>> &observers) {
|
||||
internal::shadow_repository shadow(node->repo_);
|
||||
relation_completer completer(shadow);
|
||||
relation_completer completer(shadow, observers);
|
||||
|
||||
completer.complete_node_relations(node);
|
||||
}
|
||||
@@ -131,10 +131,10 @@ public:
|
||||
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
|
||||
|
||||
private:
|
||||
explicit relation_completer(internal::shadow_repository &shadow)
|
||||
: schema_(shadow)
|
||||
, log_(logger::create_logger("relation_completer")) {
|
||||
}
|
||||
explicit relation_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<Type>>>& observers)
|
||||
: schema_(shadow)
|
||||
, log_(logger::create_logger("relation_completer"))
|
||||
, observers_(observers) {}
|
||||
|
||||
void complete_node_relations(const std::shared_ptr<repository_node> &node) {
|
||||
nodes_.push(node);
|
||||
@@ -152,16 +152,19 @@ private:
|
||||
static void link_relation_endpoints(const endpoint_ptr &endpoint,
|
||||
const endpoint_ptr &other_endpoint);
|
||||
|
||||
node_ptr find_node(const std::type_index &ti) const;
|
||||
|
||||
private:
|
||||
std::stack<node_ptr> nodes_;
|
||||
internal::shadow_repository &schema_;
|
||||
logger::logger log_;
|
||||
join_columns_collector join_columns_collector_{};
|
||||
const std::vector<std::unique_ptr<observer<Type>>>& observers_;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class CollectionType>
|
||||
void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
||||
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &,
|
||||
const char *join_column,
|
||||
const utils::foreign_attributes &,
|
||||
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * /*unused*/) {
|
||||
@@ -170,12 +173,11 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
||||
using relation_value_type = many_to_many_relation<Type, value_type>;
|
||||
|
||||
// Check if the object_ptr type is already inserted in the schema (by id)
|
||||
auto result = schema_.find_node(typeid(value_type));
|
||||
if (!result) {
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
}
|
||||
const auto foreign_node = result.value();
|
||||
// has foreign node corresponding join column (join_column)
|
||||
|
||||
if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) {
|
||||
@@ -198,8 +200,8 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
||||
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
|
||||
return std::make_unique<relation_value_type>("id", join_column);
|
||||
});
|
||||
result = schema_.attach_node(node);
|
||||
}, {});
|
||||
const auto result = schema_.attach_node(node);
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
@@ -215,9 +217,9 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class CollectionType>
|
||||
void relation_completer<Type>::on_has_many(const char *id, CollectionType &, const char *join_column,
|
||||
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &, const char *join_column,
|
||||
const utils::foreign_attributes &,
|
||||
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value>
|
||||
* /*unused*/) {
|
||||
@@ -226,7 +228,7 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
|
||||
return std::make_unique<relation_value_type>(join_column, "value");
|
||||
});
|
||||
}, {});
|
||||
const auto result = schema_.attach_node(node);
|
||||
if (!result) {
|
||||
// Todo: throw internal exception
|
||||
@@ -241,9 +243,9 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
|
||||
link_relation_endpoints(local_endpoint, foreign_endpoint);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class CollectionType>
|
||||
void relation_completer<Type>::on_has_many_to_many(const char *id,
|
||||
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
|
||||
CollectionType &/*collection*/,
|
||||
const char *join_column,
|
||||
const char *inverse_join_column,
|
||||
@@ -256,9 +258,9 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class CollectionType>
|
||||
void relation_completer<Type>::on_has_many_to_many(const char *id,
|
||||
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
|
||||
CollectionType &collection,
|
||||
const utils::foreign_attributes &attr) {
|
||||
const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>();
|
||||
@@ -270,46 +272,43 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
|
||||
attr);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class ForeignPointerType>
|
||||
void relation_completer<Type>::on_has_one(const char *id,
|
||||
void relation_completer<Type, Observers...>::on_has_one(const char *id,
|
||||
ForeignPointerType &/*obj*/,
|
||||
const utils::foreign_attributes &/*attr*/) {
|
||||
using value_type = typename ForeignPointerType::value_type;
|
||||
const auto ti = std::type_index(typeid(value_type));
|
||||
const auto result = schema_.find_node(ti);
|
||||
if (!result) {
|
||||
// Node was not found
|
||||
// Todo: Throw internal error
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
}
|
||||
|
||||
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<relation_endpoint>(id, relation_type::HasOne, result.value());
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, foreign_node);
|
||||
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()) {
|
||||
if (const auto foreign_it = foreign_node->info().find_relation_endpoint(typeid(Type)); foreign_it != foreign_node->info().endpoint_end()) {
|
||||
link_relation_endpoints(local_it->second, foreign_it->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<class ForeignPointerType>
|
||||
void relation_completer<Type>::on_belongs_to(const char *id,
|
||||
void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
|
||||
ForeignPointerType & /*obj*/,
|
||||
const utils::foreign_attributes & /*attr*/) {
|
||||
using value_type = typename ForeignPointerType::value_type;
|
||||
const auto ti = std::type_index(typeid(value_type));
|
||||
auto result = schema_.find_node(ti);
|
||||
if (!result) {
|
||||
// Type was not found
|
||||
// Todo: Throw internal error
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
}
|
||||
|
||||
// Type was found
|
||||
const auto &foreign_node = result.value();
|
||||
// Check foreign node and relation endpoint
|
||||
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
|
||||
@@ -341,21 +340,20 @@ void relation_completer<Type>::on_belongs_to(const char *id,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
template<typename NodeType>
|
||||
void relation_completer<Type>::attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) {
|
||||
void relation_completer<Type, Observers...>::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<NodeType, Type>;
|
||||
using value_type = NodeType;
|
||||
|
||||
// Check if the object_ptr type is already inserted in the schema (by id)
|
||||
auto result = schema_.find_node(typeid(value_type));
|
||||
if (!result) {
|
||||
auto foreign_node = find_node(typeid(value_type));
|
||||
if (!foreign_node) {
|
||||
// Todo: throw internal error or attach node
|
||||
return;
|
||||
}
|
||||
|
||||
const auto foreign_node = result.value();
|
||||
result = schema_.find_node(name);
|
||||
auto result = schema_.find_node(name);
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
@@ -364,14 +362,16 @@ void relation_completer<Type>::attach_relation_node(const std::string &name, con
|
||||
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
|
||||
};
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), name, std::move(creator));
|
||||
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
|
||||
|
||||
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), name, std::move(creator), std::move(observers));
|
||||
result = schema_.attach_node(node);
|
||||
if (!result) {
|
||||
// Todo: throw internal error
|
||||
return;
|
||||
}
|
||||
|
||||
foreign_node_completer<relation_value_type>::complete(result.value());
|
||||
foreign_node_completer<relation_value_type>::complete(result.value(), {});
|
||||
|
||||
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
|
||||
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
|
||||
@@ -389,18 +389,31 @@ void relation_completer<Type>::attach_relation_node(const std::string &name, con
|
||||
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void relation_completer<Type>::register_relation_endpoints(const endpoint_ptr &endpoint,
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
void relation_completer<Type, 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 Type>
|
||||
void relation_completer<Type>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
void relation_completer<Type, 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);
|
||||
}
|
||||
|
||||
template<typename Type, template <typename> class ... Observers>
|
||||
typename relation_completer<Type, Observers...>::node_ptr relation_completer<Type, Observers...>::find_node(const std::type_index &ti) const {
|
||||
node_ptr foreign_node;
|
||||
if (auto result = schema_.find_node(ti); result) {
|
||||
return result.value();
|
||||
}
|
||||
|
||||
if (!schema_.is_node_announced(ti)) {
|
||||
return {};
|
||||
}
|
||||
return schema_.announce_node(ti);
|
||||
}
|
||||
}
|
||||
#endif //RELATION_COMPLETER_HPP
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint);
|
||||
|
||||
private:
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
friend class relation_completer;
|
||||
template<typename Type, template<typename> typename ...Observers>
|
||||
friend class foreign_node_completer;
|
||||
|
||||
@@ -38,44 +38,55 @@ public:
|
||||
*/
|
||||
explicit repository(std::string name = "");
|
||||
|
||||
template<typename Type, typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
|
||||
return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers>(observers)...);
|
||||
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, typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... 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));
|
||||
auto result = find_node(ti);
|
||||
if (!result) {
|
||||
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
|
||||
}
|
||||
|
||||
return attach_type<Type, Observers...>(name, (*result)->name(), std::forward<Observers>(observers)...);
|
||||
return attach_type<Type, Observers...>(name, (*result)->name(), std::forward<Observers<Type>>(observers)...);
|
||||
}
|
||||
|
||||
template<typename Type, typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers&&... observers) {
|
||||
return attach_type<Type, Observers...>(name, parent, std::forward<Observers>(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, typename... Observers>
|
||||
[[nodiscard]] utils::result<void, utils::error> attach_type(const std::string &name, const std::string &parent, Observers&&... 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
|
||||
auto node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::forward<Observers>(observers)...);
|
||||
std::shared_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));
|
||||
}
|
||||
if (auto result = attach_node(node, parent); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
foreign_node_completer<Type>::complete(node);
|
||||
relation_completer<Type>::complete(node);
|
||||
const auto info = node->template info<Type>();
|
||||
foreign_node_completer<Type, Observers...>::complete(node, info.get().observers());
|
||||
relation_completer<Type, Observers...>::complete(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);
|
||||
}
|
||||
relation_completer<Type>::complete(it->second);
|
||||
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"));
|
||||
@@ -195,6 +206,11 @@ private:
|
||||
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
|
||||
void remove_object_for_type(const std::type_index &ti);
|
||||
|
||||
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
|
||||
void push_announce_node(const std::type_index &ti, const node_ptr &node);
|
||||
[[nodiscard]] node_ptr announce_node(const std::type_index &ti);
|
||||
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti);
|
||||
|
||||
private:
|
||||
friend class internal::shadow_repository;
|
||||
friend class repository_node;
|
||||
@@ -209,9 +225,11 @@ private:
|
||||
t_type_index_node_map nodes_by_type_;
|
||||
logger::logger log_;
|
||||
|
||||
std::unordered_map<std::type_index, std::shared_ptr<repository_node>> announced_node_;
|
||||
std::unordered_map<std::type_index, attribute*> missing_references_;
|
||||
std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
|
||||
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "matador/object/object_generator.hpp"
|
||||
#include "matador/object/object_info.hpp"
|
||||
#include "matador/object/internal/observer_list_creator.hpp"
|
||||
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
@@ -20,22 +21,11 @@ public:
|
||||
template< typename Type>
|
||||
using creator_func = std::function<std::unique_ptr<Type>()>;
|
||||
|
||||
template < typename Type, typename... Observers >
|
||||
static std::shared_ptr<repository_node> make_node(repository& repo, const std::string& name, creator_func<Type> creator, Observers&&... observers) {
|
||||
const std::type_index ti(typeid(Type));
|
||||
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||
|
||||
auto obj = object_generator::generate<Type>(creator(), repo, name);
|
||||
auto info = std::make_unique<object_info<Type>>(
|
||||
node,
|
||||
std::move(obj),
|
||||
std::forward<creator_func<Type>>(creator)
|
||||
);
|
||||
(info->register_observer(observer_ptr<Type>(std::unique_ptr<Observers>(new Observers(std::forward<Observers>(observers))))), ...);
|
||||
node->info_ = std::move(info);
|
||||
|
||||
return node;
|
||||
}
|
||||
template < typename Type, template<typename> typename... Observers >
|
||||
static std::shared_ptr<repository_node> make_node(repository& repo,
|
||||
const std::string& name,
|
||||
creator_func<Type> creator,
|
||||
std::vector<std::unique_ptr<observer<Type>>>&& observers);
|
||||
|
||||
static std::shared_ptr<repository_node> make_null_node(repository& repo);
|
||||
|
||||
@@ -74,11 +64,9 @@ private:
|
||||
|
||||
void unlink();
|
||||
|
||||
static utils::result<node_ptr, utils::error> make_and_attach_node(repository& repo, const std::string& name, const std::type_index& ti);
|
||||
|
||||
private:
|
||||
friend class repository;
|
||||
template<typename Type>
|
||||
template<typename Type, template<typename> typename... Observers>
|
||||
friend class relation_completer;
|
||||
template < typename NodeType, template<typename> typename ...Observers >
|
||||
friend class foreign_node_completer;
|
||||
@@ -98,5 +86,24 @@ private:
|
||||
size_t depth_{0};
|
||||
};
|
||||
|
||||
template<typename Type, template <typename> class ... Observers>
|
||||
std::shared_ptr<repository_node> repository_node::make_node(repository &repo, const std::string &name,
|
||||
creator_func<Type> creator, std::vector<std::unique_ptr<observer<Type>>> &&observers) {
|
||||
const std::type_index ti(typeid(Type));
|
||||
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
|
||||
|
||||
internal::observer_list_creator<Type, Observers...>::create_missing(observers);
|
||||
|
||||
auto obj = object_generator::generate<Type>(creator(), repo, name);
|
||||
auto info = std::make_unique<object_info<Type>>(
|
||||
node,
|
||||
std::move(obj),
|
||||
std::move(observers),
|
||||
std::forward<creator_func<Type>>(creator)
|
||||
);
|
||||
node->info_ = std::move(info);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
#endif //SCHEMA_NODE_HPP
|
||||
|
||||
Reference in New Issue
Block a user