Skip to content

fix(swift): convert scalar values in GraphQLSelectionSet template#991

Open
Take111 wants to merge 2 commits intoaws-amplify:mainfrom
Take111:fix/graphql-enum-casting-in-selection-set
Open

fix(swift): convert scalar values in GraphQLSelectionSet template#991
Take111 wants to merge 2 commits intoaws-amplify:mainfrom
Take111:fix/graphql-enum-casting-in-selection-set

Conversation

@Take111
Copy link

@Take111 Take111 commented Mar 4, 2026

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

  • PR description included
  • yarn test passes
  • E2E test run linked
  • Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)
  • Breaking changes to existing customers are released behind a feature flag or major version update
  • Changes are tested using sample applications for all relevant platforms (iOS/android/flutter/Javascript) that use the feature added/modified
  • Changes are tested on windows. Some Node functions (such as path) behave differently on windows.
  • Changes adhere to the GraphQL Spec and supports the GraphQL types type, input, enum, interface, union and scalar types.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

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.
@Take111 Take111 marked this pull request as ready for review March 4, 2026 12:12
@Take111 Take111 requested a review from a team as a code owner March 4, 2026 12:12
Copilot AI review requested due to automatic review settings March 4, 2026 12:12
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 / convertValue helpers to convert decoded snapshot values based on GraphQLOutputType metadata 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.

Comment on lines +116 to +119
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)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants