使用宏实现高效的分页查询功能
批量数据查询:基于宏的分页列表查询解决方案
在现代Web应用中,分页查询是处理大量数据的标准方式。本文将介绍如何使用Rust过程宏自动化分页查询的实现,提供统一的分页接口和灵活的查询选项。
分页查询的复杂性
传统的手动分页实现:
rustpub 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) }
每个实体都需要重复实现相似的分页逻辑。
宏驱动的分页解决方案
rustcrud_entity!({ entity: categories, route_prefix: "/api/categories", permission_prefix: "categories", operations: ["list"] });
核心实现
1. 分页查询函数生成
rustfn 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. 分页参数处理
rust#[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) }
分页参数结构
定义统一的分页查询参数:
rust#[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. 基本分页查询
rustcrud_entity!({ entity: categories, route_prefix: "/api/categories", permission_prefix: "categories", operations: ["list"] });
2. 前端调用
httpGET /api/categories?page=1&limit=10 GET /api/categories?page=2&limit=20
3. 响应格式
json[ { "id": 1, "name": "Technology", "slug": "tech" }, { "id": 2, "name": "Science", "slug": "science" } ]
高级功能
1. 排序支持
扩展分页参数支持排序:
rust#[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. 过滤条件
支持查询过滤:
rust#[derive(Debug, Deserialize)] pub struct CategoryQuery { pub page: u64, pub limit: u64, pub name: Option<String>, pub slug: Option<String>, }
性能考虑
1. 数据库优化
rust// 使用索引优化的查询 category::Entity::find() .limit(limit) .offset((page - 1) * limit) .all(db)
2. 防止过度分页
rust// 限制最大分页大小 let limit = limit.min(100); // 最大100条记录
错误处理
完善的错误处理机制:
rustmatch 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. 管理后台
javascript// 前端管理后台表格 const loadData = async (page, pageSize) => { const response = await fetch(`/api/categories?page=${page}&limit=${pageSize}`); return await response.json(); };
2. 移动端应用
dart// 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应用,能够显著提高开发效率和系统性能。
