< 返回版块

akaisiro 发表于 2025-05-15 03:06

Tags:axum,diesel,postgresql,pagination

最近在用axum,diesel,postgresql写后台管理系统,在写分页查询时卡住了,前来求教。参考这里写的:https://github.com/diesel-rs/diesel/blob/master/examples/postgres/advanced-blog-cli/src/pagination.rs 这是model层employee的分页查询函数

pub(crate) fn employee_list(
    mut conn: &mut bb8::PooledConnection<'static, AsyncDieselConnectionManager<AsyncPgConnection>>,
    page: i32,
    per_page: i32
) -> Result<(Vec<Employee>, i32), diesel::result::Error> {
        let mut query = t_employee::table
        .order(t_employee::id.asc())
        .filter(t_employee::is_deleted.eq(false))
        .paginate(page).per_page(std::cmp::min(per_page, 25)).load_and_count_pages::<Employee>(conn)?;
    println!("{:?}", query);
    Ok(query)
}

这是pagination.rs

use diesel::{
    pg::Pg, query_builder::{AstPass, Query, QueryFragment, QueryId}, query_dsl::methods::LoadQuery, sql_types::Integer, QueryResult, RunQueryDsl, 
};
use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection};

pub(crate) trait Paginate: Sized {
    fn paginate(self, page: i32) -> Paginated<Self>;
}

impl<T> Paginate for T {
    fn paginate(self, page: i32) -> Paginated<Self> {
        Paginated {
            query: self,
            per_page: DEFAULT_PER_PAGE,
            page,
            offset: (page - 1) * DEFAULT_PER_PAGE,
        }
    }
}

const DEFAULT_PER_PAGE: i32 = 10;

#[derive(Debug, Clone, Copy, QueryId)]
pub struct Paginated<T> {
    query: T,
    page: i32,
    per_page: i32,
    offset: i32,
}

impl<T> Paginated<T> {
    pub(super) fn per_page(self, per_page: i32) -> Self {
        Paginated {
            per_page,
            offset: (self.page - 1) * per_page,
            ..self
        }
    }

    pub(super) fn load_and_count_pages<'a, U>(
        self,
        conn: &mut bb8::PooledConnection<'static, AsyncDieselConnectionManager<AsyncPgConnection>>,
    ) -> QueryResult<(Vec<U>, i32)>
    where
        Self: LoadQuery<'a, bb8::PooledConnection<'static, AsyncDieselConnectionManager<AsyncPgConnection>>, (U, i32)>,
    {
        let per_page = self.per_page;
        let results = self.load::<(U, i32)>(conn)?;
        let total = results.first().map(|x| x.1).unwrap_or(0);
        let records = results.into_iter().map(|x| x.0).collect();
        let total_pages = (total as f32 / per_page as f32).ceil() as i32;
        Ok((records, total_pages))
    }
}

impl<T: Query> Query for Paginated<T> {
    type SqlType = (T::SqlType, Integer);
}

impl<T> RunQueryDsl<bb8::PooledConnection<'static, AsyncDieselConnectionManager<AsyncPgConnection>>> for Paginated<T> {}

impl<T> QueryFragment<Pg> for Paginated<T> where T: QueryFragment<Pg> {
    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
        out.push_sql("SELECT *, COUNT(*) OVER () FROM (");
        self.query.walk_ast(out.reborrow())?;
        out.push_sql(") t LIMIT");
        out.push_bind_param::<Integer, _>(&self.per_page)?;
        out.push_sql(" OFFSET ");
        out.push_bind_param::<Integer, _>(&self.offset)?;
        Ok(())
    }
}

评论区

写评论
zsen 2025-05-15 19:11

异步一样的,只要把 Connection 改成异步的就行,其他的不用改

作者 akaisiro 2025-05-15 18:41

谢谢,这个可以用,但是要怎么改成异步版本的呢

--
👇
zsen: 或者这个:https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ad0a5d8f6a5706da416e2d66d86676e2

zsen 2025-05-15 14:38

或者这个:https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=ad0a5d8f6a5706da416e2d66d86676e2

zsen 2025-05-15 14:35

不好意思,试试这个,https://gist.github.com/rust-play/eff800b9ab0284a057472ada7db840fa

作者 akaisiro 2025-05-15 14:24

这里面是个helloworld函数啊

--
👇
zsen: 这段代码可以直接运行查看生成的 sql 语句,完整测试需要部署数据库,测试函数在最下面

我还加了个动态条件筛选,一般分页查询都需要的

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024

zsen 2025-05-15 12:30

这段代码可以直接运行查看生成的 sql 语句,完整测试需要部署数据库,测试函数在最下面

我还加了个动态条件筛选,一般分页查询都需要的

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024

1 共 6 条评论, 1 页