Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ferry cannot decompose fragment on TypeCondition #595

Open
Masadow opened this issue Apr 10, 2024 · 1 comment
Open

Ferry cannot decompose fragment on TypeCondition #595

Masadow opened this issue Apr 10, 2024 · 1 comment

Comments

@Masadow
Copy link

Masadow commented Apr 10, 2024

Assume the following schema :

  interface GenericValue {
    name: String
  }

  type TextValue implements GenericValue {
    name: String
    text: String
  }

  type NumberValue implements GenericValue {
    name: String
    number: Int
  }

  type Test {
    value: GenericValue
  }

  type CrashTest {
    a: Test
    b: Test
  }

  type Query {
    fixme: CrashTest
  }

And now, in your app, you query it like

fragment Text on TextValue {
  name
  text
}

fragment Number on NumberValue {
  name
  number
}

fragment CrashTestFragment on Test {
  value {
    ...Text
    ...Number
  }
}

query Test {
  fixme {
    a {
      ...CrashTestFragment
    }
    b {
      ...CrashTestFragment
    }
  }
}

Building the following will result in

[SEVERE] ferry_generator:graphql_builder on lib/src/views/questionnaires/questionnaires.graphql:

Bad state: No element
dart:collection                                          ListBase.firstWhere
package:gql_code_builder/src/operation/data.dart 457:8   _getFieldTypeNode
package:gql_code_builder/src/operation/data.dart 153:24  buildSelectionSetDataClasses.<fn>
dart:core                                                Iterable.toList
package:gql_code_builder/src/operation/data.dart 169:5   buildSelectionSetDataClasses
package:gql_code_builder/src/operation/data.dart 235:22  buildSelectionSetDataClasses.<fn>
dart:core                                                List.addAll
package:gql_code_builder/src/operation/data.dart 234:10  buildSelectionSetDataClasses
package:gql_code_builder/src/operation/data.dart 235:22  buildSelectionSetDataClasses.<fn>
dart:core                                                List.addAll
package:gql_code_builder/src/operation/data.dart 234:10  buildSelectionSetDataClasses
package:gql_code_builder/src/operation/data.dart 235:22  buildSelectionSetDataClasses.<fn>
dart:core                                                List.addAll
package:gql_code_builder/src/operation/data.dart 234:10  buildSelectionSetDataClasses
package:gql_code_builder/src/operation/data.dart 24:10   buildOperationDataClasses
package:gql_code_builder/data.dart 36:17                 buildDataLibrary.<fn>
dart:core                                                Iterable.toList
package:gql_code_builder/data.dart 46:8                  buildDataLibrary
package:ferry_generator/graphql_builder.dart 104:22      GraphqlBuilder.build

Until this is resolved, a workaround is to wrap your fragment with the type condition :

fragment CrashTestFragment on Test {
  value {
    ... on TextValue { ...Text }
    ... on NumberValue { ...Number }
  }
}

In case it's useful, source of graphql manifest : https://spec.graphql.org/October2021/#sec-Type-Conditions

@knaeckeKami
Copy link
Collaborator

knaeckeKami commented Apr 10, 2024

the issue is here in buildSelectionSetDataClasses

    final typeDef = getTypeDefinitionNode(
        schemaSource.document,
        type,
      )!;
    final typeNode = _getFieldTypeNode(
        typeDef,
        node.name.value,
      );

we only get the type definition node for the type A the is queried, but the selection may come from a fragment that is on a subtype B of A
So, when we lookup the queried field in A, we can't find it, as it is only in B.

We need to check the selections list for FragmentSpreadNode, and use the type from that FragmentSpreadNode instead when possible.

Edge cases to think about:

  • what if selections occur with different types in different fragment spread nodes? the "right" way to handle is is probably the generate the same code as if the user explicitly used type conditions

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

No branches or pull requests

2 participants