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