1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use diesel::prelude::*;
use diesel::query_builder::*;
use diesel::types::BigInt;
use diesel::pg::Pg;

pub struct Paginated<T> {
    query: T,
    limit: i64,
    offset: i64,
}

pub trait Paginate: AsQuery + Sized {
    fn paginate(self, limit: i64, offset: i64) -> Paginated<Self::Query> {
        Paginated {
            query: self.as_query(),
            limit,
            offset,
        }
    }
}

impl<T: AsQuery> Paginate for T {}

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

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

impl_query_id!(Paginated<T>);