use cynic::serde::de::DeserializeOwned;
use cynic::serde::Serialize;
use cynic::{GraphQlResponse, QueryFragment, QueryVariables};
use tap::TapFallible as _;
use crate::{GraphQlErrors, GraphQlResponseExt as _};
pub struct PagedResponse<Init>(
pub(crate) GraphQlResponse<Init>,
pub(crate) Vec<GraphQlResponse<Init::NextPage>>,
)
where
Init: Paged;
impl<Init> PagedResponse<Init>
where
Init: Paged,
{
pub fn try_into_data(self) -> PagesDataResult<Init> {
let Self(first, next) = self;
let Some(initial) = first.try_into_data().tap_err_mut(|e| e.page = Some(0))? else {
return Ok(None);
};
let mut pages = vec![];
for (i, response) in next.into_iter().enumerate() {
if let Some(page_data) = response
.try_into_data()
.tap_err_mut(|e| e.page = Some(i + 1))?
{
pages.push(page_data);
} else {
break;
}
}
Ok(Some((initial, pages)))
}
pub fn into_inner(self) -> (GraphQlResponse<Init>, Vec<GraphQlResponse<Init::NextPage>>) {
(self.0, self.1)
}
}
pub type PagesDataResult<T> = Result<Option<(T, Vec<<T as Paged>::NextPage>)>, GraphQlErrors>;
pub trait Paged:
DeserializeOwned + QueryFragment<VariablesFields = <Self::Input as QueryVariables>::Fields>
{
type Input: QueryVariables + Send + Serialize;
type NextInput: QueryVariables + Send + Serialize;
type NextPage: DeserializeOwned
+ QueryFragment<VariablesFields = <Self::NextInput as QueryVariables>::Fields>
+ Send;
fn next_variables(&self, prev_vars: Self::Input) -> Option<Self::NextInput>;
}