10#include <userver/engine/deadline.hpp>
11#include <userver/tracing/scope_time.hpp>
12#include <userver/utils/fast_pimpl.hpp>
14#include <userver/storages/mysql/execution_result.hpp>
15#include <userver/storages/mysql/impl/io/extractor.hpp>
16#include <userver/storages/mysql/impl/tracing_tags.hpp>
18USERVER_NAMESPACE_BEGIN
23class StatementFetcher;
30template <
typename DbType>
31class MappedStatementResultSet;
37class StatementResultSet
final {
39 explicit StatementResultSet(impl::StatementFetcher&& fetcher,
41 StatementResultSet(infra::ConnectionPtr&& connection,
42 impl::StatementFetcher&& fetcher,
tracing::Span&& span);
43 ~StatementResultSet();
45 StatementResultSet(
const StatementResultSet& other) =
delete;
46 StatementResultSet(StatementResultSet&& other)
noexcept;
85 template <
typename Container>
99 template <
typename Container>
114 template <
typename T>
128 template <
typename T>
143 template <
typename T>
157 template <
typename T>
169 template <
typename DbType>
170 MappedStatementResultSet<DbType>
MapFrom() &&;
176 template <
typename T>
177 friend class CursorResultSet;
179 template <
typename DbType>
180 friend class MappedStatementResultSet;
182 template <
typename Container,
typename MapFrom,
typename ExtractionTag>
183 Container DoAsContainerMapped() &&;
185 template <
typename T,
typename ExtractionTag>
186 std::optional<T> DoAsOptionalSingleRow() &&;
188 bool FetchResult(impl::io::ExtractorBase& extractor);
191 utils::FastPimpl<Impl, 72, 8> impl_;
205template <
typename DbType>
206class MappedStatementResultSet
final {
208 explicit MappedStatementResultSet(StatementResultSet&& result_set);
209 ~MappedStatementResultSet();
217 template <
typename T>
226 template <
typename T>
235 template <
typename Container>
244 template <
typename Container>
247 template <
typename T>
249 static_assert(!
sizeof(T),
250 "Not implemented, just use StatementResultSet version and "
251 "convert yourself.");
254 template <
typename T>
255 std::optional<T> AsOptionalSingleRow() && {
256 static_assert(!
sizeof(T),
257 "Not implemented, just use StatementResultSet version and "
258 "convert yourself.");
262 StatementResultSet result_set_;
267 return std::move(*
this).AsContainer<std::vector<T>>();
272 return std::move(*
this).AsContainer<std::vector<T>>(kFieldTag);
275template <
typename Container>
277 static_assert(meta::kIsRange<Container>,
278 "The type isn't actually a container");
279 using Row =
typename Container::value_type;
281 return std::move(*
this).DoAsContainerMapped<Container, Row,
RowTag>();
284template <
typename Container>
286 static_assert(meta::kIsRange<Container>,
287 "The type isn't actually a container");
288 using Row =
typename Container::value_type;
290 return std::move(*
this).DoAsContainerMapped<Container, Row,
FieldTag>();
295 auto optional_data = std::move(*
this).AsOptionalSingleRow<T>();
297 if (!optional_data.has_value()) {
298 throw std::runtime_error{
"Result set is empty"};
301 return std::move(*optional_data);
306 auto optional_data = std::move(*
this).AsOptionalSingleField<T>();
308 if (!optional_data.has_value()) {
309 throw std::runtime_error{
"Result set is empty"};
312 return std::move(*optional_data);
317 return std::move(*
this).DoAsOptionalSingleRow<T,
RowTag>();
322 return std::move(*
this).DoAsOptionalSingleRow<T,
FieldTag>();
325template <
typename Container,
typename MapFrom,
typename ExtractionTag>
326Container StatementResultSet::DoAsContainerMapped() && {
327 static_assert(meta::kIsRange<Container>,
328 "The type isn't actually a container");
329 using Extractor = impl::io::TypedExtractor<Container, MapFrom, ExtractionTag>;
331 Extractor extractor{};
334 std::move(*
this).FetchResult(extractor);
337 return Container{extractor.ExtractData()};
340template <
typename T,
typename ExtractionTag>
341std::optional<T> StatementResultSet::DoAsOptionalSingleRow() && {
343 if constexpr (std::is_same_v<
RowTag, ExtractionTag>) {
344 return std::move(*
this).AsVector<T>();
346 return std::move(*
this).AsVector<T>(kFieldTag);
354 if (rows.size() > 1) {
355 throw std::runtime_error{fmt::format(
356 "There is more than one row in result set ({} rows)", rows.size())};
359 return {std::move(rows.front())};
362template <
typename DbType>
363MappedStatementResultSet<DbType>::MappedStatementResultSet(
364 StatementResultSet&& result_set)
365 : result_set_{std::move(result_set)} {}
367template <
typename DbType>
368MappedStatementResultSet<DbType>::~MappedStatementResultSet() =
default;
373 return std::move(*
this).
template AsContainer<std::vector<T>>();
379 return std::move(*
this).
template AsContainer<std::vector<T>>(kFieldTag);
383template <
typename Container>
385 return std::move(result_set_)
386 .DoAsContainerMapped<Container, DbType, RowTag>();
390template <
typename Container>
392 return std::move(result_set_)
393 .DoAsContainerMapped<Container, DbType, FieldTag>();
396template <
typename DbType>
397MappedStatementResultSet<DbType> StatementResultSet::
MapFrom() && {
398 return MappedStatementResultSet<DbType>{std::move(*
this)};