Rework Failure #671

This commit is contained in:
Sunli 2021-11-04 19:37:22 +08:00
parent 246d72a9f0
commit d62aca8052
11 changed files with 199 additions and 174 deletions

View File

@ -1,6 +1,9 @@
use std::any::Any;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@ -20,15 +23,13 @@ impl ErrorExtensionValues {
} }
/// An error in a GraphQL server. /// An error in a GraphQL server.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct ServerError { pub struct ServerError {
/// An explanatory message of the error. /// An explanatory message of the error.
pub message: String, pub message: String,
/// An explanatory message of the error. (for debug) /// The concrete error type, comes from [`Failure<T>`].
///
/// This message comes from [`Failure<T>`].
#[serde(skip)] #[serde(skip)]
pub debug_message: Option<String>, pub error: Option<Arc<dyn Any + Send + Sync>>,
/// Where the error occurred. /// Where the error occurred.
#[serde(skip_serializing_if = "Vec::is_empty", default)] #[serde(skip_serializing_if = "Vec::is_empty", default)]
pub locations: Vec<Pos>, pub locations: Vec<Pos>,
@ -44,21 +45,53 @@ fn error_extensions_is_empty(values: &Option<ErrorExtensionValues>) -> bool {
values.as_ref().map_or(true, |values| values.0.is_empty()) values.as_ref().map_or(true, |values| values.0.is_empty())
} }
impl Debug for ServerError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ServerError")
.field("message", &self.message)
.field("locations", &self.locations)
.field("path", &self.path)
.field("extensions", &self.extensions)
.finish()
}
}
impl PartialEq for ServerError {
fn eq(&self, other: &Self) -> bool {
self.message.eq(&other.message)
&& self.locations.eq(&other.locations)
&& self.path.eq(&other.path)
&& self.extensions.eq(&other.extensions)
}
}
impl ServerError { impl ServerError {
/// Create a new server error with the message. /// Create a new server error with the message.
pub fn new(message: impl Into<String>, pos: Option<Pos>) -> Self { pub fn new(message: impl Into<String>, pos: Option<Pos>) -> Self {
Self { Self {
message: message.into(), message: message.into(),
debug_message: None, error: None,
locations: pos.map(|pos| vec![pos]).unwrap_or_default(), locations: pos.map(|pos| vec![pos]).unwrap_or_default(),
path: Vec::new(), path: Vec::new(),
extensions: None, extensions: None,
} }
} }
/// Returns `debug_message` if it is `Some`, otherwise returns `message`. /// Downcast the error object by reference.
pub fn debug_message(&self) -> &str { ///
self.debug_message.as_deref().unwrap_or(&self.message) /// # Examples
///
/// ```rust
/// use std::string::FromUtf8Error;
/// use async_graphql::{Failure, Error, ServerError, Pos};
///
/// let bytes = vec![0, 159];
/// let err: Error = String::from_utf8(bytes).map_err(Failure).unwrap_err().into();
/// let server_err: ServerError = err.into_server_error(Pos { line: 1, column: 1 });
/// assert!(server_err.concrete_error::<FromUtf8Error>().is_some());
/// ```
pub fn concrete_error<T: Any + Send + Sync>(&self) -> Option<&T> {
self.error.as_ref().map(|err| err.downcast_ref()).flatten()
} }
#[doc(hidden)] #[doc(hidden)]
@ -83,7 +116,7 @@ impl From<parser::Error> for ServerError {
fn from(e: parser::Error) -> Self { fn from(e: parser::Error) -> Self {
Self { Self {
message: e.to_string(), message: e.to_string(),
debug_message: None, error: None,
locations: e.positions().collect(), locations: e.positions().collect(),
path: Vec::new(), path: Vec::new(),
extensions: None, extensions: None,
@ -172,24 +205,39 @@ impl<T: InputType, E: Display> From<E> for InputValueError<T> {
pub type InputValueResult<T> = Result<T, InputValueError<T>>; pub type InputValueResult<T> = Result<T, InputValueError<T>>;
/// An error with a message and optional extensions. /// An error with a message and optional extensions.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[derive(Clone, Serialize)]
pub struct Error { pub struct Error {
/// The error message. /// The error message.
pub message: String, pub message: String,
/// The debug error message. /// The concrete error type, comes from [`Failure<T>`].
#[serde(skip)] #[serde(skip)]
pub debug_message: Option<String>, pub error: Option<Arc<dyn Any + Send + Sync>>,
/// Extensions to the error. /// Extensions to the error.
#[serde(skip_serializing_if = "error_extensions_is_empty")] #[serde(skip_serializing_if = "error_extensions_is_empty")]
pub extensions: Option<ErrorExtensionValues>, pub extensions: Option<ErrorExtensionValues>,
} }
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Error")
.field("message", &self.message)
.field("extensions", &self.extensions)
.finish()
}
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
self.message.eq(&other.message) && self.extensions.eq(&other.extensions)
}
}
impl Error { impl Error {
/// Create an error from the given error message. /// Create an error from the given error message.
pub fn new(message: impl Into<String>) -> Self { pub fn new(message: impl Into<String>) -> Self {
Self { Self {
message: message.into(), message: message.into(),
debug_message: None, error: None,
extensions: None, extensions: None,
} }
} }
@ -199,7 +247,7 @@ impl Error {
pub fn into_server_error(self, pos: Pos) -> ServerError { pub fn into_server_error(self, pos: Pos) -> ServerError {
ServerError { ServerError {
message: self.message, message: self.message,
debug_message: self.debug_message, error: self.error,
locations: vec![pos], locations: vec![pos],
path: Vec::new(), path: Vec::new(),
extensions: self.extensions, extensions: self.extensions,
@ -207,21 +255,21 @@ impl Error {
} }
} }
impl<T: Display> From<T> for Error { impl<T: Display + Send + Sync + 'static> From<T> for Error {
fn from(e: T) -> Self { fn from(e: T) -> Self {
Self { Self {
message: e.to_string(), message: e.to_string(),
debug_message: None, error: None,
extensions: None, extensions: None,
} }
} }
} }
impl<T: Display + Debug> From<Failure<T>> for Error { impl<T: StdError + Send + Sync + 'static> From<Failure<T>> for Error {
fn from(err: Failure<T>) -> Self { fn from(e: Failure<T>) -> Self {
Self { Self {
message: format!("{}", err.0), message: e.0.to_string(),
debug_message: Some(format!("{:?}", err.0)), error: Some(Arc::new(e.0)),
extensions: None, extensions: None,
} }
} }
@ -307,7 +355,7 @@ pub trait ErrorExtensions: Sized {
let Error { let Error {
message, message,
debug_message, error,
extensions, extensions,
} = self.extend(); } = self.extend();
@ -316,7 +364,7 @@ pub trait ErrorExtensions: Sized {
Error { Error {
message, message,
debug_message, error,
extensions: Some(extensions), extensions: Some(extensions),
} }
} }
@ -330,17 +378,17 @@ impl ErrorExtensions for Error {
// implementing for &E instead of E gives the user the possibility to implement for E which does // implementing for &E instead of E gives the user the possibility to implement for E which does
// not conflict with this implementation acting as a fallback. // not conflict with this implementation acting as a fallback.
impl<E: std::fmt::Display> ErrorExtensions for &E { impl<E: Display> ErrorExtensions for &E {
fn extend(self) -> Error { fn extend(self) -> Error {
Error { Error {
message: self.to_string(), message: self.to_string(),
debug_message: None, error: None,
extensions: None, extensions: None,
} }
} }
} }
impl<T: Display + Debug> ErrorExtensions for Failure<T> { impl<T: StdError + Send + Sync + 'static> ErrorExtensions for Failure<T> {
fn extend(self) -> Error { fn extend(self) -> Error {
Error::from(self) Error::from(self)
} }
@ -381,19 +429,17 @@ where
} }
} }
/// An error type contains `T` that implements `Display` and `Debug`. /// A wrapper around a dynamic error type.
///
/// This type can solve the problem described in [#671](https://github.com/async-graphql/async-graphql/issues/671).
#[derive(Debug)] #[derive(Debug)]
pub struct Failure<T>(pub T); pub struct Failure<T>(pub T);
impl<T: Display + Debug> From<T> for Failure<T> { impl<T: Any + Send + Sync> From<T> for Failure<T> {
fn from(err: T) -> Self { fn from(err: T) -> Self {
Self(err) Self(err)
} }
} }
impl<T: Display + Debug> Failure<T> { impl<T: Any + Send + Sync> Failure<T> {
/// Create a new failure. /// Create a new failure.
#[inline] #[inline]
pub fn new(err: T) -> Self { pub fn new(err: T) -> Self {

View File

@ -851,7 +851,7 @@ impl From<RuleError> for ServerError {
fn from(e: RuleError) -> Self { fn from(e: RuleError) -> Self {
Self { Self {
message: e.message, message: e.message,
debug_message: None, error: None,
locations: e.locations, locations: e.locations,
path: Vec::new(), path: Vec::new(),
extensions: e.extensions, extensions: e.extensions,

View File

@ -1,5 +1,4 @@
use async_graphql::*; use async_graphql::*;
use std::fmt::{self, Display, Formatter};
#[tokio::test] #[tokio::test]
pub async fn test_error_extensions() { pub async fn test_error_extensions() {
@ -79,13 +78,13 @@ pub async fn test_error_extensions() {
#[tokio::test] #[tokio::test]
pub async fn test_failure() { pub async fn test_failure() {
#[derive(Debug)] #[derive(thiserror::Error, Debug, PartialEq)]
struct MyError; enum MyError {
#[error("error1")]
Error1,
impl Display for MyError { #[error("error2")]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Error2,
write!(f, "my error")
}
} }
struct Query; struct Query;
@ -93,23 +92,23 @@ pub async fn test_failure() {
#[Object] #[Object]
impl Query { impl Query {
async fn failure(&self) -> Result<i32> { async fn failure(&self) -> Result<i32> {
Err(Failure(MyError).into()) Err(Failure(MyError::Error1).into())
} }
async fn failure2(&self) -> Result<i32> { async fn failure2(&self) -> Result<i32> {
Err(Failure(MyError))?; Err(Failure(MyError::Error2))?;
Ok(1) Ok(1)
} }
async fn failure3(&self) -> Result<i32> { async fn failure3(&self) -> Result<i32> {
Err(Failure(MyError) Err(Failure(MyError::Error1)
.extend_with(|_, values| values.set("a", 1)) .extend_with(|_, values| values.set("a", 1))
.extend_with(|_, values| values.set("b", 2)))?; .extend_with(|_, values| values.set("b", 2)))?;
Ok(1) Ok(1)
} }
async fn failure4(&self) -> Result<i32> { async fn failure4(&self) -> Result<i32> {
Err(Failure(MyError)) Err(Failure(MyError::Error2))
.extend_err(|_, values| values.set("a", 1)) .extend_err(|_, values| values.set("a", 1))
.extend_err(|_, values| values.set("b", 2))?; .extend_err(|_, values| values.set("b", 2))?;
Ok(1) Ok(1)
@ -117,73 +116,53 @@ pub async fn test_failure() {
} }
let schema = Schema::new(Query, EmptyMutation, EmptySubscription); let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
let err = schema
.execute("{ failure }")
.await
.into_result()
.unwrap_err()
.remove(0);
assert_eq!(err.concrete_error::<MyError>().unwrap(), &MyError::Error1);
let err = schema
.execute("{ failure2 }")
.await
.into_result()
.unwrap_err()
.remove(0);
assert_eq!(err.concrete_error::<MyError>().unwrap(), &MyError::Error2);
let err = schema
.execute("{ failure3 }")
.await
.into_result()
.unwrap_err()
.remove(0);
assert_eq!(err.concrete_error::<MyError>().unwrap(), &MyError::Error1);
assert_eq!( assert_eq!(
schema err.extensions,
.execute("{ failure }") Some({
.await let mut values = ErrorExtensionValues::default();
.into_result() values.set("a", 1);
.unwrap_err(), values.set("b", 2);
vec![ServerError { values
message: "my error".to_string(), })
debug_message: Some("MyError".to_string()),
locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("failure".to_string())],
extensions: None
}]
); );
let err = schema
.execute("{ failure4 }")
.await
.into_result()
.unwrap_err()
.remove(0);
assert_eq!(err.concrete_error::<MyError>().unwrap(), &MyError::Error2);
assert_eq!( assert_eq!(
schema err.extensions,
.execute("{ failure2 }") Some({
.await let mut values = ErrorExtensionValues::default();
.into_result() values.set("a", 1);
.unwrap_err(), values.set("b", 2);
vec![ServerError { values
message: "my error".to_string(), })
debug_message: Some("MyError".to_string()),
locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("failure2".to_string())],
extensions: None
}]
);
assert_eq!(
schema
.execute("{ failure3 }")
.await
.into_result()
.unwrap_err(),
vec![ServerError {
message: "my error".to_string(),
debug_message: Some("MyError".to_string()),
locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("failure3".to_string())],
extensions: Some({
let mut values = ErrorExtensionValues::default();
values.set("a", 1);
values.set("b", 2);
values
})
}]
);
assert_eq!(
schema
.execute("{ failure4 }")
.await
.into_result()
.unwrap_err(),
vec![ServerError {
message: "my error".to_string(),
debug_message: Some("MyError".to_string()),
locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("failure4".to_string())],
extensions: Some({
let mut values = ErrorExtensionValues::default();
values.set("a", 1);
values.set("b", 2);
values
})
}]
); );
} }

View File

@ -242,7 +242,7 @@ pub async fn test_find_entity_with_context() {
schema.execute(query).await.into_result().unwrap_err(), schema.execute(query).await.into_result().unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Not found".to_string(), message: "Not found".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 2, line: 2,
column: 13 column: 13

View File

@ -85,7 +85,7 @@ pub async fn test_field_features() {
vec![ServerError { vec![ServerError {
message: r#"Unknown field "valueAbc" on type "QueryRoot". Did you mean "value"?"# message: r#"Unknown field "valueAbc" on type "QueryRoot". Did you mean "value"?"#
.to_owned(), .to_owned(),
debug_message: None, error: None,
locations: vec![Pos { column: 3, line: 1 }], locations: vec![Pos { column: 3, line: 1 }],
path: Vec::new(), path: Vec::new(),
extensions: None, extensions: None,
@ -114,7 +114,7 @@ pub async fn test_field_features() {
vec![ServerError { vec![ServerError {
message: r#"Unknown field "valueAbc" on type "MyObj". Did you mean "value"?"# message: r#"Unknown field "valueAbc" on type "MyObj". Did you mean "value"?"#
.to_owned(), .to_owned(),
debug_message: None, error: None,
locations: vec![Pos { column: 9, line: 1 }], locations: vec![Pos { column: 9, line: 1 }],
path: Vec::new(), path: Vec::new(),
extensions: None, extensions: None,
@ -150,7 +150,7 @@ pub async fn test_field_features() {
.errors, .errors,
vec![ServerError { vec![ServerError {
message: r#"Unknown field "valuesAbc" on type "SubscriptionRoot". Did you mean "values", "valuesBson"?"#.to_owned(), message: r#"Unknown field "valuesAbc" on type "SubscriptionRoot". Did you mean "values", "valuesBson"?"#.to_owned(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
column: 16, column: 16,
line: 1 line: 1

View File

@ -99,7 +99,7 @@ pub async fn test_guard_simple_rule() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -128,7 +128,7 @@ pub async fn test_guard_simple_rule() {
.errors, .errors,
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 16 column: 16
@ -178,7 +178,7 @@ pub async fn test_guard_and_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -198,7 +198,7 @@ pub async fn test_guard_and_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -218,7 +218,7 @@ pub async fn test_guard_and_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -288,7 +288,7 @@ pub async fn test_guard_or_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -338,7 +338,7 @@ pub async fn test_guard_chain_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -359,7 +359,7 @@ pub async fn test_guard_chain_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -380,7 +380,7 @@ pub async fn test_guard_chain_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -401,7 +401,7 @@ pub async fn test_guard_chain_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -493,7 +493,7 @@ pub async fn test_guard_race_operator() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("value".to_owned())], path: vec![PathSegment::Field("value".to_owned())],
extensions: None, extensions: None,
@ -549,7 +549,7 @@ pub async fn test_guard_use_params() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "Forbidden".to_string(), message: "Forbidden".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("get".to_owned())], path: vec![PathSegment::Field("get".to_owned())],
extensions: None, extensions: None,

View File

@ -67,7 +67,7 @@ pub async fn test_input_validator_string_min_length() {
.expect_err(&should_fail_msg), .expect_err(&should_fail_msg),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -85,7 +85,7 @@ pub async fn test_input_validator_string_min_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -179,7 +179,7 @@ pub async fn test_input_validator_string_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -197,7 +197,7 @@ pub async fn test_input_validator_string_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -290,7 +290,7 @@ pub async fn test_input_validator_chars_min_length() {
.expect_err(&should_fail_msg), .expect_err(&should_fail_msg),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -308,7 +308,7 @@ pub async fn test_input_validator_chars_min_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -403,7 +403,7 @@ pub async fn test_input_validator_chars_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -421,7 +421,7 @@ pub async fn test_input_validator_chars_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -542,7 +542,7 @@ pub async fn test_input_validator_string_email() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -561,7 +561,7 @@ pub async fn test_input_validator_string_email() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -692,7 +692,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg.clone(), message: field_error_msg.clone(),
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -711,7 +711,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg.clone(), message: object_error_msg.clone(),
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -729,7 +729,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -748,7 +748,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -806,7 +806,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -825,7 +825,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -867,7 +867,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -886,7 +886,7 @@ pub async fn test_input_validator_string_mac() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -947,7 +947,7 @@ pub async fn test_input_validator_int_range() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -965,7 +965,7 @@ pub async fn test_input_validator_int_range() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1054,7 +1054,7 @@ pub async fn test_input_validator_int_less_than() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1072,7 +1072,7 @@ pub async fn test_input_validator_int_less_than() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1163,7 +1163,7 @@ pub async fn test_input_validator_int_greater_than() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1181,7 +1181,7 @@ pub async fn test_input_validator_int_greater_than() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1265,7 +1265,7 @@ pub async fn test_input_validator_int_nonzero() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1283,7 +1283,7 @@ pub async fn test_input_validator_int_nonzero() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1371,7 +1371,7 @@ pub async fn test_input_validator_int_equal() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1389,7 +1389,7 @@ pub async fn test_input_validator_int_equal() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1489,7 +1489,7 @@ pub async fn test_input_validator_list_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1507,7 +1507,7 @@ pub async fn test_input_validator_list_max_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1607,7 +1607,7 @@ pub async fn test_input_validator_list_min_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1625,7 +1625,7 @@ pub async fn test_input_validator_list_min_length() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1733,7 +1733,7 @@ pub async fn test_input_validator_operator_or() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1751,7 +1751,7 @@ pub async fn test_input_validator_operator_or() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1852,7 +1852,7 @@ pub async fn test_input_validator_operator_and() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17
@ -1870,7 +1870,7 @@ pub async fn test_input_validator_operator_and() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 14 column: 14
@ -1974,7 +1974,7 @@ pub async fn test_input_validator_variable() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: field_error_msg, message: field_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 37 column: 37
@ -1992,7 +1992,7 @@ pub async fn test_input_validator_variable() {
.expect_err(&should_fail_msg[..]), .expect_err(&should_fail_msg[..]),
vec![ServerError { vec![ServerError {
message: object_error_msg, message: object_error_msg,
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 34 column: 34
@ -2079,7 +2079,7 @@ pub async fn test_custom_input_validator_with_extensions() {
.expect_err(should_fail_msg), .expect_err(should_fail_msg),
vec![ServerError { vec![ServerError {
message: field_error_msg.into(), message: field_error_msg.into(),
debug_message: None, error: None,
locations: vec!(Pos { locations: vec!(Pos {
line: 1, line: 1,
column: 17 column: 17

View File

@ -18,7 +18,7 @@ pub async fn test_input_value_custom_error() {
vec![ServerError { vec![ServerError {
message: "Failed to parse \"Int\": Only integers from -128 to 127 are accepted." message: "Failed to parse \"Int\": Only integers from -128 to 127 are accepted."
.to_owned(), .to_owned(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 14, column: 14,

View File

@ -167,7 +167,7 @@ pub async fn test_array_type() {
vec![ServerError { vec![ServerError {
message: r#"Failed to parse "[Int!]": Expected input type "[Int; 6]", found [Int; 5]."# message: r#"Failed to parse "[Int!]": Expected input type "[Int; 6]", found [Int; 5]."#
.to_owned(), .to_owned(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 22, column: 22,

View File

@ -34,14 +34,14 @@ pub async fn test_fieldresult() {
errors: vec![ errors: vec![
ServerError { ServerError {
message: "TestError".to_string(), message: "TestError".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("error1".to_owned())], path: vec![PathSegment::Field("error1".to_owned())],
extensions: None, extensions: None,
}, },
ServerError { ServerError {
message: "TestError".to_string(), message: "TestError".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 19, column: 19,
@ -62,7 +62,7 @@ pub async fn test_fieldresult() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "TestError".to_string(), message: "TestError".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![PathSegment::Field("optError".to_owned())], path: vec![PathSegment::Field("optError".to_owned())],
extensions: None, extensions: None,
@ -77,7 +77,7 @@ pub async fn test_fieldresult() {
.unwrap_err(), .unwrap_err(),
vec![ServerError { vec![ServerError {
message: "TestError".to_string(), message: "TestError".to_string(),
debug_message: None, error: None,
locations: vec![Pos { line: 1, column: 3 }], locations: vec![Pos { line: 1, column: 3 }],
path: vec![ path: vec![
PathSegment::Field("vecError".to_owned()), PathSegment::Field("vecError".to_owned()),
@ -192,7 +192,7 @@ pub async fn test_error_propagation() {
cache_control: Default::default(), cache_control: Default::default(),
errors: vec![ServerError { errors: vec![ServerError {
message: "myerror".to_string(), message: "myerror".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 20, column: 20,
@ -220,7 +220,7 @@ pub async fn test_error_propagation() {
cache_control: Default::default(), cache_control: Default::default(),
errors: vec![ServerError { errors: vec![ServerError {
message: "myerror".to_string(), message: "myerror".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 23, column: 23,
@ -244,7 +244,7 @@ pub async fn test_error_propagation() {
cache_control: Default::default(), cache_control: Default::default(),
errors: vec![ServerError { errors: vec![ServerError {
message: "myerror".to_string(), message: "myerror".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 23, column: 23,
@ -274,7 +274,7 @@ pub async fn test_error_propagation() {
cache_control: Default::default(), cache_control: Default::default(),
errors: vec![ServerError { errors: vec![ServerError {
message: "myerror".to_string(), message: "myerror".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 23, column: 23,

View File

@ -345,7 +345,7 @@ pub async fn test_subscription_error() {
stream.next().await, stream.next().await,
Some(Err(vec![ServerError { Some(Err(vec![ServerError {
message: "TestError".to_string(), message: "TestError".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 25 column: 25
@ -391,7 +391,7 @@ pub async fn test_subscription_fieldresult() {
cache_control: Default::default(), cache_control: Default::default(),
errors: vec![ServerError { errors: vec![ServerError {
message: "StreamErr".to_string(), message: "StreamErr".to_string(),
debug_message: None, error: None,
locations: vec![Pos { locations: vec![Pos {
line: 1, line: 1,
column: 16 column: 16