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
218/// @brief Options for MSETEX (NX/XX combined with EX/PX/EXAT/PXAT/KEEPTTL).
220 /// Existence precondition for the affected keys.
221 enum class Exist : std::uint8_t {
222 /// No precondition (default).
224 /// NX — set only if none of the affected keys currently exists.
226 /// XX — set only if all of the affected keys currently exist.
228 };
229 /// What TTL clause to attach to the new values.
230 enum class TtlAction : std::uint8_t {
231 /// No TTL clause on the wire — server applies default behavior.
233 /// EX seconds.
235 /// PX milliseconds.
237 /// EXAT unix-ts-sec.
239 /// PXAT unix-ts-ms.
241 /// KEEPTTL — keep the existing TTL of each key if any; @c ttl is ignored.
243 };
244
246 TtlAction ttl_action{TtlAction::kNone};
247 std::chrono::milliseconds ttl{0};
248
249 /// @brief No TTL clause on the wire — server applies default behavior.
251 /// @brief KEEPTTL — keep the existing TTL of each key if any.
253 /// @brief Set TTL to a relative duration. Posted on the wire as PX (ms-precision).
254 static MsetexOptions Expire(std::chrono::milliseconds ttl);
255 /// @brief Set TTL to an absolute deadline. Posted on the wire as PXAT (ms-precision).
256 static MsetexOptions ExpireAt(std::chrono::system_clock::time_point deadline);
257
258 /// @brief Chainable modifier — NX: write only if **none** of the affected
259 /// keys currently exist.
262 return *this;
263 }
264 /// @brief Chainable modifier — XX: write only if **all** of the affected
265 /// keys currently exist.
267 exist = Exist::kSetIfAllExist;
268 return *this;
269 }
270 /// @brief NX (rvalue overload).
273 return std::move(*this);
274 }
275 /// @brief XX (rvalue overload).
277 exist = Exist::kSetIfAllExist;
278 return std::move(*this);
279 }
280};
281
283 enum class Exist { kSetAlways, kSetIfNotExist, kSetIfExist };
284 enum class Compare { kNone, kGreaterThan, kLessThan };
285
286 ExpireOptions() = default;
287 constexpr ExpireOptions(Exist exist, Compare compare = Compare::kNone)
288 : exist(exist),
289 compare(compare)
290 {
291 if (exist == Exist::kSetIfNotExist && compare != Compare::kNone) {
292 // @see https://redis-docs.ru/commands/expire/
293 throw std::invalid_argument("When exist is kSetIfNotExist, compare must be kNone");
294 }
295 }
296
297 constexpr ExpireOptions(Compare compare, Exist exist = Exist::kSetAlways)
298 : exist(exist),
299 compare(compare)
300 {
301 if (exist == Exist::kSetIfNotExist && compare != Compare::kNone) {
302 // @see https://redis-docs.ru/commands/expire/
303 throw std::invalid_argument("When exist is kSetIfNotExist, compare must be kNone");
304 }
305 }
306
307 Exist exist = Exist::kSetAlways;
308 Compare compare = Compare::kNone;
309};
310
312 bool withscores = false;
313};
314
316 ScoreOptions score_options;
317 RangeOptions range_options;
318};
319
320/// @brief Data type for JSON.MSET command arguments (key + path + JSON value triplet).
321struct JsonKeyPathValue final {
322 std::string key;
323 std::string path;
324 formats::json::Value value;
325};
326
327/// @brief Options for HGETEX command — at most one TTL action per call.
329 /// What to do with the TTL of each fetched field.
330 enum class TtlAction : std::uint8_t {
331 /// Leave the TTL unchanged (no modifier on the wire).
333 /// EX seconds — set TTL to a duration; @c ttl is interpreted as whole seconds.
335 /// PX milliseconds — set TTL to a duration; @c ttl is used as-is in milliseconds.
337 /// EXAT unix-ts-sec — set absolute expiration; @c ttl is interpreted as whole seconds since epoch.
339 /// PXAT unix-ts-ms — set absolute expiration; @c ttl is used as-is in milliseconds since epoch.
341 /// PERSIST — remove TTL from the fields; @c ttl is ignored.
343 };
344
345 TtlAction ttl_action{TtlAction::kKeep};
346 std::chrono::milliseconds ttl{0};
347
348 /// @brief Do not touch the TTL of the read fields (no modifier on the wire).
350 /// @brief Remove TTL on all read fields (PERSIST modifier).
352 /// @brief Set TTL to a relative duration. Posted on the wire as PX (ms-precision).
353 static HgetexOptions Expire(std::chrono::milliseconds ttl);
354 /// @brief Set TTL to an absolute deadline. Posted on the wire as PXAT (ms-precision).
355 static HgetexOptions ExpireAt(std::chrono::system_clock::time_point deadline);
356};
357
358/// @brief Single field/value entry for HSETEX.
360 std::string field;
361 std::string value;
362};
363
364/// @brief Options for HSETEX (FNX/FXX combined with EX/PX/EXAT/PXAT/KEEPTTL).
366 /// Existence precondition for the affected fields.
367 enum class Exist : std::uint8_t {
368 /// No precondition (default).
370 /// FNX — set only if none of the affected fields currently exists.
372 /// FXX — set only if all of the affected fields currently exist.
374 };
375 /// What TTL clause to attach to the new values.
376 enum class TtlAction : std::uint8_t {
377 /// No TTL clause on the wire — server applies default behavior.
379 /// EX seconds.
381 /// PX milliseconds.
383 /// EXAT unix-ts-sec.
385 /// PXAT unix-ts-ms.
387 /// KEEPTTL — keep the existing TTL of each field if any; @c ttl is ignored.
389 };
390
392 TtlAction ttl_action{TtlAction::kNone};
393 std::chrono::milliseconds ttl{0};
394
395 /// @brief No TTL clause on the wire — server applies default behavior.
397 /// @brief KEEPTTL — keep the existing TTL of each field if any.
399 /// @brief Set TTL to a relative duration. Posted on the wire as PX (ms-precision).
400 static HsetexOptions Expire(std::chrono::milliseconds ttl);
401 /// @brief Set TTL to an absolute deadline. Posted on the wire as PXAT (ms-precision).
402 static HsetexOptions ExpireAt(std::chrono::system_clock::time_point deadline);
403
404 /// @brief Chainable modifier — FNX: write only if **none** of the affected
405 /// fields currently exist.
408 return *this;
409 }
410 /// @brief Chainable modifier — FXX: write only if **all** of the affected
411 /// fields currently exist.
413 exist = Exist::kSetIfAllExist;
414 return *this;
415 }
416 /// @brief FNX (rvalue overload).
419 return std::move(*this);
420 }
421 /// @brief FXX (rvalue overload).
423 exist = Exist::kSetIfAllExist;
424 return std::move(*this);
425 }
426};
427
428} // namespace storages::redis
429
430USERVER_NAMESPACE_END