代码 如何在Rust中使用Axum和sqlx封装一个简单的分页查询函数

2024-11-19 03:57:58 +0800 CST views 1261

Rust的Axum+sqlx封装一个简单的分页查询函数

封装

// src/utils/pagination.rs

use std::marker::PhantomData;
use serde::Serialize;
use sqlx::{FromRow, PgPool, Postgres, QueryBuilder};
use crate::utils::log;
use super::env;

#[derive(Serialize, Debug)]
pub struct PaginatedResult<T> {
    pub records: Vec<T>,
    pub limit: i64,
    pub page: i64,
    pub total: i64,
}

/// 通用分页请求器
pub struct PaginatedQueryBuilder<'a, T> {
    pool: &'a PgPool,
    select: &'a str,
    page: Option<i64>,
    limit: Option<i64>,
    sort_field: Option<&'a str>,
    _marker: PhantomData<T>, // 引入泛型类型 T
}

/// 请求器类型
pub enum BuilderType {
    RECORDS,
    TOTAL,
}

impl<'a, T> PaginatedQueryBuilder<'a, T>
where
    T: for<'r> FromRow<'r, sqlx::postgres::PgRow> + Unpin + Send + 'static + std::fmt::Debug,
{
    pub fn new(
        pool: &'a PgPool,
        select: &'a str,
        page: Option<i64>,
        limit: Option<i64>,
        sort_field: Option<&'a str>,
    ) -> Self {
        Self {
            pool,
            select,
            page,
            limit,
            sort_field,
            _marker: PhantomData, // 初始化 PhantomData
        }
    }

    pub async fn paginate(
        &self,
        apply_filter: impl Fn(&mut QueryBuilder<Postgres>, BuilderType),
    ) -> Result<PaginatedResult<T>, sqlx::Error> {
        let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new(r#"SELECT "#);
        query_builder.push(self.select);
        query_builder.push(" FROM ");

        let mut query_builder_total: QueryBuilder<Postgres> =
            QueryBuilder::new(r#"SELECT COUNT(*) FROM "#);

        let page_size = self
            .limit
            .unwrap_or(env::APP_PAGE_LIMIT.parse::<i64>().unwrap_or(10));
        let offset = (self.page.unwrap_or(1) - 1) * page_size;

        let order_by = self.sort_field.unwrap_or("created_at DESC");

        apply_filter(&mut query_builder, BuilderType::RECORDS);
        apply_filter(&mut query_builder_total, BuilderType::TOTAL);

        query_builder.push(" ORDER BY ");
        query_builder.push_bind(order_by);
        query_builder.push(" DESC LIMIT ");
        query_builder.push_bind(page_size);
        query_builder.push(" OFFSET ");
        query_builder.push_bind(offset);

        log::info("SQL", query_builder.sql());
        log::info("SQL", query_builder_total.sql());

        let total = query_builder_total
            .build_query_scalar()
            .fetch_one(&*self.pool)
            .await?;

        let records: Vec<T> = query_builder
            .build_query_as()
            .fetch_all(&*self.pool)
            .await?;

        Ok(PaginatedResult {
            records,
            limit: page_size,
            page: self.page.unwrap_or(1),
            total,
        })
    }
}

使用

// src/modules/user/mod.rs

let query_builder = PaginatedQueryBuilder::<PageQsoRes>::new(
    &pool,
    "u.*, a.address as address", // 这块是select模块
    payload.page,
    payload.limit,
    None,
);

// 添加通用过滤条件
let apply_filter = |qb: &mut QueryBuilder<Postgres>, builder_type: BuilderType| {
    qb.push(" users u ");

    if let BuilderType::RECORDS = builder_type {
        qb.push(" LEFT JOIN address a ON u.address_id = a.id ");
    }

    qb.push(" WHERE u.user_id =");
    qb.push_bind(user_id);

    if let Some(user_name) = &payload.user_name {
        if !user_name.is_empty() {
            qb.push(" AND u.user_name = ");
            qb.push_bind(user_name);
        }
    }
};

let res = query_builder.paginate(apply_filter).await?;
println!("res: {:?}", res);

//{
//  "records": [
//      {
//         // ...
//      }
//  ],
//  "limit": 10,
//  "page": 1,
//  "total": 1
//},
复制全文 生成海报 Rust 数据库 分页查询

推荐文章

在 Vue 3 中如何创建和使用插件?
2024-11-18 13:42:12 +0800 CST
Dropzone.js实现文件拖放上传功能
2024-11-18 18:28:02 +0800 CST
filecmp,一个Python中非常有用的库
2024-11-19 03:23:11 +0800 CST
markdown语法
2024-11-18 18:38:43 +0800 CST
企业官网案例-芊诺网络科技官网
2024-11-18 11:30:20 +0800 CST
纯CSS绘制iPhoneX的外观
2024-11-19 06:39:43 +0800 CST
XSS攻击是什么?
2024-11-19 02:10:07 +0800 CST
2025年,小程序开发到底多少钱?
2025-01-20 10:59:05 +0800 CST
Go语言中的`Ring`循环链表结构
2024-11-19 00:00:46 +0800 CST
curl错误代码表
2024-11-17 09:34:46 +0800 CST
Golang 中应该知道的 defer 知识
2024-11-18 13:18:56 +0800 CST
支付宝批量转账
2024-11-18 20:26:17 +0800 CST
Nginx 反向代理
2024-11-19 08:02:10 +0800 CST
Vue3中如何进行性能优化?
2024-11-17 22:52:59 +0800 CST
MySQL 1364 错误解决办法
2024-11-19 05:07:59 +0800 CST
Golang 随机公平库 satmihir/fair
2024-11-19 03:28:37 +0800 CST
liunx宝塔php7.3安装mongodb扩展
2024-11-17 11:56:14 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
如何将TypeScript与Vue3结合使用
2024-11-19 01:47:20 +0800 CST
程序员茄子在线接单