userver: userver/storages/redis/request.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 scan_tag>
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) : impl_(std::move(impl)) {}
38
39 /// Wait for the request to finish on Redis server
40 void Wait() { impl_->Wait(); }
41
42 /// Ignore the query result and do not wait for the Redis server to finish executing it
43 void IgnoreResult() const noexcept {}
44
45 /// Wait for the request to finish on Redis server and get the result
46 ReplyType Get(const std::string& request_description = {}) { return impl_->Get(request_description); }
47
48 /// @cond
49 /// Internal helper for WaitAny/WaitAll
50 engine::impl::ContextAccessor* TryGetContextAccessor() noexcept { return impl_->TryGetContextAccessor(); }
51 /// @endcond
52
53 template <typename T1, typename T2>
54 friend class RequestEval;
55
56 template <typename T1, typename T2>
57 friend class RequestEvalSha;
58
59 template <ScanTag scan_tag>
60 friend class RequestScanData;
61
62private:
63 ReplyPtr GetRaw() { return impl_->GetRaw(); }
64
65 std::unique_ptr<RequestDataBase<ReplyType>> impl_;
66};
67
68/// @brief Redis future for a SCAN-like responses.
69///
70/// Member functions of classes storages::redis::Client and storages::redis::Transaction that do send SCAN-like request
71/// to the Redis return this type or storages::redis::ScanRequest.
72template <ScanTag scan_tag>
73class ScanRequest final {
74public:
75 using ReplyElem = typename ScanReplyElem<scan_tag>::type;
76
77 explicit ScanRequest(std::unique_ptr<RequestScanDataBase<scan_tag>>&& impl) : impl_(std::move(impl)) {}
78
79 template <typename T = std::vector<ReplyElem>>
80 T GetAll(std::string request_description) {
81 SetRequestDescription(std::move(request_description));
82 return GetAll<T>();
83 }
84
85 template <typename T = std::vector<ReplyElem>>
86 T GetAll() {
87 return T{begin(), end()};
88 }
89
90 void SetRequestDescription(std::string request_description) {
91 impl_->SetRequestDescription(std::move(request_description));
92 }
93
94 class Iterator {
95 public:
96 using iterator_category = std::input_iterator_tag;
97 using difference_type = ptrdiff_t;
98 using value_type = ReplyElem;
99 using reference = value_type&;
100 using pointer = value_type*;
101
102 explicit Iterator(ScanRequest* stream) : stream_(stream) {
103 if (stream_ && !stream_->HasMore()) stream_ = nullptr;
104 }
105
107 public:
108 ReplyElemHolder(value_type reply_elem) : reply_elem_(std::move(reply_elem)) {}
109
110 value_type& operator*() { return reply_elem_; }
111
112 private:
113 value_type reply_elem_;
114 };
115
116 ReplyElemHolder operator++(int) {
117 ReplyElemHolder old_value(stream_->Current());
118 ++*this;
119 return old_value;
120 }
121
122 Iterator& operator++() {
123 stream_->Get();
124 if (!stream_->HasMore()) stream_ = nullptr;
125 return *this;
126 }
127
128 reference operator*() { return stream_->Current(); }
129
130 pointer operator->() { return &**this; }
131
132 bool operator==(const Iterator& rhs) const { return stream_ == rhs.stream_; }
133
134 bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
135
136 private:
137 ScanRequest* stream_;
138 };
139
140 Iterator begin() { return Iterator(this); }
141 Iterator end() { return Iterator(nullptr); }
142
144 public:
145 using Exception::Exception;
146 };
147
148private:
149 ReplyElem& Current() { return impl_->Current(); }
150
151 ReplyElem Get() { return impl_->Get(); }
152
153 bool HasMore() { return !impl_->Eof(); }
154
155 friend class Iterator;
156
157 std::unique_ptr<RequestScanDataBase<scan_tag>> impl_;
158};
159
160/// @name Valkey/Redis futures aliases
161/// @{
162using RequestAppend = Request<size_t>;
163using RequestBitop = Request<size_t>;
164using RequestDbsize = Request<size_t>;
165using RequestDecr = Request<int64_t>;
166using RequestDel = Request<size_t>;
167using RequestUnlink = Request<size_t>;
168using RequestEvalCommon = Request<ReplyData>;
169using RequestEvalShaCommon = Request<ReplyData>;
170using RequestScriptLoad = Request<std::string>;
171using RequestExec = Request<ReplyData, void>;
172using RequestExists = Request<size_t>;
173using RequestExpire = Request<ExpireReply>;
174using RequestGeoadd = Request<size_t>;
175using RequestGeoradius = Request<std::vector<GeoPoint>>;
176using RequestGeosearch = Request<std::vector<GeoPoint>>;
177using RequestGet = Request<std::optional<std::string>>;
178using RequestGetset = Request<std::optional<std::string>>;
179using RequestHdel = Request<size_t>;
180using RequestHexists = Request<size_t>;
181using RequestHget = Request<std::optional<std::string>>;
182using RequestHgetall = Request<std::unordered_map<std::string, std::string>>;
183using RequestHincrby = Request<int64_t>;
184using RequestHincrbyfloat = Request<double>;
185using RequestHkeys = Request<std::vector<std::string>>;
186using RequestHlen = Request<size_t>;
187using RequestHmget = Request<std::vector<std::optional<std::string>>>;
188using RequestHmset = Request<StatusOk, void>;
189using RequestHscan = ScanRequest<ScanTag::kHscan>;
190using RequestHset = Request<HsetReply>;
191using RequestHsetnx = Request<size_t, bool>;
192using RequestHvals = Request<std::vector<std::string>>;
193using RequestIncr = Request<int64_t>;
194using RequestKeys = Request<std::vector<std::string>>;
195using RequestLindex = Request<std::optional<std::string>>;
196using RequestLlen = Request<size_t>;
197using RequestLpop = Request<std::optional<std::string>>;
198using RequestLpush = Request<size_t>;
199using RequestLpushx = Request<size_t>;
200using RequestLrange = Request<std::vector<std::string>>;
201using RequestLrem = Request<size_t>;
202using RequestLtrim = Request<StatusOk, void>;
203using RequestMget = Request<std::vector<std::optional<std::string>>>;
204using RequestMset = Request<StatusOk, void>;
205using RequestPersist = Request<PersistReply>;
206using RequestPexpire = Request<ExpireReply>;
207using RequestPing = Request<StatusPong, void>;
208using RequestPingMessage = Request<std::string>;
209using RequestPublish = Request<size_t>;
210using RequestRename = Request<StatusOk, void>;
211using RequestRpop = Request<std::optional<std::string>>;
212using RequestRpush = Request<size_t>;
213using RequestRpushx = Request<size_t>;
214using RequestSadd = Request<size_t>;
215using RequestScan = ScanRequest<ScanTag::kScan>;
216using RequestScard = Request<size_t>;
217using RequestSet = Request<StatusOk, void>;
218using RequestSetIfExist = Request<std::optional<StatusOk>, bool>;
219using RequestSetIfNotExist = Request<std::optional<StatusOk>, bool>;
220using RequestSetOptions = Request<SetReply>;
221using RequestSetex = Request<StatusOk, void>;
222using RequestSismember = Request<size_t>;
223using RequestSmembers = Request<std::unordered_set<std::string>>;
224using RequestSrandmember = Request<std::optional<std::string>>;
225using RequestSrandmembers = Request<std::vector<std::string>>;
226using RequestSrem = Request<size_t>;
227using RequestSscan = ScanRequest<ScanTag::kSscan>;
228using RequestStrlen = Request<size_t>;
229using RequestTime = Request<std::chrono::system_clock::time_point>;
230using RequestTtl = Request<TtlReply>;
231using RequestType = Request<KeyType>;
232using RequestZadd = Request<size_t>;
233using RequestZaddIncr = Request<double>;
234using RequestZaddIncrExisting = Request<std::optional<double>>;
235using RequestZcard = Request<size_t>;
236using RequestZcount = Request<size_t>;
237using RequestZrange = Request<std::vector<std::string>>;
238using RequestZrangeWithScores = Request<std::vector<MemberScore>>;
239using RequestZrangebyscore = Request<std::vector<std::string>>;
240using RequestZrangebyscoreWithScores = Request<std::vector<MemberScore>>;
241using RequestZrem = Request<size_t>;
242using RequestZremrangebyrank = Request<size_t>;
243using RequestZremrangebyscore = Request<size_t>;
244using RequestZscan = ScanRequest<ScanTag::kZscan>;
245using RequestZscore = Request<std::optional<double>>;
246/// @}
247
248} // namespace storages::redis
249
250USERVER_NAMESPACE_END