-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add QueryVariableLiterals trait
- Loading branch information
Showing
12 changed files
with
264 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use darling::util::SpannedValue; | ||
use syn::spanned::Spanned; | ||
|
||
use crate::{idents::RenamableFieldIdent, RenameAll}; | ||
|
||
#[derive(darling::FromDeriveInput)] | ||
#[darling(attributes(cynic), supports(struct_named))] | ||
pub struct QueryVariableLiteralsInput { | ||
pub(super) ident: proc_macro2::Ident, | ||
pub(super) generics: syn::Generics, | ||
pub(super) data: darling::ast::Data<(), QueryVariableLiteralsField>, | ||
|
||
#[darling(default)] | ||
pub(super) rename_all: Option<RenameAll>, | ||
} | ||
|
||
#[derive(Debug, darling::FromField)] | ||
#[darling(attributes(cynic))] | ||
pub(super) struct QueryVariableLiteralsField { | ||
pub(super) ident: Option<proc_macro2::Ident>, | ||
|
||
#[darling(default)] | ||
pub(super) skip_serializing_if: Option<SpannedValue<syn::Path>>, | ||
|
||
#[darling(default)] | ||
pub(super) rename: Option<SpannedValue<String>>, | ||
} | ||
|
||
impl QueryVariableLiteralsField { | ||
pub fn graphql_ident(&self, rename_all: Option<RenameAll>) -> RenamableFieldIdent { | ||
let mut ident = RenamableFieldIdent::from( | ||
self.ident | ||
.clone() | ||
.expect("InputObject only supports named structs"), | ||
); | ||
if let Some(rename) = &self.rename { | ||
let span = rename.span(); | ||
let rename = (**rename).clone(); | ||
ident.set_rename(rename, span) | ||
} else if let Some(rename_all) = rename_all { | ||
ident.rename_with(rename_all, self.ident.span()) | ||
} | ||
ident | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use { | ||
proc_macro2::TokenStream, | ||
quote::{format_ident, quote}, | ||
syn::visit_mut::{self, VisitMut}, | ||
}; | ||
|
||
mod input; | ||
|
||
use crate::generics_for_serde; | ||
|
||
use self::input::QueryVariableLiteralsInput; | ||
|
||
pub fn query_variable_literals_derive(ast: &syn::DeriveInput) -> Result<TokenStream, syn::Error> { | ||
use darling::FromDeriveInput; | ||
|
||
match QueryVariableLiteralsInput::from_derive_input(ast) { | ||
Ok(input) => inlineable_variables_derive_impl(input), | ||
Err(e) => Ok(e.write_errors()), | ||
} | ||
} | ||
|
||
pub fn inlineable_variables_derive_impl( | ||
input: QueryVariableLiteralsInput, | ||
) -> Result<TokenStream, syn::Error> { | ||
let ident = &input.ident; | ||
|
||
let (_, ty_generics, _) = input.generics.split_for_impl(); | ||
let generics_with_ser = generics_for_serde::with_serialize_bounds(&input.generics); | ||
let (impl_generics_with_ser, _, where_clause_with_ser) = generics_with_ser.split_for_impl(); | ||
|
||
let input_fields = input.data.take_struct().unwrap().fields; | ||
|
||
let mut match_arms = Vec::new(); | ||
|
||
for f in input_fields { | ||
let name = f.ident.as_ref().unwrap(); | ||
|
||
let name_str = | ||
proc_macro2::Literal::string(&f.graphql_ident(input.rename_all).graphql_name()); | ||
|
||
let mut match_arm_rhs = | ||
quote! { Some(cynic::queries::to_input_literal(&self.#name).ok()?) }; | ||
|
||
if let Some(skip_check_fn) = f.skip_serializing_if { | ||
let skip_check_fn = &*skip_check_fn; | ||
match_arm_rhs = quote! { | ||
if #skip_check_fn(&self.#name) { | ||
None | ||
} else { | ||
#match_arm_rhs | ||
} | ||
} | ||
} | ||
|
||
match_arms.push(quote! { | ||
#name_str => #match_arm_rhs, | ||
}) | ||
} | ||
|
||
Ok(quote! { | ||
#[automatically_derived] | ||
impl #impl_generics_with_ser cynic::QueryVariableLiterals for #ident #ty_generics #where_clause_with_ser { | ||
fn get(&self, variable_name: &str) -> Option<cynic::queries::InputLiteral> { | ||
match variable_name { | ||
#(#match_arms)* | ||
_ => None | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
|
||
struct TurnLifetimesToStatic; | ||
impl VisitMut for TurnLifetimesToStatic { | ||
fn visit_lifetime_mut(&mut self, i: &mut syn::Lifetime) { | ||
i.ident = format_ident!("static"); | ||
visit_mut::visit_lifetime_mut(self, i) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use cynic::QueryVariableLiterals; | ||
|
||
#[derive(QueryVariableLiterals)] | ||
struct TestArgs<'a> { | ||
#[cynic(skip_serializing_if = "Option::is_none")] | ||
a_str: Option<&'a str>, | ||
a_bool: Option<bool>, | ||
an_input: AnInputType, | ||
} | ||
|
||
#[derive(cynic::InputObject)] | ||
#[cynic(schema_path = "../schemas/simple.graphql")] | ||
struct AnInputType { | ||
favourite_dessert: Option<Dessert>, | ||
} | ||
|
||
#[derive(cynic::Enum)] | ||
#[cynic(schema_path = "../schemas/simple.graphql")] | ||
enum Dessert { | ||
Cheesecake, | ||
IceCream, | ||
} | ||
|
||
#[test] | ||
fn test_the_derive() { | ||
let args = TestArgs { | ||
a_str: Some("hello"), | ||
a_bool: Some(false), | ||
an_input: AnInputType { | ||
favourite_dessert: Some(Dessert::Cheesecake), | ||
}, | ||
}; | ||
|
||
assert_eq!(args.get("aStr").unwrap().to_string(), "\"hello\""); | ||
|
||
assert_eq!(args.get("aBool").unwrap().to_string(), "false"); | ||
|
||
assert_eq!( | ||
args.get("anInput").unwrap().to_string(), | ||
"{favouriteDessert: CHEESECAKE}" | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_the_derive_with_skip_serializing_if() { | ||
let args = TestArgs { | ||
a_str: None, | ||
a_bool: None, | ||
an_input: AnInputType { | ||
favourite_dessert: None, | ||
}, | ||
}; | ||
|
||
assert_eq!(args.get("aStr"), None) | ||
} | ||
|
||
#[test] | ||
fn test_derive_with_renames() { | ||
#[derive(QueryVariableLiterals)] | ||
#[cynic(rename_all = "SCREAMING_SNAKE_CASE")] | ||
struct TestArgs<'a> { | ||
a_str: Option<&'a str>, | ||
#[cynic(rename = "renamedThisYeah")] | ||
a_bool: Option<bool>, | ||
} | ||
let args = TestArgs { | ||
a_str: Some("hello"), | ||
a_bool: Some(true), | ||
}; | ||
|
||
assert_eq!(args.get("A_STR").unwrap().to_string(), "\"hello\""); | ||
assert_eq!(args.get("renamedThisYeah").unwrap().to_string(), "true"); | ||
} | ||
|
||
mod schema { | ||
cynic::use_schema!("../schemas/simple.graphql"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters