sui_gql_client/
paged.rs

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
8/// Pages resulting from GraphQL queries.
9///
10/// The full responses are included to allow users to introspect possible errors.
11pub 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    /// Extract data (inital query, subsequent queries) from the [GraphQlResponse]s.
23    ///
24    /// Errors if any response has errors.
25    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
55/// The initial page data and subsequent ones', if any.
56pub type PagesDataResult<T> = Result<Option<(T, Vec<<T as Paged>::NextPage>)>, GraphQlErrors>;
57
58/// Interface for paged queries to allow automatic pagination.
59pub trait Paged:
60    DeserializeOwned + QueryFragment<VariablesFields = <Self::Input as QueryVariables>::Fields>
61{
62    /// The input for this query type.
63    type Input: QueryVariables + Send + Serialize;
64    /// The type of the next query variables.
65    type NextInput: QueryVariables + Send + Serialize;
66    /// The type of the next query.
67    type NextPage: DeserializeOwned
68        + QueryFragment<VariablesFields = <Self::NextInput as QueryVariables>::Fields>
69        + Send;
70
71    /// The next query variables to use for querying the next page, if any.
72    fn next_variables(&self, prev_vars: Self::Input) -> Option<Self::NextInput>;
73}