| Crates.io | redis-derive |
| lib.rs | redis-derive |
| version | 0.2.0 |
| created_at | 2022-02-28 10:16:09.6909+00 |
| updated_at | 2025-10-02 06:39:14.138487+00 |
| description | This crate implements the redis::FromRedisValue and redis::ToRedisArgs traits from mitsuhiko / redis-rs for any struct |
| homepage | |
| repository | https://github.com/kkharji/redis-derive |
| max_upload_size | |
| id | 540791 |
| size | 78,273 |
This crate implements the FromRedisValue(redis::FromRedisValue) and ToRedisArgs(redis::ToRedisArgs) traits
from redis-rs(https://github.com/redis-rs/redis-rs) for any struct or enum.
This allows seamless type conversion between Rust structs and Redis hash sets, which is more beneficial than JSON encoding the struct and storing the result in a Redis key because when saving as a Redis hash set, sorting algorithms can be performed without having to move data out of the database.
There is also the benefit of being able to retrieve just one value of the struct in the database.
Initial development was done by @Michaelvanstraten 🙏🏽.
Add this to your Cargo.toml:
[dependencies]
redis-derive = "0.2.0"
redis = "0.32"
Import the procedural macros:
use redis_derive::{FromRedisValue, ToRedisArgs};
use redis::Commands;
use redis_derive::{FromRedisValue, ToRedisArgs};
#[derive(ToRedisArgs, FromRedisValue, Debug)]
struct User {
id: u64,
username: String,
email: Option<String>,
active: bool,
}
fn main() -> redis::RedisResult<()> {
let client = redis::Client::open("redis://127.0.0.1/")?;
let mut con = client.get_connection()?;
let user = User {
id: 12345,
username: "john_doe".to_string(),
email: Some("john@example.com".to_string()),
active: true,
};
// Store individual fields
con.hset("user:12345", "id", user.id)?;
con.hset("user:12345", "username", &user.username)?;
con.hset("user:12345", "email", &user.email)?;
con.hset("user:12345", "active", user.active)?;
// Retrieve the complete struct
let retrieved_user: User = con.hgetall("user:12345")?;
println!("Retrieved: {:?}", retrieved_user);
Ok(())
}
#[derive(ToRedisArgs, FromRedisValue, Debug, PartialEq)]
#[redis(rename_all = "snake_case")]
enum UserRole {
Administrator, // stored as "administrator"
PowerUser, // stored as "power_user"
RegularUser, // stored as "regular_user"
GuestUser, // stored as "guest_user"
}
// Works seamlessly with Redis
let role = UserRole::PowerUser;
con.set("user:role", &role)?;
let retrieved: UserRole = con.get("user:role")?;
assert_eq!(role, retrieved);
The rename_all attribute supports multiple case conversion rules:
#[derive(ToRedisArgs, FromRedisValue)]
#[redis(rename_all = "snake_case")]
enum Status {
InProgress, // → "in_progress"
WaitingForReview, // → "waiting_for_review"
Completed, // → "completed"
}
#[derive(ToRedisArgs, FromRedisValue)]
#[redis(rename_all = "kebab-case")]
enum Priority {
HighPriority, // → "high-priority"
MediumPriority, // → "medium-priority"
LowPriority, // → "low-priority"
}
Supported case conversion rules:
"lowercase": MyField → myfield"UPPERCASE": MyField → MYFIELD"PascalCase": my_field → MyField"camelCase": my_field → myField"snake_case": MyField → my_field"kebab-case": MyField → my-fieldKey insight: The case conversion applies to both serialization and deserialization:
// With rename_all = "snake_case"
let role = UserRole::PowerUser;
// Serialization: PowerUser → "power_user"
con.set("key", &role)?;
// Deserialization: "power_user" → PowerUser
let retrieved: UserRole = con.get("key")?;
// Error messages also use converted names:
// "Unknown variant 'admin' for UserRole. Valid variants: [administrator, power_user, regular_user, guest_user]"
This crate handles multiple Redis value types automatically:
#[derive(ToRedisArgs, FromRedisValue)]
struct SessionData {
user_id: u64,
#[redis(expire = "1800")] // 30 minutes
access_token: String,
#[redis(expire = "7200")] // 2 hours
refresh_token: String,
}
#[derive(ToRedisArgs, FromRedisValue)]
#[redis(cluster_key = "user_id")]
struct UserProfile {
user_id: u64,
profile_data: String,
}
#[derive(ToRedisArgs, FromRedisValue)]
#[redis(cache = true, ttl = "600")]
struct CachedData {
id: u64,
data: String,
}
The crate includes comprehensive examples in the examples/ directory:
# Start Redis with Docker
cd examples && docker-compose up -d
# Run basic example
cargo run --example main
# Test all enum deserialization branches
cargo run --example enum_branches
# Debug attribute parsing behavior
cargo run --example debug_attributes
num_of_args() instead of deprecated num_args())License: MIT OR Apache-2.0
License: MIT OR Apache-2.0