userver: userver/storages/postgres/io/optional.hpp Source File
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/optional.hpp
4/// @brief Optional values I/O support
5/// @ingroup userver_postgres_parse_and_format
6
7#include <optional>
8
9#include <userver/utils/assert.hpp>
10#include <userver/utils/optional_ref.hpp>
11
12#include <userver/storages/postgres/io/buffer_io.hpp>
13#include <userver/storages/postgres/io/buffer_io_base.hpp>
14#include <userver/storages/postgres/io/nullable_traits.hpp>
15#include <userver/storages/postgres/io/traits.hpp>
16
17#include <boost/optional/optional_fwd.hpp>
18
19USERVER_NAMESPACE_BEGIN
20
21namespace storages::postgres::io {
22
23namespace detail {
24
25template <template <typename> class Optional, typename T, bool Categories = false>
26struct OptionalValueParser : BufferParserBase<Optional<T>> {
27 using BaseType = BufferParserBase<Optional<T>>;
28 using ValueParser = typename traits::IO<T>::ParserType;
29
30 using BaseType::BaseType;
31
32 void operator()(const FieldBuffer& buffer) {
33 T val;
34 ValueParser{val}(buffer);
35 this->value = std::move(val);
36 }
37};
38
39template <template <typename> class Optional, typename T>
40struct OptionalValueParser<Optional, T, true> : BufferParserBase<Optional<T>> {
41 using BaseType = BufferParserBase<Optional<T>>;
42 using ValueParser = typename traits::IO<T>::ParserType;
43
44 using BaseType::BaseType;
45
46 void operator()(const FieldBuffer& buffer, const TypeBufferCategory& categories) {
47 T val;
48 ValueParser{val}(buffer, categories);
49 this->value = std::move(val);
50 }
51};
52
53template <template <typename> class Optional, typename T>
54struct OptionalValueFormatter : BufferFormatterBase<Optional<T>> {
55 using BaseType = BufferFormatterBase<Optional<T>>;
56 using ValueFormatter = typename traits::IO<T>::FormatterType;
57
58 using BaseType::BaseType;
59
60 template <typename Buffer>
61 void operator()(const UserTypes& types, Buffer& buffer) const {
62 if (this->value) {
63 ValueFormatter{*this->value}(types, buffer);
64 }
65 }
66};
67
68} // namespace detail
69
70/// Parser specialization for boost::optional
71template <traits::HasParser T>
72struct BufferParser<boost::optional<T>>
73 : detail::OptionalValueParser<boost::optional, T, detail::kParserRequiresTypeCategories<T>> {
74 using BaseType = detail::OptionalValueParser<boost::optional, T, detail::kParserRequiresTypeCategories<T>>;
75 using BaseType::BaseType;
76};
77
78/// Formatter specialization for boost::optional
79template <traits::HasFormatter T>
80struct BufferFormatter<boost::optional<T>> : detail::OptionalValueFormatter<boost::optional, T> {
81 using BaseType = detail::OptionalValueFormatter<boost::optional, T>;
82 using BaseType::BaseType;
83};
84
85/// Parser specialization for std::optional
86template <traits::HasParser T>
87struct BufferParser<std::optional<T>>
88 : detail::OptionalValueParser<std::optional, T, detail::kParserRequiresTypeCategories<T>> {
89 using BaseType = detail::OptionalValueParser<std::optional, T, detail::kParserRequiresTypeCategories<T>>;
90 using BaseType::BaseType;
91};
92
93/// Formatter specialization for std::optional
94template <traits::HasFormatter T>
95struct BufferFormatter<std::optional<T>> : detail::OptionalValueFormatter<std::optional, T> {
96 using BaseType = detail::OptionalValueFormatter<std::optional, T>;
97 using BaseType::BaseType;
98};
99
100/// Formatter specialization for utils::OptionalRef
101template <traits::HasFormatter T>
102struct BufferFormatter<USERVER_NAMESPACE::utils::OptionalRef<T>>
103 : detail::OptionalValueFormatter<USERVER_NAMESPACE::utils::OptionalRef, T> {
104 using BaseType = detail::OptionalValueFormatter<USERVER_NAMESPACE::utils::OptionalRef, T>;
105 using BaseType::BaseType;
106};
107
108/// Pg mapping specialization for boost::optional
109template <traits::kIsMappedToPg T>
110struct CppToPg<boost::optional<T>> : CppToPg<T> {};
111
112/// Pg mapping specialization for std::optional
113template <traits::kIsMappedToPg T>
114struct CppToPg<std::optional<T>> : CppToPg<T> {};
115
116/// Pg mapping specialization for USERVER_NAMESPACE::utils::OptionalRef
117template <traits::kIsMappedToPg T>
118struct CppToPg<USERVER_NAMESPACE::utils::OptionalRef<T>> : CppToPg<T> {};
119
120namespace traits {
121
122/// Nullability traits for boost::optional
123template <typename T>
124struct IsNullable<boost::optional<T>> : std::true_type {};
125
126template <typename T>
127struct GetSetNull<boost::optional<T>> {
128 using ValueType = boost::optional<T>;
129 inline static bool IsNull(const ValueType& v) { return !v; }
130 inline static void SetNull(ValueType& v) { v = ValueType{}; }
131 inline static void SetDefault(ValueType& v) { v.emplace(); }
132};
133
134template <typename T>
135struct IsMappedToPg<boost::optional<T>> : IsMappedToPg<T> {};
136template <typename T>
137struct IsSpecialMapping<boost::optional<T>> : IsMappedToPg<T> {};
138
139template <typename T>
140struct ParserBufferCategory<BufferParser<boost::optional<T>>>
141 : ParserBufferCategory<typename traits::IO<T>::ParserType> {};
142
143/// Nullability traits for std::optional
144template <typename T>
145struct IsNullable<std::optional<T>> : std::true_type {};
146
147template <typename T>
148struct GetSetNull<std::optional<T>> {
149 using ValueType = std::optional<T>;
150 inline static bool IsNull(const ValueType& v) { return !v; }
151 inline static void SetNull(ValueType& v) { v = std::nullopt; }
152 inline static void SetDefault(ValueType& v) { v.emplace(); }
153};
154
155template <typename T>
156struct IsMappedToPg<std::optional<T>> : IsMappedToPg<T> {};
157template <typename T>
158struct IsSpecialMapping<std::optional<T>> : IsMappedToPg<T> {};
159
160template <typename T>
161struct ParserBufferCategory<BufferParser<std::optional<T>>> : ParserBufferCategory<typename traits::IO<T>::ParserType> {
162};
163
164/// Nullability traits for USERVER_NAMESPACE::utils::OptionalRef
165template <typename T>
166struct IsNullable<USERVER_NAMESPACE::utils::OptionalRef<T>> : std::true_type {};
167
168template <typename T>
169struct GetSetNull<USERVER_NAMESPACE::utils::OptionalRef<T>> {
170 using ValueType = USERVER_NAMESPACE::utils::OptionalRef<T>;
171 inline static bool IsNull(const ValueType& v) { return !v; }
172 inline static void SetNull(ValueType&) { static_assert(!sizeof(T), "SetNull not enabled for utils::OptionalRef"); }
173 inline static void SetDefault(ValueType&) {
174 static_assert(!sizeof(T), "SetDefault not enabled for utils::OptionalRef");
175 }
176};
177
178template <typename T>
179struct IsMappedToPg<USERVER_NAMESPACE::utils::OptionalRef<T>> : IsMappedToPg<T> {};
180template <typename T>
181struct IsSpecialMapping<USERVER_NAMESPACE::utils::OptionalRef<T>> : IsMappedToPg<T> {};
182
183} // namespace traits
184
185} // namespace storages::postgres::io
186
187USERVER_NAMESPACE_END