userver
C++ Async Framework
Loading...
Searching...
No Matches
typed_result_set.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/storages/postgres/typed_result_set.hpp
4
/// @brief Typed PostgreSQL results
5
6
#
include
<
type_traits
>
7
8
#
include
<
userver
/
storages
/
postgres
/
detail
/
typed_rows
.
hpp
>
9
#
include
<
userver
/
storages
/
postgres
/
result_set
.
hpp
>
10
11
USERVER_NAMESPACE_BEGIN
12
13
namespace
storages
::
postgres
{
14
15
/// @page pg_user_row_types uPg: Typed PostgreSQL results
16
///
17
/// The ResultSet provides access to a generic PostgreSQL result buffer wrapper
18
/// with access to individual column buffers and means to parse the buffers into
19
/// a certain type.
20
///
21
/// For a user that wishes to get the results in a form of a sequence or a
22
/// container of C++ tuples or structures, the driver provides a way to coerce
23
/// the generic result set into a typed result set or a container of tuples or
24
/// structures that fulfill certain conditions.
25
///
26
/// TypedResultSet provides container interface for typed result rows for
27
/// iteration or random access without converting all the result set at once.
28
/// The iterators in the TypedResultSet satisfy requirements for a constant
29
/// RandomAccessIterator with the exception of dereferencing iterators.
30
///
31
/// @warning The operator* of the iterators returns value (not a reference to
32
/// it) and the iterators don't have the operator->.
33
///
34
/// @par Data row extraction
35
///
36
/// The data rows can be obtained as:
37
/// - std::tuple;
38
/// - aggregate class as is;
39
/// - non-aggregate class with some augmentation.
40
///
41
/// Data members of the tuple or the classes must be supported by the driver.
42
/// For more information on supported data types please see @ref pg_types
43
///
44
/// @par std::tuple.
45
///
46
/// The first option is to convert ResultSet's row to std::tuples.
47
///
48
/// ```
49
/// using MyRowType = std::tuple<int, string>;
50
/// auto trx = ...;
51
/// auto generic_result = trx.Execute("select a, b from my_table");
52
/// auto iteration = generic_result.AsSetOf<MyRowType>();
53
/// for (auto row : iteration) {
54
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
55
/// "Iterate over tuples");
56
/// auto [a, b] = row;
57
/// std::cout << "a = " << a << "; b = " << b << "\n";
58
/// }
59
///
60
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
61
/// ```
62
///
63
/// @par Aggregate classes.
64
///
65
/// A data row can be coerced to an aggregate class.
66
///
67
/// An aggregate class (C++03 8.5.1 §1) is a class that with no base classes, no
68
/// protected or private non-static data members, no user-declared constructors
69
/// and no virtual functions.
70
///
71
/// ```
72
/// struct MyRowType {
73
/// int a;
74
/// std::string b;
75
/// };
76
/// auto generic_result = trx.Execute("select a, b from my_table");
77
/// auto iteration = generic_result.AsSetOf<MyRowType>();
78
/// for (auto row : iteration) {
79
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
80
/// "Iterate over aggregate classes");
81
/// std::cout << "a = " << row.a << "; b = " << row.b << "\n";
82
/// }
83
///
84
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
85
/// ```
86
///
87
/// @par Non-aggregate classes.
88
///
89
/// Classes that do not satisfy the aggregate class requirements can be used
90
/// to be created from data rows by providing additional `Introspect` non-static
91
/// member function. The function should return a tuple of references to
92
/// member data fields. The class must be default constructible.
93
///
94
/// ```
95
/// class MyRowType {
96
/// private:
97
/// int a_;
98
/// std::string b_;
99
/// public:
100
/// MyRowType() = default; // default ctor is required
101
/// explicit MyRowType(int x);
102
///
103
/// auto Introspect() {
104
/// return std::tie(a_, b_);
105
/// }
106
/// int GetA() const;
107
/// const std::string& GetB() const;
108
/// };
109
///
110
/// auto generic_result = trx.Execute("select a, b from my_table");
111
/// auto iteration = generic_result.AsSetOf<MyRowType>();
112
/// for (auto row : iteration) {
113
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
114
/// "Iterate over non-aggregate classes");
115
/// std::cout << "a = " << row.GetA() << "; b = " << row.GetB() << "\n";
116
/// }
117
///
118
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
119
/// ```
120
/// @par Single-column result set
121
///
122
/// A single-column result set can be used to extract directly to the column
123
/// type. User types mapped to PostgreSQL will work as well. If you need to
124
/// extract the whole row into such a structure, you will need to disambiguate
125
/// the call with the kRowTag.
126
///
127
/// @code
128
/// auto string_set = generic_result.AsSetOf<std::string>();
129
/// std::string s = string_set[0];
130
///
131
/// auto string_vec = generic_result.AsContainer<std::vector<std::string>>();
132
///
133
/// // Extract first column into the composite type
134
/// auto foo_set = generic_result.AsSetOf<FooBar>();
135
/// auto foo_vec = generic_result.AsContainer<std::vector<FooBar>>();
136
///
137
/// // Extract the whole row, disambiguation
138
/// auto foo_set = generic_result.AsSetOf<FooBar>(kRowTag);
139
///
140
/// @endcode
141
///
142
///
143
/// ----------
144
///
145
/// @htmlonly <div class="bottom-nav"> @endhtmlonly
146
/// ⇦ @ref pg_types | @ref pg_errors ⇨
147
/// @htmlonly </div> @endhtmlonly
148
149
template
<
typename
T
,
typename
ExtractionTag
>
150
class
TypedResultSet
{
151
public
:
152
using
size_type
=
ResultSet
::
size_type
;
153
using
difference_type
=
ResultSet
::
difference_type
;
154
static
constexpr
size_type
npos
=
ResultSet
::
npos
;
155
static
constexpr
ExtractionTag
kExtractTag
{};
156
157
//@{
158
/** @name Row container concept */
159
using
const_iterator
=
160
detail
::
ConstTypedRowIterator
<
T
,
ExtractionTag
,
161
detail
::
IteratorDirection
::
kForward
>;
162
using
const_reverse_iterator
=
163
detail
::
ConstTypedRowIterator
<
T
,
ExtractionTag
,
164
detail
::
IteratorDirection
::
kReverse
>;
165
166
using
value_type
=
T
;
167
using
pointer
=
const_iterator
;
168
169
// Forbidding assignments to operator[] result in debug, getting max
170
// performance in release.
171
#
ifdef
NDEBUG
172
using
reference
=
value_type
;
173
#
else
174
using
reference
=
std
::
add_const_t
<
value_type
>;
175
#
endif
176
177
//@}
178
explicit
TypedResultSet
(
ResultSet
result
) :
result_
{
std
::
move
(
result
)} {}
179
180
/// Number of rows in the result set
181
size_type
Size
()
const
{
return
result_
.
Size
(); }
182
bool
IsEmpty
()
const
{
return
Size
() == 0; }
183
//@{
184
/** @name Container interface */
185
//@{
186
/** @name Row container interface */
187
//@{
188
/** @name Forward iteration */
189
const_iterator
cbegin
()
const
& {
return
const_iterator
{
result_
.
pimpl_
, 0}; }
190
const_iterator
begin
()
const
& {
return
cbegin
(); }
191
const_iterator
cend
()
const
& {
192
return
const_iterator
{
result_
.
pimpl_
,
Size
()};
193
}
194
const_iterator
end
()
const
& {
return
cend
(); }
195
const_iterator
cbegin
()
const
&& {
ReportMisuse
(); }
196
const_iterator
begin
()
const
&& {
ReportMisuse
(); }
197
const_iterator
cend
()
const
&& {
ReportMisuse
(); }
198
const_iterator
end
()
const
&& {
ReportMisuse
(); }
199
//@}
200
//@{
201
/** @name Reverse iteration */
202
const_reverse_iterator
crbegin
()
const
& {
203
return
const_reverse_iterator
(
result_
.
pimpl_
,
Size
() - 1);
204
}
205
const_reverse_iterator
rbegin
()
const
& {
return
crbegin
(); }
206
const_reverse_iterator
crend
()
const
& {
207
return
const_reverse_iterator
(
result_
.
pimpl_
,
npos
);
208
}
209
const_reverse_iterator
rend
()
const
& {
return
crend
(); }
210
const_reverse_iterator
crbegin
()
const
&& {
ReportMisuse
(); }
211
const_reverse_iterator
rbegin
()
const
&& {
ReportMisuse
(); }
212
const_reverse_iterator
crend
()
const
&& {
ReportMisuse
(); }
213
const_reverse_iterator
rend
()
const
&& {
ReportMisuse
(); }
214
//@}
215
/// @brief Access a row by index
216
/// @throws RowIndexOutOfBounds if index is out of bounds
217
// NOLINTNEXTLINE(readability-const-return-type)
218
reference
operator
[](
size_type
index
)
const
& {
219
return
result_
[
index
].
template
As
<
value_type
>(
kExtractTag
);
220
}
221
// NOLINTNEXTLINE(readability-const-return-type)
222
reference
operator
[](
size_type
)
const
&& {
ReportMisuse
(); }
223
//@}
224
private
:
225
[[
noreturn
]]
static
void
ReportMisuse
() {
226
static_assert
(!
sizeof
(
T
),
"keep the TypedResultSet before using, please"
);
227
}
228
229
ResultSet
result_
;
230
};
231
232
}
// namespace storages::postgres
233
234
USERVER_NAMESPACE_END
userver
storages
postgres
typed_result_set.hpp
Generated on Wed Mar 27 2024 19:19:20 for userver by
Doxygen
1.10.0