293 lines
7.9 KiB
Rust
293 lines
7.9 KiB
Rust
use async_graphql::*;
|
|
use futures_util::stream::Stream;
|
|
|
|
#[tokio::test]
|
|
pub async fn test_fieldresult() {
|
|
struct Query;
|
|
|
|
#[Object]
|
|
impl Query {
|
|
async fn error(&self) -> Result<i32> {
|
|
Err("TestError".into())
|
|
}
|
|
|
|
async fn opt_error(&self) -> Option<Result<i32>> {
|
|
Some(Err("TestError".into()))
|
|
}
|
|
|
|
async fn vec_error(&self) -> Vec<Result<i32>> {
|
|
vec![Ok(1), Err("TestError".into())]
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
assert_eq!(
|
|
schema.execute("{ error1:optError error2:optError }").await,
|
|
Response {
|
|
data: value!({
|
|
"error1": null,
|
|
"error2": null,
|
|
}),
|
|
extensions: Default::default(),
|
|
cache_control: Default::default(),
|
|
errors: vec![
|
|
ServerError {
|
|
message: "TestError".to_string(),
|
|
source: None,
|
|
locations: vec![Pos { line: 1, column: 3 }],
|
|
path: vec![PathSegment::Field("error1".to_owned())],
|
|
extensions: None,
|
|
},
|
|
ServerError {
|
|
message: "TestError".to_string(),
|
|
source: None,
|
|
locations: vec![Pos {
|
|
line: 1,
|
|
column: 19,
|
|
}],
|
|
path: vec![PathSegment::Field("error2".to_owned())],
|
|
extensions: None,
|
|
},
|
|
],
|
|
http_headers: Default::default(),
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute("{ optError }")
|
|
.await
|
|
.into_result()
|
|
.unwrap_err(),
|
|
vec![ServerError {
|
|
message: "TestError".to_string(),
|
|
source: None,
|
|
locations: vec![Pos { line: 1, column: 3 }],
|
|
path: vec![PathSegment::Field("optError".to_owned())],
|
|
extensions: None,
|
|
}]
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute("{ vecError }")
|
|
.await
|
|
.into_result()
|
|
.unwrap_err(),
|
|
vec![ServerError {
|
|
message: "TestError".to_string(),
|
|
source: None,
|
|
locations: vec![Pos { line: 1, column: 3 }],
|
|
path: vec![
|
|
PathSegment::Field("vecError".to_owned()),
|
|
PathSegment::Index(1)
|
|
],
|
|
extensions: None,
|
|
}]
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_custom_error() {
|
|
#[derive(Clone)]
|
|
struct MyError;
|
|
|
|
impl From<MyError> for Error {
|
|
fn from(_: MyError) -> Self {
|
|
Error::new("custom error")
|
|
}
|
|
}
|
|
|
|
#[derive(SimpleObject)]
|
|
#[graphql(complex)]
|
|
struct MyObj {
|
|
value1: i32,
|
|
}
|
|
|
|
#[ComplexObject]
|
|
impl MyObj {
|
|
async fn value2(&self) -> Result<i32, MyError> {
|
|
Err(MyError)
|
|
}
|
|
}
|
|
|
|
#[derive(Interface)]
|
|
#[graphql(field(name = "value2", type = "i32"))]
|
|
enum MyInterface {
|
|
MyObj(MyObj),
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
impl Query {
|
|
async fn value(&self) -> Result<i32, MyError> {
|
|
Err(MyError)
|
|
}
|
|
}
|
|
|
|
struct Subscription;
|
|
|
|
#[Subscription]
|
|
impl Subscription {
|
|
async fn value1(&self) -> Result<impl Stream<Item = i32>, MyError> {
|
|
Err::<futures_util::stream::Once<futures_util::future::Ready<i32>>, _>(MyError)
|
|
}
|
|
|
|
async fn value2(&self) -> impl Stream<Item = Result<i32, MyError>> {
|
|
futures_util::stream::once(async move { Err(MyError) })
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_error_propagation() {
|
|
struct ParentObject;
|
|
|
|
#[Object]
|
|
impl ParentObject {
|
|
async fn child(&self) -> ChildObject {
|
|
ChildObject
|
|
}
|
|
|
|
async fn child_opt(&self) -> Option<ChildObject> {
|
|
Some(ChildObject)
|
|
}
|
|
}
|
|
|
|
struct ChildObject;
|
|
|
|
#[Object]
|
|
impl ChildObject {
|
|
async fn name(&self) -> Result<i32> {
|
|
Err("myerror".into())
|
|
}
|
|
|
|
async fn name_opt(&self) -> Option<Result<i32>> {
|
|
Some(Err("myerror".into()))
|
|
}
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
impl Query {
|
|
async fn parent(&self) -> ParentObject {
|
|
ParentObject
|
|
}
|
|
|
|
async fn parent_opt(&self) -> Option<ParentObject> {
|
|
Some(ParentObject)
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
assert_eq!(
|
|
schema.execute("{ parent { child { name } } }").await,
|
|
Response {
|
|
data: Value::Null,
|
|
extensions: Default::default(),
|
|
cache_control: Default::default(),
|
|
errors: vec![ServerError {
|
|
message: "myerror".to_string(),
|
|
source: None,
|
|
locations: vec![Pos {
|
|
line: 1,
|
|
column: 20,
|
|
}],
|
|
path: vec![
|
|
PathSegment::Field("parent".to_owned()),
|
|
PathSegment::Field("child".to_owned()),
|
|
PathSegment::Field("name".to_owned()),
|
|
],
|
|
extensions: None,
|
|
}],
|
|
http_headers: Default::default(),
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
schema.execute("{ parent { childOpt { name } } }").await,
|
|
Response {
|
|
data: value!({
|
|
"parent": {
|
|
"childOpt": null,
|
|
}
|
|
}),
|
|
extensions: Default::default(),
|
|
cache_control: Default::default(),
|
|
errors: vec![ServerError {
|
|
message: "myerror".to_string(),
|
|
source: None,
|
|
locations: vec![Pos {
|
|
line: 1,
|
|
column: 23,
|
|
}],
|
|
path: vec![
|
|
PathSegment::Field("parent".to_owned()),
|
|
PathSegment::Field("childOpt".to_owned()),
|
|
PathSegment::Field("name".to_owned()),
|
|
],
|
|
extensions: None,
|
|
}],
|
|
http_headers: Default::default(),
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
schema.execute("{ parentOpt { child { name } } }").await,
|
|
Response {
|
|
data: value!({ "parentOpt": null }),
|
|
extensions: Default::default(),
|
|
cache_control: Default::default(),
|
|
errors: vec![ServerError {
|
|
message: "myerror".to_string(),
|
|
source: None,
|
|
locations: vec![Pos {
|
|
line: 1,
|
|
column: 23,
|
|
}],
|
|
path: vec![
|
|
PathSegment::Field("parentOpt".to_owned()),
|
|
PathSegment::Field("child".to_owned()),
|
|
PathSegment::Field("name".to_owned()),
|
|
],
|
|
extensions: None,
|
|
}],
|
|
http_headers: Default::default(),
|
|
}
|
|
);
|
|
|
|
assert_eq!(
|
|
schema.execute("{ parentOpt { child { nameOpt } } }").await,
|
|
Response {
|
|
data: value!({
|
|
"parentOpt": {
|
|
"child": {
|
|
"nameOpt": null,
|
|
}
|
|
},
|
|
}),
|
|
extensions: Default::default(),
|
|
cache_control: Default::default(),
|
|
errors: vec![ServerError {
|
|
message: "myerror".to_string(),
|
|
source: None,
|
|
locations: vec![Pos {
|
|
line: 1,
|
|
column: 23,
|
|
}],
|
|
path: vec![
|
|
PathSegment::Field("parentOpt".to_owned()),
|
|
PathSegment::Field("child".to_owned()),
|
|
PathSegment::Field("nameOpt".to_owned()),
|
|
],
|
|
extensions: None,
|
|
}],
|
|
http_headers: Default::default(),
|
|
}
|
|
);
|
|
}
|