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