redis_macros/
lib.rs

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//! Simple macros and wrappers to [redis-rs](https://github.com/redis-rs/redis-rs/)
//! to automatically serialize and deserialize structs with serde.
//!
//! ## Simple usage
//!
//! The simplest way to start is to derive `Serialize`, `Deserialize`,
//! [`FromRedisValue`], [`ToRedisArgs`] for any kind of struct... and that's it!
//! You can now get and set these values with regular redis commands:
//!
//! ```rust,no_run
//! use redis::{Client, Commands, RedisResult};
//! use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize)]
//! enum Address {
//!     Street(String),
//!     Road(String),
//! }
//!
//! // Derive the necessary traits
//! #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! struct User {
//!     id: u32,
//!     name: String,
//!     addresses: Vec<Address>,
//! }
//!
//! fn main () -> redis::RedisResult<()> {
//!     let client = redis::Client::open("redis://localhost:6379/")?;
//!     let mut con = client.get_connection()?;
//!
//!     let user = User {
//!         id: 1,
//!         name: "Ziggy".to_string(),
//!         addresses: vec![
//!             Address::Street("Downing".to_string()),
//!             Address::Road("Abbey".to_string()),
//!         ],
//!     };
//!
//!     // Just use it as you would a primitive
//!     con.set("user", user)?;
//!     // user and stored_user will be the same
//!     let stored_user: User = con.get("user")?;
//!     # Ok(())
//! }
//! ```
//!
//! ## Usage with RedisJSON
//!
//! You can even use it with RedisJSON, to extract separate parts of the object.
//!
//! ```rust,no_run
//! # use redis::{Client, RedisResult};
//! use redis::JsonCommands;
//! # use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! # use serde::{Deserialize, Serialize};
//!
//! // Derive FromRedisValue, ToRedisArgs to the inner struct
//! #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! enum Address { Street(String), Road(String) }
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # struct User { id: u32, name: String, addresses: Vec<Address> }
//!
//! # fn main () -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://localhost:6379/")?;
//! # let mut con = client.get_connection()?;
//! # let user = User { id: 1, name: "Ziggy".to_string(), addresses: vec![ Address::Street("Downing".to_string()), Address::Road("Abbey".to_string()) ] };
//! // Simple usage is equivalent to set-get
//! con.json_set("user", "$", &user)?;
//! let stored_user: User = con.json_get("user", "$")?;
//!
//! // But you can get deep values - don't forget to derive traits for these too!
//! let stored_address: Address = con.json_get("user", "$.addresses[0]")?;
//! # Ok(())
//! # }
//! ```
//!
//! One issue you might be facing is that `redis` already has overrides for some types,
//! for example Vec, String and most primitives. For this you have to use the [Json wrapper](#json-wrapper-with-redisjson).
//!
//! ```rust,no_run
//! # use redis::{Client, JsonCommands, RedisResult};
//! # use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! # use serde::{Deserialize, Serialize};
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # enum Address { Street(String), Road(String) }
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # struct User { id: u32, name: String, addresses: Vec<Address> }
//! # fn main () -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://localhost:6379/")?;
//! # let mut con = client.get_connection()?;
//! # let user = User { id: 1, name: "Ziggy".to_string(), addresses: vec![ Address::Street("Downing".to_string()), Address::Road("Abbey".to_string()) ] };
//! # con.json_set("user", "$", &user)?;
//! // This WON'T work
//! let stored_addresses: Vec<Address> = con.json_get("user", "$.addresses")?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Json wrapper with RedisJSON
//!
//! To deserialize Vecs and primitive types when using RedisJSON, you cannot use the regular types,
//! because these are non-compatible with RedisJSON. However `redis-macros` exports a useful wrapper
//! struct: [`Json`]. When using RedisJSON, you can wrap your non-structs return values into this:
//!
//! ```rust,no_run
//! use redis_macros::Json;
//! # use redis::{Client, JsonCommands, RedisResult};
//! # use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! # use serde::{Deserialize, Serialize};
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # enum Address { Street(String), Road(String) }
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # struct User { id: u32, name: String, addresses: Vec<Address> }
//! # fn main () -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://localhost:6379/")?;
//! # let mut con = client.get_connection()?;
//! # let user = User { id: 1, name: "Ziggy".to_string(), addresses: vec![ Address::Street("Downing".to_string()), Address::Road("Abbey".to_string()) ] };
//! # con.json_set("user", "$", &user)?;

//! // Return type can be wrapped into Json
//! let Json(stored_name): Json<String> = con.json_get("user", "$.name")?;
//!
//! // It works with Vecs as well
//! let Json(stored_addresses): Json<Vec<Address>> = con.json_get("user", "$.addresses")?;
//! // ...now stored_addresses will be equal to user.addresses
//! # Ok(())
//! # }
//! ```
//!
//! If you only use RedisJSON, you can even do away with deriving `FromRedisValue` and `ToRedisArgs`, and use `Json` everywhere.
//!
//! ```rust,no_run
//! # use redis::{Client, JsonCommands, RedisResult};
//! # use redis_macros::Json;
//! # use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! # use serde::{Deserialize, Serialize};
//! # #[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! # enum Address { Street(String), Road(String) }
//! #[derive(Serialize, Deserialize)]
//! struct User { /* .. */ }
//! # fn main () -> redis::RedisResult<()> {
//! # let client = redis::Client::open("redis://localhost:6379/")?;
//! # let mut con = client.get_connection()?;
//! # let user = User {};
//! # con.json_set("user", "$", &user)?;
//!
//! // This works with simple redis-rs
//! con.json_set("user", "$", &user)?;
//! // ...and you can get back with Json wrapper
//! let Json(stored_user): Json<User> = con.json_get("user", "$")?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Using other serializer (e.g. serde-yaml)
//!
//! In case you want to use another serializer, for example `serde_yaml`, you can install it and use the derives,
//! the same way you would. The only difference should be adding an attribute `redis_serializer` under the derive,
//! with the library you want to serialize with. You can use any Serde serializer as long as they support
//! `from_str` and `to_string` methods. For the full list, see: [Serde data formats](https://serde.rs/#data-formats).
//!
//! ```rust,no_run
//! # use redis::{Client, JsonCommands, RedisResult};
//! # use redis_macros_derive::{FromRedisValue, ToRedisArgs};
//! # use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
//! #[redis_serializer(serde_yaml)]
//! struct User { /* ... */ }
//! ```

#[cfg(feature = "macros")]
extern crate redis_macros_derive;

#[cfg(feature = "json")]
mod json;

#[cfg(feature = "json")]
pub use json::Json;

/// Derive macro for the redis crate's [`FromRedisValue`](../redis/trait.FromRedisValue.html) trait to allow parsing Redis responses to this type.
/// 
/// For more information see the `redis_macros_derive` crate: [`FromRedisValue`](../redis_macros_derive/derive.FromRedisValue.html)
#[cfg(feature = "macros")]
pub use redis_macros_derive::FromRedisValue;

/// Derive macro for the redis crate's [`ToRedisArgs`](../redis/trait.ToRedisArgs.html) trait to allow passing the type to Redis commands.
/// 
/// For more information see the `redis_macros_derive` crate: [`ToRedisArgs`](../redis_macros_derive/derive.FromRedisValue.html)
#[cfg(feature = "macros")]
pub use redis_macros_derive::ToRedisArgs;