#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 #include namespace matador::object { enum class object_state : uint8_t { Transient, Persistent, Detached, Removed }; 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) , state_(object_state::Persistent){ } // Transient explicit object_proxy(std::shared_ptr obj) : obj_(obj) , pk_(primary_key_resolver::resolve_object(*obj).pk) { } void attach(std::shared_ptr obj) { std::lock_guard lock(mutex_); obj_ = std::move(obj); if (obj_) { pk_ = primary_key_resolver::resolve_object(*obj_).pk; state_.store(object_state::Persistent, std::memory_order_release); } } void invalidate() { std::lock_guard lock(mutex_); obj_.reset(); resolver_.reset(); state_.store(object_state::Detached, std::memory_order_release); } [[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 !obj_ && resolver_.expired(); } [[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; } bool is_persistent() const { return state_ == object_state::Persistent; } bool is_transient() const { return state_ == object_state::Transient; } bool is_detached() const { return state_ == object_state::Detached; } bool is_removed() const { return state_ == object_state::Removed; } void change_state(const object_state state) { state_.store(state, std::memory_order_release); } 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_{}; std::atomic state_{object_state::Transient}; mutable std::mutex mutex_{}; }; } #endif //OBJECT_PROXY_HPP