userver: userver/storages/clickhouse/impl/insertion_request.hpp Source File
Loading...
Searching...
No Matches
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