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);