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;
37 ArrayDataHolder(
typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position, ColumnRef&& column);
39 ArrayDataHolder operator++(
int);
40 ArrayDataHolder& operator++();
41 cpp_type& UpdateValue();
43 bool operator==(
const ArrayDataHolder& other)
const;
48 std::optional<cpp_type> current_value_ = std::nullopt;
50 using iterator_data = ArrayDataHolder;
52 static ColumnRef Serialize(
const container_type& from);
53 static cpp_type RetrieveElement(
const ColumnRef& ref, std::size_t ind);
57ArrayColumn<T>::ArrayDataHolder::ArrayDataHolder(
58 typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position,
61 : inner_{std::move(column)}, ind_(iter_position ==
decltype(iter_position)::kEnd ? GetColumnSize(inner_) : 0) {}
64typename ArrayColumn<T>::ArrayDataHolder ArrayColumn<T>::ArrayDataHolder::operator++(
int) {
65 ArrayDataHolder old{};
68 old.current_value_ = std::move_if_noexcept(current_value_);
69 current_value_.reset();
75typename ArrayColumn<T>::ArrayDataHolder& ArrayColumn<T>::ArrayDataHolder::operator++() {
77 current_value_.reset();
83typename ArrayColumn<T>::cpp_type& ArrayColumn<T>::ArrayDataHolder::UpdateValue() {
84 UASSERT(ind_ < GetColumnSize(inner_));
85 if (!current_value_.has_value()) {
86 cpp_type item = RetrieveElement(inner_, ind_);
87 current_value_.emplace(std::move(item));
90 return *current_value_;
94bool ArrayColumn<T>::ArrayDataHolder::operator==(
const ArrayDataHolder& other)
const {
95 return inner_.get() == other.inner_.get() && ind_ == other.ind_;
99ArrayColumn<T>::ArrayColumn(ColumnRef column) : ClickhouseColumn<ArrayColumn>{column} {}
102ColumnRef ArrayColumn<T>::Serialize(
const container_type& from) {
103 uint64_t cumulative_offset = 0;
104 std::vector<uint64_t> offsets;
105 offsets.reserve(from.size());
107 for (
const auto& value : from) {
108 cumulative_offset += value.size();
109 offsets.push_back(cumulative_offset);
111 typename T::container_type values;
112 values.reserve(cumulative_offset);
114 for (
const auto& value : from) {
115 for (
const auto& item : value) {
116 values.push_back(item);
120 ArrayColumnMeta array_meta;
121 array_meta.offsets = UInt64Column::Serialize(offsets);
122 array_meta.data = T::Serialize(values);
124 return ConvertMetaToColumn(std::move(array_meta));
128typename ArrayColumn<T>::cpp_type ArrayColumn<T>::RetrieveElement(
const ColumnRef& ref, std::size_t ind) {
129 auto array_item = ExtractArrayItem(ref, ind);
130 T typed_column(array_item);
133 result.reserve(GetColumnSize(array_item));
134 for (
auto it = typed_column.begin(); it != typed_column.end(); ++it) {
135 result.push_back(std::move(*it));