#![cfg_attr(not(test), deny(clippy::unwrap_used))]
#![cfg_attr(not(test), deny(clippy::expect_used))]
#![cfg_attr(not(test), deny(clippy::panic))]
mod field_type;
mod fragments;
pub(crate) mod operation_limits;
pub(crate) mod query;
mod schema;
mod selection;
use displaydoc::Display;
pub(crate) use field_type::*;
pub(crate) use fragments::*;
pub(crate) use query::Query;
pub(crate) use query::TYPENAME;
pub(crate) use schema::QueryHash;
pub(crate) use schema::Schema;
pub(crate) use schema::SchemaHash;
pub(crate) use selection::*;
use serde::Deserialize;
use serde::Serialize;
use thiserror::Error;
use crate::error::ValidationErrors;
use crate::graphql::ErrorExtension;
use crate::graphql::IntoGraphQLErrors;
use crate::json_ext::Object;
pub(crate) const LINK_DIRECTIVE_NAME: &str = "link";
pub(crate) const LINK_URL_ARGUMENT: &str = "url";
pub(crate) const LINK_AS_ARGUMENT: &str = "as";
#[derive(Error, Debug, Display, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub(crate) enum SpecError {
UnknownFileId,
RecursionLimitExceeded,
InvalidType(String),
InvalidField(String, String),
TransformError(String),
ParseError(ValidationErrors),
ValidationError(ValidationErrors),
UnknownOperation(String),
MultipleOperationWithoutOperationName,
NoOperation,
SubscriptionNotSupported,
QueryHashing(String),
}
pub(crate) const GRAPHQL_VALIDATION_FAILURE_ERROR_KEY: &str = "## GraphQLValidationFailure\n";
impl SpecError {
pub(crate) const fn get_error_key(&self) -> &'static str {
match self {
SpecError::TransformError(_) | SpecError::ParseError(_) => "## GraphQLParseFailure\n",
SpecError::UnknownOperation(_) => "## GraphQLUnknownOperationName\n",
_ => GRAPHQL_VALIDATION_FAILURE_ERROR_KEY,
}
}
}
impl ErrorExtension for SpecError {
fn extension_code(&self) -> String {
match self {
SpecError::UnknownFileId => "GRAPHQL_VALIDATION_FAILED",
SpecError::RecursionLimitExceeded => "RECURSION_LIMIT_EXCEEDED",
SpecError::InvalidType(_) => "INVALID_TYPE",
SpecError::InvalidField(_, _) => "INVALID_FIELD",
SpecError::TransformError(_) => "PARSING_ERROR",
SpecError::ParseError(_) => "PARSING_ERROR",
SpecError::ValidationError(_) => "GRAPHQL_VALIDATION_FAILED",
SpecError::UnknownOperation(_) => "GRAPHQL_VALIDATION_FAILED",
SpecError::MultipleOperationWithoutOperationName => "GRAPHQL_VALIDATION_FAILED",
SpecError::NoOperation => "GRAPHQL_VALIDATION_FAILED",
SpecError::SubscriptionNotSupported => "SUBSCRIPTION_NOT_SUPPORTED",
SpecError::QueryHashing(_) => "QUERY_HASHING",
}
.to_string()
}
fn custom_extension_details(&self) -> Option<Object> {
let mut obj = Object::new();
match self {
SpecError::InvalidType(ty) => {
obj.insert("type", ty.clone().into());
}
SpecError::InvalidField(field, ty) => {
obj.insert("type", ty.clone().into());
obj.insert("field", field.clone().into());
}
_ => (),
}
(!obj.is_empty()).then_some(obj)
}
}
impl IntoGraphQLErrors for SpecError {
fn into_graphql_errors(self) -> Result<Vec<crate::graphql::Error>, Self> {
match self {
SpecError::ParseError(e) => {
Ok(e.errors
.into_iter()
.map(|error| {
crate::graphql::Error::builder()
.message(format!("parsing error: {}", error.message))
.locations(
error
.locations
.into_iter()
.map(|loc| crate::graphql::Location {
line: loc.line as u32,
column: loc.column as u32,
})
.collect(),
)
.extension_code("PARSING_ERROR")
.build()
})
.collect())
}
SpecError::ValidationError(e) => {
e.into_graphql_errors().map_err(SpecError::ValidationError)
}
_ => {
let gql_err = match self.custom_extension_details() {
Some(extension_details) => crate::graphql::Error::builder()
.message(self.to_string())
.extension_code(self.extension_code())
.extensions(extension_details)
.build(),
None => crate::graphql::Error::builder()
.message(self.to_string())
.extension_code(self.extension_code())
.build(),
};
Ok(vec![gql_err])
}
}
}
}