easy-sqlx 0.1.7

The Rust Toolkit to easy use sqlx
Documentation

easy-sqlx

介绍

根据结构体定义同步生成数据库表结构,简化增删改操作和大部分的单表查询操作,省去大部分手写 sql 语句和 bind 参数操作。

当前仅支持 postgres 数据库。

目标是帮助大部分 sql 功能开发节省心思,而不是覆盖全部的 sql 功能。

要求

1 sqlx 版本 >= 0.8
2 如果依据 struct 定义生成同步数据库表结构,请尽量不要使用 query 宏,以免造成不必要的困扰

安装

在 Cargo.toml 中添加依赖

[dependencies]
# easy-sqlx-core = { git = "https://gitee.com/knowgo/easy-sqlx.git", features = ["postgres"] }
# easy-sqlx = { git = "https://gitee.com/knowgo/easy-sqlx.git" }

tokio = { version = "1", features = ["full"] }
easy-sqlx-core = { features = ["postgres"], version = "^0" }
easy-sqlx = { version = "^0.8" }
sqlx = { version = "^0", features = [
    "runtime-async-std",
    "tls-native-tls",
    "postgres",
    "macros",
    "chrono",
] }
tracing = { version = "0.1.40" }
tracing-subscriber = { version = "0.3.18" } # , features = ["env-filter"] }

chrono = { version = "0.4", features = ["serde"] }

使用说明

同步表结构

定义表结构 #[derive(Table)]

use easy_sqlx::WhereAppend; // 引用 WhereAppend

#[derive(Table, FromRow, Debug)]
#[table(
    indexes [
        (name = "name_index_1", columns("name"))
    ]
)]
#[index(columns("name"))]
struct User {
    #[col(column = "key", comment = "123")]
    #[col(pk)]
    pub id: i64,
    #[col(comment = "姓名", len = 20)]
    pub name: Option<String>,
    pub blob: Option<Vec<u8>>,
    #[col()]
    pub create_time: Option<chrono::NaiveTime>,
}

不同步表结构的话,只需要使用 Table 和 col(pk) 即可,可空字段必须为 Option<data_type>

同步表结构,参数 connection 为数据库连接

sync_tables(connection, vec![User::table()]).await?;
添加 1 全量添加
let user = User {
    id: 1,
    name: Some("test".to_string()),
    ..Default::default()
};
user.insert().execute(&mut conn).await.unwrap();
添加 2 只添加部分字段,其它字段为 null,如果没有为必填字段 set 值,大概率会出错
User::build_insert()
    .set(User::id(2)) // 设置字段值,未设置的为 null
    .execute(&mut conn)
    .await
    .unwrap();
修改 1 根据主键全量修改,如果可空字段的值为 None 则会更新对应的表中的字段值为 null
let user = User {
    id: 1,
    name: Some("test---1".to_string()),
    ..Default::default()
};
user.update().execute(&mut conn).await.unwrap();
修改 2 根据条件修改
User::build_update()
        .set(User::name("007".to_string()))
        .and(User::id_eq(2))
        .execute(&mut conn)
        .await
        .unwrap();
修改 3 根据主键修改
User::update_by_id(2)
        .set(User::name("by_id"))
        .execute(&mut conn)
        .await
        .unwrap();
关于添加和修改的 set 函数
删除 1 根据主键 删除
let user = User {
    id: 1, // 主键值为 1
    name: Some("test---1".to_string()),
    ..Default::default()
};

user.delete().execute(&mut conn).await.unwrap();
删除 2 根据主键 删除
User::delete_by_id(2).execute(&mut conn).await.unwrap();
删除 3 根据条件 删除
User::build_delete()
        .and(User::id_eq(2)) // 删除 id 为 2 的记录
        .execute(&mut conn).await.unwrap();
对于增删改的说明

增删改调用的 execute 函数,有对应 execute_return 函数, 此函数可以返回该条语句插入、修改、或删除的记录

查询 1 根据主键查询
let u: User = User::select_by_id(1) // 联合主键会有多个参数
.one(&mut conn).await.unwrap();
println!("{:?}", u);
查询 2 根据条件查询
User::select() // 生成 SelectBuilder
    .and(User::id_eq(1)) // 查询条件 id = 1
    .one(&mut conn).await.unwrap();
查询 3 返回 HashMap
let umap: HashMap<i64, User> = User::select()
        .map_all(&mut conn, |o: &User| o.id)
        .await
        .unwrap();
println!("{:?}", umap);
查询 4 查询最大值和最小值
let max: Option<i64> = User::select()
        .optional_scalar(&mut conn, &User::col_id().max())
        .await
        .unwrap();
println!("max: {}", min.unwrap());
let min: Option<i64> = User::select()
        .optional_scalar(&mut conn, &User::col_id().min())
        .await
        .unwrap();
println!("min: {}", min.unwrap());
分页查询
let wh = Where::new(User::id_gt(0)); // id > 0
let mut page_result: PageResult<User> = User::select()
    .and(wh.clone())
    .order_by(User::id_asc()) // id 升序
    .page(&mut conn, &PageRequest::new(10, 1))
    .await
    .unwrap();
// 统计分页信息
page_result.set_total( User::select().and(wh).count(&mut conn).await.unwrap());
关于查询条件及返回
查询必要字段, UserSummary 不要同步表结构,即不需要在 sync_tables 函数的参数中出现 ,其 query_only 属性限制生成代码量
#[derive(Table, Default, Debug, Clone, FromRow)]
#[table(name = "User", query_only)] // name 属性指定表名称, query_only 表示只生成查询相关代码
pub struct UserSummary {
    #[col(pk)]
    pub id: i64,
    pub name: String,
}

let u: UserSummary = UserSummary::select_by_id(1)
    .one(&mut conn).await.unwrap();
println!("{:?}", u);
打印 sql 日志

修改 Cargo.toml

easy-sqlx-core = { features = ["postgres", "logsql"], version = "^0" }

程序启动时,订阅日志

let layer = tracing_subscriber::fmt::layer()
        .with_file(true)
        .with_line_number(true)
        .with_filter(tracing_subscriber::filter::LevelFilter::INFO);
Registry::default().with(layer).init();