Rust Tiny Orm

一个基于sqlx的极简orm,本项目将sql代码以derive属性方式和结构体进行关联,并自动生成相关CRUD相关API,可根据需要实现任意复杂度的数据获取。

本项目开发主要原因:

  1. 目前rust的orm产品都太大而全了,习惯了Python Django的自动化的实现,对DSL相当不习惯,个人觉得太繁琐了;
  2. 实际orm就是api和sql的转换,因为orm的实现限制,sql的复杂查询的实现都比较别扭,为了与数据库交互还得额外学习大量orm dsl的用法,有点舍本求木了!

因此,是否可以将数据查询的sql和rust结合,由程序员自行控制sql的表现,这样在rust的高性能助力下,我们可以写成性能超级赞的数据库应用。

特性

根据你的数据库类型选择不同特性,缺省为mysql

  1. mysql
  2. postgres
  3. sqlite
  4. mssql
  5. any

添加依赖

修改Cargo.toml,增加

``` [dependencies] async-trait = "^0.1" tinyormmacro_derive="^0.2"

[dependencies.tinyormcore] version = "^0.2" features = [ "mysql", ]

```

示例代码

``` //! 数据库模型的测试 use sqlx::mysql::MySqlPoolOptions; use sqlx::Row; use tinyormcore::prelude::*;

use super::*;

[derive(Debug,PartialEq, Eq)]

pub struct UserType { /// 类型编号 pub id: Option, /// 类型名称 pub name: String, /// 中断短信模板 pub template: String, } impl UserType { /// 完整创建器 /// /// # 参数说明 /// /// * id 类型编号 /// * name 类型名称 /// * template 中断短信模板 pub fn new(id: u32, name: &str, template: &str) -> Self { UserType { id: Some(id), name: name.into(), template: template.into(), } } } /// 测试用户 /// tinyorm 会自动实现各种数据获取和更新等方法,其中: /// TestUser::ormfilterwithsql等orm开头的方法,会调用TestUser::ormrowmap进行数据转换 /// TestUser::dbfetchall_row等db开头的方法,直接返回sqlx:Row

[allow(dead_code)]

[derive(TinyOrm, TinyOrmQuery, Debug,PartialEq, Eq)]

[ormtablename_pref = "core"]

[ormtablename = "user"]

[ormselectfield = "user.*,usertype.name as usertypename, usertype.template"]

[ormselectjoin = "JOIN usertype ON usertype.id = usertypeid"]

[ormselectbyidwhere = "user.id = ? "]

[ormdeletewhere = "id = ? "]

pub struct TestUser { /// 类型编号 pub id: Option, /// 类型名称 pub name: String, /// 手机号码 pub mobilephone: String, /// 密码 password: String, /// 用户类型 pub usertype: UserType }

impl TestUser { /// 完整创建器 /// /// # 参数说明 /// /// * id 编号 /// * name 姓名 /// * mobilephone 手机 /// * password 密码 /// * usertype 用户类型 /// * org 对应机构 pub fn new( id: u32, name: &str, mobilephone: &str, password: &str, usertype: UserType, ) -> Self { Self { id: Some(id), name: name.into(), mobilephone: mobilephone.into(), password: password.into(), usertype, } } } /// 实现数据获取接口 /// tinyorm 会自动实现各种数据获取和更新等方法,其中: /// TestUser::ormfilterwithsql等orm开头的方法,会调用TestUser::ormrowmap进行数据转换 /// TestUser::dbfetchallrow等db开头的方法,直接返回sqlx:Row impl TinyOrmData for TestUser { /// 将sql返回数据映射为TestUser fn ormrowmap(row: TinyOrmSqlRow) -> Self { TestUser::new( row.get::("id"), row.get("name"), row.get("mobilephone"), row.get("password"), UserType::new( row.get::("usertypeid"), row.get("usertype_name"), row.get("template"), ) ) } }

async fn getpool() -> Result { let username = "netguard"; let password = "netguard@20220806"; let ip = "localhost"; let port = 3306; let dbname = "abcnetguard"; let pool = MySqlPoolOptions::new() .maxconnections(1) .connect(&format!( "mysql://{}:{}@{}:{}/{}", username, password, ip, port, dbname )) .await?; Ok(pool) }

/// 测试SQL生成 /// 也可以使用TestUser::DBMETA.buildselect_sql等方法生成个性化sql

[test]

fn testuser() { println!("user sql : \n{}", TestUser::DBMETA.select_sql); }

/// 测试数据获取

[test]

fn testdbquery() { tokio::runtime::Builder::newcurrentthread() .enableall() .build() .unwrap() .blockon(async { let pool = getpool().await.unwrap(); let data = TestUser::ormget_all(&pool).await.unwrap(); dbg!(data); }); }

/// 测试根据id获取用户

[test]

fn testormgetbyid() { tokio::runtime::Builder::newcurrentthread() .enableall() .build() .unwrap() .blockon(async { let pool = getpool().await.unwrap(); let user = TestUser::ormgetbyid(&pool, 1).await.unwrap(); dbg!(user); }); }

/// 测试是否存在

[test]

fn testormexists() { tokio::runtime::Builder::newcurrentthread() .enableall() .build() .unwrap() .blockon(async { let pool = getpool().await.unwrap(); let isexist = TestUser::ormexists(&pool, 1).await.unwrap(); dbg!(isexist); }); }

/// 测试删除

[test]

fn testormdelete() { tokio::runtime::Builder::newcurrentthread() .enableall() .build() .unwrap() .blockon(async { let pool = getpool().await.unwrap(); TestUser::ormdelete(&pool, 6).await.unwrap();

    });

}

/// 测试filter

[test]

fn testdbfilter() { tokio::runtime::Builder::newcurrentthread() .enableall() .build() .unwrap() .blockon(async { let pool = getpool().await.unwrap(); let sql = TestUser::DBMETA.buildselectsql("name like ? "); println!("{sql}"); let key = String::from("%黄%"); let data = TestUser::ormfilterwith_sql(&pool, &sql, &key).await.unwrap(); dbg!(data); }); } ```