userver: userver/storages/clickhouse/io/result_mapper.hpp Source File
Loading...
Searching...
No Matches
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