userver: userver/storages/clickhouse/io/impl/validate.hpp Source File
Loading...
Searching...
No Matches
validate.hpp
1#pragma once
2
3#include <type_traits>
4#include <vector>
5
6#include <boost/pfr/core.hpp>
7
8#include <userver/utils/assert.hpp>
9#include <userver/utils/meta_light.hpp>
10
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>
17
18USERVER_NAMESPACE_BEGIN
19
20namespace storages::clickhouse::io::impl {
21
22template <typename T>
23constexpr void EnsureInstantiationOfVector([[maybe_unused]] const T& t) {
24 static_assert(meta::kIsInstantiationOf<std::vector, T>);
25}
26
27template <typename T>
28struct EnsureInstantiationOfColumn {
29 ~EnsureInstantiationOfColumn() {
30 static_assert(!std::is_same_v<columns::ClickhouseColumn<T>, T>);
31 static_assert(std::is_base_of_v<columns::ClickhouseColumn<T>, T>);
32 }
33};
34
35template <typename T>
36struct EnsureInstantiationOfColumn<columns::NullableColumn<T>> {
37 ~EnsureInstantiationOfColumn() {
38 static_assert(!std::is_same_v<columns::ClickhouseColumn<T>, T>);
39 static_assert(std::is_base_of_v<columns::ClickhouseColumn<T>, T>);
40 }
41};
42
43template <typename T,
44 typename Seq = std::make_index_sequence<std::tuple_size_v<T>>>
45struct TupleColumnsValidate;
46
47template <typename T, size_t... S>
48struct TupleColumnsValidate<T, std::index_sequence<S...>> {
49 ~TupleColumnsValidate() {
50 (...,
51 (void)impl::EnsureInstantiationOfColumn<std::tuple_element_t<S, T>>{});
52 }
53};
54
55template <size_t I, typename Row>
56using CppType = boost::pfr::tuple_element_t<I, Row>;
57
58template <typename T>
59using MappedType = typename CppToClickhouse<T>::mapped_type;
60
61template <size_t I, typename Row>
62using ClickhouseType =
63 typename std::tuple_element_t<I, MappedType<Row>>::cpp_type;
64
65template <typename T>
66inline constexpr auto kCppTypeColumnsCount = boost::pfr::tuple_size_v<T>;
67
68template <typename T>
69inline constexpr auto kClickhouseTypeColumnsCount =
70 std::tuple_size_v<MappedType<T>>;
71
72template <typename T>
73constexpr void CommonValidateMapping() {
74 static_assert(traits::kIsMappedToClickhouse<T>, "not mapped to clickhouse");
75 static_assert(kCppTypeColumnsCount<T> == kClickhouseTypeColumnsCount<T>);
76
77 [[maybe_unused]] TupleColumnsValidate<MappedType<T>> validator{};
78}
79
80template <typename T>
81constexpr void ValidateColumnsMapping(const T& t) {
82 boost::pfr::for_each_field(
83 t, [](const auto& field) { impl::EnsureInstantiationOfVector(field); });
84
85 impl::CommonValidateMapping<T>();
86}
87
88template <size_t I>
89struct FailIndexAssertion : std::false_type {};
90
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>>...};
95
96 size_t i = 0;
97 for (bool v : results) {
98 if (!v) return i;
99 ++i;
100 }
101
102 return i;
103}
104
105template <typename T>
106constexpr void ValidateRowsMapping() {
107 impl::CommonValidateMapping<T>();
108
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.");
118 }
119}
120
121template <typename T>
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());
127 }
128 UINVARIANT(*rows_count == field.size(),
129 "All rows should have same number of elements");
130 });
131}
132
133template <typename T>
134void ValidateColumnsCount(size_t expected) {
135 constexpr auto columns_count = kCppTypeColumnsCount<T>;
136 UINVARIANT(columns_count == expected, "Columns count mismatch.");
137}
138
139} // namespace storages::clickhouse::io::impl
140
141USERVER_NAMESPACE_END