#redis #stream #key #derive #macro-derive #model #hash

redis-om

Redis ORM风格的库,简化开发过程并减少构建利用[redis]强大功能和用例的程序所需的样板代码数量。

1个不稳定版本

0.1.0 2023年4月3日

#1430 in Rust模式

MIT许可协议

55KB
1K SLoC

redis-om

MIT licensed Build status Crates.io

一个Rust/Redis ORM风格的库,简化开发过程并减少构建利用redis强大功能和用例的程序所需的样板代码数量。

状态进行中,已完全测试,可能存在破坏性更改,请保持关注

功能

  • ORM风格的API用于定义/操作使用derive宏的Redis数据结构(例如,散列、JSON、流)。
  • Redis数据和Rust对象之间的自动序列化和反序列化。
  • serde兼容性,例如使用renamerename_allserde
  • 支持嵌套散列数据类型(例如,list.1或嵌套模型account.balance作为键)。

用法

路线图

  • 0.1.0
    • 允许用户使用最常见的方法定义和派生散列模型。
    • 允许用户使用最常见的方法定义和派生JSON模型。
    • 允许用户使用管理器定义和派生流,以向它们发布/从中读取。
    • 支持用户选择异步和同步运行时。
  • 0.2.0
    • 允许多流管理器支持,使用户能够组合多个RedisModels
    • 支持使用serde序列化和反序列化HashModel复杂字段。
    • 支持RedisSearch并提供查询构建API。
    • .....
  • 0.3.0
    • 支持结构体字段和枚举值的验证(可能使用validator库)。
    • .....

入门指南

redis-om = { version = "*" }
# TLS support with async-std
redis-om = { version = "*", features = ["tls"] }
# async support with tokio
redis-om = { version = "*", features = ["tokio-comp"] }
# async support with async-std
redis-om = { version = "*", features = ["async-std-comp"] }
# TLS and async support with tokio
redis-om = { version = "*", features = ["tokio-native-tls-comp"] }
# TLS support with async-std
redis-om = { version = "*", features = ["async-std-tls-comp"] }

散列

use redis_om::HashModel;

#[derive(HashModel, Debug, PartialEq, Eq)]
struct Customer {
    id: String,
    first_name: String,
    last_name: String,
    email: String,
    bio: Option<String>,
    interests: Vec<String>
}

// Now that we have a `Customer` model, let's use it to save customer data to Redis.

// First, we create a new `Customer` object:
let mut jane = Customer {
    id: "".into(), // will be auto generated when it's empty
    first_name: "Jane".into(),
    last_name: "Doe".into(),
    email: "[email protected]".into(),
    bio: Some("Open Source Rust developer".into()),
    interests: vec!["Books".to_string()],
};

// Get client
let client = redis_om::Client::open("redis://127.0.0.1/").unwrap();
// Get connection
let mut conn = client.get_connection().unwrap();

// We can save the model to Redis by calling `save()`:
jane.save(&mut conn).unwrap();

// Expire the model after 1 min (60 seconds)
jane.expire(60, &mut conn).unwrap();

// Retrieve this customer with its primary key
let jane_db = Customer::get(&jane.id, &mut conn).unwrap();

// Delete customer
Customer::delete(&jane.id, &mut conn).unwrap();

assert_eq!(jane_db, jane);

JSON

redis-om 通过 redis_om::JsonModel 支持 JSON 数据类型。它要求类型继承 serde::Deserialize 以及 serde::Serialize

use redis_om::JsonModel;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
struct AccountDetails {
    balance: String,
}

#[derive(JsonModel, Deserialize, Serialize, Debug, PartialEq, Eq)]
struct Account {
    id: String,
    first_name: String,
    last_name: String,
    details: AccountDetails,
}

// Now that we have a `Account` model, let's use it to save account data to Redis.

// First, we create a new `Account` object:
let mut john = Account {
    id: "".into(), // will be auto generated when it's empty
    first_name: "John".into(),
    last_name: "Doe".into(),
    details: AccountDetails {
        balance: "1.5m".into(),
    }
};

// Get client
let client = redis_om::Client::open("redis://127.0.0.1/").unwrap();
// Get connection
let mut conn = client.get_connection().unwrap();

// We can save the model to Redis by calling `save()`:
john.save(&mut conn).unwrap();

// Expire the model after 1 min (60 seconds)
john.expire(60, &mut conn).unwrap();

// Retrieve this account with its primary key
let john_db = Account::get(&john.id, &mut conn).unwrap();

// Delete customer
Account::delete(&john.id, &mut conn).unwrap();

assert_eq!(john_db, john);

redis-om 通过 redis_om::StreamModel 支持 JSON 数据类型。它要求任何嵌套类型都继承 redis_om::RedisTransportValue

use redis_om::{RedisTransportValue, StreamModel};

/// An enum of room service kind
#[derive(RedisTransportValue)]
pub enum RoomServiceJob {
    Clean,
    ExtraTowels,
    ExtraPillows,
    FoodOrder,
}

/// An enum of room service kind
#[derive(StreamModel)]
#[redis(key = "room")] // rename stream key in redis
pub struct RoomServiceEvent {
    status: String,
    room: usize,
    job: RoomServiceJob,
}

// Get client
let client = redis_om::Client::open("redis://127.0.0.1/").unwrap();
// Get connection
let mut conn = client.get_connection().unwrap();

// Create a new instance of Room service Event Manager with consumer group.
// Note: consumer name is auto generated,
// use RoomServiceEventManager::new_with_consumer_name, // for a custom name
let manager = RoomServiceEventManager::new("Staff");

// Ensure the consumer group
manager.ensure_group_stream(&mut conn).unwrap();

// Create new event
let event = RoomServiceEvent {
    status: "pending".into(),
    room: 3,
    job: RoomServiceJob::Clean,
};

// Publish the event to the RoomServiceEvent redis stream
RoomServiceEventManager::publish(&event, &mut conn).unwrap();

// Read with optional read_count: Option<usize>, block_interval: Option<usize>
let read = manager.read(None, None, &mut conn).unwrap();

// Get first incoming event
let incoming_event = read.first().unwrap();
// Get first incoming event data
let incoming_event_data = incoming_event.data::<RoomServiceEvent>().unwrap();
// Acknowledge that you received the event, so other in the consumers don't get it
RoomServiceEventManager::ack(manager.group_name(), &[&incoming_event.id], &mut conn).unwrap();

assert_eq!(incoming_event_data.room, event.room);

依赖

~4–17MB
~246K SLoC