使用宏实现高效的分页查询功能
使用宏实现高效的分页查询功能
批量数据查询:基于宏的分页列表查询解决方案
在现代Web应用中,分页查询是处理大量数据的标准方式。本文将介绍如何使用Rust过程宏自动化分页查询的实现,提供统一的分页接口和灵活的查询选项。
分页查询的复杂性
传统的手动分页实现:
pub async fn list_categories(db: &DatabaseConnection,page: u64,limit: u64,
) -> Result<Vec<category::Model>, AppError> {let categories = category::Entity::find().limit(limit).offset((page - 1) * limit).all(db).await.map_err(|e| AppError::DatabaseError(e.to_string()))?;Ok(categories)
}
每个实体都需要重复实现相似的分页逻辑。
宏驱动的分页解决方案
crud_entity!({entity: categories,route_prefix: "/api/categories",permission_prefix: "categories",operations: ["list"]
});
核心实现
1. 分页查询函数生成
fn generate_list_code(entity: &Ident,route_prefix: &LitStr,permission_prefix: &LitStr,
) -> proc_macro2::TokenStream {let get_fn = format_ident!("get_{}_all", entity.to_string().to_lowercase());let get_handler = format_ident!("get_{}_all_handler", entity.to_string().to_lowercase());quote! {pub async fn #get_fn(db_pool: &DatabaseConnection,page: u64,limit: u64,) -> Result<HttpResponse, AppError> {match #entity::Entity::find().limit(limit).offset((page - 1) * limit).all(db_pool).await {Ok(data) => Ok(HttpResponse::Ok().json(data)),Err(e) => {println!("Database query error: {}", e);Err(AppError::DatabaseConnectionError(e.to_string()))}}}}
}
2. 分页参数处理
#[crate::route_permission(path = #full_path,method = "get",permission = #full_permission
)]
pub async fn #get_handler(db: web::Data<DatabaseConnection>,query: web::Query<PaginationQuery>,
) -> HttpResult {let PaginationQuery { page, limit } = query.into_inner();let result = #get_fn(db.as_ref(), page, limit).await?;Ok(result)
}
分页参数结构
定义统一的分页查询参数:
#[derive(Debug, Deserialize)]
pub struct PaginationQuery {pub page: u64,pub limit: u64,
}impl Default for PaginationQuery {fn default() -> Self {Self {page: 1,limit: 20,}}
}
使用示例
1. 基本分页查询
crud_entity!({entity: categories,route_prefix: "/api/categories",permission_prefix: "categories",operations: ["list"]
});
2. 前端调用
GET /api/categories?page=1&limit=10
GET /api/categories?page=2&limit=20
3. 响应格式
[{"id": 1,"name": "Technology","slug": "tech"},{"id": 2, "name": "Science","slug": "science"}
]
高级功能
1. 排序支持
扩展分页参数支持排序:
#[derive(Debug, Deserialize)]
pub struct PaginationQuery {pub page: u64,pub limit: u64,pub sort_by: Option<String>,pub sort_order: Option<String>, // "asc" or "desc"
}
2. 过滤条件
支持查询过滤:
#[derive(Debug, Deserialize)]
pub struct CategoryQuery {pub page: u64,pub limit: u64,pub name: Option<String>,pub slug: Option<String>,
}
性能考虑
1. 数据库优化
// 使用索引优化的查询
category::Entity::find().limit(limit).offset((page - 1) * limit).all(db)
2. 防止过度分页
// 限制最大分页大小
let limit = limit.min(100); // 最大100条记录
错误处理
完善的错误处理机制:
match category::Entity::find().limit(limit).offset((page - 1) * limit).all(db_pool).await {Ok(data) => Ok(HttpResponse::Ok().json(data)),Err(e) => {println!("Database query error: {}", e);Err(AppError::DatabaseConnectionError(e.to_string()))}
}
实际应用场景
1. 管理后台
// 前端管理后台表格
const loadData = async (page, pageSize) => {const response = await fetch(`/api/categories?page=${page}&limit=${pageSize}`);return await response.json();
};
2. 移动端应用
// Flutter应用中的分页加载
Future<List<Category>> fetchCategories(int page, int limit) async {final response = await http.get(Uri.parse('/api/categories?page=$page&limit=$limit'));return categoryFromJson(response.body);
}
扩展功能建议
- 总数返回:在响应中包含总记录数
- 元数据:返回分页元信息(当前页、总页数等)
- 缓存策略:为频繁查询的数据添加缓存
- 搜索集成:结合全文搜索功能
总结
通过过程宏自动化分页查询功能,我们实现了:
- 统一的分页接口:所有实体使用相同的分页参数格式
- 灵活的查询选项:支持排序、过滤等高级功能
- 完善的错误处理:统一的数据库错误处理
- 性能优化:合理的分页限制和查询优化
- 易于扩展:支持各种定制化需求
这种方案特别适合需要处理大量数据的Web应用,能够显著提高开发效率和系统性能。