userver: userver/storages/clickhouse/io/columns/array_column.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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