userver: userver/storages/redis/command_options.hpp Source File
Loading...
Searching...
No Matches
command_options.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @brief Definitions of structures representing options for different commands
5
6#include <optional>
7#include <string>
8#include <vector>
9
10#include <userver/formats/json/value.hpp>
11#include <userver/storages/redis/base.hpp>
12#include <userver/storages/redis/command_control.hpp>
13#include <userver/storages/redis/exception.hpp>
14#include <userver/storages/redis/scan_tag.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::redis {
19
20using Longitude = utils::StrongTypedef<struct LongitudeTag, double>;
21using Latitude = utils::StrongTypedef<struct LatitudeTag, double>;
22using BoxWidth = utils::StrongTypedef<struct BoxWidthTag, double>;
23using BoxHeight = utils::StrongTypedef<struct BoxHeightTag, double>;
24
26 std::optional<size_t> offset;
27 std::optional<size_t> count;
28};
29
30struct GeoaddArg {
31 double lon;
32 double lat;
33 std::string member;
34};
35
37 enum class Sort { kNone, kAsc, kDesc };
38 enum class Unit { kM, kKm, kMi, kFt };
39
40 Unit unit = Unit::kM;
41 bool withcoord = false;
42 bool withdist = false;
43 bool withhash = false;
44 size_t count = 0;
45 Sort sort = Sort::kNone;
46};
47
49 enum class Sort { kNone, kAsc, kDesc };
50 enum class Unit { kM, kKm, kMi, kFt };
51
52 Unit unit = Unit::kM;
53 bool withcoord = false;
54 bool withdist = false;
55 bool withhash = false;
56 size_t count = 0;
57 Sort sort = Sort::kNone;
58};
59
61 enum class Exist { kAddAlways, kAddIfNotExist, kAddIfExist };
62 enum class Compare { kNone, kGreaterThan, kLessThan };
63 enum class ReturnValue { kAddedCount, kChangedCount };
64
65 ZaddOptions() = default;
66 constexpr ZaddOptions(
67 Exist exist,
68 ReturnValue return_value = ReturnValue::kAddedCount,
69 Compare compare = Compare::kNone
70 )
71 : exist(exist),
72 compare(compare),
73 return_value(return_value)
74 {}
75 constexpr ZaddOptions(Exist exist, Compare compare, ReturnValue return_value = ReturnValue::kAddedCount)
76 : exist(exist),
77 compare(compare),
78 return_value(return_value)
79 {}
80
81 constexpr ZaddOptions(ReturnValue return_value, Exist exist = Exist::kAddAlways, Compare compare = Compare::kNone)
82 : exist(exist),
83 compare(compare),
84 return_value(return_value)
85 {}
86 constexpr ZaddOptions(ReturnValue return_value, Compare compare, Exist exist = Exist::kAddAlways)
87 : exist(exist),
88 compare(compare),
89 return_value(return_value)
90 {}
91
92 constexpr ZaddOptions(
93 Compare compare,
94 Exist exist = Exist::kAddAlways,
95 ReturnValue return_value = ReturnValue::kAddedCount
96 )
97 : exist(exist),
98 compare(compare),
99 return_value(return_value)
100 {}
101 constexpr ZaddOptions(Compare compare, ReturnValue return_value, Exist exist = Exist::kAddAlways)
102 : exist(exist),
103 compare(compare),
104 return_value(return_value)
105 {}
106
107 Exist exist = Exist::kAddAlways;
108 Compare compare = Compare::kNone;
109 ReturnValue return_value = ReturnValue::kAddedCount;
110};
111
112constexpr ZaddOptions operator|(ZaddOptions::Exist exist, ZaddOptions::ReturnValue return_value) {
113 return {exist, return_value};
114}
115constexpr ZaddOptions operator|(ZaddOptions::Exist exist, ZaddOptions::Compare compare) { return {exist, compare}; }
116constexpr ZaddOptions operator|(ZaddOptions::Compare compare, ZaddOptions::Exist exist) { return {compare, exist}; }
117constexpr ZaddOptions operator|(ZaddOptions::Compare compare, ZaddOptions::ReturnValue return_value) {
118 return {compare, return_value};
119}
120constexpr ZaddOptions operator|(ZaddOptions::ReturnValue return_value, ZaddOptions::Exist exist) {
121 return {return_value, exist};
122}
123constexpr ZaddOptions operator|(ZaddOptions::ReturnValue return_value, ZaddOptions::Compare compare) {
124 return {return_value, compare};
125}
126
127/// @brief A command option to use in Scan, Hscan, Scan and Zscan commands.
128///
129/// Sample usage:
130/// @snippet redis/src/storages/redis/client_scan_redistest.cpp Sample Scan usage
131class Match final {
132public:
133 explicit Match(std::string value)
134 : value_(std::move(value))
135 {}
136
137 const std::string& Get() const& { return value_; }
138
139 std::string Get() && { return std::move(value_); }
140
141private:
142 std::string value_;
143};
144
145/// @brief A hint for Scan, Hscan, Scan and Zscan commands.
146class Count final {
147public:
148 constexpr explicit Count(std::size_t value) noexcept : value_(value) {}
149
150 constexpr std::size_t Get() const noexcept { return value_; }
151
152private:
153 std::size_t value_;
154};
155
156/// @brief A command option to use in Scan, Hscan, Scan and Zscan commands that combines Match and Count options.
158public:
159 using Match = storages::redis::Match;
160 using Count = storages::redis::Count;
161
162 ScanOptionsGeneric() = default;
163
164 ScanOptionsGeneric(const ScanOptionsGeneric& other) = default;
165 ScanOptionsGeneric& operator=(const ScanOptionsGeneric& other) = default;
166
167 ScanOptionsGeneric(ScanOptionsGeneric&& other) = default;
168 ScanOptionsGeneric& operator=(ScanOptionsGeneric&& other) = default;
169
170 template <typename... Args>
171 ScanOptionsGeneric(Args... args) {
172 (Apply(std::move(args)), ...);
173 }
174
175 const std::optional<Match>& GetMatchOptional() const noexcept { return pattern_; }
176
177 const std::optional<Count>& GetCountOptional() const noexcept { return count_; }
178
179 std::optional<Match> ExtractMatch() noexcept { return std::move(pattern_); }
180
181 std::optional<Count> ExtractCount() noexcept { return std::move(count_); }
182
183private:
184 void Apply(Match pattern) {
185 if (pattern_) {
186 throw InvalidArgumentException("duplicate Match parameter");
187 }
188 pattern_ = std::move(pattern);
189 }
190
191 void Apply(Count count) {
192 if (count_) {
193 throw InvalidArgumentException("duplicate Count parameter");
194 }
195 count_ = count;
196 }
197
198 std::optional<Match> pattern_;
199 std::optional<Count> count_;
200};
201
202template <ScanTag TScanTag>
203using ScanOptionsTmpl [[deprecated("Just use ScanOptionsGeneric")]] = ScanOptionsGeneric;
204
205using ScanOptions = ScanOptionsGeneric;
206using SscanOptions = ScanOptionsGeneric;
207using HscanOptions = ScanOptionsGeneric;
208using ZscanOptions = ScanOptionsGeneric;
209
211 enum class Exist { kSetAlways, kSetIfNotExist, kSetIfExist };
212
213 int seconds = 0;
214 int milliseconds = 0;
215 Exist exist = Exist::kSetAlways;
216};
217
219 enum class Exist { kSetAlways, kSetIfNotExist, kSetIfExist };
220 enum class Compare { kNone, kGreaterThan, kLessThan };
221
222 ExpireOptions() = default;
223 constexpr ExpireOptions(Exist exist, Compare compare = Compare::kNone)
224 : exist(exist),
225 compare(compare)
226 {
227 if (exist == Exist::kSetIfNotExist && compare != Compare::kNone) {
228 // @see https://redis-docs.ru/commands/expire/
229 throw std::invalid_argument("When exist is kSetIfNotExist, compare must be kNone");
230 }
231 }
232
233 constexpr ExpireOptions(Compare compare, Exist exist = Exist::kSetAlways)
234 : exist(exist),
235 compare(compare)
236 {
237 if (exist == Exist::kSetIfNotExist && compare != Compare::kNone) {
238 // @see https://redis-docs.ru/commands/expire/
239 throw std::invalid_argument("When exist is kSetIfNotExist, compare must be kNone");
240 }
241 }
242
243 Exist exist = Exist::kSetAlways;
244 Compare compare = Compare::kNone;
245};
246
248 bool withscores = false;
249};
250
252 ScoreOptions score_options;
253 RangeOptions range_options;
254};
255
256/// @brief Data type for JSON.MSET command arguments (key + path + JSON value triplet).
257struct JsonKeyPathValue final {
258 std::string key;
259 std::string path;
260 formats::json::Value value;
261};
262
263/// @brief Options for HGETEX command — at most one TTL action per call.
265 /// What to do with the TTL of each fetched field.
266 enum class TtlAction : std::uint8_t {
267 /// Leave the TTL unchanged (no modifier on the wire).
269 /// EX seconds — set TTL to a duration; @c ttl is interpreted as whole seconds.
271 /// PX milliseconds — set TTL to a duration; @c ttl is used as-is in milliseconds.
273 /// EXAT unix-ts-sec — set absolute expiration; @c ttl is interpreted as whole seconds since epoch.
275 /// PXAT unix-ts-ms — set absolute expiration; @c ttl is used as-is in milliseconds since epoch.
277 /// PERSIST — remove TTL from the fields; @c ttl is ignored.
279 };
280
281 TtlAction ttl_action{TtlAction::kKeep};
282 std::chrono::milliseconds ttl{0};
283
284 /// @brief Do not touch the TTL of the read fields (no modifier on the wire).
286 /// @brief Remove TTL on all read fields (PERSIST modifier).
288 /// @brief Set TTL to a relative duration. Posted on the wire as PX (ms-precision).
289 static HgetexOptions Expire(std::chrono::milliseconds ttl);
290 /// @brief Set TTL to an absolute deadline. Posted on the wire as PXAT (ms-precision).
291 static HgetexOptions ExpireAt(std::chrono::system_clock::time_point deadline);
292};
293
294/// @brief Single field/value entry for HSETEX.
296 std::string field;
297 std::string value;
298};
299
300/// @brief Options for HSETEX (FNX/FXX combined with EX/PX/EXAT/PXAT/KEEPTTL).
302 /// Existence precondition for the affected fields.
303 enum class Exist : std::uint8_t {
304 /// No precondition (default).
306 /// FNX — set only if none of the affected fields currently exists.
308 /// FXX — set only if all of the affected fields currently exist.
310 };
311 /// What TTL clause to attach to the new values.
312 enum class TtlAction : std::uint8_t {
313 /// No TTL clause on the wire — server applies default behavior.
315 /// EX seconds.
317 /// PX milliseconds.
319 /// EXAT unix-ts-sec.
321 /// PXAT unix-ts-ms.
323 /// KEEPTTL — keep the existing TTL of each field if any; @c ttl is ignored.
325 };
326
328 TtlAction ttl_action{TtlAction::kNone};
329 std::chrono::milliseconds ttl{0};
330
331 /// @brief No TTL clause on the wire — server applies default behavior.
333 /// @brief KEEPTTL — keep the existing TTL of each field if any.
335 /// @brief Set TTL to a relative duration. Posted on the wire as PX (ms-precision).
336 static HsetexOptions Expire(std::chrono::milliseconds ttl);
337 /// @brief Set TTL to an absolute deadline. Posted on the wire as PXAT (ms-precision).
338 static HsetexOptions ExpireAt(std::chrono::system_clock::time_point deadline);
339
340 /// @brief Chainable modifier — FNX: write only if **none** of the affected
341 /// fields currently exist.
344 return *this;
345 }
346 /// @brief Chainable modifier — FXX: write only if **all** of the affected
347 /// fields currently exist.
349 exist = Exist::kSetIfAllExist;
350 return *this;
351 }
352 /// @brief FNX (rvalue overload).
355 return std::move(*this);
356 }
357 /// @brief FXX (rvalue overload).
359 exist = Exist::kSetIfAllExist;
360 return std::move(*this);
361 }
362};
363
364} // namespace storages::redis
365
366USERVER_NAMESPACE_END