#sqlx #orm #top #miniorm #macro #built #automatic

miniorm-macros

基于sqlx构建的非常简单的ORM

4个版本 (破坏性更新)

0.4.0 2024年4月7日
0.3.0 2024年3月15日
0.2.0 2024年3月15日
0.1.0 2024年3月15日

#1783 in 过程宏


3个crate中使用(通过miniorm

MIT许可

19KB
248

miniorm

Build Test Clippy Doc

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

简介

miniorm crate提供在ORM之上非常简单的接口。

sqlx已经提供了FromRow trait,可以自动从数据库行转换到对象。然而,没有相应的宏可以将对象转换回行以插入到数据库中。

这就是miniorm的作用所在。它提供了多个可以自动派生的特质。使用这些特质,miniorm提供了一种Store类型,该类型基于标准“CRUD”操作

  • (C)创建
  • (R)读取
  • (U)更新
  • (D)删除

目前,miniorm支持三种最常见的数据库后端

  • Sqlite
  • MySql
  • Postgres

每个后端都应该使用相应的功能标志来启用。

示例

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(())
}
此示例需要sqlite

等等,还有更多!

可以将一个 Store 转换为一个 Router,该 Router 可以安装来通过 REST API 提供这些 CRUD 操作。为此,您的实体类型应该实现来自 SerializeDeserializeserde

这需要 axum 功能标志。

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(())
}
此示例需要 sqliteaxum 功能标志。

依赖项

~1–1.6MB
~33K SLoC