Add flatten type field support for input objects. #255
This commit is contained in:
parent
fbccfecbc0
commit
366c7c03da
|
@ -457,6 +457,7 @@ pub struct InputField {
|
|||
pub desc: Option<String>,
|
||||
pub default: Option<TokenStream>,
|
||||
pub validator: TokenStream,
|
||||
pub flatten: bool,
|
||||
}
|
||||
|
||||
impl InputField {
|
||||
|
@ -465,6 +466,7 @@ impl InputField {
|
|||
let mut desc = None;
|
||||
let mut default = None;
|
||||
let mut validator = quote! { None };
|
||||
let mut flatten = false;
|
||||
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("field") {
|
||||
|
@ -480,6 +482,9 @@ impl InputField {
|
|||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("default") => {
|
||||
default = Some(quote! { Default::default() });
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("flatten") => {
|
||||
flatten = true;
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) => {
|
||||
if nv.path.is_ident("name") {
|
||||
if let syn::Lit::Str(lit) = &nv.lit {
|
||||
|
@ -523,6 +528,7 @@ impl InputField {
|
|||
desc,
|
||||
default,
|
||||
validator,
|
||||
flatten,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,15 +46,42 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
|||
let mut put_fields = Vec::new();
|
||||
let mut fields = Vec::new();
|
||||
let mut schema_fields = Vec::new();
|
||||
let mut flatten_fields = Vec::new();
|
||||
|
||||
for field in &s.fields {
|
||||
let field_args = args::InputField::parse(&crate_name, &field.attrs)?;
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
let ty = &field.ty;
|
||||
let validator = &field_args.validator;
|
||||
let name = field_args
|
||||
.name
|
||||
.unwrap_or_else(|| ident.unraw().to_string().to_camel_case());
|
||||
|
||||
if field_args.flatten {
|
||||
flatten_fields.push((ident, ty));
|
||||
|
||||
schema_fields.push(quote! {
|
||||
#ty::create_type_info(registry);
|
||||
if let Some(#crate_name::registry::MetaType::InputObject{ input_fields, .. }) =
|
||||
registry.types.remove(&*<#ty as #crate_name::Type>::type_name()) {
|
||||
fields.extend(input_fields);
|
||||
}
|
||||
});
|
||||
|
||||
get_fields.push(quote! {
|
||||
let #ident: #ty = #crate_name::InputValueType::parse(Some(#crate_name::Value::Object(obj.clone())))?;
|
||||
});
|
||||
|
||||
fields.push(ident);
|
||||
|
||||
put_fields.push(quote! {
|
||||
if let #crate_name::Value::Object(values) = #crate_name::InputValueType::to_value(&self.#ident) {
|
||||
map.extend(values);
|
||||
}
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
let validator = &field_args.validator;
|
||||
let desc = field_args
|
||||
.desc
|
||||
.as_ref()
|
||||
|
@ -139,5 +166,8 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
|||
|
||||
impl #crate_name::InputObjectType for #ident {}
|
||||
};
|
||||
if gql_typename == "MyInputObject11" {
|
||||
println!("{}", expanded);
|
||||
}
|
||||
Ok(expanded.into())
|
||||
}
|
||||
|
|
|
@ -91,10 +91,9 @@ pub async fn test_input_object_default_value() {
|
|||
pub async fn test_inputobject_derive_and_item_attributes() {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[async_graphql::InputObject]
|
||||
#[InputObject]
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct MyInputObject {
|
||||
#[field]
|
||||
#[serde(alias = "other")]
|
||||
real: i32,
|
||||
}
|
||||
|
@ -104,3 +103,131 @@ pub async fn test_inputobject_derive_and_item_attributes() {
|
|||
MyInputObject { real: 100 }
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
pub async fn test_inputobject_flatten() {
|
||||
#[derive(GQLInputObject, Debug, Eq, PartialEq)]
|
||||
struct A {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
#[derive(GQLInputObject, Debug, Eq, PartialEq)]
|
||||
struct B {
|
||||
#[field(default = 70)]
|
||||
b: i32,
|
||||
#[field(flatten)]
|
||||
a_obj: A,
|
||||
}
|
||||
|
||||
#[derive(GQLInputObject, Debug, Eq, PartialEq)]
|
||||
struct MyInputObject {
|
||||
#[field(flatten)]
|
||||
b_obj: B,
|
||||
c: i32,
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MyInputObject::parse(Some(
|
||||
serde_json::json!({
|
||||
"a": 10,
|
||||
"b": 20,
|
||||
"c": 30,
|
||||
})
|
||||
.into()
|
||||
))
|
||||
.unwrap(),
|
||||
MyInputObject {
|
||||
b_obj: B {
|
||||
b: 20,
|
||||
a_obj: A { a: 10 }
|
||||
},
|
||||
c: 30,
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
MyInputObject {
|
||||
b_obj: B {
|
||||
b: 20,
|
||||
a_obj: A { a: 10 }
|
||||
},
|
||||
c: 30,
|
||||
}
|
||||
.to_value(),
|
||||
serde_json::json!({
|
||||
"a": 10,
|
||||
"b": 20,
|
||||
"c": 30,
|
||||
})
|
||||
.into()
|
||||
);
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn test(&self, input: MyInputObject) -> i32 {
|
||||
input.c + input.b_obj.b + input.b_obj.a_obj.a
|
||||
}
|
||||
|
||||
async fn test_with_default(
|
||||
&self,
|
||||
#[arg(default_with = r#"MyInputObject {
|
||||
b_obj: B {
|
||||
b: 2,
|
||||
a_obj: A { a: 1 }
|
||||
},
|
||||
c: 3,
|
||||
}"#)]
|
||||
input: MyInputObject,
|
||||
) -> i32 {
|
||||
input.c + input.b_obj.b + input.b_obj.a_obj.a
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
r#"{
|
||||
test(input:{a:10, b: 20, c: 30})
|
||||
}"#
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.data,
|
||||
serde_json::json!({
|
||||
"test": 60,
|
||||
})
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
r#"{
|
||||
test(input:{a:10, c: 30})
|
||||
}"#
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.data,
|
||||
serde_json::json!({
|
||||
"test": 110,
|
||||
})
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
schema
|
||||
.execute(
|
||||
r#"{
|
||||
testWithDefault
|
||||
}"#
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.data,
|
||||
serde_json::json!({
|
||||
"testWithDefault": 6,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user