userver: userver/storages/clickhouse/io/columns/array_column.hpp Source File
Loading...
Searching...
No Matches
array_column.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/clickhouse/io/columns/array_column.hpp
4/// @brief Array column support
5/// @ingroup userver_clickhouse_types
6
7#include <userver/utils/assert.hpp>
8
9#include <userver/storages/clickhouse/io/columns/column_includes.hpp>
10#include <userver/storages/clickhouse/io/columns/common_columns.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace storages::clickhouse::io::columns {
15
16struct ArrayColumnMeta final {
17 ColumnRef data;
18 ColumnRef offsets;
19};
20
21ColumnRef ConvertMetaToColumn(ArrayColumnMeta&& meta);
22ColumnRef ExtractArrayItem(const ColumnRef& column, std::size_t ind);
23
24/// @brief Represents ClickHouse Array(T) column,
25/// where T is a ClickhouseColumn as well
26template <typename T>
27class ArrayColumn final : public ClickhouseColumn<ArrayColumn<T>> {
28 public:
29 using cpp_type = std::vector<typename T::cpp_type>;
30 using container_type = std::vector<cpp_type>;
31
32 ArrayColumn(ColumnRef column);
33
34 class ArrayDataHolder final {
35 public:
36 ArrayDataHolder() = default;
37 ArrayDataHolder(
38 typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position,
39 ColumnRef&& column);
40
41 ArrayDataHolder operator++(int);
42 ArrayDataHolder& operator++();
43 cpp_type& UpdateValue();
44
45 bool operator==(const ArrayDataHolder& other) const;
46
47 private:
48 ColumnRef inner_{};
49 std::size_t ind_{0};
50 std::optional<cpp_type> current_value_ = std::nullopt;
51 };
52 using iterator_data = ArrayDataHolder;
53
54 static ColumnRef Serialize(const container_type& from);
55 static cpp_type RetrieveElement(const ColumnRef& ref, std::size_t ind);
56};
57
58template <typename T>
59ArrayColumn<T>::ArrayDataHolder::ArrayDataHolder(
60 typename ColumnIterator<ArrayColumn<T>>::IteratorPosition iter_position,
61 ColumnRef&& column)
62 : inner_{std::move(column)},
63 ind_(iter_position == decltype(iter_position)::kEnd
64 ? GetColumnSize(inner_)
65 : 0) {}
66
67template <typename T>
68typename ArrayColumn<T>::ArrayDataHolder
69ArrayColumn<T>::ArrayDataHolder::operator++(int) {
70 ArrayDataHolder old{};
71 old.inner_ = inner_;
72 old.ind_ = ind_++;
73 old.current_value_ = std::move_if_noexcept(current_value_);
74 current_value_.reset();
75
76 return old;
77}
78
79template <typename T>
80typename ArrayColumn<T>::ArrayDataHolder&
81ArrayColumn<T>::ArrayDataHolder::operator++() {
82 ++ind_;
83 current_value_.reset();
84
85 return *this;
86}
87
88template <typename T>
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));
95 }
96
97 return *current_value_;
98}
99
100template <typename T>
101bool ArrayColumn<T>::ArrayDataHolder::operator==(
102 const ArrayDataHolder& other) const {
103 return inner_.get() == other.inner_.get() && ind_ == other.ind_;
104}
105
106template <typename T>
107ArrayColumn<T>::ArrayColumn(ColumnRef column)
108 : ClickhouseColumn<ArrayColumn>{column} {}
109
110template <typename T>
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());
115
116 for (const auto& value : from) {
117 cumulative_offset += value.size();
118 offsets.push_back(cumulative_offset);
119 }
120 typename T::container_type values;
121 values.reserve(cumulative_offset);
122
123 for (const auto& value : from) {
124 for (const auto& item : value) {
125 values.push_back(item);
126 }
127 }
128
129 ArrayColumnMeta array_meta;
130 array_meta.offsets = UInt64Column::Serialize(offsets);
131 array_meta.data = T::Serialize(values);
132
133 return ConvertMetaToColumn(std::move(array_meta));
134}
135
136template <typename T>
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);
141
142 cpp_type result;
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));
146 }
147 return result;
148}
149
150} // namespace storages::clickhouse::io::columns
151
152USERVER_NAMESPACE_END