一个基于 SeaORM 的 Rust Repository 模式库,通过派生宏自动生成 CRUD 操作。
- 🚀 自动生成 CRUD:通过派生宏自动生成常用方法
- 🎯 类型安全:基于 SeaORM 的强类型系统
- 🔍 灵活查询:支持自定义 FindFilter、SearchFilter、DeleteFilter
- 📦 分页支持:支持 PageOffset 和 Cursor 两种分页方式
- 🔄 批量操作:支持批量插入、Upsert(自动分块处理)
- 🎨 功能选择:通过
all、include、exclude灵活控制生成的方法 - 💾 事务支持:批量操作自动使用事务
[dependencies]
searepo = "0.1"
sea-orm = "2.0"
tokio = { version = "1", features = ["full"] }use searepo::Repository;
use sea_orm::DatabaseConnection;
use std::sync::Arc;
#[derive(Repository)]
#[repository(entity = "entities::user", domain = "User")]
pub struct UserRepository {
db: Arc<DatabaseConnection>,
}
impl UserRepository {
pub fn new(db: Arc<DatabaseConnection>) -> Self {
Self { db }
}
}use searepo::{FindFilter, SearchFilter, DeleteFilter, Pagination};
use sea_orm::*;
pub mod filter {
use super::*;
// 单条查询过滤器
pub enum Find {
ById(i64),
ByEmail(String),
}
impl FindFilter<entities::user::Entity> for Find {
fn to_select(self) -> Select<entities::user::Entity> {
match self {
Find::ById(id) => entities::user::Entity::find_by_id(id),
Find::ByEmail(email) => {
entities::user::Entity::find()
.filter(entities::user::Column::Email.eq(email))
}
}
}
}
// 搜索过滤器(支持分页)
#[derive(Default)]
pub struct Search {
pub username: Option<String>,
pub active: Option<bool>,
pub pagination: Option<Pagination>,
}
impl SearchFilter<entities::user::Entity> for Search {
fn to_select(self) -> Select<entities::user::Entity> {
let mut query = entities::user::Entity::find();
if let Some(username) = self.username {
query = query.filter(entities::user::Column::Username.contains(&username));
}
if let Some(active) = self.active {
query = query.filter(entities::user::Column::Active.eq(active));
}
query
}
fn pagination(&self) -> Option<Pagination> {
self.pagination
}
}
// 删除过滤器
pub enum Delete {
ById(i64),
}
impl DeleteFilter<entities::user::Entity> for Delete {
fn to_select(self) -> Select<entities::user::Entity> {
match self {
Delete::ById(id) => entities::user::Entity::find_by_id(id),
}
}
}
}// 查询
let user = repo.find(filter::Find::ById(1)).await?; // Option<User>
let user = repo.load(filter::Find::ById(1)).await?; // User (不存在则报错)
let exists = repo.exists(filter::Find::ById(1)).await?; // bool
// 搜索(支持分页)
let result = repo.search(filter::Search::default ()).await?;
println!("总数: {}, 当前页: {}", result.total_count, result.items.len());
// 插入
let new_user = User { id: 1, username: "alice".into(), email: "alice@example.com".into() };
let created = repo.insert(new_user).await?;
// 批量插入(自动分块,使用事务)
let users = vec![user1, user2, user3];
let created = repo.batch_insert(users).await?;
// 更新
repo.update(user).await?;
// 删除(返回被删除的实体)
let deleted_users = repo.delete(filter::Delete::ById(1)).await?;
// 或只获取删除数量
let count = repo.delete_count(filter::Delete::ById(1)).await?;通过宏参数灵活控制生成的方法:
#[derive(Repository)]
#[repository(entity = "entities::user", domain = "User")]
pub struct UserRepository {
db: Arc<DatabaseConnection>
}
// 生成: find(), load(), exists(), search(), count()#[repository(entity = "...", domain = "...", all = true)]#[repository(
entity = "...",
domain = "...",
include = ["find", "insert", "delete"]
)]#[repository(
entity = "...",
domain = "...",
exclude = ["delete", "upsert"]
)]
// 启用除 delete 和 upsert 外的所有功能| Feature | 生成的方法 |
|---|---|
find |
find(), load(), exists() |
search |
search(), count() |
insert |
insert(), batch_insert() |
update |
update() |
delete |
delete(), delete_count() |
upsert |
upsert(), batch_upsert() |
优先级: all > include > exclude > 默认 (find + search)
支持两种分页方式:
use searepo::Pagination;
// 1. PageOffset 分页(页码 + 页大小)
let result = repo.search(filter::Search {
pagination: Some(Pagination::PageOffset { page: 1, size: 20 }),
..Default::default ()
}).await?;
println!("第 {}/{} 页", result.page, result.total_page);
println!("共 {} 条记录", result.total_count);
println!("是否有更多: {}", result.has_more());
// 2. Cursor 分页(游标分页,适用于大数据集)
let result = repo.search(filter::Search {
pagination: Some(Pagination::Cursor { limit: 50 }),
..Default::default ()
}).await?;use searepo::Upsertable;
use sea_orm::sea_query::OnConflict;
// 在领域实体上实现 Upsertable trait
impl Upsertable<entities::product::Entity> for Product {
fn on_conflict() -> OnConflict {
use entities::product::Column;
OnConflict::columns([Column::Sku])
.update_columns([Column::Name, Column::Price])
.to_owned()
}
}
// 使用
repo.upsert(product).await?;
repo.batch_upsert(products).await?; // 批量 upsert(自动分块)批量操作会自动计算最大分块大小(基于 PostgreSQL 参数限制),并使用事务确保原子性:
// 批量插入
let users = generate_users(10000); // 大量数据
let inserted = repo.batch_insert(users).await?; // 自动分块处理
// 批量 upsert
repo.batch_upsert(products).await?;| 方法 | 说明 | 返回类型 |
|---|---|---|
find(filter) |
查找单个(可能不存在) | Option<T> |
load(filter) |
查找单个(必须存在) | T |
exists(filter) |
检查是否存在 | bool |
| 方法 | 说明 | 返回类型 |
|---|---|---|
search(filter) |
搜索(支持分页) | SearchResult<T> |
count(filter) |
统计数量 | u64 |
| 方法 | 说明 | 返回类型 |
|---|---|---|
insert(entity) |
插入单个 | T |
batch_insert(entities) |
批量插入(自动分块,事务) | Vec<T> |
| 方法 | 说明 | 返回类型 |
|---|---|---|
update(entity) |
更新单个 | T |
| 方法 | 说明 | 返回类型 |
|---|---|---|
delete(filter) |
删除并返回被删除的实体 | Vec<T> |
delete_count(filter) |
删除并返回数量 | u64 |
| 方法 | 说明 | 返回类型 |
|---|---|---|
upsert(entity) |
插入或更新 | () |
batch_upsert(entities) |
批量 upsert(自动分块,事务) | () |
// Command 侧
#[repository(entity = "...", domain = "...", include = ["insert", "update", "delete"])]
pub struct UserCommandRepository {
db: Arc<DatabaseConnection>
}
// Query 侧
#[repository(entity = "...", domain = "...")] // 默认只有 find + search
pub struct UserQueryRepository {
db: Arc<DatabaseConnection>
}#[repository(entity = "...", domain = "...", include = ["insert", "search"])]
pub struct AuditLogRepository {
db: Arc<DatabaseConnection>
}#[repository(entity = "...", domain = "...", include = ["upsert"])]
pub struct DataSyncRepository {
db: Arc<DatabaseConnection>
}根据启用的功能,需要实现相应的 trait:
| 功能 | 需要实现的 Trait |
|---|---|
find |
FindFilter |
search |
SearchFilter |
insert / update |
From<Domain> for ActiveModel, From<Model> for Domain |
delete |
DeleteFilter |
upsert |
Upsertable, From<Domain> for ActiveModel |
查看 examples/ 目录获取更多示例:
cargo run --example basic_crud
cargo run --example pagination
cargo run --example feature_flagsMIT License - 查看 LICENSE 文件了解详情。