1use cynic::serde::Serialize;
2use cynic::serde::de::DeserializeOwned;
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 match response
35 .try_into_data()
36 .tap_err_mut(|e| e.page = Some(i + 1))?
37 {
38 Some(page_data) => {
39 pages.push(page_data);
40 }
41 _ => {
42 break;
43 }
44 }
45 }
46
47 Ok(Some((initial, pages)))
48 }
49
50 pub fn into_inner(self) -> (GraphQlResponse<Init>, Vec<GraphQlResponse<Init::NextPage>>) {
51 (self.0, self.1)
52 }
53}
54
55pub type PagesDataResult<T> = Result<Option<(T, Vec<<T as Paged>::NextPage>)>, GraphQlErrors>;
57
58pub trait Paged:
60 DeserializeOwned + QueryFragment<VariablesFields = <Self::Input as QueryVariables>::Fields>
61{
62 type Input: QueryVariables + Send + Serialize;
64 type NextInput: QueryVariables + Send + Serialize;
66 type NextPage: DeserializeOwned
68 + QueryFragment<VariablesFields = <Self::NextInput as QueryVariables>::Fields>
69 + Send;
70
71 fn next_variables(&self, prev_vars: Self::Input) -> Option<Self::NextInput>;
73}