diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 5abbe95..2f4959b 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -28,6 +28,8 @@ tempfile = "3" async-stream = "0.3" futures-util = "0.3" insta={version="1",features=["json"]} +prettier-please="0.2" +unindent = "0.2" [lib] proc-macro = true diff --git a/derive/src/args/common.rs b/derive/src/args/common.rs index 003e0d8..a4a7ce0 100644 --- a/derive/src/args/common.rs +++ b/derive/src/args/common.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - pub use args::*; pub use clippy_error::impl_suppress_tupple_clippy_error; pub use fields::*; @@ -274,7 +272,7 @@ where A: CommonArg, { let mut errors = Vec::new(); - let mut types = HashSet::new(); + let mut types = Vec::new(); let fields = object.get_fields()?; fields @@ -293,13 +291,17 @@ where if is_arg_ctx(arg) { return; } - types.insert(&ty.ty); + if !types.contains(&&ty.ty) { + types.push(&ty.ty); + } } }); let ty = field.get_type(); match ty { Ok(ty) => { - types.insert(ty); + if !types.contains(&ty) { + types.push(ty); + } } Err(err) => errors.push(err), }; diff --git a/derive/src/args/common/clippy_error.rs b/derive/src/args/common/clippy_error.rs index a1d6b1b..fd121ea 100644 --- a/derive/src/args/common/clippy_error.rs +++ b/derive/src/args/common/clippy_error.rs @@ -21,7 +21,7 @@ pub fn impl_suppress_tupple_clippy_error( impl #impl_generics #ident #ty_generics #where_clause { #[allow(dead_code)] #[doc(hidden)] - fn _suppress_clippy_error(&self) { + fn __suppress_clippy_error(&self) { #accesses } } diff --git a/derive/src/args/mod.rs b/derive/src/args/mod.rs index 97a80b2..32021e8 100644 --- a/derive/src/args/mod.rs +++ b/derive/src/args/mod.rs @@ -27,4 +27,6 @@ mod resolved_object; mod resolved_object_fields; mod scalar; mod simple_object; +#[cfg(test)] +mod test_output; mod union; diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__app.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__app.snap new file mode 100644 index 0000000..515e34f --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__app.snap @@ -0,0 +1,33 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct App(QueryRoot, PostApp); + +impl dynamic_graphql::internal::Register for App { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let registry = registry.register::(); + registry + } +} +impl App { + pub fn create_schema() -> dynamic_graphql::dynamic::SchemaBuilder { + let registry = dynamic_graphql::internal::Registry::new(); + let registry = registry.register::(); + registry.create_schema() + } +} +impl App { + #[allow(dead_code)] + #[doc(hidden)] + fn __suppress_clippy_error(&self) { + let _ = self.0; + let _ = self.1; + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__enum.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__enum.snap new file mode 100644 index 0000000..efc3c35 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__enum.snap @@ -0,0 +1,93 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +enum Example { + Foo, + Bar, +} + +impl dynamic_graphql::internal::TypeName for Example { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Example".into() + } +} +impl dynamic_graphql::internal::InputTypeName for Example {} +impl dynamic_graphql::internal::OutputTypeName for Example {} +impl dynamic_graphql::internal::Enum for Example {} +impl From<&Example> for dynamic_graphql::Value { + fn from(value: &Example) -> Self { + match value { + Example::Foo => { + dynamic_graphql::Value::Enum(dynamic_graphql::Name::new("FOO")) + } + Example::Bar => { + dynamic_graphql::Value::Enum(dynamic_graphql::Name::new("BAR")) + } + } + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for Example { + fn resolve_owned( + self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::value(&self))) + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for Example { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::value(self))) + } +} +impl dynamic_graphql::internal::FromValue for Example { + fn from_value( + __value: dynamic_graphql::Result, + ) -> dynamic_graphql::internal::InputValueResult { + let __value = __value?; + let string_value = __value.enum_name()?; + match string_value { + "FOO" => Ok(Example::Foo), + "BAR" => Ok(Example::Bar), + _ => { + Err( + dynamic_graphql::internal::InputValueError::custom( + format!( + "Unknown variant `{}` for enum `{}`", string_value, < Example + as dynamic_graphql::internal::Enum > ::get_enum_type_name() + .as_ref() + ), + ), + ) + } + } + } +} +impl dynamic_graphql::internal::Register for Example { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let object = dynamic_graphql::dynamic::Enum::new( + ::get_enum_type_name().as_ref(), + ); + let field = dynamic_graphql::dynamic::EnumItem::new("FOO"); + let object = object.item(field); + let field = dynamic_graphql::dynamic::EnumItem::new("BAR"); + let object = object.item(field); + registry.register_type(object) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__expand_object.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__expand_object.snap new file mode 100644 index 0000000..0ebeb2d --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__expand_object.snap @@ -0,0 +1,90 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct ExampleQuery<'a>(&'a Query); + +impl<'a> ExampleQuery<'a> { + fn __registers( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + registry + } +} +impl<'a> dynamic_graphql::internal::ParentType for ExampleQuery<'a> { + type Type = Query; +} +impl<'a> dynamic_graphql::internal::ExpandObject for ExampleQuery<'a> { + fn get_expand_object_name() -> std::borrow::Cow<'static, str> { + "ExampleQuery".into() + } +} +impl<'a> From<&'a Query> for ExampleQuery<'a> { + fn from(target: &'a Query) -> Self { + Self(target) + } +} +impl<'a> dynamic_graphql::internal::RegisterFns for ExampleQuery<'a> { + const REGISTER_FNS: &'static [fn( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry] = &[ExampleQuery::<'a>::__registers]; +} +impl<'a> ExampleQuery<'a> { + #[allow(dead_code)] + #[doc(hidden)] + fn __suppress_clippy_error(&self) { + let _ = self.0; + } +} + + +impl ExampleQuery<'_> { + fn the_example(&self) -> Example { + Example { + field: "field".to_string(), + } + } +} + +impl dynamic_graphql::internal::Register for ExampleQuery<'_> { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let registry = ::REGISTER_FNS + .iter() + .fold(registry, |registry, f| f(registry)); + let field = dynamic_graphql::dynamic::Field::new( + "theExample", + ::get_output_type_ref(), + |ctx| { + dynamic_graphql::dynamic::FieldFuture::new(async move { + let parent = ctx + .parent_value + .try_downcast_ref::< + ::Type, + >()? + .into(); + let arg0 = &parent; + let value = ExampleQuery::the_example(arg0); + dynamic_graphql::internal::Resolve::resolve(value, &ctx) + }) + }, + ); + let __field_0 = field; + registry + .update_object( + <::Type as dynamic_graphql::internal::Object>::get_object_type_name() + .as_ref(), + ::get_expand_object_name() + .as_ref(), + |object| { + let object = object.field(__field_0); + object + }, + ) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__input_object.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__input_object.snap new file mode 100644 index 0000000..7cc762b --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__input_object.snap @@ -0,0 +1,48 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct ExampleInput { + pub string: String, +} + +impl dynamic_graphql::internal::TypeName for ExampleInput { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "ExampleInput".into() + } +} +impl dynamic_graphql::internal::InputTypeName for ExampleInput {} +impl dynamic_graphql::internal::InputObject for ExampleInput {} +impl dynamic_graphql::internal::Register for ExampleInput { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let object = dynamic_graphql::dynamic::InputObject::new( + ::get_input_object_type_name() + .as_ref(), + ); + let field = dynamic_graphql::dynamic::InputValue::new( + "string", + ::get_input_type_ref(), + ); + let object = object.field(field); + registry.register_type(object) + } +} +impl dynamic_graphql::internal::FromValue for ExampleInput { + fn from_value( + __value: dynamic_graphql::Result, + ) -> dynamic_graphql::internal::InputValueResult { + let __value = __value?; + let __object = __value.object()?; + let field0 = dynamic_graphql::internal::FromValue::from_value( + __object.try_get("string"), + ) + .map_err(|e| e.into_field_error("string"))?; + Ok(Self { string: field0 }) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__interface.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__interface.snap new file mode 100644 index 0000000..f2c912c --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__interface.snap @@ -0,0 +1,75 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +trait Node { + fn id(&self) -> String; +} + + +impl dynamic_graphql::internal::TypeName for dyn Node { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Node".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for dyn Node {} +impl dynamic_graphql::internal::Interface for dyn Node {} +impl dynamic_graphql::internal::Register for dyn Node { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let object = dynamic_graphql::dynamic::Interface::new( + ::get_interface_type_name() + .as_ref(), + ); + let field = dynamic_graphql::dynamic::InterfaceField::new( + "id", + ::get_output_type_ref(), + ); + let object = object.field(field); + registry.register_type(object) + } +} +impl dynamic_graphql::internal::RegisterInstance for dyn Node +where + T: Node + dynamic_graphql::internal::Object + 'static, + T: Send + Sync, +{ + fn register_instance( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let field = dynamic_graphql::dynamic::Field::new( + "id", + ::get_output_type_ref(), + |ctx| { + dynamic_graphql::dynamic::FieldFuture::new(async move { + let parent = ctx.parent_value.try_downcast_ref::()?; + let arg0 = parent; + let value = T::id(arg0); + dynamic_graphql::internal::Resolve::resolve(value, &ctx) + }) + }, + ); + let __field_0 = field; + registry + .update_object( + ::get_object_type_name() + .as_ref(), + ::get_interface_type_name() + .as_ref(), + |object| { + let object = object.field(__field_0); + let object = object + .implement( + ::get_interface_type_name() + .as_ref(), + ); + object + }, + ) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__mutation.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__mutation.snap new file mode 100644 index 0000000..3e99901 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__mutation.snap @@ -0,0 +1,124 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct MutationRoot; + +impl dynamic_graphql::internal::ParentType for MutationRoot { + type Type = MutationRoot; +} +impl dynamic_graphql::internal::TypeName for MutationRoot { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "MutationRoot".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for MutationRoot {} +impl dynamic_graphql::internal::Object for MutationRoot {} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for MutationRoot { + fn resolve_owned( + self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::owned_any(self))) + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for MutationRoot { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::borrowed_any(self))) + } +} +impl MutationRoot {} +impl dynamic_graphql::internal::Register for MutationRoot { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry + .set_mutation( + ::get_object_type_name() + .as_ref(), + ); + let object = dynamic_graphql::dynamic::Object::new( + ::get_object_type_name().as_ref(), + ); + registry.register_type(object) + } +} + + +struct MyMutation(MutationRoot); + +impl MyMutation { + fn __registers( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + registry + } +} +impl dynamic_graphql::internal::ParentType for MyMutation { + type Type = MutationRoot; +} +impl dynamic_graphql::internal::ExpandObject for MyMutation { + fn get_expand_object_name() -> std::borrow::Cow<'static, str> { + "MyMutation".into() + } +} +impl dynamic_graphql::internal::Mutation for MyMutation {} +impl dynamic_graphql::internal::RegisterFns for MyMutation { + const REGISTER_FNS: &'static [fn( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry] = &[MyMutation::__registers]; +} + + +impl MyMutation { + fn the_example() -> String { + "field".to_string() + } +} + +impl dynamic_graphql::internal::Register for MyMutation { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let registry = ::REGISTER_FNS + .iter() + .fold(registry, |registry, f| f(registry)); + let field = dynamic_graphql::dynamic::Field::new( + "theExample", + ::get_output_type_ref(), + |ctx| { + dynamic_graphql::dynamic::FieldFuture::new(async move { + let value = MyMutation::the_example(); + dynamic_graphql::internal::Resolve::resolve(value, &ctx) + }) + }, + ); + let __field_0 = field; + registry + .update_object( + <::Type as dynamic_graphql::internal::Object>::get_object_type_name() + .as_ref(), + ::get_expand_object_name() + .as_ref(), + |object| { + let object = object.field(__field_0); + object + }, + ) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__resoled_object.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__resoled_object.snap new file mode 100644 index 0000000..d6ecf80 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__resoled_object.snap @@ -0,0 +1,131 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct Example { + pub field: String, +} + +impl Example { + fn __registers( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + registry + } +} +impl dynamic_graphql::internal::ParentType for Example { + type Type = Example; +} +impl dynamic_graphql::internal::TypeName for Example { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Example".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for Example {} +impl dynamic_graphql::internal::Object for Example {} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for Example { + fn resolve_owned( + self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::owned_any(self))) + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for Example { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::borrowed_any(self))) + } +} +impl Example { + fn __register_doc( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + registry + } +} +impl Example { + fn __register_interface( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry + .update_object( + ::get_object_type_name() + .as_ref(), + ::get_object_type_name() + .as_ref(), + |object| { object }, + ); + registry + } +} +impl Example { + fn __register_root( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + registry + } +} +impl dynamic_graphql::internal::RegisterFns for Example { + const REGISTER_FNS: &'static [fn( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry] = &[ + Example::__register_interface, + Example::__register_root, + Example::__register_doc, + Example::__registers, + ]; +} + + +impl Example { + fn field(&self) -> &str { + &self.field + } +} + +impl dynamic_graphql::internal::Register for Example { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::<&str>(); + let object = dynamic_graphql::dynamic::Object::new( + ::get_object_type_name().as_ref(), + ); + let field = dynamic_graphql::dynamic::Field::new( + "field", + <&str as dynamic_graphql::internal::GetOutputTypeRef>::get_output_type_ref(), + |ctx| { + dynamic_graphql::dynamic::FieldFuture::new(async move { + let parent = ctx + .parent_value + .try_downcast_ref::< + ::Type, + >()? + .into(); + let arg0 = parent; + let value = Self::field(arg0); + dynamic_graphql::internal::Resolve::resolve(value, &ctx) + }) + }, + ); + let object = object.field(field); + let registry = ::REGISTER_FNS + .iter() + .fold(registry, |registry, f| f(registry)); + registry.register_type(object) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__scalar.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__scalar.snap new file mode 100644 index 0000000..b4377d8 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__scalar.snap @@ -0,0 +1,68 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct Example; + +impl dynamic_graphql::internal::TypeName for Example { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Example".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for Example {} +impl dynamic_graphql::internal::InputTypeName for Example {} +impl dynamic_graphql::internal::Scalar for Example {} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for Example { + fn resolve_owned( + self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + let value = dynamic_graphql::ScalarValue::to_value(&self); + Ok(Some(dynamic_graphql::FieldValue::value(value))) + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for Example { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + let value = dynamic_graphql::ScalarValue::to_value(self); + Ok(Some(dynamic_graphql::FieldValue::value(value))) + } +} +impl dynamic_graphql::internal::FromValue for Example { + fn from_value( + value: dynamic_graphql::Result, + ) -> dynamic_graphql::internal::InputValueResult { + let value = value?.as_value().clone(); + Ok(dynamic_graphql::ScalarValue::from_value(value)?) + } +} +impl dynamic_graphql::internal::Register for Example { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let object = dynamic_graphql::dynamic::Scalar::new( + ::get_scalar_type_name().as_ref(), + ); + registry.register_type(object) + } +} +impl Example { + #[allow(dead_code)] + #[doc(hidden)] + fn __suppress_clippy_error(&self) { + let _ = self.0; + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__simple_object.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__simple_object.snap new file mode 100644 index 0000000..b6abe31 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__simple_object.snap @@ -0,0 +1,73 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +struct Example { + pub field: String, +} + +impl dynamic_graphql::internal::ParentType for Example { + type Type = Example; +} +impl dynamic_graphql::internal::TypeName for Example { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Example".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for Example {} +impl dynamic_graphql::internal::Object for Example {} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for Example { + fn resolve_owned( + self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::owned_any(self))) + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for Example { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + _ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + Ok(Some(dynamic_graphql::FieldValue::borrowed_any(self))) + } +} +impl Example { + fn __resolve_field(&self) -> &String { + &self.field + } +} +impl dynamic_graphql::internal::Register for Example { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let object = dynamic_graphql::dynamic::Object::new( + ::get_object_type_name().as_ref(), + ); + let field = dynamic_graphql::dynamic::Field::new( + "field", + ::get_output_type_ref(), + |ctx| { + dynamic_graphql::dynamic::FieldFuture::new(async move { + let parent = ctx.parent_value.try_downcast_ref::()?; + let value = Self::__resolve_field(parent); + dynamic_graphql::internal::Resolve::resolve(value, &ctx) + }) + }, + ); + let object = object.field(field); + registry.register_type(object) + } +} + +``` diff --git a/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__union.snap b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__union.snap new file mode 100644 index 0000000..98af716 --- /dev/null +++ b/derive/src/args/snapshots/dynamic_graphql_derive__args__test_output__union.snap @@ -0,0 +1,115 @@ +--- +source: derive/src/args/test_output.rs +expression: output +--- +```rust +enum Animal { + Dog(Dog), + Cat(Cat), +} + +impl dynamic_graphql::internal::TypeName for Animal { + fn get_type_name() -> std::borrow::Cow<'static, str> { + "Animal".into() + } +} +impl dynamic_graphql::internal::OutputTypeName for Animal {} +impl dynamic_graphql::internal::Union for Animal {} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveOwned<'__dynamic_graphql_lifetime> for Animal { + fn resolve_owned( + self, + ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + match self { + Animal::Dog(value) => { + dynamic_graphql::internal::Resolve::resolve(value, ctx) + .map(|value| { + value + .map(|value| { + value + .with_type( + ::get_object_type_name(), + ) + }) + }) + } + Animal::Cat(value) => { + dynamic_graphql::internal::Resolve::resolve(value, ctx) + .map(|value| { + value + .map(|value| { + value + .with_type( + ::get_object_type_name(), + ) + }) + }) + } + } + } +} +impl< + '__dynamic_graphql_lifetime, +> dynamic_graphql::internal::ResolveRef<'__dynamic_graphql_lifetime> for Animal { + fn resolve_ref( + &'__dynamic_graphql_lifetime self, + ctx: &dynamic_graphql::Context, + ) -> dynamic_graphql::Result< + Option>, + > { + match self { + Animal::Dog(value) => { + dynamic_graphql::internal::Resolve::resolve(value, ctx) + .map(|value| { + value + .map(|value| { + value + .with_type( + ::get_object_type_name(), + ) + }) + }) + } + Animal::Cat(value) => { + dynamic_graphql::internal::Resolve::resolve(value, ctx) + .map(|value| { + value + .map(|value| { + value + .with_type( + ::get_object_type_name(), + ) + }) + }) + } + } + } +} +impl dynamic_graphql::internal::Register for Animal { + fn register( + registry: dynamic_graphql::internal::Registry, + ) -> dynamic_graphql::internal::Registry { + let registry = registry.register::(); + let registry = registry.register::(); + let object = dynamic_graphql::dynamic::Union::new( + ::get_union_type_name().as_ref(), + ); + let object = object + .possible_type( + ::get_object_type_name() + .as_ref(), + ); + let object = object + .possible_type( + ::get_object_type_name() + .as_ref(), + ); + registry.register_type(object) + } +} + +``` diff --git a/derive/src/args/test_output.rs b/derive/src/args/test_output.rs new file mode 100644 index 0000000..5679184 --- /dev/null +++ b/derive/src/args/test_output.rs @@ -0,0 +1,210 @@ +use super::*; +use crate::utils::impl_block::FromItemImpl; +use crate::FromItemTrait; +use darling::FromDeriveInput; +use prettier_please::unparse; +use unindent::Unindent; + +fn pretty_expand(tokens: impl quote::ToTokens) -> String { + let tokens = tokens.into_token_stream(); + let file: syn::File = syn::parse2(tokens).unwrap(); + unparse(&file) +} + +fn derive(input: impl AsRef) -> D { + let input = input.as_ref(); + let file: syn::DeriveInput = syn::parse_str(input).unwrap(); + D::from_derive_input(&file).unwrap() +} + +fn pretty_derive(input: impl AsRef) -> String { + let input = input.as_ref().unindent(); + let derived = derive::(&input); + let pretty = pretty_expand(&derived); + format!("{}\n{}", input, pretty) +} + +fn expand_item_impl(input: impl AsRef) -> D { + let input = input.as_ref(); + let mut file: syn::ItemImpl = syn::parse_str(input).unwrap(); + D::from_item_impl(&mut file).unwrap() +} + +fn pretty_expand_item_impl(input: impl AsRef) -> String { + let expanded = expand_item_impl::(&input); + let pretty = pretty_expand(&expanded); + format!("{}\n{}", input.as_ref().unindent(), pretty) +} + +fn expand_item_trait(input: impl AsRef) -> D { + let input = input.as_ref(); + let mut file: syn::ItemTrait = syn::parse_str(input).unwrap(); + D::from_item_trait(&mut file).unwrap() +} + +fn pretty_expand_item_trait(input: impl AsRef) -> String { + let expanded = expand_item_trait::(&input); + let pretty = pretty_expand(&expanded); + format!("{}\n{}", input.as_ref().unindent(), pretty) +} + +fn md(outputs: &[&str]) -> String { + format!("```rust\n{}\n```", outputs.join("\n\n")) +} + +#[test] +fn test_app() { + let input = r#" + struct App(QueryRoot, PostApp); + "#; + + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_expand_object() { + let input1 = r#" + struct ExampleQuery<'a>(&'a Query); + "#; + + let input2 = r#" + impl ExampleQuery<'_> { + fn the_example(&self) -> Example { + Example { + field: "field".to_string(), + } + } + } + "#; + + let pretty1 = pretty_derive::(input1); + let pretty2 = pretty_expand_item_impl::(input2); + let output = md(&[&pretty1, &pretty2]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_enum() { + let input = r#" + enum Example { + Foo, + Bar, + } + "#; + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_input_object() { + let input = r#" + struct ExampleInput { + pub string: String, + } + "#; + + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_interface() { + let input = r#" + trait Node { + fn id(&self) -> String; + } + + "#; + + let pretty = pretty_expand_item_trait::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_mutation() { + let input1 = r#" + struct MutationRoot; + "#; + + let input2 = r#" + struct MyMutation(MutationRoot); + "#; + let input3 = r#" + impl MyMutation { + fn the_example() -> String { + "field".to_string() + } + } + "#; + + let pretty1 = pretty_derive::(input1); + let pretty2 = pretty_derive::(input2); + let pretty3 = pretty_expand_item_impl::(input3); + let output = md(&[&pretty1, &pretty2, &pretty3]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_resoled_object() { + let input1 = r#" + struct Example { + pub field: String, + } + "#; + + let input2 = r#" + impl Example { + fn field(&self) -> &str { + &self.field + } + } + "#; + + let pretty1 = pretty_derive::(input1); + let pretty2 = pretty_expand_item_impl::(input2); + let output = md(&[&pretty1, &pretty2]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_scalar() { + let input = r#" + struct Example; + "#; + + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_simple_object() { + let input = r#" + struct Example { + pub field: String, + } + "#; + + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +} + +#[test] +fn test_union() { + let input = r#" + enum Animal { + Dog(Dog), + Cat(Cat), + } + "#; + + let pretty = pretty_derive::(input); + let output = md(&[&pretty]); + insta::assert_snapshot!(output); +}