1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use futures::future::Future;
use redis::{aio::ConnectionLike, cmd, Cmd, ErrorKind, FromRedisValue, RedisFuture, ToRedisArgs};

impl<T> Commands for T where T: ConnectionLike + Sized + Send + 'static {}

/// A helper trait to easily execute common
/// asynchronous Redis commands on a
/// `redis::async::ConnectionLike`
pub trait Commands: Sized + ConnectionLike + Send + 'static {
    /// Execute a command and expect a result
    fn query<T>(self, cmd: &Cmd) -> RedisFuture<(Self, T)>
    where
        T: FromRedisValue + Send + 'static,
    {
        cmd.query_async(self)
    }

    /// Execute a command and do not expect a result and instead
    /// just check whether the command did not fail
    fn execute<T>(self, cmd: &Cmd) -> RedisFuture<(Self, ())>
    where
        T: FromRedisValue + Send + 'static,
    {
        cmd.query_async(self)
    }

    /// Send a ping command.
    fn ping(self) -> RedisFuture<(Self, ())> {
        Box::new(
            Cmd::new()
                .arg("PING")
                .query_async::<_, String>(self)
                .and_then(|(conn, rsp)| {
                    if rsp == "PONG" {
                        Ok((conn, ()))
                    } else {
                        Err((ErrorKind::IoError, "ping failed").into())
                    }
                }),
        )
    }

    /// Gets all keys matching pattern
    fn keys<K: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
    ) -> RedisFuture<(Self, RV)> {
        cmd("KEYS").arg(key).query_async(self)
    }

    /// Get the value of a key.  If key is a vec this becomes an `MGET`.
    fn get<K: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
    ) -> RedisFuture<(Self, RV)> {
        cmd(if key.is_single_arg() { "GET" } else { "MGET" })
            .arg(key)
            .query_async(self)
    }

    /// Set the string value of a key.
    fn set<K: ToRedisArgs, V: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
        value: V,
    ) -> RedisFuture<(Self, RV)> {
        cmd("SET").arg(key).arg(value).query_async(self)
    }

    /// Set the value of a key, only if the key does not exist
    fn set_nx<K: ToRedisArgs, V: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
        value: V,
    ) -> RedisFuture<(Self, RV)> {
        cmd("SETNX").arg(key).arg(value).query_async(self)
    }

    /// Sets multiple keys to their values.
    fn set_multiple<K: ToRedisArgs, V: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        items: &[(K, V)],
    ) -> RedisFuture<(Self, RV)> {
        cmd("MSET").arg(items).query_async(self)
    }

    /// Sets multiple keys to their values failing if at least one already exists.
    fn set_multiple_nx<K: ToRedisArgs, V: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        items: &[(K, V)],
    ) -> RedisFuture<(Self, RV)> {
        cmd("MSETNX").arg(items).query_async(self)
    }

    /// Delete one or more keys.
    fn del<K: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
    ) -> RedisFuture<(Self, RV)> {
        cmd("DEL").arg(key).query_async(self)
    }

    /// Determine if one or more keys exist.
    fn exists<K: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
    ) -> RedisFuture<(Self, RV)> {
        cmd("EXISTS").arg(key).query_async(self)
    }

    /// Determine the number of keys.
    fn db_size<K: ToRedisArgs, RV: FromRedisValue + Send + 'static>(
        self,
        key: K,
    ) -> RedisFuture<(Self, RV)> {
        cmd("DBSIZE").arg(key).query_async(self)
    }
}