fix(swift): convert scalar values in GraphQLSelectionSet template#991
fix(swift): convert scalar values in GraphQLSelectionSet template#991Take111 wants to merge 2 commits intoaws-amplify:mainfrom
Conversation
Add convertFieldValues/convertValue helpers to GraphQLSelectionSet template that use GraphQLField.type metadata to convert scalar values via JSONDecodable.init(jsonValue:), with a fast-path type check to skip conversion when the value is already the correct type.
There was a problem hiding this comment.
Pull request overview
This PR updates the Swift GraphQLSelectionSet decoding template to proactively convert raw JSON snapshot values into their expected scalar types (notably enums) using GraphQLField.type metadata, avoiding crashes from direct casting of raw String values to enum types.
Changes:
- Add
convertFieldValues/convertValuehelpers to convert decoded snapshot values based onGraphQLOutputTypemetadata before initializing the selection set snapshot. - Apply conversion recursively for nested objects and lists.
- Update Swift codegen Jest snapshots to match the new generated template output.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/graphql-types-generator/src/swift/appSyncCompatibilityTypes.ts | Adds snapshot value conversion during GraphQLSelectionSet decoding using field type metadata. |
| packages/graphql-types-generator/test/swift/snapshots/codeGeneration.ts.snap | Updates expected Swift generator snapshot output for the new conversion helpers. |
| packages/graphql-generator/src/tests/snapshots/types.test.ts.snap | Updates expected snapshot output where the Swift selection set template is emitted/validated. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| guard let field = selection as? GraphQLField else { continue } | ||
| let key = field.responseKey | ||
| guard let value = result[key], let unwrapped = value else { continue } | ||
| result[key] = convertValue(unwrapped, for: field.type) |
There was a problem hiding this comment.
convertFieldValues(in:using:) only processes GraphQLField selections. Generated selections arrays also include GraphQLFragmentSpread, GraphQLTypeCondition, GraphQLBooleanCondition, and GraphQLTypeCase (see Swift codegen), so scalar conversion will be skipped for enum/scalar fields that are selected via fragments/inline fragments/type cases. This likely reintroduces the same decoding crash for enums inside fragments/type conditions. Consider recursively traversing these selection kinds (e.g., expanding fragment spreads to fragment.selections, recursing into selections for boolean/type conditions, and processing both default and all variants for type cases) so all reachable fields get converted.
| guard let field = selection as? GraphQLField else { continue } | |
| let key = field.responseKey | |
| guard let value = result[key], let unwrapped = value else { continue } | |
| result[key] = convertValue(unwrapped, for: field.type) | |
| switch selection { | |
| case let field as GraphQLField: | |
| let key = field.responseKey | |
| guard let value = result[key], let unwrapped = value else { continue } | |
| result[key] = convertValue(unwrapped, for: field.type) | |
| case let fragmentSpread as GraphQLFragmentSpread: | |
| result = convertFieldValues( | |
| in: result, | |
| using: type(of: fragmentSpread.fragment).selections | |
| ) | |
| case let booleanCondition as GraphQLBooleanCondition: | |
| result = convertFieldValues( | |
| in: result, | |
| using: booleanCondition.selections | |
| ) | |
| case let typeCondition as GraphQLTypeCondition: | |
| result = convertFieldValues( | |
| in: result, | |
| using: typeCondition.selections | |
| ) | |
| case let typeCase as GraphQLTypeCase: | |
| result = convertFieldValues( | |
| in: result, | |
| using: typeCase.default | |
| ) | |
| for (_, variantSelections) in typeCase.variants { | |
| result = convertFieldValues( | |
| in: result, | |
| using: variantSelections | |
| ) | |
| } | |
| default: | |
| continue | |
| } |
Description of changes
Add convertFieldValues/convertValue helpers to GraphQLSelectionSet template that use GraphQLField.type metadata to convert scalar values via JSONDecodable.init(jsonValue:), with a fast-path type check to skip conversion when the value is already the correct type.
This fixes the crash when decoding GraphQL responses containing enum fields, where raw String values in the snapshot fail to cast directly to the enum type.
Codegen Paramaters Changed or Added
None
Issue #, if available
Related issue in amplify-swift: aws-amplify/amplify-swift#3953
Description of how you validated changes
Verified that the generated template output matches the manually tested fix in amplify-swift. Unit tests for enum decoding (non-optional, optional, null, nested list, unknown value) are in the amplify-swift PR.
Checklist
yarn testpassespath) behave differently on windows.type,input,enum,interface,unionand scalar types.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.