comigor / artemis

Build dart types from GraphQL schemas and queries
MIT License
495 stars 119 forks source link

Queries with fragments don't work with Artemis v7 #350

Closed paoloposo closed 3 years ago

paoloposo commented 3 years ago

Bug description

After upgrading to version 7 in order to migrate my app to null-safety, I ran into an issue where my queries would fail. After some investigating I narrowed it down to the use of fragments in my queries.

I made a minimal working example: https://github.com/paoloposo/artemis_test

It uses the Pokemon sample API. There are two queries in the example that request the same data. One has all the fields directly in the query:

query withoutFragments {
    pokemon(name: "Blastoise") {
        id
        name
        height {
            minimum
            maximum
        }
        weight {
            minimum
            maximum
        }
        fleeRate
    }
}

The other one uses a fragment:

fragment PokemonDetails on Pokemon {
    id
    name
    height {
        minimum
        maximum
    }
    weight {
        minimum
        maximum
    }
    fleeRate
}
query withFragments {
    pokemon(name: "Blastoise") {
        ...PokemonDetails
    }
}

The first one, without the fragment, produces the expected result:

{pokemon: {id: UG9rZW1vbjowMDk=, name: Blastoise, height: {minimum: 1.4m, maximum: 1.8m}, weight: {minimum: 74.81kg, maximum: 96.19kg}, fleeRate: 0.05}}

The one with the fragment produces this, however:

{pokemon: null}

Specs

Artemis version: 7.1.1-beta.1

build.yaml: ```yaml targets: $default: sources: - lib/** - graphql/** builders: json_serializable: options: include_if_null: false artemis: options: # fragments_glob: graphql/fragments/*.graphql # this doesn't work either schema_mapping: - schema: graphql/schema.graphql queries_glob: graphql/operations/**.graphql output: lib/graphql/graphql_api.dart fragments_glob: graphql/fragments/*.graphql ```
Artemis output: ```bash Precompiling executable... Precompiled build_runner:build_runner. [INFO] Entrypoint:Generating build script... [INFO] Entrypoint:Generating build script completed, took 298ms [INFO] Bootstrap:Precompiling build script...... [INFO] Bootstrap:Precompiling build script... completed, took 6.2s [FINE] Bootstrap:Core package locations file does not exist [WARNING] build.fallback: The package `artemis_test` does not include some required sources in any of its targets (see their build.yaml file). The missing sources are: - $package$ [INFO] BuildDefinition:Initializing inputs [INFO] BuildDefinition:Building new asset graph... [INFO] BuildDefinition:Building new asset graph completed, took 589ms [INFO] BuildDefinition:Checking for unexpected pre-existing outputs.... [INFO] BuildDefinition:Checking for unexpected pre-existing outputs. completed, took 1ms [INFO] Build:Running build... [FINE] artemis:artemis on lib/$lib$:-> Class [FINE] artemis:artemis on lib/$lib$:┌ [TypeName(name:r'withFragments'), TypeName(name:r'Query')][Query][null null] () [FINE] artemis:artemis on lib/$lib$:| [TypeName(name:r'withFragments'), TypeName(name:r'Query')][Query][ClassName(name:r'Pokemon') ClassPropertyName(name:r'pokemon')] -> WithFragments$Query$Pokemon? [FINE] artemis:artemis on lib/$lib$:| -> Class [FINE] artemis:artemis on lib/$lib$:| ┌ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][null null] () [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')]: ... expanding PokemonDetails [FINE] artemis:artemis on lib/$lib$:| | | -> Class [FINE] artemis:artemis on lib/$lib$:| | | ┌ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | | [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | | [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | └ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | <- Generated class WithFragments$Query$Pokemon$PokemonDetailsMixin$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| | | -> Class [FINE] artemis:artemis on lib/$lib$:| | | ┌ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | | [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | | [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | └ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), FragmentName(name:r'PokemonDetailsMixin'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | <- Generated class WithFragments$Query$Pokemon$PokemonDetailsMixin$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| └ [TypeName(name:r'withFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][null null] () [FINE] artemis:artemis on lib/$lib$:| <- Generated class WithFragments$Query$Pokemon. [FINE] artemis:artemis on lib/$lib$:└ [TypeName(name:r'withFragments'), TypeName(name:r'Query')][Query][null null] () [FINE] artemis:artemis on lib/$lib$:<- Generated class WithFragments$Query. [FINE] artemis:artemis on lib/$lib$:-> Fragment [FINE] artemis:artemis on lib/$lib$:┌ [][PokemonDetails] [FINE] artemis:artemis on lib/$lib$:| [FragmentName(name:r'PokemonDetails')][Pokemon][ClassName(name:r'ID') ClassPropertyName(name:r'id')] -> String [FINE] artemis:artemis on lib/$lib$:| [FragmentName(name:r'PokemonDetails')][Pokemon][ClassName(name:r'String') ClassPropertyName(name:r'name')] -> String? [FINE] artemis:artemis on lib/$lib$:| [FragmentName(name:r'PokemonDetails')][Pokemon][ClassName(name:r'PokemonDimension') ClassPropertyName(name:r'height')] -> PokemonDetailsMixin$PokemonDimension? [FINE] artemis:artemis on lib/$lib$:| -> Class [FINE] artemis:artemis on lib/$lib$:| ┌ [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| └ [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| <- Generated class PokemonDetailsMixin$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| [FragmentName(name:r'PokemonDetails')][Pokemon][ClassName(name:r'PokemonDimension') ClassPropertyName(name:r'weight')] -> PokemonDetailsMixin$PokemonDimension? [FINE] artemis:artemis on lib/$lib$:| -> Class [FINE] artemis:artemis on lib/$lib$:| ┌ [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| └ [FragmentName(name:r'PokemonDetails'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| <- Generated class PokemonDetailsMixin$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| [FragmentName(name:r'PokemonDetails')][Pokemon][ClassName(name:r'Float') ClassPropertyName(name:r'fleeRate')] -> double? [FINE] artemis:artemis on lib/$lib$:└ [][PokemonDetails] [FINE] artemis:artemis on lib/$lib$:<- Generated fragment PokemonDetailsMixin. [FINE] artemis:artemis on lib/$lib$:-> Class [FINE] artemis:artemis on lib/$lib$:┌ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query')][Query][null null] () [FINE] artemis:artemis on lib/$lib$:| [TypeName(name:r'withoutFragments'), TypeName(name:r'Query')][Query][ClassName(name:r'Pokemon') ClassPropertyName(name:r'pokemon')] -> WithoutFragments$Query$Pokemon? [FINE] artemis:artemis on lib/$lib$:| -> Class [FINE] artemis:artemis on lib/$lib$:| ┌ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][null null] () [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][ClassName(name:r'ID') ClassPropertyName(name:r'id')] -> String [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][ClassName(name:r'String') ClassPropertyName(name:r'name')] -> String? [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][ClassName(name:r'PokemonDimension') ClassPropertyName(name:r'height')] -> WithoutFragments$Query$Pokemon$PokemonDimension? [FINE] artemis:artemis on lib/$lib$:| | -> Class [FINE] artemis:artemis on lib/$lib$:| | ┌ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | └ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | <- Generated class WithoutFragments$Query$Pokemon$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][ClassName(name:r'PokemonDimension') ClassPropertyName(name:r'weight')] -> WithoutFragments$Query$Pokemon$PokemonDimension? [FINE] artemis:artemis on lib/$lib$:| | -> Class [FINE] artemis:artemis on lib/$lib$:| | ┌ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'minimum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][ClassName(name:r'String') ClassPropertyName(name:r'maximum')] -> String? [FINE] artemis:artemis on lib/$lib$:| | └ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon'), ClassName(name:r'PokemonDimension')][PokemonDimension][null null] () [FINE] artemis:artemis on lib/$lib$:| | <- Generated class WithoutFragments$Query$Pokemon$PokemonDimension. [FINE] artemis:artemis on lib/$lib$:| | [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][ClassName(name:r'Float') ClassPropertyName(name:r'fleeRate')] -> double? [FINE] artemis:artemis on lib/$lib$:| └ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query'), ClassName(name:r'Pokemon')][Pokemon][null null] () [FINE] artemis:artemis on lib/$lib$:| <- Generated class WithoutFragments$Query$Pokemon. [FINE] artemis:artemis on lib/$lib$:└ [TypeName(name:r'withoutFragments'), TypeName(name:r'Query')][Query][null null] () [FINE] artemis:artemis on lib/$lib$:<- Generated class WithoutFragments$Query. [INFO] build_resolvers:Generating SDK summary... [INFO] Heartbeat:3.0s elapsed, 1/4 actions completed. [INFO] build_resolvers:Generating SDK summary completed, took 2.7s [INFO] Heartbeat:4.2s elapsed, 3/4 actions completed. [FINE] json_serializable:json_serializable on lib/graphql/graphql_api.graphql.dart:Running JsonSerializableGenerator - 1 of 2 [FINE] json_serializable:json_serializable on lib/graphql/graphql_api.graphql.dart:Running JsonLiteralGenerator - 2 of 2 [INFO] Build:Running build completed, took 4.5s [INFO] Build:Caching finalized dependency graph... [INFO] Build:Caching finalized dependency graph completed, took 19ms [INFO] Build:Succeeded after 4.5s with 4 outputs (8 actions) ```

vasilich6107 commented 3 years ago

@paoloposo set fetchPolicy: FetchPolicy.noCache and everything will work

image

vasilich6107 commented 3 years ago

@paoloposo it seems that you are missing store setup for cache https://github.com/zino-app/graphql-flutter/tree/beta/packages/graphql#persistence

vasilich6107 commented 3 years ago

If you look on your example the error is somewhere in cache cause two queries are identical

the difference is the suource that graphql tries to get results

image

samuelchanx commented 2 years ago

@vasilich6107 May I know how to fix this issue? Using fragments in Artemis suddenly return null when used with flutter_graphql, unless I use FetchPolicy.noCache

https://github.com/zino-hofmann/graphql-flutter/issues/994

pdkcoder commented 2 years ago

Is this fixed? I'm using ^7.8.0-beta and fragment is still not working

vasilich6107 commented 2 years ago

@thphuc If you have an issue create new one with reply

pdkcoder commented 2 years ago

Hi @vasilich6107 thanks for your quick response. Yes, I have to use FetchPolicy.noCache to make my fragment work, like @samuelchanx mentioned

baconcheese113 commented 2 years ago

See #393 for the solution