sui-graphql-client 0.0.7

Sui GraphQL RPC Client for the Sui Blockchain
Documentation
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::num::ParseIntError;
use std::num::TryFromIntError;

use cynic::GraphQlError;

use sui_types::AddressParseError;
use sui_types::DigestParseError;
use sui_types::TypeParseError;

type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;

pub type Result<T, E = Error> = std::result::Result<T, E>;

/// General error type for the client. It is used to wrap all the possible errors that can occur.
#[derive(Debug)]
pub struct Error {
    inner: Box<InnerError>,
}

/// Error type for the client. It is split into multiple fields to allow for more granular error
/// handling. The `source` field is used to store the original error.
#[derive(Debug)]
struct InnerError {
    /// Error kind.
    kind: Kind,
    /// Errors returned by the GraphQL server.
    query_errors: Option<Vec<GraphQlError>>,
    /// The original error.
    source: Option<BoxError>,
}

#[derive(Debug)]
#[non_exhaustive]
pub enum Kind {
    Deserialization,
    Parse,
    Query,
    Other,
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.inner.source.as_deref().map(|e| e as _)
    }
}

impl Error {
    // Public accessors

    /// Returns the kind of error.
    pub fn kind(&self) -> &Kind {
        &self.inner.kind
    }

    /// Original GraphQL query errors.
    pub fn graphql_errors(&self) -> Option<&[GraphQlError]> {
        self.inner.query_errors.as_deref()
    }

    // Private constructors

    /// Convert the given error into a generic error.
    pub fn from_error<E: Into<BoxError>>(kind: Kind, error: E) -> Self {
        Self {
            inner: Box::new(InnerError {
                kind,
                source: Some(error.into()),
                query_errors: None,
            }),
        }
    }

    /// Special constructor for queries that expect to return data but it's none.
    pub fn empty_response_error() -> Self {
        Self {
            inner: Box::new(InnerError {
                kind: Kind::Query,
                source: Some("Expected a non-empty response data from query".into()),
                query_errors: None,
            }),
        }
    }

    /// Create a Query kind of error with the original graphql errors.
    pub fn graphql_error(errors: Vec<GraphQlError>) -> Self {
        Self {
            inner: Box::new(InnerError {
                kind: Kind::Query,
                source: None,
                query_errors: Some(errors),
            }),
        }
    }
}

impl std::fmt::Display for Kind {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Kind::Deserialization => write!(f, "Deserialization error:"),
            Kind::Parse => write!(f, "Parse error:"),
            Kind::Query => write!(f, "Query error:"),
            Kind::Other => write!(f, "Error:"),
        }
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", self.inner.kind)?;

        if let Some(source) = &self.inner.source {
            writeln!(f, " {source}")?;
        }
        Ok(())
    }
}

impl From<bcs::Error> for Error {
    fn from(error: bcs::Error) -> Self {
        Self::from_error(Kind::Deserialization, error)
    }
}

impl From<reqwest::Error> for Error {
    fn from(error: reqwest::Error) -> Self {
        Self::from_error(Kind::Other, error)
    }
}

impl From<url::ParseError> for Error {
    fn from(error: url::ParseError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<ParseIntError> for Error {
    fn from(error: ParseIntError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<AddressParseError> for Error {
    fn from(error: AddressParseError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<base64ct::Error> for Error {
    fn from(error: base64ct::Error) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<chrono::ParseError> for Error {
    fn from(error: chrono::ParseError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<DigestParseError> for Error {
    fn from(error: DigestParseError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<TryFromIntError> for Error {
    fn from(error: TryFromIntError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}

impl From<TypeParseError> for Error {
    fn from(error: TypeParseError) -> Self {
        Self::from_error(Kind::Parse, error)
    }
}