feat: add with for object & complex object & update documentation
This commit is contained in:
parent
f3ef60033f
commit
b361119ca0
|
@ -40,6 +40,7 @@ pub fn generate(
|
|||
if derived.name.is_some() && derived.into.is_some() {
|
||||
let base_function_name = &method.sig.ident;
|
||||
let name = derived.name.unwrap();
|
||||
let with = derived.with;
|
||||
let into = Type::Verbatim(
|
||||
proc_macro2::TokenStream::from_str(&derived.into.unwrap()).unwrap(),
|
||||
);
|
||||
|
@ -93,11 +94,16 @@ pub fn generate(
|
|||
.into_iter(),
|
||||
);
|
||||
|
||||
let new_block = quote!({
|
||||
{
|
||||
::std::result::Result::Ok(#self_ty::#base_function_name(&self, #other_atts).await?.into())
|
||||
}
|
||||
});
|
||||
let new_block = match with {
|
||||
Some(with) => quote!({
|
||||
::std::result::Result::Ok(#with(#self_ty::#base_function_name(&self, #other_atts).await?))
|
||||
}),
|
||||
None => quote!({
|
||||
{
|
||||
::std::result::Result::Ok(#self_ty::#base_function_name(&self, #other_atts).await?.into())
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
new_impl.block = syn::parse2::<Block>(new_block).expect("invalid block");
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ pub fn generate(
|
|||
if derived.name.is_some() && derived.into.is_some() {
|
||||
let base_function_name = &method.sig.ident;
|
||||
let name = derived.name.unwrap();
|
||||
let with = derived.with;
|
||||
let into = Type::Verbatim(
|
||||
proc_macro2::TokenStream::from_str(&derived.into.unwrap()).unwrap(),
|
||||
);
|
||||
|
@ -108,11 +109,16 @@ pub fn generate(
|
|||
.into_iter(),
|
||||
);
|
||||
|
||||
let new_block = quote!({
|
||||
{
|
||||
::std::result::Result::Ok(#self_ty::#base_function_name(&self, #other_atts).await?.into())
|
||||
}
|
||||
});
|
||||
let new_block = match with {
|
||||
Some(with) => quote!({
|
||||
::std::result::Result::Ok(#with(#self_ty::#base_function_name(&self, #other_atts).await?))
|
||||
}),
|
||||
None => quote!({
|
||||
{
|
||||
::std::result::Result::Ok(#self_ty::#base_function_name(&self, #other_atts).await?.into())
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
new_impl.block = syn::parse2::<Block>(new_block).expect("invalid block");
|
||||
|
||||
|
|
|
@ -69,9 +69,9 @@ impl From<Vec<U>> for Vec<T> {
|
|||
}
|
||||
```
|
||||
|
||||
So you wouldn't be able to generate derived fields for existing wrapper type structures like `Vec` or `Option`. But when you implement a `From<U> for T` you should be able to derived a `From<Vec<U>> for Vec<T>` and a `From<Option<U>> for Option<T>`, so a coercion mecanism has been included so you'll be able to use the derived macro argument with `Vec` and `Option`.
|
||||
So you wouldn't be able to generate derived fields for existing wrapper type structures like `Vec` or `Option`. But when you implement a `From<U> for T` you should be able to derived a `From<Vec<U>> for Vec<T>` and a `From<Option<U>> for Option<T>`.
|
||||
We included a `with` parameter to help you define a function to call instead of using the `Into` trait implementation between wrapper structures.
|
||||
|
||||
This coercion mecanism impose these derived to be `owned`.
|
||||
|
||||
### Example
|
||||
|
||||
|
@ -91,15 +91,13 @@ impl From<ValueDerived> for ValueDerived2 {
|
|||
}
|
||||
}
|
||||
|
||||
fn option_to_option<T, U: From<T>>(value: Option<T>) -> Option<U> {
|
||||
value.map(|x| x.into())
|
||||
}
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
struct TestObj {
|
||||
#[graphql(derived(owned, name = "value2", into = "Option<ValueDerived2>"))]
|
||||
#[graphql(derived(owned, name = "value2", into = "Option<ValueDerived2>", with = "option_to_option"))]
|
||||
pub value1: Option<ValueDerived>,
|
||||
#[graphql(derived(owned, name = "value_vec_2", into = "Vec<ValueDerived2>"))]
|
||||
pub value_vec_1: Vec<ValueDerived>,
|
||||
#[graphql(derived(owned, name = "value_opt_vec_2", into = "Option<Vec<ValueDerived2>>"))]
|
||||
pub value_opt_vec_1: Option<Vec<ValueDerived>>,
|
||||
#[graphql(derived(owned, name = "value_vec_opt_2", into = "Vec<Option<ValueDerived2>>"))]
|
||||
pub value_vec_opt_1: Vec<Option<ValueDerived>>,
|
||||
}
|
||||
```
|
||||
|
|
|
@ -295,6 +295,7 @@ pub type FieldResult<T> = Result<T>;
|
|||
/// |--------------|------------------------------------------|------------ |----------|
|
||||
/// | name | Generated derived field name | string | N |
|
||||
/// | into | Type to derived an into | string | Y |
|
||||
/// | with | Function to apply to manage advanced use cases | string| Y |
|
||||
///
|
||||
/// # Valid field return types
|
||||
///
|
||||
|
@ -467,8 +468,8 @@ pub use async_graphql_derive::Object;
|
|||
/// |--------------|------------------------------------------|------------ |----------|
|
||||
/// | name | Generated derived field name | string | N |
|
||||
/// | into | Type to derived an into | string | Y |
|
||||
/// | into | Type to derived an into | string | Y |
|
||||
/// | owned | Field resolver return a ownedship value | bool | Y |
|
||||
/// | with | Function to apply to manage advanced use cases | string| Y |
|
||||
///
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -533,6 +534,7 @@ pub use async_graphql_derive::SimpleObject;
|
|||
/// |--------------|------------------------------------------|------------ |----------|
|
||||
/// | name | Generated derived field name | string | N |
|
||||
/// | into | Type to derived an into | string | Y |
|
||||
/// | with | Function to apply to manage advanced use cases | string| Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -46,6 +46,60 @@ pub async fn test_derived_field_object() {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_derived_field_object_with() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
struct Query;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ValueDerived(String);
|
||||
|
||||
scalar!(ValueDerived);
|
||||
|
||||
impl From<i32> for ValueDerived {
|
||||
fn from(value: i32) -> Self {
|
||||
ValueDerived(format!("{}", value))
|
||||
}
|
||||
}
|
||||
|
||||
fn option_to_option<T, U: From<T>>(value: Option<T>) -> Option<U> {
|
||||
value.map(|x| x.into())
|
||||
}
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[graphql(derived(
|
||||
name = "value2",
|
||||
into = "Option<ValueDerived>",
|
||||
with = "option_to_option"
|
||||
))]
|
||||
async fn value1(&self, #[graphql(default = 100)] input: i32) -> Option<i32> {
|
||||
Some(input)
|
||||
}
|
||||
}
|
||||
|
||||
let query = "{ value1 value2 }";
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema.execute(query).await.data,
|
||||
value!({
|
||||
"value1": 100,
|
||||
"value2": "100",
|
||||
})
|
||||
);
|
||||
|
||||
let query = "{ value1(input: 1) value2(input: 2) }";
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema.execute(query).await.data,
|
||||
value!({
|
||||
"value1": 1,
|
||||
"value2": "2",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_derived_field_simple_object() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -261,3 +315,69 @@ pub async fn test_derived_field_complex_object() {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_derived_field_complex_object_derived() {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
#[graphql(complex)]
|
||||
struct MyObj {
|
||||
a: i32,
|
||||
#[graphql(owned, derived(name = "f", into = "ValueDerived"))]
|
||||
b: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct ValueDerived(String);
|
||||
|
||||
scalar!(ValueDerived);
|
||||
|
||||
impl From<i32> for ValueDerived {
|
||||
fn from(value: i32) -> Self {
|
||||
ValueDerived(format!("{}", value))
|
||||
}
|
||||
}
|
||||
|
||||
fn option_to_option<T, U: From<T>>(value: Option<T>) -> Option<U> {
|
||||
value.map(|x| x.into())
|
||||
}
|
||||
|
||||
#[ComplexObject]
|
||||
impl MyObj {
|
||||
async fn c(&self) -> i32 {
|
||||
self.a + self.b
|
||||
}
|
||||
|
||||
#[graphql(derived(name = "e", into = "Option<ValueDerived>", with = "option_to_option"))]
|
||||
async fn d(&self, v: i32) -> Option<i32> {
|
||||
Some(self.a + self.b + v)
|
||||
}
|
||||
}
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MyObj { a: 10, b: 20 }
|
||||
}
|
||||
}
|
||||
|
||||
let query = "{ obj { a b c d(v:100) e(v: 200) f } }";
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
dbg!(schema.execute(query).await);
|
||||
assert_eq!(
|
||||
schema.execute(query).await.data,
|
||||
value!({
|
||||
"obj": {
|
||||
"a": 10,
|
||||
"b": 20,
|
||||
"c": 30,
|
||||
"d": 130,
|
||||
"e": "230",
|
||||
"f": "20",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue