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