From 623a64b6109f0f40b589b7e916f3232ce9afd64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 18 Jan 2026 22:11:51 +0100 Subject: [PATCH] added collection, collection proxy and collection resolver implementations --- .../matador/object/abstract_type_resolver.hpp | 20 +++++ .../object/abstract_type_resolver_factory.hpp | 17 ++++ include/matador/object/collection.hpp | 39 ++++++++- include/matador/object/collection_proxy.hpp | 82 +++++++++++++++++++ .../matador/object/collection_resolver.hpp | 19 +++++ .../object/collection_resolver_factory.hpp | 21 +++++ include/matador/object/object_resolver.hpp | 21 +---- .../object/object_resolver_factory.hpp | 10 +-- include/matador/query/schema.hpp | 2 +- .../sql/internal/query_result_impl.hpp | 1 + .../sql/internal/resolver_producer.hpp | 2 +- .../matador/sql/producer_resolver_factory.hpp | 8 +- source/core/CMakeLists.txt | 5 ++ source/orm/sql/producer_resolver_factory.cpp | 4 +- test/backends/QueryTest.cpp | 7 -- 15 files changed, 214 insertions(+), 44 deletions(-) create mode 100644 include/matador/object/abstract_type_resolver.hpp create mode 100644 include/matador/object/abstract_type_resolver_factory.hpp create mode 100644 include/matador/object/collection_proxy.hpp create mode 100644 include/matador/object/collection_resolver.hpp create mode 100644 include/matador/object/collection_resolver_factory.hpp diff --git a/include/matador/object/abstract_type_resolver.hpp b/include/matador/object/abstract_type_resolver.hpp new file mode 100644 index 0000000..347f90c --- /dev/null +++ b/include/matador/object/abstract_type_resolver.hpp @@ -0,0 +1,20 @@ +#ifndef MATADOR_ABSTRACT_TYPE_RESOLVER_HPP +#define MATADOR_ABSTRACT_TYPE_RESOLVER_HPP + +#include + +namespace matador::object { +class abstract_type_resolver { +public: + virtual ~abstract_type_resolver() = default; + + [[nodiscard]] const std::type_index& type() const { return type_; } + +protected: + explicit abstract_type_resolver(const std::type_index& ti) : type_(ti) {} + +public: + const std::type_index type_; +}; +} +#endif //MATADOR_ABSTRACT_TYPE_RESOLVER_HPP \ No newline at end of file diff --git a/include/matador/object/abstract_type_resolver_factory.hpp b/include/matador/object/abstract_type_resolver_factory.hpp new file mode 100644 index 0000000..cd65a47 --- /dev/null +++ b/include/matador/object/abstract_type_resolver_factory.hpp @@ -0,0 +1,17 @@ +#ifndef MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP +#define MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP + +#include "matador/object/abstract_type_resolver.hpp" + +#include + +namespace matador::object { +class abstract_type_resolver_factory { +public: + virtual ~abstract_type_resolver_factory() = default; + + virtual std::shared_ptr acquire_resolver(const std::type_index &type) = 0; + virtual void register_resolver(std::shared_ptr &&resolver) = 0; +}; +} +#endif //MATADOR_ABSTRACT_TYPE_RESOLVER_FACTORY_HPP \ No newline at end of file diff --git a/include/matador/object/collection.hpp b/include/matador/object/collection.hpp index 22253a0..f42151f 100644 --- a/include/matador/object/collection.hpp +++ b/include/matador/object/collection.hpp @@ -1,7 +1,7 @@ #ifndef COLLECTION_HPP #define COLLECTION_HPP -#include +#include "matador/object/collection_proxy.hpp" namespace matador::object { @@ -9,12 +9,43 @@ template < class Type > class collection { public: using value_type = Type; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; - void push_back(const Type& value) { data_.push_back(value); } + void push_back(const value_type& value) { + proxy_->items().push_back(value); + } + + iterator begin() { + return proxy_->items().begin(); + } + + iterator end() { + return proxy_->items().end(); + } + + const_iterator begin() const { + return proxy_->items().begin(); + } + + const_iterator end() const { + return proxy_->items().end(); + } + + [[nodiscard]] size_t size() const { + return proxy_->items().size(); + } + + [[nodiscard]] bool empty() const { + return proxy_->items_.empty(); + } + + void reset(std::shared_ptr> proxy) { + proxy_ = std::move(proxy); + } - [[nodiscard]] size_t size() const { return data_.size(); } private: - std::vector data_; + std::shared_ptr> proxy_; }; } diff --git a/include/matador/object/collection_proxy.hpp b/include/matador/object/collection_proxy.hpp new file mode 100644 index 0000000..e4b334e --- /dev/null +++ b/include/matador/object/collection_proxy.hpp @@ -0,0 +1,82 @@ +#ifndef MATADOR_COLLECTION_PROXY_HPP +#define MATADOR_COLLECTION_PROXY_HPP + +#include + +#include "matador/object/object_ptr.hpp" + +#include "matador/utils/identifier.hpp" + +#include + +namespace matador::object { + +class abstract_collection_resolver { +public: + virtual ~abstract_collection_resolver() = default; + + [[nodiscard]] const std::type_index& type() const { return type_; } + +protected: + explicit abstract_collection_resolver(const std::type_index& ti) : type_(ti) {} + +public: + const std::type_index type_; +}; + + +template +class collection_resolver : public abstract_collection_resolver { +public: + collection_resolver() : abstract_collection_resolver(typeid(Type)) {} + + virtual std::shared_ptr resolve(const utils::identifier& id) = 0; +}; + +template +class collection_proxy final { +public: + collection_proxy(std::weak_ptr> resolver, utils::identifier owner_id) + : owner_id_(std::move(owner_id)), resolver_(std::move(resolver)) {} + + collection_proxy(std::weak_ptr> resolver, std::vector> items) + : items_(std::move(items)), resolver_(std::move(resolver)) {} + + explicit collection_proxy(std::vector> items) + : items_(std::move(items)) {} + + [[nodiscard]] const utils::identifier& owner_id() const { + return owner_id_; + } + const std::vector>& items() const { + return items_; + } + std::vector>& items() { + return items_; + } +private: + void resolve() const { + if (loaded_) { + return; + } + + std::lock_guard lock(mutex_); + auto resolver = resolver_.lock(); + if (!resolver) { + return; + // Todo: Add states (Detached, Attached, Transient) - if attached an no resolver is available throw runtime exception + // throw std::runtime_error("Detached proxy (session expired)"); + } + + items_ = resolver->resolve(owner_id_); + } + +private: + const utils::identifier owner_id_; + std::atomic_bool loaded_{false}; + std::vector> items_; + std::weak_ptr> resolver_{}; + mutable std::mutex mutex_{}; +}; +} +#endif //MATADOR_COLLECTION_PROXY_HPP \ No newline at end of file diff --git a/include/matador/object/collection_resolver.hpp b/include/matador/object/collection_resolver.hpp new file mode 100644 index 0000000..4c03fdb --- /dev/null +++ b/include/matador/object/collection_resolver.hpp @@ -0,0 +1,19 @@ +#ifndef MATADOR_COLLECTION_RESOLVER_HPP +#define MATADOR_COLLECTION_RESOLVER_HPP + +#include "matador/object/abstract_type_resolver.hpp" +#include "matador/object/object_ptr.hpp" + +#include +#include + +namespace matador::object { +template +class collection_resolver : public abstract_type_resolver { +public: + collection_resolver() : abstract_type_resolver(typeid(std::vector>)) {} + + virtual std::vector> resolve(const utils::identifier& id) = 0; +}; +} +#endif //MATADOR_COLLECTION_RESOLVER_HPP \ No newline at end of file diff --git a/include/matador/object/collection_resolver_factory.hpp b/include/matador/object/collection_resolver_factory.hpp new file mode 100644 index 0000000..e01dca2 --- /dev/null +++ b/include/matador/object/collection_resolver_factory.hpp @@ -0,0 +1,21 @@ +#ifndef MATADOR_CONTAINER_RESOLVER_FACTORY_HPP +#define MATADOR_CONTAINER_RESOLVER_FACTORY_HPP + +#include "matador/object/abstract_type_resolver_factory.hpp" +#include "matador/object/collection_resolver.hpp" + +namespace matador::object { +class collection_resolver_factory : public abstract_type_resolver_factory { +public: + template + std::shared_ptr> resolver() { + const auto res = acquire_resolver(typeid(std::vector>)); + if (!res) { + return std::dynamic_pointer_cast>(res); + } + + return std::dynamic_pointer_cast>(res); + } +}; +} +#endif //MATADOR_CONTAINER_RESOLVER_FACTORY_HPP \ No newline at end of file diff --git a/include/matador/object/object_resolver.hpp b/include/matador/object/object_resolver.hpp index 7ffea49..cbac7ad 100644 --- a/include/matador/object/object_resolver.hpp +++ b/include/matador/object/object_resolver.hpp @@ -1,33 +1,18 @@ #ifndef MATADOR_OBJECT_LOADER_HPP #define MATADOR_OBJECT_LOADER_HPP +#include "matador/object/abstract_type_resolver.hpp" #include -#include namespace matador::utils { class identifier; } namespace matador::object { - -class abstract_object_resolver { -public: - virtual ~abstract_object_resolver() = default; - - [[nodiscard]] const std::type_index& type() const { return type_; } - -protected: - explicit abstract_object_resolver(const std::type_index& ti) : type_(ti) {} - -public: - const std::type_index type_; -}; - - template -class object_resolver : public abstract_object_resolver { +class object_resolver : public abstract_type_resolver { public: - object_resolver() : abstract_object_resolver(typeid(Type)) {} + object_resolver() : abstract_type_resolver(typeid(Type)) {} virtual std::shared_ptr resolve(const utils::identifier& id) = 0; }; diff --git a/include/matador/object/object_resolver_factory.hpp b/include/matador/object/object_resolver_factory.hpp index ac8390d..a1c060b 100644 --- a/include/matador/object/object_resolver_factory.hpp +++ b/include/matador/object/object_resolver_factory.hpp @@ -1,15 +1,12 @@ #ifndef MATADOR_OBJECT_RESOLVER_FACTORY_HPP #define MATADOR_OBJECT_RESOLVER_FACTORY_HPP +#include "matador/object/abstract_type_resolver_factory.hpp" #include "matador/object/object_resolver.hpp" -#include - namespace matador::object { -class object_resolver_factory { +class object_resolver_factory : public abstract_type_resolver_factory { public: - virtual ~object_resolver_factory() = default; - template std::shared_ptr> resolver() { const auto res = acquire_resolver(std::type_index(typeid(Type))); @@ -19,9 +16,6 @@ public: return std::dynamic_pointer_cast>(res); } - - virtual std::shared_ptr acquire_resolver(const std::type_index &type) = 0; - virtual void register_resolver(std::shared_ptr &&resolver) = 0; }; } #endif //MATADOR_OBJECT_RESOLVER_FACTORY_HPP \ No newline at end of file diff --git a/include/matador/query/schema.hpp b/include/matador/query/schema.hpp index dd83356..889bfc5 100644 --- a/include/matador/query/schema.hpp +++ b/include/matador/query/schema.hpp @@ -27,7 +27,7 @@ public: , table_(tab) , pk_name_(std::move(pk_name)) {} - std::shared_ptr produce(sql::executor &exec) override { + std::shared_ptr produce(sql::executor &exec) override { return std::make_shared>(repo_, exec, table_, std::move(pk_name_)); } diff --git a/include/matador/sql/internal/query_result_impl.hpp b/include/matador/sql/internal/query_result_impl.hpp index 9a4d2de..5c98d35 100644 --- a/include/matador/sql/internal/query_result_impl.hpp +++ b/include/matador/sql/internal/query_result_impl.hpp @@ -129,6 +129,7 @@ public: auto resolver = resolver_factory_->resolver(); if (attr.fetch() == utils::fetch_type::Lazy) { + // pk_reader_.read(*id, column_index_++); } else { const auto ti = std::type_index(typeid(value_type)); diff --git a/include/matador/sql/internal/resolver_producer.hpp b/include/matador/sql/internal/resolver_producer.hpp index 477ed9f..11bdbca 100644 --- a/include/matador/sql/internal/resolver_producer.hpp +++ b/include/matador/sql/internal/resolver_producer.hpp @@ -10,7 +10,7 @@ class executor; class resolver_producer { public: virtual ~resolver_producer() = default; - virtual std::shared_ptr produce(executor &exec) = 0; + virtual std::shared_ptr produce(executor &exec) = 0; [[nodiscard]] const std::type_index& type() const; diff --git a/include/matador/sql/producer_resolver_factory.hpp b/include/matador/sql/producer_resolver_factory.hpp index a7856c0..a3de911 100644 --- a/include/matador/sql/producer_resolver_factory.hpp +++ b/include/matador/sql/producer_resolver_factory.hpp @@ -5,17 +5,19 @@ #include "matador/sql/internal/resolver_producer.hpp" +#include + namespace matador::sql { class executor; class producer_resolver_factory : public object::object_resolver_factory { public: - std::shared_ptr acquire_resolver(const std::type_index &type) override; - void register_resolver(std::shared_ptr &&resolver) override; + std::shared_ptr acquire_resolver(const std::type_index &type) override; + void register_resolver(std::shared_ptr &&resolver) override; private: - std::unordered_map> resolvers_; + std::unordered_map> resolvers_; }; } #endif //MATADOR_RESOLVER_FACTORY_HPP \ No newline at end of file diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index 355359b..750b5f9 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -113,6 +113,11 @@ add_library(matador-core STATIC utils/uuid.cpp utils/value.cpp utils/version.cpp + ../../include/matador/object/collection_proxy.hpp + ../../include/matador/object/collection_resolver_factory.hpp + ../../include/matador/object/collection_resolver.hpp + ../../include/matador/object/abstract_type_resolver.hpp + ../../include/matador/object/abstract_type_resolver_factory.hpp ) target_link_libraries(matador-core ${CMAKE_DL_LIBS}) diff --git a/source/orm/sql/producer_resolver_factory.cpp b/source/orm/sql/producer_resolver_factory.cpp index a1fd68c..22202b1 100644 --- a/source/orm/sql/producer_resolver_factory.cpp +++ b/source/orm/sql/producer_resolver_factory.cpp @@ -1,14 +1,14 @@ #include "matador/sql/producer_resolver_factory.hpp" namespace matador::sql { -std::shared_ptr producer_resolver_factory::acquire_resolver(const std::type_index &type) { +std::shared_ptr producer_resolver_factory::acquire_resolver(const std::type_index &type) { if (const auto it = resolvers_.find(type); it != resolvers_.end()) { return it->second; } return nullptr; } -void producer_resolver_factory::register_resolver(std::shared_ptr &&resolver) { +void producer_resolver_factory::register_resolver(std::shared_ptr &&resolver) { resolvers_[resolver->type()] = std::move(resolver); } } diff --git a/test/backends/QueryTest.cpp b/test/backends/QueryTest.cpp index 4057c79..687ec82 100644 --- a/test/backends/QueryTest.cpp +++ b/test/backends/QueryTest.cpp @@ -636,13 +636,6 @@ TEST_CASE_METHOD(QueryFixture, "Test load entity with lazy belongs to relation", REQUIRE(count.is_ok()); REQUIRE(*count == 5); - // auto emps_result = query::select({EMPLOYEE.id, EMPLOYEE.first_name, EMPLOYEE.last_name, DEPARTMENT.id, DEPARTMENT.name}) - // .from(EMPLOYEE) - // .join_left(DEPARTMENT) - // .on(EMPLOYEE.dep_id == DEPARTMENT.id) - // .order_by(EMPLOYEE.id).asc() - // .fetch_all(db); - auto emps_result = query::select({EMPLOYEE.id, EMPLOYEE.first_name, EMPLOYEE.last_name, EMPLOYEE.dep_id}) .from(EMPLOYEE) .order_by(EMPLOYEE.id).asc()