#ifndef QUERY_QUERY_RESULT_HPP #define QUERY_QUERY_RESULT_HPP #include "matador/object/attribute.hpp" #include "matador/object/object_ptr.hpp" #include "matador/sql/internal/query_result_impl.hpp" #include #include #include "matador/object/object.hpp" namespace matador::sql { class record; class query_result_impl; template < typename Type > class query_result; template < typename Type > class query_result_iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = Type; using difference_type = std::ptrdiff_t; using self = query_result_iterator; /**< Shortcut for this class. */ using pointer = value_type*; /**< Shortcut for the pointer type. */ using reference = value_type&; /**< Shortcut for the reference type */ public: query_result_iterator() = default; explicit query_result_iterator(query_result *res) : result_(res) {} query_result_iterator(query_result *res, object::object_ptr obj) : obj_(std::move(obj)) , result_(res) {} query_result_iterator(query_result_iterator&& x) noexcept : obj_(std::move(x.obj_)) , result_(x.result_) {} query_result_iterator& operator=(query_result_iterator&& x) noexcept { result_ = x.result_; obj_ = std::move(x.obj_); return *this; } ~query_result_iterator() = default; bool operator==(const query_result_iterator& rhs) const { return obj_ == rhs.obj_; } bool operator!=(const query_result_iterator& rhs) const { return !operator==(rhs); } self& operator++() { auto obj = result_->create(); result_->bind(*obj); obj_.reset(); if (result_->fetch(*obj)) { obj_ = object::object_ptr(std::make_shared>(result_->resolver_, std::move(obj))); } return *this; } self operator++(int) { const self tmp(result_, obj_); auto obj = result_->create(); result_->bind(*obj); obj_.reset(); if (result_->fetch(*obj)) { obj_ = object::object_ptr(std::make_shared>(result_->resolver_, std::move(obj))); } return tmp; } pointer operator->() { return obj_.get(); } object::object_ptr operator*() { return obj_; } object::object_ptr optr() { return obj_; } private: object::object_ptr obj_; query_result *result_{nullptr}; }; namespace detail { template < typename Type > std::shared_ptr create_prototype(const std::vector &/*prototype*/) { return std::make_shared(); } record create_prototype(const std::vector &prototype); } template class query_result final { public: using iterator = query_result_iterator; using creator_func = std::function()>; query_result(std::unique_ptr &&impl, const std::shared_ptr> &resolver, creator_func&& creator) : impl_(std::move(impl)) , resolver_(resolver) , creator_(std::move(creator)) {} iterator begin() { return std::move(++iterator(this)); } iterator end() { return {}; } private: friend class query_result_iterator; std::shared_ptr create(); void bind(const Type& obj); bool fetch(Type& obj); protected: std::unique_ptr impl_; std::shared_ptr> resolver_; creator_func creator_; }; template std::shared_ptr query_result::create() { return creator_(); } template void query_result::bind(const Type &obj) { impl_->bind(obj); } template bool query_result::fetch(Type &obj) { return impl_->fetch(obj); } template <> class query_result; template <> class query_result_iterator { public: using iterator_category = std::forward_iterator_tag; using value_type = record; using difference_type = std::ptrdiff_t; using self = query_result_iterator; /**< Shortcut for this class. */ using pointer = value_type*; /**< Shortcut for the pointer type. */ using reference = value_type&; /**< Shortcut for the reference type */ public: query_result_iterator() = default; explicit query_result_iterator(query_result *res) : result_(res) {} query_result_iterator(query_result *res, record rec) : record_(std::move(rec)) , result_(res) {} query_result_iterator(query_result_iterator&& x) noexcept : record_(std::move(x.record_)) , result_(x.result_) {} query_result_iterator& operator=(query_result_iterator&& x) noexcept { result_ = x.result_; record_ = std::move(x.record_); return *this; } ~query_result_iterator() = default; bool operator==(const query_result_iterator& rhs) const { return record_ == rhs.record_; } bool operator!=(const query_result_iterator& rhs) const { return !(*this == rhs); } self& operator++(); self operator++(int); pointer operator->() { return &record_; } reference operator*() { return record_; } record release() { return std::move(record_); } private: record record_; query_result *result_{nullptr}; }; template<> class query_result final { public: using iterator = query_result_iterator; query_result(std::unique_ptr &&impl, const std::vector &prototype) : impl_(std::move(impl)) , prototype_(prototype) {} iterator begin() { return std::move(++iterator(this)); } iterator end() { return {}; } private: friend class query_result_iterator; [[nodiscard]] record create() const; void bind(const record& obj) const; bool fetch(record& obj) const; protected: std::unique_ptr impl_; std::vector prototype_; }; inline record query_result::create() const { record rec; int index{0}; for (const auto &col: prototype_) { rec.append({ col.name(), col.type(), col.attributes().options(), col.attributes().size(), index++ }); } return rec; } inline void query_result::bind(const record &obj) const { impl_->bind(obj); } inline bool query_result::fetch(record &obj) const { return impl_->fetch(obj); } inline query_result_iterator::self & query_result_iterator::operator++() { record_ = result_->create(); result_->bind(record_); if (!result_->fetch(record_)) { record_.clear(); } return *this; } inline query_result_iterator::self query_result_iterator::operator++(int) { self tmp(result_, record_); record_ = result_->create(); result_->bind(record_); if (!result_->fetch(record_)) { record_.clear(); } return tmp; } } // namespace matador::sql #endif //QUERY_QUERY_RESULT_HPP