userver: userver/storages/clickhouse/io/result_mapper.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
result_mapper.hpp
1#pragma once
2
3#include <iterator>
4#include <memory>
5#include <optional>
6#include <type_traits>
7#include <utility>
8
9#include <boost/pfr/core.hpp>
10
11#include <userver/storages/clickhouse/impl/block_wrapper_fwd.hpp>
12#include <userver/storages/clickhouse/impl/iterators_helper.hpp>
13#include <userver/storages/clickhouse/io/columns/column_wrapper.hpp>
14#include <userver/storages/clickhouse/io/io_fwd.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::clickhouse::io {
19
20class IteratorsTester;
21
22template <typename MappedType>
23class ColumnsMapper final {
24 public:
25 explicit ColumnsMapper(clickhouse::impl::BlockWrapper& block)
26 : block_{block} {}
27
28 template <typename Field, size_t Index>
29 void operator()(Field& field, std::integral_constant<size_t, Index> i) {
30 using ColumnType = std::tuple_element_t<Index, MappedType>;
31 static_assert(std::is_same_v<Field, typename ColumnType::container_type>);
32
33 auto column = ColumnType{io::columns::GetWrappedColumn(block_, i)};
34 field.reserve(column.Size());
35 for (auto& it : column) field.push_back(std::move(it));
36 }
37
38 private:
39 clickhouse::impl::BlockWrapper& block_;
40};
41
42template <typename Row>
43class RowsMapper final {
44 public:
45 using MappedType = typename CppToClickhouse<Row>::mapped_type;
46 explicit RowsMapper(clickhouse::impl::BlockWrapperPtr&& block)
47 : block_{block.release()} {
48 IteratorsHelperT::Init(begin_iterators_, end_iterators_, *block_);
49 }
50 ~RowsMapper() = default;
51
52 using IteratorsTupleT = clickhouse::impl::IteratorsTupleT<MappedType>;
53
54 class Iterator final {
55 public:
56 using iterator_category = std::forward_iterator_tag;
57 using difference_type = std::ptrdiff_t;
58 using value_type = Row;
59 using reference = value_type&;
60 using pointer = value_type*;
61
62 Iterator() = default;
63 Iterator(IteratorsTupleT iterators);
64
65 Iterator operator++(int);
66 Iterator& operator++();
67 reference operator*() const;
68 pointer operator->() const;
69
70 bool operator==(const Iterator& other) const;
71 bool operator!=(const Iterator& other) const;
72
73 friend class IteratorsTester;
74
75 private:
76 Row& UpdateValue() const;
77
78 class FieldMapper final {
79 public:
80 FieldMapper(const IteratorsTupleT& iterators) : iterators_{iterators} {}
81
82 template <typename Field, size_t Index>
83 void operator()(
84 Field& field,
85 [[maybe_unused]] std::integral_constant<size_t, Index> i) const {
86 if constexpr (kCanMoveFromIterators) {
87 field = std::move(*std::get<Index>(iterators_));
88 } else {
89 field = *std::get<Index>(iterators_);
90 }
91 }
92
93 private:
94 const IteratorsTupleT& iterators_;
95 };
96
97 IteratorsTupleT iterators_;
98 mutable std::optional<Row> current_value_ = std::nullopt;
99 };
100
101 Iterator begin() const { return Iterator{begin_iterators_}; }
102 Iterator end() const { return Iterator{end_iterators_}; }
103
104 friend class IteratorsTester;
105
106 private:
107 template <typename TypesTuple>
108 struct IteratorValuesAreNoexceptMovable;
109
110 template <typename... Ts>
111 struct IteratorValuesAreNoexceptMovable<std::tuple<Ts...>>
112 : std::conjunction<std::is_nothrow_move_constructible<
113 typename Ts::iterator::value_type>...> {};
114
115 static constexpr auto kCanMoveFromIterators =
116 IteratorValuesAreNoexceptMovable<MappedType>::value;
117
118 using IteratorsHelperT = clickhouse::impl::IteratorsHelper<MappedType>;
119
120 clickhouse::impl::BlockWrapperPtr block_;
121 IteratorsTupleT begin_iterators_{};
122 IteratorsTupleT end_iterators_{};
123};
124
125template <typename Row>
126RowsMapper<Row>::Iterator::Iterator(IteratorsTupleT iterators)
127 : iterators_{std::move(iterators)} {}
128
129template <typename Row>
130typename RowsMapper<Row>::Iterator RowsMapper<Row>::Iterator::operator++(int) {
131 Iterator old{};
132 old.iterators_ = IteratorsHelperT::PostfixIncrement(iterators_);
133 old.current_value_ = std::move_if_noexcept(current_value_);
134 current_value_.reset();
135
136 return old;
137}
138
139template <typename Row>
140typename RowsMapper<Row>::Iterator& RowsMapper<Row>::Iterator::operator++() {
141 IteratorsHelperT::PrefixIncrement(iterators_);
142 current_value_.reset();
143
144 return *this;
145}
146
147template <typename Row>
148typename RowsMapper<Row>::Iterator::reference
149RowsMapper<Row>::Iterator::operator*() const {
150 return UpdateValue();
151}
152
153template <typename Row>
154typename RowsMapper<Row>::Iterator::pointer
155RowsMapper<Row>::Iterator::operator->() const {
156 return &UpdateValue();
157}
158
159template <typename Row>
160Row& RowsMapper<Row>::Iterator::UpdateValue() const {
161 if (!current_value_.has_value()) {
162 Row result{};
163 boost::pfr::for_each_field(result, FieldMapper{iterators_});
164 current_value_.emplace(std::move(result));
165 }
166
167 return *current_value_;
168}
169
170template <typename Row>
171bool RowsMapper<Row>::Iterator::operator==(const Iterator& other) const {
172 return iterators_ == other.iterators_;
173}
174
175template <typename Row>
176bool RowsMapper<Row>::Iterator::operator!=(const Iterator& other) const {
177 return !((*this) == other);
178}
179
180} // namespace storages::clickhouse::io
181
182USERVER_NAMESPACE_END