GET /mangas recomputed count(*) over FILTER_WHERE (up to five correlated subqueries) on every page, so pagination cost scaled with catalog size. The total doesn't change as a caller walks pages, so compute it once at offset 0 and return null thereafter (the envelope already serialises total as Option<i64>; the frontend types it number|null and the library route ignores it). Bump to 0.124.7. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
52 lines
1.3 KiB
Rust
52 lines
1.3 KiB
Rust
//! Shared pagination envelope for list endpoints.
|
|
//!
|
|
//! `total` is `Option<i64>` and is always serialised — `null` when the
|
|
//! handler hasn't computed it yet, a number once it has. The shape is fixed
|
|
//! across `/mangas`, `/chapters`, `/bookmarks`, etc. so consumers can
|
|
//! handle pagination uniformly.
|
|
|
|
use serde::Serialize;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct PageInfo {
|
|
pub limit: i64,
|
|
pub offset: i64,
|
|
pub total: Option<i64>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct PagedResponse<T> {
|
|
pub items: Vec<T>,
|
|
pub page: PageInfo,
|
|
}
|
|
|
|
impl<T> PagedResponse<T> {
|
|
pub fn new(items: Vec<T>, limit: i64, offset: i64) -> Self {
|
|
Self {
|
|
items,
|
|
page: PageInfo { limit, offset, total: None },
|
|
}
|
|
}
|
|
|
|
pub fn with_total(items: Vec<T>, limit: i64, offset: i64, total: i64) -> Self {
|
|
Self {
|
|
items,
|
|
page: PageInfo { limit, offset, total: Some(total) },
|
|
}
|
|
}
|
|
|
|
/// For handlers that compute `total` only on some pages (e.g. the first)
|
|
/// and leave it `None` elsewhere.
|
|
pub fn with_optional_total(
|
|
items: Vec<T>,
|
|
limit: i64,
|
|
offset: i64,
|
|
total: Option<i64>,
|
|
) -> Self {
|
|
Self {
|
|
items,
|
|
page: PageInfo { limit, offset, total },
|
|
}
|
|
}
|
|
}
|