Skip to content

Commit

Permalink
Don't require skip_serializing_none to have any attribute set and add…
Browse files Browse the repository at this point in the history
… end-to-end test for it.
  • Loading branch information
Selyatin committed Aug 19, 2022
1 parent 942373b commit ed98d33
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 42 deletions.
29 changes: 29 additions & 0 deletions graphql_client/tests/skip_serializing_none.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use graphql_client::*;

#[derive(GraphQLQuery)]
#[graphql(
schema_path = "tests/skip_serializing_none/schema.graphql",
query_path = "tests/skip_serializing_none/query.graphql",
skip_serializing_none
)]
pub struct SkipSerializingNoneMutation;

#[test]
fn skip_serializing_none() {
use skip_serializing_none_mutation::*;

let query = SkipSerializingNoneMutation::build_query(Variables {
param: Some(Param {
data: Author {
name: "test".to_owned(),
id: None,
},
}),
});

let stringified = serde_json::to_string(&query).expect("SkipSerializingNoneMutation is valid");

println!("{}", stringified);

assert!(stringified.contains(r#""data":{"name":"test"}"#));
}
6 changes: 6 additions & 0 deletions graphql_client/tests/skip_serializing_none/query.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation SkipSerializingNoneMutation($param: Param) {
optInput(query: $param) {
name
__typename
}
}
25 changes: 25 additions & 0 deletions graphql_client/tests/skip_serializing_none/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
schema {
mutation: Mutation
}

# The query type, represents all of the entry points into our object graph
type Mutation {
optInput(mutation: Param!): Named
}

input Param {
data: Author!
}

input Author {
id: String,
name: String!
}

# A named entity
type Named {
# The ID of the entity
id: ID!
# The name of the entity
name: String!
}
12 changes: 6 additions & 6 deletions graphql_client_codegen/src/codegen/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::{
codegen_options::GraphQLClientCodegenOptions,
query::{BoundQuery, UsedTypes},
schema::input_is_recursive_without_indirection,
type_qualifiers::GraphqlTypeQualifier,
};
use heck::ToSnakeCase;
use proc_macro2::{Ident, Span, TokenStream};
Expand All @@ -29,11 +28,12 @@ pub(super) fn generate_input_object_definitions(
let normalized_field_type_name = options
.normalization()
.field_type(field_type.id.name(query.schema));
let optional_skip_serializing_none = if *options.skip_serializing_none() && field_type.is_optional() {
Some(quote!(#[serde(skip_serializing_if = "Option::is_none")]))
} else {
None
};
let optional_skip_serializing_none =
if *options.skip_serializing_none() && field_type.is_optional() {
Some(quote!(#[serde(skip_serializing_if = "Option::is_none")]))
} else {
None
};
let type_name = Ident::new(normalized_field_type_name.as_ref(), Span::call_site());
let field_type_tokens = super::decorate_type(&type_name, &field_type.qualifiers);
let field_type = if field_type
Expand Down
65 changes: 29 additions & 36 deletions graphql_query_derive/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ fn path_to_match() -> syn::Path {
syn::parse_str("graphql").expect("`graphql` is a valid path")
}

pub fn ident_exists(ast: &syn::DeriveInput, ident: &str) -> Result<(), syn::Error> {
let graphql_path = path_to_match();
let attribute = ast
.attrs
.iter()
.find(|attr| attr.path == graphql_path)
.ok_or_else(|| syn::Error::new_spanned(ast, "The graphql attribute is missing"))?;

if let syn::Meta::List(items) = &attribute.parse_meta().expect("Attribute is well formatted") {
for item in items.nested.iter() {
if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = item {
if let Some(ident_) = path.get_ident() {
if ident_ == ident {
return Ok(());
}
}
}
}
}

Err(syn::Error::new_spanned(
&ast,
format!("Ident `{}` not found", ident),
))
}

/// Extract an configuration parameter specified in the `graphql` attribute.
pub fn extract_attr(ast: &syn::DeriveInput, attr: &str) -> Result<String, syn::Error> {
let attributes = &ast.attrs;
Expand Down Expand Up @@ -104,10 +130,7 @@ pub fn extract_fragments_other_variant(ast: &syn::DeriveInput) -> bool {
}

pub fn extract_skip_serializing_none(ast: &syn::DeriveInput) -> bool {
extract_attr(ast, "skip_serializing_none")
.ok()
.and_then(|s| FromStr::from_str(s.as_str()).ok())
.unwrap_or(false)
ident_exists(ast, "skip_serializing_none").is_ok()
}

#[cfg(test)]
Expand Down Expand Up @@ -228,50 +251,20 @@ mod test {
}

#[test]
fn test_skip_serializing_none_set_to_true() {
fn test_skip_serializing_none_set() {
let input = r#"
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "x",
query_path = "x",
skip_serializing_none = "true"
skip_serializing_none
)]
struct MyQuery;
"#;
let parsed = syn::parse_str(input).unwrap();
assert!(extract_skip_serializing_none(&parsed));
}

#[test]
fn test_skip_serializing_none_set_to_false() {
let input = r#"
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "x",
query_path = "x",
skip_serializing_none = "false"
)]
struct MyQuery;
"#;
let parsed = syn::parse_str(input).unwrap();
assert!(!extract_skip_serializing_none(&parsed));
}

#[test]
fn test_skip_serializing_none_set_to_invalid() {
let input = r#"
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "x",
query_path = "x",
skip_serializing_none = "invalid"
)]
struct MyQuery;
"#;
let parsed = syn::parse_str(input).unwrap();
assert!(!extract_skip_serializing_none(&parsed));
}

#[test]
fn test_skip_serializing_none_unset() {
let input = r#"
Expand Down

0 comments on commit ed98d33

Please sign in to comment.