From 47d0f971fcf64d1bb036f0081d2ff209ec5007ee Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 17 Feb 2022 05:31:06 +0900 Subject: initial commit --- src/pagination.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/pagination.rs (limited to 'src/pagination.rs') diff --git a/src/pagination.rs b/src/pagination.rs new file mode 100644 index 0000000..961b079 --- /dev/null +++ b/src/pagination.rs @@ -0,0 +1,103 @@ +use diesel::prelude::*; +use diesel::query_builder::*; +use diesel::query_dsl::methods::LoadQuery; +use diesel::sql_types::BigInt; +use diesel::sqlite::Sqlite; +use rocket::serde::Serialize; + +pub trait SortingAndPaging: Sized { + fn paginate(self, page: i64) -> SortedAndPaginated; +} + +impl SortingAndPaging for T { + fn paginate(self, page: i64) -> SortedAndPaginated { + SortedAndPaginated { + query: self, + sort_by: "".to_string(), + sort_direction: "".to_string(), + per_page: 100, + page, + } + } +} + +#[derive(Serialize)] +#[serde(crate = "rocket::serde")] +pub struct Page { + pub data: Vec, + pub page_num: i64, + pub page_size: i64, + pub total_elements: i64, +} + +impl Page { + pub fn new(data: Vec, page_num: i64, page_size: i64, total_elements: i64) -> Page { + Page { + data, + page_num, + page_size, + total_elements, + } + } +} + +#[derive(Debug, Clone, QueryId)] +pub struct SortedAndPaginated { + query: T, + sort_by: String, + sort_direction: String, + page: i64, + per_page: i64, +} + +impl SortedAndPaginated { + pub fn per_page(self, per_page: i64) -> Self { + SortedAndPaginated { per_page, ..self } + } + + pub fn sort(self, sort_by: String, sort_direction: String) -> Self { + SortedAndPaginated { + sort_by, + sort_direction, + ..self + } + } + + pub fn load_and_count_items(self, conn: &SqliteConnection) -> QueryResult> + where + Self: LoadQuery, + { + let page = self.page; + let per_page = self.per_page; + let results = self.load::<(U, i64)>(conn)?; + let total = results.get(0).map(|x| x.1).unwrap_or(0); + let records = results.into_iter().map(|x| x.0).collect(); + Ok(Page::new(records, page, per_page, total)) + } +} + +impl Query for SortedAndPaginated { + type SqlType = (T::SqlType, BigInt); +} + +impl RunQueryDsl for SortedAndPaginated {} + +impl QueryFragment for SortedAndPaginated +where + T: QueryFragment, +{ + fn walk_ast(&self, mut out: AstPass) -> QueryResult<()> { + out.push_sql("SELECT *, COUNT(*) OVER () FROM ("); + self.query.walk_ast(out.reborrow())?; + out.push_sql(") t "); + if &self.sort_by.as_str().len() > &0 { + out.push_sql(format!(" ORDER BY {} {}", &self.sort_by, &self.sort_direction).as_str()); + } + out.push_sql(" LIMIT "); + out.push_bind_param::(&self.per_page)?; + out.push_sql(" OFFSET "); + let offset = (self.page - 1) * self.per_page; + out.push_bind_param::(&offset)?; + Ok(()) + } +} -- cgit v1.2.3-70-g09d2