use std::borrow::Cow;
use dynamic_graphql::App;
use dynamic_graphql::FieldValue;
use dynamic_graphql::InputObject;
use dynamic_graphql::ResolvedObject;
use dynamic_graphql::ResolvedObjectFields;
use dynamic_graphql::SimpleObject;
use dynamic_graphql::dynamic::DynamicRequestExt;
use dynamic_graphql::internal::Object;
use dynamic_graphql::internal::Register;
use dynamic_graphql::internal::TypeName;
use crate::schema_utils::normalize_schema;
#[test]
fn test_impl_resolved_object() {
#[derive(ResolvedObject)]
struct Example;
impl Register for Example {}
assert_eq!(<Example as Object>::get_object_type_name(), "Example");
}
#[test]
fn test_impl_resolved_object_with_name() {
#[derive(ResolvedObject)]
#[graphql(name = "Other")]
struct Example;
impl Register for Example {}
assert_eq!(<Example as Object>::get_object_type_name(), "Other");
}
#[test]
fn test_schema() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
fn the_string(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
theString: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
}
#[test]
fn test_schema_with_rename() {
#[derive(ResolvedObject)]
#[graphql(name = "Other")]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
#[graphql(name = "other")]
fn string(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Other {
other: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Other
}
"#);
}
#[test]
fn test_schema_with_type_name() {
#[derive(ResolvedObject)]
#[graphql(root)]
#[graphql(get_type_name)]
struct Query;
impl TypeName for Query {
fn get_type_name() -> Cow<'static, str> {
"Other".into()
}
}
#[ResolvedObjectFields]
impl Query {
fn the_string(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Other {
theString: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Other
}
"#);
}
#[test]
fn test_schema_with_skip() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
fn string(&self) -> String {
"Hello".to_string()
}
#[graphql(skip)]
#[allow(dead_code)]
fn other(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
string: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
}
#[tokio::test]
async fn test_query() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query {
value: String,
}
#[ResolvedObjectFields]
impl Query {
fn string(&self) -> String {
"Hello".to_string()
}
fn value(&self) -> &String {
&self.value
}
fn other(&self) -> &str {
&self.value
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
string: String!
value: String!
other: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
let query = r#"
query {
string
value
other
}
"#;
let root = Query {
value: "Hello".to_string(),
};
let req = dynamic_graphql::Request::new(query).root_value(FieldValue::owned_any(root));
let res = schema.execute(req).await;
let data = res.data.into_json().unwrap();
assert_eq!(
data,
serde_json::json!(
{
"string": "Hello",
"value": "Hello",
"other": "Hello",
}
)
);
}
#[test]
fn test_schema_with_doc() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
fn string(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
"this is the query object"
type Query {
"this is the string field"
string: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
}
#[test]
fn test_schema_with_deprecation() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
#[graphql(deprecation)]
fn deprecated(&self) -> String {
"Hello".to_string()
}
#[graphql(deprecation = "this is the old one")]
fn with_reason(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
deprecated: String! @deprecated
withReason: String! @deprecated(reason: "this is the old one")
}
"Marks an element of a GraphQL schema as no longer supported."
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
}
#[test]
fn test_rename_fields() {
#[derive(ResolvedObject)]
#[allow(non_camel_case_types)]
#[graphql(root)]
struct the_query;
#[ResolvedObjectFields]
#[graphql(rename_fields = "snake_case")]
impl the_query {
fn the_string(&self) -> String {
"Hello".to_string()
}
}
#[derive(App)]
struct App(the_query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type TheQuery {
the_string: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: TheQuery
}
"#);
}
#[tokio::test]
async fn test_async_query() {
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query {
value: String,
}
#[ResolvedObjectFields]
impl Query {
async fn string(&self) -> String {
"Hello".to_string()
}
async fn value(&self) -> &String {
&self.value
}
async fn other(&self) -> &str {
&self.value
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
string: String!
value: String!
other: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
let query = r#"
query {
string
value
other
}
"#;
let root = Query {
value: "Hello".to_string(),
};
let req = dynamic_graphql::Request::new(query).root_value(FieldValue::owned_any(root));
let res = schema.execute(req).await;
let data = res.data.into_json().unwrap();
assert_eq!(
data,
serde_json::json!(
{
"string": "Hello",
"value": "Hello",
"other": "Hello",
}
)
);
}
#[tokio::test]
async fn test_auto_register() {
#[derive(SimpleObject)]
struct Foo {
value: String,
}
#[derive(SimpleObject)]
struct Example {
value: String,
}
#[derive(InputObject)]
struct ExampleInput {
value: String,
}
#[derive(ResolvedObject)]
#[graphql(register(Foo))]
#[graphql(root)]
struct Query;
#[ResolvedObjectFields]
impl Query {
fn example(&self, input: ExampleInput) -> Example {
Example { value: input.value }
}
}
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Example {
value: String!
}
input ExampleInput {
value: String!
}
type Foo {
value: String!
}
type Query {
example(input: ExampleInput!): Example!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
let query = r#"
query {
example(input: {value: "Hello"}) {
value
}
}
"#;
let root = Query;
let req = dynamic_graphql::Request::new(query).root_value(FieldValue::owned_any(root));
let res = schema.execute(req).await;
let data = res.data.into_json().unwrap();
assert_eq!(
data,
serde_json::json!(
{
"example": {
"value": "Hello",
}
}
)
);
}
mod in_mod {
use dynamic_graphql::App;
use dynamic_graphql::ResolvedObject;
use crate::schema_utils::normalize_schema;
#[derive(ResolvedObject)]
#[graphql(root)]
struct Query;
mod deep {
use dynamic_graphql::ResolvedObjectFields;
#[ResolvedObjectFields]
impl super::Query {
fn the_string(&self) -> String {
"Hello".to_string()
}
}
}
#[test]
fn test_schema() {
#[derive(App)]
struct App(Query);
let schema = App::create_schema().finish().unwrap();
let sdl = schema.sdl();
insta::assert_snapshot!(normalize_schema(&sdl), @r#"
type Query {
theString: String!
}
"Directs the executor to include this field or fragment only when the `if` argument is true."
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
schema {
query: Query
}
"#);
}
}