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