From a714cd2a53ca344cbbdc238ae5da1b98f48a9676 Mon Sep 17 00:00:00 2001 From: sascha Date: Fri, 8 May 2026 15:53:52 +0200 Subject: [PATCH] has many primitive relation progress --- .../matador/object/many_to_many_relation.hpp | 5 +++ include/matador/object/relation_completer.hpp | 4 +- .../matador/query/insert_query_builder.hpp | 35 ++++++++++++++- include/matador/query/schema.hpp | 4 +- source/orm/sql/statement.cpp | 2 + test/backends/SessionInsertHasMany.cpp | 45 +++++++++++++++++++ 6 files changed, 89 insertions(+), 6 deletions(-) diff --git a/include/matador/object/many_to_many_relation.hpp b/include/matador/object/many_to_many_relation.hpp index d45ceee..8bd1029 100644 --- a/include/matador/object/many_to_many_relation.hpp +++ b/include/matador/object/many_to_many_relation.hpp @@ -46,6 +46,11 @@ public: many_to_relation(std::string local_name, std::string remote_name) : local_name_(std::move(local_name)) , type_name_(std::move(remote_name)) {} + many_to_relation(std::string local_name, std::string remote_name, const object_ptr& local, const Type& value) + : local_name_(std::move(local_name)) + , type_name_(std::move(remote_name)) + , local_(local) + , value_(value){} template void process(Operator &op) { diff --git a/include/matador/object/relation_completer.hpp b/include/matador/object/relation_completer.hpp index ab60ab6..0cb66b9 100644 --- a/include/matador/object/relation_completer.hpp +++ b/include/matador/object/relation_completer.hpp @@ -227,9 +227,11 @@ void relation_completer::on_has_many(const char *id, Collect using value_type = typename CollectionType::value_type; using relation_value_type = many_to_relation; + auto observers = internal::observer_list_copy_creator::copy_create(observers_); + auto node = repository_node::make_node(repo_, id, [join_column] { return std::make_unique(join_column, "value"); - }, {}); + }, std::move(observers)); const auto result = repo_.attach_node(node.release(), ""); if (!result) { // Todo: throw internal exception diff --git a/include/matador/query/insert_query_builder.hpp b/include/matador/query/insert_query_builder.hpp index 3080256..b24f192 100644 --- a/include/matador/query/insert_query_builder.hpp +++ b/include/matador/query/insert_query_builder.hpp @@ -104,7 +104,10 @@ public: on_foreign_object(obj, attr); } template - void on_has_many(const char * /*id*/, object::collection> &objects, const char *join_column, const utils::foreign_attributes &attr) { + void on_has_many(const char * /*id*/, + object::collection> &objects, + const char *join_column, + const utils::foreign_attributes &attr) { if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) { return; } @@ -120,7 +123,35 @@ public: } template - static void on_has_many(const char * /*id*/, object::collection &/*con*/, const char *, const utils::foreign_attributes &/*attr*/) {} + void on_has_many(const char *id, + object::collection &objects, + const char *join_column, + const utils::foreign_attributes &attr) { + if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) { + return; + } + + const auto it = schema_.find(std::string{id}); + if (it == schema_.end()) { + throw query_builder_exception(error_code::UnknownType, "Unknown type " + std::string{id}); + } + + using relation_value_type = object::many_to_relation; + if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) { + throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type"); + } + + const auto cit = contexts_by_type_.find(it->second.node().info().type_index()); + if (cit == contexts_by_type_.end()) { + throw query_builder_exception(error_code::UnknownType, "Unknown type" + std::string{id}); + } + + for (auto &obj : objects) { + auto rel = object::make_object(join_column, "value", ptr_, obj); + + relation_steps_.push_back(std::make_unique>(cit->second.insert, rel)); + } + } template void on_has_many_to_many(const char *id, object::collection> &objects, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) { diff --git a/include/matador/query/schema.hpp b/include/matador/query/schema.hpp index 201a5fc..557b2e3 100644 --- a/include/matador/query/schema.hpp +++ b/include/matador/query/schema.hpp @@ -94,9 +94,7 @@ public: } template - void on_has_many(const char * /*id*/, CollectionType &/*cont*/, const char * /*join_column*/, const utils::foreign_attributes &/*attr*/, std::enable_if_t::value> * = nullptr) { - - } + void on_has_many(const char * /*id*/, CollectionType &/*cont*/, 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 &, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) { diff --git a/source/orm/sql/statement.cpp b/source/orm/sql/statement.cpp index 6cb9d0c..9071f55 100644 --- a/source/orm/sql/statement.cpp +++ b/source/orm/sql/statement.cpp @@ -68,6 +68,8 @@ utils::result, utils::error> statement::fetch() const { } utils::result, utils::error> statement::fetch_one() const { + logger_->on_fetch(statement_proxy_->sql()); + std::cout << statement_proxy_->sql() << std::endl; auto result = statement_proxy_->fetch(*bindings_); if (!result.is_ok()) { return utils::failure(result.err()); diff --git a/test/backends/SessionInsertHasMany.cpp b/test/backends/SessionInsertHasMany.cpp index 3891173..b8e0085 100644 --- a/test/backends/SessionInsertHasMany.cpp +++ b/test/backends/SessionInsertHasMany.cpp @@ -1,3 +1,5 @@ +#include + #include "catch2/catch_test_macros.hpp" #include "SessionFixture.hpp" @@ -65,6 +67,30 @@ using book_identity = book_pk_generator; using book_sequence = book_pk_generator; using book_table = book_pk_generator; +template +struct colorlist_pk_generator { + unsigned int id{}; + std::string name; + collection colors; + + colorlist_pk_generator() = default; + colorlist_pk_generator(std::string name, const std::vector& color_names) + : name(std::move(name)) + , colors(color_names) {} + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id, PkAttribute); + field::attribute(op, "name", name, VarChar511); + field::has_many(op, "colors", colors, "colorlist_id", utils::CascadeAllFetchLazy); + } +}; + +using colorlist_identity = colorlist_pk_generator; +using colorlist_sequence = colorlist_pk_generator; +using colorlist_table = colorlist_pk_generator; + } template @@ -162,4 +188,23 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation with auto author = *author_result; REQUIRE(author.is_persistent()); REQUIRE(author->books.size() == 5); +} + +TEST_CASE_METHOD(SessionFixture, "Test insert object with has many primitive relation with table sequence", "[session][insert][has_many][primitive][table_sequence]") { + const auto result = schema.attach("colorlist") + .and_then([this] { return schema.create(db); } ); + REQUIRE(result.is_ok()); + + session ses({bus, connection::dns, 4}, schema); + + const auto c = make_object("rgb", std::vector{"red", "green", "blue"}); + + auto res = ses.insert(c); + REQUIRE(res.is_ok()); + + auto colorlist_result = ses.find(c->id); + REQUIRE(colorlist_result); + auto clist = *colorlist_result; + REQUIRE(clist.is_persistent()); + REQUIRE(clist->colors.size() == 3); } \ No newline at end of file