redis_driver/commands/
generic_commands.rs

1use crate::{
2    prepare_command,
3    resp::{
4        cmd, CommandArg, CommandArgs, FromSingleValueArray, FromValue, IntoArgs,
5        SingleArgOrCollection, Value,
6    },
7    Error, PreparedCommand, Result,
8};
9
10/// A group of generic Redis commands
11///
12/// # See Also
13/// [Redis Generic Commands](https://redis.io/commands/?group=generic)
14pub trait GenericCommands {
15    /// This command copies the value stored at the source key to the destination key.
16    ///
17    /// # Return
18    /// Success of the operation
19    ///
20    /// # See Also
21    /// [<https://redis.io/commands/copy/>](https://redis.io/commands/copy/)
22    #[must_use]
23    fn copy<S, D>(
24        &mut self,
25        source: S,
26        destination: D,
27        destination_db: Option<usize>,
28        replace: bool,
29    ) -> PreparedCommand<Self, bool>
30    where
31        Self: Sized,
32        S: Into<CommandArg>,
33        D: Into<CommandArg>,
34    {
35        prepare_command(
36            self,
37            cmd("COPY")
38                .arg(source)
39                .arg(destination)
40                .arg(destination_db.map(|db| ("DB", db)))
41                .arg_if(replace, "REPLACE"),
42        )
43    }
44
45    /// Removes the specified keys. A key is ignored if it does not exist.
46    ///
47    /// # Return
48    /// The number of keys that were removed.
49    ///
50    /// # See Also
51    /// [<https://redis.io/commands/del/>](https://redis.io/commands/del/)
52    #[must_use]
53    fn del<K, C>(&mut self, keys: C) -> PreparedCommand<Self, usize>
54    where
55        Self: Sized,
56        K: Into<CommandArg>,
57        C: SingleArgOrCollection<K>,
58    {
59        prepare_command(self, cmd("DEL").arg(keys))
60    }
61
62    /// Serialize the value stored at key in a Redis-specific format and return it to the user.
63    ///
64    /// # Return
65    /// The serialized value.
66    ///
67    /// # See Also
68    /// [<https://redis.io/commands/dump/>](https://redis.io/commands/dump/)
69    #[must_use]
70    fn dump<K>(&mut self, key: K) -> PreparedCommand<Self, DumpResult>
71    where
72        Self: Sized,
73        K: Into<CommandArg>,
74    {
75        prepare_command(self, cmd("DUMP").arg(key))
76    }
77
78    /// Returns if keys exist.
79    ///
80    /// # Return
81    /// The number of keys that exist from those specified as arguments.
82    ///
83    /// # See Also
84    /// [<https://redis.io/commands/exists/>](https://redis.io/commands/exists/)
85    #[must_use]
86    fn exists<K, C>(&mut self, keys: C) -> PreparedCommand<Self, usize>
87    where
88        Self: Sized,
89        K: Into<CommandArg>,
90        C: SingleArgOrCollection<K>,
91    {
92        prepare_command(self, cmd("EXISTS").arg(keys))
93    }
94
95    /// Set a timeout on key in seconds
96    ///
97    /// # Return
98    /// * `true` - if the timeout was set.
99    /// * `false` - if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.
100    ///
101    /// # See Also
102    /// [<https://redis.io/commands/expire/>](https://redis.io/commands/expire/)
103    #[must_use]
104    fn expire<K>(
105        &mut self,
106        key: K,
107        seconds: u64,
108        option: ExpireOption,
109    ) -> PreparedCommand<Self, bool>
110    where
111        Self: Sized,
112        K: Into<CommandArg>,
113    {
114        prepare_command(self, cmd("EXPIRE").arg(key).arg(seconds).arg(option))
115    }
116
117    /// EXPIREAT has the same effect and semantic as EXPIRE,
118    /// but instead of specifying the number of seconds representing the TTL (time to live),
119    /// it takes an absolute Unix timestamp (seconds since January 1, 1970)
120    ///
121    /// A timestamp in the past will delete the key
122    ///
123    /// # Return
124    /// * `true` - if the timeout was set.
125    /// * `false` - if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.
126    ///
127    /// # See Also
128    /// [<https://redis.io/commands/expireat/>](https://redis.io/commands/expireat/)
129    #[must_use]
130    fn expireat<K>(
131        &mut self,
132        key: K,
133        unix_time_seconds: u64,
134        option: ExpireOption,
135    ) -> PreparedCommand<Self, bool>
136    where
137        Self: Sized,
138        K: Into<CommandArg>,
139    {
140        prepare_command(
141            self,
142            cmd("EXPIREAT").arg(key).arg(unix_time_seconds).arg(option),
143        )
144    }
145
146    /// Returns the absolute Unix timestamp (since January 1, 1970) in seconds at which the given key will expire.
147    ///
148    /// # Return
149    /// Expiration Unix timestamp in seconds, or a negative value in order to signal an error (see the description below).
150    /// - The command returns -1 if the key exists but has no associated expiration time.
151    /// - The command returns -2 if the key does not exist.
152    ///
153    /// # See Also
154    /// [<https://redis.io/commands/expiretime/>](https://redis.io/commands/expiretime/)
155    #[must_use]
156    fn expiretime<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
157    where
158        Self: Sized,
159        K: Into<CommandArg>,
160    {
161        prepare_command(self, cmd("EXPIRETIME").arg(key))
162    }
163
164    /// Returns all keys matching pattern.
165    ///
166    /// # Return
167    /// list of keys matching pattern.
168    ///
169    /// # See Also
170    /// [<https://redis.io/commands/keys/>](https://redis.io/commands/keys/)
171    #[must_use]
172    fn keys<P, K, A>(&mut self, pattern: P) -> PreparedCommand<Self, A>
173    where
174        Self: Sized,
175        P: Into<CommandArg>,
176        K: FromValue,
177        A: FromSingleValueArray<K>,
178    {
179        prepare_command(self, cmd("KEYS").arg(pattern))
180    }
181
182    /// Atomically transfer a key or a collection of keys from a source Redis instance to a destination Redis instance.
183    ///
184    /// # Return
185    /// * `true` - on success
186    /// * `false` - if no keys were found in the source instance.
187    ///
188    /// # See Also
189    /// [<https://redis.io/commands/migrate/>](https://redis.io/commands/migrate/)
190    #[must_use]
191    fn migrate<H, K>(
192        &mut self,
193        host: H,
194        port: u16,
195        key: K,
196        destination_db: usize,
197        timeout: u64,
198        options: MigrateOptions,
199    ) -> PreparedCommand<Self, MigrateResult>
200    where
201        Self: Sized,
202        H: Into<CommandArg>,
203        K: Into<CommandArg>,
204    {
205        prepare_command(
206            self,
207            cmd("MIGRATE")
208                .arg(host)
209                .arg(port)
210                .arg(key)
211                .arg(destination_db)
212                .arg(timeout)
213                .arg(options),
214        )
215    }
216
217    /// Move key from the currently selected database to the specified destination database.
218    ///
219    /// # Return
220    /// * `true` - if key was moved.
221    /// * `false` - f key was not moved.
222    ///
223    /// # See Also
224    /// [<https://redis.io/commands/move/>](https://redis.io/commands/move/)
225    #[must_use]
226    fn move_<K>(&mut self, key: K, db: usize) -> PreparedCommand<Self, i64>
227    where
228        Self: Sized,
229        K: Into<CommandArg>,
230    {
231        prepare_command(self, cmd("MOVE").arg(key).arg(db))
232    }
233
234    /// Returns the internal encoding for the Redis object stored at `key`
235    ///
236    /// # Return
237    /// The encoding of the object, or nil if the key doesn't exist
238    ///
239    /// # See Also
240    /// [<https://redis.io/commands/object-encoding/>](https://redis.io/commands/object-encoding/)
241    #[must_use]
242    fn object_encoding<K, E>(&mut self, key: K) -> PreparedCommand<Self, E>
243    where
244        Self: Sized,
245        K: Into<CommandArg>,
246        E: FromValue,
247    {
248        prepare_command(self, cmd("OBJECT").arg("ENCODING").arg(key))
249    }
250
251    /// This command returns the logarithmic access frequency counter of a Redis object stored at `key`.
252    ///
253    /// # Return
254    /// The counter's value.
255    ///
256    /// # See Also
257    /// [<https://redis.io/commands/object-freq/>](https://redis.io/commands/object-freq/)
258    #[must_use]
259    fn object_freq<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
260    where
261        Self: Sized,
262        K: Into<CommandArg>,
263    {
264        prepare_command(self, cmd("OBJECT").arg("FREQ").arg(key))
265    }
266
267    /// This command returns the time in seconds since the last access to the value stored at `key`.
268    ///
269    /// # Return
270    /// The idle time in seconds.
271    ///
272    /// # See Also
273    /// [<https://redis.io/commands/object-idletime/>](https://redis.io/commands/object-idletime/)
274    #[must_use]
275    fn object_idle_time<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
276    where
277        Self: Sized,
278        K: Into<CommandArg>,
279    {
280        prepare_command(self, cmd("OBJECT").arg("IDLETIME").arg(key))
281    }
282
283    /// This command returns the reference count of the stored at `key`.
284    ///
285    /// # Return
286    /// The number of references.
287    ///
288    /// # See Also
289    /// [<https://redis.io/commands/object-refcount/>](https://redis.io/commands/object-refcount/)
290    #[must_use]
291    fn object_refcount<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
292    where
293        Self: Sized,
294        K: Into<CommandArg>,
295    {
296        prepare_command(self, cmd("OBJECT").arg("REFCOUNT").arg(key))
297    }
298
299    /// Remove the existing timeout on key,
300    /// turning the key from volatile (a key with an expire set)
301    /// to persistent (a key that will never expire as no timeout is associated).
302    ///
303    /// # Return
304    /// * `true` - if the timeout was removed.
305    /// * `false` - if key does not exist or does not have an associated timeout.
306    ///
307    /// # See Also
308    /// [<https://redis.io/commands/persist/>](https://redis.io/commands/persist/)
309    #[must_use]
310    fn persist<K>(&mut self, key: K) -> PreparedCommand<Self, bool>
311    where
312        Self: Sized,
313        K: Into<CommandArg>,
314    {
315        prepare_command(self, cmd("PERSIST").arg(key))
316    }
317
318    /// This command works exactly like EXPIRE but the time to live of the key is specified in milliseconds instead of seconds.
319    ///
320    /// # Return
321    /// * `true` - if the timeout was set.
322    /// * `false` - if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.
323    ///
324    /// # See Also
325    /// [<https://redis.io/commands/pexpire/>](https://redis.io/commands/pexpire/)
326    #[must_use]
327    fn pexpire<K>(
328        &mut self,
329        key: K,
330        milliseconds: u64,
331        option: ExpireOption,
332    ) -> PreparedCommand<Self, bool>
333    where
334        Self: Sized,
335        K: Into<CommandArg>,
336    {
337        prepare_command(self, cmd("PEXPIRE").arg(key).arg(milliseconds).arg(option))
338    }
339
340    /// PEXPIREAT has the same effect and semantic as EXPIREAT,
341    /// but the Unix time at which the key will expire is specified in milliseconds instead of seconds.
342    ///
343    /// # Return
344    /// * `true` - if the timeout was set.
345    /// * `false` - if the timeout was not set. e.g. key doesn't exist, or operation skipped due to the provided arguments.
346    ///
347    /// # See Also
348    /// [<https://redis.io/commands/pexpireat/>](https://redis.io/commands/pexpireat/)
349    #[must_use]
350    fn pexpireat<K>(
351        &mut self,
352        key: K,
353        unix_time_milliseconds: u64,
354        option: ExpireOption,
355    ) -> PreparedCommand<Self, bool>
356    where
357        Self: Sized,
358        K: Into<CommandArg>,
359    {
360        prepare_command(
361            self,
362            cmd("PEXPIREAT")
363                .arg(key)
364                .arg(unix_time_milliseconds)
365                .arg(option),
366        )
367    }
368
369    /// PEXPIRETIME has the same semantic as EXPIRETIME,
370    /// but returns the absolute Unix expiration timestamp in milliseconds instead of seconds.
371    ///
372    /// # Return
373    ///  Expiration Unix timestamp in milliseconds, or a negative value in order to signal an error (see the description below).
374    /// - The command returns -1 if the key exists but has no associated expiration time.
375    /// - The command returns -2 if the key does not exist.
376    ///
377    /// # See Also
378    /// [<https://redis.io/commands/pexpiretime/>](https://redis.io/commands/pexpiretime/)
379    #[must_use]
380    fn pexpiretime<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
381    where
382        Self: Sized,
383        K: Into<CommandArg>,
384    {
385        prepare_command(self, cmd("PEXPIRETIME").arg(key))
386    }
387
388    /// Returns the remaining time to live of a key that has a timeout.
389    ///
390    /// # Return
391    /// TTL in milliseconds, or a negative value in order to signal an error:
392    /// -2 if the key does not exist.
393    /// -1 if the key exists but has no associated expire.
394    ///
395    /// # See Also
396    /// [<https://redis.io/commands/pttl/>](https://redis.io/commands/pttl/)
397    #[must_use]
398    fn pttl<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
399    where
400        Self: Sized,
401        K: Into<CommandArg>,
402    {
403        prepare_command(self, cmd("PTTL").arg(key))
404    }
405
406    /// Return a random key from the currently selected database.
407    ///
408    /// # Return
409    /// The number of references.
410    ///
411    /// # See Also
412    /// [<https://redis.io/commands/randomkey/>](https://redis.io/commands/randomkey/)
413    #[must_use]
414    fn randomkey<R>(&mut self) -> PreparedCommand<Self, R>
415    where
416        Self: Sized,
417        R: FromValue,
418    {
419        prepare_command(self, cmd("RANDOMKEY"))
420    }
421
422    /// Renames key to newkey.
423    ///
424    /// # See Also
425    /// [<https://redis.io/commands/rename/>](https://redis.io/commands/rename/)
426    #[must_use]
427    fn rename<K1, K2>(&mut self, key: K1, new_key: K2) -> PreparedCommand<Self, ()>
428    where
429        Self: Sized,
430        K1: Into<CommandArg>,
431        K2: Into<CommandArg>,
432    {
433        prepare_command(self, cmd("RENAME").arg(key).arg(new_key))
434    }
435
436    /// Renames key to newkey if newkey does not yet exist.
437    /// It returns an error when key does not exist.
438    ///
439    /// # Return
440    /// * `true` if key was renamed to newkey.
441    /// * `false` if newkey already exists.
442    /// # See Also
443    /// [<https://redis.io/commands/renamenx/>](https://redis.io/commands/renamenx/)
444    #[must_use]
445    fn renamenx<K1, K2>(&mut self, key: K1, new_key: K2) -> PreparedCommand<Self, bool>
446    where
447        Self: Sized,
448        K1: Into<CommandArg>,
449        K2: Into<CommandArg>,
450    {
451        prepare_command(self, cmd("RENAMENX").arg(key).arg(new_key))
452    }
453
454    /// Create a key associated with a value that is obtained by deserializing
455    /// the provided serialized value (obtained via DUMP).
456    ///
457    /// # Return
458    /// Restore command builder
459    ///
460    /// # See Also
461    /// [<https://redis.io/commands/restore/>](https://redis.io/commands/restore/)
462    #[must_use]
463    fn restore<K>(
464        &mut self,
465        key: K,
466        ttl: u64,
467        serialized_value: Vec<u8>,
468        options: RestoreOptions,
469    ) -> PreparedCommand<Self, ()>
470    where
471        Self: Sized,
472        K: Into<CommandArg>,
473    {
474        prepare_command(
475            self,
476            cmd("RESTORE")
477                .arg(key)
478                .arg(ttl)
479                .arg(CommandArg::Binary(serialized_value))
480                .arg(options),
481        )
482    }
483
484    /// Iterates the set of keys in the currently selected Redis database.
485    ///
486    /// # Return
487    /// A list of keys
488    ///
489    /// # See Also
490    /// [<https://redis.io/commands/scan/>](https://redis.io/commands/scan/)
491    #[must_use]
492    fn scan<K, A>(&mut self, cursor: u64, options: ScanOptions) -> PreparedCommand<Self, (u64, A)>
493    where
494        Self: Sized,
495        K: FromValue,
496        A: FromSingleValueArray<K>,
497    {
498        prepare_command(self, cmd("SCAN").arg(cursor).arg(options))
499    }
500
501    /// Returns the elements contained in the list, set or sorted set at key.
502    ///
503    /// # Return
504    /// A collection of sorted elements.
505    ///
506    /// # See Also
507    /// [<https://redis.io/commands/sort/>](https://redis.io/commands/sort/)
508    #[must_use]
509    fn sort<K, M, A>(&mut self, key: K, options: SortOptions) -> PreparedCommand<Self, A>
510    where
511        Self: Sized,
512        K: Into<CommandArg>,
513        M: FromValue,
514        A: FromSingleValueArray<M>,
515    {
516        prepare_command(self, cmd("SORT").arg(key).arg(options))
517    }
518
519    /// Stores the elements contained in the list, set or sorted set at key.
520    ///
521    /// # Return
522    /// The number of sorted elements in the destination list.
523    ///
524    /// # See Also
525    /// [<https://redis.io/commands/sort/>](https://redis.io/commands/sort/)
526    #[must_use]
527    fn sort_and_store<K, D>(
528        &mut self,
529        key: K,
530        destination: D,
531        options: SortOptions,
532    ) -> PreparedCommand<Self, usize>
533    where
534        Self: Sized,
535        K: Into<CommandArg>,
536        D: Into<CommandArg>,
537    {
538        prepare_command(
539            self,
540            cmd("SORT")
541                .arg(key)
542                .arg(options)
543                .arg("STORE")
544                .arg(destination),
545        )
546    }
547
548    /// Read-only variant of the SORT command.
549    ///
550    /// It is exactly like the original SORT but refuses the STORE option
551    /// and can safely be used in read-only replicas.
552    ///
553    /// # Return
554    /// A collection of sorted elements.
555    ///
556    /// # See Also
557    /// [<https://redis.io/commands/sort_ro/>](https://redis.io/commands/sort_ro/)
558    #[must_use]
559    fn sort_readonly<K, M, A>(&mut self, key: K, options: SortOptions) -> PreparedCommand<Self, A>
560    where
561        Self: Sized,
562        K: Into<CommandArg>,
563        M: FromValue,
564        A: FromSingleValueArray<M>,
565    {
566        prepare_command(self, cmd("SORT_RO").arg(key).arg(options))
567    }
568
569    /// Alters the last access time of a key(s). A key is ignored if it does not exist.
570    ///
571    /// # Return
572    /// The number of keys that were touched.
573    ///
574    /// # See Also
575    /// [<https://redis.io/commands/touch/>](https://redis.io/commands/touch/)
576    #[must_use]
577    fn touch<K, KK>(&mut self, keys: KK) -> PreparedCommand<Self, usize>
578    where
579        Self: Sized,
580        K: Into<CommandArg>,
581        KK: SingleArgOrCollection<K>,
582    {
583        prepare_command(self, cmd("TOUCH").arg(keys))
584    }
585
586    /// Returns the remaining time to live of a key that has a timeout.
587    ///
588    /// # Return
589    /// TTL in seconds, or a negative value in order to signal an error:
590    /// -2 if the key does not exist.
591    /// -1 if the key exists but has no associated expire.
592    ///
593    /// # See Also
594    /// [<https://redis.io/commands/ttl/>](https://redis.io/commands/ttl/)
595    #[must_use]
596    fn ttl<K>(&mut self, key: K) -> PreparedCommand<Self, i64>
597    where
598        Self: Sized,
599        K: Into<CommandArg>,
600    {
601        prepare_command(self, cmd("TTL").arg(key))
602    }
603
604    /// Returns the string representation of the type of the value stored at key.
605    ///
606    /// The different types that can be returned are: string, list, set, zset, hash and stream.
607    ///
608    /// # Return
609    /// type of key, or empty string when key does not exist.
610    ///
611    /// # See Also
612    /// [<https://redis.io/commands/type/>](https://redis.io/commands/type/)
613    #[must_use]
614    fn type_<K>(&mut self, key: K) -> PreparedCommand<Self, String>
615    where
616        Self: Sized,
617        K: Into<CommandArg>,
618    {
619        prepare_command(self, cmd("TYPE").arg(key))
620    }
621
622    /// This command is very similar to DEL: it removes the specified keys.
623    ///
624    /// # Return
625    /// The number of keys that were unlinked.
626    ///
627    /// # See Also
628    /// [<https://redis.io/commands/unlink/>](https://redis.io/commands/unlink/)
629    #[must_use]
630    fn unlink<K, C>(&mut self, keys: C) -> PreparedCommand<Self, usize>
631    where
632        Self: Sized,
633        K: Into<CommandArg>,
634        C: SingleArgOrCollection<K>,
635    {
636        prepare_command(self, cmd("UNLINK").arg(keys))
637    }
638
639    /// This command blocks the current client until all the previous write commands are
640    /// successfully transferred and acknowledged by at least the specified number of replicas.
641    ///
642    /// # Return
643    /// The number of replicas reached by all the writes performed in the context of the current connection.
644    ///
645    /// # See Also
646    /// [<https://redis.io/commands/wait/>](https://redis.io/commands/wait/)
647    #[must_use]
648    fn wait(&mut self, num_replicas: usize, timeout: u64) -> PreparedCommand<Self, usize>
649    where
650        Self: Sized,
651    {
652        prepare_command(self, cmd("WAIT").arg(num_replicas).arg(timeout))
653    }
654}
655
656/// Options for the [`expire`](crate::GenericCommands::expire) command
657pub enum ExpireOption {
658    /// No option
659    None,
660    /// Set expiry only when the key has no expiry
661    Nx,
662    /// Set expiry only when the key has no expiry    
663    Xx,
664    /// Set expiry only when the new expiry is greater than current one
665    Gt,
666    /// Set expiry only when the new expiry is less than current one
667    Lt,
668}
669
670impl Default for ExpireOption {
671    fn default() -> Self {
672        ExpireOption::None
673    }
674}
675
676impl IntoArgs for ExpireOption {
677    fn into_args(self, args: CommandArgs) -> CommandArgs {
678        match self {
679            ExpireOption::None => args,
680            ExpireOption::Nx => args.arg("NX"),
681            ExpireOption::Xx => args.arg("XX"),
682            ExpireOption::Gt => args.arg("GT"),
683            ExpireOption::Lt => args.arg("LT"),
684        }
685    }
686}
687
688#[derive(Default)]
689pub struct MigrateOptions {
690    command_args: CommandArgs,
691}
692
693impl MigrateOptions {
694    #[must_use]
695    pub fn copy(self) -> Self {
696        Self {
697            command_args: self.command_args.arg("COPY"),
698        }
699    }
700
701    #[must_use]
702    pub fn replace(self) -> Self {
703        Self {
704            command_args: self.command_args.arg("REPLACE"),
705        }
706    }
707
708    #[must_use]
709    pub fn auth<P: Into<CommandArg>>(self, password: P) -> Self {
710        Self {
711            command_args: self.command_args.arg("AUTH").arg(password),
712        }
713    }
714
715    #[must_use]
716    pub fn auth2<U: Into<CommandArg>, P: Into<CommandArg>>(self, username: U, password: P) -> Self {
717        Self {
718            command_args: self.command_args.arg("AUTH2").arg(username).arg(password),
719        }
720    }
721
722    #[must_use]
723    pub fn keys<K: Into<CommandArg>, KK: SingleArgOrCollection<K>>(self, keys: KK) -> Self {
724        Self {
725            command_args: self.command_args.arg("KEYS").arg(keys),
726        }
727    }
728}
729
730impl IntoArgs for MigrateOptions {
731    fn into_args(self, args: CommandArgs) -> CommandArgs {
732        args.arg(self.command_args)
733    }
734}
735
736/// Options for the [`restore`](crate::GenericCommands::restore) command
737#[derive(Default)]
738pub struct RestoreOptions {
739    command_args: CommandArgs,
740}
741
742impl RestoreOptions {
743    #[must_use]
744    pub fn replace(self) -> Self {
745        Self {
746            command_args: self.command_args.arg("REPLACE"),
747        }
748    }
749
750    #[must_use]
751    pub fn abs_ttl(self) -> Self {
752        Self {
753            command_args: self.command_args.arg("ABSTTL"),
754        }
755    }
756
757    #[must_use]
758    pub fn idle_time(self, idle_time: i64) -> Self {
759        Self {
760            command_args: self.command_args.arg("IDLETIME").arg(idle_time),
761        }
762    }
763
764    #[must_use]
765    pub fn frequency(self, frequency: f64) -> Self {
766        Self {
767            command_args: self.command_args.arg("FREQ").arg(frequency),
768        }
769    }
770}
771
772impl IntoArgs for RestoreOptions {
773    fn into_args(self, args: CommandArgs) -> CommandArgs {
774        args.arg(self.command_args)
775    }
776}
777
778/// Order option of the [`sort`](crate::GenericCommands::sort) command
779pub enum SortOrder {
780    Asc,
781    Desc,
782}
783
784impl IntoArgs for SortOrder {
785    fn into_args(self, args: CommandArgs) -> CommandArgs {
786        match self {
787            SortOrder::Asc => args.arg("ASC"),
788            SortOrder::Desc => args.arg("DESC"),
789        }
790    }
791}
792
793/// Options for the [`sort`](crate::GenericCommands::sort) command
794#[derive(Default)]
795pub struct SortOptions {
796    command_args: CommandArgs,
797}
798
799impl SortOptions {
800    #[must_use]
801    pub fn by<P: Into<CommandArg>>(self, pattern: P) -> Self {
802        Self {
803            command_args: self.command_args.arg("BY").arg(pattern),
804        }
805    }
806
807    #[must_use]
808    pub fn limit(self, offset: usize, count: isize) -> Self {
809        Self {
810            command_args: self.command_args.arg("LIMIT").arg(offset).arg(count),
811        }
812    }
813
814    #[must_use]
815    pub fn get<P: Into<CommandArg>>(self, pattern: P) -> Self {
816        Self {
817            command_args: self.command_args.arg("GET").arg(pattern),
818        }
819    }
820
821    #[must_use]
822    pub fn order(self, order: SortOrder) -> Self {
823        Self {
824            command_args: self.command_args.arg(order),
825        }
826    }
827
828    #[must_use]
829    pub fn alpha(self) -> Self {
830        Self {
831            command_args: self.command_args.arg("ALPHA"),
832        }
833    }
834}
835
836impl IntoArgs for SortOptions {
837    fn into_args(self, args: CommandArgs) -> CommandArgs {
838        args.arg(self.command_args)
839    }
840}
841
842/// Result for the [`dump`](crate::GenericCommands::dump) command.
843pub struct DumpResult {
844    pub serialized_value: Vec<u8>,
845}
846
847impl FromValue for DumpResult {
848    fn from_value(value: Value) -> crate::Result<Self> {
849        match value {
850            Value::BulkString(Some(b)) => Ok(DumpResult {
851                serialized_value: b,
852            }),
853            _ => Err(Error::Client("Unexpected dump format".to_owned())),
854        }
855    }
856}
857
858/// Options for the [`scan`](crate::GenericCommands::scan) command
859#[derive(Default)]
860pub struct ScanOptions {
861    command_args: CommandArgs,
862}
863
864impl ScanOptions {
865    #[must_use]
866    pub fn match_pattern<P: Into<CommandArg>>(self, match_pattern: P) -> Self {
867        Self {
868            command_args: self.command_args.arg("MATCH").arg(match_pattern),
869        }
870    }
871
872    #[must_use]
873    pub fn count(self, count: usize) -> Self {
874        Self {
875            command_args: self.command_args.arg("COUNT").arg(count),
876        }
877    }
878
879    #[must_use]
880    pub fn type_<TY: Into<CommandArg>>(self, type_: TY) -> Self {
881        Self {
882            command_args: self.command_args.arg("TYPE").arg(type_),
883        }
884    }
885}
886
887impl IntoArgs for ScanOptions {
888    fn into_args(self, args: CommandArgs) -> CommandArgs {
889        args.arg(self.command_args)
890    }
891}
892
893/// Result for the [`migrate`](crate::GenericCommands::migrate) command
894pub enum MigrateResult {
895    /// key(s) successfully migrated
896    Ok,
897    /// no keys were found in the source instance.
898    NoKey,
899}
900
901impl FromValue for MigrateResult {
902    fn from_value(value: Value) -> Result<Self> {
903        let result: String = value.into()?;
904        match result.as_str() {
905            "OK" => Ok(Self::Ok),
906            "NOKEY" => Ok(Self::NoKey),
907            _ => Err(Error::Client(
908                "Unexpected result for command 'MIGRATE'".to_owned(),
909            )),
910        }
911    }
912}