7#include <userver/storages/postgres/exceptions.hpp>
8#include <userver/storages/postgres/io/buffer_io.hpp>
9#include <userver/storages/postgres/io/buffer_io_base.hpp>
10#include <userver/storages/postgres/io/nullable_traits.hpp>
12#include <userver/utils/strong_typedef.hpp>
13#include <userver/utils/void_t.hpp>
15USERVER_NAMESPACE_BEGIN
44template <
typename Tag,
typename T, USERVER_NAMESPACE::utils::StrongTypedefOps Ops,
typename Enable>
45inline constexpr bool kIsStrongTypedefDirectlyMapped =
47 kIsMappedToUserType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> ||
49 kIsMappedToSystemType<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>> ||
51 kIsMappedToArray<USERVER_NAMESPACE::utils::StrongTypedef<Tag, T, Ops, Enable>>;
53template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
56 : BoolConstant<kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> || kIsMappedToPg<T>> {};
60template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
63 : BoolConstant<!kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> && kIsMappedToPg<T>> {};
65template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
68template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
70 using ValueType = USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>;
72 inline static bool IsNull(
const ValueType& v) {
return UnderlyingGetSet::IsNull(v.GetUnderlying()); }
73 inline static void SetNull(ValueType& v) { UnderlyingGetSet::SetNull(v.GetUnderlying()); }
74 inline static void SetDefault(ValueType& v) { UnderlyingGetSet::SetDefault(v.GetUnderlying()); }
79template <
typename T,
typename = USERVER_NAMESPACE::
utils::void_t<>>
85constexpr bool CheckCanUseEnumAsStrongTypedef() {
89 "storages::postgres::io::traits::CanUseEnumAsStrongTypedef "
90 "should be specialized only for enums"
93 std::is_signed_v<std::underlying_type_t<T>>,
94 "storages::postgres::io::traits::CanUseEnumAsStrongTypedef should be "
95 "specialized only for enums with signed underlying type"
107using EnableIfCanUseEnumAsStrongTypedef = std::enable_if_t<impl::CheckCanUseEnumAsStrongTypedef<T>()>;
111template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
112struct BufferFormatter<USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>>
113 : detail::BufferFormatterBase<USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>> {
114 using BaseType = detail::BufferFormatterBase<USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>>;
115 using BaseType::BaseType;
117 template <
typename Buffer>
118 void operator()(
const UserTypes& types, Buffer& buf)
const {
119 io::WriteBuffer(types, buf,
this->value.GetUnderlying());
124template <
typename StrongTypedef,
bool Categories =
false>
125struct StrongTypedefParser : BufferParserBase<StrongTypedef> {
126 using BaseType = BufferParserBase<StrongTypedef>;
127 using UnderlyingType =
typename StrongTypedef::UnderlyingType;
129 using BaseType::BaseType;
132 UnderlyingType& v =
this->value.GetUnderlying();
133 io::ReadBuffer(buffer, v);
137template <
typename StrongTypedef>
138struct StrongTypedefParser<StrongTypedef,
true> : BufferParserBase<StrongTypedef> {
139 using BaseType = BufferParserBase<StrongTypedef>;
140 using UnderlyingType =
typename StrongTypedef::UnderlyingType;
142 using BaseType::BaseType;
144 void operator()(
const FieldBuffer& buffer,
const TypeBufferCategory& categories) {
145 UnderlyingType& v =
this->value.GetUnderlying();
146 io::ReadBuffer(buffer, v, categories);
152template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
153struct BufferParser<USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>>
154 : detail::StrongTypedefParser<
155 USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>,
156 detail::kParserRequiresTypeCategories<T>> {
157 using BaseType = detail::StrongTypedefParser<
158 USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>,
159 detail::kParserRequiresTypeCategories<T>>;
160 using BaseType::BaseType;
164template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
166 USERVER_NAMESPACE::
utils::StrongTypedef<Tag, T, Ops, Enable>,
167 std::enable_if_t<!
traits::kIsStrongTypedefDirectlyMapped<Tag, T, Ops, Enable> &&
traits::kIsMappedToPg<T>>>
172template <
typename Tag,
typename T, USERVER_NAMESPACE::
utils::StrongTypedefOps Ops,
typename Enable>
181struct EnumStrongTypedefFormatter : BufferFormatterBase<T> {
182 using BaseType = BufferFormatterBase<T>;
183 using BaseType::BaseType;
185 template <
typename Buffer>
186 void operator()(
const UserTypes& types, Buffer& buf)
const {
187 io::WriteBuffer(types, buf, USERVER_NAMESPACE::
utils::UnderlyingValue(
this->value));
192struct EnumStrongTypedefParser : BufferParserBase<T> {
193 using BaseType = BufferParserBase<T>;
194 using ValueType =
typename BaseType::ValueType;
195 using UnderlyingType = std::underlying_type_t<ValueType>;
197 using BaseType::BaseType;
201 io::ReadBuffer(buffer, v);
202 this->value =
static_cast<ValueType>(v);
211struct Output<T, EnableIfCanUseEnumAsStrongTypedef<T>> {
212 using type =
io::detail::EnumStrongTypedefFormatter<T>;
216struct Input<T, EnableIfCanUseEnumAsStrongTypedef<T>> {
217 using type =
io::detail::EnumStrongTypedefParser<T>;
221struct IsMappedToPg<T, EnableIfCanUseEnumAsStrongTypedef<T>> : std::true_type {};
230struct CppToPg<T,
traits::EnableIfCanUseEnumAsStrongTypedef<T>> : CppToPg<std::underlying_type_t<T>> {};