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);