rustis/commands/string_commands.rs
1use crate::{
2 client::{PreparedCommand, prepare_command},
3 commands::{RequestPolicy, ResponsePolicy},
4 resp::{FastPathCommandBuilder, Response, cmd},
5};
6use serde::{
7 Deserialize, Deserializer, Serialize,
8 de::{self, SeqAccess, Visitor},
9};
10use std::fmt;
11
12/// A group of Redis commands related to [`Strings`](https://redis.io/docs/data-types/strings/)
13/// # See Also
14/// [Redis Generic Commands](https://redis.io/commands/?group=string)
15pub trait StringCommands<'a>: Sized {
16 /// If key already exists and is a string,
17 /// this command appends the value at the end of the string.
18 /// If key does not exist it is created and set as an empty string,
19 /// so APPEND will be similar to SET in this special case.
20 ///
21 /// # Return
22 /// the length of the string after the append operation.
23 ///
24 /// # See Also
25 /// [<https://redis.io/commands/append/>](https://redis.io/commands/append/)
26 #[must_use]
27 fn append(
28 self,
29 key: impl Serialize,
30 value: impl Serialize,
31 ) -> PreparedCommand<'a, Self, usize> {
32 prepare_command(self, cmd("APPEND").key(key).arg(value))
33 }
34
35 /// Decrements the number stored at key by one.
36 ///
37 /// If the key does not exist, it is set to 0 before performing the operation.
38 /// An error is returned if the key contains a value of the wrong type or contains
39 /// a string that can not be represented as integer.
40 /// This operation is limited to 64 bit signed integers.
41 ///
42 /// # Return
43 /// the value of key after the decrement
44 ///
45 /// # See Also
46 /// [<https://redis.io/commands/decr/>](https://redis.io/commands/decr/)
47 #[must_use]
48 fn decr(self, key: impl Serialize) -> PreparedCommand<'a, Self, i64> {
49 prepare_command(self, cmd("DECR").key(key))
50 }
51
52 /// Decrements the number stored at key by one.
53 ///
54 /// If the key does not exist, it is set to 0 before performing the operation.
55 /// An error is returned if the key contains a value of the wrong type or contains
56 /// a string that can not be represented as integer.
57 /// This operation is limited to 64 bit signed integers.
58 ///
59 /// # Return
60 /// the value of key after the decrement
61 ///
62 /// # See Also
63 /// [<https://redis.io/commands/decrby/>](https://redis.io/commands/decrby/)
64 #[must_use]
65 fn decrby(self, key: impl Serialize, decrement: i64) -> PreparedCommand<'a, Self, i64> {
66 prepare_command(self, cmd("DECRBY").key(key).arg(decrement))
67 }
68
69 /// Get the value of key.
70 ///
71 /// Get the value of key. If the key does not exist the special
72 /// value nil is returned. An error is returned if the value
73 /// stored at key is not a string, because GET only handles
74 /// string values.
75 ///
76 /// # Return
77 /// the value of key, or `nil` when key does not exist.
78 ///
79 /// # Example
80 /// ```
81 /// use rustis::{
82 /// client::{Client, ClientPreparedCommand},
83 /// commands::{FlushingMode, ServerCommands, StringCommands},
84 /// resp::{cmd},
85 /// Result
86 /// };
87 ///
88 /// #[cfg_attr(feature = "tokio-runtime", tokio::main)]
89 /// #[cfg_attr(feature = "async-std-runtime", async_std::main)]
90 /// async fn main() -> Result<()> {
91 /// let client = Client::connect("127.0.0.1:6379").await?;
92 /// client.flushall(FlushingMode::Sync).await?;
93 ///
94 /// // return value can be an Option<String>...
95 /// let value: Option<String> = client.get("key").await?;
96 /// assert_eq!(None, value);
97 ///
98 /// // ... or it can be directly a String.
99 /// // In this cas a `nil` value will result in an empty String
100 /// let value: String = client.get("key").await?;
101 /// assert_eq!("", value);
102 ///
103 /// client.set("key", "value").await?;
104 /// let value: String = client.get("key").await?;
105 /// assert_eq!("value", value);
106 ///
107 /// Ok(())
108 /// }
109 /// ```
110 ///
111 /// # See Also
112 /// [<https://redis.io/commands/get/>](https://redis.io/commands/get/)
113 #[must_use]
114 fn get<R: Response>(self, key: impl Serialize) -> PreparedCommand<'a, Self, R> {
115 prepare_command(self, FastPathCommandBuilder::get(key))
116 }
117
118 /// Get the value of key and delete the key.
119 ///
120 /// This command is similar to GET, except for the fact that it also deletes the key on success
121 /// (if and only if the key's value type is a string).
122 ///
123 /// # Return
124 /// the value of key, `nil` when key does not exist, or an error if the key's value type isn't a string.
125 ///
126 /// # See Also
127 /// [<https://redis.io/commands/getdel/>](https://redis.io/commands/getdel/)
128 #[must_use]
129 fn getdel<R: Response>(self, key: impl Serialize) -> PreparedCommand<'a, Self, R> {
130 prepare_command(self, cmd("GETDEL").key(key))
131 }
132
133 /// Get the value of key and optionally set its expiration. GETEX is similar to GET, but is a write command with additional options.
134 ///
135 /// Decrements the number stored at key by decrement.
136 /// If the key does not exist, it is set to 0 before performing the operation.
137 /// An error is returned if the key contains a value of the wrong type
138 /// or contains a string that can not be represented as integer.
139 /// This operation is limited to 64 bit signed integers.
140 ///
141 /// # Return
142 /// the value of key, or `nil` when key does not exist.
143 ///
144 /// # Example
145 /// ```
146 /// use rustis::{
147 /// client::{Client, ClientPreparedCommand},
148 /// commands::{FlushingMode, GetExOptions, GenericCommands, ServerCommands, StringCommands},
149 /// resp::cmd,
150 /// Result,
151 /// };
152 ///
153 /// #[cfg_attr(feature = "tokio-runtime", tokio::main)]
154 /// #[cfg_attr(feature = "async-std-runtime", async_std::main)]
155 /// async fn main() -> Result<()> {
156 /// let client = Client::connect("127.0.0.1:6379").await?;
157 /// client.flushall(FlushingMode::Sync).await?;
158 ///
159 /// client.set("key", "value").await?;
160 /// let value: String = client.getex("key", GetExOptions::Ex(60)).await?;
161 /// assert_eq!("value", value);
162 ///
163 /// let ttl = client.ttl("key").await?;
164 /// assert!(59 <= ttl && ttl <= 60);
165 ///
166 /// Ok(())
167 /// }
168 /// ```
169 ///
170 /// # See Also
171 /// [<https://redis.io/commands/getex/>](https://redis.io/commands/getex/)
172 #[must_use]
173 fn getex<R: Response>(
174 self,
175 key: impl Serialize,
176 options: GetExOptions,
177 ) -> PreparedCommand<'a, Self, R> {
178 prepare_command(self, cmd("GETEX").key(key).arg(options))
179 }
180
181 /// Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive).
182 ///
183 /// Negative offsets can be used in order to provide an offset starting from the end of the string.
184 /// So -1 means the last character, -2 the penultimate and so forth.
185 ///
186 /// The function handles out of range requests by limiting the resulting range to the actual length of the string.
187 ///
188 /// # Example
189 /// ```
190 /// use rustis::{
191 /// client::Client,
192 /// commands::{FlushingMode, ServerCommands, StringCommands},
193 /// Result,
194 /// };
195 ///
196 /// #[cfg_attr(feature = "tokio-runtime", tokio::main)]
197 /// #[cfg_attr(feature = "async-std-runtime", async_std::main)]
198 /// async fn main() -> Result<()> {
199 /// let client = Client::connect("127.0.0.1:6379").await?;
200 /// client.flushall(FlushingMode::Sync).await?;
201 /// client.set("mykey", "This is a string").await?;
202 ///
203 /// let value: String = client.getrange("mykey", 0, 3).await?;
204 /// assert_eq!("This", value);
205 /// let value: String = client.getrange("mykey", -3, -1).await?;
206 /// assert_eq!("ing", value);
207 /// let value: String = client.getrange("mykey", 0, -1).await?;
208 /// assert_eq!("This is a string", value);
209 /// let value: String = client.getrange("mykey", 10, 100).await?;
210 /// assert_eq!("string", value);
211 /// Ok(())
212 /// }
213 /// ```
214 ///
215 /// # See Also
216 /// [<https://redis.io/commands/getrange/>](https://redis.io/commands/getrange/)
217 #[must_use]
218 fn getrange<R: Response>(
219 self,
220 key: impl Serialize,
221 start: isize,
222 end: isize,
223 ) -> PreparedCommand<'a, Self, R> {
224 prepare_command(self, cmd("GETRANGE").key(key).arg(start).arg(end))
225 }
226
227 /// Atomically sets key to value and returns the old value stored at key.
228 /// Returns an error when key exists but does not hold a string value.
229 /// Any previous time to live associated with the key is discarded on successful SET operation.
230 ///
231 /// # Return
232 /// the old value stored at key, or nil when key did not exist.
233 ///
234 /// # See Also
235 /// [<https://redis.io/commands/getset/>](https://redis.io/commands/getset/)
236 #[must_use]
237 fn getset<R: Response>(
238 self,
239 key: impl Serialize,
240 value: impl Serialize,
241 ) -> PreparedCommand<'a, Self, R> {
242 prepare_command(self, cmd("GETSET").key(key).arg(value))
243 }
244
245 /// Increments the number stored at key by one.
246 ///
247 /// If the key does not exist, it is set to 0 before performing the operation.
248 /// An error is returned if the key contains a value of the wrong type
249 /// or contains a string that can not be represented as integer.
250 /// This operation is limited to 64 bit signed integers.
251 ///
252 /// Note: this is a string operation because Redis does not have a dedicated integer type.
253 /// The string stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.
254 ///
255 /// Redis stores integers in their integer representation, so for string values that actually hold an integer,
256 /// there is no overhead for storing the string representation of the integer.
257 ///
258 /// # Return
259 /// the value of key after the increment
260 ///
261 /// # See Also
262 /// [<https://redis.io/commands/incr/>](https://redis.io/commands/incr/)
263 #[must_use]
264 fn incr(self, key: impl Serialize) -> PreparedCommand<'a, Self, i64> {
265 prepare_command(self, cmd("INCR").key(key))
266 }
267
268 /// Increments the number stored at key by increment.
269 ///
270 /// If the key does not exist, it is set to 0 before performing the operation.
271 /// An error is returned if the key contains a value of the wrong type
272 /// or contains a string that can not be represented as integer.
273 /// This operation is limited to 64 bit signed integers.
274 ///
275 /// See [incr](StringCommands::incr) for extra information on increment/decrement operations.
276 ///
277 /// # Return
278 /// the value of key after the increment
279 ///
280 /// # See Also
281 /// [<https://redis.io/commands/incrby/>](https://redis.io/commands/incrby/)
282 #[must_use]
283 fn incrby(self, key: impl Serialize, increment: i64) -> PreparedCommand<'a, Self, i64> {
284 prepare_command(self, cmd("INCRBY").key(key).arg(increment))
285 }
286
287 ///Increment the string representing a floating point number stored at key by the specified increment.
288 /// By using a negative increment value, the result is that the value stored at the key is decremented (by the obvious properties of addition).
289 /// If the key does not exist, it is set to 0 before performing the operation.
290 /// An error is returned if one of the following conditions occur:
291 ///
292 /// - The key contains a value of the wrong type (not a string).
293 ///
294 /// - The current key content or the specified increment are not parsable as a double precision floating point number.
295 ///
296 /// If the command is successful the new incremented value is stored as the new value of the key (replacing the old one),
297 /// and returned to the caller as a string.
298 ///
299 /// Both the value already contained in the string key and the increment argument can be optionally provided in exponential notation,
300 /// however the value computed after the increment is stored consistently in the same format, that is,
301 /// an integer number followed (if needed) by a dot, and a variable number of digits representing the decimal part of the number.
302 /// Trailing zeroes are always removed.
303 ///
304 /// The precision of the output is fixed at 17 digits after the decimal point
305 /// regardless of the actual internal precision of the computation.
306 ///
307 /// # Return
308 /// the value of key after the increment
309 ///
310 /// # See Also
311 /// [<https://redis.io/commands/incrbyfloat/>](https://redis.io/commands/incrbyfloat/)
312 #[must_use]
313 fn incrbyfloat(self, key: impl Serialize, increment: f64) -> PreparedCommand<'a, Self, f64> {
314 prepare_command(self, cmd("INCRBYFLOAT").key(key).arg(increment))
315 }
316
317 /// The LCS command implements the longest common subsequence algorithm
318 ///
319 /// # Return
320 /// The string representing the longest common substring.
321 ///
322 /// # See Also
323 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
324 #[must_use]
325 fn lcs<R: Response>(
326 self,
327 key1: impl Serialize,
328 key2: impl Serialize,
329 ) -> PreparedCommand<'a, Self, R> {
330 prepare_command(self, cmd("LCS").key(key1).arg(key2))
331 }
332
333 /// The LCS command implements the longest common subsequence algorithm
334 ///
335 /// # Return
336 /// The length of the longest common substring.
337 ///
338 /// # See Also
339 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
340 #[must_use]
341 fn lcs_len(
342 self,
343 key1: impl Serialize,
344 key2: impl Serialize,
345 ) -> PreparedCommand<'a, Self, usize> {
346 prepare_command(self, cmd("LCS").key(key1).key(key2).arg("LEN"))
347 }
348
349 /// The LCS command implements the longest common subsequence algorithm
350 ///
351 /// # Return
352 /// An array with the LCS length and all the ranges in both the strings,
353 /// start and end offset for each string, where there are matches.
354 /// When `with_match_len` is given each match will also have the length of the match
355 ///
356 /// # See Also
357 /// [<https://redis.io/commands/lcs/>](https://redis.io/commands/lcs/)
358 #[must_use]
359 fn lcs_idx(
360 self,
361 key1: impl Serialize,
362 key2: impl Serialize,
363 min_match_len: Option<usize>,
364 with_match_len: bool,
365 ) -> PreparedCommand<'a, Self, LcsResult> {
366 prepare_command(
367 self,
368 cmd("LCS")
369 .key(key1)
370 .key(key2)
371 .arg("IDX")
372 .arg(min_match_len.map(|len| ("MINMATCHLEN", len)))
373 .arg_if(with_match_len, "WITHMATCHLEN"),
374 )
375 }
376
377 /// Returns the values of all specified keys.
378 ///
379 /// For every key that does not hold a string value or does not exist,
380 /// the special value nil is returned. Because of this, the operation never fails.
381 ///
382 /// # Return
383 /// Array reply: list of values at the specified keys.
384 ///
385 /// # See Also
386 /// [<https://redis.io/commands/mget/>](https://redis.io/commands/mget/)
387 #[must_use]
388 fn mget<R: Response>(self, keys: impl Serialize) -> PreparedCommand<'a, Self, R> {
389 prepare_command(
390 self,
391 cmd("MGET")
392 .key(keys)
393 .cluster_info(RequestPolicy::MultiShard, None, 1),
394 )
395 }
396
397 /// Sets the given keys to their respective values.
398 ///
399 /// # Return
400 /// always OK since MSET can't fail.
401 ///
402 /// # See Also
403 /// [<https://redis.io/commands/mset/>](https://redis.io/commands/mset/)
404 #[must_use]
405 fn mset(self, items: impl Serialize) -> PreparedCommand<'a, Self, ()> {
406 prepare_command(
407 self,
408 cmd("MSET").key_with_step(items, 2).cluster_info(
409 RequestPolicy::MultiShard,
410 ResponsePolicy::AllSucceeded,
411 2,
412 ),
413 )
414 }
415
416 /// Atomically sets multiple string keys with an optional shared expiration in a single operation.
417 ///
418 /// # Return
419 /// * `false` - if none of the keys were set
420 /// * `true` - if all of the keys were set.
421 ///
422 /// # See Also
423 /// [<https://redis.io/commands/mset/>](https://redis.io/commands/mset/)
424 #[must_use]
425 fn msetex<'b>(
426 self,
427 items: impl Serialize,
428 condition: impl Into<Option<SetCondition<'b>>>,
429 expiration: impl Into<Option<SetExpiration>>,
430 ) -> PreparedCommand<'a, Self, bool> {
431 prepare_command(
432 self,
433 cmd("MSETEX")
434 .key_with_step(items, 2)
435 .arg(condition.into())
436 .arg(expiration.into())
437 .cluster_info(RequestPolicy::MultiShard, ResponsePolicy::AllSucceeded, 2),
438 )
439 }
440
441 /// Sets the given keys to their respective values.
442 /// MSETNX will not perform any operation at all even if just a single key already exists.
443 ///
444 /// Because of this semantic MSETNX can be used in order to set different keys representing
445 /// different fields of a unique logic object in a way that ensures that either
446 /// all the fields or none at all are set.
447 ///
448 /// MSETNX is atomic, so all given keys are set at once. It is not possible for
449 /// clients to see that some of the keys were updated while others are unchanged.
450 ///
451 /// # Return
452 /// specifically:
453 /// - 1 if the all the keys were set.
454 /// - 0 if no key was set (at least one key already existed).
455 ///
456 /// # See Also
457 /// [<https://redis.io/commands/msetnx/>](https://redis.io/commands/msetnx/)
458 #[must_use]
459 fn msetnx(self, items: impl Serialize) -> PreparedCommand<'a, Self, bool> {
460 prepare_command(
461 self,
462 cmd("MSETNX")
463 .key_with_step(items, 2)
464 .cluster_info(None, None, 2),
465 )
466 }
467
468 /// Works exactly like [setex](StringCommands::setex) with the sole
469 /// difference that the expire time is specified in milliseconds instead of seconds.
470 ///
471 /// If key already holds a value, it is overwritten, regardless of its type.
472 /// Any previous time to live associated with the key is discarded on successful SET operation.
473 ///
474 /// # See Also
475 /// [<https://redis.io/commands/psetex/>](https://redis.io/commands/psetex/)
476 #[must_use]
477 fn psetex(
478 self,
479 key: impl Serialize,
480 milliseconds: u64,
481 value: impl Serialize,
482 ) -> PreparedCommand<'a, Self, ()> {
483 prepare_command(self, cmd("PSETEX").key(key).arg(milliseconds).arg(value))
484 }
485
486 ///Set key to hold the string value.
487 ///
488 /// If key already holds a value, it is overwritten, regardless of its type.
489 /// Any previous time to live associated with the key is discarded on successful SET operation.
490 ///
491 /// # See Also
492 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
493 #[must_use]
494 fn set(self, key: impl Serialize, value: impl Serialize) -> PreparedCommand<'a, Self, ()> {
495 prepare_command(self, FastPathCommandBuilder::set(key, value))
496 }
497
498 /// Set key to hold the string value.
499 ///
500 /// # Return
501 /// * `true` if SET was executed correctly.
502 /// * `false` if the SET operation was not performed because the user
503 /// specified the NX or XX option but the condition was not met.
504 ///
505 /// # See Also
506 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
507 #[must_use]
508 fn set_with_options<'b>(
509 self,
510 key: impl Serialize,
511 value: impl Serialize,
512 condition: impl Into<Option<SetCondition<'b>>>,
513 expiration: impl Into<Option<SetExpiration>>,
514 ) -> PreparedCommand<'a, Self, bool> {
515 prepare_command(
516 self,
517 cmd("SET")
518 .key(key)
519 .arg(value)
520 .arg(condition.into())
521 .arg(expiration.into()),
522 )
523 }
524
525 /// Set key to hold the string value wit GET option enforced
526 ///
527 /// # See Also
528 /// [<https://redis.io/commands/set/>](https://redis.io/commands/set/)
529 #[must_use]
530 fn set_get_with_options<'b, R: Response>(
531 self,
532 key: impl Serialize,
533 value: impl Serialize,
534 condition: impl Into<Option<SetCondition<'b>>>,
535 expiration: impl Into<Option<SetExpiration>>,
536 ) -> PreparedCommand<'a, Self, R> {
537 prepare_command(
538 self,
539 cmd("SET")
540 .key(key)
541 .arg(value)
542 .arg(condition.into())
543 .arg("GET")
544 .arg(expiration.into()),
545 )
546 }
547
548 /// Set key to hold the string value and set key to timeout after a given number of seconds.
549 ///
550 /// # See Also
551 /// [<https://redis.io/commands/setex/>](https://redis.io/commands/setex/)
552 #[must_use]
553 fn setex(
554 self,
555 key: impl Serialize,
556 seconds: u64,
557 value: impl Serialize,
558 ) -> PreparedCommand<'a, Self, ()> {
559 prepare_command(self, cmd("SETEX").key(key).arg(seconds).arg(value))
560 }
561
562 /// Set key to hold string value if key does not exist.
563 ///
564 /// In that case, it is equal to SET.
565 /// When key already holds a value, no operation is performed.
566 /// SETNX is short for "SET if Not eXists".
567 ///
568 /// # Return
569 /// specifically:
570 /// * `true` - if the key was set
571 /// * `false` - if the key was not set
572 ///
573 /// # See Also
574 /// [<https://redis.io/commands/setnx/>](https://redis.io/commands/setnx/)
575 #[must_use]
576 fn setnx(self, key: impl Serialize, value: impl Serialize) -> PreparedCommand<'a, Self, bool> {
577 prepare_command(self, cmd("SETNX").key(key).arg(value))
578 }
579
580 /// Overwrites part of the string stored at key,
581 /// starting at the specified offset,
582 /// for the entire length of value.
583 ///
584 /// # Return
585 /// the length of the string after it was modified by the command.
586 ///
587 /// # See Also
588 /// [<https://redis.io/commands/setrange/>](https://redis.io/commands/setrange/)
589 #[must_use]
590 fn setrange(
591 self,
592 key: impl Serialize,
593 offset: usize,
594 value: impl Serialize,
595 ) -> PreparedCommand<'a, Self, usize> {
596 prepare_command(self, cmd("SETRANGE").key(key).arg(offset).arg(value))
597 }
598
599 /// Returns the length of the string value stored at key.
600 ///
601 /// An error is returned when key holds a non-string value.
602 ///
603 /// # Return
604 /// the length of the string at key, or 0 when key does not exist.
605 ///
606 /// # See Also
607 /// [<https://redis.io/commands/strlen/>](https://redis.io/commands/strlen/)
608 #[must_use]
609 fn strlen(self, key: impl Serialize) -> PreparedCommand<'a, Self, usize> {
610 prepare_command(self, cmd("STRLEN").key(key))
611 }
612
613 /// Returns the substring of the string value stored at key, determined by the offsets start and end (both are inclusive).
614 ///
615 /// Negative offsets can be used in order to provide an offset starting from the end of the string.
616 /// So -1 means the last character, -2 the penultimate and so forth.
617 ///
618 /// The function handles out of range requests by limiting the resulting range to the actual length of the string.
619 ///
620 /// # Example
621 /// ```
622 /// # use rustis::{
623 /// # client::Client,
624 /// # commands::{FlushingMode, ServerCommands, StringCommands},
625 /// # Result,
626 /// # };
627 ///
628 /// # #[cfg_attr(feature = "tokio-runtime", tokio::main)]
629 /// # #[cfg_attr(feature = "async-std-runtime", async_std::main)]
630 /// # async fn main() -> Result<()> {
631 /// # let client = Client::connect("127.0.0.1:6379").await?;
632 /// # client.flushdb(FlushingMode::Sync).await?;
633 /// client.set("mykey", "This is a string").await?;
634 ///
635 /// let value: String = client.substr("mykey", 0, 3).await?;
636 /// assert_eq!("This", value);
637 /// let value: String = client.substr("mykey", -3, -1).await?;
638 /// assert_eq!("ing", value);
639 /// let value: String = client.substr("mykey", 0, -1).await?;
640 /// assert_eq!("This is a string", value);
641 /// let value: String = client.substr("mykey", 10, 100).await?;
642 /// assert_eq!("string", value);
643 /// # Ok(())
644 /// # }
645 /// ```
646 ///
647 /// # See Also
648 /// [<https://redis.io/commands/substr/>](https://redis.io/commands/substr/)
649 #[must_use]
650 fn substr<R: Response>(
651 self,
652 key: impl Serialize,
653 start: isize,
654 end: isize,
655 ) -> PreparedCommand<'a, Self, R> {
656 prepare_command(self, cmd("SUBSTR").key(key).arg(start).arg(end))
657 }
658}
659
660/// Options for the [`getex`](StringCommands::getex) and the [`hgetex`](crate::commands::HashCommands::hgetex) commands
661#[derive(Serialize)]
662#[serde(rename_all = "UPPERCASE")]
663pub enum GetExOptions {
664 /// Set the specified expire time, in seconds.
665 Ex(u64),
666 /// Set the specified expire time, in milliseconds.
667 Px(u64),
668 /// Set the specified Unix time at which the key will expire, in seconds.
669 Exat(u64),
670 /// Set the specified Unix time at which the key will expire, in milliseconds.
671 Pxat(u64),
672 /// Remove the time to live associated with the key.
673 Persist,
674}
675
676/// Part of the result for the [`lcs`](StringCommands::lcs) command
677#[derive(Debug, PartialEq, Eq)]
678pub struct LcsMatch(pub (usize, usize), pub (usize, usize), pub Option<usize>);
679
680impl<'de> Deserialize<'de> for LcsMatch {
681 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
682 where
683 D: Deserializer<'de>,
684 {
685 struct LcsMatchVisitor;
686
687 impl<'de> Visitor<'de> for LcsMatchVisitor {
688 type Value = LcsMatch;
689
690 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
691 formatter.write_str("LcsMatch")
692 }
693
694 fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
695 where
696 A: SeqAccess<'de>,
697 {
698 let Some(first): Option<(usize, usize)> = seq.next_element()? else {
699 return Err(de::Error::invalid_length(0, &"fewer elements in tuple"));
700 };
701
702 let Some(second): Option<(usize, usize)> = seq.next_element()? else {
703 return Err(de::Error::invalid_length(1, &"fewer elements in tuple"));
704 };
705
706 let match_len: Option<usize> = seq.next_element()?;
707
708 Ok(LcsMatch(first, second, match_len))
709 }
710 }
711
712 deserializer.deserialize_seq(LcsMatchVisitor)
713 }
714}
715
716/// Result for the [`lcs`](StringCommands::lcs) command
717#[derive(Debug, Deserialize)]
718pub struct LcsResult {
719 pub matches: Vec<LcsMatch>,
720 pub len: usize,
721}
722
723/// Expiration option for the [`set_with_options`](StringCommands::set_with_options) and [`hsetex`](crate::commands::HashCommands::hsetex) commands
724#[derive(Serialize)]
725#[serde(rename_all = "UPPERCASE")]
726pub enum SetExpiration {
727 /// Set the specified expire time, in seconds.
728 Ex(u64),
729 /// Set the specified expire time, in milliseconds.
730 Px(u64),
731 /// Set the specified Unix time at which the key will expire, in seconds.
732 Exat(u64),
733 /// Set the specified Unix time at which the key will expire, in milliseconds.
734 Pxat(u64),
735 /// Retain the time to live associated with the key.
736 KeepTtl,
737}
738
739/// Condition option for the [`set_with_options`](StringCommands::set_with_options) command
740#[derive(Serialize)]
741#[serde(rename_all = "UPPERCASE")]
742pub enum SetCondition<'a> {
743 /// Only set the key if it does not already exist.
744 NX,
745 /// Only set the key if it already exist.
746 XX,
747 /// Set the key’s value and expiration only if the hash digest of its current value is equal to the provided value.
748 /// If the key doesn’t exist, it won’t be created.
749 IFEQ(&'a str),
750 /// Set the key’s value and expiration only if the hash digest of its current value is not equal to the provided value.
751 /// If the key doesn’t exist, it will be created.
752 IFDNE(&'a str),
753}