userver: userver/storages/postgres/io/traits.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
traits.hpp
1#pragma once
2
3#include <limits>
4#include <string>
5#include <type_traits>
6#include <unordered_map>
7
8#include <userver/storages/postgres/detail/is_decl_complete.hpp>
9#include <userver/storages/postgres/io/pg_types.hpp>
10#include <userver/utils/void_t.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace storages::postgres {
15
16class UserTypes;
17
18namespace io {
19
20/// Category of buffer contents.
21///
22/// Applied to binary parsers and deduced from field's data type.
23enum class BufferCategory {
24 kKeepCategory = -1, //!< kKeepCategory keep current buffer category
25 kNoParser = 0, //!< kNoParser the data type doesn't have a parser defined
26 kVoid, //!< kVoid there won't be a buffer for this field, but the category is
27 //!< required for correctly handling void results
28 kPlainBuffer, //!< kPlainBuffer the buffer is a single plain value
29 kArrayBuffer, //!< kArrayBuffer the buffer contains an array of values
30 kCompositeBuffer, //!< kCompositeBuffer the buffer contains a user-defined
31 //!< composite type
32 kRangeBuffer //!< kRangeBuffer the buffer contains a range type
33};
34
35const std::string& ToString(BufferCategory);
36
37template <BufferCategory Category>
39
41
42BufferCategory GetTypeBufferCategory(const TypeBufferCategory&, Oid);
43
44struct BufferCategoryHash {
46 std::size_t operator()(BufferCategory val) const {
47 return std::hash<IntegerType>{}(static_cast<IntegerType>(val));
48 }
49};
50
51inline constexpr int kPgBinaryDataFormat = 1;
52
53/// Fields that are null are denoted by specifying their length == -1
54inline constexpr Integer kPgNullBufferSize = -1;
55
56struct FieldBuffer {
57 static constexpr std::size_t npos = std::numeric_limits<std::size_t>::max();
58
59 bool is_null = false;
61 std::size_t length = 0;
62 const std::uint8_t* buffer = nullptr;
63
64 std::string ToString() const {
65 return {reinterpret_cast<const char*>(buffer), length};
66 }
67 constexpr FieldBuffer GetSubBuffer(
68 std::size_t offset, std::size_t size = npos,
70
71 template <typename T>
72 std::size_t Read(T&& value,
74 std::size_t length = sizeof(T));
75 template <typename T>
76 std::size_t Read(T&& value, const TypeBufferCategory& categories,
77 std::size_t length = sizeof(T),
79
80 // Read 'raw' postgres buffer - first read the size, then read the value
81 template <typename T>
82 std::size_t ReadRaw(T&& value, const TypeBufferCategory& categories,
84};
85
86/// @brief Primary template for Postgre buffer parser.
87/// Specialisations should provide call operators that parse FieldBuffer.
88template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
89struct BufferParser;
90
91/// @brief Primary template for Postgre buffer formatter
92/// Specialisations should provide call operators that write to a buffer.
93template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
94struct BufferFormatter;
95
96namespace traits {
97
98/// Customisation point for parsers
99template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
100struct Input {
101 using type = BufferParser<T>;
102};
103
104/// Customisation point for formatters
105template <typename T, typename Enable = USERVER_NAMESPACE::utils::void_t<>>
106struct Output {
107 using type = BufferFormatter<T>;
108};
109
110/// @brief A default deducer of parsers/formatters for a type/data format.
111/// Can be specialised for a type/format pair providing custom
112/// parsers/formatters.
113template <typename T>
114struct IO {
115 using ParserType = typename Input<T>::type;
116 using FormatterType = typename Output<T>::type;
117};
118
119/// @brief Metafunction to detect if a type has a parser.
120template <typename T>
121struct HasParser : utils::IsDeclComplete<typename IO<T>::ParserType> {};
122
123/// @brief Metafunction to detect if a type has a formatter.
124template <typename T>
125struct HasFormatter : utils::IsDeclComplete<typename IO<T>::FormatterType> {};
126
127//@{
128/** @name Shortcut metafunction result values */
129template <typename T>
130inline constexpr bool kHasParser = HasParser<T>::value;
131template <typename T>
132inline constexpr bool kHasFormatter = HasFormatter<T>::value;
133//@}
134
135template <typename T>
136constexpr bool CheckParser() {
137 static_assert(kHasParser<T> || std::is_enum_v<T>,
138 "Type doesn't have a parser. Probably you forgot to include "
139 "file with parser or to define your own. Please see page "
140 "`uPg: Supported data types` for more information");
141
142 static_assert(kHasParser<T> || !std::is_enum_v<T>,
143 "Type doesn't have a parser. Probably you forgot to include "
144 "file with parser, to define your own or to specialize "
145 "`storages::postgres::io::traits::CanUseEnumAsStrongTypedef`. "
146 "See page `uPg: Supported data types` for more information");
147
148 return true;
149}
150
151template <typename T>
152constexpr void CheckFormatter() {
153 static_assert(kHasFormatter<T> || std::is_enum_v<T>,
154 "Type doesn't have a formatter. Probably you forgot to include "
155 "file with formatter or to define your own. Please see page "
156 "`uPg: Supported data types` for more information");
157
158 static_assert(kHasFormatter<T> || !std::is_enum_v<T>,
159 "Type doesn't have a formatter. Probably you forgot to include "
160 "file with formatter, to define your own or to specialize "
161 "`storages::postgres::io::traits::CanUseEnumAsStrongTypedef`. "
162 "See page `uPg: Supported data types` for more information");
163}
164
165/// Buffer category for parser
166template <typename T>
169template <typename T>
170using ParserBufferCategoryType = typename ParserBufferCategory<T>::type;
171template <typename T>
172inline constexpr BufferCategory kParserBufferCategory =
173 ParserBufferCategory<T>::value;
174
175//@{
176/** @name Buffer category for a type */
177namespace detail {
178template <typename T>
179constexpr auto DetectBufferCategory() {
180 if constexpr (kHasParser<T>) {
181 return ParserBufferCategoryType<typename IO<T>::ParserType>{};
182 } else {
183 return BufferCategoryConstant<BufferCategory::kNoParser>{};
184 }
185}
186} // namespace detail
187template <typename T>
188struct TypeBufferCategory : decltype(detail::DetectBufferCategory<T>()) {};
189template <typename T>
190inline constexpr BufferCategory kTypeBufferCategory =
191 TypeBufferCategory<T>::value;
192//@}
193
194namespace detail {
195
196template <typename T>
197struct CustomParserDefined : utils::IsDeclComplete<BufferParser<T>> {};
198template <typename T>
199inline constexpr bool kCustomParserDefined = CustomParserDefined<T>::value;
200
201template <typename T>
202struct CustomFormatterDefined : utils::IsDeclComplete<BufferFormatter<T>> {};
203template <typename T>
204inline constexpr bool kCustomFormatterDefined =
205 CustomFormatterDefined<T>::value;
206
207} // namespace detail
208
209} // namespace traits
210
211} // namespace io
212} // namespace storages::postgres
213
214USERVER_NAMESPACE_END