7#include <userver/utils/assert.hpp> 
    9#include <userver/storages/clickhouse/io/columns/column_includes.hpp> 
   10#include <userver/storages/clickhouse/io/columns/common_columns.hpp> 
   12USERVER_NAMESPACE_BEGIN
 
   16struct ArrayColumnMeta 
final {
 
   21ColumnRef ConvertMetaToColumn(ArrayColumnMeta&& meta);
 
   22ColumnRef ExtractArrayItem(
const ColumnRef& column, std::size_t ind);
 
   29  using cpp_type = std::vector<
typename T::cpp_type>;
 
   30  using container_type = std::vector<cpp_type>;
 
   32  ArrayColumn(ColumnRef column);
 
   34  class ArrayDataHolder 
final {
 
   36    ArrayDataHolder() = 
default;
 
   38        typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position,
 
   41    ArrayDataHolder operator++(
int);
 
   42    ArrayDataHolder& operator++();
 
   43    cpp_type& UpdateValue();
 
   45    bool operator==(
const ArrayDataHolder& other) 
const;
 
   50    std::optional<cpp_type> current_value_ = std::nullopt;
 
   52  using iterator_data = ArrayDataHolder;
 
   54  static ColumnRef Serialize(
const container_type& from);
 
   55  static cpp_type RetrieveElement(
const ColumnRef& ref, std::size_t ind);
 
   59ArrayColumn<T>::ArrayDataHolder::ArrayDataHolder(
 
   60    typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position,
 
   62    : inner_{std::move(column)},
 
   63      ind_(iter_position == 
decltype(iter_position)::kEnd
 
   64               ? GetColumnSize(inner_)
 
   68typename ArrayColumn<T>::ArrayDataHolder
 
   69ArrayColumn<T>::ArrayDataHolder::operator++(
int) {
 
   70  ArrayDataHolder old{};
 
   73  old.current_value_ = std::move_if_noexcept(current_value_);
 
   74  current_value_.reset();
 
   80typename ArrayColumn<T>::ArrayDataHolder&
 
   81ArrayColumn<T>::ArrayDataHolder::operator++() {
 
   83  current_value_.reset();
 
   89typename ArrayColumn<T>::cpp_type&
 
   90ArrayColumn<T>::ArrayDataHolder::UpdateValue() {
 
   91  UASSERT(ind_ < GetColumnSize(inner_));
 
   92  if (!current_value_.has_value()) {
 
   93    cpp_type item = RetrieveElement(inner_, ind_);
 
   94    current_value_.emplace(std::move(item));
 
   97  return *current_value_;
 
  101bool ArrayColumn<T>::ArrayDataHolder::operator==(
 
  102    const ArrayDataHolder& other) 
const {
 
  103  return inner_.get() == other.inner_.get() && ind_ == other.ind_;
 
  107ArrayColumn<T>::ArrayColumn(ColumnRef column)
 
  108    : ClickhouseColumn<ArrayColumn>{column} {}
 
  111ColumnRef ArrayColumn<T>::Serialize(
const container_type& from) {
 
  112  uint64_t cumulative_offset = 0;
 
  113  std::vector<uint64_t> offsets;
 
  114  offsets.reserve(from.size());
 
  116  for (
const auto& value : from) {
 
  117    cumulative_offset += value.size();
 
  118    offsets.push_back(cumulative_offset);
 
  120  typename T::container_type values;
 
  121  values.reserve(cumulative_offset);
 
  123  for (
const auto& value : from) {
 
  124    for (
const auto& item : value) {
 
  125      values.push_back(item);
 
  129  ArrayColumnMeta array_meta;
 
  130  array_meta.offsets = UInt64Column::Serialize(offsets);
 
  131  array_meta.data = T::Serialize(values);
 
  133  return ConvertMetaToColumn(std::move(array_meta));
 
  137typename ArrayColumn<T>::cpp_type ArrayColumn<T>::RetrieveElement(
 
  138    const ColumnRef& ref, std::size_t ind) {
 
  139  auto array_item = ExtractArrayItem(ref, ind);
 
  140  T typed_column(array_item);
 
  143  result.reserve(GetColumnSize(array_item));
 
  144  for (
auto it = typed_column.begin(); it != typed_column.end(); ++it) {
 
  145    result.push_back(std::move(*it));