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{};
37struct IsTuple : std::false_type {};
38template <
typename... T>
39struct IsTuple<std::tuple<T...>> : std::true_type {};
43template <
typename T,
typename = USERVER_NAMESPACE::utils::void_t<>>
44struct HasConstIntrospection : std::false_type {};
47struct HasConstIntrospection<T, USERVER_NAMESPACE::utils::void_t<
decltype(std::declval<
const T&>().Introspect())>>
50template <
typename T,
typename = USERVER_NAMESPACE::utils::void_t<>>
51struct HasNonConstIntrospection : std::false_type {
53 !impl::HasConstIntrospection<T>::value,
54 "PostgreSQL driver requires non-const Introspect(). "
55 "Example: auto Introspect() { return std::tie(a, b, c, d); }"
60struct HasNonConstIntrospection<T, USERVER_NAMESPACE::utils::void_t<
decltype(std::declval<T&>().Introspect())>>
63 IsTuple<
decltype(std::declval<T&>().Introspect())>::value,
64 "Introspect() should return a std::tuple. "
65 "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;
81template <
typename T,
typename = USERVER_NAMESPACE::utils::void_t<>>
82struct IsPostgresBuildInTypeWrapper : std::false_type {};
85struct IsPostgresBuildInTypeWrapper<T, USERVER_NAMESPACE::utils::void_t<
decltype(T::kIsPostgresBuildInTypeWrapper)>>
86 : std::integral_constant<
const bool, T::kIsPostgresBuildInTypeWrapper> {
88 std::is_same_v<
decltype(T::kIsPostgresBuildInTypeWrapper),
const bool>,
89 "kIsPostgresBuildInTypeWrapper must be bool"
94inline constexpr bool kIsPostgresBuildInTypeWrapper = IsPostgresBuildInTypeWrapper<T>::value;
97constexpr bool DetectIsSuitableRowType() {
98 using type = std::remove_cv_t<T>;
99 return std::is_class_v<type> && !std::is_empty_v<type> &&
100 boost::pfr::is_implicitly_reflectable_v<type, detail::ForDeserializationTag> &&
101 !std::is_polymorphic_v<type> && !std::is_union_v<type> && !postgres::detail::kIsInStdNamespace<type> &&
102 !postgres::detail::kIsInBoostNamespace<type> && !detail::kIsPostgresBuildInTypeWrapper<type>;
114inline constexpr bool kIsSuitableRowType = IsSuitableRowType<T>::value;
116enum class RowCategoryType { kNonRow, kTuple, kAggregate, kIntrusiveIntrospection };
137inline constexpr RowCategoryType kRowCategory = RowCategory<T>::value;
140constexpr void AssertIsValidRowType() {
142 kRowCategory<T> != RowCategoryType::kNonRow,
143 "Row type must be one of the following: "
144 "1. primitive type. "
146 "3. Aggregation type. See std::aggregation. "
147 "4. Has a Introspect method that makes the std::tuple from your "
149 "For more info see `uPg: Typed PostgreSQL results` chapter in docs."
154inline constexpr bool kIsRowType = kRowCategory<T> != RowCategoryType::kNonRow;
157inline constexpr bool kIsCompositeType = kIsRowType<T>;
160inline constexpr bool kIsColumnType = kRowCategory<T> == RowCategoryType::kNonRow;
162template <
typename T,
typename Enable = USERVER_NAMESPACE::
utils::
void_t<>>
173inline constexpr typename ExtractionTag<T>::type kExtractionTag{};
179template <
typename T,
traits::RowCategoryType C>
182 traits::kRowCategory<T> !=
traits::RowCategoryType::kNonRow,
183 "This type cannot be used as a row type"
188struct RowTypeImpl<T,
traits::RowCategoryType::kTuple> {
191 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
192 using IndexSequence = std::make_index_sequence<size>;
194 static TupleType& GetTuple(ValueType& v) {
return v; }
195 static const TupleType& GetTuple(
const ValueType& v) {
return v; }
199struct RowTypeImpl<T,
traits::RowCategoryType::kAggregate> {
201 using TupleType =
decltype(boost::pfr::structure_tie(std::declval<ValueType&>()));
202 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
204 using IndexSequence = std::make_index_sequence<size>;
205 static TupleType GetTuple(ValueType& v) {
return boost::pfr::structure_tie(v); }
206 static auto GetTuple(
const ValueType& value) {
return boost::pfr::structure_to_tuple(value); }
210struct RowTypeImpl<T,
traits::RowCategoryType::kIntrusiveIntrospection> {
212 using TupleType =
decltype(std::declval<ValueType&>().Introspect());
213 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
214 using IndexSequence = std::make_index_sequence<size>;
215 using ConstRefTuple =
typename traits::AddTupleConstRef<TupleType>::type;
217 static TupleType GetTuple(ValueType& v) {
return v.Introspect(); }
218 static auto GetTuple(
const ValueType& v) {
222 return ConstRefTuple{
const_cast<ValueType&>(v).Introspect()};
229struct RowType : detail::RowTypeImpl<T,
traits::kRowCategory<T>> {};