#ifndef OBJECT_PROXY_HPP #define OBJECT_PROXY_HPP #include "matador/object/primary_key_resolver.hpp" #include "matador/object/object_resolver.hpp" #include #include #include #include namespace matador::object { template class object_proxy final { public: object_proxy() = default; // Lazy object_proxy(std::weak_ptr> resolver, utils::identifier id) : resolver_(resolver) , pk_(std::move(id)) { } // Eager object_proxy(std::weak_ptr> resolver, std::shared_ptr obj) : obj_(obj) , resolver_(resolver) , pk_(primary_key_resolver::resolve_object(*obj).pk) { } // Transient explicit object_proxy(std::shared_ptr obj) : obj_(obj) , pk_(primary_key_resolver::resolve_object(*obj).pk) { } [[nodiscard]] void *raw_pointer() const { return static_cast(pointer()); } Type *operator->() { return pointer(); } Type &operator*() { return *pointer(); } const Type &operator*() const { return *pointer(); } Type *pointer() const { return resolve(); } [[nodiscard]] bool empty() const { return resolver_ == nullptr; } [[nodiscard]] bool valid() const { return !empty(); } [[nodiscard]] bool has_primary_key() const { return !pk_.is_null(); } [[nodiscard]] const utils::identifier &primary_key() const { return pk_; } void primary_key(const utils::identifier &pk) { pk_ = pk; } private: Type* resolve() const { if (obj_) { return obj_.get(); } std::lock_guard lock(mutex_); auto resolver = resolver_.lock(); if (!resolver) { return nullptr; // Todo: Add states (Detached, Attached, Transient) - if attached an no resolver is available throw runtime exception // throw std::runtime_error("Detached proxy (session expired)"); } const_cast&>(obj_) = resolver->resolve(pk_); return obj_.get(); } private: std::shared_ptr obj_{}; std::weak_ptr> resolver_{}; utils::identifier pk_{}; mutable std::mutex mutex_{}; }; } #endif //OBJECT_PROXY_HPP