userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
result_set.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/storages/postgres/result_set.hpp
4
/// @brief Result accessors
5
6
#
include
<
limits
>
7
#
include
<
memory
>
8
#
include
<
optional
>
9
#
include
<
type_traits
>
10
#
include
<
utility
>
11
12
#
include
<
fmt
/
format
.
h
>
13
14
#
include
<
userver
/
storages
/
postgres
/
detail
/
typed_rows
.
hpp
>
15
#
include
<
userver
/
storages
/
postgres
/
exceptions
.
hpp
>
16
#
include
<
userver
/
storages
/
postgres
/
io
/
supported_types
.
hpp
>
17
#
include
<
userver
/
storages
/
postgres
/
row
.
hpp
>
18
19
#
include
<
userver
/
compiler
/
demangle
.
hpp
>
20
#
include
<
userver
/
logging
/
log
.
hpp
>
21
22
USERVER_NAMESPACE_BEGIN
23
24
namespace
storages::
postgres
{
25
26
template
<
typename
T,
typename
ExtractionTag>
27
class
TypedResultSet
;
28
29
/// @brief PostgreSQL result set
30
///
31
/// Provides random access to rows via indexing operations
32
/// and bidirectional iteration via iterators.
33
///
34
/// ## Usage synopsis
35
/// ```
36
/// auto trx = ...;
37
/// auto res = trx.Execute("select a, b from table");
38
/// for (auto row : res) {
39
/// // Process row data
40
/// }
41
/// ```
42
class
ResultSet
{
43
public
:
44
using
size_type = std::size_t;
45
using
difference_type = std::ptrdiff_t;
46
static
constexpr
size_type npos = std::numeric_limits<size_type>::max();
47
48
//@{
49
/** @name Row container concept */
50
using
const_iterator =
ConstRowIterator
;
51
using
const_reverse_iterator =
ReverseConstRowIterator
;
52
53
using
value_type =
Row
;
54
using
reference = value_type;
55
using
pointer = const_iterator;
56
//@}
57
58
explicit
ResultSet(std::shared_ptr<detail::ResultWrapper> pimpl)
59
: pimpl_{std::move(pimpl)}
60
{}
61
62
/// Number of rows in the result set
63
size_type
Size
()
const
;
64
bool
IsEmpty()
const
{
return
Size
(
)
== 0; }
65
66
size_type RowsAffected()
const
;
67
std::string CommandStatus()
const
;
68
69
//@{
70
/** @name Row container interface */
71
//@{
72
/** @name Forward iteration */
73
const_iterator cbegin()
const
&;
74
const_iterator begin()
const
& {
return
cbegin(); }
75
const_iterator cend()
const
&;
76
const_iterator end()
const
& {
return
cend(); }
77
78
// One should store ResultSet before using its accessors
79
const_iterator cbegin()
const
&& =
delete
;
80
const_iterator begin()
const
&& =
delete
;
81
const_iterator cend()
const
&& =
delete
;
82
const_iterator end()
const
&& =
delete
;
83
//@}
84
//@{
85
/** @name Reverse iteration */
86
const_reverse_iterator crbegin()
const
&;
87
const_reverse_iterator rbegin()
const
& {
return
crbegin(); }
88
const_reverse_iterator crend()
const
&;
89
const_reverse_iterator rend()
const
& {
return
crend(); }
90
// One should store ResultSet before using its accessors
91
const_reverse_iterator crbegin()
const
&& =
delete
;
92
const_reverse_iterator rbegin()
const
&& =
delete
;
93
const_reverse_iterator crend()
const
&& =
delete
;
94
const_reverse_iterator rend()
const
&& =
delete
;
95
//@}
96
97
reference Front()
const
&;
98
reference Back()
const
&;
99
// One should store ResultSet before using its accessors
100
reference Front()
const
&& =
delete
;
101
reference Back()
const
&& =
delete
;
102
103
/// @brief Access a row by index
104
/// @throws RowIndexOutOfBounds if index is out of bounds
105
reference
operator
[](size_type index)
const
&;
106
// One should store ResultSet before using its accessors
107
reference operator[](size_type index)
const
&& =
delete
;
108
//@}
109
110
//@{
111
/** @name ResultSet metadata access */
112
// TODO ResultSet metadata access interface
113
size_type FieldCount()
const
;
114
RowDescription
GetRowDescription()
const
& {
return
{pimpl_}; }
115
// One should store ResultSet before using its accessors
116
RowDescription
GetRowDescription()
const
&& =
delete
;
117
//@}
118
119
//@{
120
/** @name Typed results */
121
/// @brief Get a wrapper for iterating over a set of typed results.
122
/// For more information see @ref scripts/docs/en/userver/pg/user_row_types.md
123
template
<
typename
T>
124
auto
AsSetOf
()
const
;
125
template
<
typename
T>
126
auto
AsSetOf(
RowTag
)
const
;
127
template
<
typename
T>
128
auto
AsSetOf(
FieldTag
)
const
;
129
130
/// @brief Extract data into a container.
131
/// For more information see @ref scripts/docs/en/userver/pg/user_row_types.md
132
template
<
typename
Container>
133
Container
AsContainer
()
const
;
134
template
<
typename
Container>
135
Container AsContainer(
RowTag
)
const
;
136
137
/// @brief Extract first row into user type.
138
/// A single row result set is expected, will throw an exception when result
139
/// set size != 1
140
template
<
typename
T>
141
auto
AsSingleRow
()
const
;
142
template
<
typename
T>
143
auto
AsSingleRow(
RowTag
)
const
;
144
template
<
typename
T>
145
auto
AsSingleRow(
FieldTag
)
const
;
146
147
/// @brief Extract first row into user type.
148
/// @returns A single row result set if non empty result was returned, empty
149
/// std::optional otherwise
150
/// @throws exception when result set size > 1
151
template
<
typename
T>
152
std::optional<T>
AsOptionalSingleRow
()
const
;
153
template
<
typename
T>
154
std::optional<T> AsOptionalSingleRow(
RowTag
)
const
;
155
template
<
typename
T>
156
std::optional<T> AsOptionalSingleRow(
FieldTag
)
const
;
157
//@}
158
private
:
159
friend
class
detail::ConnectionImpl;
160
void
FillBufferCategories(
const
UserTypes
& types);
161
void
SetBufferCategoriesFrom(
const
ResultSet
&);
162
163
template
<
typename
T,
typename
Tag>
164
friend
class
TypedResultSet
;
165
friend
class
ConnectionImpl;
166
167
std::shared_ptr<detail::ResultWrapper> pimpl_;
168
};
169
170
template
<
typename
T>
171
auto
ResultSet
::
AsSetOf
()
const
{
172
return
AsSetOf<T>(kFieldTag);
173
}
174
175
template
<
typename
T>
176
auto
ResultSet
::AsSetOf(
RowTag
)
const
{
177
detail::AssertSaneTypeToDeserialize<T>();
178
using
ValueType = std::remove_cvref_t<T>;
179
io
::
traits
::AssertIsValidRowType<ValueType>();
180
return
TypedResultSet
<T,
RowTag
>{*
this
};
181
}
182
183
template
<
typename
T>
184
auto
ResultSet
::AsSetOf(
FieldTag
)
const
{
185
detail::AssertSaneTypeToDeserialize<T>();
186
using
ValueType = std::remove_cvref_t<T>;
187
detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
188
if
(FieldCount() > 1) {
189
throw
NonSingleColumnResultSet
{FieldCount(),
compiler
::GetTypeName<T>(),
"AsSetOf"
};
190
}
191
return
TypedResultSet
<T,
FieldTag
>{*
this
};
192
}
193
194
template
<
typename
Container>
195
Container
ResultSet
::
AsContainer
()
const
{
196
detail::AssertSaneTypeToDeserialize<Container>();
197
using
ValueType =
typename
Container::value_type;
198
Container c;
199
if
constexpr
(
io
::
traits
::
CanReserve
<Container>) {
200
c.reserve(
Size
(
)
);
201
}
202
auto
res = AsSetOf<ValueType>();
203
204
auto
inserter =
io
::
traits
::Inserter(c);
205
auto
row_it = res.begin();
206
for
(std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
207
*inserter = *row_it;
208
}
209
210
return
c;
211
}
212
213
template
<
typename
Container>
214
Container
ResultSet
::AsContainer(
RowTag
)
const
{
215
detail::AssertSaneTypeToDeserialize<Container>();
216
using
ValueType =
typename
Container::value_type;
217
Container c;
218
if
constexpr
(
io
::
traits
::
CanReserve
<Container>) {
219
c.reserve(
Size
(
)
);
220
}
221
auto
res = AsSetOf<ValueType>(kRowTag);
222
223
auto
inserter =
io
::
traits
::Inserter(c);
224
auto
row_it = res.begin();
225
for
(std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
226
*inserter = *row_it;
227
}
228
229
return
c;
230
}
231
232
template
<
typename
T>
233
auto
ResultSet
::
AsSingleRow
()
const
{
234
return
AsSingleRow<T>(kFieldTag);
235
}
236
237
template
<
typename
T>
238
auto
ResultSet
::AsSingleRow(
RowTag
)
const
{
239
detail::AssertSaneTypeToDeserialize<T>();
240
if
(
Size
(
)
!= 1) {
241
throw
NonSingleRowResultSet
{
Size
(
)
};
242
}
243
return
Front().As<T>(kRowTag);
244
}
245
246
template
<
typename
T>
247
auto
ResultSet
::AsSingleRow(
FieldTag
)
const
{
248
detail::AssertSaneTypeToDeserialize<T>();
249
if
(
Size
(
)
!= 1) {
250
throw
NonSingleRowResultSet
{
Size
(
)
};
251
}
252
return
Front().As<T>(kFieldTag);
253
}
254
255
template
<
typename
T>
256
std::optional<T>
ResultSet
::
AsOptionalSingleRow
()
const
{
257
return
AsOptionalSingleRow<T>(kFieldTag);
258
}
259
260
template
<
typename
T>
261
std::optional<T>
ResultSet
::AsOptionalSingleRow(
RowTag
)
const
{
262
return
IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kRowTag)};
263
}
264
265
template
<
typename
T>
266
std::optional<T>
ResultSet
::AsOptionalSingleRow(
FieldTag
)
const
{
267
return
IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kFieldTag)};
268
}
269
270
template
<
typename
T,
typename
ExtractionTag>
271
class
TypedResultSet
{
272
public
:
273
using
size_type =
ResultSet
::size_type;
274
using
difference_type =
ResultSet
::difference_type;
275
static
constexpr
size_type npos =
ResultSet
::npos;
276
static
constexpr
ExtractionTag kExtractTag{};
277
278
//@{
279
/** @name Row container concept */
280
using
const_iterator = detail::ConstTypedRowIterator<T, ExtractionTag, detail::IteratorDirection::kForward>;
281
using
const_reverse_iterator = detail::ConstTypedRowIterator<T, ExtractionTag, detail::IteratorDirection::kReverse>;
282
283
using
value_type = T;
284
using
pointer = const_iterator;
285
286
// Forbidding assignments to operator[] result in debug, getting max
287
// performance in release.
288
#
ifdef
NDEBUG
289
using
reference
=
value_type
;
290
#
else
291
using
reference = std::add_const_t<value_type>;
292
#
endif
293
294
//@}
295
explicit
TypedResultSet(
ResultSet
result)
296
: result_{std::move(result)}
297
{}
298
299
/// Number of rows in the result set
300
size_type
Size
()
const
{
return
result_
.
Size
(
)
; }
301
bool
IsEmpty()
const
{
return
Size
(
)
== 0; }
302
//@{
303
/** @name Container interface */
304
//@{
305
/** @name Row container interface */
306
//@{
307
/** @name Forward iteration */
308
const_iterator cbegin()
const
& {
return
const_iterator{result_.pimpl_, 0}; }
309
const_iterator begin()
const
& {
return
cbegin(); }
310
const_iterator cend()
const
& {
return
const_iterator{result_.pimpl_,
Size
(
)
}; }
311
const_iterator end()
const
& {
return
cend(); }
312
const_iterator cbegin()
const
&& { ReportMisuse(); }
313
const_iterator begin()
const
&& { ReportMisuse(); }
314
const_iterator cend()
const
&& { ReportMisuse(); }
315
const_iterator end()
const
&& { ReportMisuse(); }
316
//@}
317
//@{
318
/** @name Reverse iteration */
319
const_reverse_iterator crbegin()
const
& {
return
const_reverse_iterator(result_.pimpl_,
Size
(
)
- 1); }
320
const_reverse_iterator rbegin()
const
& {
return
crbegin(); }
321
const_reverse_iterator crend()
const
& {
return
const_reverse_iterator(result_.pimpl_, npos); }
322
const_reverse_iterator rend()
const
& {
return
crend(); }
323
const_reverse_iterator crbegin()
const
&& { ReportMisuse(); }
324
const_reverse_iterator rbegin()
const
&& { ReportMisuse(); }
325
const_reverse_iterator crend()
const
&& { ReportMisuse(); }
326
const_reverse_iterator rend()
const
&& { ReportMisuse(); }
327
//@}
328
/// @brief Access a row by index
329
/// @throws RowIndexOutOfBounds if index is out of bounds
330
// NOLINTNEXTLINE(readability-const-return-type)
331
reference
operator
[](size_type index)
const
& {
return
result_
[
index
]
.
template
As<value_type>(kExtractTag); }
332
// NOLINTNEXTLINE(readability-const-return-type)
333
reference operator[](size_type)
const
&& { ReportMisuse(); }
334
//@}
335
private
:
336
[[
noreturn
]]
static
void
ReportMisuse() {
337
static_assert
(!
sizeof
(T),
"keep the TypedResultSet before using, please"
);
338
}
339
340
ResultSet
result_;
341
};
342
343
}
// namespace storages::postgres
344
345
USERVER_NAMESPACE_END
userver
storages
postgres
result_set.hpp
Generated on
for userver by
Doxygen
1.17.0