userver: userver/storages/sqlite/result_set.hpp Source File
Loading...
Searching...
No Matches
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 /// @brief Parse statement result set as std::vector<T>.
35 /// T is expected to be an aggregate of supported types.
36 ///
37 /// Throw exceptions on columns count mismatch or types mismatch.
38 ///
39 template <typename T>
40 std::vector<T> AsVector() &&;
41
42 /// @brief Parse statement result set as std::vector<T>.
43 /// Result set is expected to have a single column, `T` is expected to be one
44 /// of supported types.
45 ///
46 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
47 ///
48 template <typename T>
49 std::vector<T> AsVector(FieldTag) &&;
50
51 /// @brief Parse statement result as T.
52 /// Result set is expected to have a single row, `T` is expected to be an
53 /// aggregate of supported types.
54 ///
55 /// Throw exceptions on columns count mismatch or types mismatch.
56 /// throws if result set is empty or contains more than one row.
57 ///
58 template <typename T>
59 T AsSingleRow() &&;
60
61 /// @brief Parse statement result as T.
62 /// Result set is expected to have a single row and a single column,
63 /// `T` is expected to be one of supported types.
64 ///
65 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
66 /// throws if result set is empty of contains more than one row.
67 ///
68 template <typename T>
69 T AsSingleField() &&;
70
71 /// @brief Parse statement result as std::optional<T>.
72 /// Result set is expected to have not more than one row,
73 /// `T` is expected to be an aggregate of supported types.
74 ///
75 /// Throw exceptions on columns count mismatch or types mismatch.
76 /// throws if result set contains more than one row.
77 ///
78 template <typename T>
79 std::optional<T> AsOptionalSingleRow() &&;
80
81 /// @brief Parse statement result as T.
82 /// Result set is expected to have not more than one row,
83 /// `T` is expected to be one of supported types.
84 ///
85 /// Throw exceptions on columns count not being equal to 1 or type mismatch.
86 /// throws if result set contains more than one row.
87 ///
88 template <typename T>
89 std::optional<T> AsOptionalSingleField() &&;
90
91 /// @brief Get statement execution metadata.
92 ExecutionResult AsExecutionResult() &&;
93
94private:
95 template <typename T>
96 friend class CursorResultSet;
97
98 void FetchAllResult(impl::ExtractorBase& extractor);
99
100 bool FetchResult(impl::ExtractorBase& extractor, size_t batch_size);
101
102 impl::ResultWrapperPtr pimpl_;
103};
104
105template <typename T>
106std::vector<T> ResultSet::AsVector() && {
107 impl::TypedExtractor<T, RowTag> extractor{*pimpl_};
108 FetchAllResult(extractor);
109 return extractor.ExtractData();
110}
111
112template <typename T>
113std::vector<T> ResultSet::AsVector(FieldTag) && {
114 impl::TypedExtractor<T, FieldTag> extractor{*pimpl_};
115 FetchAllResult(extractor);
116 return extractor.ExtractData();
117}
118
119template <typename T>
121 auto optional_data = std::move(*this).AsOptionalSingleRow<T>();
122 if (!optional_data.has_value()) {
123 throw SQLiteException{"Result set is empty"};
124 }
125 return std::move(*optional_data);
126}
127
128template <typename T>
130 auto optional_data = std::move(*this).AsOptionalSingleField<T>();
131 if (!optional_data.has_value()) {
132 throw SQLiteException{"Result set is empty"};
133 }
134 return std::move(*optional_data);
135}
136
137template <typename T>
138std::optional<T> ResultSet::AsOptionalSingleRow() && {
139 auto rows = std::move(*this).AsVector<T>();
140 if (rows.empty()) {
141 return std::nullopt;
142 }
143 if (rows.size() > 1) {
144 // TODO: Maybe better logging warning
145 throw SQLiteException("Result set contains more than one row");
146 }
147 return {{std::move(rows.front())}};
148}
149
150template <typename T>
151std::optional<T> ResultSet::AsOptionalSingleField() && {
152 auto rows = std::move(*this).AsVector<T>(kFieldTag);
153 if (rows.empty()) {
154 return std::nullopt;
155 }
156 if (rows.size() > 1) {
157 // TODO: Maybe better logging warning
158 throw SQLiteException("Result set contains more than one row");
159 }
160 return {{std::move(rows.front())}};
161}
162
163} // namespace storages::sqlite
164
165USERVER_NAMESPACE_END