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/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