Skip to content

Commit c66cf3a

Browse files
committed
Option for externally defined enums
Allow to deserialize GraphQL enums into user defined Rust enums.
1 parent c51adb1 commit c66cf3a

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

graphql_client_codegen/src/codegen/enums.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ pub(super) fn generate_enum_definitions<'a, 'schema: 'a>(
2323
);
2424
let normalization = options.normalization();
2525

26-
all_used_types.enums(query.schema).map(move |(_id, r#enum)| {
26+
all_used_types.enums(query.schema)
27+
.filter(move |(_id, r#enum)| !options.extern_enums().contains(&r#enum.name))
28+
.map(move |(_id, r#enum)| {
2729
let variant_names: Vec<TokenStream> = r#enum
2830
.variants
2931
.iter()

graphql_client_codegen/src/codegen_options.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub struct GraphQLClientCodegenOptions {
4141
normalization: Normalization,
4242
/// Custom scalar definitions module path
4343
custom_scalars_module: Option<syn::Path>,
44+
/// List of externally defined enum types. Type names must match those used in the schema exactly.
45+
extern_enums: Vec<String>,
4446
}
4547

4648
impl GraphQLClientCodegenOptions {
@@ -59,6 +61,7 @@ impl GraphQLClientCodegenOptions {
5961
schema_file: Default::default(),
6062
normalization: Normalization::None,
6163
custom_scalars_module: Default::default(),
64+
extern_enums: Default::default(),
6265
}
6366
}
6467

@@ -187,4 +190,14 @@ impl GraphQLClientCodegenOptions {
187190
pub fn set_custom_scalars_module(&mut self, module: syn::Path) {
188191
self.custom_scalars_module = Some(module)
189192
}
193+
194+
/// Get the externally defined enums type names
195+
pub fn extern_enums(&self) -> &[String] {
196+
&self.extern_enums
197+
}
198+
199+
/// Set the externally defined enums type names
200+
pub fn set_extern_enums(&mut self, enums: Vec<String>) {
201+
self.extern_enums = enums;
202+
}
190203
}

graphql_query_derive/src/attributes.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,42 @@ pub fn extract_attr(ast: &syn::DeriveInput, attr: &str) -> Result<String, syn::E
3636
Err(syn::Error::new_spanned(ast, "Attribute not found"))
3737
}
3838

39+
/// Extract a list of configuration parameter values specified in the `graphql` attribute.
40+
pub fn extract_attr_list(ast: &syn::DeriveInput, attr: &str) -> Result<Vec<String>, syn::Error> {
41+
let attributes = &ast.attrs;
42+
let graphql_path = path_to_match();
43+
let attribute = attributes
44+
.iter()
45+
.find(|attr| attr.path == graphql_path)
46+
.ok_or_else(|| syn::Error::new_spanned(ast, "The graphql attribute is missing"))?;
47+
if let syn::Meta::List(items) = &attribute.parse_meta().expect("Attribute is well formatted") {
48+
for item in items.nested.iter() {
49+
if let syn::NestedMeta::Meta(syn::Meta::List(value_list)) = item {
50+
if let Some(ident) = value_list.path.get_ident() {
51+
if ident == attr {
52+
return value_list
53+
.nested
54+
.iter()
55+
.map(|lit| {
56+
if let syn::NestedMeta::Lit(syn::Lit::Str(lit)) = lit {
57+
Ok(lit.value())
58+
} else {
59+
Err(syn::Error::new_spanned(
60+
lit,
61+
"Attribute inside value list must be a literal",
62+
))
63+
}
64+
})
65+
.collect();
66+
}
67+
}
68+
}
69+
}
70+
}
71+
72+
Err(syn::Error::new_spanned(ast, "Attribute not found"))
73+
}
74+
3975
/// Get the deprecation from a struct attribute in the derive case.
4076
pub fn extract_deprecation_strategy(
4177
ast: &syn::DeriveInput,

graphql_query_derive/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ fn build_graphql_client_derive_options(
7171
let variables_derives = attributes::extract_attr(input, "variables_derives").ok();
7272
let response_derives = attributes::extract_attr(input, "response_derives").ok();
7373
let custom_scalars_module = attributes::extract_attr(input, "custom_scalars_module").ok();
74+
let extern_enums = attributes::extract_attr_list(input, "extern_enums").ok();
7475

7576
let mut options = GraphQLClientCodegenOptions::new(CodegenMode::Derive);
7677
options.set_query_file(query_path);
@@ -105,6 +106,11 @@ fn build_graphql_client_derive_options(
105106
options.set_custom_scalars_module(custom_scalars_module);
106107
}
107108

109+
// The user can specify a list of enums types that are defined externally, rather than generated by this library
110+
if let Some(extern_enums) = extern_enums {
111+
options.set_extern_enums(extern_enums);
112+
}
113+
108114
options.set_struct_ident(input.ident.clone());
109115
options.set_module_visibility(input.vis.clone());
110116
options.set_operation_name(input.ident.to_string());

0 commit comments

Comments
 (0)