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)
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>);
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));
45template <
typename Row>
46class RowsMapper
final {
48 using MappedType =
typename CppToClickhouse<Row>::mapped_type;
49 explicit RowsMapper(
clickhouse::impl::BlockWrapperPtr&& block)
50 : block_{block.release()}
52 IteratorsHelperT::Init(begin_iterators_, end_iterators_, *block_);
54 ~RowsMapper() =
default;
56 using IteratorsTupleT =
clickhouse::impl::IteratorsTupleT<MappedType>;
58 class Iterator
final {
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*;
67 Iterator(IteratorsTupleT iterators);
69 Iterator operator++(
int);
70 Iterator& operator++();
71 reference operator*()
const;
72 pointer operator->()
const;
74 bool operator==(
const Iterator& other)
const;
75 bool operator!=(
const Iterator& other)
const;
77 friend class IteratorsTester;
80 Row& UpdateValue()
const;
82 class FieldMapper
final {
84 FieldMapper(
const IteratorsTupleT& iterators)
85 : iterators_{iterators}
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_));
93 field = *std::get<Index>(iterators_);
98 const IteratorsTupleT& iterators_;
101 IteratorsTupleT iterators_;
102 mutable std::optional<Row> current_value_ = std::nullopt;
105 Iterator begin()
const {
return Iterator{begin_iterators_}; }
106 Iterator end()
const {
return Iterator{end_iterators_}; }
108 friend class IteratorsTester;
111 template <
typename TypesTuple>
112 struct IteratorValuesAreNoexceptMovable;
114 template <
typename... Ts>
115 struct IteratorValuesAreNoexceptMovable<std::tuple<Ts...>>
116 : std::conjunction<std::is_nothrow_move_constructible<
typename Ts::iterator::value_type>...> {};
118 static constexpr auto kCanMoveFromIterators = IteratorValuesAreNoexceptMovable<MappedType>::value;
120 using IteratorsHelperT =
clickhouse::impl::IteratorsHelper<MappedType>;
123 IteratorsTupleT begin_iterators_{};
124 IteratorsTupleT end_iterators_{};
127template <
typename Row>
128RowsMapper<Row>::Iterator::Iterator(IteratorsTupleT iterators)
129 : iterators_{std::move(iterators)}
132template <
typename Row>
133typename RowsMapper<Row>::Iterator RowsMapper<Row>::Iterator::operator++(
int) {
135 old.iterators_ = IteratorsHelperT::PostfixIncrement(iterators_);
136 old.current_value_ = std::move_if_noexcept(current_value_);
137 current_value_.reset();
142template <
typename Row>
143typename RowsMapper<Row>::Iterator& RowsMapper<Row>::Iterator::operator++() {
144 IteratorsHelperT::PrefixIncrement(iterators_);
145 current_value_.reset();
150template <
typename Row>
151typename RowsMapper<Row>::Iterator::reference RowsMapper<Row>::Iterator::operator*()
const {
152 return UpdateValue();
155template <
typename Row>
156typename RowsMapper<Row>::Iterator::pointer RowsMapper<Row>::Iterator::operator->()
const {
157 return &UpdateValue();
160template <
typename Row>
161Row& RowsMapper<Row>::Iterator::UpdateValue()
const {
162 if (!current_value_.has_value()) {
164 boost::pfr::for_each_field(result, FieldMapper{iterators_});
165 current_value_.emplace(std::move(result));
168 return *current_value_;
171template <
typename Row>
172bool RowsMapper<Row>::Iterator::operator==(
const Iterator& other)
const {
173 return iterators_ == other.iterators_;
176template <
typename Row>
177bool RowsMapper<Row>::Iterator::operator!=(
const Iterator& other)
const {
178 return !((*
this) == other);