userver: userver/storages/clickhouse/impl/insertion_request.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
insertion_request.hpp
1#pragma once
2
3#include <memory>
4#include <string>
5#include <string_view>
6#include <vector>
7
8#include <userver/utils/assert.hpp>
9
10#include <userver/storages/clickhouse/impl/block_wrapper_fwd.hpp>
11#include <userver/storages/clickhouse/io/impl/validate.hpp>
12
13#include <userver/storages/clickhouse/io/columns/column_wrapper.hpp>
14#include <userver/storages/clickhouse/io/columns/common_columns.hpp>
15#include <userver/storages/clickhouse/io/columns/nullable_column.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace storages::clickhouse::impl {
20
21class InsertionRequest final {
22 public:
23 InsertionRequest(const std::string& table_name,
24 const std::vector<std::string_view>& column_names);
25 InsertionRequest(InsertionRequest&&) noexcept;
26 ~InsertionRequest();
27
28 template <typename T>
29 static InsertionRequest Create(
30 const std::string& table_name,
31 const std::vector<std::string_view>& column_names, const T& data);
32
33 template <typename Container>
34 static InsertionRequest CreateFromRows(
35 const std::string& table_name,
36 const std::vector<std::string_view>& column_names, const Container& data);
37
38 const std::string& GetTableName() const;
39
40 const impl::BlockWrapper& GetBlock() const;
41
42 private:
43 template <typename MappedType>
44 class ColumnsMapper final {
45 public:
46 ColumnsMapper(impl::BlockWrapper& block,
47 const std::vector<std::string_view>& column_names)
48 : block_{block}, column_names_{column_names} {}
49
50 template <typename Field, size_t Index>
51 void operator()(const Field& field,
52 std::integral_constant<size_t, Index> i) {
53 using ColumnType = std::tuple_element_t<Index, MappedType>;
54 static_assert(std::is_same_v<Field, typename ColumnType::container_type>);
55
56 io::columns::AppendWrappedColumn(block_, ColumnType::Serialize(field),
57 column_names_[i], i);
58 }
59
60 private:
61 impl::BlockWrapper& block_;
62 const std::vector<std::string_view>& column_names_;
63 };
64
65 template <typename MappedType, typename Container>
66 class RowsMapper final {
67 public:
68 RowsMapper(impl::BlockWrapper& block,
69 const std::vector<std::string_view>& column_names,
70 const Container& data)
71 : block_{block}, column_names_{column_names}, data_{data} {}
72
73 template <typename Field, size_t Index>
74 void operator()(const Field&, std::integral_constant<size_t, Index> i) {
75 using ColumnType = std::tuple_element_t<Index, MappedType>;
76 static_assert(std::is_same_v<Field, typename ColumnType::cpp_type>);
77
78 std::vector<Field> column_data;
79 column_data.reserve(data_.size());
80 for (const auto& row : data_) {
81 column_data.emplace_back(boost::pfr::get<Index>(row));
82 }
83
84 io::columns::AppendWrappedColumn(
85 block_, ColumnType::Serialize(column_data), column_names_[i], i);
86 }
87
88 private:
89 impl::BlockWrapper& block_;
90 const std::vector<std::string_view>& column_names_;
91 const Container& data_;
92 };
93
94 const std::string& table_name_;
95 const std::vector<std::string_view>& column_names_;
96
97 std::unique_ptr<impl::BlockWrapper> block_;
98};
99
100template <typename T>
101InsertionRequest InsertionRequest::Create(
102 const std::string& table_name,
103 const std::vector<std::string_view>& column_names, const T& data) {
104 io::impl::ValidateColumnsMapping(data);
105 io::impl::ValidateRowsCount(data);
106 // TODO : static_assert this when std::span comes
107 io::impl::ValidateColumnsCount<T>(column_names.size());
108
109 InsertionRequest request{table_name, column_names};
110 using MappedType = typename io::CppToClickhouse<T>::mapped_type;
111 auto mapper = InsertionRequest::ColumnsMapper<MappedType>{
112 *request.block_, request.column_names_};
113
114 boost::pfr::for_each_field(data, mapper);
115 return request;
116}
117
118template <typename Container>
119InsertionRequest InsertionRequest::CreateFromRows(
120 const std::string& table_name,
121 const std::vector<std::string_view>& column_names, const Container& data) {
122 using T = typename Container::value_type;
123 io::impl::CommonValidateMapping<T>();
124 // TODO : static_assert this when std::span comes
125 io::impl::ValidateColumnsCount<T>(column_names.size());
126
127 UINVARIANT(!data.empty(), "An attempt to insert empty chunk of data");
128
129 InsertionRequest request{table_name, column_names};
130 using MappedType = typename io::CppToClickhouse<T>::mapped_type;
131 auto mapper = InsertionRequest::RowsMapper<MappedType, Container>{
132 *request.block_, request.column_names_, data};
133
134 boost::pfr::for_each_field(data.front(), mapper);
135 return request;
136}
137
138} // namespace storages::clickhouse::impl
139
140USERVER_NAMESPACE_END