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/array_column.hpp>
12#include <userver/storages/clickhouse/io/columns/base_column.hpp>
13#include <userver/storages/clickhouse/io/columns/common_columns.hpp>
14#include <userver/storages/clickhouse/io/columns/nullable_column.hpp>
15#include <userver/storages/clickhouse/io/io_fwd.hpp>
16#include <userver/storages/clickhouse/io/type_traits.hpp>
18USERVER_NAMESPACE_BEGIN
23constexpr void EnsureInstantiationOfVector([[maybe_unused]]
const T& t) {
24 static_assert(meta::kIsInstantiationOf<std::vector, T>);
28struct EnsureInstantiationOfColumn {
29 ~EnsureInstantiationOfColumn() {
36struct EnsureInstantiationOfColumn<
columns::NullableColumn<T>> {
37 ~EnsureInstantiationOfColumn() {
44 typename Seq = std::make_index_sequence<std::tuple_size_v<T>>>
45struct TupleColumnsValidate;
47template <
typename T, size_t... S>
48struct TupleColumnsValidate<T, std::index_sequence<S...>> {
49 ~TupleColumnsValidate() {
51 (
void)impl::EnsureInstantiationOfColumn<std::tuple_element_t<S, T>>{});
55template <size_t I,
typename Row>
56using CppType = boost::pfr::tuple_element_t<I, Row>;
59using MappedType =
typename CppToClickhouse<T>::mapped_type;
61template <size_t I,
typename Row>
63 typename std::tuple_element_t<I, MappedType<Row>>::cpp_type;
66inline constexpr auto kCppTypeColumnsCount = boost::pfr::tuple_size_v<T>;
69inline constexpr auto kClickhouseTypeColumnsCount =
70 std::tuple_size_v<MappedType<T>>;
73constexpr void CommonValidateMapping() {
74 static_assert(traits::kIsMappedToClickhouse<T>,
"not mapped to clickhouse");
75 static_assert(kCppTypeColumnsCount<T> == kClickhouseTypeColumnsCount<T>);
77 [[maybe_unused]] TupleColumnsValidate<MappedType<T>> validator{};
81constexpr void ValidateColumnsMapping(
const T& t) {
82 boost::pfr::for_each_field(
83 t, [](
const auto& field) { impl::EnsureInstantiationOfVector(field); });
85 impl::CommonValidateMapping<T>();
89struct FailIndexAssertion : std::false_type {};
91template <
typename Row, size_t... I>
92constexpr size_t FieldTypeFindMismatch(std::index_sequence<I...>) {
93 constexpr bool results[] = {
94 std::is_same_v<CppType<I, Row>, ClickhouseType<I, Row>>...};
97 for (
bool v : results) {
106constexpr void ValidateRowsMapping() {
107 impl::CommonValidateMapping<T>();
109 constexpr auto columns_count = kClickhouseTypeColumnsCount<T>;
110 constexpr auto type_mismatch_index =
111 FieldTypeFindMismatch<T>(std::make_index_sequence<columns_count>());
112 if constexpr (type_mismatch_index != columns_count) {
113 static_assert(std::is_same_v<CppType<type_mismatch_index, T>,
114 ClickhouseType<type_mismatch_index, T>>,
115 "Make sure your ClickHouse mapping is correct.");
116 static_assert(FailIndexAssertion<type_mismatch_index>::value,
117 "Recheck your mapping at this index.");
122void ValidateRowsCount(
const T& t) {
123 std::optional<size_t> rows_count;
124 boost::pfr::for_each_field(t, [&rows_count](
const auto& field) {
125 if (!rows_count.has_value()) {
126 rows_count.emplace(field.size());
129 "All rows should have same number of elements");
134void ValidateColumnsCount(size_t expected) {
135 constexpr auto columns_count = kCppTypeColumnsCount<T>;
136 UINVARIANT(columns_count == expected,
"Columns count mismatch.");