-
|
Hi there, trying to get a hang of rust and diesel, have tried to follow the extending query with the paginator example, you can find my current code which throws I paste the code here for easy access on current state, the full code is there if you want to test locally. //use diesel::backend::{BindCollector, QueryBuilder};
// use diesel::impl_query_id; // deprecated since 1.1.0
use diesel::pg::Pg;
use diesel::query_builder::{AsQuery, AstPass, Query, QueryFragment};
use diesel::query_dsl::limit_dsl::LimitDsl;
use diesel::sql_types::BigInt;
use diesel::{dsl, Expression};
use diesel::{PgConnection, QueryDsl, QueryResult, RunQueryDsl};
use diesel::{QueryId, Queryable};
use diesel_demo::schema::posts;
// Implement `QueryFragment`
impl<T> QueryFragment<Pg> for PaginatedResult<T>
where
T: QueryFragment<Pg>,
PaginatedResult<T>: LimitDsl,
{
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(") LIMIT ");
out.push_bind_param(&self.limit(self.per_page))?;
out.push_sql(" OFFSET ");
out.push_bind_param::<BigInt, _>(&self.offset())?;
Ok(())
}
}
// Whenever you implement `QueryFragment` you need to implement `QueryId`
impl<T: Query> Query for PaginatedResult<T> {
type SqlType = (T::SqlType, BigInt);
}
impl<T> RunQueryDsl<PgConnection> for PaginatedResult<T> {}
// FIXME: maybe implement this? but not this way?
// impl<T> QueryDsl for Paginated<T> {}
impl<T: LimitDsl + LimitDsl<Output = T>> LimitDsl for PaginatedResult<T> {
type Output = PaginatedResult<dsl::Limit<T>>;
fn limit(self, limit: i64) -> Self::Output {
limit
}
}
// Using `trait Paginate` to implement all that
pub trait Paginate: AsQuery + Sized {
fn paginate(self, page: i64) -> PaginatedResult<Self::Query> {
PaginatedResult {
query: self.as_query(),
page,
per_page: DEFAULT_PER_PAGE,
}
}
}
impl<T: AsQuery> Paginate for T {}
const DEFAULT_PER_PAGE: i64 = 10;
#[derive(Queryable, QueryId, Debug)]
pub struct PaginatedResult<T> {
query: T,
page: i64,
per_page: i64,
}
impl<T> PaginatedResult<T> {
pub fn per_page(self, per_page: i64) -> Self {
PaginatedResult { per_page, ..self }
}
}
fn main() {
let second = posts::table.paginate(3).per_page(2);
println!("count hay {:?}", &second);
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
|
There are multiple issues with your code:
Given these points its really hard to understand what exactly you want to achieve. Therefore I cannot offer any concrete help here. Maybe have another look at the corresponding guide? Each part of the exemplary implementation is explained there in detail. |
Beta Was this translation helpful? Give feedback.
-
|
Gotcha //use diesel::backend::{BindCollector, QueryBuilder};
//use diesel::impl_query_id; // deprecated since 1.1.0
use diesel::pg::Pg;
use diesel::query_builder::{AsQuery, AstPass, Query, QueryFragment};
use diesel::query_dsl::LoadQuery;
use diesel::sql_types::BigInt;
use diesel::{PgConnection, QueryResult, RunQueryDsl};
use diesel::{QueryId, Queryable};
use diesel_demo::establish_connection;
use diesel_demo::models::Post;
use diesel_demo::schema::posts;
// Implement `QueryFragment`
impl<T> QueryFragment<Pg> for PaginatedQuery<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(") as internal LIMIT ");
out.push_bind_param::<BigInt, _>(&self.per_page)?;
out.push_sql(" OFFSET ");
out.push_bind_param::<BigInt, _>(&self.page)?;
Ok(())
}
}
// impl_query_id!(PaginatedQuery<T>);
impl<T: Query> Query for PaginatedQuery<T> {
type SqlType = (T::SqlType, BigInt);
}
impl<T> RunQueryDsl<PgConnection> for PaginatedQuery<T> {}
pub trait Paginate: AsQuery + Sized {
fn paginate(self, page: i64) -> PaginatedQuery<Self::Query> {
PaginatedQuery {
query: self.as_query(),
page,
per_page: DEFAULT_PER_PAGE,
}
}
}
impl<T: AsQuery> Paginate for T {}
const DEFAULT_PER_PAGE: i64 = 10;
#[derive(Debug, QueryId)]
pub struct PaginatedQuery<T> {
query: T,
page: i64,
per_page: i64,
}
impl<T> PaginatedQuery<T> {
pub fn per_page(self, per_page: i64) -> Self {
PaginatedQuery { per_page, ..self }
}
fn load_and_count_pages<U>(self, conn: &PgConnection) -> QueryResult<(Vec<U>, i64)>
where
Self: LoadQuery<PgConnection, (U, i64)>,
{
let per_page = self.per_page;
let results: Vec<(U, i64)> = self.load(conn)?;
let total = results.get(0).map(|(_, total)| total).unwrap_or(&0);
let total = f64::from(*total as i32);
let records: Vec<U> = results.into_iter().map(|(record, _)| record).collect();
let total_pages = (total / per_page as f64).ceil() as i64;
Ok((records, total_pages))
}
}
fn main() {
let conn = establish_connection();
let results: Vec<(Post, i64)> = posts::table
.paginate(3)
.per_page(25)
.get_results(&conn)
.expect("error");
println!("{:?}", results);
let paginated_query = posts::table.paginate(3).per_page(2);
let records: (Vec<Post>, i64) = paginated_query.load_and_count_pages(&conn).expect("error");
println!("*** records {:?}", records.0);
println!("*** pages {:?}", records.1);
}Sended PR for update the guide and some typos. |
Beta Was this translation helpful? Give feedback.
Gotcha