3#include <boost/pfr/core.hpp>
4#include <boost/pfr/traits.hpp>
6#include <userver/storages/postgres/detail/is_in_namespace.hpp>
7#include <userver/storages/postgres/io/type_traits.hpp>
9#include <userver/utils/strong_typedef.hpp>
11USERVER_NAMESPACE_BEGIN
28inline constexpr RowTag kRowTag{};
29inline constexpr FieldTag kFieldTag{};
38template <
typename... T>
43template <
typename T,
typename = USERVER_NAMESPACE::utils::void_t<>>
44struct HasConstIntrospection : std::false_type {};
47struct HasConstIntrospection<
48 T, USERVER_NAMESPACE::utils::void_t<
49 decltype(std::declval<
const T&>().Introspect())>> : std::true_type {
52template <
typename T,
typename = USERVER_NAMESPACE::utils::void_t<>>
53struct HasNonConstIntrospection : std::false_type {
54 static_assert(!impl::HasConstIntrospection<T>::value,
55 "PostgreSQL driver requires non-const Introspect(). "
56 "Example: auto Introspect() { return std::tie(a, b, c, d); }");
60struct HasNonConstIntrospection<
62 USERVER_NAMESPACE::utils::void_t<
decltype(std::declval<T&>().Introspect())>>
64 static_assert(IsTuple<
decltype(std::declval<T&>().Introspect())>::value,
65 "Introspect() should return a std::tuple. "
66 "Example: auto Introspect() { return std::tie(a, b, c, d); }");
73 static_assert(!std::is_const_v<T>);
74 static_assert(!std::is_reference_v<T>);
79struct ForDeserializationTag;
82constexpr bool DetectIsSuitableRowType() {
83 using type = std::remove_cv_t<T>;
84 return std::is_class_v<type> && !std::is_empty_v<type> &&
85 boost::pfr::is_implicitly_reflectable_v<
86 type, detail::ForDeserializationTag> &&
87 !std::is_polymorphic_v<type> && !std::is_union_v<type> &&
88 !postgres::detail::kIsInStdNamespace<type> &&
89 !postgres::detail::kIsInBoostNamespace<type>;
98template <
typename Tag,
typename T,
101 USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
105inline constexpr bool kIsSuitableRowType = IsSuitableRowType<T>::value;
107enum class RowCategoryType {
111 kIntrusiveIntrospection
129template <
typename Tag,
typename T,
131struct RowCategory<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>
135inline constexpr RowCategoryType kRowCategory = RowCategory<T>::value;
138constexpr void AssertIsValidRowType() {
140 kRowCategory<T> != RowCategoryType::kNonRow,
141 "Row type must be one of the following: "
142 "1. primitive type. "
144 "3. Aggregation type. See std::aggregation. "
145 "4. Has a Introspect method that makes the std::tuple from your "
147 "For more info see `uPg: Typed PostgreSQL results` chapter in docs.");
151inline constexpr bool kIsRowType = kRowCategory<T> != RowCategoryType::kNonRow;
154inline constexpr bool kIsCompositeType = kIsRowType<T>;
157inline constexpr bool kIsColumnType =
158 kRowCategory<T> == RowCategoryType::kNonRow;
160template <
typename T,
typename Enable = USERVER_NAMESPACE::
utils::
void_t<>>
171inline constexpr typename ExtractionTag<T>::type kExtractionTag{};
177template <
typename T,
traits::RowCategoryType C>
179 static_assert(
traits::kRowCategory<T> !=
traits::RowCategoryType::kNonRow,
180 "This type cannot be used as a row type");
184struct RowTypeImpl<T,
traits::RowCategoryType::kTuple> {
187 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
188 using IndexSequence = std::make_index_sequence<size>;
190 static TupleType& GetTuple(ValueType& v) {
return v; }
191 static const TupleType& GetTuple(
const ValueType& v) {
return v; }
195struct RowTypeImpl<T,
traits::RowCategoryType::kAggregate> {
198 decltype(boost::pfr::structure_tie(std::declval<ValueType&>()));
199 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
201 using IndexSequence = std::make_index_sequence<size>;
202 static TupleType GetTuple(ValueType& v) {
203 return boost::pfr::structure_tie(v);
205 static auto GetTuple(
const ValueType& value) {
206 return boost::pfr::structure_to_tuple(value);
211struct RowTypeImpl<T,
traits::RowCategoryType::kIntrusiveIntrospection> {
213 using TupleType =
decltype(std::declval<ValueType&>().Introspect());
214 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
215 using IndexSequence = std::make_index_sequence<size>;
216 using ConstRefTuple =
typename traits::AddTupleConstRef<TupleType>::type;
218 static TupleType GetTuple(ValueType& v) {
return v.Introspect(); }
219 static auto GetTuple(
const ValueType& v) {
223 return ConstRefTuple{
const_cast<ValueType&>(v).Introspect()};
230struct RowType : detail::RowTypeImpl<T,
traits::kRowCategory<T>> {};