From d33f88e42bd4d8caf0b842788ee471db7970339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Houl=C3=A9?= Date: Mon, 8 Dec 2025 16:43:12 +0100 Subject: [PATCH] Add changelog ahead of 0.15.0 --- CHANGELOG.md | 14 ++++++++ graphql_client_cli/src/generate.rs | 8 +++-- graphql_client_cli/src/main.rs | 4 +-- graphql_client_codegen/src/codegen/inputs.rs | 18 +++++++--- .../src/codegen/selection.rs | 34 +++++++++++++------ graphql_client_codegen/src/query/selection.rs | 6 +--- .../src/schema/json_conversion.rs | 9 +---- graphql_client_codegen/src/tests/mod.rs | 3 +- graphql_query_derive/src/lib.rs | 2 +- 9 files changed, 63 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c12aff5f..a865075e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## Unreleased + +- Support for `deprecated` directive on InputValue fields (#553) +- Support for custom variable and response types (#536) +- Allow using `#[derive(GraphQLQuery)]` without depending on `serde` directly (#487) +- CLI option for extern enums (#520) +- Support deserializing IDs from integers or strings (#476) +- Introspection schema now includes `oneOf` and `specifiedByUrl` (#501) +- Update `reqwest` to 0.12 (#499) +- Fix required ID deserialization (#523) +- Fix `skip_serializing_none` for root level variables (#485) +- Use consistent reference to `graphql_client` crate in codegen (#484) +- Fix multiple operations example in README (#497) + ## 0.14.0 - 2024-03-26 - Add support for GraphQL’s `extend type` directive diff --git a/graphql_client_cli/src/generate.rs b/graphql_client_cli/src/generate.rs index 1a36d0cf..f6fe05fe 100644 --- a/graphql_client_cli/src/generate.rs +++ b/graphql_client_cli/src/generate.rs @@ -93,11 +93,13 @@ pub(crate) fn generate_code(params: CliCodegenParams) -> CliResult<()> { options.set_custom_scalars_module(custom_scalars_module); } - + if let Some(custom_variable_types) = custom_variable_types { - options.set_custom_variable_types(custom_variable_types.split(",").map(String::from).collect()); + options.set_custom_variable_types( + custom_variable_types.split(",").map(String::from).collect(), + ); } - + if let Some(custom_response_type) = custom_response_type { options.set_custom_response_type(custom_response_type); } diff --git a/graphql_client_cli/src/main.rs b/graphql_client_cli/src/main.rs index 6721953b..a7476477 100644 --- a/graphql_client_cli/src/main.rs +++ b/graphql_client_cli/src/main.rs @@ -139,8 +139,8 @@ fn main() -> CliResult<()> { selected_operation, custom_scalars_module, fragments_other_variant, - external_enums, - custom_variable_types, + external_enums, + custom_variable_types, custom_response_type, } => generate::generate_code(generate::CliCodegenParams { query_path, diff --git a/graphql_client_codegen/src/codegen/inputs.rs b/graphql_client_codegen/src/codegen/inputs.rs index d8cc1080..c3674f4c 100644 --- a/graphql_client_codegen/src/codegen/inputs.rs +++ b/graphql_client_codegen/src/codegen/inputs.rs @@ -19,11 +19,19 @@ pub(super) fn generate_input_object_definitions( all_used_types .inputs(query.schema) .map(|(input_id, input)| { - let custom_variable_type = query.query.variables.iter() + let custom_variable_type = query + .query + .variables + .iter() .enumerate() - .find(|(_, v) | v.r#type.id.as_input_id().is_some_and(|i| i == input_id)) - .map(|(index, _)| custom_variable_types.get(index)) - .flatten(); + .find(|(_, v)| { + v.r#type + .id + .as_input_id() + .map(|i| i == input_id) + .unwrap_or_default() + }) + .and_then(|(index, _)| custom_variable_types.get(index)); if let Some(custom_type) = custom_variable_type { generate_type_def(input, options, custom_type) } else if input.is_one_of { @@ -38,7 +46,7 @@ pub(super) fn generate_input_object_definitions( fn generate_type_def( input: &StoredInputType, options: &GraphQLClientCodegenOptions, - custom_type: &String, + custom_type: &str, ) -> TokenStream { let custom_type = syn::parse_str::(custom_type).unwrap(); let normalized_name = options.normalization().input_name(input.name.as_str()); diff --git a/graphql_client_codegen/src/codegen/selection.rs b/graphql_client_codegen/src/codegen/selection.rs index ec1703b8..9a1fa0fe 100644 --- a/graphql_client_codegen/src/codegen/selection.rs +++ b/graphql_client_codegen/src/codegen/selection.rs @@ -12,8 +12,7 @@ use crate::{ }, schema::{Schema, TypeId}, type_qualifiers::GraphqlTypeQualifier, - GraphQLClientCodegenOptions, - GeneralError, + GeneralError, GraphQLClientCodegenOptions, }; use heck::*; use proc_macro2::{Ident, Span, TokenStream}; @@ -43,12 +42,27 @@ pub(crate) fn render_response_data_fields<'a>( if let Some(custom_response_type) = options.custom_response_type() { if operation.selection_set.len() == 1 { let selection_id = operation.selection_set[0]; - let selection_field = query.query.get_selection(selection_id).as_selected_field() - .ok_or_else(|| GeneralError(format!("Custom response type {custom_response_type} will only work on fields")))?; - calculate_custom_response_type_selection(&mut expanded_selection, response_data_type_id, custom_response_type, selection_id, selection_field); + let selection_field = query + .query + .get_selection(selection_id) + .as_selected_field() + .ok_or_else(|| { + GeneralError(format!( + "Custom response type {custom_response_type} will only work on fields" + )) + })?; + calculate_custom_response_type_selection( + &mut expanded_selection, + response_data_type_id, + custom_response_type, + selection_id, + selection_field, + ); return Ok(expanded_selection); } else { - return Err(GeneralError(format!("Custom response type {custom_response_type} requires single selection field"))); + return Err(GeneralError(format!( + "Custom response type {custom_response_type} requires single selection field" + ))); } } @@ -66,10 +80,10 @@ pub(crate) fn render_response_data_fields<'a>( fn calculate_custom_response_type_selection<'a>( context: &mut ExpandedSelection<'a>, struct_id: ResponseTypeId, - custom_response_type: &'a String, + custom_response_type: &'a str, selection_id: SelectionId, - field: &'a SelectedField) -{ + field: &'a SelectedField, +) { let (graphql_name, rust_name) = context.field_name(field); let struct_name_string = full_path_prefix(selection_id, context.query); let field = context.query.schema.get_field(field.field_id); @@ -88,7 +102,7 @@ fn calculate_custom_response_type_selection<'a>( name: struct_name_string.into(), }); context.push_type_alias(TypeAlias { - name: custom_response_type.as_str(), + name: custom_response_type, struct_id, boxed: false, }); diff --git a/graphql_client_codegen/src/query/selection.rs b/graphql_client_codegen/src/query/selection.rs index 018e6f22..d7e14e2d 100644 --- a/graphql_client_codegen/src/query/selection.rs +++ b/graphql_client_codegen/src/query/selection.rs @@ -34,11 +34,7 @@ pub(super) fn validate_type_conditions( TypeId::Union(union_id) => { let union = query.schema.get_union(union_id); - if !union - .variants - .iter() - .any(|variant| *variant == selected_type) - { + if !union.variants.contains(&selected_type) { return Err(QueryValidationError::new(format!( "The spread {}... on {} is not valid.", union.name, diff --git a/graphql_client_codegen/src/schema/json_conversion.rs b/graphql_client_codegen/src/schema/json_conversion.rs index 18dea687..2cb2bbd1 100644 --- a/graphql_client_codegen/src/schema/json_conversion.rs +++ b/graphql_client_codegen/src/schema/json_conversion.rs @@ -146,14 +146,7 @@ fn ingest_enum(schema: &mut Schema, enm: &mut FullType) { .as_mut() .expect("enm.enum_values.as_mut()") .iter_mut() - .map(|v| { - std::mem::take( - v.name - .as_mut() - .take() - .expect("variant.name.as_mut().take()"), - ) - }) + .map(|v| std::mem::take(v.name.as_mut().expect("variant.name.as_mut().take()"))) .collect(); let enm = super::StoredEnum { name, variants }; diff --git a/graphql_client_codegen/src/tests/mod.rs b/graphql_client_codegen/src/tests/mod.rs index aaed3e5d..5bd158f9 100644 --- a/graphql_client_codegen/src/tests/mod.rs +++ b/graphql_client_codegen/src/tests/mod.rs @@ -62,7 +62,8 @@ fn blended_custom_types_works() { match r { Ok(_) => { // Variables and returns should be replaced with custom types - assert!(generated_code.contains("pub type SearchQuerySearch = external_crate :: Transaction")); + assert!(generated_code + .contains("pub type SearchQuerySearch = external_crate :: Transaction")); assert!(generated_code.contains("pub type extern_ = external_crate :: ID")); } Err(e) => { diff --git a/graphql_query_derive/src/lib.rs b/graphql_query_derive/src/lib.rs index c6a7eca3..e1314f16 100644 --- a/graphql_query_derive/src/lib.rs +++ b/graphql_query_derive/src/lib.rs @@ -106,7 +106,7 @@ fn build_graphql_client_derive_options( if let Some(custom_variable_types) = custom_variable_types { options.set_custom_variable_types(custom_variable_types); } - + if let Some(custom_response_type) = custom_response_type { options.set_custom_response_type(custom_response_type); }