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