#macro-derive #redis #json #macro #derive

redis-macros

为redis-rs提供简单的宏和包装器,以自动使用serde对结构体进行序列化和反序列化。

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 编码

Download history 3249/week @ 2024-05-02 4728/week @ 2024-05-09 3869/week @ 2024-05-16 3600/week @ 2024-05-23 4428/week @ 2024-05-30 6275/week @ 2024-06-06 7997/week @ 2024-06-13 7793/week @ 2024-06-20 10130/week @ 2024-06-27 11944/week @ 2024-07-04 8079/week @ 2024-07-11 8081/week @ 2024-07-18 6484/week @ 2024-07-25 4995/week @ 2024-08-01 5221/week @ 2024-08-08 3808/week @ 2024-08-15

22,829 每月下载量
2 crates 中使用

MIT 许可证

23KB
61 代码行

redis-macros

redis-rs提供简单的宏和包装器,以自动使用serde对结构体进行序列化和反序列化。

安装

要安装它,只需添加包redis-macros。此包是redis的辅助工具,使用serdeserde_json(或任何其他序列化器),因此也将这些添加到依赖项中。

[dependencies]
redis-macros = "0.3.0"
redis = { version = "0.25.2" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }

基本用法

简单用法

最简单的方法是为任何类型的结构体派生SerializeDeserializeFromRedisValueToRedisArgs...然后就可以了!现在您可以使用常规的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,甚至可以去掉派生FromRedisValueToRedisArgs,并使用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 WrapperJson Wrapper 高级示例。

使用其他序列化程序(例如 serde-yaml)

如果您想使用其他序列化程序,例如serde_yaml,您可以安装它并使用derives,方法与之前相同。唯一的区别应该是在derives下添加一个属性redis_serializer,用于您想要序列化的库。只要它们支持from_strto_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-previewgrcov

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