ferry icon indicating copy to clipboard operation
ferry copied to clipboard

Bug when generating the classes of fragments with a union type

Open Stefuu opened this issue 4 years ago • 8 comments

I think i found a bug with the class generation, i have a query structure that makes use of fragments that have unions, like the ComponentsFragment fragment, and everything works perfectly when i test it on graphql playground, but the ferry_generator seems to not be able to make sense of the fragment ComponentsFragment when its used inside the getPage query and/or inside PageBuilderChildScrollFragment, i get an error when generating the classes with the command flutter pub run build_runner build --delete-conflicting-outputs. The error message makes no sense to me because this structure works in the scope of graphql, so it should work with ferry, that's why i think it could be a bug.

Graphql structure:

query getPage($pageId: String!, $data: String) {
  page(pageId: $pageId, data: $data) {
    id
    components {
      ... on PageBuilderChildScrollContract {
        ...PageBuilderChildScrollFragment
      }
      ...ComponentsFragment
    }
  }
}

fragment PageBuilderChildScrollFragment on PageBuilderChildScrollContract {
  name
  components {
    ...ComponentsFragment
  }
}

fragment ComponentsFragment on Component {
  ... on SearchTermDisplayContract {
    ...SearchTermDisplayFragment
  }
  ... on SuperDealsContract {
    ...SuperDealsFragment
  }
}

fragment SearchTermDisplayFragment on SearchTermDisplayContract {
  name
  searchTerm
  description
}

fragment SuperDealsFragment on SuperDealsContract {
  name
  items{
    price
    image{
      id
      src
      alt
      position
      title
    }
  }
}

Graphql schema

interface Component {
  name: String!
}

type SearchTermDisplayContract implements Component {
  name: String!
  searchTerm: String
  description: String
}


type SuperDealsContract implements Component {
  name: String!
}

type Page {
  id: String
  components: [Component]
}

type PageBuilderChildScrollContract implements Component {
  name: String!
  components: [Component!]
}

type Query {
  page(pageId: String!, data: String): Page
}

Error when running "flutter pub run build_runner build --delete-conflicting-outputs":

[INFO] Running build...
[INFO] 2.2s elapsed, 3/4 actions completed.
[INFO] Running build completed, took 2.8s

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 49ms

[SEVERE] gql_build:data_builder on lib/graphql/get_page.graphql (cached):

Stack Overflow
[SEVERE] built_value_generator:built_value on lib/graphql/get_page.req.gql.dart (cached):
Error in BuiltValueGenerator for abstract class GgetPageReq implements Built<GgetPageReq, dynamic>, OperationRequest<dynamic, GgetPageVars>.
Please make the following changes to use BuiltValue:

1. Make field optimisticResponse have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
[SEVERE] Failed after 2.9s
pub finished with exit code 1

Stefuu avatar Nov 26 '21 18:11 Stefuu

I have the same problem

netogdn999 avatar Nov 26 '21 18:11 netogdn999

Not to negate the original issue filed here that's specifically about fragments with a union type, but this misleading error can also show up if you have misspelled (or have an outdated version of) something in your .graphql file. Just in case this is related to anybody else's issue here, you may want to try copy/pasting your graphql into GraphQL Playground or Altair to verify the query is spelled correctly. It might also help to double-check that your query name matches exactly with what is defined in your schema file.

Source: https://zenn.dev/kenghaya/articles/a49261a6914d53 (you may need to translate this page)

lisamartin00 avatar Dec 13 '21 18:12 lisamartin00

I see your point @lisamartin00, but in this case i have tested everything in GraphQL Playground, and it works perfectly there, and still it doesn't work when i try to generate the classes with ferry using the same schema, fragments and queries. Maybe i'm still missing something, but if it works in GraphQL Playground i think it should work with Ferry too.

Stefuu avatar Dec 16 '21 02:12 Stefuu

Oh 100% @Stefuu I think you have a legitimate bug that is separate from what I was talking about. I just wanted to point out for those that stumble onto this issue that the error message you received:

Error in BuiltValueGenerator for abstract class GgetPageReq implements Built<GgetPageReq, dynamic>, OperationRequest<dynamic, GgetPageVars>.
Please make the following changes to use BuiltValue:

1. Make field optimisticResponse have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
[SEVERE] Failed after 2.9s
pub finished with exit code 1

is misleading and can have other causes besides your fragment / union issue. Hope you get some help soon! 🤞

lisamartin00 avatar Dec 16 '21 04:12 lisamartin00

Is there any solution to that error message you posted? I'm currently following the Desktop codelab on the website, and I'm getting that error every time I run the flutter pub run build_runner build --delete-conflicting-outputs command.

[SEVERE] built_value_generator:built_value on lib/third_party/github_graphql_schema/__generated__/schema.docs.schema.gql.dart (cached):
Error in BuiltValueGenerator for abstract class GVerifiableDomainOrder implements Built<GVerifiableDomainOrder, dynamic>.
Please make the following changes to use BuiltValue:

1. Make field direction have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.

And when I go and check, there is a class that is missing.

fenrirstrife avatar Jan 05 '22 05:01 fenrirstrife

@fenrirstrife

What I've resorted to for now is just copying and pasting what I need everywhere, and then treating it as dynamic in the code that needs to deal with it. It's not ideal, but it works. I've also stuck TODO comments on every line that uses dynamic with a reminder to fix it when this issue gets fixed.

Here's an example. Let's say that you have this schema:

interface Example {
  id: ID!
}

type NamedExample implements Example {
  id: ID!
  name: String!
}

type Query {
  example: Example!
}

This does not work:

fragment NamedExampleFragment on NamedExample {
  name
}

query ExampleQuery {
  example {
    id
    ... on NamedExample {
      ...NamedExampleFragment
    }
  }
}

But this does:

query ExampleQuery {
  example {
    id
    ... on NamedExample {
      # No fragment used.
      name
    }
  }
}

DeedleFake avatar Jan 05 '22 06:01 DeedleFake

I am here that I was also misled to this error but the real issue for me was not having up-to-date schema file locally.

get-graphql-schema http://localhost:1401/graphql > lib/schema.graphql

this resolved my issue.

Leaving this just to inform the ones like me...

aquadesk avatar Feb 28 '22 19:02 aquadesk

Now I encountered the issue and I have a minimal reproduce setup https://github.com/aquadesk/ferry_codegen_test

detail captured here https://github.com/aquadesk/ferry_codegen_test/issues/1

I think it's not even getting finished the schema.schema.gql.dart

with 0 graphql files, you still get errors.

[SEVERE] built_value_generator:built_value on lib/schema.schema.gql.dart:
Error in BuiltValueGenerator for /ferry_codegen_test/lib/schema.schema.gql.dart.
...
1. Declare GENUM_AQUATIC_ACTIVETYPE.serializer as: static Serializer<GENUM_AQUATIC_ACTIVETYPE> get serializer => _$gENUMAQUATICACTIVETYPESerializer; got static Serializer<GENUM_AQUATIC_ACTIVETYPE> get serializer => _$genumAquaticActivetypeSerializer;
2. Declare GENUM_AQUATIC_BREEDINGLEVEL.serializer as: static Serializer<GENUM_AQUATIC_BREEDINGLEVEL> get serializer => _$gENUMAQUATICBREEDINGLEVELSerializer; got static Serializer<GENUM_AQUATIC_BREEDINGLEVEL> get serializer => _$genumAquaticBreedinglevelSerializer;
3. Declare GENUM_AQUATIC_CARELEVEL.serializer as: static Serializer<GENUM_AQUATIC_CARELEVEL> get serializer => _$gENUMAQUATICCARELEVELSerializer; got static Serializer<GENUM_AQUATIC_CARELEVEL> get serializer => _$genumAquaticCarelevelSerializer;
4. Declare GENUM_AQUATIC_DIET.serializer as: static Serializer<GENUM_AQUATIC_DIET> get serializer => _$gENUMAQUATICDIETSerializer; got static Serializer<GENUM_AQUATIC_DIET> get serializer => _$genumAquaticDietSerializer;
5. Declare GENUM_AQUATIC_SCHOOLING.serializer as: static Serializer<GENUM_AQUATIC_SCHOOLING> get serializer => _$gENUMAQUAT
...

aquadesk avatar Mar 02 '22 03:03 aquadesk