From 96c6c78cb8e092eb52a815f59fec0a9c8517ea86 Mon Sep 17 00:00:00 2001 From: sascha Date: Tue, 28 Apr 2026 16:43:01 +0200 Subject: [PATCH] has many generator progress --- .../matador/query/insert_query_builder.hpp | 6 +- include/matador/query/session.hpp | 14 ++--- .../matador/utils/primary_key_accessor.hpp | 2 +- .../matador/utils/primary_key_attribute.hpp | 3 + source/orm/query/insert_query_builder.cpp | 11 +--- source/orm/query/session.cpp | 16 ++++-- test/backends/SessionInsertHasMany.cpp | 56 ++++++++++++++----- 7 files changed, 71 insertions(+), 37 deletions(-) diff --git a/include/matador/query/insert_query_builder.hpp b/include/matador/query/insert_query_builder.hpp index 92d0082..acd4ee9 100644 --- a/include/matador/query/insert_query_builder.hpp +++ b/include/matador/query/insert_query_builder.hpp @@ -56,7 +56,7 @@ private: struct insert_step { sql::query_context ctx; - utils::result acquire_and_bind(sql::statement_cache &cache) const; + utils::result acquire_and_bind(sql::statement &stmt) const; // Session uses these to handle manual/sequence/table pre-insert PKs utils::generator_type pk_generator{utils::generator_type::Manual}; @@ -300,7 +300,9 @@ private: return utils::failure(utils::error{error_code::UnknownType, "Unknown type"}); } step.ctx = cit->second.insert; - step.bind_object = [ptr](sql::statement &stmt) { stmt.bind(*ptr); }; + step.bind_object = [ptr](sql::statement &stmt) { + stmt.bind(*ptr); + }; if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) { const auto pk_name = info.primary_key_attribute()->name(); const table_column pk_col(&it->second.table(), pk_name); diff --git a/include/matador/query/session.hpp b/include/matador/query/session.hpp index 6d34af8..b629d30 100644 --- a/include/matador/query/session.hpp +++ b/include/matador/query/session.hpp @@ -112,8 +112,7 @@ utils::result, utils::error> session::insert(object::ob return utils::failure(stmt.err()); } - auto result = step.acquire_and_bind(cache_); - if (!result.is_ok()) { + if (auto result = step.acquire_and_bind(*stmt); !result.is_ok()) { return utils::failure(result.err()); } @@ -127,7 +126,7 @@ utils::result, utils::error> session::insert(object::ob return utils::failure(make_error(error_code::FailedToFindObject, "Failed to insert object and retrieve identity.")); } step.apply_returning(*record.value()); - } else if (const auto exec_result = result->execute(); !exec_result.is_ok()) { + } else if (const auto exec_result = stmt->execute(); !exec_result.is_ok()) { return utils::failure(exec_result.err()); } step.make_object_persistent(); @@ -157,9 +156,7 @@ public: stmt_.bind(binding_position_, x); } - static void on_revision(const char * /*id*/, uint64_t &/*rev*/) { - } - + static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} template static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/) {} template @@ -257,8 +254,7 @@ utils::result, utils::error> session::find(const Primar select_query_builder eqb(schema_); auto data = eqb.build(*it->second.table().primary_key_column() == pk); if (!data.is_ok()) { - return utils::failure(make_error(error_code::FailedToBuildQuery, - "Failed to build query for type " + it->second.name() + ".")); + return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + it->second.name() + ".")); } auto ctx = data->compile(dialect_); @@ -272,7 +268,7 @@ utils::result, utils::error> session::find(const Primar } template -utils::result, utils::error> session::find(query::criteria_ptr clause) { +utils::result, utils::error> session::find(criteria_ptr clause) { const auto it = schema_.find(typeid(Type)); if (it == schema_.end()) { return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); diff --git a/include/matador/utils/primary_key_accessor.hpp b/include/matador/utils/primary_key_accessor.hpp index fadb16c..5d4a42a 100644 --- a/include/matador/utils/primary_key_accessor.hpp +++ b/include/matador/utils/primary_key_accessor.hpp @@ -25,7 +25,7 @@ public: static void on_base(const BaseType&) {} template void on_primary_key(const char * /*id*/, PrimaryKeyType &pk, const primary_key_attribute & = DefaultPkAttributes) { - const auto value = pk_.as(); + const auto value = pk_.convert(); if (!value) { // Todo: throw error } diff --git a/include/matador/utils/primary_key_attribute.hpp b/include/matador/utils/primary_key_attribute.hpp index 7a198f1..4a7ec9d 100644 --- a/include/matador/utils/primary_key_attribute.hpp +++ b/include/matador/utils/primary_key_attribute.hpp @@ -48,7 +48,10 @@ private: }; const primary_key_attribute DefaultPkAttributes {}; +const primary_key_attribute Manual {generator_type::Manual}; const primary_key_attribute Identity {generator_type::Identity}; +const primary_key_attribute Sequence {generator_type::Sequence}; +const primary_key_attribute Table {generator_type::Table}; const primary_key_attribute ManualVarChar63 {63}; const primary_key_attribute ManualVarChar127 {127}; const primary_key_attribute ManualVarChar255 {255}; diff --git a/source/orm/query/insert_query_builder.cpp b/source/orm/query/insert_query_builder.cpp index 08455ea..bf9cd0f 100644 --- a/source/orm/query/insert_query_builder.cpp +++ b/source/orm/query/insert_query_builder.cpp @@ -3,14 +3,9 @@ #include "matador/sql/statement_cache.hpp" namespace matador::query { -utils::result insert_step::acquire_and_bind(sql::statement_cache &cache) const { - auto result = cache.acquire(ctx); - if (!result.is_ok()) { - return utils::failure(result.err()); - } +utils::result insert_step::acquire_and_bind(sql::statement &stmt) const { + bind_object(stmt); - bind_object(*result); - - return utils::ok(std::move(*result)); + return utils::ok(); } } // namespace matador::query \ No newline at end of file diff --git a/source/orm/query/session.cpp b/source/orm/query/session.cpp index a8ba604..c71820e 100644 --- a/source/orm/query/session.cpp +++ b/source/orm/query/session.cpp @@ -55,10 +55,18 @@ session::session(session_context&& ctx, const basic_schema &scm) } columns.push_back(col); } - queries.insert = query::insert() - .into(node.name(), columns) - .values(generator::placeholders(columns.size())) - .compile(dialect_); + if (node.pk_generator().type() == utils::generator_type::Identity) { + queries.insert = query::insert() + .into(node.name(), columns) + .values(generator::placeholders(columns.size())) + .returning(node.table().primary_key_column()->as(node.table().primary_key_column()->column_name())) + .compile(dialect_); + } else { + queries.insert = query::insert() + .into(node.name(), columns) + .values(generator::placeholders(columns.size())) + .compile(dialect_); + } queries.insert.resolver = resolver_service_; queries.update_one.resolver = resolver_service_; diff --git a/test/backends/SessionInsertHasMany.cpp b/test/backends/SessionInsertHasMany.cpp index 719ae40..8075126 100644 --- a/test/backends/SessionInsertHasMany.cpp +++ b/test/backends/SessionInsertHasMany.cpp @@ -15,11 +15,14 @@ using namespace matador::object; using namespace matador::test; namespace matador::test { +template struct book_identity; + +template struct author_identity { unsigned int id{}; std::string name; - collection > books; + collection>> books; author_identity() = default; explicit author_identity(std::string name) @@ -28,31 +31,38 @@ struct author_identity { template void process(Operator &op) { namespace field = matador::access; - field::primary_key(op, "id", id, utils::Identity); + field::primary_key(op, "id", id, PkAttribute); field::attribute(op, "name", name, VarChar63); field::has_many(op, "books", books, "author_id", utils::CascadeAllFetchLazy); } }; +template struct book_identity { unsigned int id{}; std::string title; - object_ptr book_author; + object_ptr> book_author; unsigned short published_in{}; book_identity() = default; - book_identity(std::string title, object_ptr author, const unsigned short published_in) + book_identity(std::string title, object_ptr> author, const unsigned short published_in) : title(std::move(title)), book_author(std::move(author)), published_in(published_in) {} template void process(Operator &op) { namespace field = matador::access; - field::primary_key(op, "id", id, utils::Identity); + field::primary_key(op, "id", id, PkAttribute); field::attribute(op, "title", title, VarChar511); field::belongs_to(op, "author_id", book_author, utils::CascadeAllFetchEager); field::attribute(op, "published_in", published_in); } }; + +using author_sequence = author_identity; +using author_table = author_identity; +using book_sequence = book_identity; +using book_table = book_identity; + } TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[session][insert][has_many]") { @@ -76,20 +86,40 @@ TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation", "[ } TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation with identity", "[session][insert][has_many][identity]") { - const auto result = schema.attach("books") - .and_then( [this] { return schema.attach("authors"); } ) + const auto result = schema.attach>("books") + .and_then( [this] { return schema.attach>("authors"); } ) .and_then([this] { return schema.create(db); } ); REQUIRE(result.is_ok()); session ses({bus, connection::dns, 4}, schema); - auto s_king = make_object("Steven King"); + auto s_king = make_object>("Steven King"); - s_king->books.push_back(make_object("Carrie", nullobj, 1974)); - s_king->books.push_back(make_object("The Shining", nullobj, 1977)); - s_king->books.push_back(make_object("It", nullobj, 1986)); - s_king->books.push_back(make_object("Misery", nullobj, 1987)); - s_king->books.push_back(make_object("The Dark Tower: The Gunslinger", nullobj, 1982)); + s_king->books.push_back(make_object>("Carrie", nullobj, 1974)); + s_king->books.push_back(make_object>("The Shining", nullobj, 1977)); + s_king->books.push_back(make_object>("It", nullobj, 1986)); + s_king->books.push_back(make_object>("Misery", nullobj, 1987)); + s_king->books.push_back(make_object>("The Dark Tower: The Gunslinger", nullobj, 1982)); + + auto res = ses.insert(s_king); + REQUIRE(res.is_ok()); +} + +TEST_CASE_METHOD(SessionFixture, "Test insert object with has many relation with sequence", "[session][insert][has_many][sequence]") { + const auto result = schema.attach("books") + .and_then( [this] { return schema.attach("authors"); } ) + .and_then([this] { return schema.create(db); } ); + REQUIRE(result.is_ok()); + + session ses({bus, connection::dns, 4}, schema); + + auto s_king = make_object("Steven King"); + + s_king->books.push_back(make_object("Carrie", nullobj, 1974)); + s_king->books.push_back(make_object("The Shining", nullobj, 1977)); + s_king->books.push_back(make_object("It", nullobj, 1986)); + s_king->books.push_back(make_object("Misery", nullobj, 1987)); + s_king->books.push_back(make_object("The Dark Tower: The Gunslinger", nullobj, 1982)); auto res = ses.insert(s_king); REQUIRE(res.is_ok());