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
43
/// @ref scripts/docs/en/userver/pg_types.md.
44
///
45
/// @par std::tuple.
46
///
47
/// The first option is to convert ResultSet's row to std::tuples.
48
///
49
/// ```
50
/// using MyRowType = std::tuple<int, string>;
51
/// auto trx = ...;
52
/// auto generic_result = trx.Execute("select a, b from my_table");
53
/// auto iteration = generic_result.AsSetOf<MyRowType>();
54
/// for (auto row : iteration) {
55
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
56
/// "Iterate over tuples");
57
/// auto [a, b] = row;
58
/// std::cout << "a = " << a << "; b = " << b << "\n";
59
/// }
60
///
61
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
62
/// ```
63
///
64
/// @par Aggregate classes.
65
///
66
/// A data row can be coerced to an aggregate class.
67
///
68
/// An aggregate class (C++03 8.5.1 §1) is a class that with no base classes, no
69
/// protected or private non-static data members, no user-declared constructors
70
/// and no virtual functions.
71
///
72
/// ```
73
/// struct MyRowType {
74
/// int a;
75
/// std::string b;
76
/// };
77
/// auto generic_result = trx.Execute("select a, b from my_table");
78
/// auto iteration = generic_result.AsSetOf<MyRowType>();
79
/// for (auto row : iteration) {
80
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
81
/// "Iterate over aggregate classes");
82
/// std::cout << "a = " << row.a << "; b = " << row.b << "\n";
83
/// }
84
///
85
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
86
/// ```
87
///
88
/// @par Non-aggregate classes.
89
///
90
/// Classes that do not satisfy the aggregate class requirements can be used
91
/// to be created from data rows by providing additional `Introspect` non-static
92
/// member function. The function should return a tuple of references to
93
/// member data fields. The class must be default constructible.
94
///
95
/// ```
96
/// class MyRowType {
97
/// private:
98
/// int a_;
99
/// std::string b_;
100
/// public:
101
/// MyRowType() = default; // default ctor is required
102
/// explicit MyRowType(int x);
103
///
104
/// auto Introspect() {
105
/// return std::tie(a_, b_);
106
/// }
107
/// int GetA() const;
108
/// const std::string& GetB() const;
109
/// };
110
///
111
/// auto generic_result = trx.Execute("select a, b from my_table");
112
/// auto iteration = generic_result.AsSetOf<MyRowType>();
113
/// for (auto row : iteration) {
114
/// static_assert(std::is_same_v<decltype(row), MyRowType>,
115
/// "Iterate over non-aggregate classes");
116
/// std::cout << "a = " << row.GetA() << "; b = " << row.GetB() << "\n";
117
/// }
118
///
119
/// auto data = geric_result.AsContainer<std::vector<MyRowType>>();
120
/// ```
121
/// @par Single-column result set
122
///
123
/// A single-column result set can be used to extract directly to the column
124
/// type. User types mapped to PostgreSQL will work as well. If you need to
125
/// extract the whole row into such a structure, you will need to disambiguate
126
/// the call with the kRowTag.
127
///
128
/// @code
129
/// auto string_set = generic_result.AsSetOf<std::string>();
130
/// std::string s = string_set[0];
131
///
132
/// auto string_vec = generic_result.AsContainer<std::vector<std::string>>();
133
///
134
/// // Extract first column into the composite type
135
/// auto foo_set = generic_result.AsSetOf<FooBar>();
136
/// auto foo_vec = generic_result.AsContainer<std::vector<FooBar>>();
137
///
138
/// // Extract the whole row, disambiguation
139
/// auto foo_set = generic_result.AsSetOf<FooBar>(kRowTag);
140
///
141
/// @endcode
142
///
143
///
144
/// ----------
145
///
146
/// @htmlonly <div class="bottom-nav"> @endhtmlonly
147
/// ⇦ @ref scripts/docs/en/userver/pg_types.md | @ref pg_errors ⇨
148
/// @htmlonly </div> @endhtmlonly
149
150
template
<
typename
T
,
typename
ExtractionTag
>
151
class
TypedResultSet
{
152
public
:
153
using
size_type
=
ResultSet
::
size_type
;
154
using
difference_type
=
ResultSet
::
difference_type
;
155
static
constexpr
size_type
npos
=
ResultSet
::
npos
;
156
static
constexpr
ExtractionTag
kExtractTag
{};
157
158
//@{
159
/** @name Row container concept */
160
using
const_iterator
=
detail
::
ConstTypedRowIterator
<
T
,
ExtractionTag
,
detail
::
IteratorDirection
::
kForward
>;
161
using
const_reverse_iterator
=
detail
::
ConstTypedRowIterator
<
T
,
ExtractionTag
,
detail
::
IteratorDirection
::
kReverse
>;
162
163
using
value_type
=
T
;
164
using
pointer
=
const_iterator
;
165
166
// Forbidding assignments to operator[] result in debug, getting max
167
// performance in release.
168
#
ifdef
NDEBUG
169
using
reference
=
value_type
;
170
#
else
171
using
reference
=
std
::
add_const_t
<
value_type
>;
172
#
endif
173
174
//@}
175
explicit
TypedResultSet
(
ResultSet
result
) :
result_
{
std
::
move
(
result
)} {}
176
177
/// Number of rows in the result set
178
size_type
Size
()
const
{
return
result_
.
Size
(); }
179
bool
IsEmpty
()
const
{
return
Size
() == 0; }
180
//@{
181
/** @name Container interface */
182
//@{
183
/** @name Row container interface */
184
//@{
185
/** @name Forward iteration */
186
const_iterator
cbegin
()
const
& {
return
const_iterator
{
result_
.
pimpl_
, 0}; }
187
const_iterator
begin
()
const
& {
return
cbegin
(); }
188
const_iterator
cend
()
const
& {
return
const_iterator
{
result_
.
pimpl_
,
Size
()}; }
189
const_iterator
end
()
const
& {
return
cend
(); }
190
const_iterator
cbegin
()
const
&& {
ReportMisuse
(); }
191
const_iterator
begin
()
const
&& {
ReportMisuse
(); }
192
const_iterator
cend
()
const
&& {
ReportMisuse
(); }
193
const_iterator
end
()
const
&& {
ReportMisuse
(); }
194
//@}
195
//@{
196
/** @name Reverse iteration */
197
const_reverse_iterator
crbegin
()
const
& {
return
const_reverse_iterator
(
result_
.
pimpl_
,
Size
() - 1); }
198
const_reverse_iterator
rbegin
()
const
& {
return
crbegin
(); }
199
const_reverse_iterator
crend
()
const
& {
return
const_reverse_iterator
(
result_
.
pimpl_
,
npos
); }
200
const_reverse_iterator
rend
()
const
& {
return
crend
(); }
201
const_reverse_iterator
crbegin
()
const
&& {
ReportMisuse
(); }
202
const_reverse_iterator
rbegin
()
const
&& {
ReportMisuse
(); }
203
const_reverse_iterator
crend
()
const
&& {
ReportMisuse
(); }
204
const_reverse_iterator
rend
()
const
&& {
ReportMisuse
(); }
205
//@}
206
/// @brief Access a row by index
207
/// @throws RowIndexOutOfBounds if index is out of bounds
208
// NOLINTNEXTLINE(readability-const-return-type)
209
reference
operator
[](
size_type
index
)
const
& {
return
result_
[
index
].
template
As
<
value_type
>(
kExtractTag
); }
210
// NOLINTNEXTLINE(readability-const-return-type)
211
reference
operator
[](
size_type
)
const
&& {
ReportMisuse
(); }
212
//@}
213
private
:
214
[[
noreturn
]]
static
void
ReportMisuse
() {
215
static_assert
(!
sizeof
(
T
),
"keep the TypedResultSet before using, please"
);
216
}
217
218
ResultSet
result_
;
219
};
220
221
}
// namespace storages::postgres
222
223
USERVER_NAMESPACE_END
userver
storages
postgres
typed_result_set.hpp
Generated on Tue Nov 19 2024 11:32:42 for userver by
Doxygen
1.10.0