rustis/commands/
hash_commands.rs

1use crate::{
2    client::{prepare_command, PreparedCommand},
3    commands::{ExpireOption, GetExOptions, SetExpiration},
4    resp::{
5        cmd, deserialize_vec_of_pairs, CollectionResponse, CommandArgs, KeyValueArgsCollection,
6        KeyValueCollectionResponse, PrimitiveResponse, SingleArg, SingleArgCollection, ToArgs,
7    },
8};
9use serde::{de::DeserializeOwned, Deserialize};
10
11/// A group of Redis commands related to [`Hashes`](https://redis.io/docs/data-types/hashes/)
12///
13/// # See Also
14/// [Redis Hash Commands](https://redis.io/commands/?group=hash)
15pub trait HashCommands<'a> {
16    /// Removes the specified fields from the hash stored at key.
17    ///
18    /// # Return
19    /// the number of fields that were removed from the hash, not including specified but non existing fields.
20    ///
21    /// # See Also
22    /// [<https://redis.io/commands/hdel/>](https://redis.io/commands/hdel/)
23    #[must_use]
24    fn hdel<K, F, C>(self, key: K, fields: C) -> PreparedCommand<'a, Self, usize>
25    where
26        Self: Sized,
27        K: SingleArg,
28        F: SingleArg,
29        C: SingleArgCollection<F>,
30    {
31        prepare_command(self, cmd("HDEL").arg(key).arg(fields))
32    }
33
34    /// Returns if field is an existing field in the hash stored at key.
35    ///
36    /// # Return
37    /// * `true` - if the hash contains field.
38    /// * `false` - if the hash does not contain field, or key does not exist.
39    ///
40    /// # See Also
41    /// [<https://redis.io/commands/hexists/>](https://redis.io/commands/hexists/)
42    #[must_use]
43    fn hexists<K, F>(self, key: K, field: F) -> PreparedCommand<'a, Self, bool>
44    where
45        Self: Sized,
46        K: SingleArg,
47        F: SingleArg,
48    {
49        prepare_command(self, cmd("HEXISTS").arg(key).arg(field))
50    }
51
52    /// Set an expiration (TTL or time to live) on one or more fields of a given hash key.
53    ///
54    /// Field(s) will automatically be deleted from the hash key when their TTLs expire.
55    ///
56    /// # Arguments
57    /// * `key` - The hash key
58    /// * `seconds ` - The expiration time in seconds
59    /// * `option` - The [`ExpireOption`](crate::commands::ExpireOption) option.
60    /// * `fields` - The fields to expire.
61    ///
62    /// # Return
63    /// For each field:
64    /// * `-2` - if no such field exists in the provided hash key, or the provided key does not exist.
65    /// * `0` - if the specified NX | XX | GT | LT condition has not been met.
66    /// * `1` - if the expiration time was set/updated.
67    /// * `2` - when the command is called with 0 seconds.
68    ///
69    /// # See Also
70    /// [<https://redis.io/commands/hexpire/>](https://redis.io/commands/hexpire/)
71    #[must_use]
72    fn hexpire<K, F, FF, R>(
73        self,
74        key: K,
75        seconds: u64,
76        option: ExpireOption,
77        fields: FF,
78    ) -> PreparedCommand<'a, Self, R>
79    where
80        Self: Sized,
81        K: SingleArg,
82        F: SingleArg,
83        FF: SingleArgCollection<F>,
84        R: CollectionResponse<i64>,
85    {
86        prepare_command(
87            self,
88            cmd("HEXPIRE")
89                .arg(key)
90                .arg(seconds)
91                .arg(option)
92                .arg("FIELDS")
93                .arg(fields.num_args())
94                .arg(fields),
95        )
96    }
97
98    /// HEXPIREAT has the same effect and semantics as HEXPIRE,
99    /// but instead of specifying the number of seconds for the TTL (time to live),
100    /// it takes an absolute Unix timestamp in seconds since Unix epoch.
101    ///
102    /// A timestamp in the past will delete the field immediately.
103    ///
104    /// # Arguments
105    /// * `key` - The hash key
106    /// * `unix_time_seconds ` - The aboslute unix timestamp the fields will expire at.
107    /// * `option` - The [`ExpireOption`](crate::commands::ExpireOption) option.
108    /// * `fields` - The fields to expire.
109    ///
110    /// # Return
111    /// For each field:
112    /// * `-2` - if no such field exists in the provided hash key, or the provided key does not exist.
113    /// * `0` - if the specified NX | XX | GT | LT condition has not been met.
114    /// * `1` - if the expiration time was set/updated.
115    /// * `2` - when the command is called with a past Unix time in seconds.
116    ///
117    /// # See Also
118    /// [<https://redis.io/commands/hexpireat/>](https://redis.io/commands/hexpireat/)
119    #[must_use]
120    fn hexpireat<K, F, FF, R>(
121        self,
122        key: K,
123        unix_time_seconds: u64,
124        option: ExpireOption,
125        fields: FF,
126    ) -> PreparedCommand<'a, Self, R>
127    where
128        Self: Sized,
129        K: SingleArg,
130        F: SingleArg,
131        FF: SingleArgCollection<F>,
132        R: CollectionResponse<i64>,
133    {
134        prepare_command(
135            self,
136            cmd("HEXPIREAT")
137                .arg(key)
138                .arg(unix_time_seconds)
139                .arg(option)
140                .arg("FIELDS")
141                .arg(fields.num_args())
142                .arg(fields),
143        )
144    }
145
146    /// Returns the absolute Unix timestamp in seconds since Unix epoch
147    /// at which the given key's field(s) will expire.
148    ///
149    /// # Arguments
150    /// * `key` - The hash key
151    /// * `fields` - The fields to get the expiration time from.
152    ///
153    /// # Return
154    /// For each field, the expiration (Unix timestamp) in seconds.
155    /// - The command returns -2 if no such field exists in the provided hash key, or the provided key does not exist.
156    /// - The command returns -1 if the field exists but has no associated expiration set.
157    ///
158    /// # See Also
159    /// [<https://redis.io/commands/hexpiretime/>](https://redis.io/commands/hexpiretime/)
160    #[must_use]
161    fn hexpiretime<K, F, FF, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
162    where
163        Self: Sized,
164        K: SingleArg,
165        F: SingleArg,
166        FF: SingleArgCollection<F>,
167        R: CollectionResponse<i64>,
168    {
169        prepare_command(
170            self,
171            cmd("HEXPIRETIME")
172                .arg(key)
173                .arg("FIELDS")
174                .arg(fields.num_args())
175                .arg(fields),
176        )
177    }
178
179    /// Returns the value associated with field in the hash stored at key.
180    ///
181    /// # Return
182    /// The value associated with field, or nil when field is not present in the hash or key does not exist.
183    ///
184    /// # See Also
185    /// [<https://redis.io/commands/hget/>](https://redis.io/commands/hget/)
186    #[must_use]
187    fn hget<K, F, V>(self, key: K, field: F) -> PreparedCommand<'a, Self, V>
188    where
189        Self: Sized,
190        K: SingleArg,
191        F: SingleArg,
192        V: PrimitiveResponse,
193    {
194        prepare_command(self, cmd("HGET").arg(key).arg(field))
195    }
196
197    /// Returns all fields and values of the hash stored at key.
198    ///
199    /// # Return
200    /// The list of fields and their values stored in the hash, or an empty list when key does not exist.
201    ///
202    /// # See Also
203    /// [<https://redis.io/commands/hgetall/>](https://redis.io/commands/hgetall/)
204    #[must_use]
205    fn hgetall<K, F, V, R>(self, key: K) -> PreparedCommand<'a, Self, R>
206    where
207        Self: Sized,
208        K: SingleArg,
209        F: PrimitiveResponse,
210        V: PrimitiveResponse,
211        R: KeyValueCollectionResponse<F, V>,
212    {
213        prepare_command(self, cmd("HGETALL").arg(key))
214    }
215
216    /// Get and delete the value of one or more fields of a given hash key.
217    ///
218    /// When the last field is deleted, the key will also be deleted.
219    ///
220    /// # Arguments
221    /// * `key` - The hash key
222    /// * `fields` - The fields to get and delete.
223    ///
224    /// # Return
225    /// A list of deleted fields and their values or nil for fields that do not exist.
226    ///
227    /// # See Also
228    /// [<https://redis.io/commands/hgetdel/>](https://redis.io/commands/hgetdel/)
229    #[must_use]
230    fn hgetdel<K, F, FF, RV, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
231    where
232        Self: Sized,
233        K: SingleArg,
234        F: SingleArg,
235        FF: SingleArgCollection<F>,
236        RV: PrimitiveResponse + DeserializeOwned,
237        R: CollectionResponse<RV> + DeserializeOwned,
238    {
239        prepare_command(
240            self,
241            cmd("HGETDEL")
242                .arg(key)
243                .arg("FIELDS")
244                .arg(fields.num_args())
245                .arg(fields),
246        )
247    }
248
249    /// Get the value of one or more fields of a given hash key
250    /// and optionally set their expiration time or time-to-live (TTL).
251    ///
252    /// # Arguments
253    /// * `key` - The hash key
254    /// * `options` - The [`GetExOptions`](crate::commands::GetExOptions) options.
255    /// * `fields` - The fields to get.
256    ///
257    /// # Return
258    /// a list of values associated with the given fields, in the same order as they are requested.
259    ///
260    /// # See Also
261    /// [<https://redis.io/commands/hgetex/>](https://redis.io/commands/hgetex/)
262    #[must_use]
263    fn hgetex<K, F, FF, RV, R>(
264        self,
265        key: K,
266        options: GetExOptions,
267        fields: FF,
268    ) -> PreparedCommand<'a, Self, R>
269    where
270        Self: Sized,
271        K: SingleArg,
272        F: SingleArg,
273        FF: SingleArgCollection<F>,
274        RV: PrimitiveResponse + DeserializeOwned,
275        R: CollectionResponse<RV> + DeserializeOwned,
276    {
277        prepare_command(
278            self,
279            cmd("HGETEX")
280                .arg(key)
281                .arg(options)
282                .arg("FIELDS")
283                .arg(fields.num_args())
284                .arg(fields),
285        )
286    }
287
288    /// Increments the number stored at field in the hash stored at key by increment.
289    ///
290    /// # Return
291    /// The value at field after the increment operation.
292    ///
293    /// # See Also
294    /// [<https://redis.io/commands/hincrby/>](https://redis.io/commands/hincrby/)
295    #[must_use]
296    fn hincrby<K, F>(self, key: K, field: F, increment: i64) -> PreparedCommand<'a, Self, i64>
297    where
298        Self: Sized,
299        K: SingleArg,
300        F: SingleArg,
301    {
302        prepare_command(self, cmd("HINCRBY").arg(key).arg(field).arg(increment))
303    }
304
305    /// Increment the specified field of a hash stored at key,
306    /// and representing a floating point number, by the specified increment.
307    ///
308    /// # Return
309    /// The value at field after the increment operation.
310    ///
311    /// # See Also
312    /// [<https://redis.io/commands/hincrbyfloat/>](https://redis.io/commands/hincrbyfloat/)
313    #[must_use]
314    fn hincrbyfloat<K, F>(self, key: K, field: F, increment: f64) -> PreparedCommand<'a, Self, f64>
315    where
316        Self: Sized,
317        K: SingleArg,
318        F: SingleArg,
319    {
320        prepare_command(self, cmd("HINCRBYFLOAT").arg(key).arg(field).arg(increment))
321    }
322
323    /// Returns all field names in the hash stored at key.
324    ///
325    /// # Return
326    /// The list of fields in the hash, or an empty list when key does not exist.
327    ///
328    /// # See Also
329    /// [<https://redis.io/commands/hkeys/>](https://redis.io/commands/hkeys/)
330    #[must_use]
331    fn hkeys<K, F, A>(self, key: K) -> PreparedCommand<'a, Self, A>
332    where
333        Self: Sized,
334        K: SingleArg,
335        F: PrimitiveResponse + DeserializeOwned,
336        A: CollectionResponse<F> + DeserializeOwned,
337    {
338        prepare_command(self, cmd("HKEYS").arg(key))
339    }
340
341    /// Returns the number of fields contained in the hash stored at key.
342    ///
343    /// # Return
344    /// The number of fields in the hash, or 0 when key does not exist.
345    ///
346    /// # See Also
347    /// [<https://redis.io/commands/hlen/>](https://redis.io/commands/hlen/)
348    #[must_use]
349    fn hlen<K>(self, key: K) -> PreparedCommand<'a, Self, usize>
350    where
351        Self: Sized,
352        K: SingleArg,
353    {
354        prepare_command(self, cmd("HLEN").arg(key))
355    }
356
357    /// Returns the values associated with the specified fields in the hash stored at key.
358    ///
359    /// # Return
360    /// The list of values associated with the given fields, in the same order as they are requested.
361    ///
362    /// # See Also
363    /// [<https://redis.io/commands/hmget/>](https://redis.io/commands/hmget/)
364    #[must_use]
365    fn hmget<K, F, FF, RV, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
366    where
367        Self: Sized,
368        K: SingleArg,
369        F: SingleArg,
370        FF: SingleArgCollection<F>,
371        RV: PrimitiveResponse + DeserializeOwned,
372        R: CollectionResponse<RV> + DeserializeOwned,
373    {
374        prepare_command(self, cmd("HMGET").arg(key).arg(fields))
375    }
376
377    /// Remove the existing expiration on a hash key's field(s),
378    /// turning the field(s) from volatile (a field with expiration set)
379    /// to persistent (a field that will never expire as no TTL (time to live) is associated).
380    ///
381    /// # Return
382    /// For each field:
383    /// * `-2` - if no such field exists in the provided hash key, or the provided key does not exist.
384    /// * `-1` - if the field exists but has no associated expiration set.
385    /// * `1` - the expiration was removed.
386    ///
387    /// # See Also
388    /// [<https://redis.io/commands/hpersist/>](https://redis.io/commands/hpersist/)
389    #[must_use]
390    fn hpersist<K, F, FF, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
391    where
392        Self: Sized,
393        K: SingleArg,
394        F: SingleArg,
395        FF: SingleArgCollection<F>,
396        R: CollectionResponse<i64> + DeserializeOwned,
397    {
398        prepare_command(self, cmd("HPERSIST").arg(key).arg(fields))
399    }
400
401    /// This command works like [`hexpire`](HashCommands::hexpire), but the expiration of a field is specified in milliseconds instead of seconds.
402    ///
403    /// # Arguments
404    /// * `key` - The hash key
405    /// * `milliseconds ` - The expiration time in milliseconds
406    /// * `option` - The [`ExpireOption`](crate::commands::ExpireOption) option.
407    /// * `fields` - The fields to expire.
408    ///
409    /// # Return
410    /// For each field:
411    /// * `-2` - if no such field exists in the provided hash key, or the provided key does not exist.
412    /// * `0` - if the specified NX | XX | GT | LT condition has not been met.
413    /// * `1` - if the expiration time was set/updated.
414    /// * `2` - when the command is called with 0 milliseconds.
415    ///
416    /// # See Also
417    /// [<https://redis.io/commands/hpexpire/>](https://redis.io/commands/hpexpire/)
418    #[must_use]
419    fn hpexpire<K, F, FF, R>(
420        self,
421        key: K,
422        milliseconds: u64,
423        option: ExpireOption,
424        fields: FF,
425    ) -> PreparedCommand<'a, Self, R>
426    where
427        Self: Sized,
428        K: SingleArg,
429        F: SingleArg,
430        FF: SingleArgCollection<F>,
431        R: CollectionResponse<i64>,
432    {
433        prepare_command(
434            self,
435            cmd("HPEXPIRE")
436                .arg(key)
437                .arg(milliseconds)
438                .arg(option)
439                .arg("FIELDS")
440                .arg(fields.num_args())
441                .arg(fields),
442        )
443    }
444
445    /// This command has the same effect and semantics as [`hexpireat`](HashCommands::hexpireat),
446    /// but the Unix time at which the field will expire
447    /// is specified in milliseconds since Unix epoch instead of seconds.
448    ///
449    /// # Arguments
450    /// * `key` - The hash key
451    /// * `unix_time_milliseconds` - The aboslute unix timestamp in milliseconds, the fields will expire at.
452    /// * `option` - The [`ExpireOption`](crate::commands::ExpireOption) option.
453    /// * `fields` - The fields to expire.
454    ///
455    /// # Return
456    /// For each field:
457    /// * `-2` - if no such field exists in the provided hash key, or the provided key does not exist.
458    /// * `0` - if the specified NX | XX | GT | LT condition has not been met.
459    /// * `1` - if the expiration time was set/updated.
460    /// * `2` - when the command is called with a past Unix time in milliseconds.
461    ///
462    /// # See Also
463    /// [<https://redis.io/commands/hpexpireat/>](https://redis.io/commands/hpexpireat/)
464    #[must_use]
465    fn hpexpireat<K, F, FF, R>(
466        self,
467        key: K,
468        unix_time_milliseconds: u64,
469        option: ExpireOption,
470        fields: FF,
471    ) -> PreparedCommand<'a, Self, R>
472    where
473        Self: Sized,
474        K: SingleArg,
475        F: SingleArg,
476        FF: SingleArgCollection<F>,
477        R: CollectionResponse<i64>,
478    {
479        prepare_command(
480            self,
481            cmd("HPEXPIREAT")
482                .arg(key)
483                .arg(unix_time_milliseconds)
484                .arg(option)
485                .arg("FIELDS")
486                .arg(fields.num_args())
487                .arg(fields),
488        )
489    }
490
491    /// This command has the same semantics as [`hexpiretime`](HashCommands::hexpiretime),
492    /// but returns the absolute Unix expiration timestamp
493    /// in milliseconds since Unix epoch instead of seconds.
494    ///
495    /// # Arguments
496    /// * `key` - The hash key
497    /// * `fields` - The fields to get the expiration time from.
498    ///
499    /// # Return
500    /// For each field, the expiration (Unix timestamp) in milliseconds.
501    /// - The command returns -2 if no such field exists in the provided hash key, or the provided key does not exist.
502    /// - The command returns -1 if the field exists but has no associated expiration set.
503    ///
504    /// # See Also
505    /// [<https://redis.io/commands/hpexpiretime/>](https://redis.io/commands/hpexpiretime/)
506    #[must_use]
507    fn hpexpiretime<K, F, FF, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
508    where
509        Self: Sized,
510        K: SingleArg,
511        F: SingleArg,
512        FF: SingleArgCollection<F>,
513        R: CollectionResponse<i64>,
514    {
515        prepare_command(
516            self,
517            cmd("HPEXPIRETIME")
518                .arg(key)
519                .arg("FIELDS")
520                .arg(fields.num_args())
521                .arg(fields),
522        )
523    }
524
525    /// Like [`httl`](HashCommands::httl), this command returns the remaining TTL (time to live)
526    /// of a field that has an expiration set, but in milliseconds instead of seconds.
527    ///
528    /// # Arguments
529    /// * `key` - The hash key
530    /// * `fields` - The fields to get the TTL from.
531    ///
532    /// # Return
533    /// the TTL in milliseconds.
534    /// - The command returns -2 if no such field exists in the provided hash key, or the provided key does not exist.
535    /// - The command returns -1 if the field exists but has no associated expiration set.
536    ///
537    /// # See Also
538    /// [<https://redis.io/commands/hpttl/>](https://redis.io/commands/hpttl/)
539    #[must_use]
540    fn hpttl<K, F, FF, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
541    where
542        Self: Sized,
543        K: SingleArg,
544        F: SingleArg,
545        FF: SingleArgCollection<F>,
546        R: CollectionResponse<i64>,
547    {
548        prepare_command(
549            self,
550            cmd("HPTTL")
551                .arg(key)
552                .arg("FIELDS")
553                .arg(fields.num_args())
554                .arg(fields),
555        )
556    }
557
558    /// return random fields from the hash value stored at key.
559    ///
560    /// # Return
561    /// * When called with just the key argument, return a random field from the hash value stored at key.
562    ///
563    /// # See Also
564    /// [<https://redis.io/commands/hrandfield/>](https://redis.io/commands/hrandfield/)
565    #[must_use]
566    fn hrandfield<K, F>(self, key: K) -> PreparedCommand<'a, Self, F>
567    where
568        Self: Sized,
569        K: SingleArg,
570        F: PrimitiveResponse,
571    {
572        prepare_command(self, cmd("HRANDFIELD").arg(key))
573    }
574
575    /// return random fields from the hash value stored at key.
576    ///
577    /// # Return
578    /// * If the provided count argument is positive, return an array of distinct fields.
579    ///   The array's length is either count or the hash's number of fields (HLEN), whichever is lower.
580    /// * If called with a negative count, the behavior changes and the command is allowed to return the same field multiple times.
581    ///   In this case, the number of returned fields is the absolute value of the specified count.
582    ///
583    /// # See Also
584    /// [<https://redis.io/commands/hrandfield/>](https://redis.io/commands/hrandfield/)
585    #[must_use]
586    fn hrandfields<K, F, A>(self, key: K, count: isize) -> PreparedCommand<'a, Self, A>
587    where
588        Self: Sized,
589        K: SingleArg,
590        F: PrimitiveResponse + DeserializeOwned,
591        A: CollectionResponse<F> + DeserializeOwned,
592    {
593        prepare_command(self, cmd("HRANDFIELD").arg(key).arg(count))
594    }
595
596    /// return random fields from the hash value stored at key.
597    ///
598    /// # Return
599    /// * If the provided count argument is positive, return an array of distinct fields.
600    ///   The array's length is either count or the hash's number of fields (HLEN), whichever is lower.
601    /// * If called with a negative count, the behavior changes and the command is allowed to return the same field multiple times.
602    ///   In this case, the number of returned fields is the absolute value of the specified count.
603    ///   The optional WITHVALUES modifier changes the reply so it includes the respective values of the randomly selected hash fields.
604    ///
605    /// # See Also
606    /// [<https://redis.io/commands/hrandfield/>](https://redis.io/commands/hrandfield/)
607    #[must_use]
608    fn hrandfields_with_values<K, F, V, A>(
609        self,
610        key: K,
611        count: isize,
612    ) -> PreparedCommand<'a, Self, A>
613    where
614        Self: Sized,
615        K: SingleArg,
616        F: PrimitiveResponse,
617        V: PrimitiveResponse,
618        A: KeyValueCollectionResponse<F, V>,
619    {
620        prepare_command(
621            self,
622            cmd("HRANDFIELD").arg(key).arg(count).arg("WITHVALUES"),
623        )
624    }
625
626    /// Iterates fields of Hash types and their associated values.
627    ///
628    /// # Return
629    /// array of elements contain two elements, a field and a value,
630    /// for every returned element of the Hash.
631    ///
632    /// # See Also
633    /// [<https://redis.io/commands/hlen/>](https://redis.io/commands/hscan/)
634    #[must_use]
635    fn hscan<K, F, V>(
636        self,
637        key: K,
638        cursor: u64,
639        options: HScanOptions,
640    ) -> PreparedCommand<'a, Self, HScanResult<F, V>>
641    where
642        Self: Sized,
643        K: SingleArg,
644        F: PrimitiveResponse + DeserializeOwned,
645        V: PrimitiveResponse + DeserializeOwned,
646    {
647        prepare_command(self, cmd("HSCAN").arg(key).arg(cursor).arg(options))
648    }
649
650    /// Sets field in the hash stored at key to value.
651    ///
652    /// # Return
653    /// The number of fields that were added.
654    ///
655    /// # See Also
656    /// [<https://redis.io/commands/hset/>](https://redis.io/commands/hset/)
657    #[must_use]
658    fn hset<K, F, V, I>(self, key: K, items: I) -> PreparedCommand<'a, Self, usize>
659    where
660        Self: Sized,
661        K: SingleArg,
662        F: SingleArg,
663        V: SingleArg,
664        I: KeyValueArgsCollection<F, V>,
665    {
666        prepare_command(self, cmd("HSET").arg(key).arg(items))
667    }
668
669    /// Set the value of one or more fields of a given hash key,
670    /// and optionally set their expiration time or time-to-live (TTL).
671    ///
672    /// # Return
673    /// * `true` if all the fields wereset.
674    /// * `false` if no fields were set.
675    ///
676    /// # See Also
677    /// [<https://redis.io/commands/hsetex/>](https://redis.io/commands/hsetex/)
678    #[must_use]
679    fn hsetex<K, F, V, I>(
680        self,
681        key: K,
682        condition: HSetExCondition,
683        expiration: SetExpiration,
684        keep_ttl: bool,
685        items: I,
686    ) -> PreparedCommand<'a, Self, bool>
687    where
688        Self: Sized,
689        K: SingleArg,
690        F: SingleArg,
691        V: SingleArg,
692        I: KeyValueArgsCollection<F, V>,
693    {
694        prepare_command(
695            self,
696            cmd("HSETEX")
697                .arg(key)
698                .arg(condition)
699                .arg(expiration)
700                .arg_if(keep_ttl, "KEEPTTL")
701                .arg("FIELDS")
702                .arg(items.num_args() / 2)
703                .arg(items),
704        )
705    }
706
707    /// Sets field in the hash stored at key to value, only if field does not yet exist.
708    ///
709    /// # Return
710    /// * `true` - if field is a new field in the hash and value was set.
711    /// * `false` - if field already exists in the hash and no operation was performed.
712    ///
713    /// # See Also
714    /// [<https://redis.io/commands/hsetnx/>](https://redis.io/commands/hsetnx/)
715    #[must_use]
716    fn hsetnx<K, F, V>(self, key: K, field: F, value: V) -> PreparedCommand<'a, Self, bool>
717    where
718        Self: Sized,
719        K: SingleArg,
720        F: SingleArg,
721        V: SingleArg,
722    {
723        prepare_command(self, cmd("HSETNX").arg(key).arg(field).arg(value))
724    }
725
726    /// Returns the string length of the value associated with field in the hash stored at key.
727    ///
728    /// # Return
729    /// the string length of the value associated with field,
730    /// or zero when field is not present in the hash or key does not exist at all.
731    ///
732    /// # See Also
733    /// [<https://redis.io/commands/hstrlen/>](https://redis.io/commands/hstrlen/)
734    #[must_use]
735    fn hstrlen<K, F>(self, key: K, field: F) -> PreparedCommand<'a, Self, usize>
736    where
737        Self: Sized,
738        K: SingleArg,
739        F: SingleArg,
740    {
741        prepare_command(self, cmd("HSTRLEN").arg(key).arg(field))
742    }
743
744    /// Returns the remaining TTL (time to live) of a hash key's field(s) that have a set expiration.
745    /// This introspection capability allows you to check how many seconds
746    /// a given hash field will continue to be part of the hash key.
747    ///
748    /// # Arguments
749    /// * `key` - The hash key
750    /// * `fields` - The fields to get the TTL from.
751    ///
752    /// # Return
753    /// The TTL in seconds.
754    /// - The command returns -2 if no such field exists in the provided hash key, or the provided key does not exist.
755    /// - The command returns -1 if the field exists but has no associated expiration set.
756    ///
757    /// # See Also
758    /// [<https://redis.io/commands/httl/>](https://redis.io/commands/httl/)
759    #[must_use]
760    fn httl<K, F, FF, R>(self, key: K, fields: FF) -> PreparedCommand<'a, Self, R>
761    where
762        Self: Sized,
763        K: SingleArg,
764        F: SingleArg,
765        FF: SingleArgCollection<F>,
766        R: CollectionResponse<i64>,
767    {
768        prepare_command(
769            self,
770            cmd("HTTL")
771                .arg(key)
772                .arg("FIELDS")
773                .arg(fields.num_args())
774                .arg(fields),
775        )
776    }
777
778    /// list of values in the hash, or an empty list when key does not exist.
779    ///
780    /// # Return
781    /// The list of values in the hash, or an empty list when key does not exist.
782    ///
783    /// # See Also
784    /// [<https://redis.io/commands/hvals/>](https://redis.io/commands/hvals/)
785    #[must_use]
786    fn hvals<K, V, A>(self, key: K) -> PreparedCommand<'a, Self, A>
787    where
788        Self: Sized,
789        K: SingleArg,
790        V: PrimitiveResponse + DeserializeOwned,
791        A: CollectionResponse<V> + DeserializeOwned,
792    {
793        prepare_command(self, cmd("HVALS").arg(key))
794    }
795}
796
797/// Options for the [`hscan`](HashCommands::hscan) command
798#[derive(Default)]
799pub struct HScanOptions {
800    command_args: CommandArgs,
801}
802
803impl HScanOptions {
804    #[must_use]
805    pub fn match_pattern<P: SingleArg>(mut self, match_pattern: P) -> Self {
806        Self {
807            command_args: self.command_args.arg("MATCH").arg(match_pattern).build(),
808        }
809    }
810
811    #[must_use]
812    pub fn count(mut self, count: usize) -> Self {
813        Self {
814            command_args: self.command_args.arg("COUNT").arg(count).build(),
815        }
816    }
817}
818
819impl ToArgs for HScanOptions {
820    fn write_args(&self, args: &mut CommandArgs) {
821        args.arg(&self.command_args);
822    }
823}
824
825/// Result for the [`hscan`](HashCommands::hscan) command.
826#[derive(Debug, Deserialize)]
827pub struct HScanResult<F, V>
828where
829    F: PrimitiveResponse + DeserializeOwned,
830    V: PrimitiveResponse + DeserializeOwned,
831{
832    pub cursor: u64,
833    #[serde(deserialize_with = "deserialize_vec_of_pairs")]
834    pub elements: Vec<(F, V)>,
835}
836
837/// Condition option for the [`hsetex`](HashCommands::hsetex) command
838#[derive(Default)]
839pub enum HSetExCondition {
840    /// No condition
841    #[default]
842    None,
843    /// Only set the fields if none of them already exist.
844    FNX,
845    /// Only set the fields if all of them already exist.
846    FXX,
847}
848
849impl ToArgs for HSetExCondition {
850    fn write_args(&self, args: &mut CommandArgs) {
851        match self {
852            HSetExCondition::None => {}
853            HSetExCondition::FNX => {
854                args.arg("FNX");
855            }
856            HSetExCondition::FXX => {
857                args.arg("FXX");
858            }
859        }
860    }
861}