From 410e92eb5b9bb23b2cdbb5e2e400380fcb6a0566 Mon Sep 17 00:00:00 2001 From: Marco Correia Date: Tue, 14 Oct 2025 09:43:35 +0100 Subject: [PATCH] Fix: Preserve trailing underscores in GraphQL field names --- graphql_client/Cargo.toml | 2 +- graphql_client_codegen/src/codegen/inputs.rs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/graphql_client/Cargo.toml b/graphql_client/Cargo.toml index 680d7068..6422bf4d 100644 --- a/graphql_client/Cargo.toml +++ b/graphql_client/Cargo.toml @@ -10,7 +10,7 @@ categories = ["network-programming", "web-programming", "wasm"] edition = "2018" homepage = "https://github.com/graphql-rust/graphql-client" readme = "../README.md" -rust-version.workspace = true +rust-version = "1.64.0" [package.metadata.docs.rs] features = ["reqwest"] diff --git a/graphql_client_codegen/src/codegen/inputs.rs b/graphql_client_codegen/src/codegen/inputs.rs index d8cc1080..b6c12692 100644 --- a/graphql_client_codegen/src/codegen/inputs.rs +++ b/graphql_client_codegen/src/codegen/inputs.rs @@ -9,6 +9,18 @@ use heck::{ToSnakeCase, ToUpperCamelCase}; use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; +fn to_snake_case_preserve_trailing_underscores(s: &str) -> String { + let trailing_underscores = s.chars().rev().take_while(|&c| c == '_').count(); + if trailing_underscores == 0 { + s.to_snake_case() + } else { + let without_trailing = &s[..s.len() - trailing_underscores]; + let suffix = "_".repeat(trailing_underscores); + format!("{}{}", without_trailing.to_snake_case(), suffix) + } +} + + pub(super) fn generate_input_object_definitions( all_used_types: &UsedTypes, options: &GraphQLClientCodegenOptions, @@ -61,7 +73,7 @@ fn generate_struct( let struct_name = Ident::new(safe_name.as_ref(), Span::call_site()); let fields = input.fields.iter().map(|(field_name, field_type)| { - let safe_field_name = keyword_replace(field_name.to_snake_case()); + let safe_field_name = keyword_replace(to_snake_case_preserve_trailing_underscores(field_name)); let annotation = field_rename_annotation(field_name, safe_field_name.as_ref()); let name_ident = Ident::new(safe_field_name.as_ref(), Span::call_site()); let normalized_field_type_name = options