8#include <userver/utils/assert.hpp>
10#include <userver/storages/clickhouse/impl/block_wrapper_fwd.hpp>
11#include <userver/storages/clickhouse/io/impl/validate.hpp>
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>
18USERVER_NAMESPACE_BEGIN
22class InsertionRequest
final {
24 InsertionRequest(
const std::string& table_name,
25 const std::vector<std::string_view>& column_names);
26 InsertionRequest(InsertionRequest&&)
noexcept;
30 static InsertionRequest Create(
31 const std::string& table_name,
32 const std::vector<std::string_view>& column_names,
const T& data);
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);
39 const std::string& GetTableName()
const;
41 const impl::BlockWrapper& GetBlock()
const;
44 template <
typename MappedType>
45 class ColumnsMapper
final {
47 ColumnsMapper(impl::BlockWrapper& block,
48 const std::vector<std::string_view>& column_names)
49 : block_{block}, column_names_{column_names} {}
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>);
57 io::columns::AppendWrappedColumn(block_, ColumnType::Serialize(field),
62 impl::BlockWrapper& block_;
63 const std::vector<std::string_view>& column_names_;
66 template <
typename MappedType,
typename Container>
67 class RowsMapper
final {
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} {}
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>);
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));
85 io::columns::AppendWrappedColumn(
86 block_, ColumnType::Serialize(column_data), column_names_[i], i);
90 impl::BlockWrapper& block_;
91 const std::vector<std::string_view>& column_names_;
92 const Container& data_;
95 const std::string& table_name_;
96 const std::vector<std::string_view>& column_names_;
98 std::unique_ptr<impl::BlockWrapper> block_;
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);
108 io::impl::ValidateColumnsCount<T>(column_names.size());
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_};
115 boost::pfr::for_each_field(data, mapper);
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>();
126 io::impl::ValidateColumnsCount<T>(column_names.size());
128 UINVARIANT(!data.empty(),
"An attempt to insert empty chunk of data");
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};
135 boost::pfr::for_each_field(data.front(), mapper);