Macros for redis-rs to serialize and deserialize structs automatically

Overview

redis-macros

Simple macros and wrappers to redis-rs to automatically serialize and deserialize structs with serde.

Installation

To install it, simply add the package redis-macros. This package is a helper for redis and uses serde and serde_json (or any other serializer), so add these too to the dependencies.

[dependencies]
redis-macros = "0.1.0"
redis = { version = "0.22.2" }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.91" }

Basic usage

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:

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://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")?;
}

For more information, see the Basic or Async examples.

Usage with RedisJSON

You can even use it with RedisJSON, to extract separate parts of the object.

// 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]")?;

For more information, see the RedisJSON example.

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.

// This WON'T work
let stored_addresses: Vec<Address> = con.json_get("user", "$.addresses")?;

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:

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

If you only use RedisJSON, you can even do away with deriving FromRedisValue and ToRedisArgs, and use Json everywhere.

#[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", "$")?;

For more information, see the Json Wrapper and Json Wrapper Advanced examples.

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.

#[derive(Debug, PartialEq, Serialize, Deserialize, FromRedisValue, ToRedisArgs)]
#[redis_serializer(serde_yaml)]
struct User { /* ... */ }

For more information, see the YAML example.

Testing

You can run the unit tests on the code with cargo test:

cargo test

For integration testing, you can run the examples. You will need a RedisJSON compatible redis-server on port 6379, redis-stack docker image is recommended:

docker run -d --rm -p 6379:6379 --name redis docker.io/redis/redis-stack
cargo test --examples
# cleanup the container
docker stop redis

Coverage

For coverage, you can use grcov. Simply install llvm-tools-preview and grcov if you don't have it already:

rustup component add llvm-tools-preview
cargo install grcov

You have to export a few flags to make it work properly:

export RUSTFLAGS='-Cinstrument-coverage'
export LLVM_PROFILE_FILE='.coverage/cargo-test-%p-%m.profraw'

And finally, run the tests and generate the output:

cargo test
cargo test --examples
grcov .coverage/ -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./target/debug/coverage/

Now you can open ./target/debug/coverage/index.html, and view it in the browser to see the coverage.

You might also like...
A rust Key-Value store based on Redis.

Key-Value Store A Key-Value store that uses Redis to store data. Built using an async web framework in Rust with a full Command-Line interface and log

[POC] Redis Module for TiKV

RedisTikvPoc [POC] Redis Module for TiKV This is a POC repository. This Redis Module will add branch new Redis commands to operate TiKV data. After bu

Basic Redis Protocol specification in Rust

Basic Redis Protocol specification in Rust

Redis compatible server framework for Rust
Redis compatible server framework for Rust

Redis compatible server framework for Rust Features Create a fast custom Redis compatible server in Rust Simple API. Support for pipelining and telnet

A port of `java.util.*SummaryStatistics` as a Redis Module

RedisNumbersStats RedisNumbersStats is a Redis module that implements a Redis version of the Java Util *SummaryStatistics classes, such as DoubleSumma

A simplified version of a Redis server supporting SET/GET commands

This is a starting point for Rust solutions to the "Build Your Own Redis" Challenge. In this challenge, you'll build a toy Redis clone that's capable

An intentionally-limited Rust implementation of the Redis server with no external dependencies.

lil-redis An intentionally-limited Rust implementation of the Redis server. lil redis is an accessible implementation of a very basic Redis server (wi

A cross-platform redis gui client

Redis-Manager A cross-platform redis gui client started developing with Tauri, React and Typescript in Vite. Get Started Prerequisites Install Node.js

📺 Netflix in Rust/ React-TS/ NextJS, Actix-Web, Async Apollo-GraphQl, Cassandra/ ScyllaDB, Async SQLx, Kafka, Redis, Tokio, Actix, Elasticsearch, Influxdb Iox, Tensorflow, AWS
📺 Netflix in Rust/ React-TS/ NextJS, Actix-Web, Async Apollo-GraphQl, Cassandra/ ScyllaDB, Async SQLx, Kafka, Redis, Tokio, Actix, Elasticsearch, Influxdb Iox, Tensorflow, AWS

Fullstack Movie Streaming Platform 📺 Netflix in RUST/ NextJS, Actix-Web, Async Apollo-GraphQl, Cassandra/ ScyllaDB, Async SQLx, Spark, Kafka, Redis,

Owner
Daniel Grant
Daniel Grant
Automatically publish MongoDB changes to Redis for Meteor.

changestream-to-redis Warning The project is currently in its alpha phase. There are no production loads using it yet nor any large-scale tests were c

Radosław Miernik 8 Jul 29, 2023
General basic key-value structs for Key-Value based storages

General basic key-value structs for Key-Value based storages

Al Liu 0 Dec 3, 2022
RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

RedisLess is a fast, lightweight, embedded and scalable in-memory Key/Value store library compatible with the Redis API.

Qovery 145 Nov 23, 2022
Incomplete Redis client and server implementation using Tokio - for learning purposes only

mini-redis mini-redis is an incomplete, idiomatic implementation of a Redis client and server built with Tokio. The intent of this project is to provi

Tokio 2.3k Jan 4, 2023
Rewrite Redis in Rust for evaluation and learning.

Drill-Redis This library has been created for the purpose of evaluating Rust functionality and performance. As such, it has not been fully tested. The

Akira Kawahara 3 Oct 18, 2022
Lightweight async Redis client with connection pooling written in pure Rust and 100% memory safe

redi-rs (or redirs) redi-rs is a Lightweight Redis client with connection pooling written in Rust and 100% memory safe redi-rs is a Redis client writt

Oğuz Türkay 4 May 20, 2023
Simple and flexible queue implementation for Rust with support for multiple backends (Redis, RabbitMQ, SQS, etc.)

Omniqueue Omniqueue is an abstraction layer over queue backends for Rust. It includes support for RabbitMQ, Redis streams, and SQS out of the box. The

Svix 8 May 26, 2023
Redis re-implemented in Rust.

rsedis Redis re-implemented in Rust. Why? To learn Rust. Use Cases rsedis does not rely on UNIX-specific features. Windows users can run it as a repla

Sebastian Waisbrot 1.6k Jan 6, 2023
Redis library for rust

redis-rs Redis-rs is a high level redis library for Rust. It provides convenient access to all Redis functionality through a very flexible but low-lev

Armin Ronacher 2.8k Jan 8, 2023
RedisJSON - a JSON data type for Redis

RedisJSON RedisJSON is a Redis module that implements ECMA-404 The JSON Data Interchange Standard as a native data type. It allows storing, updating a

null 3.4k Jan 1, 2023