#pragma once #include "read_context.h" #include "data_context.inl" #include "../helper/nullable_helper.inl" #include "../helper/container_helper.inl" namespace cpphibernate { namespace mariadb { read_context::read_context( const schema_t& p_schema, ::cppmariadb::connection& p_connection, const filter_t& p_filter, size_t p_real_dataset_id) : data_context (p_schema, p_connection) , filter (p_filter) , real_dataset_id (p_real_dataset_id) , is_dynamic (false) { } template T_dataset& read_context::emplace(const table_t * table) const { using dataset_type = mp::decay_t; /* check table */ auto dataset_id = get_type_id(hana::type_c); if (!table) table = &schema.table(dataset_id); else if (table->dataset_id != dataset_id) throw exception("wrong table passed!"); /* check base */ auto tbl = table; while (tbl && tbl->dataset_id != real_dataset_id) tbl = tbl->base_table; if (!tbl) { throw exception(cppcore::type_helper::name() + " is not a derived type of dataset with id " + std::to_string(real_dataset_id)); } /* create dataset */ auto ptr = std::make_unique(); auto data = emplace_intern(ptr.get(), dataset_id); if (!data) throw exception("unable to store created dataset in context!"); ptr.release(); return *static_cast(data); } void read_context::emplace() const { emplace_intern(nullptr, 0); } void read_context::finish() const { finish_intern(); } namespace __impl { /* read_context_builder */ template struct read_context_builder { template static constexpr decltype(auto) apply(T_args&&... args) { static_assert(sizeof...(args) == -1, "Invalid parameters for make_read_context(...)!"); } }; /* read_context_builder - fake */ template< typename T_schema, typename T_connection, typename T_dataset, typename T_filter> struct read_context_builder< mp::list, mp::enable_if_t< mp::is_same_v>> >> { using dataset_type = typename mp::decay_t::type; struct context_impl : public read_context { public: inline context_impl( const schema_t& p_schema, ::cppmariadb::connection& p_connection, T_dataset& p_dataset, const filter_t& p_filter) : read_context (p_schema, p_connection, p_filter, get_type_id(hana::type_c>>)) { } private: void * emplace_intern(void* data, size_t dataset_id) const override { return nullptr; } void finish_intern() const override { clear(); } }; template static constexpr decltype(auto) apply(X_args&&... args) { return context_impl(std::forward(args)...); } }; /* read_context_builder - normal types */ template< typename T_schema, typename T_connection, typename T_dataset, typename T_filter> struct read_context_builder< mp::list, mp::enable_if_t< !is_container_v> && !is_nullable_v> && !mp::is_same_v>> >> { using dataset_type = mp::decay_t; struct context_impl : public read_context { private: mutable size_t _count; dataset_type& _dataset; public: inline context_impl( const schema_t& p_schema, ::cppmariadb::connection& p_connection, T_dataset& p_dataset, const filter_t& p_filter) : read_context (p_schema, p_connection, p_filter, get_type_id(hana::type_c>>)) , _count (0) , _dataset (p_dataset) { } private: void * emplace_intern(void* data, size_t dataset_id) const override { if (data || dataset_id != 0) throw exception("Static datasets can not be assigned!"); ++_count; if (_count > 1) throw exception("Expected exactly one dataset, but received more!"); return set(_dataset); } void finish_intern() const override { if (_count < 1) throw exception("Expected exactly one dataset, but received none!"); clear(); } }; template static constexpr decltype(auto) apply(X_args&&... args) { return context_impl(std::forward(args)...); } }; /* read_context_builder - nullable */ template< typename T_schema, typename T_connection, typename T_dataset, typename T_filter> struct read_context_builder< mp::list, mp::enable_if_t< !is_container_v> && is_nullable_v> >> { using dataset_type = mp::decay_t; using nullable_helper_type = nullable_helper; using value_type = typename nullable_helper_type::value_type; struct context_impl : public read_context { private: dataset_type& _dataset; mutable size_t _count; public: inline context_impl( const schema_t& p_schema, ::cppmariadb::connection& p_connection, T_dataset& p_dataset, const filter_t& p_filter) : read_context (p_schema, p_connection, p_filter, get_type_id(hana::type_c>>)) , _count (0) , _dataset (p_dataset) { is_dynamic = is_pointer_v; nullable_helper_type::clear(_dataset); } private: void * emplace_intern(void * data, size_t dataset_id) const override { if (data && !is_pointer_v) throw exception("None pointer type can not be assigned!"); ++_count; if (_count > 1) throw exception("Expected exactly one dataset, but received more!"); if (data) { auto* cast = static_cast(data); auto& value = nullable_helper_type::set(_dataset, cast); if (cast != &value) throw exception("Nullable pointer value has changed!"); return set(value, dataset_id); } else { auto& value = nullable_helper_type::set(_dataset, value_type { }); return set(value); } } void finish_intern() const override { clear(); } }; template static constexpr decltype(auto) apply(X_args&&... args) { return context_impl(std::forward(args)...); } }; /* container_emplace_helper */ template struct container_emplace_helper; template struct container_emplace_helper< T_dataset, mp::enable_if_t< mp::is_valid_v::value_type> && !is_pointer_v::value_type> >> { static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id) { using container_helper_type = container_helper; using value_type = typename container_helper_type::value_type; if (data || data_id != 0) throw exception("Static datasets can not be assigned!"); auto& value = container_helper_type::emplace(dataset); data_id = get_type_id(hana::type_c); return value; } }; template struct container_emplace_helper< T_dataset, mp::enable_if_t< mp::is_valid_v::value_type> && is_pointer_v::value_type> >> { static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id) { using container_helper_type = container_helper; using nullable_type = typename container_helper_type::value_type; using nullable_helper_type = nullable_helper; using inner_value_type = typename nullable_helper_type::value_type; if (!data) throw exception("Expected dynamic data for pointer type!"); if (data_id == 0) throw exception("Expected dataset id for pointer type!"); if (!is_pointer_v) throw exception("None pointer type can not be assigned!"); auto& nullable = container_helper_type::emplace(dataset); auto* cast = static_cast(data); auto& value = nullable_helper_type::set(nullable, cast); if (cast != &value) throw exception("Nullable pointer value has changed!"); return value; } }; /* read_context_builder - container */ template< typename T_schema, typename T_connection, typename T_dataset, typename T_filter> struct read_context_builder< mp::list, mp::enable_if_t< is_container_v> && !is_nullable_v> >> { using dataset_type = mp::decay_t; using real_dataset_type = real_dataset_t; using container_helper_type = container_helper; using value_type = typename container_helper_type::value_type; using emplace_helper_type = container_emplace_helper; struct context_impl : public read_context { private: dataset_type& _dataset; public: inline context_impl( const schema_t& p_schema, ::cppmariadb::connection& p_connection, T_dataset& p_dataset, const filter_t& p_filter) : read_context (p_schema, p_connection, p_filter, get_type_id(hana::type_c>>)) , _dataset (p_dataset) { is_dynamic = is_pointer_v; container_helper_type::clear(_dataset); } private: void * emplace_intern(void * data, size_t dataset_id) const override { auto& value = emplace_helper_type::emplace(_dataset, data, dataset_id); return set(value, dataset_id); } void finish_intern() const override { clear(); } }; template static constexpr decltype(auto) apply(X_args&&... args) { return context_impl(std::forward(args)...); } }; } } }