DynamoDB library for single-table design in Rust

Overview

A DynamoDB abstraction for Rust

Crates.io

Deez is a DynamoDB abstraction for implementing Single Table Design easily, inspired by ElectroDB.

Getting Started

Define a schema for your entities using the Deez procedural macro. Doing so will derive the From conversion traits for your structs and the HashMap<String, AttributeValue> type used by the aws_sdk_dynamodb library, with some additional features for facilitating Single Table Design.

use aws_sdk_dynamodb::types::AttributeValue;
use deez::*;
use std::collections::HashMap;
use uuid::Uuid;

#[derive(Debug, Clone, Deez)]
#[deez_schema(table = "TaskTable", service = "TaskService", entity = "Task")]
#[deez_schema(primary_hash = "pk", primary_range = "sk")]
#[deez_schema(gsi1_name = "gsi1", gsi1_hash = "gsi1pk", gsi1_range = "gsi1sk")]
#[deez_schema(gsi2_name = "gsi2", gsi2_hash = "gsi2pk", gsi2_range = "gsi2sk")]
pub struct Task {
    #[deez_primary(key = "hash")]
    #[deez_gsi1(key = "range", position = 1)]
    #[deez_gsi2(key = "range", position = 1)]
    pub task_id: Option<String>,
    #[deez_primary(key = "range", position = 1)]
    #[deez_gsi1(key = "hash")]
    #[deez_gsi2(key = "range")]
    pub project: Option<String>,
    #[deez_primary(key = "range")]
    #[deez_gsi1(key = "range")]
    #[deez_gsi2(key = "hash")]
    pub employee: Option<String>,
    pub description: String,
    #[deez_ignore(ignore)]
    pub some_metadata: String,
}

impl Default for Task {
    fn default() -> Self {
        Task {
            task_id: Some(Uuid::new_v4().to_string()),
            project: Some("".to_string()),
            employee: Some("".to_string()),
            description: "".to_string(),
            some_metadata: "".to_string(),
        }
    }
}

Now you can convert your struct to a HashMap that you can pass directly to the DynamoDB client.

let task = Task {
    project: Some("foo_project".to_string()),
    employee: Some("e42069".to_string()),
    description: "nothin' but chillin' 20's".to_string(),
    some_metadata: "baz".to_string(),
    ..Default::default()
};

let map: HashMap<String, AttributeValue> = task.into();
println!("{:#?}", map);

// keys are generated based on schema!
// output:
// {
//     "pk": S("$TaskService#Task#task_id_1885ea1d-e296-4c0f-9fbf-863b1318c698"), <-
//     "sk": S("$Task#employee_e42069#project_foo_project"), <-
//     "gsi1pk": S("$TaskService#Task#project_foo_project"), <-
//     "gsi1sk": S("$Task#employee_e42069#task_id_1885ea1d-e296-4c0f-9fbf-863b1318c698"), <-
//     "gsi2pk": S("$TaskService#Task#employee_e42069"), <-
//     "gsi2sk": S("$Task#project_foo_project#task_id_1885ea1d-e296-4c0f-9fbf-863b1318c698"), <-
//     "task_id": S("1885ea1d-e296-4c0f-9fbf-863b1318c698"),
//     "project": S("foo_project"),
//     "employee": S("e42069"),
//     "description": S("nothin' but chillin' 20's"),
// }

The following example shows a practical use-case interacting with DynamoDB client:

use anyhow::Result;
use aws_sdk_dynamodb::Client;

#[tokio::main]
async fn main() -> Result<()> {
    // local configuration
    let client = Client::new(
        &aws_config::from_env()
            .endpoint_url("http://localhost:8000")
            .region("us-east-1")
            .load()
            .await,
    );

    // `create` convenience macro utilizes the `attribute_not_exists()` parameter
    // to ensure records are only “created” and not overwritten when inserting
    // new records into the table.
    create!(
        client;
        Task {
            project: Some("foo_project".to_string()),
            employee: Some("e42069".to_string()),
            description: "nothin' but chillin' 20's".to_string(),
            some_metadata: "baz".to_string(),
            ..Default::default()
        }
    )?;

    let keys = Task {
        task_id: Some("1a2b3c4d".to_string()),
        project: Some("foo_project".to_string()),
        employee: Some("e42069".to_string()),
        ..Default::default()
    }
    .primary_keys();

    // `vec_from_query` macro handles the process of converting the response
    // back to `Vec<Task>`.
    let tasks = vec_from_query!(
        client
            .query()
            .table_name(Task::table_name())
            .key_condition_expression("#pk = :pk and begins_with(#sk, :sk)")
            .set_expression_attribute_names(Some(HashMap::from([
                ("#pk".to_string(), keys.hash.field()),
                ("#sk".to_string(), keys.range.field()),
            ])))
            .set_expression_attribute_values(Some(HashMap::from([
                (":pk".to_string(), keys.hash.av()),
                (":sk".to_string(), keys.range.av()),
            ])))
            .send()
            .await?

        => TaskItems
    );

    // do something with `tasks`...

    Ok(())
}
You might also like...
A Rust library for calculating sun positions

sun A rust port of the JS library suncalc. Install Add the following to your Cargo.toml [dependencies] sun = "0.2" Usage pub fn main() { let unixti

A cross-platform serial port library in Rust.

Introduction serialport-rs is a general-purpose cross-platform serial port library for Rust. It provides a blocking I/O interface and port enumeration

A high level diffing library for rust based on diffs
A high level diffing library for rust based on diffs

Similar: A Diffing Library Similar is a dependency free crate for Rust that implements different diffing algorithms and high level interfaces for it.

A reactive DOM library for Rust in WASM

maple A VDOM-less web library with fine-grained reactivity. Getting started The recommended build tool is Trunk. Start by adding maple-core to your Ca

transmute-free Rust library to work with the Arrow format

Arrow2: Transmute-free Arrow This repository contains a Rust library to work with the Arrow format. It is a re-write of the official Arrow crate using

Cross-platform Window library in Rust for Tauri. [WIP]

Cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android. Built for you, maintained for Tauri.

A library in Rust for theorem proving with Intuitionistic Propositional Logic.

Prop Propositional logic with types in Rust. A library in Rust for theorem proving with Intuitionistic Propositional Logic. Supports theorem proving i

A Rust library for constructing tilings of regular polygons
A Rust library for constructing tilings of regular polygons

tiling tiling is a library for constructing tilings of regular polygons and their dual tilings. Resources Documentation Tilings by regular polygons Li

miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!
miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!

miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!

Releases(v0.3.0)
Owner
level over 9000 h4x0r
null
Serverless setup for activity pub (using lambda+dynamodb) in Rust

Serverless ActivityPub About This is an experiment to have free/cheaper activitypub instances running on AWS (making use of free tiers as much as poss

Conrad Ludgate 3 Dec 30, 2022
A lambda extension to hot reload parameters from SSM Parameter Store, Secrets Manager, DynamoDB, AppConfig

A lambda extension to hot reload parameters from SSM Parameter Store, Secrets Manager, DynamoDB, AppConfig

Jake Scott 7 Jun 12, 2022
A simple string interner / symbol table for Rust projects.

Symbol Interner A small Rust crate that provides a naïve string interner. Consult the documentation to learn about the types that are exposed. Install

Ryan Chandler 1 Nov 18, 2021
Rust libraries for working with GPT (GUID Partition Table) disk data

gpt-disk-rs no_std libraries related to GPT (GUID Partition Table) disk data. There are three Rust packages in this repository: uguid The uguid packag

Google 25 Dec 24, 2022
Byte is a blazingly fast🚀 Discord Bot with a user-friendly design using twilight written in rust🦀.

Byte Byte is a blazingly fast?? Discord Bot with a user-friendly design using twilight written in rust??. How To Run There is a public version of the

TakoTheDev 3 Nov 15, 2023
Rust library to scan files and expand multi-file crates source code as a single tree

syn-file-expand This library allows you to load full source code of multi-file crates into a single syn::File. Features: Based on syn crate. Handling

Vitaly Shukela 11 Jul 27, 2022
single file, std only, async Rust executor

whorl - A single file, std only, async Rust executor whorl was created to teach you how async executors work in Rust. It is not the fastest executor n

Michael Gattozzi 459 Dec 29, 2022
A self-contained, single-binary Rust and Leptos application for remote Wake-on-LAN

Remote Wake-on-LAN with Rust and Leptos A self-contained, single-binary Rust and Leptos application serving a web interface to wake another device on

Valentin Bersier 6 Jan 28, 2023
A tool that transforms an IMVU badge canvas into a single cohesive image.

IMVU Badge Canvas Image Generator This tool fetches an IMVU user's badge canvas and creates a single unified image representation of it. Instead of ha

Helba 3 Sep 20, 2023
A library to compile USDT probes into a Rust library

sonde sonde is a library to compile USDT probes into a Rust library, and to generate a friendly Rust idiomatic API around it. Userland Statically Defi

Ivan Enderlin 40 Jan 7, 2023