1use cynic::serde::de::DeserializeOwned;
2use cynic::serde::Serialize;
3use cynic::{GraphQlResponse, QueryFragment, QueryVariables};
4use tap::TapFallible as _;
5
6use crate::{GraphQlErrors, GraphQlResponseExt as _};
7
8pub struct PagedResponse<Init>(
12 pub(crate) GraphQlResponse<Init>,
13 pub(crate) Vec<GraphQlResponse<Init::NextPage>>,
14)
15where
16 Init: Paged;
17
18impl<Init> PagedResponse<Init>
19where
20 Init: Paged,
21{
22 pub fn try_into_data(self) -> PagesDataResult<Init> {
26 let Self(first, next) = self;
27
28 let Some(initial) = first.try_into_data().tap_err_mut(|e| e.page = Some(0))? else {
29 return Ok(None);
30 };
31
32 let mut pages = vec![];
33 for (i, response) in next.into_iter().enumerate() {
34 if let Some(page_data) = response
35 .try_into_data()
36 .tap_err_mut(|e| e.page = Some(i + 1))?
37 {
38 pages.push(page_data);
39 } else {
40 break;
41 }
42 }
43
44 Ok(Some((initial, pages)))
45 }
46
47 pub fn into_inner(self) -> (GraphQlResponse<Init>, Vec<GraphQlResponse<Init::NextPage>>) {
48 (self.0, self.1)
49 }
50}
51
52pub type PagesDataResult<T> = Result<Option<(T, Vec<<T as Paged>::NextPage>)>, GraphQlErrors>;
54
55pub trait Paged:
57 DeserializeOwned + QueryFragment<VariablesFields = <Self::Input as QueryVariables>::Fields>
58{
59 type Input: QueryVariables + Send + Serialize;
61 type NextInput: QueryVariables + Send + Serialize;
63 type NextPage: DeserializeOwned
65 + QueryFragment<VariablesFields = <Self::NextInput as QueryVariables>::Fields>
66 + Send;
67
68 fn next_variables(&self, prev_vars: Self::Input) -> Option<Self::NextInput>;
70}