From 463647ba5956ef3f626dc3821ad849e44c3c7aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Wed, 8 Oct 2025 16:03:00 +0200 Subject: [PATCH] fixed session tests --- include/matador/orm/session.hpp | 139 +++++++++++------- include/matador/orm/session_query_builder.hpp | 13 +- .../query/intermediates/fetchable_query.hpp | 10 +- include/matador/sql/query_result.hpp | 40 ++--- include/matador/sql/statement.hpp | 10 +- source/orm/orm/session.cpp | 5 +- .../query/intermediates/fetchable_query.cpp | 5 +- source/orm/sql/statement.cpp | 10 +- test/backends/SessionTest.cpp | 3 +- 9 files changed, 144 insertions(+), 91 deletions(-) diff --git a/include/matador/orm/session.hpp b/include/matador/orm/session.hpp index 790005b..8833862 100644 --- a/include/matador/orm/session.hpp +++ b/include/matador/orm/session.hpp @@ -100,61 +100,25 @@ public: utils::result create_schema() const; + /** + * Insert the given object into the session. + * + * @tparam Type Type of object to insert + * @param obj Object to insert + * @return Inserted object + */ template utils::result, utils::error> insert(Type *obj); - template< class Type, typename... Args > - utils::result, utils::error> insert(Args&&... args) { - return insert(new Type(std::forward(args)...)); - } - - template - utils::result, utils::error> find(const PrimaryKeyType &pk) { - auto info = schema_->info(); - if (!info) { - return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); - } - - session_query_builder eqb(*schema_, *this); - auto data = eqb.build(pk); - if (!data.is_ok()) { - return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + ".")); - } - - auto res = build_select_query(data.release()).prepare(*this); - // auto obj = build_select_query(data.release()).template fetch_one(*this); - - if (!res) { - return utils::failure(res.err()); - } - auto stmt_result = res->bind(0, const_cast(pk)).template fetch_one(); - if (!stmt_result) { - return utils::failure(make_error(error_code::FailedToFindObject, "Failed to find object of type " + info->get().name() + " with primary key " + std::to_string(pk) + ".")); - } - return utils::ok(object::object_ptr{ stmt_result->release() }); - } + utils::result, utils::error> insert(Args&&... args); template - utils::result, utils::error> find() { - auto info = schema_->info(); - if (!info) { - return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); - } + utils::result, utils::error> update(const object::object_ptr &obj); - session_query_builder eqb(*schema_, *this); - auto data = eqb.build(); - if (!data.is_ok()) { - return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + ".")); - } - - const auto ctx = build_select_query(data.release()).compile(dialect_, query::query_mode::Prepared); - - auto result = fetch(ctx); - if (!result.is_ok()) { - return utils::failure(result.err()); - } - return utils::ok(sql::query_result(result.release(), []{ return new Type();})); - } + template + utils::result, utils::error> find(const PrimaryKeyType &pk); + template + utils::result, utils::error> find(); template utils::result drop_table(); @@ -207,14 +171,89 @@ utils::result, utils::error> session::insert(Type *obj) auto res = query::query::insert() .into(info->get().name(), sql::column_generator::generate(*schema_, true)) .values(*obj) - .execute(*this); + .prepare(*this); if (!res) { return utils::failure(res.err()); } + if (const auto insert_result = res->bind(*obj).execute(); !insert_result.is_ok()) { + return utils::failure(insert_result.err()); + } return utils::ok(object::object_ptr{obj}); } +template +utils::result, utils::error> session::insert( Args&&... args ) { + return insert(new Type(std::forward(args)...)); +} + +template +utils::result, utils::error> session::update( const object::object_ptr& obj ) { + auto info = schema_->info(); + if (!info) { + return utils::failure(info.err()); + } + + auto res = query::query::update(info->get().name()) + .set(*obj) + // .where(sql::column(info->prototype().primary_key()->name()) == _) + .prepare(*this); + if (!res) { + return utils::failure(res.err()); + } + + if (const auto insert_result = res->bind(*obj).execute(); !insert_result.is_ok()) { + return utils::failure(insert_result.err()); + } + return utils::ok(object::object_ptr{obj}); +} + +template +utils::result, utils::error> session::find( const PrimaryKeyType& pk ) { + auto info = schema_->info(); + if (!info) { + return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); + } + + session_query_builder eqb(*schema_, *this); + auto data = eqb.build(pk); + if (!data.is_ok()) { + return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + ".")); + } + + auto res = build_select_query(data.release()).prepare(*this); + + if (!res) { + return utils::failure(res.err()); + } + auto stmt_result = res->bind(0, const_cast(pk)).template fetch_one(); + if (stmt_result && !stmt_result.value()) { + return utils::failure(make_error(error_code::FailedToFindObject, "Failed to find object of type " + info->get().name() + " with primary key " + std::to_string(pk) + ".")); + } + return utils::ok(object::object_ptr{ stmt_result->release() }); +} + +template +utils::result, utils::error> session::find() { + auto info = schema_->info(); + if (!info) { + return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); + } + + session_query_builder eqb(*schema_, *this); + auto data = eqb.build(); + if (!data.is_ok()) { + return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + ".")); + } + + auto result = build_select_query(data.release()).prepare(*this); + if (!result.is_ok()) { + return utils::failure(result.err()); + } + + return result->template fetch(); +} + template utils::result session::drop_table() { auto info = schema_->info(); diff --git a/include/matador/orm/session_query_builder.hpp b/include/matador/orm/session_query_builder.hpp index 74497ba..ee508f4 100644 --- a/include/matador/orm/session_query_builder.hpp +++ b/include/matador/orm/session_query_builder.hpp @@ -261,6 +261,11 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u if (!info) { throw query_builder_exception{query_build_error::UnknownType}; } + auto pk = info->get().definition().primary_key(); + if (!pk) { + throw query_builder_exception{query_build_error::MissingPrimaryKey}; + } + const auto foreign_table = std::make_shared(info->get().name(), build_alias('t', ++table_index)); if (attr.fetch() == utils::fetch_type::EAGER) { @@ -274,10 +279,6 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u access::process(*this, obj); table_info_stack_.pop(); - auto pk = info->get().definition().primary_key(); - if (!pk) { - throw query_builder_exception{query_build_error::MissingPrimaryKey}; - } append_join( sql::column{table_info_stack_.top().table, id}, sql::column{next->second, pk->name()} @@ -287,9 +288,9 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u using namespace matador::utils; using namespace matador::query; // create select query - auto result = matador::query::query::select(schema_) + auto result = matador::query::query::select(sql::column_generator::generate(schema_, true)) .from(*foreign_table) - .where(sql::column(foreign_table, id, "") == _) + .where(sql::column(foreign_table, pk->name(), "") == _) .prepare(executor_); if (!result) { throw query_builder_exception(query_build_error::QueryError, result.release_error()); diff --git a/include/matador/query/intermediates/fetchable_query.hpp b/include/matador/query/intermediates/fetchable_query.hpp index b2fdd08..345be36 100644 --- a/include/matador/query/intermediates/fetchable_query.hpp +++ b/include/matador/query/intermediates/fetchable_query.hpp @@ -31,7 +31,10 @@ public: return utils::failure(result.err()); } - return utils::ok(sql::query_result(result.release())); + const auto prototype = result.value()->prototype(); + return utils::ok(sql::query_result(result.release(), [prototype] { + return sql::detail::create_prototype(prototype); + })); } [[nodiscard]] utils::result, utils::error> fetch_all(const sql::executor &exec) const; @@ -43,7 +46,10 @@ public: return utils::failure(result.err()); } - auto objects = sql::query_result(result.release()); + const auto prototype = result.value()->prototype(); + auto objects = sql::query_result(result.release(), [prototype] { + return sql::detail::create_prototype(prototype); + }); auto first = objects.begin(); if (first == objects.end()) { return utils::ok(std::unique_ptr{nullptr}); diff --git a/include/matador/sql/query_result.hpp b/include/matador/sql/query_result.hpp index 5e61942..d2d510c 100644 --- a/include/matador/sql/query_result.hpp +++ b/include/matador/sql/query_result.hpp @@ -40,8 +40,7 @@ public: , result_(x.result_) {} - query_result_iterator& operator=(query_result_iterator&& x) noexcept - { + query_result_iterator& operator=(query_result_iterator&& x) noexcept { result_ = x.result_; obj_ = std::move(x.obj_); return *this; @@ -49,18 +48,15 @@ public: ~query_result_iterator() = default; - bool operator==(const query_result_iterator& rhs) - { + bool operator==(const query_result_iterator& rhs) { return obj_ == rhs.obj_; } - bool operator!=(const query_result_iterator& rhs) - { + bool operator!=(const query_result_iterator& rhs) { return obj_ != rhs.obj_; } - self& operator++() - { + self& operator++() { obj_.reset(result_->create()); result_->bind(*obj_); if (!result_->fetch(*obj_)) { @@ -70,8 +66,7 @@ public: return *this; } - self operator++(int) - { + self operator++(int) { const self tmp(result_, obj_); obj_.reset(result_->create()); @@ -83,23 +78,19 @@ public: return tmp; } - pointer operator->() - { + pointer operator->() { return obj_.get(); } - reference operator*() - { + reference operator*() { return *obj_; } - pointer get() - { + pointer get() { return obj_.get(); } - pointer release() - { + pointer release() { return obj_.release(); } @@ -111,8 +102,7 @@ private: namespace detail { template < typename Type > -Type* create_prototype(const std::vector &/*prototype*/) -{ +Type* create_prototype(const std::vector &/*prototype*/) { return new Type{}; } @@ -128,11 +118,11 @@ public: using creator_func = std::function; public: - explicit query_result(std::unique_ptr &&impl) - : impl_(std::move(impl)) - , creator_([this] { - return detail::create_prototype(impl_->prototype()); - }) {} + // explicit query_result(std::unique_ptr &&impl) + // : impl_(std::move(impl)) + // , creator_([this] { + // return detail::create_prototype(impl_->prototype()); + // }) {} query_result(std::unique_ptr &&impl, creator_func&& creator) : impl_(std::move(impl)) diff --git a/include/matador/sql/statement.hpp b/include/matador/sql/statement.hpp index ecff489..d32ade9 100644 --- a/include/matador/sql/statement.hpp +++ b/include/matador/sql/statement.hpp @@ -150,7 +150,10 @@ statement &statement::bind(const Type &obj) { template utils::result, utils::error> statement::fetch() { return statement_proxy_->fetch(*bindings_).and_then([](std::unique_ptr &&value) { - return utils::ok(query_result(std::forward(value))); + const auto prototype = value->prototype(); + return utils::ok(query_result(std::forward(value), [prototype] { + return detail::create_prototype(prototype); + })); }); } @@ -160,7 +163,10 @@ utils::result, utils::error> statement::fetch_one() { if (!result.is_ok()) { return utils::failure(result.err()); } - auto records = query_result(result.release()); + const auto prototype = result.value()->prototype(); + auto records = query_result(result.release(), [prototype] { + return detail::create_prototype(prototype); + }); auto first = records.begin(); if (first == records.end()) { return utils::ok(std::unique_ptr{nullptr}); diff --git a/source/orm/orm/session.cpp b/source/orm/orm/session.cpp index 68c25eb..9974e86 100644 --- a/source/orm/orm/session.cpp +++ b/source/orm/orm/session.cpp @@ -108,7 +108,10 @@ utils::result, utils::error> session::fetch_all(c if (!res) { return utils::failure(res.err()); } - return utils::ok(sql::query_result{std::move(*res)}); + const auto prototype = res.value()->prototype(); + return utils::ok(sql::query_result{std::move(*res), [prototype] { + return sql::detail::create_prototype(prototype); + }}); } utils::result session::execute(const std::string &sql) const { diff --git a/source/orm/query/intermediates/fetchable_query.cpp b/source/orm/query/intermediates/fetchable_query.cpp index 452f0a9..bc8a3ee 100644 --- a/source/orm/query/intermediates/fetchable_query.cpp +++ b/source/orm/query/intermediates/fetchable_query.cpp @@ -53,7 +53,10 @@ utils::result, utils::error> fetchable_query::fetch_o return utils::failure(result.err()); } - sql::query_result records(std::move(*result)); + const auto prototype = result.value()->prototype(); + sql::query_result records(std::move(*result), [prototype] { + return detail::create_prototype(prototype); + }); auto first = records.begin(); if (first == records.end()) { return utils::ok(std::optional{std::nullopt}); diff --git a/source/orm/sql/statement.cpp b/source/orm/sql/statement.cpp index 41d716b..dfe8f3f 100644 --- a/source/orm/sql/statement.cpp +++ b/source/orm/sql/statement.cpp @@ -61,7 +61,10 @@ utils::result, utils::error> statement::fetch() const { return utils::failure(result.err()); } // logger_.info(statement_->query_.sql); - return utils::ok(query_result{std::move(*result)}); + const auto prototype = result.value()->prototype(); + return utils::ok(query_result(std::move(*result), [prototype] { + return detail::create_prototype(prototype); + })); } utils::result, utils::error> statement::fetch_one() const { @@ -71,7 +74,10 @@ utils::result, utils::error> statement::fetch_one() const return utils::failure(result.err()); } - query_result records(std::move(*result)); + const auto prototype = result.value()->prototype(); + query_result records(std::move(*result), [prototype] { + return sql::detail::create_prototype(prototype); + }); auto first = records.begin(); if (first == records.end()) { return utils::ok(std::optional{std::nullopt}); diff --git a/test/backends/SessionTest.cpp b/test/backends/SessionTest.cpp index f0621a5..c7f4cb0 100644 --- a/test/backends/SessionTest.cpp +++ b/test/backends/SessionTest.cpp @@ -208,7 +208,7 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with one-to-ma TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with many-to-many eager relation", "[session][find][many-to-many][eager]") { auto result = ses.attach("recipes") .and_then( [this] { return ses.attach("ingredients"); } ) - .and_then( [this] { return ses.attach("recipe_ingredients"); } ) + // .and_then( [this] { return ses.attach("recipe_ingredients"); } ) .and_then( [this] { return ses.create_schema(); } ); tables_to_drop.emplace("recipes"); @@ -217,7 +217,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with many-to-m std::vector> ingredients; ingredients.push_back(std::make_unique(1, "Apple")); - ingredients.push_back(std::make_unique(1, "Apple")); ingredients.push_back(std::make_unique(2, "Strawberry")); ingredients.push_back(std::make_unique(3, "Pineapple")); ingredients.push_back(std::make_unique(4, "Sugar"));