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