#ifndef MATADOR_COLLECTION_PROXY_HPP #define MATADOR_COLLECTION_PROXY_HPP #include "matador/object/collection_resolver.hpp" #include "matador/object/many_to_many_relation.hpp" #include "matador/utils/identifier.hpp" #include #include #include namespace matador::object { // has many primitive // relation // has many ptr // relation // has many to many // relation template < class RelationType > struct relation_iterator_traits; template < typename Type, typename OwnerType > struct relation_iterator_traits> { }; template class collection_proxy_iterator { public: using value_type = Type; using reference = Type&; using pointer = Type*; using iterator_category = std::forward_iterator_tag; collection_proxy_iterator() = default; explicit collection_proxy_iterator(typename std::vector::iterator it) : it_(it) {} reference operator*() { return *it_; } pointer operator->() { return &*it_; } collection_proxy_iterator& operator++() { ++it_; return *this; } bool operator==(const collection_proxy_iterator& other) const { return it_ == other.it_; } bool operator!=(const collection_proxy_iterator& other) const { return !operator==(other); } private: typename std::vector::iterator it_; }; template class abstract_collection_proxy { public: using value_type = Type; using relation_type = RelationType; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; virtual ~abstract_collection_proxy() = default; virtual void push_back(const value_type& value) = 0; virtual iterator begin() = 0; virtual iterator end() = 0; virtual const_iterator begin() const = 0; virtual const_iterator end() const = 0; [[nodiscard]] virtual size_t size() const = 0; [[nodiscard]] virtual bool empty() const = 0; // virtual collection_proxy_iterator begin() = 0; // virtual collection_proxy_iterator end() = 0; [[nodiscard]] virtual const utils::identifier& owner_id() const = 0; protected: std::vector items_; }; template class collection_proxy : public abstract_collection_proxy { public: using value_type = Type; using iterator = typename abstract_collection_proxy::iterator; using const_iterator = typename abstract_collection_proxy::const_iterator; collection_proxy() = default; // Lazy collection_proxy(std::weak_ptr> resolver, utils::identifier owner_id) : owner_id_(std::move(owner_id)), resolver_(std::move(resolver)) {} // Eager collection_proxy(std::weak_ptr> resolver, std::vector items) : loaded_{true}, items_(std::move(items)), resolver_(std::move(resolver)) {} // Transient explicit collection_proxy(std::vector items) : items_(std::move(items)) {} [[nodiscard]] const utils::identifier& owner_id() const override { return owner_id_; } iterator begin() override { resolve(); return items_.begin(); } iterator end() override { resolve(); return items_.end(); } const_iterator begin() const override { resolve(); return items_.begin(); } const_iterator end() const override { resolve(); return items_.end(); } // const std::vector& items() const { // resolve(); // return items_; // } // std::vector& items() { // resolve(); // return items_; // } private: void resolve() { 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_); loaded_ = true; } private: const utils::identifier owner_id_; std::atomic_bool loaded_{false}; std::vector items_; std::weak_ptr> resolver_{}; mutable std::mutex mutex_{}; }; template class collection_many_to_many_proxy { public: using value_type = Type; using owner_type = OwnerType; using relation_type = many_to_many_relation; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; private: std::vector relations_; }; } #endif //MATADOR_COLLECTION_PROXY_HPP