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 Cursor::empty.
140
/// @throws IgnoreResultsError if @ref Cursor::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 Cursor::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
/// @returns `true` if the cursor has no rows
162
bool
empty
()
const
;
163
/// @returns the number of rows in the cursor
164
std::size_t
size
()
const
;
165
166
CursorIterator begin();
167
std::default_sentinel_t end();
168
169
private
:
170
friend
class
Row;
171
friend
class
CursorIterator;
172
173
bool
truncated_;
174
bool
is_consumed_{
false
};
175
// Row should not be invalidated after moving Cursor, hence the indirection.
176
utils::UniqueRef<impl::ParseState> parse_state_;
177
};
178
179
class
ExecuteResponse
final
{
180
public
:
181
/// @cond
182
explicit
ExecuteResponse(NYdb::NQuery::TExecuteQueryResult&& query_result);
183
/// @endcond
184
185
ExecuteResponse(
const
ExecuteResponse&) =
delete
;
186
ExecuteResponse(ExecuteResponse&&)
noexcept
=
default
;
187
ExecuteResponse& operator=(
const
ExecuteResponse&) =
delete
;
188
ExecuteResponse& operator=(ExecuteResponse&&) =
delete
;
189
190
std::size_t GetCursorCount()
const
;
191
Cursor GetCursor(std::size_t index)
const
;
192
Cursor GetSingleCursor()
const
;
193
194
/// Query stats are only available if initially requested
195
const
std::optional<NYdb::NTable::TQueryStats>&
//
196
GetQueryStats
()
const
noexcept
;
197
198
/// Returns true if Execute used the server query cache
199
bool
IsFromServerQueryCache
()
const
noexcept
;
200
201
private
:
202
void
EnsureResultSetsNotEmpty()
const
;
203
204
std::optional<NYdb::NTable::TQueryStats> query_stats_;
205
std::vector<NYdb::TResultSet> result_sets_;
206
};
207
208
class
ReadTableResults
final
{
209
public
:
210
/// @cond
211
explicit
ReadTableResults(NYdb::NTable::TTablePartIterator iterator);
212
/// @endcond
213
214
std::optional<Cursor> GetNextResult();
215
216
ReadTableResults(
const
ReadTableResults&) =
delete
;
217
ReadTableResults(ReadTableResults&&)
noexcept
=
default
;
218
ReadTableResults& operator=(
const
ReadTableResults&) =
delete
;
219
ReadTableResults& operator=(ReadTableResults&&) =
delete
;
220
221
private
:
222
NYdb::NTable::TTablePartIterator iterator_;
223
};
224
225
class
ScanQueryResults
final
{
226
using
TScanQueryPartIterator = NYdb::NTable::TScanQueryPartIterator;
227
228
public
:
229
using
TScanQueryPart = NYdb::NTable::TScanQueryPart;
230
231
/// @cond
232
explicit
ScanQueryResults(TScanQueryPartIterator iterator);
233
/// @endcond
234
235
std::optional<TScanQueryPart> GetNextResult();
236
237
std::optional<Cursor> GetNextCursor();
238
239
ScanQueryResults(
const
ScanQueryResults&) =
delete
;
240
ScanQueryResults(ScanQueryResults&&)
noexcept
=
default
;
241
ScanQueryResults& operator=(
const
ScanQueryResults&) =
delete
;
242
ScanQueryResults& operator=(ScanQueryResults&&) =
delete
;
243
244
private
:
245
TScanQueryPartIterator iterator_;
246
};
247
248
template
<
typename
T>
249
T Row::
As
() && {
250
if
(&
typeid
(T) != parse_state_.row_type_id) {
251
parse_state_.cpp_to_ydb_field_mapping = impl::StructRowParser<T>::MakeCppToYdbFieldMapping(parse_state_.parser);
252
parse_state_.row_type_id = &
typeid
(T);
253
}
254
return
impl::StructRowParser<T>::ParseRow(parse_state_.parser, parse_state_.cpp_to_ydb_field_mapping);
255
}
256
257
template
<
typename
T>
258
T Row::
Get
(std::string_view column_name) {
259
#
ifndef
NDEBUG
260
ConsumedColumnsCheck(parse_state_.parser.ColumnIndex(impl::ToString(column_name)));
261
#
endif
262
auto
& column = GetColumn(column_name);
263
return
Parse<T>(column, ParseContext{.column_name = column_name});
264
}
265
266
template
<
typename
T>
267
T Row::
Get
(std::size_t column_index) {
268
#
ifndef
NDEBUG
269
ConsumedColumnsCheck(column_index);
270
#
endif
271
auto
& column = GetColumn(column_index);
272
const
auto
column_name = std::to_string(column_index);
273
return
Parse<T>(column, ParseContext{.column_name = column_name});
274
}
275
276
template
<
typename
Container>
277
Container Cursor::
AsContainer
() && {
278
using
ValueType =
typename
Container::value_type;
279
Container c;
280
if
constexpr
(
meta
::
kIsReservable
<Container>) {
281
c.reserve(
size
(
)
);
282
}
283
284
auto
inserter =
meta
::Inserter(c);
285
for
(Row row : *
this
) {
286
*inserter = std::move(row).As<ValueType>();
287
++inserter;
288
}
289
290
return
c;
291
}
292
293
template
<
typename
T>
294
T Cursor::
AsSingleRow
() && {
295
return
std::move(*
this
).GetSingleRow().As<T>();
296
}
297
298
template
<
typename
T>
299
std::optional<T> Cursor::
AsOptionalSingleRow
() && {
300
if
(
empty
(
)
) {
301
return
std::nullopt;
302
}
303
return
std::move(*
this
).AsSingleRow<T>();
304
}
305
306
}
// namespace ydb
307
308
USERVER_NAMESPACE_END
userver
ydb
response.hpp
Generated on
for userver by
Doxygen
1.17.0