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}