| Crates.io | sqlxplus |
| lib.rs | sqlxplus |
| version | 0.2.6 |
| created_at | 2025-12-16 07:34:30.403145+00 |
| updated_at | 2026-01-06 03:41:10.72917+00 |
| description | A powerful SQL query builder and ORM for sqlx with CRUD operations |
| homepage | |
| repository | https://github.com/fangbc5/sqlx-plus |
| max_upload_size | |
| id | 1987350 |
| size | 237,448 |
在保持 SQLx 性能与 SQL 灵活性的前提下,为 Rust 项目提供一套可生产、跨 MySQL/Postgres/SQLite 的高级数据库封装(CRUD、分页、动态查询、代码生成)。
Model trait、derive(CRUD) 宏、QueryBuilder),减少样板代码[dependencies]
sqlxplus = { version = "0.2.0", features = ["mysql"] }
sqlx = { version = "0.8.6", features = ["runtime-tokio-native-tls", "chrono", "mysql"] }
tokio = { version = "1.40", features = ["full"] }
根据你使用的数据库选择对应的 feature:
features = ["mysql"]features = ["postgres"]features = ["sqlite"]features = ["mysql", "postgres", "sqlite"]use sqlxplus::{DbPool, Crud, QueryBuilder};
// 定义模型
#[derive(Debug, sqlx::FromRow, sqlxplus::ModelMeta, sqlxplus::CRUD)]
#[model(table = "users", pk = "id")]
struct User {
id: Option<i64>,
name: Option<String>,
email: Option<String>,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 连接数据库
let pool = DbPool::connect("mysql://user:pass@localhost/db").await?;
// 插入数据
let user = User {
id: None,
name: Some("张三".to_string()),
email: Some("zhangsan@example.com".to_string()),
};
let id = user.insert(&pool).await?;
println!("插入成功,ID: {}", id);
// 查找用户
let user = User::find_by_id(&pool, id).await?;
println!("查找到用户: {:?}", user);
// 更新用户
if let Some(mut user) = user {
user.name = Some("李四".to_string());
user.update(&pool).await?;
println!("更新成功");
}
// 删除用户
User::delete_by_id(&pool, id).await?;
println!("删除成功");
Ok(())
}
使用 ModelMeta 和 CRUD 宏自动生成 CRUD 操作:
#[derive(Debug, sqlx::FromRow, sqlxplus::ModelMeta, sqlxplus::CRUD)]
#[model(table = "users", pk = "id")]
struct User {
pub id: Option<i64>,
pub name: Option<String>,
pub email: Option<String>,
pub status: Option<i32>,
}
属性说明:
table: 数据库表名pk: 主键字段名(默认为 "id")soft_delete: 逻辑删除字段名(可选)支持逻辑删除(软删除),只需指定 soft_delete 字段:
#[derive(Debug, sqlx::FromRow, sqlxplus::ModelMeta, sqlxplus::CRUD)]
#[model(table = "posts", pk = "id", soft_delete = "is_deleted")]
struct Post {
pub id: Option<i64>,
pub title: Option<String>,
pub content: Option<String>,
pub is_deleted: Option<i32>, // 0=未删除,1=已删除
}
// 使用逻辑删除
Post::delete_by_id(&pool, 1).await?; // 将 is_deleted 设置为 1
// 查询时自动过滤已删除的记录
let post = Post::find_by_id(&pool, 1).await?; // 返回 None
let user = User {
id: None,
name: Some("张三".to_string()),
email: Some("zhangsan@example.com".to_string()),
status: Some(1),
};
let id = user.insert(&pool).await?;
// 根据 ID 查询单条记录
let user = User::find_by_id(&pool, 1).await?;
// 根据多个 ID 查询
let users = User::find_by_ids(&pool, vec![1, 2, 3]).await?;
// 使用查询构建器查询单条
let builder = QueryBuilder::new("").and_eq("email", "zhangsan@example.com");
let user = User::find_one(&pool, builder).await?;
// 查询所有(最多 1000 条)
let users = User::find_all(&pool, None).await?;
// Patch 语义:Option 字段为 None 时不更新
let mut user = User::find_by_id(&pool, 1).await?.unwrap();
user.name = Some("李四".to_string());
user.email = None; // 不更新 email 字段
user.update(&pool).await?;
// Reset 语义:Option 字段为 None 时重置为数据库默认值
user.update_with_none(&pool).await?;
// 根据模型配置自动选择物理删除或逻辑删除
User::delete_by_id(&pool, 1).await?;
// 强制物理删除
User::hard_delete_by_id(&pool, 1).await?;
// 强制逻辑删除(需要配置 soft_delete)
User::soft_delete_by_id(&pool, 1).await?;
QueryBuilder 提供了安全、灵活的动态查询构建:
use sqlxplus::QueryBuilder;
// 基础查询
let builder = QueryBuilder::new("")
.and_eq("status", 1)
.and_like("name", "%张%")
.order_by("created_at", false); // false = DESC
let users = User::find_all(&pool, Some(builder)).await?;
// 条件分组
let builder = QueryBuilder::new("")
.and_group(|b| {
b.or_eq("status", 1).or_eq("status", 2)
})
.and_gt("age", 18);
// SQL: WHERE (status = 1 OR status = 2) AND age > 18
// 复杂查询
let builder = QueryBuilder::new("")
.and_in("category", vec!["tech", "news"])
.and_between("price", 100, 500)
.and_is_not_null("published_at")
.order_by("views", false)
.limit(20)
.offset(40);
可用方法:
and_eq, and_ne, and_gt, and_gte, and_lt, and_lteand_like, and_not_likeand_in, and_not_in, and_betweenand_is_null, and_is_not_nulland_group, or_grouporder_bylimit, offsetlet builder = QueryBuilder::new("")
.and_eq("status", 1)
.order_by("created_at", false);
let page = User::paginate(&pool, builder, 1, 10).await?;
println!("总数: {}", page.total);
println!("当前页: {}", page.page);
println!("每页大小: {}", page.size);
println!("总页数: {}", page.pages);
println!("数据: {:?}", page.items);
use sqlxplus::Transaction;
// 开启事务
let mut tx = pool.begin().await?;
// 在事务中执行操作
let user = User {
id: None,
name: Some("张三".to_string()),
email: Some("zhangsan@example.com".to_string()),
status: Some(1),
};
let id = user.insert(&mut tx).await?;
// 更新
let mut user = User::find_by_id(&mut tx, id).await?.unwrap();
user.status = Some(2);
user.update(&mut tx).await?;
// 提交事务
tx.commit().await?;
use sqlxplus::DbPool;
// MySQL
let pool = DbPool::connect("mysql://user:pass@localhost:3306/database").await?;
// PostgreSQL
let pool = DbPool::connect("postgres://user:pass@localhost:5432/database").await?;
// SQLite
let pool = DbPool::connect("sqlite://database.db").await?;
let pool = DbPool::connect("sqlite::memory:").await?; // 内存数据库
let builder = QueryBuilder::new("").and_eq("status", 1);
let count = User::count(&pool, builder).await?;
println!("符合条件的记录数: {}", count);
sqlx-plus/
├─ core/ # 核心库(sqlxplus)- 已发布到 crates.io
├─ derive/ # proc-macro crate(sqlxplus-derive)- 已发布到 crates.io
├─ cli/ # 代码生成器
└─ examples/ # 示例项目
├─ mysql_example/
├─ postgres_example/
└─ sqlite_example/
Option<T> 包装字段,以支持 NULL 值和灵活的更新语义Option<i64>,插入时设为 None 自动生成update(): Patch 语义,None 值的字段不更新update_with_none(): Reset 语义,None 值的字段重置为默认值查看 examples/ 目录获取完整的示例代码:
MIT OR Apache-2.0