9#include <boost/pfr/core.hpp>
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>
16USERVER_NAMESPACE_BEGIN
22template <
typename MappedType>
23class ColumnsMapper
final {
25 explicit ColumnsMapper(
clickhouse::impl::BlockWrapper& block)
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>);
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));
42template <
typename Row>
43class RowsMapper
final {
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_);
50 ~RowsMapper() =
default;
52 using IteratorsTupleT = clickhouse::impl::IteratorsTupleT<MappedType>;
54 class Iterator
final {
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*;
63 Iterator(IteratorsTupleT iterators);
65 Iterator operator++(
int);
66 Iterator& operator++();
67 reference operator*()
const;
68 pointer operator->()
const;
70 bool operator==(
const Iterator& other)
const;
71 bool operator!=(
const Iterator& other)
const;
73 friend class IteratorsTester;
76 Row& UpdateValue()
const;
78 class FieldMapper
final {
80 FieldMapper(
const IteratorsTupleT& iterators) : iterators_{iterators} {}
82 template <
typename Field, size_t Index>
85 [[maybe_unused]] std::integral_constant<size_t, Index> i)
const {
86 if constexpr (kCanMoveFromIterators) {
87 field = std::move(*std::get<Index>(iterators_));
89 field = *std::get<Index>(iterators_);
94 const IteratorsTupleT& iterators_;
97 IteratorsTupleT iterators_;
98 mutable std::optional<Row> current_value_ = std::nullopt;
101 Iterator begin()
const {
return Iterator{begin_iterators_}; }
102 Iterator end()
const {
return Iterator{end_iterators_}; }
104 friend class IteratorsTester;
107 template <
typename TypesTuple>
108 struct IteratorValuesAreNoexceptMovable;
110 template <
typename... Ts>
111 struct IteratorValuesAreNoexceptMovable<std::tuple<Ts...>>
112 : std::conjunction<std::is_nothrow_move_constructible<
113 typename Ts::iterator::value_type>...> {};
115 static constexpr auto kCanMoveFromIterators =
116 IteratorValuesAreNoexceptMovable<MappedType>::value;
118 using IteratorsHelperT = clickhouse::impl::IteratorsHelper<MappedType>;
121 IteratorsTupleT begin_iterators_{};
122 IteratorsTupleT end_iterators_{};
125template <
typename Row>
126RowsMapper<Row>::Iterator::Iterator(IteratorsTupleT iterators)
127 : iterators_{std::move(iterators)} {}
129template <
typename Row>
130typename RowsMapper<Row>::Iterator RowsMapper<Row>::Iterator::operator++(
int) {
132 old.iterators_ = IteratorsHelperT::PostfixIncrement(iterators_);
133 old.current_value_ = std::move_if_noexcept(current_value_);
134 current_value_.reset();
139template <
typename Row>
140typename RowsMapper<Row>::Iterator& RowsMapper<Row>::Iterator::operator++() {
141 IteratorsHelperT::PrefixIncrement(iterators_);
142 current_value_.reset();
147template <
typename Row>
148typename RowsMapper<Row>::Iterator::reference
149RowsMapper<Row>::Iterator::operator*()
const {
150 return UpdateValue();
153template <
typename Row>
154typename RowsMapper<Row>::Iterator::pointer
155RowsMapper<Row>::Iterator::operator->()
const {
156 return &UpdateValue();
159template <
typename Row>
160Row& RowsMapper<Row>::Iterator::UpdateValue()
const {
161 if (!current_value_.has_value()) {
163 boost::pfr::for_each_field(result, FieldMapper{iterators_});
164 current_value_.emplace(std::move(result));
167 return *current_value_;
170template <
typename Row>
171bool RowsMapper<Row>::Iterator::operator==(
const Iterator& other)
const {
172 return iterators_ == other.iterators_;
175template <
typename Row>
176bool RowsMapper<Row>::Iterator::operator!=(
const Iterator& other)
const {
177 return !((*
this) == other);