Skip to main content

rustis/commands/
sorted_set_commands.rs

1use crate::{
2    client::{PreparedCommand, prepare_command},
3    resp::{FastPathCommandBuilder, cmd, deserialize_vec_of_pairs, serialize_flag},
4};
5use serde::{Deserialize, Serialize, de::DeserializeOwned};
6
7/// A group of Redis commands related to [`Sorted Sets`](https://redis.io/docs/data-types/sorted-sets/)
8///
9/// # See Also
10/// [Redis Sorted Set Commands](https://redis.io/commands/?group=sorted-set)
11pub trait SortedSetCommands<'a>: Sized {
12    /// Adds all the specified members with the specified scores
13    /// to the sorted set stored at key.
14    ///
15    /// # Return
16    /// * When used without optional arguments, the number of elements added to the sorted set (excluding score updates).
17    /// * If the `change` option is specified, the number of elements that were changed (added or updated).
18    ///
19    /// # See Also
20    /// [<https://redis.io/commands/zadd/>](https://redis.io/commands/zadd/)
21    #[must_use]
22    fn zadd(
23        self,
24        key: impl Serialize,
25        items: impl Serialize,
26        options: ZAddOptions,
27    ) -> PreparedCommand<'a, Self, usize> {
28        prepare_command(self, cmd("ZADD").key(key).arg(options).arg(items))
29    }
30
31    /// In this mode ZADD acts like ZINCRBY.
32    /// Only one score-element pair can be specified in this mode.
33    ///
34    /// # Return
35    /// The new score of member (a double precision floating point number),
36    /// or nil if the operation was aborted (when called with either the XX or the NX option).
37    ///
38    /// # See Also
39    /// [<https://redis.io/commands/zadd/>](https://redis.io/commands/zadd/)
40    #[must_use]
41    fn zadd_incr(
42        self,
43        key: impl Serialize,
44        condition: impl Into<Option<ZAddCondition>>,
45        comparison: impl Into<Option<ZAddComparison>>,
46        change: bool,
47        score: f64,
48        member: impl Serialize,
49    ) -> PreparedCommand<'a, Self, Option<f64>> {
50        prepare_command(
51            self,
52            cmd("ZADD")
53                .key(key)
54                .arg(condition.into())
55                .arg(comparison.into())
56                .arg_if(change, "CH")
57                .arg("INCR")
58                .arg(score)
59                .arg(member),
60        )
61    }
62
63    /// Returns the sorted set cardinality (number of elements)
64    /// of the sorted set stored at key.
65    ///
66    /// # Return
67    /// The cardinality (number of elements) of the sorted set, or 0 if key does not exist.
68    ///
69    /// # See Also
70    /// [<https://redis.io/commands/zcard/>](https://redis.io/commands/zcard/)
71    #[must_use]
72    fn zcard(self, key: impl Serialize) -> PreparedCommand<'a, Self, usize> {
73        prepare_command(self, cmd("ZCARD").key(key).readonly())
74    }
75
76    /// Returns the number of elements in the sorted set at key with a score between min and max.
77    ///
78    /// # Return
79    /// The number of elements in the specified score range.
80    ///
81    /// # See Also
82    /// [<https://redis.io/commands/zcount/>](https://redis.io/commands/zcount/)
83    #[must_use]
84    fn zcount(
85        self,
86        key: impl Serialize,
87        min: impl Serialize,
88        max: impl Serialize,
89    ) -> PreparedCommand<'a, Self, usize> {
90        prepare_command(self, cmd("ZCOUNT").key(key).arg(min).arg(max).readonly())
91    }
92
93    /// This command is similar to [zdiffstore](SortedSetCommands::zdiffstore), but instead of storing the resulting sorted set,
94    /// it is returned to the client.
95    ///
96    /// # Return
97    /// The result of the difference
98    ///
99    /// # See Also
100    /// [<https://redis.io/commands/zdiff/>](https://redis.io/commands/zdiff/)
101    #[must_use]
102    fn zdiff<R: DeserializeOwned>(self, keys: impl Serialize) -> PreparedCommand<'a, Self, R> {
103        prepare_command(self, cmd("ZDIFF").key_with_count(keys).readonly())
104    }
105
106    /// This command is similar to [zdiffstore](SortedSetCommands::zdiffstore), but instead of storing the resulting sorted set,
107    /// it is returned to the client.
108    ///
109    /// # Return
110    /// The result of the difference with their scores
111    ///
112    /// # See Also
113    /// [<https://redis.io/commands/zdiff/>](https://redis.io/commands/zdiff/)
114    #[must_use]
115    fn zdiff_with_scores<R: DeserializeOwned>(
116        self,
117        keys: impl Serialize,
118    ) -> PreparedCommand<'a, Self, R> {
119        prepare_command(
120            self,
121            cmd("ZDIFF")
122                .key_with_count(keys)
123                .arg("WITHSCORES")
124                .readonly(),
125        )
126    }
127
128    /// Computes the difference between the first and all successive
129    /// input sorted sets and stores the result in destination.
130    ///
131    /// # Return
132    /// The number of elements in the resulting sorted set at destination.
133    ///
134    /// # See Also
135    /// [<https://redis.io/commands/zdiffstore/>](https://redis.io/commands/zdiffstore/)
136    #[must_use]
137    fn zdiffstore(
138        self,
139        destination: impl Serialize,
140        keys: impl Serialize,
141    ) -> PreparedCommand<'a, Self, usize> {
142        prepare_command(
143            self,
144            cmd("ZDIFFSTORE").key(destination).key_with_count(keys),
145        )
146    }
147
148    /// Increments the score of member in the sorted set stored at key by increment.
149    ///
150    /// # Return
151    /// the new score of member
152    ///
153    /// # See Also
154    /// [<https://redis.io/commands/zincrby/>](https://redis.io/commands/zincrby/)
155    #[must_use]
156    fn zincrby(
157        self,
158        key: impl Serialize,
159        increment: f64,
160        member: impl Serialize,
161    ) -> PreparedCommand<'a, Self, f64> {
162        prepare_command(
163            self,
164            FastPathCommandBuilder::zincrby(key, increment, member),
165        )
166    }
167
168    /// This command is similar to [zinterstore](SortedSetCommands::zinterstore),
169    /// but instead of storing the resulting sorted set, it is returned to the client.
170    ///
171    /// # Return
172    /// The result of the intersection as an array of members
173    ///
174    /// # See Also
175    /// [<https://redis.io/commands/zinter/>](https://redis.io/commands/zinter/)
176    #[must_use]
177    fn zinter<R: DeserializeOwned>(
178        self,
179        keys: impl Serialize,
180        weights: impl Serialize,
181        aggregate: impl Into<Option<ZAggregate>>,
182    ) -> PreparedCommand<'a, Self, R> {
183        prepare_command(
184            self,
185            cmd("ZINTER")
186                .key_with_count(keys)
187                .arg_labeled("WEIGHTS", weights)
188                .arg_labeled("AGGREGATE", aggregate.into())
189                .readonly(),
190        )
191    }
192
193    /// This command is similar to [zinterstore](SortedSetCommands::zinterstore),
194    /// but instead of storing the resulting sorted set, it is returned to the client.
195    ///
196    /// # Return
197    /// The result of the intersection as an array of members with their scores
198    ///
199    /// # See Also
200    /// [<https://redis.io/commands/zinter/>](https://redis.io/commands/zinter/)
201    #[must_use]
202    fn zinter_with_scores<R: DeserializeOwned>(
203        self,
204        keys: impl Serialize,
205        weights: impl Serialize,
206        aggregate: impl Into<Option<ZAggregate>>,
207    ) -> PreparedCommand<'a, Self, R> {
208        prepare_command(
209            self,
210            cmd("ZINTER")
211                .key_with_count(keys)
212                .arg_labeled("WEIGHTS", weights)
213                .arg_labeled("AGGREGATE", aggregate.into())
214                .arg("WITHSCORES")
215                .readonly(),
216        )
217    }
218
219    /// This command is similar to [zinter](SortedSetCommands::zinter),
220    /// but instead of returning the result set, it returns just the cardinality of the result.
221    ///
222    //// limit: if the intersection cardinality reaches limit partway through the computation,
223    /// the algorithm will exit and yield limit as the cardinality. 0 means unlimited
224    ///
225    /// # See Also
226    /// [<https://redis.io/commands/zintercard/>](https://redis.io/commands/zintercard/)
227    #[must_use]
228    fn zintercard(self, keys: impl Serialize, limit: usize) -> PreparedCommand<'a, Self, usize> {
229        prepare_command(
230            self,
231            cmd("ZINTERCARD")
232                .key_with_count(keys)
233                .arg("LIMIT")
234                .arg(limit)
235                .readonly(),
236        )
237    }
238
239    /// Computes the intersection of numkeys sorted sets given by the specified keys,
240    /// and stores the result in destination.
241    ///
242    /// # Return
243    /// The number of elements in the resulting sorted set at destination.
244    ///
245    /// # See Also
246    /// [<https://redis.io/commands/zinterstore/>](https://redis.io/commands/zinterstore/)
247    #[must_use]
248    fn zinterstore(
249        self,
250        destination: impl Serialize,
251        keys: impl Serialize,
252        weights: impl Serialize,
253        aggregate: impl Into<Option<ZAggregate>>,
254    ) -> PreparedCommand<'a, Self, usize> {
255        prepare_command(
256            self,
257            cmd("ZINTERSTORE")
258                .key(destination)
259                .key_with_count(keys)
260                .arg_labeled("WEIGHTS", weights)
261                .arg_labeled("AGGREGATE", aggregate.into()),
262        )
263    }
264
265    /// When all the elements in a sorted set are inserted with the same score,
266    /// in order to force lexicographical ordering, this command returns the number
267    /// of elements in the sorted set at key with a value between min and max.
268    ///
269    /// # Return
270    /// the number of elements in the specified score range.
271    ///
272    /// # See Also
273    /// [<https://redis.io/commands/zlexcount/>](https://redis.io/commands/zlexcount/)
274    #[must_use]
275    fn zlexcount(
276        self,
277        key: impl Serialize,
278        min: impl Serialize,
279        max: impl Serialize,
280    ) -> PreparedCommand<'a, Self, usize> {
281        prepare_command(self, cmd("ZLEXCOUNT").key(key).arg(min).arg(max).readonly())
282    }
283
284    /// Pops one or more elements, that are member-score pairs,
285    /// from the first non-empty sorted set in the provided list of key names.
286    ///
287    /// # Return
288    /// * None if no element could be popped
289    /// * A tuple made up of
290    ///     * The name of the key from which elements were popped
291    ///     * An array of tuples with all the popped members and their scores
292    ///
293    /// # See Also
294    /// [<https://redis.io/commands/zmpop/>](https://redis.io/commands/zmpop/)
295    #[must_use]
296    fn zmpop<R: DeserializeOwned>(
297        self,
298        keys: impl Serialize,
299        where_: ZWhere,
300        count: usize,
301    ) -> PreparedCommand<'a, Self, Option<ZMPopResult<R>>> {
302        prepare_command(
303            self,
304            cmd("ZMPOP")
305                .key_with_count(keys)
306                .arg(where_)
307                .arg("COUNT")
308                .arg(count),
309        )
310    }
311
312    /// Returns the scores associated with the specified members in the sorted set stored at key.
313    ///
314    /// For every member that does not exist in the sorted set, a nil value is returned.
315    ///
316    /// # Return
317    /// The list of scores or nil associated with the specified member value
318    ///
319    /// # See Also
320    /// [<https://redis.io/commands/zmscore/>](https://redis.io/commands/zmscore/)
321    #[must_use]
322    fn zmscore<R: DeserializeOwned>(
323        self,
324        key: impl Serialize,
325        members: impl Serialize,
326    ) -> PreparedCommand<'a, Self, R> {
327        prepare_command(self, cmd("ZMSCORE").key(key).arg(members).readonly())
328    }
329
330    /// Removes and returns up to count members with the highest scores in the sorted set stored at key.
331    ///
332    /// # Return
333    /// The list of popped elements and scores.
334    ///
335    /// # See Also
336    /// [<https://redis.io/commands/zpopmax/>](https://redis.io/commands/zpopmax/)
337    #[must_use]
338    fn zpopmax<R: DeserializeOwned>(
339        self,
340        key: impl Serialize,
341        count: usize,
342    ) -> PreparedCommand<'a, Self, R> {
343        prepare_command(self, cmd("ZPOPMAX").key(key).arg(count))
344    }
345
346    /// Removes and returns up to count members with the lowest scores in the sorted set stored at key.
347    ///
348    /// # Return
349    /// The list of popped elements and scores.
350    ///
351    /// # See Also
352    /// [<https://redis.io/commands/zpopmin/>](https://redis.io/commands/zpopmin/)
353    #[must_use]
354    fn zpopmin<R: DeserializeOwned>(
355        self,
356        key: impl Serialize,
357        count: usize,
358    ) -> PreparedCommand<'a, Self, R> {
359        prepare_command(self, cmd("ZPOPMIN").key(key).arg(count))
360    }
361
362    /// Return a random element from the sorted set value stored at key.
363    ///
364    /// # Return
365    /// The randomly selected element, or nil when key does not exist.
366    ///
367    /// # See Also
368    /// [<https://redis.io/commands/zrandmember/>](https://redis.io/commands/zrandmember/)
369    #[must_use]
370    fn zrandmember<R: DeserializeOwned>(self, key: impl Serialize) -> PreparedCommand<'a, Self, R> {
371        prepare_command(self, cmd("ZRANDMEMBER").key(key).readonly())
372    }
373
374    /// Return random elements from the sorted set value stored at key.
375    ///
376    /// # Return
377    /// * If the provided count argument is positive, return an array of distinct elements.
378    ///   The array's length is either count or the sorted set's cardinality (ZCARD), whichever is lower.
379    /// * If called with a negative count, the behavior changes and the command is allowed
380    ///   to return the same element multiple times. In this case, the number of returned elements
381    ///   is the absolute value of the specified count.
382    ///
383    /// # See Also
384    /// [<https://redis.io/commands/zrandmember/>](https://redis.io/commands/zrandmember/)
385    #[must_use]
386    fn zrandmembers<R: DeserializeOwned>(
387        self,
388        key: impl Serialize,
389        count: isize,
390    ) -> PreparedCommand<'a, Self, R> {
391        prepare_command(self, cmd("ZRANDMEMBER").key(key).arg(count).readonly())
392    }
393
394    /// Return random elements with their scores from the sorted set value stored at key.
395    ///
396    /// # Return
397    /// * If the provided count argument is positive, return an array of distinct elements with their scores.
398    ///   The array's length is either count or the sorted set's cardinality (ZCARD), whichever is lower.
399    /// * If called with a negative count, the behavior changes and the command is allowed
400    ///   to return the same element multiple times. In this case, the number of returned elements
401    ///   is the absolute value of the specified count.
402    ///
403    /// # See Also
404    /// [<https://redis.io/commands/zrandmember/>](https://redis.io/commands/zrandmember/)
405    #[must_use]
406    fn zrandmembers_with_scores<R: DeserializeOwned>(
407        self,
408        key: impl Serialize,
409        count: isize,
410    ) -> PreparedCommand<'a, Self, R> {
411        prepare_command(
412            self,
413            cmd("ZRANDMEMBER")
414                .key(key)
415                .arg(count)
416                .arg("WITHSCORES")
417                .readonly(),
418        )
419    }
420
421    /// Returns the specified range of elements in the sorted set stored at `key`.
422    ///
423    /// # Return
424    /// A collection of elements in the specified range
425    ///
426    /// # See Also
427    /// [<https://redis.io/commands/zrange/>](https://redis.io/commands/zrange/)
428    #[must_use]
429    fn zrange<R: DeserializeOwned>(
430        self,
431        key: impl Serialize,
432        start: impl Serialize,
433        stop: impl Serialize,
434        options: ZRangeOptions,
435    ) -> PreparedCommand<'a, Self, R> {
436        prepare_command(
437            self,
438            cmd("ZRANGE")
439                .key(key)
440                .arg(start)
441                .arg(stop)
442                .arg(options)
443                .readonly(),
444        )
445    }
446
447    /// Returns the specified range of elements in the sorted set stored at `key`.
448    ///
449    /// # Return
450    /// A collection of elements and their scores in the specified range
451    ///
452    /// # See Also
453    /// [<https://redis.io/commands/zrange/>](https://redis.io/commands/zrange/)
454    #[must_use]
455    fn zrange_with_scores<R: DeserializeOwned>(
456        self,
457        key: impl Serialize,
458        start: impl Serialize,
459        stop: impl Serialize,
460        options: ZRangeOptions,
461    ) -> PreparedCommand<'a, Self, R> {
462        prepare_command(
463            self,
464            cmd("ZRANGE")
465                .key(key)
466                .arg(start)
467                .arg(stop)
468                .arg(options)
469                .arg("WITHSCORES")
470                .readonly(),
471        )
472    }
473
474    /// This command is like [zrange](SortedSetCommands::zrange),
475    /// but stores the result in the `dst` destination key.
476    ///
477    /// # Return
478    /// The number of elements in the resulting sorted set.
479    ///
480    /// # See Also
481    /// [<https://redis.io/commands/zrangestore/>](https://redis.io/commands/zrangestore/)
482    #[must_use]
483    fn zrangestore(
484        self,
485        dst: impl Serialize,
486        src: impl Serialize,
487        start: impl Serialize,
488        stop: impl Serialize,
489        options: ZRangeOptions,
490    ) -> PreparedCommand<'a, Self, usize> {
491        prepare_command(
492            self,
493            cmd("ZRANGESTORE")
494                .key(dst)
495                .key(src)
496                .arg(start)
497                .arg(stop)
498                .arg(options),
499        )
500    }
501
502    /// Returns the rank of member in the sorted set stored at key,
503    /// with the scores ordered from low to high.
504    ///
505    /// # Return
506    /// * If member exists in the sorted set, the rank of member.
507    /// * If member does not exist in the sorted set or key does not exist, None.
508    ///
509    /// # See Also
510    /// [<https://redis.io/commands/zrank/>](https://redis.io/commands/zrank/)
511    #[must_use]
512    fn zrank(
513        self,
514        key: impl Serialize,
515        member: impl Serialize,
516    ) -> PreparedCommand<'a, Self, Option<usize>> {
517        prepare_command(self, cmd("ZRANK").key(key).arg(member).readonly())
518    }
519
520    /// Returns the rank of member in the sorted set stored at key,
521    /// with the scores ordered from low to high.
522    ///
523    /// # Return
524    /// * If member exists in the sorted set, the rank of member and its score
525    /// * If member does not exist in the sorted set or key does not exist, None.
526    ///
527    /// # See Also
528    /// [<https://redis.io/commands/zrank/>](https://redis.io/commands/zrank/)
529    #[must_use]
530    fn zrank_with_score(
531        self,
532        key: impl Serialize,
533        member: impl Serialize,
534    ) -> PreparedCommand<'a, Self, Option<(usize, f64)>> {
535        prepare_command(
536            self,
537            cmd("ZRANK")
538                .key(key)
539                .arg(member)
540                .arg("WITHSCORE")
541                .readonly(),
542        )
543    }
544
545    /// Removes the specified members from the sorted set stored at key.
546    ///
547    /// # Return
548    /// The number of members removed from the sorted set, not including non existing members.
549    ///
550    /// # See Also
551    /// [<https://redis.io/commands/zrem/>](https://redis.io/commands/zrem/)
552    #[must_use]
553    fn zrem(
554        self,
555        key: impl Serialize,
556        members: impl Serialize,
557    ) -> PreparedCommand<'a, Self, usize> {
558        prepare_command(self, cmd("ZREM").key(key).arg(members))
559    }
560
561    /// When all the elements in a sorted set are inserted with the same score,
562    /// in order to force lexicographical ordering,
563    /// this command removes all elements in the sorted set stored at key
564    /// between the lexicographical range specified by min and max.
565    ///
566    /// # Return
567    /// the number of elements removed.
568    ///
569    /// # See Also
570    /// [<https://redis.io/commands/zremrangebylex/>](https://redis.io/commands/zremrangebylex/)
571    #[must_use]
572    fn zremrangebylex(
573        self,
574        key: impl Serialize,
575        start: impl Serialize,
576        stop: impl Serialize,
577    ) -> PreparedCommand<'a, Self, usize> {
578        prepare_command(self, cmd("ZREMRANGEBYLEX").key(key).arg(start).arg(stop))
579    }
580
581    /// Removes all elements in the sorted set stored at key with rank between start and stop.
582    ///
583    /// # Return
584    /// the number of elements removed.
585    ///
586    /// # See Also
587    /// [<https://redis.io/commands/zremrangebyrank/>](https://redis.io/commands/zremrangebyrank/)
588    #[must_use]
589    fn zremrangebyrank(
590        self,
591        key: impl Serialize,
592        start: isize,
593        stop: isize,
594    ) -> PreparedCommand<'a, Self, usize> {
595        prepare_command(self, cmd("ZREMRANGEBYRANK").key(key).arg(start).arg(stop))
596    }
597
598    /// Removes all elements in the sorted set stored at key with a score between min and max (inclusive).
599    ///
600    /// # Return
601    /// the number of elements removed.
602    ///
603    /// # See Also
604    /// [<https://redis.io/commands/zremrangebyscore/>](https://redis.io/commands/zremrangebyscore/)
605    #[must_use]
606    fn zremrangebyscore(
607        self,
608        key: impl Serialize,
609        start: impl Serialize,
610        stop: impl Serialize,
611    ) -> PreparedCommand<'a, Self, usize> {
612        prepare_command(self, cmd("ZREMRANGEBYSCORE").key(key).arg(start).arg(stop))
613    }
614
615    /// Returns the rank of member in the sorted set stored at key, with the scores ordered from high to low.
616    ///
617    /// # Return
618    /// * If member exists in the sorted set, the rank of member.
619    /// * If member does not exist in the sorted set or key does not exist, None.
620    ///
621    /// # See Also
622    /// [<https://redis.io/commands/zrevrank/>](https://redis.io/commands/zrevrank/)
623    #[must_use]
624    fn zrevrank(
625        self,
626        key: impl Serialize,
627        member: impl Serialize,
628    ) -> PreparedCommand<'a, Self, Option<usize>> {
629        prepare_command(self, cmd("ZREVRANK").key(key).arg(member).readonly())
630    }
631
632    /// Returns the rank of member in the sorted set stored at key, with the scores ordered from high to low.
633    ///
634    /// # Return
635    /// * If member exists in the sorted set, the rank of member and its score.
636    /// * If member does not exist in the sorted set or key does not exist, None.
637    ///
638    /// # See Also
639    /// [<https://redis.io/commands/zrevrank/>](https://redis.io/commands/zrevrank/)
640    #[must_use]
641    fn zrevrank_with_score(
642        self,
643        key: impl Serialize,
644        member: impl Serialize,
645    ) -> PreparedCommand<'a, Self, Option<(usize, f64)>> {
646        prepare_command(
647            self,
648            cmd("ZREVRANK")
649                .key(key)
650                .arg(member)
651                .arg("WITHSCORE")
652                .readonly(),
653        )
654    }
655
656    /// Iterates elements of Sorted Set types and their associated scores.
657    ///
658    /// # Returns
659    /// A tuple where
660    /// * The first value is the cursor as an unsigned 64 bit number
661    /// * The second value is a list of members and their scores in a Vec of Tuples
662    ///
663    /// # See Also
664    /// [<https://redis.io/commands/zscan/>](https://redis.io/commands/zscan/)
665    #[must_use]
666    fn zscan<R: DeserializeOwned>(
667        self,
668        key: impl Serialize,
669        cursor: usize,
670        options: ZScanOptions,
671    ) -> PreparedCommand<'a, Self, ZScanResult<R>> {
672        prepare_command(
673            self,
674            cmd("ZSCAN").key(key).arg(cursor).arg(options).readonly(),
675        )
676    }
677
678    /// Returns the score of member in the sorted set at key.
679    ///
680    /// # Return
681    /// The score of `member` or nil if `key`does not exist
682    ///
683    /// # See Also
684    /// [<https://redis.io/commands/zscore/>](https://redis.io/commands/zscore/)
685    #[must_use]
686    fn zscore(
687        self,
688        key: impl Serialize,
689        member: impl Serialize,
690    ) -> PreparedCommand<'a, Self, Option<f64>> {
691        prepare_command(self, cmd("ZSCORE").key(key).arg(member).readonly())
692    }
693
694    /// This command is similar to [zunionstore](SortedSetCommands::zunionstore),
695    /// but instead of storing the resulting sorted set, it is returned to the client.
696    ///
697    /// # Return
698    /// The result of the unionsection as an array of members
699    ///
700    /// # See Also
701    /// [<https://redis.io/commands/zunion/>](https://redis.io/commands/zunion/)
702    #[must_use]
703    fn zunion<R: DeserializeOwned>(
704        self,
705        keys: impl Serialize,
706        weights: impl Serialize,
707        aggregate: impl Into<Option<ZAggregate>>,
708    ) -> PreparedCommand<'a, Self, R> {
709        prepare_command(
710            self,
711            cmd("ZUNION")
712                .key_with_count(keys)
713                .arg_labeled("WEIGHTS", weights)
714                .arg_labeled("AGGREGATE", aggregate.into())
715                .readonly(),
716        )
717    }
718
719    /// This command is similar to [zunionstore](SortedSetCommands::zunionstore),
720    /// but instead of storing the resulting sorted set, it is returned to the client.
721    ///
722    /// # Return
723    /// The result of the unionsection as an array of members with their scores
724    ///
725    /// # See Also
726    /// [<https://redis.io/commands/zunion/>](https://redis.io/commands/zunion/)
727    #[must_use]
728    fn zunion_with_scores<R: DeserializeOwned>(
729        self,
730        keys: impl Serialize,
731        weights: impl Serialize,
732        aggregate: impl Into<Option<ZAggregate>>,
733    ) -> PreparedCommand<'a, Self, R> {
734        prepare_command(
735            self,
736            cmd("ZUNION")
737                .key_with_count(keys)
738                .arg_labeled("WEIGHTS", weights)
739                .arg_labeled("AGGREGATE", aggregate.into())
740                .arg("WITHSCORES")
741                .readonly(),
742        )
743    }
744
745    /// Computes the unionsection of numkeys sorted sets given by the specified keys,
746    /// and stores the result in destination.
747    ///
748    /// # Return
749    /// The number of elements in the resulting sorted set at destination.
750    ///
751    /// # See Also
752    /// [<https://redis.io/commands/zunionstore/>](https://redis.io/commands/zunionstore/)
753    #[must_use]
754    fn zunionstore(
755        self,
756        destination: impl Serialize,
757        keys: impl Serialize,
758        weights: impl Serialize,
759        aggregate: impl Into<Option<ZAggregate>>,
760    ) -> PreparedCommand<'a, Self, usize> {
761        prepare_command(
762            self,
763            cmd("ZUNIONSTORE")
764                .key(destination)
765                .key_with_count(keys)
766                .arg_labeled("WEIGHTS", weights)
767                .arg_labeled("AGGREGATE", aggregate.into()),
768        )
769    }
770}
771
772/// Condition option for the [`zadd`](SortedSetCommands::zadd) command
773#[derive(Serialize)]
774#[serde(rename_all = "UPPERCASE")]
775#[non_exhaustive]
776pub enum ZAddCondition {
777    /// Only update elements that already exist. Don't add new elements.
778    NX,
779    /// Only add new elements. Don't update already existing elements.
780    XX,
781}
782
783/// Comparison option for the [`zadd`](SortedSetCommands::zadd) command
784#[derive(Serialize)]
785#[serde(rename_all = "UPPERCASE")]
786#[non_exhaustive]
787pub enum ZAddComparison {
788    /// Only update existing elements if the new score is greater than the current score.
789    ///
790    /// This flag doesn't prevent adding new elements.
791    GT,
792    /// Only update existing elements if the new score is less than the current score.
793    ///
794    /// This flag doesn't prevent adding new elements.
795    LT,
796}
797
798/// sort by option of the [`zrange`](SortedSetCommands::zrange) command
799#[derive(Serialize)]
800#[serde(rename_all = "UPPERCASE")]
801#[non_exhaustive]
802pub enum ZRangeSortBy {
803    /// When the `ByScore` option is provided, the command behaves like `ZRANGEBYSCORE` and returns
804    /// the range of elements from the sorted set having scores equal or between `start` and `stop`.
805    ByScore,
806    /// When the `ByLex` option is used, the command behaves like `ZRANGEBYLEX` and returns the range
807    /// of elements from the sorted set between the `start` and `stop` lexicographical closed range intervals.
808    ByLex,
809}
810
811/// Option that specify how results of an union or intersection are aggregated
812///
813/// # See Also
814/// [zinter](SortedSetCommands::zinter)
815/// [zinterstore](SortedSetCommands::zinterstore)
816/// [zunion](SortedSetCommands::zunion)
817/// [zunionstore](SortedSetCommands::zunionstore)
818#[derive(Serialize)]
819#[serde(rename_all = "UPPERCASE")]
820#[non_exhaustive]
821pub enum ZAggregate {
822    /// The score of an element is summed across the inputs where it exists.
823    Sum,
824    /// The minimum score of an element across the inputs where it exists.
825    Min,
826    /// The maximum score of an element across the inputs where it exists.
827    Max,
828    /// The score of an element is the number of inputs it exists in.
829    Count,
830}
831
832/// Where option of the [`zmpop`](SortedSetCommands::zmpop) command
833#[derive(Serialize)]
834#[serde(rename_all = "UPPERCASE")]
835#[non_exhaustive]
836pub enum ZWhere {
837    /// When the MIN modifier is used, the elements popped are those
838    /// with the lowest scores from the first non-empty sorted set.
839    Min,
840    /// The MAX modifier causes elements with the highest scores to be popped.
841    Max,
842}
843
844/// Options for the [`zadd`](SortedSetCommands::zadd) command.
845#[derive(Default, Serialize)]
846#[serde(rename_all = "UPPERCASE")]
847pub struct ZAddOptions {
848    #[serde(rename = "", skip_serializing_if = "Option::is_none")]
849    condition: Option<ZAddCondition>,
850    #[serde(rename = "", skip_serializing_if = "Option::is_none")]
851    comparison: Option<ZAddComparison>,
852    #[serde(
853        rename = "CH",
854        skip_serializing_if = "std::ops::Not::not",
855        serialize_with = "serialize_flag"
856    )]
857    change: bool,
858}
859
860impl ZAddOptions {
861    #[must_use]
862    pub fn condition(mut self, condition: ZAddCondition) -> Self {
863        self.condition = Some(condition);
864        self
865    }
866
867    #[must_use]
868    pub fn comparison(mut self, comparison: ZAddComparison) -> Self {
869        self.comparison = Some(comparison);
870        self
871    }
872
873    #[must_use]
874    pub fn change(mut self) -> Self {
875        self.change = true;
876        self
877    }
878}
879
880/// Result for [`zmpop`](SortedSetCommands::zmpop) the command.
881pub type ZMPopResult<E> = (String, Vec<(E, f64)>);
882
883/// Options for the [`zrange`](SortedSetCommands::zrange)
884/// and [`zrangestore`](SortedSetCommands::zrangestore) commands
885#[derive(Default, Serialize)]
886#[serde(rename_all = "UPPERCASE")]
887pub struct ZRangeOptions {
888    #[serde(rename = "", skip_serializing_if = "Option::is_none")]
889    sort_by: Option<ZRangeSortBy>,
890    #[serde(
891        rename = "REV",
892        skip_serializing_if = "std::ops::Not::not",
893        serialize_with = "serialize_flag"
894    )]
895    reverse: bool,
896    #[serde(skip_serializing_if = "Option::is_none")]
897    limit: Option<(u32, i32)>,
898}
899
900impl ZRangeOptions {
901    #[must_use]
902    pub fn sort_by(mut self, sort_by: ZRangeSortBy) -> Self {
903        self.sort_by = Some(sort_by);
904        self
905    }
906
907    /// Walks the range from the highest element down.
908    ///
909    /// The bounds keep their `start stop` order but swap meaning: with
910    /// `BYSCORE` or `BYLEX` the higher bound must be given first.
911    #[must_use]
912    pub fn reverse(mut self) -> Self {
913        self.reverse = true;
914        self
915    }
916
917    #[must_use]
918    pub fn limit(mut self, offset: u32, count: i32) -> Self {
919        self.limit = Some((offset, count));
920        self
921    }
922}
923
924/// Options for the [`zscan`](SortedSetCommands::zscan) command
925#[derive(Default, Serialize)]
926#[serde(rename_all = "UPPERCASE")]
927pub struct ZScanOptions<'a> {
928    #[serde(skip_serializing_if = "Option::is_none")]
929    r#match: Option<&'a str>,
930    #[serde(skip_serializing_if = "Option::is_none")]
931    count: Option<u32>,
932}
933
934impl<'a> ZScanOptions<'a> {
935    #[must_use]
936    pub fn match_pattern(mut self, match_pattern: &'a str) -> Self {
937        self.r#match = Some(match_pattern);
938        self
939    }
940
941    #[must_use]
942    pub fn count(mut self, count: u32) -> Self {
943        self.count = Some(count);
944        self
945    }
946}
947
948/// Result for the [`zscan`](SortedSetCommands::zscan) command.
949#[derive(Debug, Deserialize)]
950#[non_exhaustive]
951pub struct ZScanResult<R: DeserializeOwned> {
952    pub cursor: u64,
953    #[serde(deserialize_with = "deserialize_vec_of_pairs")]
954    pub elements: Vec<(R, f64)>,
955}