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