6#include <boost/pfr/core.hpp> 
    8#include <userver/utils/assert.hpp> 
    9#include <userver/utils/meta_light.hpp> 
   11#include <userver/storages/clickhouse/io/columns/base_column.hpp> 
   12#include <userver/storages/clickhouse/io/columns/common_columns.hpp> 
   13#include <userver/storages/clickhouse/io/columns/nullable_column.hpp> 
   14#include <userver/storages/clickhouse/io/io_fwd.hpp> 
   15#include <userver/storages/clickhouse/io/type_traits.hpp> 
   17USERVER_NAMESPACE_BEGIN
 
   22constexpr void EnsureInstantiationOfVector([[maybe_unused]] 
const T& t) {
 
   23  static_assert(meta::kIsInstantiationOf<std::vector, T>);
 
   27struct EnsureInstantiationOfColumn {
 
   28  ~EnsureInstantiationOfColumn() {
 
   35struct EnsureInstantiationOfColumn<
columns::NullableColumn<T>> {
 
   36  ~EnsureInstantiationOfColumn() {
 
   43          typename Seq = std::make_index_sequence<std::tuple_size_v<T>>>
 
   44struct TupleColumnsValidate;
 
   46template <
typename T, size_t... S>
 
   47struct TupleColumnsValidate<T, std::index_sequence<S...>> {
 
   48  ~TupleColumnsValidate() {
 
   50     (
void)impl::EnsureInstantiationOfColumn<std::tuple_element_t<S, T>>{});
 
   54template <size_t I, 
typename Row>
 
   55using CppType = boost::pfr::tuple_element_t<I, Row>;
 
   58using MappedType = 
typename CppToClickhouse<T>::mapped_type;
 
   60template <size_t I, 
typename Row>
 
   62    typename std::tuple_element_t<I, MappedType<Row>>::cpp_type;
 
   65inline constexpr auto kCppTypeColumnsCount = boost::pfr::tuple_size_v<T>;
 
   68inline constexpr auto kClickhouseTypeColumnsCount =
 
   69    std::tuple_size_v<MappedType<T>>;
 
   72constexpr void CommonValidateMapping() {
 
   73  static_assert(traits::kIsMappedToClickhouse<T>, 
"not mapped to clickhouse");
 
   74  static_assert(kCppTypeColumnsCount<T> == kClickhouseTypeColumnsCount<T>);
 
   76  [[maybe_unused]] TupleColumnsValidate<MappedType<T>> validator{};
 
   80constexpr void ValidateColumnsMapping(
const T& t) {
 
   81  boost::pfr::for_each_field(
 
   82      t, [](
const auto& field) { impl::EnsureInstantiationOfVector(field); });
 
   84  impl::CommonValidateMapping<T>();
 
   88struct FailIndexAssertion : std::false_type {};
 
   90template <
typename Row, size_t... I>
 
   91constexpr size_t FieldTypeFindMismatch(std::index_sequence<I...>) {
 
   92  constexpr bool results[] = {
 
   93      std::is_same_v<CppType<I, Row>, ClickhouseType<I, Row>>...};
 
   96  for (
bool v : results) {
 
  105constexpr void ValidateRowsMapping() {
 
  106  impl::CommonValidateMapping<T>();
 
  108  constexpr auto columns_count = kClickhouseTypeColumnsCount<T>;
 
  109  constexpr auto type_mismatch_index =
 
  110      FieldTypeFindMismatch<T>(std::make_index_sequence<columns_count>());
 
  111  if constexpr (type_mismatch_index != columns_count) {
 
  112    static_assert(std::is_same_v<CppType<type_mismatch_index, T>,
 
  113                                 ClickhouseType<type_mismatch_index, T>>,
 
  114                  "Make sure your ClickHouse mapping is correct.");
 
  115    static_assert(FailIndexAssertion<type_mismatch_index>::value,
 
  116                  "Recheck your mapping at this index.");
 
  121void ValidateRowsCount(
const T& t) {
 
  122  std::optional<size_t> rows_count;
 
  123  boost::pfr::for_each_field(t, [&rows_count](
const auto& field) {
 
  124    if (!rows_count.has_value()) {
 
  125      rows_count.emplace(field.size());
 
  128               "All rows should have same number of elements");
 
  133void ValidateColumnsCount(size_t expected) {
 
  134  constexpr auto columns_count = kCppTypeColumnsCount<T>;
 
  135  UINVARIANT(columns_count == expected, 
"Columns count mismatch.");