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>
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>;
110template <
typename Tag,
typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops,
typename Enable>
114inline constexpr bool kIsSuitableRowType = IsSuitableRowType<T>::value;
116enum class RowCategoryType { kNonRow, kTuple, kAggregate, kIntrusiveIntrospection };
118template <RowCategoryType Tag>
119using RowCategoryConstant = std::integral_constant<RowCategoryType, Tag>;
123 : std::conditional_t<
125 RowCategoryConstant<RowCategoryType::kTuple>,
128 RowCategoryConstant<RowCategoryType::kIntrusiveIntrospection>,
131 RowCategoryConstant<RowCategoryType::kAggregate>,
132 RowCategoryConstant<RowCategoryType::kNonRow>>>> {};
134template <
typename Tag,
typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops,
typename Enable>
138inline constexpr RowCategoryType kRowCategory = RowCategory<T>::value;
141constexpr void AssertIsValidRowType() {
143 kRowCategory<T> != RowCategoryType::kNonRow,
144 "Row type must be one of the following: "
145 "1. primitive type. "
147 "3. Aggregation type. See std::aggregation. "
148 "4. Has a Introspect method that makes the std::tuple from your "
150 "For more info see `uPg: Typed PostgreSQL results` chapter in docs."
155inline constexpr bool kIsRowType = kRowCategory<T> != RowCategoryType::kNonRow;
158inline constexpr bool kIsCompositeType = kIsRowType<T>;
161inline constexpr bool kIsColumnType = kRowCategory<T> == RowCategoryType::kNonRow;
163template <
typename T,
typename Enable = USERVER_NAMESPACE::utils::void_t<>>
174inline constexpr typename ExtractionTag<T>::type kExtractionTag{};
180template <
typename T,
traits::RowCategoryType C>
183 traits::kRowCategory<T> !=
traits::RowCategoryType::kNonRow,
184 "This type cannot be used as a row type"
189struct RowTypeImpl<T,
traits::RowCategoryType::kTuple> {
192 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
193 using IndexSequence = std::make_index_sequence<size>;
195 static TupleType& GetTuple(ValueType& v) {
return v; }
196 static const TupleType& GetTuple(
const ValueType& v) {
return v; }
200struct RowTypeImpl<T,
traits::RowCategoryType::kAggregate> {
202 using TupleType =
decltype(boost::pfr::structure_tie(std::declval<ValueType&>()));
203 static constexpr std::size_t size = std::tuple_size<TupleType>::value;
205 using IndexSequence = std::make_index_sequence<size>;
206 static TupleType GetTuple(ValueType& v) {
return boost::pfr::structure_tie(v); }
207 static auto GetTuple(
const ValueType& value) {
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()};