sqlx_query_dsl/
page.rs

1
2use sqlx::{MySql, MySqlPool, QueryBuilder};
3use crate::params::QueryParams;
4use crate::whitelist::FieldWhitelist;
5use crate::builder::build_filter;
6
7/// 分页查询结果封装
8pub struct PageResult<T> {
9    /// 总记录数
10    pub total: i64,
11    /// 当前页的数据列表
12    pub list: Vec<T>,
13}
14
15/// 执行分页查询
16///
17/// 该函数会执行两次查询:一次用于计算总数,一次用于获取当前页数据。
18///
19/// # Arguments
20/// * `pool` - 数据库连接池
21/// * `base_sql` - 基础查询 SQL(不包含 WHERE, LIMIT 等)
22/// * `count_sql` - 用于统计总数的 SQL(通常是 SELECT COUNT(*) ...)
23/// * `params` - 查询参数,包含过滤条件和分页信息
24/// * `whitelist` - 字段白名单,用于校验过滤条件中的字段
25pub async fn query_page<T>(
26    pool: &MySqlPool,
27    base_sql: &str,
28    count_sql: &str,
29    params: QueryParams,
30    whitelist: FieldWhitelist,
31) -> Result<PageResult<T>, sqlx::Error>
32where
33    T: for<'r> sqlx::FromRow<'r, sqlx::mysql::MySqlRow> + Send + Unpin,
34{
35    let mut count_qb = QueryBuilder::<MySql>::new(count_sql);
36    if let Some(f) = &params.filter {
37        count_qb.push(" WHERE ");
38        build_filter(&mut count_qb, f, &whitelist).map_err(|e| sqlx::Error::Protocol(e))?;
39    }
40    let total: i64 = count_qb.build_query_scalar().fetch_one(pool).await?;
41
42    let mut qb = QueryBuilder::<MySql>::new(base_sql);
43    if let Some(f) = &params.filter {
44        qb.push(" WHERE ");
45        build_filter(&mut qb, f, &whitelist).map_err(|e| sqlx::Error::Protocol(e))?;
46    }
47    qb.push(" LIMIT ");
48    qb.push_bind(params.page_size);
49    qb.push(" OFFSET ");
50    qb.push_bind(params.page * params.page_size);
51
52    let list = qb.build_query_as::<T>().fetch_all(pool).await?;
53    Ok(PageResult { total, list })
54}