pub use cynic;
use cynic::schema::{MutationRoot, QueryRoot};
use cynic::serde::Serialize;
use cynic::serde::de::DeserializeOwned;
use cynic::{GraphQlError, GraphQlResponse, Operation, QueryFragment, QueryVariables};
use extension_traits::extension;
pub use sui_gql_schema::{scalars, schema};
pub mod queries;
mod raw_client;
pub mod reqwest;
#[deprecated(since = "0.14.8", note = "use the graphql-extract crate")]
pub mod extract;
mod paged;
pub use self::paged::{Paged, PagedResponse, PagesDataResult};
pub use self::raw_client::{Error as RawClientError, RawClient};
#[trait_variant::make(Send)]
pub trait GraphQlClient: Sync {
type Error: std::error::Error + Send + 'static;
async fn query_paged<Init>(&self, vars: Init::Input) -> Result<PagedResponse<Init>, Self::Error>
where
Init: Paged + Send + 'static,
Init::SchemaType: QueryRoot,
Init::Input: Clone,
Init::NextPage:
Paged<Input = Init::NextInput, NextInput = Init::NextInput, NextPage = Init::NextPage>,
<Init::NextPage as QueryFragment>::SchemaType: QueryRoot,
<Init::NextPage as Paged>::Input: Clone,
{
async {
let initial: GraphQlResponse<Init> = self.query(vars.clone()).await?;
let mut next_vars = initial.data.as_ref().and_then(|d| d.next_variables(vars));
let mut pages = vec![];
while let Some(vars) = next_vars {
let next_page: GraphQlResponse<Init::NextPage> = self.query(vars.clone()).await?;
next_vars = next_page.data.as_ref().and_then(|d| d.next_variables(vars));
pages.push(next_page);
}
Ok(PagedResponse(initial, pages))
}
}
async fn query<Query, Variables>(
&self,
vars: Variables,
) -> Result<GraphQlResponse<Query>, Self::Error>
where
Variables: QueryVariables + Send + Serialize,
Query: DeserializeOwned + QueryFragment<VariablesFields = Variables::Fields> + 'static,
Query::SchemaType: QueryRoot,
{
use cynic::QueryBuilder as _;
self.run_graphql(Query::build(vars))
}
async fn mutation<Mutation, Vars>(
&self,
vars: Vars,
) -> Result<GraphQlResponse<Mutation>, Self::Error>
where
Vars: QueryVariables + Send + Serialize,
Mutation: DeserializeOwned + QueryFragment<VariablesFields = Vars::Fields> + 'static,
Mutation::SchemaType: MutationRoot,
{
use cynic::MutationBuilder as _;
self.run_graphql(Mutation::build(vars))
}
async fn run_graphql<Query, Vars>(
&self,
operation: Operation<Query, Vars>,
) -> Result<GraphQlResponse<Query>, Self::Error>
where
Vars: Serialize + Send,
Query: DeserializeOwned + 'static;
}
#[extension(pub trait GraphQlResponseExt)]
impl<T> GraphQlResponse<T> {
fn try_into_data(self) -> Result<Option<T>, GraphQlErrors> {
if let Some(errors) = self.errors
&& !errors.is_empty()
{
return Err(GraphQlErrors { errors, page: None });
}
let Some(data) = self.data else {
return Ok(None);
};
Ok(Some(data))
}
}
#[derive(thiserror::Error, Clone, Debug, Eq, PartialEq, serde::Deserialize)]
pub struct GraphQlErrors<Extensions = serde::de::IgnoredAny> {
pub errors: Vec<GraphQlError<Extensions>>,
pub page: Option<usize>,
}
impl<Extensions> std::fmt::Display for GraphQlErrors<Extensions> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let page_info = self
.page
.map_or_else(String::new, |page| format!(" at page {page}"));
writeln!(
f,
"Query execution produced the following errors{page_info}:"
)?;
for error in &self.errors {
writeln!(f, "{error}")?;
}
Ok(())
}
}