redis_client/
commands.rs

1use errors::RedisError;
2use redis::{PubSubArg, PubSubClientAsync, RedisClient, RedisClientAsync};
3use results::RedisResult;
4use std::collections::HashMap;
5use types::PubSubType;
6
7/// A RedisCommand purpose is to build redis commands.
8/// It can contains one or more commands for pipelining
9///
10/// Example:
11///
12/// ```
13/// # use redis_client::commands::CommandBuilder;
14/// let cmd = &mut redis_client::RedisCommand::new();
15/// cmd.set("key", "value2").get("key");
16/// ```
17///
18/// or its equivalent:
19///
20/// ```
21/// let cmd = &mut redis_client::RedisCommand::new();
22/// cmd.add_cmd("SET").add_arg("key").add_arg("value2").end().add_cmd("GET").add_arg("key").end();
23/// ```
24pub struct RedisCommand {
25    cmd: Vec<u8>,
26    cmd_nb: usize,
27}
28
29impl<'a> From<&'a mut RedisCommand> for &'a[u8] {
30    fn from(command: &mut RedisCommand) -> &[u8] {
31        &command.cmd[..]
32    }
33}
34
35impl<'a> From<&'a mut RedisCommand> for Vec<u8> {
36    fn from(command: &mut RedisCommand) -> Vec<u8> {
37        command.cmd.clone()
38    }
39}
40
41impl RedisCommand {
42    pub fn new() -> RedisCommand {
43        RedisCommand {
44            cmd: vec![],
45            cmd_nb: 0,
46        }
47    }
48
49    /// Add a string representing the command (APPEND, GET, SET...) to the command. (Each command should start with this method)
50    pub fn add_cmd<C>(&mut self, command: C) -> &mut RedisCommand where C: ToString {
51        self.cmd.extend(command.to_string().into_bytes());
52        self
53    }
54
55    /// Add a whitespace and a string to the commands
56    pub fn add_arg<A>(&mut self, arg: A) -> &mut RedisCommand where A: ToString {
57        self.cmd.extend([32].iter().cloned()); 
58        self.cmd.extend(arg.to_string().into_bytes());
59        self
60    }
61
62    /// Add a whitespace and a string for each one of the vector's items to the commands 
63    pub fn add_args<A>(&mut self, args: Vec<A>) -> &mut RedisCommand where A: ToString {
64        for arg in args {
65            self.cmd.extend([32].iter().cloned()); 
66            self.cmd.extend(arg.to_string().into_bytes());
67        }
68        self
69    }
70
71    /// Add a whitespace a key another whitespace and the value for each pair of the hash map to the curent command   
72    pub fn add_arg_map<F: ToString>(&mut self, args: HashMap<String, F>) -> &mut RedisCommand {
73        for (arg, value) in args {
74            self.cmd.extend([32].iter().cloned()); 
75            self.cmd.extend(arg.to_string().into_bytes());
76            self.cmd.extend([32].iter().cloned()); 
77            self.cmd.extend(value.to_string().into_bytes());
78        }
79        self
80    }
81    
82    /// Add a whitespace and then an array of byte to the command        
83    pub fn add_binary_arg(&mut self, arg: &[u8]) -> &mut RedisCommand {
84        self.cmd.extend([32].iter().cloned()); 
85        self.cmd.extend(arg.iter().cloned());
86        self
87    }
88
89    /// Teminate a command
90    pub fn end(&mut self) -> &mut RedisCommand {
91        self.cmd.extend([13, 10].iter().cloned());
92        self.cmd_nb += 1;
93        self
94    }
95
96    /// Get the number of commands in the RedisCommand object
97    pub fn get_command_nb(&self) -> usize {
98        self.cmd_nb
99    }
100}
101
102macro_rules! generate_command_traits {
103    ($(
104        fn $func_name:ident$(<$($gen_id:ident: $gen_type:ident),*>)*($($arg_name:ident: $arg_type:ty),*)  {
105            $($cmd:ident $bo:expr;)+
106        } 
107    )*)
108    => 
109    (
110        /// The trait CommandBuilder implements methods to abstract the construction of redis commands.
111        ///
112        /// So we can use:
113        ///
114        /// ```
115        /// # use redis_client::commands::CommandBuilder;
116        /// let cmd = &mut redis_client::RedisCommand::new();
117        /// cmd.set("key", "value2");
118        /// ```
119        ///
120        /// Instead of:
121        ///
122        /// ```
123        /// let cmd = &mut redis_client::RedisCommand::new();
124        /// cmd.add_cmd("SET").add_arg("key").add_arg("value2").end();
125        /// ```
126        pub trait CommandBuilder {
127            $(
128                fn $func_name$(<$($gen_id : $gen_type),*>)* (&mut self $(,$arg_name: $arg_type)*) -> &mut RedisCommand;
129            )*
130        }
131
132        impl CommandBuilder for RedisCommand{
133            $(
134                fn $func_name$(<$($gen_id : $gen_type),*>)* (&mut self $(,$arg_name: $arg_type)*) -> &mut RedisCommand {
135                    $(self.$cmd($bo));*;
136                    self.end()
137                }
138            )*
139        }
140
141        /// The trait CommandSender implements methods to send redis commands and receive the response synchronously.
142        ///
143        /// Each methods returns a:
144        ///
145        /// ```plain
146        /// Result<R: From<RedisResult>, RedisError>
147        /// ```
148        /// 
149        /// It means that when calling a method from this trait you need to specify the type you want R to be.
150        /// For example:
151        ///
152        /// ```no_run
153        /// # use redis_client::commands::CommandSender;
154        /// # fn function() -> Result<(), redis_client::errors::RedisError> {
155        /// # let mut client = redis_client::redis::RedisClient::new("127.0.0.1", "6379").unwrap();
156        /// let result: String = try!(client.set("key", "value"));
157        /// # Ok(())}
158        /// ```
159        pub trait CommandSender {
160            $(
161                fn $func_name<R: From<RedisResult>, $($($gen_id : $gen_type),*)*> (&mut self $(,$arg_name: $arg_type)*) -> Result<R, RedisError>;
162            )*
163        }
164
165        impl CommandSender for RedisClient{
166            $(
167                fn $func_name<R: From<RedisResult>, $($($gen_id : $gen_type),*)*> (&mut self $(,$arg_name: $arg_type)*) -> Result<R, RedisError> {
168                    let cmd = &mut RedisCommand::new();
169                    cmd.$func_name($($arg_name),*);
170
171                    let res = try!(self.exec_redis_command(cmd));     
172                    Ok(res.convert::<R>())
173                }
174            )*
175        }
176
177        /// The trait CommandSenderAsync implements methods to send redis commands and receive the response asynchronously.
178        ///
179        /// Each methods returns a:
180        ///
181        /// ```plain
182        /// Result<(), RedisError>
183        /// ```
184        /// 
185        /// It means that when calling a method from this trait if the Result is an error, the command execution failed to start.
186        /// Otherwise it means that the command execution was successfully launched.
187        /// 
188        /// Each method will contained a callback argument:
189        ///
190        /// ```plain
191        /// Fn(Result<RedisResult, RedisError>)
192        /// ```
193        /// Once the command execution is over, it will be called once the pump method is called.
194        /// 
195        /// All commands execution are made in a background thread. 
196        pub trait CommandSenderAsync {
197            $(
198                fn $func_name<G: Fn(Result<RedisResult, RedisError>), $($($gen_id : $gen_type),*)*> (&mut self $(,$arg_name: $arg_type)*, callback: G) 
199                    -> Result<(), RedisError> where G: Send + 'static;
200            )*
201        }
202
203        impl CommandSenderAsync for RedisClientAsync{
204            $(
205                fn $func_name<G: Fn(Result<RedisResult, RedisError>), $($($gen_id : $gen_type),*)*> (&mut self $(,$arg_name: $arg_type)*, callback: G) 
206                    -> Result<(), RedisError> where G: Send + 'static 
207                {
208                    let cmd = &mut RedisCommand::new();
209                    cmd.$func_name($($arg_name),*);
210
211                    try!(self.exec_redis_command_async(cmd, callback));     
212                    Ok(())
213                }
214            )*
215        }
216
217        pub trait PubSubCommandAsync {
218            fn subscribe<C: ToString, G: Fn(Result<RedisResult, RedisError>), S: Fn(RedisResult)>(&mut self, channel: C, cmd_callback: G, callback: S) 
219                -> Result<(), RedisError> where G: Send + 'static, S: Send + 'static;
220
221            fn psubscribe<C: ToString, G: Fn(Result<RedisResult, RedisError>), S: Fn(RedisResult)>(&mut self, channel: C, cmd_callback: G, callback: S) 
222                -> Result<(), RedisError> where G: Send + 'static, S: Send + 'static;
223
224            fn publish<C: ToString, M: ToString, G: Fn(Result<RedisResult, RedisError>)>(&mut self, channel: C, message: M, cmd_callback: G)
225                -> Result<(), RedisError> where G: Send + 'static;
226        }
227
228        impl PubSubCommandAsync for PubSubClientAsync {
229            fn subscribe<C: ToString, G: Fn(Result<RedisResult, RedisError>), S: Fn(RedisResult)>(&mut self, channel: C, cmd_callback: G, callback: S) 
230                -> Result<(), RedisError> where G: Send + 'static, S: Send + 'static
231            {
232                let channel_str: String = channel.to_string();
233                let cmd = &mut RedisCommand::new();
234                cmd.add_arg("SUBSCRIBE").add_arg(channel).end();
235
236                try!(self.exec_redis_command_async(cmd, cmd_callback, PubSubArg{
237                    pubsub_type: PubSubType::Channel(channel_str), 
238                    callback: Some(Box::new(callback))
239                }));     
240                Ok(())
241            }
242
243            fn psubscribe<C: ToString, G: Fn(Result<RedisResult, RedisError>), S: Fn(RedisResult)>(&mut self, channel: C, cmd_callback: G, callback: S) 
244                -> Result<(), RedisError> where G: Send + 'static, S: Send + 'static
245            {
246                let channel_str: String = channel.to_string();
247                let cmd = &mut RedisCommand::new();
248                cmd.add_arg("PSUBSCRIBE").add_arg(channel).end();
249
250                try!(self.exec_redis_command_async(cmd, cmd_callback, PubSubArg{
251                    pubsub_type: PubSubType::Pattern(channel_str), 
252                    callback: Some(Box::new(callback))
253                }));     
254                Ok(())
255            }
256
257            fn publish<C: ToString, M: ToString, G: Fn(Result<RedisResult, RedisError>)>(&mut self, channel: C, message: M, cmd_callback: G) 
258                -> Result<(), RedisError> where G: Send + 'static
259            {
260                let cmd = &mut RedisCommand::new();
261                cmd.add_arg("PUBLISH").add_arg(channel).add_arg(message).end();
262
263                try!(self.exec_redis_command_async(cmd, cmd_callback, PubSubArg{
264                    pubsub_type: PubSubType::Simple,
265                    callback: None
266                }));     
267                Ok(())
268            }
269        }
270    )
271}
272
273generate_command_traits!{
274    fn append<K: ToString, V: ToString>(key: K, value: V) {
275        add_cmd("APPEND");
276        add_arg(key);
277        add_arg(value);
278    }
279
280    fn auth<P: ToString>(password: P) {
281        add_cmd("AUTH");
282        add_arg(password);
283    }
284
285    fn bgrewriteaof() {
286        add_cmd("BGREWRITEAOF");
287    }
288
289    fn bgsave() {
290        add_cmd("BGSAVE");
291    }
292
293    fn bitcount<K: ToString>(key: K) {
294        add_cmd("BITCOUNT");
295        add_arg(key);
296    }
297
298    fn bitcount_range<K: ToString>(key: K, start_range: i64, end_range: i64) {
299        add_cmd("BITCOUNT");
300        add_arg(key);
301        add_arg(start_range);
302        add_arg(end_range);
303    }
304
305    fn blpop<K: ToString>(key: K, timeout: u32) {
306        add_cmd("BLPOP");
307        add_arg(key);
308        add_arg(timeout);
309    }
310
311    fn mblpop<K: ToString>(keys: Vec<K>, timeout: u32) {
312        add_cmd("BLPOP");
313        add_args(keys);
314        add_arg(timeout);
315    }
316
317    fn brpop<K: ToString>(key: K, timeout: u32) {
318        add_cmd("BRPOP");
319        add_arg(key);
320        add_arg(timeout);
321    }
322
323    fn mbrpop<K: ToString>(keys: Vec<K>, timeout: u32) {
324        add_cmd("BRPOP");
325        add_args(keys);
326        add_arg(timeout);
327    }
328
329    fn brpoplpush<S: ToString, D: ToString>(source: S, dest: D, timeout: u32) {
330        add_cmd("BRPOPLPUSH");
331        add_arg(source);
332        add_arg(dest);
333        add_arg(timeout);
334    }
335
336    fn decr<K: ToString>(key: K) {
337        add_cmd("DECR");
338        add_arg(key);
339    }
340
341    fn decrby<K: ToString>(key: K, increment: i64) {
342        add_cmd("DECRBY");
343        add_arg(key);
344        add_arg(increment);
345    }
346
347    fn del<K: ToString>(key: K) {
348        add_cmd("DEL");
349        add_arg(key);
350    }
351
352    fn mdel<K: ToString>(keys: Vec<K>){
353        add_cmd("DEL");
354        add_args(keys);
355    }
356
357    fn discard() {
358        add_cmd("DISCARD");
359    }
360
361    fn echo<K: ToString>(msg: K) {
362        add_cmd("ECHO");
363        add_arg(msg);
364    }
365
366    fn exec() {
367        add_cmd("EXEC");
368    }
369
370    fn exists<K: ToString>(key: K) {
371        add_cmd("EXISTS");
372        add_arg(key);
373    }
374
375    fn mexists<K: ToString>(keys: Vec<K>){
376        add_cmd("EXISTS");
377        add_args(keys);
378    }
379
380    fn expire<K: ToString>(key: K, expiry: i64) {
381        add_cmd("EXPIRE");
382        add_arg(key);
383        add_arg(expiry);
384    }
385
386    fn expireat<K: ToString>(key: K, timestamp: i64) {
387        add_cmd("EXPIREAT");
388        add_arg(key);
389        add_arg(timestamp);
390    }
391
392    fn get<K: ToString>(key: K) {
393        add_cmd("GET");
394        add_arg(key);
395    }
396
397    fn getrange<K: ToString>(key: K, start_range: i64, end_range: i64) {
398        add_cmd("GETRANGE");
399        add_arg(key);
400        add_arg(start_range);
401        add_arg(end_range);
402    }
403
404    fn hdel<K: ToString, F: ToString>(key: K, field: F) {
405        add_cmd("HDEL");
406        add_arg(key);
407        add_arg(field);
408    }
409
410    fn hmdel<K: ToString, V: ToString>(key: K, fields: Vec<V>) {
411        add_cmd("HDEL");
412        add_arg(key);
413        add_args(fields);
414    }
415
416    fn hexists<K: ToString, F: ToString>(key: K, field: F) {
417        add_cmd("HEXISTS");
418        add_arg(key);
419        add_arg(field);
420    }
421
422    fn hget<K: ToString, F: ToString>(key: K, field: F) {
423        add_cmd("HGET");
424        add_arg(key);
425        add_arg(field);
426    }
427
428    fn hgetall<K: ToString>(key: K) {
429        add_cmd("HGETALL");
430        add_arg(key);
431    }
432
433    fn hincrby<K: ToString, F: ToString>(key: K, field: F, increment: i64) {
434        add_cmd("HINCRBY");
435        add_arg(key);
436        add_arg(field);
437        add_arg(increment);
438    }
439
440    fn hincrbyfloat<K: ToString, F: ToString>(key: K, field: F, increment: f64) {
441        add_cmd("HINCRBYBYFLOAT");
442        add_arg(key);
443        add_arg(field);
444        add_arg(increment);
445    }
446
447    fn hkeys<K: ToString>(key: K) {
448        add_cmd("HKEYS");
449        add_arg(key);
450    }
451
452    fn hlen<K: ToString>(key: K) {
453        add_cmd("HLEN");
454        add_arg(key);
455    }
456
457    fn hmget<K: ToString, F: ToString>(key: K, fields: Vec<F>) {
458        add_cmd("HMGET");
459        add_arg(key);
460        add_args(fields);
461    }
462
463    fn hmset<K: ToString>(key: K, fields: HashMap<String, K>) {
464        add_cmd("HMSET");
465        add_arg(key);
466        add_arg_map(fields);
467    }
468
469    fn hset<K: ToString, F: ToString, V: ToString>(key: K, field: F, value: V) {
470        add_cmd("HSET");
471        add_arg(key);
472        add_arg(field);
473        add_arg(value);
474    }
475
476    fn hstrlen<K: ToString, F: ToString>(key: K, field: F) {
477        add_cmd("HSTRLEN");
478        add_arg(key);
479        add_arg(field);
480    }
481
482    fn hsetnx<K: ToString, F: ToString, V: ToString>(key: K, field: F, value: V) {
483        add_cmd("HSETNX");
484        add_arg(key);
485        add_arg(field);
486        add_arg(value);
487    }
488
489    fn hvals<K: ToString>(key: K) {
490        add_cmd("HVALS");
491        add_arg(key);
492    }
493
494    fn lindex<K: ToString>(key: K, index: i32) {
495        add_cmd("LINDEX");
496        add_arg(key);
497        add_arg(index);
498    }
499
500    fn linsert_after<K: ToString, P: ToString, V: ToString>(key: K, pivot: P, value: V) {
501        add_cmd("LINSERT");
502        add_arg(key);
503        add_arg("AFTER");
504        add_arg(pivot);
505        add_arg(value);
506    }
507
508    fn linsert_before<K: ToString, P: ToString, V: ToString>(key: K, pivot: P, value: V) {
509        add_cmd("LINSERT");
510        add_arg(key);
511        add_arg("BEFORE");
512        add_arg(pivot);
513        add_arg(value);
514    }
515
516    fn llen<K: ToString>(key: K) {
517        add_cmd("LLEN");
518        add_arg(key);
519    }
520
521    fn lpop<K: ToString>(key: K) {
522        add_cmd("LPOP");
523        add_arg(key);
524    }
525
526    fn lpush<K: ToString, V: ToString>(key: K, value: V) {
527        add_cmd("LPUSH");
528        add_arg(key);
529        add_arg(value);
530    }
531
532    fn mlpush<K: ToString, V: ToString>(key: K, values: Vec<V>) {
533        add_cmd("LPUSH");
534        add_arg(key);
535        add_args(values);
536    }
537
538    fn lpushx<K: ToString, V: ToString>(key: K, value: V) {
539        add_cmd("LPUSHX");
540        add_arg(key);
541        add_arg(value);
542    }
543
544    fn lrange<K: ToString>(key: K, start: i32, end: i32) {
545        add_cmd("LRANGE");
546        add_arg(key);
547        add_arg(start);
548        add_arg(end);
549    }
550
551    fn lrem<K: ToString, V: ToString>(key: K, count: i32, value: V) {
552        add_cmd("LREM");
553        add_arg(key);
554        add_arg(count);
555        add_arg(value);
556    }
557
558    fn lset<K: ToString, V: ToString>(key: K, index: i32, value: V) {
559        add_cmd("LSET");
560        add_arg(key);
561        add_arg(index);
562        add_arg(value);
563    }
564
565    fn ltrim<K: ToString>(key: K, start: i32, end: i32) {
566        add_cmd("LTRIM");
567        add_arg(key);
568        add_arg(start);
569        add_arg(end);
570    }
571
572    fn multi() {
573        add_cmd("MULTI");
574    }
575
576    fn rename<K: ToString, N: ToString>(key: K, new_key: N) {
577        add_cmd("RENAME");
578        add_arg(key);
579        add_arg(new_key);
580    }
581
582    fn renamenx<K: ToString, N: ToString>(key: K, new_key: N) {
583        add_cmd("RENAMENX");
584        add_arg(key);
585        add_arg(new_key);
586    }
587
588    fn rpop<K: ToString>(key: K) {
589        add_cmd("RPOP");
590        add_arg(key);
591    }
592
593    fn rpoplpush<S: ToString, D: ToString>(source: S, dest: D) {
594        add_cmd("RPOPLPUSH");
595        add_arg(source);
596        add_arg(dest);
597    }
598
599    fn rpush<K: ToString, V: ToString>(key: K, value: V) {
600        add_cmd("RPUSH");
601        add_arg(key);
602        add_arg(value);
603    }
604
605    fn mrpush<K: ToString, V: ToString>(key: K, values: Vec<V>) {
606        add_cmd("RPUSH");
607        add_arg(key);
608        add_args(values);
609    }
610
611    fn rpushx<K: ToString, V: ToString>(key: K, value: V) {
612        add_cmd("RPUSHX");
613        add_arg(key);
614        add_arg(value);
615    }
616
617    fn sadd<K: ToString, M: ToString>(key: K, member: M) {
618        add_cmd("SADD");
619        add_arg(key);
620        add_arg(member);
621    }
622
623    fn msadd<K: ToString, M: ToString>(key: K, members: Vec<M>) {
624        add_cmd("SADD");
625        add_arg(key);
626        add_args(members);
627    }
628
629    fn sadd_binary<K: ToString>(key: K, member: &[u8]) {
630        add_cmd("SADD");
631        add_arg(key);
632        add_binary_arg(member);
633    }
634
635    fn scard<K: ToString>(key: K) {
636        add_cmd("SCARD");
637        add_arg(key);
638    }
639
640    fn select(db_index: i32){
641        add_cmd("SELECT");
642        add_arg(db_index);
643    }
644
645    fn set<K: ToString, V: ToString>(key: K, value: V) {
646        add_cmd("SET");
647        add_arg(key);
648        add_arg(value);
649    }
650
651    fn set_binary<K: ToString>(key: K, value: &[u8]) {
652        add_cmd("SET");
653        add_arg(key);
654        add_binary_arg(value);
655    }
656
657    fn setex<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
658        add_cmd("SET");
659        add_arg(key);
660        add_arg(value);
661        add_arg("EX");
662        add_arg(expiry);
663    }
664
665    fn psetex<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
666        add_cmd("SET");
667        add_arg(key);
668        add_arg(value);
669        add_arg("PX");
670        add_arg(expiry);
671    }
672
673    fn setnx<K: ToString, V: ToString>(key: K, value: V) {
674        add_cmd("SET");
675        add_arg(key);
676        add_arg(value);
677        add_arg("NX");
678    }
679
680    fn setxx<K: ToString, V: ToString>(key: K, value: V) {
681        add_cmd("SET");
682        add_arg(key);
683        add_arg(value);
684        add_arg("XX");
685    }
686
687    fn setex_nx<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
688        add_cmd("SET");
689        add_arg(key);
690        add_arg(value);
691        add_arg("EX");
692        add_arg(expiry);
693        add_arg("NX");
694    }
695
696    fn setex_xx<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
697        add_cmd("SET");
698        add_arg(key);
699        add_arg(value);
700        add_arg("EX");
701        add_arg(expiry);
702        add_arg("XX");
703    }
704
705    fn psetex_nx<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
706        add_cmd("SET");
707        add_arg(key);
708        add_arg(value);
709        add_arg("PX");
710        add_arg(expiry);
711        add_arg("NX");
712    }
713
714    fn psetex_xx<K: ToString, V: ToString>(key: K, value: V, expiry: i64) {
715        add_cmd("SET");
716        add_arg(key);
717        add_arg(value);
718        add_arg("PX");
719        add_arg(expiry);
720        add_arg("XX");
721    }
722
723    fn setbit<K: ToString>(key: K, offset: u32, bit: u8) {
724        add_cmd("SETBIT");
725        add_arg(key);
726        add_arg(offset);
727        add_arg(bit);
728    }
729
730    fn setrange<K: ToString, V: ToString>(key: K, offset: u32, value: V) {
731        add_cmd("SETRANGE");
732        add_arg(key);
733        add_arg(offset);
734        add_arg(value);
735    }
736
737    fn sismember<K: ToString, M: ToString>(key: K, member: M) {
738        add_cmd("SISMEMBER");
739        add_arg(key);
740        add_arg(member);
741    }
742
743    fn smembers<K: ToString>(key: K) {
744        add_cmd("SMEMBERS");
745        add_arg(key);
746    }
747
748    fn spop<K: ToString>(key: K) {
749        add_cmd("SPOP");
750        add_arg(key);
751    }
752
753    fn spop_count<K: ToString>(key: K, count: u32) {
754        add_cmd("SPOP");
755        add_arg(key);
756        add_arg(count);
757    }
758
759    fn srem<K: ToString, M: ToString>(key: K, member: M) {
760        add_cmd("SREM");
761        add_arg(key);
762        add_arg(member);
763    }
764
765    fn msrem<K: ToString, M: ToString>(key: K, members: Vec<M>) {
766        add_cmd("SREM");
767        add_arg(key);
768        add_args(members);
769    }
770
771    fn strlen<K: ToString>(key: K) {
772        add_cmd("STRLEN");
773        add_arg(key);
774    }
775
776    fn ttl<K: ToString>(key: K) {
777        add_cmd("TTL");
778        add_arg(key);
779    }
780
781    fn unwatch() {
782        add_cmd("UNWATCH");
783    }
784
785    fn watch<K: ToString>(key: K) {
786        add_cmd("WATCH");
787        add_arg(key);
788    }
789
790    fn mwatch<K: ToString>(keys: Vec<K>) {
791        add_cmd("WATCH");
792        add_args(keys);
793    }
794
795    fn zadd<K: ToString, V: ToString>(key: K, score: f64, member: V) {
796        add_cmd("ZADD");
797        add_arg(key);
798        add_arg(score);
799        add_arg(member);
800    }
801
802    fn zadd_binary<K: ToString>(key: K, score: f64, member: &[u8]) {
803        add_cmd("ZADD");
804        add_arg(key);
805        add_arg(score);
806        add_binary_arg(member);
807    }
808
809    fn zaddnx<K: ToString, V: ToString>(key: K, score: f64, member: V) {
810        add_cmd("ZADD");
811        add_arg(key);
812        add_arg("NX");
813        add_arg(score);
814        add_arg(member);
815    }
816
817    fn zaddxx<K: ToString, V: ToString>(key: K, score: f64, member: V) {
818        add_cmd("ZADD");
819        add_arg(key);
820        add_arg("XX");
821        add_arg(score);
822        add_arg(member);
823    }
824
825    fn zaddnx_ch<K: ToString, V: ToString>(key: K, score: f64, member: V) {
826        add_cmd("ZADD");
827        add_arg(key);
828        add_arg("NX");
829        add_arg("CH");
830        add_arg(score);
831        add_arg(member);
832    }
833
834    fn zaddxx_ch<K: ToString, V: ToString>(key: K, score: f64, member: V) {
835        add_cmd("ZADD");
836        add_arg(key);
837        add_arg("XX");
838        add_arg("CH");
839        add_arg(score);
840        add_arg(member);
841    }
842
843    fn zcard<K: ToString>(key: K) {
844        add_cmd("ZCARD");
845        add_arg(key);
846    }
847
848    fn zcount<K: ToString, S: ToString, E: ToString>(key: K, start_range: S, end_range: E) {
849        add_cmd("ZCOUNT");
850        add_arg(key);
851        add_arg(start_range);
852        add_arg(end_range);
853    }
854
855    fn zincrby<K: ToString, V: ToString>(key: K, increment: f64, member: V) {
856        add_cmd("ZINCRBY");
857        add_arg(key);
858        add_arg(increment);
859        add_arg(member);
860    }
861
862    fn zlexcount<K: ToString, S: ToString, E: ToString>(key: K, min: S, max: E) {
863        add_cmd("ZLEXCOUNT");
864        add_arg(key);
865        add_arg(min);
866        add_arg(max);
867    }
868
869    fn zrem<K: ToString, M: ToString>(key: K, member: M) {
870        add_cmd("ZREM");
871        add_arg(key);
872        add_arg(member);
873    }
874
875    fn mzrem<K: ToString, M: ToString>(key: K, members: Vec<M>) {
876        add_cmd("ZREM");
877        add_arg(key);
878        add_args(members);
879    }
880
881    fn zrange<K: ToString>(key: K, start_range: i64, end_range: i64) {
882        add_cmd("ZRANGE");
883        add_arg(key);
884        add_arg(start_range);
885        add_arg(end_range);
886    }
887
888    fn zrange_with_scores<K: ToString>(key: K, start_range: i64, end_range: i64) {
889        add_cmd("ZRANGE");
890        add_arg(key);
891        add_arg(start_range);
892        add_arg(end_range);
893        add_arg("WITHSCORES");
894    }
895
896    fn zrevrange<K: ToString>(key: K, start_range: i64, end_range: i64) {
897        add_cmd("ZREVRANGE");
898        add_arg(key);
899        add_arg(start_range);
900        add_arg(end_range);
901    }
902
903    fn zrevrange_with_scores<K: ToString>(key: K, start_range: i64, end_range: i64) {
904        add_cmd("ZREVRANGE");
905        add_arg(key);
906        add_arg(start_range);
907        add_arg(end_range);
908        add_arg("WITHSCORES");
909    }
910        
911}
912