redis_macros/
json.rs

1use redis::{RedisResult, Value};
2use serde::de::DeserializeOwned;
3
4/// Json struct is a wrapper to handle the return types from the RedisJSON commands.
5/// 
6/// RedisJSON usually returns values in square brackets, which you usually had to handle manually:
7/// 
8/// ```rust,no_run
9/// # use redis::{Client, JsonCommands, RedisResult};
10/// # use redis_macros::{FromRedisValue, ToRedisArgs, Json};
11/// # use serde::{Deserialize, Serialize};
12/// # #[derive(Serialize, Deserialize)]
13/// # struct User { id: u32 }
14/// # 
15/// # fn main () -> redis::RedisResult<()> {
16/// # let client = redis::Client::open("redis://localhost:6379/")?;
17/// # let mut con = client.get_connection()?;
18/// # con.json_set("user", "$", &r#"{ "id": 1 }"#)?;
19/// // You have to manually deserialize this and pull from the Vec
20/// let user_id: String = con.json_get("user", "$.id")?;  // => "[1]"
21/// # Ok(())
22/// # }
23/// ```
24/// 
25/// Instead, `Json` implements the `FromRedisValue` trait, removes the square brackets and deserializes from JSON.
26/// For this your type don't even have to implement `FromRedisValue`, it only requires to be serde `Deserialize`-able.
27/// 
28/// ```rust,no_run
29/// # use redis::{Client, JsonCommands, RedisResult};
30/// # use redis_macros::Json;
31/// # use serde::{Deserialize, Serialize};
32/// #[derive(Serialize, Deserialize)]
33/// struct User { id: u32 }
34///  
35/// # fn main () -> redis::RedisResult<()> {
36/// # let client = redis::Client::open("redis://localhost:6379/")?;
37/// # let mut con = client.get_connection()?;
38/// # con.json_set("user", "$", &r#"{ "id": 1 }"#)?;
39/// let Json(user_id): Json<u32> = con.json_get("user", "$.id")?;  // => 1
40/// let Json(user): Json<User> = con.json_get("user", "$")?;  // => User { id: 1 }
41/// # Ok(())
42/// # }
43/// ``` 
44/// 
45/// This command is designed to use RedisJSON commands. You could probably use this type
46/// to parse normal command outputs, but it removes the first and last character
47/// so it is not recommended.
48///  
49#[derive(Debug)]
50pub struct Json<T>(
51    /// The inner type to deserialize
52    pub T
53);
54
55impl<T> ::redis::FromRedisValue for Json<T>
56where
57    T: DeserializeOwned,
58{
59    fn from_redis_value(v: &Value) -> RedisResult<Self> {
60        match *v {
61            Value::BulkString(ref bytes) => {
62                if let Ok(s) = ::std::str::from_utf8(bytes) {
63                    let mut ch = s.chars();
64                    if ch.next() == Some('[') && ch.next_back() == Some(']') {
65                        if let Ok(t) = serde_json::from_str(ch.as_str()) {
66                            Ok(Json(t))
67                        } else {
68                            Err(::redis::RedisError::from((
69                                ::redis::ErrorKind::TypeError,
70                                "Response was of incompatible type",
71                                format!("Response type in JSON was not deserializable. (response was {v:?})"),
72                            )))
73                        }
74                    } else {
75                        Err(::redis::RedisError::from((
76                            ::redis::ErrorKind::TypeError,
77                            "Response was of incompatible type",
78                            format!("Response type was not JSON type. (response was {v:?})"),
79                        )))
80                    }
81                } else {
82                    Err(::redis::RedisError::from((
83                        ::redis::ErrorKind::TypeError,
84                        "Response was of incompatible type",
85                        format!("Response was not valid UTF-8 string. (response was {v:?})"),
86                    )))
87                }
88            }
89            _ => Err(::redis::RedisError::from((
90                ::redis::ErrorKind::TypeError,
91                "Response was of incompatible type",
92                format!("Response type not RedisJSON deserializable. (response was {v:?})"),
93            ))),
94        }
95    }
96}