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}