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