From 38cbffc18bc815716b26695be8ed8dde4f4b42ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Tue, 1 Jul 2025 17:13:52 +0200 Subject: [PATCH] relation_completer progress --- include/matador/object/basic_object_info.hpp | 3 +- .../matador/object/many_to_many_relation.hpp | 25 ++++++++ include/matador/object/object_info.hpp | 24 ++++++-- include/matador/object/object_ptr.hpp | 8 +++ include/matador/object/relation_endpoint.hpp | 6 +- include/matador/object/schema.hpp | 59 +++++++++++++++---- include/matador/object/schema_node.hpp | 14 +++-- source/core/CMakeLists.txt | 4 +- source/core/object/relation_endpoint.cpp | 2 + source/core/object/schema_node.cpp | 10 +++- test/core/object/SchemaTest.cpp | 30 ++++++++++ 11 files changed, 153 insertions(+), 32 deletions(-) diff --git a/include/matador/object/basic_object_info.hpp b/include/matador/object/basic_object_info.hpp index 2c841c8..f25a82e 100644 --- a/include/matador/object/basic_object_info.hpp +++ b/include/matador/object/basic_object_info.hpp @@ -12,6 +12,7 @@ namespace matador::object { class schema_node; +class relation_endpoint; class basic_object_info { public: @@ -26,7 +27,7 @@ public: [[nodiscard]] const object_definition& definition() const; [[nodiscard]] std::shared_ptr reference_column() const; - bool has_primary_key() const; + [[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); diff --git a/include/matador/object/many_to_many_relation.hpp b/include/matador/object/many_to_many_relation.hpp index ecdd360..96ad29d 100644 --- a/include/matador/object/many_to_many_relation.hpp +++ b/include/matador/object/many_to_many_relation.hpp @@ -33,5 +33,30 @@ private: object_ptr remote_; }; +template < class LocalType, class Type > +class many_to_relation { +public: + many_to_relation() = default; + many_to_relation(std::string local_name, std::string remote_name) + : local_name_(std::move(local_name)) + , type_name_(std::move(remote_name)) {} + + template + void process(Operator &op) { + namespace field = matador::access; + field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes); + field::attribute(op, type_name_.c_str(), value_); + } + + object_ptr local() const { return local_; } + Type value() const { return value_; } + +private: + std::string local_name_; + std::string type_name_; + object_ptr local_; + Type value_; +}; + } #endif //QUERY_HAS_MANY_TO_MANY_RELATION_HPP diff --git a/include/matador/object/object_info.hpp b/include/matador/object/object_info.hpp index ab6d2cc..955e7a0 100644 --- a/include/matador/object/object_info.hpp +++ b/include/matador/object/object_info.hpp @@ -10,21 +10,33 @@ class schema_node; template class object_info final : public basic_object_info { public: - explicit object_info(const std::shared_ptr& node, - std::shared_ptr &&ref_column) + using create_func = std::function()>; + + object_info(const std::shared_ptr& node, + std::shared_ptr &&ref_column) : basic_object_info(node, typeid(Type), {}, std::move(ref_column), {}) { } - explicit object_info(const std::shared_ptr& node, - utils::identifier &&pk, - std::shared_ptr &&ref_column, - object_definition &&definition) + object_info(const std::shared_ptr& node, + utils::identifier &&pk, + std::shared_ptr &&ref_column, + object_definition &&definition) : basic_object_info(node, typeid(Type), std::move(pk), std::move(ref_column), std::move(definition)) { } + object_info(const std::shared_ptr& node, + utils::identifier &&pk, + std::shared_ptr &&ref_column, + object_definition &&definition, + create_func&& creator) + : basic_object_info(node, typeid(Type), std::move(pk), std::move(ref_column), std::move(definition)) + , creator_(std::move(creator)){ + } const Type &prototype() const { return prototype_; } + std::unique_ptr create() const { return creator_(); } private: Type prototype_; + create_func creator_{[]{ return std::make_unique(); }}; }; template diff --git a/include/matador/object/object_ptr.hpp b/include/matador/object/object_ptr.hpp index ce19087..db715d3 100644 --- a/include/matador/object/object_ptr.hpp +++ b/include/matador/object/object_ptr.hpp @@ -45,6 +45,14 @@ private: utils::identifier pk_; }; +template +struct is_object_ptr : std::false_type +{}; + +template +struct is_object_ptr> : std::true_type +{}; + } #endif //OBJECT_PTR_HPP diff --git a/include/matador/object/relation_endpoint.hpp b/include/matador/object/relation_endpoint.hpp index cd3b951..ed06d95 100644 --- a/include/matador/object/relation_endpoint.hpp +++ b/include/matador/object/relation_endpoint.hpp @@ -1,12 +1,14 @@ #ifndef MATADOR_RELATION_ENDPOINT_HPP #define MATADOR_RELATION_ENDPOINT_HPP -#include "matador/object/schema_node.hpp" - #include "matador/utils/enum_mapper.hpp" +#include + namespace matador::object { +class schema_node; + enum class relation_type : uint8_t { BELONGS_TO, HAS_ONE, diff --git a/include/matador/object/schema.hpp b/include/matador/object/schema.hpp index 548089c..c5adb8a 100644 --- a/include/matador/object/schema.hpp +++ b/include/matador/object/schema.hpp @@ -58,11 +58,11 @@ class relation_completer final { public: using value_type = Type; - static void prepare_expected_nodes(schema &scm) { - relation_completer analyzer(scm); + static void prepare_expected_nodes(schema_node &node) { + relation_completer completer(node); Type obj; - access::process(analyzer, obj); + access::process(completer, obj); } template < class PrimaryKeyType > @@ -86,11 +86,12 @@ public: } template - void on_has_many(const char * /*id*/, CollectionType &, const char *, const utils::foreign_attributes &/*attr*/); + 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 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); @@ -99,14 +100,14 @@ private: void on_foreign_key(); private: - explicit relation_completer(schema& schema, const std::shared_ptr &node) - : schema_(schema) - , node_(node){} + explicit relation_completer(schema_node& node) + : node_(node) + , schema_(node.schema_){} private: - schema &schema_; - std::shared_ptr node_; + schema_node &node_; + schema& schema_; }; @@ -134,9 +135,8 @@ public: type_index_node_map_.insert({node->type_index(), node}); } else { // analyze node (collect unknown types by type index) - relation_completer::prepare_expected_nodes(*this); - const auto node = schema_node::make_node(*this, name); + relation_completer::prepare_expected_nodes(*node); if (auto result = attach_node(node, parent); !result) { return utils::failure(result.err()); } @@ -245,8 +245,41 @@ private: template template -void relation_completer::on_has_many( const char*, CollectionType&, const char*, const utils::foreign_attributes& ) { +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; + // Process foreign key has many relation + // Check if foreign key type was already registered + auto result = schema_.find_node(typeid(value_type)); + if (result) { + } else { + // + using relation_type = many_to_many_relation; + auto creator = [] { + return new many_to_many_relation(); + }; + } + +} + +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; + + // Process values has many relation + // Register relation table + + // many_to_relation *relation = new many_to_relation(join_column, "value"); + auto result = schema_.find_node(typeid(value_type)); + if (result) { + } else { + // + using relation_type = many_to_many_relation; + auto creator = [] { + return new many_to_many_relation(); + }; + } } diff --git a/include/matador/object/schema_node.hpp b/include/matador/object/schema_node.hpp index 32b6734..4eddca3 100644 --- a/include/matador/object/schema_node.hpp +++ b/include/matador/object/schema_node.hpp @@ -17,7 +17,7 @@ public: using node_ptr = std::shared_ptr; template < typename Type > - static std::shared_ptr make_node(schema& tree, const std::string& name) { + static std::shared_ptr make_node(object::schema& tree, const std::string& name) { auto node = std::shared_ptr(new schema_node(tree, name)); primary_key_resolver resolver; @@ -34,7 +34,7 @@ public: } template < typename Type > - static std::shared_ptr make_relation_node(schema& tree, const std::string& name) { + static std::shared_ptr make_relation_node(object::schema& tree, const std::string& name) { auto node = std::shared_ptr(new schema_node(tree, name)); auto info = std::make_unique>( @@ -69,15 +69,19 @@ public: return std::ref(static_cast&>(*info_)); } + const object::schema& schema() const; + private: - explicit schema_node(schema& tree); - schema_node(schema& tree, std::string name); + explicit schema_node(object::schema& tree); + schema_node(object::schema& tree, std::string name); private: friend class schema; + template + friend class relation_completer; friend class const_schema_node_iterator; - schema &schema_; + object::schema &schema_; std::unique_ptr info_; std::shared_ptr parent_; diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index 8a2f646..93e9a65 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(matador-core STATIC ../../include/matador/object/object_proxy.hpp ../../include/matador/object/object_ptr.hpp ../../include/matador/object/primary_key_resolver.hpp + ../../include/matador/object/relation_endpoint.hpp ../../include/matador/object/schema.hpp ../../include/matador/object/schema_node.hpp ../../include/matador/object/schema_node_iterator.hpp @@ -57,6 +58,7 @@ add_library(matador-core STATIC object/error_code.cpp object/object_definition.cpp object/primary_key_resolver.cpp + object/relation_endpoint.cpp object/schema.cpp object/schema_node.cpp object/schema_node_iterator.cpp @@ -75,8 +77,6 @@ add_library(matador-core STATIC utils/uuid.cpp utils/value.cpp utils/version.cpp - ../../include/matador/object/relation_endpoint.hpp - object/relation_endpoint.cpp ) target_link_libraries(matador-core ${CMAKE_DL_LIBS}) diff --git a/source/core/object/relation_endpoint.cpp b/source/core/object/relation_endpoint.cpp index a617245..06e67e2 100644 --- a/source/core/object/relation_endpoint.cpp +++ b/source/core/object/relation_endpoint.cpp @@ -1,5 +1,7 @@ #include "matador/object/relation_endpoint.hpp" +#include "matador/object/schema_node.hpp" + namespace matador::object { relation_endpoint::relation_endpoint(std::string field_name, relation_type type, const std::shared_ptr &node) : field_name_(std::move(field_name)) diff --git a/source/core/object/schema_node.cpp b/source/core/object/schema_node.cpp index 814bc57..f50b43c 100644 --- a/source/core/object/schema_node.cpp +++ b/source/core/object/schema_node.cpp @@ -3,11 +3,11 @@ #include "matador/object/schema_node.hpp" namespace matador::object { -schema_node::schema_node(schema &tree) +schema_node::schema_node(object::schema &tree) : schema_(tree) { } -schema_node::schema_node(schema &tree, std::string name) +schema_node::schema_node(object::schema &tree, std::string name) : schema_(tree) , first_child_(std::shared_ptr(new schema_node(tree))) , last_child_(std::shared_ptr(new schema_node(tree))) @@ -16,7 +16,7 @@ schema_node::schema_node(schema &tree, std::string name) last_child_->previous_sibling_ = first_child_; } -std::shared_ptr schema_node::make_null_node(schema &tree) { +std::shared_ptr schema_node::make_null_node(object::schema &tree) { auto node = std::shared_ptr(new schema_node(tree)); node->info_ = std::make_unique(node, std::shared_ptr{}); @@ -40,6 +40,10 @@ void schema_node::update_name(const std::string& name) { info_->reference_column()->name(name); } +const object::schema& schema_node::schema() const { + return schema_; +} + 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) diff --git a/test/core/object/SchemaTest.cpp b/test/core/object/SchemaTest.cpp index 2571a4d..de4ff88 100644 --- a/test/core/object/SchemaTest.cpp +++ b/test/core/object/SchemaTest.cpp @@ -2,6 +2,8 @@ #include "matador/object/schema.hpp" +#include "../../models/department.hpp" + struct node {}; using namespace matador; @@ -15,6 +17,16 @@ struct person { struct student final : person {}; struct teacher final : person {}; +struct names { + std::vector names_list; + + template + void process(Operator &op) { + namespace field = matador::access; + field::has_many(op, "name_list", names_list, "names_id", utils::fetch_type::EAGER); + } +}; + TEST_CASE("Test empty prototype tree", "[schema_node][empty]") { const object::schema tree; @@ -51,4 +63,22 @@ TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous REQUIRE( it->name() == "person" ); REQUIRE( (--it)->name() == "person" ); REQUIRE( ++it == tree.end() ); +} + +TEST_CASE("Test automatic creating of a relation table with foreign key", "[schema][relation_table][foreign_key]") { + object::schema tree; + + REQUIRE( tree.empty() ); + + auto res = tree.attach("department"); + REQUIRE( res.is_ok() ); +} + +TEST_CASE("Test automatic creating of a relation table with values", "[schema][relation_table][values]") { + object::schema tree; + + REQUIRE( tree.empty() ); + + auto res = tree.attach("names"); + REQUIRE( res.is_ok() ); } \ No newline at end of file