1pub use cynic;
51use cynic::schema::{MutationRoot, QueryRoot};
52use cynic::serde::Serialize;
53use cynic::serde::de::DeserializeOwned;
54use cynic::{GraphQlError, GraphQlResponse, Operation, QueryFragment, QueryVariables};
55use extension_traits::extension;
56pub use sui_gql_schema::{scalars, schema};
57
58pub mod queries;
59mod raw_client;
60pub mod reqwest;
61
62#[deprecated(since = "0.14.8", note = "use the graphql-extract crate")]
63pub mod extract;
64mod paged;
65
66pub use self::paged::{Paged, PagedResponse, PagesDataResult};
67pub use self::raw_client::{Error as RawClientError, RawClient};
68
69#[trait_variant::make(Send)]
71pub trait GraphQlClient: Sync {
72 type Error: std::error::Error + Send + 'static;
73
74 async fn query_paged<Init>(&self, vars: Init::Input) -> Result<PagedResponse<Init>, Self::Error>
75 where
76 Init: Paged + Send + 'static,
77 Init::SchemaType: QueryRoot,
78 Init::Input: Clone,
79 Init::NextPage:
80 Paged<Input = Init::NextInput, NextInput = Init::NextInput, NextPage = Init::NextPage>,
81 <Init::NextPage as QueryFragment>::SchemaType: QueryRoot,
82 <Init::NextPage as Paged>::Input: Clone,
83 {
84 async {
85 let initial: GraphQlResponse<Init> = self.query(vars.clone()).await?;
86 let mut next_vars = initial.data.as_ref().and_then(|d| d.next_variables(vars));
87 let mut pages = vec![];
88 while let Some(vars) = next_vars {
89 let next_page: GraphQlResponse<Init::NextPage> = self.query(vars.clone()).await?;
90 next_vars = next_page.data.as_ref().and_then(|d| d.next_variables(vars));
91 pages.push(next_page);
92 }
93 Ok(PagedResponse(initial, pages))
94 }
95 }
96
97 async fn query<Query, Variables>(
98 &self,
99 vars: Variables,
100 ) -> Result<GraphQlResponse<Query>, Self::Error>
101 where
102 Variables: QueryVariables + Send + Serialize,
103 Query: DeserializeOwned + QueryFragment<VariablesFields = Variables::Fields> + 'static,
104 Query::SchemaType: QueryRoot,
105 {
106 use cynic::QueryBuilder as _;
107 self.run_graphql(Query::build(vars))
108 }
109
110 async fn mutation<Mutation, Vars>(
111 &self,
112 vars: Vars,
113 ) -> Result<GraphQlResponse<Mutation>, Self::Error>
114 where
115 Vars: QueryVariables + Send + Serialize,
116 Mutation: DeserializeOwned + QueryFragment<VariablesFields = Vars::Fields> + 'static,
117 Mutation::SchemaType: MutationRoot,
118 {
119 use cynic::MutationBuilder as _;
120 self.run_graphql(Mutation::build(vars))
121 }
122
123 async fn run_graphql<Query, Vars>(
124 &self,
125 operation: Operation<Query, Vars>,
126 ) -> Result<GraphQlResponse<Query>, Self::Error>
127 where
128 Vars: Serialize + Send,
129 Query: DeserializeOwned + 'static;
130}
131
132#[extension(pub trait GraphQlResponseExt)]
134impl<T> GraphQlResponse<T> {
135 fn try_into_data(self) -> Result<Option<T>, GraphQlErrors> {
138 if let Some(errors) = self.errors
139 && !errors.is_empty()
140 {
141 return Err(GraphQlErrors { errors, page: None });
142 }
143
144 let Some(data) = self.data else {
145 return Ok(None);
146 };
147 Ok(Some(data))
148 }
149}
150
151#[derive(thiserror::Error, Clone, Debug, Eq, PartialEq, serde::Deserialize)]
153pub struct GraphQlErrors<Extensions = serde::de::IgnoredAny> {
154 pub errors: Vec<GraphQlError<Extensions>>,
155 pub page: Option<usize>,
156}
157
158impl<Extensions> std::fmt::Display for GraphQlErrors<Extensions> {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 let page_info = self
161 .page
162 .map_or_else(String::new, |page| format!(" at page {page}"));
163 writeln!(
164 f,
165 "Query execution produced the following errors{page_info}:"
166 )?;
167 for error in &self.errors {
168 writeln!(f, "{error}")?;
169 }
170 Ok(())
171 }
172}