use serde::de::DeserializeOwned;
use std::marker::PhantomData;
use crate::client::WattpadRequestBuilder;
use crate::WattpadError;
pub trait PaginatedResponse<T> {
fn into_items(self) -> Vec<T>;
fn has_next_page(&self) -> bool;
}
pub struct Paginator<'a, T, R> {
req_builder: WattpadRequestBuilder<'a>,
limit: usize,
offset: usize,
_marker: PhantomData<(T, R)>,
}
impl<'a, T, R> Paginator<'a, T, R>
where
T: Send + Sync,
R: DeserializeOwned + PaginatedResponse<T> + Send + Sync,
{
pub(crate) fn new(req_builder: WattpadRequestBuilder<'a>) -> Self {
Self {
req_builder,
limit: 10, offset: 0,
_marker: PhantomData,
}
}
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit.min(100);
self
}
pub fn offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
pub async fn execute(self) -> Result<R, WattpadError> {
self.req_builder
.param("limit", Some(self.limit))
.param("offset", Some(self.offset))
.execute::<R>() .await
}
pub async fn execute_all(mut self) -> Result<Vec<T>, WattpadError> {
self.limit = 100;
self.offset = 0;
let mut all_items = Vec::new();
loop {
let response_wrapper = self.req_builder.clone()
.param("limit", Some(self.limit))
.param("offset", Some(self.offset))
.execute::<R>()
.await?;
let has_next = response_wrapper.has_next_page();
let items = response_wrapper.into_items();
all_items.extend(items);
if has_next {
self.offset += 100;
} else {
break;
}
}
Ok(all_items)
}
}