From c974628bee64c740d33200d72f24ac170baf029f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 6 Jul 2025 20:06:26 +0200 Subject: [PATCH] relation completer progress --- demo/sandbox.cpp | 40 +- include/matador/object/basic_object_info.hpp | 4 +- include/matador/object/relation_endpoint.hpp | 5 + include/matador/object/schema.hpp | 366 ++++++++++++------- include/matador/object/schema_node.hpp | 4 + source/core/logger/basic_file_sink.cpp | 2 + source/core/logger/log_domain.cpp | 2 +- source/core/object/basic_object_info.cpp | 6 +- source/core/object/relation_endpoint.cpp | 4 + source/core/object/schema.cpp | 77 +++- source/core/object/schema_node.cpp | 11 + 11 files changed, 358 insertions(+), 163 deletions(-) diff --git a/demo/sandbox.cpp b/demo/sandbox.cpp index cb6c2fc..2ca4460 100644 --- a/demo/sandbox.cpp +++ b/demo/sandbox.cpp @@ -5,20 +5,19 @@ #include "author.hpp" #include "book.hpp" +#include /* * node author * * relation_endpoints * 1. - field_name "books" - * - type_index * - type "has_many" * - node * - foreign endpoint (1) "author" * * node book * 2. - field_name "author_id" - * - type_index * - type "belongs_to" * - node * - foreign endpoint (2) "books" @@ -32,29 +31,50 @@ * - create node many_to_many_relation("author_id", "id") * - 3. create endpoint * - field name "author_id" - * - type_index * - type "belongs_to" * - node > * - foreign endpoint (1) "author * - set foreign endpoint of (1) to endpoint (3) + * - register endpoint in authors node by type book * - attach (internal) node> * * attach * - relation completer detects "belongs_to" * - belongs_to finds + * - try to find relation endpoint of type book in authors node + * - if endpoint was found + * - validate node in endpoint + * - if node is of type many_to_many_relation + * - detach node of endpoint + * - update node in endpoint to + * - else + * - create endpoint (1) + * - create endpoint (2) + * - set foreign endpoint of (1) to endpoint (2) + * - set foreign endpoint of (2) to endpoint (1) * - check relation endpoints... - * - * - * */ using namespace demo; using namespace matador; -int main() { - logger::default_min_log_level(logger::log_level::LVL_DEBUG); - logger::add_log_sink(logger::create_stdout_sink()); +int main() { + logger::default_min_log_level(logger::log_level::LVL_DEBUG); + logger::add_log_sink(logger::create_stdout_sink()); + + { object::schema schema; auto result = schema.attach("authors") .and_then([&schema] { return schema.attach("books"); }); -} \ No newline at end of file + + schema.dump(std::cout); + } + { + object::schema schema; + + auto result = schema.attach("books") + .and_then([&schema] { return schema.attach("authors"); }); + + schema.dump(std::cout); + } +} diff --git a/include/matador/object/basic_object_info.hpp b/include/matador/object/basic_object_info.hpp index f25a82e..06e4589 100644 --- a/include/matador/object/basic_object_info.hpp +++ b/include/matador/object/basic_object_info.hpp @@ -16,7 +16,7 @@ class relation_endpoint; class basic_object_info { public: - using t_endpoint_map = std::unordered_map; + using t_endpoint_map = std::unordered_map>; using endpoint_iterator = t_endpoint_map::iterator; using const_endpoint_iterator = t_endpoint_map::const_iterator; @@ -30,7 +30,7 @@ public: [[nodiscard]] bool has_primary_key() const; [[nodiscard]] const utils::identifier& primary_key() const; - void register_relation_endpoint(const std::type_index &type, const relation_endpoint &endpoint); + void register_relation_endpoint(const std::type_index &type, const std::shared_ptr &endpoint); void unregister_relation_endpoint(const std::type_index &type); [[nodiscard]] const_endpoint_iterator find_relation_endpoint(const std::type_index &type) const; diff --git a/include/matador/object/relation_endpoint.hpp b/include/matador/object/relation_endpoint.hpp index bb07ddf..891ba3b 100644 --- a/include/matador/object/relation_endpoint.hpp +++ b/include/matador/object/relation_endpoint.hpp @@ -3,6 +3,7 @@ #include "matador/utils/enum_mapper.hpp" +#include #include namespace matador::object { @@ -27,6 +28,7 @@ public: [[nodiscard]] std::string field_name() const; [[nodiscard]] relation_type type() const; + [[nodiscard]] std::string type_name() const; [[nodiscard]] const schema_node& node() const; [[nodiscard]] bool is_has_one() const; @@ -37,6 +39,9 @@ public: void link_foreign_endpoint(const std::shared_ptr& endpoint); private: + template + friend class relation_completer; + std::string field_name_; relation_type type_; std::shared_ptr node_; diff --git a/include/matador/object/schema.hpp b/include/matador/object/schema.hpp index 20f6c09..dc9d61f 100644 --- a/include/matador/object/schema.hpp +++ b/include/matador/object/schema.hpp @@ -19,8 +19,7 @@ #include namespace matador::object { - -utils::error make_error(error_code ec, const std::string& msg); +utils::error make_error(error_code ec, const std::string &msg); class schema; @@ -60,6 +59,7 @@ template class relation_completer final { public: using value_type = Type; + using endpoint_ptr = std::shared_ptr; static void complete(const std::shared_ptr &node) { relation_completer completer(node); @@ -68,16 +68,27 @@ public: access::process(completer, obj); } - template < class PrimaryKeyType > - static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t && !std::is_same_v>* = nullptr) {} - static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {} - static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} + template + static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, + std::enable_if_t && !std::is_same_v> * = nullptr) { + } + + static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) { + } + + 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) {} + 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) {} + 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); @@ -85,44 +96,53 @@ public: 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 ); + 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 ); + 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); + 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, ContainerType &collection, const utils::foreign_attributes &attr); private: - explicit relation_completer(const std::shared_ptr& node) - : node_(node) - , schema_(node->schema_) - , log_(logger::create_logger("relation_completer")) {} + explicit relation_completer(const std::shared_ptr &node) + : node_(node) + , schema_(node->schema_) + , log_(logger::create_logger("relation_completer")) { + } + 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: std::shared_ptr node_; - schema& schema_; + schema &schema_; logger::logger log_; }; class schema { public: - typedef const_schema_node_iterator const_iterator; /**< Shortcut for the list const iterator. */ + typedef const_schema_node_iterator const_iterator; /**< Shortcut for the list const iterator. */ + + using node_ptr = std::shared_ptr; /** * Creates an empty schema */ - explicit schema( std::string name = ""); + explicit schema(std::string name = ""); - template - [[nodiscard]] utils::result attach(const std::string& name, const std::string &parent = "") { + template + [[nodiscard]] utils::result attach(const std::string &name, const std::string &parent = "") { // if (has_node(name)) { - // return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists")); + // return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists")); // } auto node = acquire_node(name); - log_.info("attach node %s", name.c_str()); relation_completer::complete(node); if (auto result = attach_node(node, parent); !result) { return utils::failure(result.err()); @@ -131,17 +151,22 @@ public: return utils::ok(); } - template - [[nodiscard]] utils::result attach(const std::string name) { + template + [[nodiscard]] utils::result attach(const std::string &name) { 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 utils::failure(make_error(error_code::NodeNotFound, + "Parent node '" + std::string(ti.name()) + "' not found")); } return attach(name, (*result)->name()); } + + [[nodiscard]] utils::result detach(const node_ptr& node); + // [[nodiscard]] utils::result detach(const std::string& name); + /** * Return the first schema node. * @@ -178,42 +203,44 @@ public: */ [[nodiscard]] std::string name() const; - template + template [[nodiscard]] utils::result, utils::error> info() const { - auto result = find_node(std::type_index(typeid(Type))); - if (!result) { - return utils::failure(result.err()); - } + auto result = find_node(std::type_index(typeid(Type))); + if (!result) { + return utils::failure(result.err()); + } - return utils::ok(result.value()->info()); + return utils::ok(result.value()->info()); } - template + template [[nodiscard]] utils::result basic_info() const { - auto result = find_node(std::type_index(typeid(Type))); - if (!result) { - return utils::failure(result.err()); - } + auto result = find_node(std::type_index(typeid(Type))); + if (!result) { + return utils::failure(result.err()); + } - return utils::ok(basic_object_info_ref{result.value()->info()}); + return utils::ok(basic_object_info_ref{result.value()->info()}); } - [[nodiscard]] utils::result, utils::error> reference(const std::type_index &type_index) const; + [[nodiscard]] utils::result, utils::error> reference( + const std::type_index &type_index) const; + + void dump(std::ostream &os) const; private: - using node_ptr = std::shared_ptr; using t_node_map = std::unordered_map; using t_type_index_node_map = std::unordered_map; - [[nodiscard]] utils::result, utils::error> attach_node(const std::shared_ptr &node, - const std::string &parent); - [[nodiscard]] utils::result, utils::error> attach_node(const std::shared_ptr &node, - const std::type_index &type_index); - [[nodiscard]] utils::result, utils::error> find_node(const std::string &name) const; - [[nodiscard]] utils::result, utils::error> find_node(const std::type_index &type_index) const; + [[nodiscard]] utils::result attach_node(const std::shared_ptr &node, + const std::string &parent); + [[nodiscard]] utils::result attach_node(const std::shared_ptr &node, + const std::type_index &type_index); + [[nodiscard]] utils::result find_node(const std::string &name) const; + [[nodiscard]] utils::result find_node(const std::type_index &type_index) const; - template - std::shared_ptr acquire_node(const std::string& name) { + template + node_ptr acquire_node(const std::string &name) { if (const auto it = expected_node_map_.find(typeid(Type)); it != expected_node_map_.end()) { const auto node = it->second; expected_node_map_.erase(it); @@ -227,13 +254,14 @@ private: [[nodiscard]] bool has_node(const std::string &name) const; - [[nodiscard]] bool has_node(const std::type_index& index) const; - [[nodiscard]] bool has_node(const std::type_index& index, const std::string &name) const; + [[nodiscard]] bool has_node(const std::type_index &index) const; + [[nodiscard]] bool has_node(const std::type_index &index, const std::string &name) const; static void push_back_child(const node_ptr &parent, const node_ptr &child); + void remove_node(const node_ptr &node); private: - template + template friend class relation_completer; std::string name_; @@ -247,124 +275,180 @@ private: template template -void relation_completer::on_has_many( const char *id, CollectionType&, - const char *join_column, - const utils::foreign_attributes&, - std::enable_if_t::value>* /*unused*/ ) { - using value_type = typename CollectionType::value_type::value_type; +void relation_completer::on_has_many(const char *id, CollectionType &, + const char *join_column, + const utils::foreign_attributes &, + std::enable_if_t::value> * + /*unused*/) { + using value_type = typename CollectionType::value_type::value_type; + + // Check if the object_ptr type is already inserted in the schema (by id) + if (auto result = schema_.find_node(id); !result) { + // Type was not found. + // Create and attach the relation node. + const std::type_index ti = typeid(many_to_many_relation); + const auto endpoint = node_->info().find_relation_endpoint(ti); + if (endpoint == node_->info().endpoint_end()) { + // Endpoint was not found + log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", node_->name().c_str(), id, join_column); + const auto node = schema_node::make_relation_node >( + schema_, id, [join_column] { + return std::make_unique >(join_column, "id"); + }); + result = schema_.attach_node(node, ""); + if (!result) { + // Todo: throw internal error + return; + } + const auto local_endpoint = std::make_shared(id, relation_type::HAS_MANY, node_); + const auto foreign_endpoint = std::make_shared(join_column, relation_type::BELONGS_TO, node); + node_->info_->register_relation_endpoint(typeid(value_type), local_endpoint); + foreign_endpoint->node_->info_->register_relation_endpoint(node_->type_index(), foreign_endpoint); + link_relation_endpoints(local_endpoint, foreign_endpoint); - // Check if the object_ptr type is already inserted in the schema (by id) - if (auto result = schema_.find_node(id); !result) { - const std::type_index ti = typeid(many_to_many_relation); - const auto endpoint = node_->info().find_relation_endpoint(ti); - if (endpoint == node_->info().endpoint_end()) { - log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", node_->name().c_str(), id, join_column); - const auto node = schema_node::make_relation_node>(schema_, id, [join_column] { - return std::make_unique>(join_column, "id"); - }); - log_.debug("node '%s' many to many type: %s", node_->name().c_str(), typeid(many_to_many_relation).name()); - result = schema_.attach_node(node, ""); - if (!result) { - // Todo: throw internal error - return; - } - node_->info_->register_relation_endpoint(node->type_index(), relation_endpoint(id, relation_type::BELONGS_TO, node)); - node->info_->register_relation_endpoint(node_->type_index(), relation_endpoint(id, relation_type::HAS_MANY, node_)); - } - } else { } + } else { + // Type was found. + // Check if the relation node is already attached. + const auto &foreign_node = result.value(); + if (const auto rit = foreign_node->info_->find_relation_endpoint(node_->type_index()); rit != foreign_node->info().endpoint_end()) { + if (rit->second->is_belongs_to()) { + rit->second->node_ = foreign_node; + const auto endpoint = std::make_shared(id, relation_type::HAS_MANY, node_); + node_->info_->register_relation_endpoint(node_->type_index(), endpoint); + link_relation_endpoints(endpoint, rit->second); + } else { + // Todo: throw internal error relation node has invalid type + } + } else { + // Todo: throw internal error couldn't find relation node + } + } } template template -void relation_completer::on_has_many( const char *id, CollectionType&, const char *join_column, const utils::foreign_attributes&, std::enable_if_t::value>* /*unused*/ ) { - using value_type = typename CollectionType::value_type; +void relation_completer::on_has_many(const char *id, CollectionType &, const char *join_column, + const utils::foreign_attributes &, + std::enable_if_t::value> + * /*unused*/) { + using value_type = typename CollectionType::value_type; - const auto node = schema_node::make_relation_node>(schema_, id, [join_column] { - return new many_to_many_relation(join_column, "value"); + const auto node = schema_node::make_relation_node >( + schema_, id, [join_column] { + return new many_to_many_relation(join_column, "value"); }); - const auto result = schema_.attach>(id); - if (!result) { - // Todo: throw internal exception - } + const auto result = schema_.attach >(id); + if (!result) { + // Todo: throw internal exception + } } template template -void relation_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) { - auto result = schema_.find_node(id); - if (result) { - } else { - // - using relation_type = many_to_many_relation; - auto creator = [join_column, inverse_join_column] { - return new many_to_many_relation(join_column, inverse_join_column); - }; +void relation_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) { + auto result = schema_.find_node(id); + if (result) { + } else { + // + // using relation_type = many_to_many_relation; + // auto creator = [join_column, inverse_join_column] { + // return new many_to_many_relation(join_column, inverse_join_column); + // }; - // auto node = schema_node::make_relation_node(schema_, id); + // auto node = schema_node::make_relation_node(schema_, id); - // schema_.attach_node(node, typeid(relation_type)); - } + // schema_.attach_node(node, typeid(relation_type)); + } } template template -void relation_completer::on_has_many_to_many( const char *id, ContainerType &collection, const utils::foreign_attributes &attr ) { - auto result = schema_.find_node(id); - if (!result) { - using relation_type = many_to_many_relation; - // auto creator = [attr] { - // return new relation_type(attr.join_column, attr.inverse_join_column); - // }; - } - -} - -template -template -void relation_completer::on_has_one(const char * id, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) { - auto endpoint = std::make_shared(std::string(id), relation_type::HAS_ONE, std::shared_ptr()); - auto ti = std::type_index(typeid(typename ForeignPointerType::value_type)); - if (const auto result = schema_.find_node(ti); !result.is_ok() && schema_.expected_node_map_.count(ti) == 0) { - schema_.expected_node_map_.insert({ti, schema_node::make_node(schema_, ti.name())}); - } else { - const auto& foreign_node = result.value(); - if (const auto rit = foreign_node->info().find_relation_endpoint(ti); rit != foreign_node->info().endpoint_end()) { - if (rit->second.is_has_many()) { - - } else if (rit->second.is_has_one()) { - - } else { - - } - } - +void relation_completer::on_has_many_to_many(const char *id, ContainerType &collection, + const utils::foreign_attributes &attr) { + auto result = schema_.find_node(id); + if (!result) { + // using relation_type = many_to_many_relation; + // auto creator = [attr] { + // return new relation_type(attr.join_column, attr.inverse_join_column); + // }; } } template template -void relation_completer::on_belongs_to(const char* id, ForeignPointerType& /*obj*/, const utils::foreign_attributes& /*attr*/) { - auto ti = std::type_index(typeid(typename ForeignPointerType::value_type)); - if (auto result = schema_.find_node(ti); !result) { - log_.debug("node '%s' has foreign key '%s' belongs to '%s'", node_->name().c_str(), id, typeid(typename ForeignPointerType::value_type).name()); - } else { - const auto foreign_node = result.value(); - auto it = foreign_node->info().find_relation_endpoint(node_->type_index()); - if (it != foreign_node->info().endpoint_end()) { - auto endpoint = it->second; - } - using TP = many_to_many_relation; - log_.debug("node '%s', many to many type: %s", node_->name().c_str(), typeid(TP).name()); - log_.debug("foreign node '%s', many to many type: %s", foreign_node->name().c_str(), ti.name()); - if (foreign_node->type_index() == ti) { - log_.debug("node '%s' has foreign key '%s' belongs to '%s': already inserted", node_->name().c_str(), id, result.value()->name().c_str()); - } else { - } +void relation_completer::on_has_one(const char *id, ForeignPointerType &/*obj*/, + const utils::foreign_attributes &/*attr*/) { + auto ti = std::type_index(typeid(typename ForeignPointerType::value_type)); + if (const auto result = schema_.find_node(ti); !result.is_ok() && schema_.expected_node_map_.count(ti) == 0) { + schema_.expected_node_map_.insert({ + ti, schema_node::make_node(schema_, ti.name()) + }); + } else { + const auto &foreign_node = result.value(); + if (const auto rit = foreign_node->info().find_relation_endpoint(ti); rit != foreign_node->info().endpoint_end()) { + if (rit->second->is_has_many()) { + } else if (rit->second->is_has_one()) { + } else { + } } + } } +template +template +void relation_completer::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)); + if (auto result = schema_.find_node(ti); !result) { + // Type was not found + // Create node without the foreign relation endpoint + log_.debug("node '%s' has foreign key '%s' belongs to '%s'", node_->name().c_str(), id, ti.name()); + node_->info_->register_relation_endpoint(ti, std::make_shared(id, relation_type::BELONGS_TO, schema::node_ptr{})); + } else { + // 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(typeid(Type)); it != foreign_node->info().endpoint_end()) { + // Found corresponding relation endpoint in the foreign node + if (it->second->foreign_endpoint()->node().type_index() == typeid(many_to_many_relation)) { + // Endpoint is a "many_to_many_relation". This means there + // is a "many_to_many_relation" node attached. Because of being a + // "belongs_to"-relation the "many_to_many_relation" can be removed + // (detach), and the endpoints must be adjusted + const auto foreign_endpoint = it->second->foreign_endpoint(); + const auto detach_result = schema_.detach(foreign_endpoint->node_); + foreign_endpoint->node_ = node_; + node_->info_->register_relation_endpoint(node_->type_index(), foreign_endpoint); + } else { + // check type + } + } else { + // Relation node was not found, create endpoint. + const auto endpoint = std::make_shared(id, relation_type::BELONGS_TO, node_); + node_->info_->register_relation_endpoint(ti, endpoint); + link_relation_endpoints(endpoint, it->second); + } + } +} + +template +void relation_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 relation_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 //SCHEMA_HPP diff --git a/include/matador/object/schema_node.hpp b/include/matador/object/schema_node.hpp index 5b486c3..b007587 100644 --- a/include/matador/object/schema_node.hpp +++ b/include/matador/object/schema_node.hpp @@ -73,10 +73,14 @@ public: [[nodiscard]] const object::schema& schema() const; + [[nodiscard]] bool has_children() const; + private: explicit schema_node(object::schema& tree); schema_node(object::schema& tree, std::string name); + void unlink(); + private: friend class schema; template diff --git a/source/core/logger/basic_file_sink.cpp b/source/core/logger/basic_file_sink.cpp index 068101c..6822638 100644 --- a/source/core/logger/basic_file_sink.cpp +++ b/source/core/logger/basic_file_sink.cpp @@ -1,5 +1,7 @@ #include "matador/logger/basic_file_sink.hpp" +#include + namespace matador::logger { basic_file_sink::basic_file_sink(FILE *f) diff --git a/source/core/logger/log_domain.cpp b/source/core/logger/log_domain.cpp index 0c33d39..ddb6a3f 100644 --- a/source/core/logger/log_domain.cpp +++ b/source/core/logger/log_domain.cpp @@ -100,7 +100,7 @@ void log_domain::log(log_level lvl, const std::string &source, const char *messa #ifdef _MSC_VER int ret = sprintf_s(buffer, 1024, "%s [Thread %zu] [%-7s] [%s]: %s\n", timestamp, details::acquire_thread_index(std::this_thread::get_id()), level_strings[lvl].c_str(), source.c_str(), message); #else - int ret = sprintf(buffer, "%s [Thread %lu] [%-7s] [%s]: %s\n", timestamp, acquire_thread_index(std::this_thread::get_id()), level_strings[lvl].c_str(), source.c_str(), message); + int ret = sprintf(buffer, "%s [Thread %lu] [%-7s] [%s]: %s\n", timestamp, details::acquire_thread_index(std::this_thread::get_id()), level_strings[lvl].c_str(), source.c_str(), message); #endif std::lock_guard l(mutex_); diff --git a/source/core/object/basic_object_info.cpp b/source/core/object/basic_object_info.cpp index 5e7d1d2..61cb13d 100644 --- a/source/core/object/basic_object_info.cpp +++ b/source/core/object/basic_object_info.cpp @@ -58,7 +58,7 @@ const utils::identifier& basic_object_info::primary_key() const { return identifier_.value(); } -void basic_object_info::register_relation_endpoint(const std::type_index &type, const relation_endpoint &endpoint) { +void basic_object_info::register_relation_endpoint(const std::type_index &type, const std::shared_ptr &endpoint) { relation_endpoints_.insert(std::make_pair(type, endpoint)); } @@ -77,13 +77,13 @@ basic_object_info::endpoint_iterator basic_object_info::find_relation_endpoint(c basic_object_info::const_endpoint_iterator basic_object_info::find_relation_endpoint(const std::string &field) const { return std::find_if(relation_endpoints_.begin(), relation_endpoints_.end(), [&field](const t_endpoint_map::value_type &value) { - return value.second.field_name() == field; + return value.second->field_name() == field; }); } basic_object_info::endpoint_iterator basic_object_info::find_relation_endpoint(const std::string &field) { return std::find_if(relation_endpoints_.begin(), relation_endpoints_.end(), [&field](const t_endpoint_map::value_type &value) { - return value.second.field_name() == field; + return value.second->field_name() == field; }); } diff --git a/source/core/object/relation_endpoint.cpp b/source/core/object/relation_endpoint.cpp index c3c8823..a8f179e 100644 --- a/source/core/object/relation_endpoint.cpp +++ b/source/core/object/relation_endpoint.cpp @@ -17,6 +17,10 @@ relation_type relation_endpoint::type() const { return type_; } +std::string relation_endpoint::type_name() const { + return relation_type_enum.to_string(type_); +} + const schema_node &relation_endpoint::node() const { return *node_; } diff --git a/source/core/object/schema.cpp b/source/core/object/schema.cpp index 8501237..7ca3d06 100644 --- a/source/core/object/schema.cpp +++ b/source/core/object/schema.cpp @@ -17,6 +17,33 @@ root_->first_child_->next_sibling_ = root_->last_child_; root_->last_child_->previous_sibling_ = root_->first_child_; } +utils::result schema::detach(const node_ptr &node) { + log_.debug("detach node '%s' (type: %s)", node->name().c_str(), node->type_index().name()); + + remove_node(node); + + return utils::ok(); +} + +// utils::result schema::detach(const std::string& name) { +// const auto nit = nodes_by_name_.find(name); +// if (nit == nodes_by_name_.end()) { +// return utils::failure(make_error(error_code::NodeNotFound, "Node '" + name + "' not found.")); +// } +// +// const auto ti = nit->second->type_index(); +// nodes_by_name_.erase(nit); +// +// const auto it = nodes_by_type_.find(ti); +// if (it == nodes_by_type_.end()) { +// return utils::failure(make_error(error_code::NodeNotFound, "Node '" + name + "' not found.")); +// } +// +// nodes_by_type_.erase(it); +// +// return utils::ok(); +// } + schema::const_iterator schema::begin() const { return const_iterator(root_->first_child_->next_sibling_); } @@ -50,12 +77,23 @@ utils::result, utils::error> schema::refer return utils::failure(result.err()); } -utils::result, utils::error> schema::attach_node(const std::shared_ptr &node, - const std::string &parent) { +void schema::dump(std::ostream &os) const { + for (const auto &node : *this) { + os << "node [" << node.name() << "] (" << node.type_index().name() << ")\n"; + for (auto it = node.info().endpoint_begin(); it != node.info().endpoint_end(); ++it) { + os << " " << node.name() << "::" << it->second->field_name() << " (" << it->second->type_name() << ") <---> " << it->second->foreign_endpoint()->node().name() << "::" << it->second->foreign_endpoint()->field_name() << " (" << it->second->foreign_endpoint()->type_name() << ")\n"; + } + } +} + +utils::result schema::attach_node(const std::shared_ptr &node, + const std::string &parent) { if (has_node(node->type_index(), node->name())) { return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists.")); } + log_.info("attach node '%s' (type: %s)", node->name().c_str(), node->type_index().name()); + // set node to root node auto parent_node = root_; if (!parent.empty()) { @@ -75,8 +113,8 @@ utils::result, utils::error> schema::attach_node(co return utils::ok(node); } -utils::result, utils::error> schema::attach_node(const std::shared_ptr &node, - const std::type_index &type_index) { +utils::result schema::attach_node(const std::shared_ptr &node, + const std::type_index &type_index) { if (has_node(node->type_index(), node->name())) { return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists.")); } @@ -94,7 +132,7 @@ utils::result, utils::error> schema::attach_node(co return utils::ok(node); } -utils::result, utils::error> schema::find_node(const std::string &name) const { +utils::result schema::find_node(const std::string &name) const { // first search in the prototype map const auto i = nodes_by_name_.find(name); if (i == nodes_by_name_.end()) { @@ -103,7 +141,7 @@ utils::result, utils::error> schema::find_node(cons return utils::ok(i->second); } -utils::result, utils::error> schema::find_node(const std::type_index &type_index) const { +utils::result schema::find_node(const std::type_index &type_index) const { const auto i = nodes_by_type_.find(type_index); if (i == nodes_by_type_.end()) { return utils::failure(make_error(error_code::NodeNotFound, @@ -128,6 +166,33 @@ void schema::push_back_child(const node_ptr &parent, const node_ptr &child) { // child->depth = depth + 1; } +void schema::remove_node(const node_ptr &node) { + auto next = node->next(); + + std::stack nodes_to_remove; + nodes_to_remove.push(node); + + while (!nodes_to_remove.empty()) { + const auto current = nodes_to_remove.top(); + + if (current->has_children()) { + // Push all children to the stack (from right to left to maintain order) + auto child = current->last_child_->previous_sibling_; + while (child != current->first_child_) { + nodes_to_remove.push(child); + child = child->previous_sibling_; + } + continue; + } + + // No children left, safe to remove this node + nodes_to_remove.pop(); + current->unlink(); + nodes_by_name_.erase(current->name()); + nodes_by_type_.erase(current->type_index()); + } +} + bool schema::has_node(const std::string &name) const { return nodes_by_name_.count(name) > 0; } diff --git a/source/core/object/schema_node.cpp b/source/core/object/schema_node.cpp index d217048..32d01e3 100644 --- a/source/core/object/schema_node.cpp +++ b/source/core/object/schema_node.cpp @@ -44,6 +44,10 @@ const object::schema& schema_node::schema() const { return schema_; } +bool schema_node::has_children() const { + return first_child_->next_sibling_ != last_child_; +} + schema_node::node_ptr schema_node::next() const { // if we have a child, child is the next iterator to return // (if we don't do iterate over the siblings) @@ -76,4 +80,11 @@ schema_node::node_ptr schema_node::prev() const { // is the parent of the node return parent_->parent_ ? parent_ : parent_->first_child_->next_sibling_; } + +void schema_node::unlink() { + previous_sibling_->next_sibling_ = next_sibling_; + next_sibling_->previous_sibling_ = previous_sibling_; + next_sibling_.reset(); + previous_sibling_.reset(); +} }