6个版本 (3个重大更新)
0.4.0 | 2024年8月5日 |
---|---|
0.3.0 | 2024年4月1日 |
0.2.1 | 2023年7月4日 |
0.1.1 | 2023年2月5日 |
0.1.0 | 2023年1月30日 |
#208 in 编码
22,829 每月下载量
在 2 crates 中使用
23KB
61 代码行
redis-macros
为redis-rs提供简单的宏和包装器,以自动使用serde对结构体进行序列化和反序列化。
安装
要安装它,只需添加包redis-macros
。此包是redis的辅助工具,使用serde
和serde_json
(或任何其他序列化器),因此也将这些添加到依赖项中。
[dependencies]
redis-macros = "0.3.0"
redis = { version = "0.25.2" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
基本用法
简单用法
最简单的方法是为任何类型的结构体派生Serialize
、Deserialize
、FromRedisValue
、ToRedisArgs
...然后就可以了!现在您可以使用常规的redis命令获取和设置这些值
use redis::{Client, Commands, RedisResult};
use redis_macros::{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://127.0.0.1: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")?;
}
与RedisJSON一起使用
您甚至可以使用它与RedisJSON一起使用,以提取对象的各个部分。
// Use `JsonCommands`
use redis::{Client, JsonCommands, RedisResult};
// Derive FromRedisValue, ToRedisArgs to the inner struct
#[derive(Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
enum Address { /* ... */ }
// 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]")?;
有关更多信息,请参阅RedisJSON示例。
您可能会遇到一个问题,即redis
已经对某些类型进行了覆盖,例如Vec、String和大多数原语。对于此,您必须使用Json包装器。
// This WON'T work
let stored_addresses: Vec<Address> = con.json_get("user", "$.addresses")?;
带有RedisJSON的Json包装器
当使用RedisJSON进行反序列化Vec和原语类型时,您不能使用常规类型,因为这些与RedisJSON不兼容。然而redis-macros
导出了一个有用的包装结构:Json
。当使用RedisJSON时,您可以将非结构体返回值包装在这个中
use redis_macros::Json;
// 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
如果您只使用RedisJSON,甚至可以去掉派生FromRedisValue
和ToRedisArgs
,并使用Json
在任何地方。
#[derive(Serialize, Deserialize)]
struct 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", "$")?;
有关更多信息,请参阅Json Wrapper和Json Wrapper 高级示例。
使用其他序列化程序(例如 serde-yaml)
如果您想使用其他序列化程序,例如serde_yaml
,您可以安装它并使用derives,方法与之前相同。唯一的区别应该是在derives下添加一个属性redis_serializer
,用于您想要序列化的库。只要它们支持from_str
和to_string
方法,您就可以使用任何Serde序列化程序。完整列表请参阅:Serde数据格式。
#[derive(Debug, PartialEq, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
#[redis_serializer(serde_yaml)]
struct User { /* ... */ }
有关更多信息,请参阅YAML示例。
使用 deadpool-redis 或其他 crate
如果您使用的是重新导出redis
traits 的 crate,例如deadpool-redis,您仍然可以使用宏。您需要做的唯一改变是明确使用重新导出的redis
包。
// In the case of deadpool-redis, bring the reexported crate into scope
use deadpool_redis::redis;
// Or if you are importing multiple things from redis, use redis::self
use deadpool_redis::{redis::{self, AsyncCommands}, Config, Runtime};
有关更多信息,请参阅deadpool-redis示例。
测试
您可以使用cargo test
在代码上运行单元测试。
cargo test
对于集成测试,您可以运行示例。您需要一个与RedisJSON兼容的、运行在端口6379的redis-server,推荐使用redis-stack docker镜像。
docker run -d --rm -p 6379:6379 --name redis docker.io/redis/redis-stack
cargo test --examples
# cleanup the container
docker stop redis
覆盖率
对于覆盖率,您可以使用grcov
。如果您还没有安装,请简单地安装llvm-tools-preview
和grcov
。
rustup component add llvm-tools-preview
cargo install grcov
您必须导出一些标志以使其正常工作。
export RUSTFLAGS='-Cinstrument-coverage'
export LLVM_PROFILE_FILE='.coverage/cargo-test-%p-%m.profraw'
最后,运行测试并生成输出。
cargo test
cargo test --examples
grcov .coverage/ -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./target/debug/coverage/
现在您可以在浏览器中打开./target/debug/coverage/index.html
来查看覆盖率。
依赖关系
~0–0.9MB
~21K SLoC