userver: userver/storages/sqlite/result_set.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
result_set.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/sqlite/result_set.hpp
4/// @copybrief storages::sqlite::ResultSet
5
6#include <memory>
7#include <optional>
8#include <vector>
9
10#include <userver/storages/sqlite/exceptions.hpp>
11#include <userver/storages/sqlite/execution_result.hpp>
12#include <userver/storages/sqlite/impl/extractor.hpp>
13#include <userver/storages/sqlite/row_types.hpp>
14#include <userver/storages/sqlite/sqlite_fwd.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::sqlite {
19
20/// @brief A proxy for statement execution result.
21///
22/// This type can't be constructed in user code and is always retrieved from
23/// storages::sqlite::Client, storages::sqlite::Transaction or storages::sqlite::Savepoint methods.
24class ResultSet {
25public:
26 explicit ResultSet(impl::ResultWrapperPtr pimpl);
27
28 ResultSet(const ResultSet& other) = delete;
29 ResultSet(ResultSet&& other) noexcept;
30 ResultSet& operator=(ResultSet&&) noexcept;
31
32 ~ResultSet();
33
34 // clang-format off
35 /// @brief Parse statement result set as std::vector<T>.
36 /// T is expected to be an aggregate of supported types.
37 ///
38 /// Throw exceptions on columns count mismatch or types mismatch.
39 ///
40 // clang-format on
41 template <typename T>
42 std::vector<T> AsVector() &&;
43
44 // clang-format off
45 /// @brief Parse statement result set as std::vector<T>.
46 /// Result set is expected to have a single column, `T` is expected to be one
47 /// of supported types.
48 ///
49 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
50 ///
51 // clang-format on
52 template <typename T>
53 std::vector<T> AsVector(FieldTag) &&;
54
55 // clang-format off
56 /// @brief Parse statement result as T.
57 /// Result set is expected to have a single row, `T` is expected to be an
58 /// aggregate of supported types.
59 ///
60 /// Throw exceptions on columns count mismatch or types mismatch.
61 /// throws if result set is empty or contains more than one row.
62 ///
63 // clang-format on
64 template <typename T>
65 T AsSingleRow() &&;
66
67 // clang-format off
68 /// @brief Parse statement result as T.
69 /// Result set is expected to have a single row and a single column,
70 /// `T` is expected to be one of supported types.
71 ///
72 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
73 /// throws if result set is empty of contains more than one row.
74 ///
75 // clang-format on
76 template <typename T>
77 T AsSingleField() &&;
78
79 // clang-format off
80 /// @brief Parse statement result as std::optional<T>.
81 /// Result set is expected to have not more than one row,
82 /// `T` is expected to be an aggregate of supported types.
83 ///
84 /// Throw exceptions on columns count mismatch or types mismatch.
85 /// throws if result set contains more than one row.
86 ///
87 // clang-format on
88 template <typename T>
89 std::optional<T> AsOptionalSingleRow() &&;
90
91 // clang-format off
92 /// @brief Parse statement result as T.
93 /// Result set is expected to have not more than one row,
94 /// `T` is expected to be one of supported types.
95 ///
96 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
97 /// throws if result set contains more than one row.
98 ///
99 // clang-format on
100 template <typename T>
101 std::optional<T> AsOptionalSingleField() &&;
102
103 /// @brief Get statement execution metadata.
104 ExecutionResult AsExecutionResult() &&;
105
106private:
107 template <typename T>
108 friend class CursorResultSet;
109
110 void FetchAllResult(impl::ExtractorBase& extractor);
111
112 bool FetchResult(impl::ExtractorBase& extractor, size_t batch_size);
113
114 impl::ResultWrapperPtr pimpl_;
115};
116
117template <typename T>
118std::vector<T> ResultSet::AsVector() && {
119 impl::TypedExtractor<T, RowTag> extractor{*pimpl_};
120 FetchAllResult(extractor);
121 return extractor.ExtractData();
122}
123
124template <typename T>
125std::vector<T> ResultSet::AsVector(FieldTag) && {
126 impl::TypedExtractor<T, FieldTag> extractor{*pimpl_};
127 FetchAllResult(extractor);
128 return extractor.ExtractData();
129}
130
131template <typename T>
133 auto optional_data = std::move(*this).AsOptionalSingleRow<T>();
134 if (!optional_data.has_value()) {
135 throw SQLiteException{"Result set is empty"};
136 }
137 return std::move(*optional_data);
138}
139
140template <typename T>
142 auto optional_data = std::move(*this).AsOptionalSingleField<T>();
143 if (!optional_data.has_value()) {
144 throw SQLiteException{"Result set is empty"};
145 }
146 return std::move(*optional_data);
147}
148
149template <typename T>
150std::optional<T> ResultSet::AsOptionalSingleRow() && {
151 auto rows = std::move(*this).AsVector<T>();
152 if (rows.empty()) {
153 return std::nullopt;
154 }
155 if (rows.size() > 1) {
156 // TODO: Maybe better logging warning
157 throw SQLiteException("Result set contains more than one row");
158 }
159 return {{std::move(rows.front())}};
160}
161
162template <typename T>
163std::optional<T> ResultSet::AsOptionalSingleField() && {
164 auto rows = std::move(*this).AsVector<T>(kFieldTag);
165 if (rows.empty()) {
166 return std::nullopt;
167 }
168 if (rows.size() > 1) {
169 // TODO: Maybe better logging warning
170 throw SQLiteException("Result set contains more than one row");
171 }
172 return {{std::move(rows.front())}};
173}
174
175} // namespace storages::sqlite
176
177USERVER_NAMESPACE_END