Skip to content

Wrong usage of Fragment passed code generation process #340

@kikuchy

Description

@kikuchy

Thank you for really useful package! Our team is using this heavily.

We found one problem, the Fragment based on wrong type will pass the code generation process.

Env:

  graphql_codegen: ^0.13.11
  build_runner: ^2.4.8

Code:

type Query {
    foo(id: ID!): FooCore!
    bar(id: ID!): BarCore!
}


type BarCore {
    something: Something!
}

type FooCore {
    something: Something!
}

type Something {
    id: ID!
}

query FooQuery {
    foo(id: "1") {
        ...Share
    }

    bar(id: "1") {
        # ⭐ It should be error but code generation will not be error
        ...Share
    }
}

fragment Share on FooCore {
    something {
        id
    }
}

Command line:

➜  graphql_codegen_trouble2 flutter pub run build_runner build
Deprecated. Use `dart run` instead.
[INFO] Generating build script completed, took 222ms
[INFO] Reading cached asset graph completed, took 63ms
[INFO] Checking for updates since last build completed, took 684ms
[INFO] Running build completed, took 257ms
[INFO] Caching finalized dependency graph completed, took 34ms
[INFO] Succeeded after 295ms with 1 outputs (1 actions)

Output:

Part of `Query$FooQuery`

foo is typed as Fragment$Share, bar is typed as Query$FooQuery$bar.

class Query$FooQuery {
  Query$FooQuery({
    required this.foo,
    required this.bar,
    this.$__typename = 'Query',
  });

  factory Query$FooQuery.fromJson(Map<String, dynamic> json) {
    final l$foo = json['foo'];
    final l$bar = json['bar'];
    final l$$__typename = json['__typename'];
    return Query$FooQuery(
      foo: Fragment$Share.fromJson((l$foo as Map<String, dynamic>)),
      bar: Query$FooQuery$bar.fromJson((l$bar as Map<String, dynamic>)),
      $__typename: (l$$__typename as String),
    );
  }

  final Fragment$Share foo;

  final Query$FooQuery$bar bar;

  final String $__typename;

  Map<String, dynamic> toJson() {
    final _resultData = <String, dynamic>{};
    final l$foo = foo;
    _resultData['foo'] = l$foo.toJson();
    final l$bar = bar;
    _resultData['bar'] = l$bar.toJson();
    final l$$__typename = $__typename;
    _resultData['__typename'] = l$$__typename;
    return _resultData;
  }

  @override
  int get hashCode {
    final l$foo = foo;
    final l$bar = bar;
    final l$$__typename = $__typename;
    return Object.hashAll([
      l$foo,
      l$bar,
      l$$__typename,
    ]);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    if (!(other is Query$FooQuery) || runtimeType != other.runtimeType) {
      return false;
    }
    final l$foo = foo;
    final lOther$foo = other.foo;
    if (l$foo != lOther$foo) {
      return false;
    }
    final l$bar = bar;
    final lOther$bar = other.bar;
    if (l$bar != lOther$bar) {
      return false;
    }
    final l$$__typename = $__typename;
    final lOther$$__typename = other.$__typename;
    if (l$$__typename != lOther$$__typename) {
      return false;
    }
    return true;
  }
}
Part of `Query$FooQuery$bar`

Has complete fileds.

class Fragment$Share {
  Fragment$Share({
    required this.something,
    this.$__typename = 'FooCore',
  });

  factory Fragment$Share.fromJson(Map<String, dynamic> json) {
    final l$something = json['something'];
    final l$$__typename = json['__typename'];
    return Fragment$Share(
      something: Fragment$Share$something.fromJson(
          (l$something as Map<String, dynamic>)),
      $__typename: (l$$__typename as String),
    );
  }

  final Fragment$Share$something something;

  final String $__typename;

  Map<String, dynamic> toJson() {
    final _resultData = <String, dynamic>{};
    final l$something = something;
    _resultData['something'] = l$something.toJson();
    final l$$__typename = $__typename;
    _resultData['__typename'] = l$$__typename;
    return _resultData;
  }

  @override
  int get hashCode {
    final l$something = something;
    final l$$__typename = $__typename;
    return Object.hashAll([
      l$something,
      l$$__typename,
    ]);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    if (!(other is Fragment$Share) || runtimeType != other.runtimeType) {
      return false;
    }
    final l$something = something;
    final lOther$something = other.something;
    if (l$something != lOther$something) {
      return false;
    }
    final l$$__typename = $__typename;
    final lOther$$__typename = other.$__typename;
    if (l$$__typename != lOther$$__typename) {
      return false;
    }
    return true;
  }
}
Part of `Query$FooQuery$bar`

No fields.

class Query$FooQuery$bar {
  Query$FooQuery$bar({this.$__typename = 'BarCore'});

  factory Query$FooQuery$bar.fromJson(Map<String, dynamic> json) {
    final l$$__typename = json['__typename'];
    return Query$FooQuery$bar($__typename: (l$$__typename as String));
  }

  final String $__typename;

  Map<String, dynamic> toJson() {
    final _resultData = <String, dynamic>{};
    final l$$__typename = $__typename;
    _resultData['__typename'] = l$$__typename;
    return _resultData;
  }

  @override
  int get hashCode {
    final l$$__typename = $__typename;
    return Object.hashAll([l$$__typename]);
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    if (!(other is Query$FooQuery$bar) || runtimeType != other.runtimeType) {
      return false;
    }
    final l$$__typename = $__typename;
    final lOther$$__typename = other.$__typename;
    if (l$$__typename != lOther$$__typename) {
      return false;
    }
    return true;
  }
}

It looks expanding Share in bar I marked with ⭐ should be error, but It success code generation.
(IntelliJ's Graphql plugin shows error
スクリーンショット 2024-03-01 22 12 16
)

It doesn't stop our work, but it caused a little trouble.
We hope this behavior will fix!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions