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