userver: userver/storages/postgres/io/traits.hpp Source File
Loading...
Searching...
No Matches
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