Skip to content

meuter/miniorm-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

miniorm

Build Test Clippy Doc

Crates.io Docs.rs Crates.io Crates.io

Introduction

The miniorm crate provides a very simple ORM on top of sqlx.

sqlx already provides a FromRow trait that can be derived automatically in order to convert a row from the database into an object. However, there is no corresponding macro that would allow convert an object back into a row to be inserted into the database.

This is where miniorm comes in. It provides multiple traits that can also be automatically derived. Using these traits, miniorm provides a Store type that builds on top and all the standard "CRUD" operations:

  • (C)reate
  • (R)ead
  • (U)pdate
  • (D)elete

At the moment, miniorm supports the three most common database backend:

  • Sqlite
  • MySql
  • Postgres

Each backend should be enabled using the corresponding feature flag.

Example

use sqlx::FromRow;
use miniorm::prelude::*;

#[derive(Debug, Clone, Eq, PartialEq, FromRow, Entity)]
struct Todo {
    #[column(TEXT NOT NULL)]
    description: String,

    #[column(BOOLEAN NOT NULL DEFAULT false)]
    done: bool,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = sqlx::SqlitePool::connect(":memory:").await?;
    let store = miniorm::Store::new(db);

    let todo = Todo {
        description: "checkout miniorm".into(),
        done: false,
    };

    store.recreate_table().await?;

    println!("Inserting...");
    let todo = store.create(todo).await?;

    println!("Retrieveing by id...");
    let mut fetched = store.read(todo.id()).await?;
    assert_eq!(todo, fetched);

    println!("Updating by id...");
    fetched.done = true;
    let after_update = store.update(fetched).await?;
    assert_eq!(after_update.id(), todo.id());

    println!("Listing all...");
    let all = store.list().await?;
    assert_eq!(all.len(), 1);
    assert_eq!(&after_update, &all[0]);

    println!("Deleting by id...");
    store.delete(todo.id()).await?;

    println!("Checking delete successful");
    assert!(matches!(
        store.read(todo.id()).await,
        Err(sqlx::Error::RowNotFound)
    ));

    Ok(())
}
This example requires the sqlite and

But wait, there's more!

One can turn a Store into an Router that can be installed to serve these CRUD operations over a REST api. For this your entity type should implement Serialize and Deserialize from serde

This requires the axum feature flag.

use axum::Router;
use miniorm::prelude::*;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool};
use std::net::SocketAddr;
use tokio::net::TcpListener;

#[derive(Debug, Clone, Eq, PartialEq, FromRow, Entity, Serialize, Deserialize)]
struct Todo {
    #[column(TEXT NOT NULL)]
    description: String,

    #[column(BOOLEAN NOT NULL DEFAULT false)]
    done: bool,
}

impl Todo {
    pub fn new(description: impl AsRef<str>) -> Self {
        let description = description.as_ref().to_string();
        let done = false;
        Todo { description, done }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // connect to db 
    let db = sqlx::SqlitePool::connect(":memory:").await?;

    // initialize todo store
    let todos = Store::new(db);
    todos.recreate_table().await?;
    todos.create(Todo::new("do the laundry")).await?;
    todos.create(Todo::new("wash the dishes")).await?;
    todos.create(Todo::new("go walk the dog")).await?;
    todos.create(Todo::new("groceries")).await?;

    // create the app
    let app = Router::new().nest("/todos", todos.into_axum_router());
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    println!("listening on http://{}", addr);

    // serve the app
    let listener = TcpListener::bind(&addr).await.unwrap();
    axum::serve(listener, app).await?;

    Ok(())
}
This example requires the sqlite and axum feature flags.

About

a *very* simple ORM built on top of sqlx.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages