621 lines
13 KiB
Rust
621 lines
13 KiB
Rust
use async_graphql::*;
|
|
use futures_util::Stream;
|
|
use serde::Deserialize;
|
|
|
|
#[tokio::test]
|
|
pub async fn test_type_visible() {
|
|
#[derive(SimpleObject)]
|
|
#[graphql(visible = false)]
|
|
struct MyObj {
|
|
a: i32,
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn obj(&self) -> MyObj {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({
|
|
"__type": null,
|
|
})
|
|
);
|
|
|
|
#[derive(Deserialize)]
|
|
struct QueryResponse {
|
|
#[serde(rename = "__schema")]
|
|
schema: SchemaResponse,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct SchemaResponse {
|
|
types: Vec<TypeResponse>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct TypeResponse {
|
|
name: String,
|
|
}
|
|
|
|
let resp: QueryResponse = from_value(
|
|
schema
|
|
.execute(r#"{ __schema { types { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
)
|
|
.unwrap();
|
|
|
|
assert!(!resp.schema.types.into_iter().any(|ty| ty.name == "MyObj"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_field_visible() {
|
|
#[derive(SimpleObject)]
|
|
struct MyObj {
|
|
a: i32,
|
|
#[graphql(visible = false)]
|
|
b: i32,
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn obj(&self) -> MyObj {
|
|
todo!()
|
|
}
|
|
|
|
#[graphql(visible = false)]
|
|
async fn c(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct QueryResponse {
|
|
#[serde(rename = "__type")]
|
|
ty: TypeResponse,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct TypeResponse {
|
|
fields: Vec<FieldResposne>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct FieldResposne {
|
|
name: String,
|
|
}
|
|
|
|
let resp: QueryResponse = from_value(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj") { fields { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(
|
|
resp.ty
|
|
.fields
|
|
.iter()
|
|
.map(|field| field.name.as_str())
|
|
.collect::<Vec<_>>(),
|
|
vec!["a"]
|
|
);
|
|
|
|
let resp: QueryResponse = from_value(
|
|
schema
|
|
.execute(r#"{ __type(name: "Query") { fields { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(
|
|
resp.ty
|
|
.fields
|
|
.iter()
|
|
.map(|field| field.name.as_str())
|
|
.collect::<Vec<_>>(),
|
|
vec!["obj"]
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_enum_value_visible() {
|
|
#[derive(Enum, Eq, PartialEq, Copy, Clone)]
|
|
enum MyEnum {
|
|
A,
|
|
B,
|
|
#[graphql(visible = false)]
|
|
C,
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn e(&self) -> MyEnum {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct QueryResponse {
|
|
#[serde(rename = "__type")]
|
|
ty: TypeResponse,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct TypeResponse {
|
|
enum_values: Vec<EnumValueResponse>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct EnumValueResponse {
|
|
name: String,
|
|
}
|
|
|
|
let resp: QueryResponse = from_value(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyEnum") { enumValues { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(
|
|
resp.ty
|
|
.enum_values
|
|
.iter()
|
|
.map(|value| value.name.as_str())
|
|
.collect::<Vec<_>>(),
|
|
vec!["A", "B"]
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_visible_fn() {
|
|
mod nested {
|
|
use async_graphql::Context;
|
|
|
|
pub struct IsAdmin(pub bool);
|
|
|
|
pub fn is_admin(ctx: &Context<'_>) -> bool {
|
|
ctx.data_unchecked::<IsAdmin>().0
|
|
}
|
|
}
|
|
|
|
use nested::IsAdmin;
|
|
|
|
#[derive(SimpleObject)]
|
|
#[graphql(visible = "nested::is_admin")]
|
|
struct MyObj {
|
|
a: i32,
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn obj(&self) -> MyObj {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(Request::new(r#"{ __type(name: "MyObj") { name } }"#).data(IsAdmin(false)))
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({
|
|
"__type": null,
|
|
})
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(Request::new(r#"{ __type(name: "MyObj") { name } }"#).data(IsAdmin(true)))
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({
|
|
"__type": {
|
|
"name": "MyObj",
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn test_indirect_hiding_type() {
|
|
#[derive(SimpleObject)]
|
|
struct MyObj1 {
|
|
a: i32,
|
|
b: MyObj2,
|
|
c: MyObj3,
|
|
}
|
|
|
|
#[derive(SimpleObject)]
|
|
struct MyObj2 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(SimpleObject)]
|
|
struct MyObj3 {
|
|
a: i32,
|
|
#[graphql(visible = false)]
|
|
b: MyObj5,
|
|
}
|
|
|
|
#[derive(SimpleObject)]
|
|
#[graphql(visible = false)]
|
|
struct MyObj4 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(SimpleObject)]
|
|
struct MyObj5 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(InputObject)]
|
|
struct MyInputObj1 {
|
|
a: i32,
|
|
b: MyInputObj2,
|
|
c: MyInputObj3,
|
|
}
|
|
|
|
#[derive(InputObject)]
|
|
struct MyInputObj2 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(InputObject)]
|
|
struct MyInputObj3 {
|
|
a: i32,
|
|
#[graphql(visible = false)]
|
|
b: MyInputObj4,
|
|
}
|
|
|
|
#[derive(InputObject)]
|
|
struct MyInputObj4 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(InputObject)]
|
|
struct MyInputObj5 {
|
|
a: i32,
|
|
}
|
|
|
|
#[derive(Union)]
|
|
enum MyUnion {
|
|
MyObj3(MyObj3),
|
|
MyObj4(MyObj4),
|
|
}
|
|
|
|
#[derive(Interface)]
|
|
#[graphql(field(name = "a", type = "&i32"))]
|
|
enum MyInterface {
|
|
MyObj3(MyObj3),
|
|
MyObj4(MyObj4),
|
|
}
|
|
|
|
#[derive(Interface)]
|
|
#[graphql(visible = false, field(name = "a", type = "&i32"))]
|
|
enum MyInterface2 {
|
|
MyObj3(MyObj3),
|
|
MyObj4(MyObj4),
|
|
}
|
|
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
#[graphql(visible = false)]
|
|
async fn obj1(&self) -> MyObj1 {
|
|
todo!()
|
|
}
|
|
|
|
async fn obj3(&self) -> MyObj3 {
|
|
todo!()
|
|
}
|
|
|
|
#[graphql(visible = false)]
|
|
async fn input_obj1(&self, _obj: MyInputObj1) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn input_obj3(&self, _obj: MyInputObj3) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn input_obj5(&self, #[graphql(visible = false)] _obj: Option<MyInputObj5>) -> i32 {
|
|
todo!()
|
|
}
|
|
|
|
async fn union1(&self) -> MyUnion {
|
|
todo!()
|
|
}
|
|
|
|
async fn interface1(&self) -> MyInterface {
|
|
todo!()
|
|
}
|
|
|
|
async fn interface2(&self) -> MyInterface2 {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj1") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj2") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj3") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "name": "MyObj3" } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj1") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj2") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj3") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "name": "MyInputObj3" } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyUnion") { possibleTypes { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "possibleTypes": [{ "name": "MyObj3" }] } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInterface") { possibleTypes { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "possibleTypes": [{ "name": "MyObj3" }] } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInterface2") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj3") { interfaces { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "interfaces": [{ "name": "MyInterface" }] } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj3") { fields { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "fields": [
|
|
{ "name": "a" },
|
|
]}})
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyObj5") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj3") { inputFields { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": { "inputFields": [
|
|
{ "name": "a" },
|
|
]}})
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj4") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "MyInputObj5") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
pub async fn root() {
|
|
struct Query;
|
|
|
|
#[Object]
|
|
#[allow(unreachable_code)]
|
|
impl Query {
|
|
async fn value(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
struct Mutation;
|
|
|
|
#[Object(visible = false)]
|
|
#[allow(unreachable_code)]
|
|
impl Mutation {
|
|
async fn value(&self) -> i32 {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
struct Subscription;
|
|
|
|
#[Subscription(visible = false)]
|
|
#[allow(unreachable_code)]
|
|
impl Subscription {
|
|
async fn value(&self) -> impl Stream<Item = i32> {
|
|
futures_util::stream::iter(vec![1, 2, 3])
|
|
}
|
|
}
|
|
|
|
let schema = Schema::new(Query, Mutation, Subscription);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "Mutation") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
|
|
let schema = Schema::new(Query, Mutation, Subscription);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __schema { mutationType { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__schema": { "mutationType": null } })
|
|
);
|
|
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __type(name: "Subscription") { name } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__type": null })
|
|
);
|
|
|
|
let schema = Schema::new(Query, Mutation, Subscription);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __schema { subscriptionType { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__schema": { "subscriptionType": null } })
|
|
);
|
|
|
|
let schema = Schema::new(Query, Mutation, Subscription);
|
|
assert_eq!(
|
|
schema
|
|
.execute(r#"{ __schema { queryType { name } } }"#)
|
|
.await
|
|
.into_result()
|
|
.unwrap()
|
|
.data,
|
|
value!({ "__schema": { "queryType": { "name": "Query" } } })
|
|
);
|
|
}
|