use sea_orm::{prelude::*, Condition, DatabaseConnection, EntityTrait, QueryFilter, SelectorTrait};
use serde::{Deserialize, Serialize};
const fn default_page_size() -> u64 {
25
}
const fn default_page() -> u64 {
1
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PaginationQuery {
#[serde(
default = "default_page_size",
rename = "page_size",
deserialize_with = "deserialize_pagination_filter"
)]
pub page_size: u64,
#[serde(
default = "default_page",
rename = "page",
deserialize_with = "deserialize_pagination_filter"
)]
pub page: u64,
}
impl PaginationQuery {
#[must_use]
pub fn page(page: u64) -> Self {
Self {
page,
..Default::default()
}
}
}
impl Default for PaginationQuery {
fn default() -> Self {
Self {
page_size: default_page_size(),
page: default_page(),
}
}
}
fn deserialize_pagination_filter<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
s.parse().map_err(serde::de::Error::custom)
}
#[derive(Debug)]
pub struct PageResponse<T> {
pub page: Vec<T>,
pub total_pages: u64,
}
use crate::Result as LocoResult;
pub async fn paginate<E>(
db: &DatabaseConnection,
entity: Select<E>,
condition: Option<Condition>,
pagination_query: &PaginationQuery,
) -> LocoResult<PageResponse<E::Model>>
where
E: EntityTrait,
<E as EntityTrait>::Model: Sync,
{
let page = if pagination_query.page <= 1 {
0
} else {
pagination_query.page - 1
};
let entity = if let Some(condition) = condition {
entity.filter(condition)
} else {
entity
};
let query = entity.paginate(db, pagination_query.page_size);
let total_pages = query.num_pages().await?;
let page: Vec<<E as EntityTrait>::Model> = query.fetch_page(page).await?;
let paginated_response = PageResponse { page, total_pages };
Ok(paginated_response)
}
pub async fn fetch_page<'db, C, S>(
db: &'db C,
selector: S,
pagination_query: &PaginationQuery,
) -> LocoResult<PageResponse<<<S as PaginatorTrait<'db, C>>::Selector as SelectorTrait>::Item>>
where
C: ConnectionTrait + Sync,
S: PaginatorTrait<'db, C> + Send,
{
let page = if pagination_query.page <= 1 {
0
} else {
pagination_query.page - 1
};
let query = selector.paginate(db, pagination_query.page_size);
let total_pages = query.num_pages().await?;
let page = query.fetch_page(page).await?;
Ok(PageResponse { page, total_pages })
}