userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
response.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/ydb/response.hpp
4
/// @brief YDB query result rows, cursors and execute responses
5
6
#
include
<
ydb
-
cpp
-
sdk
/
client
/
query
/
client
.
h
>
7
#
include
<
ydb
-
cpp
-
sdk
/
client
/
result
/
result
.
h
>
8
#
include
<
ydb
-
cpp
-
sdk
/
client
/
table
/
table
.
h
>
9
10
#
include
<
cstddef
>
11
#
include
<
iterator
>
12
#
include
<
memory
>
13
#
include
<
optional
>
14
#
include
<
typeinfo
>
15
16
#
include
<
userver
/
utils
/
meta
.
hpp
>
17
#
include
<
userver
/
utils
/
not_null
.
hpp
>
18
#
include
<
userver
/
ydb
/
impl
/
cast
.
hpp
>
19
#
include
<
userver
/
ydb
/
io
/
insert_row
.
hpp
>
20
#
include
<
userver
/
ydb
/
io
/
list
.
hpp
>
21
#
include
<
userver
/
ydb
/
io
/
primitives
.
hpp
>
22
#
include
<
userver
/
ydb
/
io
/
traits
.
hpp
>
23
#
include
<
userver
/
ydb
/
types
.
hpp
>
24
25
USERVER_NAMESPACE_BEGIN
26
27
namespace
ydb {
28
29
namespace
impl {
30
31
template
<
typename
T>
32
struct
StructRowParser;
33
34
struct
ParseState
final
{
35
explicit
ParseState(
const
NYdb::TResultSet& result_set);
36
37
NYdb::TResultSetParser parser;
38
const
std::type_info* row_type_id{
nullptr
};
39
std::unique_ptr<std::size_t[]> cpp_to_ydb_field_mapping{};
40
};
41
42
}
// namespace impl
43
44
using
ValueType = NYdb::EPrimitiveType;
45
46
class
Cursor;
47
48
class
Row
final
{
49
public
:
50
/// @cond
51
// For internal use only.
52
explicit
Row(impl::ParseState& parse_state);
53
/// @endcond
54
55
Row(
const
Row&) =
delete
;
56
Row(Row&&)
noexcept
=
default
;
57
Row& operator=(
const
Row&) =
delete
;
58
Row& operator=(Row&&) =
delete
;
59
60
/// @brief Parses the whole row to `T`, which must be a struct type.
61
/// ydb::kStructMemberNames must be specialized for `T`.
62
///
63
/// @throws ydb::ColumnParseError on parsing error
64
/// @throws ydb::ParseError on extra fields on C++ side
65
/// @throws ydb::ParseError on extra fields on YDB side
66
template
<
typename
T>
67
T
As
() &&;
68
69
/// @brief Parses the specified column to `T`.
70
/// `Get` can only be called once for each column.
71
/// @throws ydb::BaseError on parsing error
72
template
<
typename
T>
73
T
Get
(std::string_view column_name);
74
75
/// @brief Parses the specified column to `T`.
76
/// `Get` can only be called once for each column.
77
/// @throws ydb::BaseError on parsing error
78
template
<
typename
T>
79
T
Get
(std::size_t column_index);
80
81
private
:
82
NYdb::TValueParser& GetColumn(std::size_t index);
83
NYdb::TValueParser& GetColumn(std::string_view name);
84
85
void
ConsumedColumnsCheck(std::size_t column_index);
86
87
impl::ParseState& parse_state_;
88
std::vector<
bool
> consumed_columns_;
89
};
90
91
class
CursorIterator
final
{
92
public
:
93
using
difference_type = std::ptrdiff_t;
94
using
value_type = Row;
95
using
reference = Row;
96
using
iterator_category = std::input_iterator_tag;
97
98
CursorIterator() =
default
;
99
100
CursorIterator(
const
CursorIterator&) =
delete
;
101
CursorIterator(CursorIterator&&)
noexcept
=
default
;
102
CursorIterator& operator=(
const
CursorIterator&) =
delete
;
103
CursorIterator& operator=(CursorIterator&&) =
default
;
104
105
Row operator*()
const
;
106
107
CursorIterator& operator++();
108
109
void
operator++(
int
);
110
111
bool
operator==(
const
std::default_sentinel_t& other)
const
noexcept
;
112
113
private
:
114
friend
class
Cursor;
115
116
explicit
CursorIterator(Cursor& cursor);
117
118
impl::ParseState* parse_state_{
nullptr
};
119
};
120
121
class
Cursor
final
{
122
public
:
123
/// @cond
124
explicit
Cursor(
const
NYdb::TResultSet& result_set);
125
/// @endcond
126
127
Cursor(
const
Cursor&) =
delete
;
128
Cursor(Cursor&&)
noexcept
=
default
;
129
Cursor& operator=(
const
Cursor&) =
delete
;
130
Cursor& operator=(Cursor&&)
noexcept
=
default
;
131
132
size_t ColumnsCount()
const
;
133
size_t RowsCount()
const
;
134
/// @throws EmptyResponseError if GetFirstRow() or begin() called before or
135
/// cursor is empty
136
Row
GetFirstRow
();
137
138
/// @brief Extract first row
139
/// @throws EmptyResponseError if @ref empty().
140
/// @throws IgnoreResultsError if @ref size() > 1.
141
Row
GetSingleRow
() &&;
142
143
/// @brief Extract data into a container. Each row is parsed using @ref Row::As.
144
template
<
typename
Container>
145
Container
AsContainer
() &&;
146
147
/// @brief Extract first row into user type using @ref Row::As.
148
/// @throws EmptyResponseError if @ref empty().
149
template
<
typename
T>
150
T
AsSingleRow
() &&;
151
152
/// @brief Extract first row into user type using @ref Row::As.
153
/// @returns A single row result set if non empty result was returned, empty `std::optional` otherwise
154
template
<
typename
T>
155
std::optional<T>
AsOptionalSingleRow
() &&;
156
157
/// Returns true if response has been truncated to the database limit
158
/// (currently 1000 rows)
159
bool
IsTruncated
()
const
;
160
161
bool
empty()
const
;
162
std::size_t size()
const
;
163
164
CursorIterator begin();
165
std::default_sentinel_t end();
166
167
private
:
168
friend
class
Row;
169
friend
class
CursorIterator;
170
171
bool
truncated_;
172
bool
is_consumed_{
false
};
173
// Row should not be invalidated after moving Cursor, hence the indirection.
174
utils
::
UniqueRef
<impl::ParseState> parse_state_;
175
};
176
177
class
ExecuteResponse
final
{
178
public
:
179
/// @cond
180
explicit
ExecuteResponse(NYdb::NQuery::TExecuteQueryResult&& query_result);
181
/// @endcond
182
183
ExecuteResponse(
const
ExecuteResponse&) =
delete
;
184
ExecuteResponse(ExecuteResponse&&)
noexcept
=
default
;
185
ExecuteResponse& operator=(
const
ExecuteResponse&) =
delete
;
186
ExecuteResponse& operator=(ExecuteResponse&&) =
delete
;
187
188
std::size_t GetCursorCount()
const
;
189
Cursor GetCursor(std::size_t index)
const
;
190
Cursor GetSingleCursor()
const
;
191
192
/// Query stats are only available if initially requested
193
const
std::optional<NYdb::NTable::TQueryStats>&
//
194
GetQueryStats
()
const
noexcept
;
195
196
/// Returns true if Execute used the server query cache
197
bool
IsFromServerQueryCache
()
const
noexcept
;
198
199
private
:
200
void
EnsureResultSetsNotEmpty()
const
;
201
202
std::optional<NYdb::NTable::TQueryStats> query_stats_;
203
std::vector<NYdb::TResultSet> result_sets_;
204
};
205
206
class
ReadTableResults
final
{
207
public
:
208
/// @cond
209
explicit
ReadTableResults(NYdb::NTable::TTablePartIterator iterator);
210
/// @endcond
211
212
std::optional<Cursor> GetNextResult();
213
214
ReadTableResults(
const
ReadTableResults&) =
delete
;
215
ReadTableResults(ReadTableResults&&)
noexcept
=
default
;
216
ReadTableResults& operator=(
const
ReadTableResults&) =
delete
;
217
ReadTableResults& operator=(ReadTableResults&&) =
delete
;
218
219
private
:
220
NYdb::NTable::TTablePartIterator iterator_;
221
};
222
223
class
ScanQueryResults
final
{
224
using
TScanQueryPartIterator = NYdb::NTable::TScanQueryPartIterator;
225
226
public
:
227
using
TScanQueryPart = NYdb::NTable::TScanQueryPart;
228
229
/// @cond
230
explicit
ScanQueryResults(TScanQueryPartIterator iterator);
231
/// @endcond
232
233
std::optional<TScanQueryPart> GetNextResult();
234
235
std::optional<Cursor> GetNextCursor();
236
237
ScanQueryResults(
const
ScanQueryResults&) =
delete
;
238
ScanQueryResults(ScanQueryResults&&)
noexcept
=
default
;
239
ScanQueryResults& operator=(
const
ScanQueryResults&) =
delete
;
240
ScanQueryResults& operator=(ScanQueryResults&&) =
delete
;
241
242
private
:
243
TScanQueryPartIterator iterator_;
244
};
245
246
template
<
typename
T>
247
T Row::
As
() && {
248
if
(&
typeid
(T) != parse_state_.row_type_id) {
249
parse_state_.cpp_to_ydb_field_mapping = impl::StructRowParser<T>::MakeCppToYdbFieldMapping(parse_state_.parser);
250
parse_state_.row_type_id = &
typeid
(T);
251
}
252
return
impl::StructRowParser<T>::ParseRow(parse_state_.parser, parse_state_.cpp_to_ydb_field_mapping);
253
}
254
255
template
<
typename
T>
256
T Row::
Get
(std::string_view column_name) {
257
#
ifndef
NDEBUG
258
ConsumedColumnsCheck(parse_state_.parser.ColumnIndex(impl::ToString(column_name)));
259
#
endif
260
auto
& column = GetColumn(column_name);
261
return
Parse<T>(column, ParseContext{.column_name = column_name});
262
}
263
264
template
<
typename
T>
265
T Row::
Get
(std::size_t column_index) {
266
#
ifndef
NDEBUG
267
ConsumedColumnsCheck(column_index);
268
#
endif
269
auto
& column = GetColumn(column_index);
270
const
auto
column_name = std::to_string(column_index);
271
return
Parse<T>(column, ParseContext{.column_name = column_name});
272
}
273
274
template
<
typename
Container>
275
Container Cursor::
AsContainer
() && {
276
using
ValueType =
typename
Container::value_type;
277
Container c;
278
if
constexpr
(meta::
kIsReservable
<Container>) {
279
c.reserve(size());
280
}
281
282
auto
inserter = meta::Inserter(c);
283
for
(Row row : *
this
) {
284
*inserter = std::move(row).As<ValueType>();
285
++inserter;
286
}
287
288
return
c;
289
}
290
291
template
<
typename
T>
292
T Cursor::
AsSingleRow
() && {
293
return
std::move(*
this
)
.
GetSingleRow
(
)
.As<T>();
294
}
295
296
template
<
typename
T>
297
std::optional<T> Cursor::
AsOptionalSingleRow
() && {
298
if
(empty()) {
299
return
std::nullopt;
300
}
301
return
std::move(*
this
).AsSingleRow<T>();
302
}
303
304
}
// namespace ydb
305
306
USERVER_NAMESPACE_END
userver
ydb
response.hpp
Generated on
for userver by
Doxygen
1.17.0