userver: userver/storages/redis/request.hpp Source File
Loading...
Searching...
No Matches
request.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @brief Valkey/Redis futures for storages::redis::Client and storages::redis::Transaction.
5
6#include <memory>
7#include <optional>
8#include <string>
9#include <unordered_map>
10#include <unordered_set>
11#include <vector>
12
13#include <userver/engine/impl/context_accessor.hpp>
14#include <userver/storages/redis/exception.hpp>
15#include <userver/storages/redis/fwd.hpp>
16#include <userver/storages/redis/reply_types.hpp>
17#include <userver/storages/redis/request_data_base.hpp>
18#include <userver/storages/redis/scan_tag.hpp>
19
20USERVER_NAMESPACE_BEGIN
21
22namespace storages::redis {
23
24template <ScanTag TScanTag>
25class RequestScanData;
26
27/// @brief Valkey or Redis future for a non-scan and non-eval responses.
28///
29/// Member functions of classes storages::redis::Client and storages::redis::Transaction that do send request to the
30/// Redis return this type or storages::redis::ScanRequest.
31template <typename ResultType, typename ReplyType>
32class [[nodiscard]] Request final {
33public:
34 using Result = ResultType;
35 using Reply = ReplyType;
36
37 explicit Request(std::unique_ptr<RequestDataBase<ReplyType>>&& impl)
38 : impl_(std::move(impl))
39 {}
40
41 /// Wait for the request to finish on Redis server, server or request errors (if any) are logged but not thrown.
42 ///
43 /// @throws Exceptions on missuse (for example, calling Wait() on a single result from a transaction before waiting
44 /// for the transaction itself).
45 void Wait() { impl_->Wait(); }
46
47 /// Ignore the query result and do not wait for the Redis server to finish executing it
48 void IgnoreResult() const noexcept {}
49
50 /// Wait for the request to finish on Redis server and get the result
51 /// @throws server or request related exceptions
52 ReplyType Get(const std::string& request_description = {}) { return impl_->Get(request_description); }
53
54 /// @cond
55 /// Internal helper for WaitAny/WaitAll
56 engine::impl::ContextAccessor* TryGetContextAccessor() noexcept { return impl_->TryGetContextAccessor(); }
57 /// @endcond
58
59 template <typename T1, typename T2>
60 friend class RequestEval;
61
62 template <typename T1, typename T2>
63 friend class RequestEvalSha;
64
65 template <ScanTag TScanTag>
66 friend class RequestScanData;
67
68 template <typename T1>
69 friend class RequestGeneric;
70
71private:
72 ReplyPtr GetRaw() { return impl_->GetRaw(); }
73
74 std::unique_ptr<RequestDataBase<ReplyType>> impl_;
75};
76
77/// @brief Redis future for a SCAN-like responses.
78///
79/// Member functions of classes storages::redis::Client and storages::redis::Transaction that do send SCAN-like request
80/// to the Redis return this type or storages::redis::ScanRequest.
81template <ScanTag TScanTag>
82class ScanRequest final {
83public:
84 using ReplyElem = typename ScanReplyElem<TScanTag>::type;
85
86 explicit ScanRequest(std::unique_ptr<RequestScanDataBase<TScanTag>>&& impl)
87 : impl_(std::move(impl))
88 {}
89
90 template <typename T = std::vector<ReplyElem>>
91 T GetAll(std::string request_description) {
92 SetRequestDescription(std::move(request_description));
93 return GetAll<T>();
94 }
95
96 template <typename T = std::vector<ReplyElem>>
97 T GetAll() {
98 return T{begin(), end()};
99 }
100
101 void SetRequestDescription(std::string request_description) {
102 impl_->SetRequestDescription(std::move(request_description));
103 }
104
105 class Iterator {
106 public:
107 using iterator_category = std::input_iterator_tag;
108 using difference_type = ptrdiff_t;
109 using value_type = ReplyElem;
110 using reference = value_type&;
111 using pointer = value_type*;
112
113 explicit Iterator(ScanRequest* stream)
114 : stream_(stream)
115 {
116 if (stream_ && !stream_->HasMore()) {
117 stream_ = nullptr;
118 }
119 }
120
122 public:
123 ReplyElemHolder(value_type reply_elem)
124 : reply_elem_(std::move(reply_elem))
125 {}
126
127 value_type& operator*() { return reply_elem_; }
128
129 private:
130 value_type reply_elem_;
131 };
132
133 ReplyElemHolder operator++(int) {
134 ReplyElemHolder old_value(stream_->Current());
135 ++*this;
136 return old_value;
137 }
138
139 Iterator& operator++() {
140 stream_->Get();
141 if (!stream_->HasMore()) {
142 stream_ = nullptr;
143 }
144 return *this;
145 }
146
147 reference operator*() { return stream_->Current(); }
148
149 pointer operator->() { return &**this; }
150
151 bool operator==(const Iterator& rhs) const { return stream_ == rhs.stream_; }
152
153 bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
154
155 private:
156 ScanRequest* stream_;
157 };
158
159 Iterator begin() { return Iterator(this); }
160 Iterator end() { return Iterator(nullptr); }
161
163 public:
164 using Exception::Exception;
165 };
166
167private:
168 ReplyElem& Current() { return impl_->Current(); }
169
170 ReplyElem Get() { return impl_->Get(); }
171
172 bool HasMore() { return !impl_->Eof(); }
173
174 friend class Iterator;
175
176 std::unique_ptr<RequestScanDataBase<TScanTag>> impl_;
177};
178
179/// @name Valkey/Redis futures aliases
180/// @{
181using RequestAppend = Request<size_t>;
182using RequestBitop = Request<size_t>;
183using RequestDbsize = Request<size_t>;
184using RequestDecr = Request<int64_t>;
185using RequestDel = Request<size_t>;
186using RequestUnlink = Request<size_t>;
187using RequestGenericCommon = Request<ReplyData>;
188using RequestEvalCommon = Request<ReplyData>;
189using RequestEvalShaCommon = Request<ReplyData>;
190using RequestScriptLoad = Request<std::string>;
191using RequestExec = Request<ReplyData, void>;
192using RequestExists = Request<size_t>;
193using RequestExpire = Request<ExpireReply>;
194using RequestGeoadd = Request<size_t>;
195using RequestGeopos = Request<std::vector<std::optional<Point>>>;
196using RequestGeoradius = Request<std::vector<GeoPoint>>;
197using RequestGeosearch = Request<std::vector<GeoPoint>>;
198using RequestGet = Request<std::optional<std::string>>;
199using RequestGetset = Request<std::optional<std::string>>;
200using RequestHdel = Request<size_t>;
201using RequestHexists = Request<size_t>;
202using RequestHget = Request<std::optional<std::string>>;
203using RequestHgetall = Request<std::unordered_map<std::string, std::string>>;
204using RequestHincrby = Request<int64_t>;
205using RequestHincrbyfloat = Request<double>;
206using RequestHkeys = Request<std::vector<std::string>>;
207using RequestHlen = Request<size_t>;
208using RequestHmget = Request<std::vector<std::optional<std::string>>>;
209using RequestHmset = Request<StatusOk, void>;
210using RequestHscan = ScanRequest<ScanTag::kHscan>;
211using RequestHset = Request<HsetReply>;
212using RequestHsetnx = Request<size_t, bool>;
213using RequestHvals = Request<std::vector<std::string>>;
214using RequestIncr = Request<int64_t>;
215using RequestKeys = Request<std::vector<std::string>>;
216using RequestLindex = Request<std::optional<std::string>>;
217using RequestLlen = Request<size_t>;
218using RequestLpop = Request<std::optional<std::string>>;
219using RequestLpush = Request<size_t>;
220using RequestLpushx = Request<size_t>;
221using RequestLrange = Request<std::vector<std::string>>;
222using RequestLrem = Request<size_t>;
223using RequestLtrim = Request<StatusOk, void>;
224using RequestMget = Request<std::vector<std::optional<std::string>>>;
225using RequestMset = Request<StatusOk, void>;
226using RequestPersist = Request<PersistReply>;
227using RequestPexpire = Request<ExpireReply>;
228using RequestPing = Request<StatusPong, void>;
229using RequestPingMessage = Request<std::string>;
230using RequestPublish = Request<size_t>;
231using RequestRename = Request<StatusOk, void>;
232using RequestRpop = Request<std::optional<std::string>>;
233using RequestRpush = Request<size_t>;
234using RequestRpushx = Request<size_t>;
235using RequestSadd = Request<size_t>;
236using RequestScan = ScanRequest<ScanTag::kScan>;
237using RequestScard = Request<size_t>;
238using RequestSet = Request<StatusOk, void>;
239using RequestSetIfExist = Request<std::optional<StatusOk>, bool>;
240using RequestSetIfNotExist = Request<std::optional<StatusOk>, bool>;
241using RequestSetIfNotExistOrGet = Request<std::optional<std::string>>;
242using RequestSetOptions = Request<SetReply>;
243using RequestSetex = Request<StatusOk, void>;
244using RequestSismember = Request<size_t>;
245using RequestSmembers = Request<std::unordered_set<std::string>>;
246using RequestSrandmember = Request<std::optional<std::string>>;
247using RequestSrandmembers = Request<std::vector<std::string>>;
248using RequestSrem = Request<size_t>;
249using RequestSscan = ScanRequest<ScanTag::kSscan>;
250using RequestStrlen = Request<size_t>;
251using RequestTime = Request<std::chrono::system_clock::time_point>;
252using RequestTtl = Request<TtlReply>;
253using RequestType = Request<KeyType>;
254using RequestZadd = Request<size_t>;
255using RequestZaddIncr = Request<double>;
256using RequestZaddIncrExisting = Request<std::optional<double>>;
257using RequestZcard = Request<size_t>;
258using RequestZcount = Request<size_t>;
259using RequestZrange = Request<std::vector<std::string>>;
260using RequestZrangeWithScores = Request<std::vector<MemberScore>>;
261using RequestZrangebyscore = Request<std::vector<std::string>>;
262using RequestZrangebyscoreWithScores = Request<std::vector<MemberScore>>;
263using RequestZrem = Request<size_t>;
264using RequestZremrangebyrank = Request<size_t>;
265using RequestZremrangebyscore = Request<size_t>;
266using RequestZscan = ScanRequest<ScanTag::kZscan>;
267using RequestZscore = Request<std::optional<double>>;
268/// @}
269
270} // namespace storages::redis
271
272USERVER_NAMESPACE_END