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