From 6e0c9c1779b282a5e5c34b98a91a77f8ba30cc8c Mon Sep 17 00:00:00 2001 From: vasilich Date: Tue, 26 Jan 2021 23:31:52 +0200 Subject: [PATCH] bugfix add typename selection set --- CHANGELOG.md | 3 + lib/builder.dart | 15 +- lib/transformer/add_typename_transformer.dart | 24 +- pubspec.yaml | 2 +- .../append_type_name_test.dart | 359 ++++++++++++++---- 5 files changed, 314 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 001331f3..20663714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG +## 6.19.3-beta.1 +- bugfix of append typename - common fragments + ## 6.19.2-beta.1 - bugfix of append typename diff --git a/lib/builder.dart b/lib/builder.dart index 6e92c2fe..d9620e1e 100644 --- a/lib/builder.dart +++ b/lib/builder.dart @@ -59,7 +59,7 @@ class GraphQLQueryBuilder implements Builder { final GeneratorOptions options; /// List FragmentDefinitionNode in fragments_glob. - final List fragmentsCommon = []; + List fragmentsCommon = []; /// The generated output file. final List expectedOutputs; @@ -84,8 +84,10 @@ class GraphQLQueryBuilder implements Builder { ), ) .toList(); - fDocs.forEach((fDoc) => fragmentsCommon.addAll( - fDoc.definitions.whereType().toList())); + fDocs.forEach( + (fDoc) => fragmentsCommon.addAll( + fDoc.definitions.whereType().toList()), + ); } for (final schemaMap in options.schemaMapping) { @@ -128,6 +130,13 @@ Make sure that `queries_glob` your build.yaml file include GraphQL queries files ); }, ).toList(); + + fragmentsCommon = fragmentsCommon + .map((fragments) => transform( + fragments, + [AppendTypename(schemaMap.typeNameField)], + )) + .toList(); } final schemaAssetStream = buildStep.findAssets(Glob(schemaMap.schema)); diff --git a/lib/transformer/add_typename_transformer.dart b/lib/transformer/add_typename_transformer.dart index 9c37bf6c..a8f6a0a8 100644 --- a/lib/transformer/add_typename_transformer.dart +++ b/lib/transformer/add_typename_transformer.dart @@ -14,6 +14,10 @@ class AppendTypename extends TransformingVisitor { @override OperationDefinitionNode visitOperationDefinitionNode( OperationDefinitionNode node) { + if (node.selectionSet == null) { + return node; + } + return OperationDefinitionNode( type: node.type, name: node.name, @@ -22,10 +26,10 @@ class AppendTypename extends TransformingVisitor { span: node.span, selectionSet: SelectionSetNode( selections: [ - FieldNode(name: NameNode(value: typeName)), ...node.selectionSet.selections.where((element) => (element is! FieldNode) || - (element is FieldNode && element.name.value != typeName)) + (element is FieldNode && element.name.value != typeName)), + FieldNode(name: NameNode(value: typeName)), ], ), ); @@ -35,6 +39,10 @@ class AppendTypename extends TransformingVisitor { @override FragmentDefinitionNode visitFragmentDefinitionNode( FragmentDefinitionNode node) { + if (node.selectionSet == null) { + return node; + } + return FragmentDefinitionNode( name: node.name, typeCondition: node.typeCondition, @@ -42,10 +50,10 @@ class AppendTypename extends TransformingVisitor { span: node.span, selectionSet: SelectionSetNode( selections: [ - FieldNode(name: NameNode(value: typeName)), ...node.selectionSet.selections.where((element) => (element is! FieldNode) || - (element is FieldNode && element.name.value != typeName)) + (element is FieldNode && element.name.value != typeName)), + FieldNode(name: NameNode(value: typeName)), ], ), ); @@ -64,10 +72,10 @@ class AppendTypename extends TransformingVisitor { span: node.span, selectionSet: SelectionSetNode( selections: [ - FieldNode(name: NameNode(value: typeName)), ...node.selectionSet.selections.where((element) => (element is! FieldNode) || - (element is FieldNode && element.name.value != typeName)) + (element is FieldNode && element.name.value != typeName)), + FieldNode(name: NameNode(value: typeName)), ], ), ); @@ -88,10 +96,10 @@ class AppendTypename extends TransformingVisitor { span: node.span, selectionSet: SelectionSetNode( selections: [ - FieldNode(name: NameNode(value: typeName)), ...node.selectionSet.selections.where((element) => (element is! FieldNode) || - (element is FieldNode && element.name.value != typeName)) + (element is FieldNode && element.name.value != typeName)), + FieldNode(name: NameNode(value: typeName)), ], ), ); diff --git a/pubspec.yaml b/pubspec.yaml index c09fef9e..181265e6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: artemis -version: 6.19.2-beta.1 +version: 6.19.3-beta.1 description: Build dart types from GraphQL schemas and queries (using Introspection Query). homepage: https://github.com/comigor/artemis diff --git a/test/query_generator/append_type_name_test.dart b/test/query_generator/append_type_name_test.dart index b72be0e2..2a0d79da 100644 --- a/test/query_generator/append_type_name_test.dart +++ b/test/query_generator/append_type_name_test.dart @@ -47,15 +47,15 @@ void main() { properties: [ ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'__typename'), - annotations: [r'''JsonKey(name: '__typename')'''], + name: ClassPropertyName(name: r'e'), isNonNull: false, - isResolveType: true), + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'e'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -63,17 +63,17 @@ void main() { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot'), properties: [ + ClassProperty( + type: TypeName(name: r'Custom$_QueryRoot$_q'), + name: ClassPropertyName(name: r'q'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'Custom$_QueryRoot$_q'), - name: ClassPropertyName(name: r'q'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -96,13 +96,13 @@ class Custom$QueryRoot$Q with EquatableMixin { factory Custom$QueryRoot$Q.fromJson(Map json) => _$Custom$QueryRoot$QFromJson(json); + String e; + @JsonKey(name: '__typename') String $$typename; - String e; - @override - List get props => [$$typename, e]; + List get props => [e, $$typename]; Map toJson() => _$Custom$QueryRoot$QToJson(this); } @@ -113,13 +113,13 @@ class Custom$QueryRoot with EquatableMixin { factory Custom$QueryRoot.fromJson(Map json) => _$Custom$QueryRootFromJson(json); + Custom$QueryRoot$Q q; + @JsonKey(name: '__typename') String $$typename; - Custom$QueryRoot$Q q; - @override - List get props => [$$typename, q]; + List get props => [q, $$typename]; Map toJson() => _$Custom$QueryRootToJson(this); } ''', @@ -163,15 +163,15 @@ class Custom$QueryRoot with EquatableMixin { properties: [ ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'__typename'), - annotations: [r'''JsonKey(name: '__typename')'''], + name: ClassPropertyName(name: r'e'), isNonNull: false, - isResolveType: true), + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'e'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -179,17 +179,17 @@ class Custom$QueryRoot with EquatableMixin { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot'), properties: [ + ClassProperty( + type: TypeName(name: r'Custom$_QueryRoot$_q'), + name: ClassPropertyName(name: r'q'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'Custom$_QueryRoot$_q'), - name: ClassPropertyName(name: r'q'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -212,13 +212,13 @@ class Custom$QueryRoot$Q with EquatableMixin { factory Custom$QueryRoot$Q.fromJson(Map json) => _$Custom$QueryRoot$QFromJson(json); + String e; + @JsonKey(name: '__typename') String $$typename; - String e; - @override - List get props => [$$typename, e]; + List get props => [e, $$typename]; Map toJson() => _$Custom$QueryRoot$QToJson(this); } @@ -229,13 +229,13 @@ class Custom$QueryRoot with EquatableMixin { factory Custom$QueryRoot.fromJson(Map json) => _$Custom$QueryRootFromJson(json); + Custom$QueryRoot$Q q; + @JsonKey(name: '__typename') String $$typename; - Custom$QueryRoot$Q q; - @override - List get props => [$$typename, q]; + List get props => [q, $$typename]; Map toJson() => _$Custom$QueryRootToJson(this); } ''', @@ -293,17 +293,17 @@ class Custom$QueryRoot with EquatableMixin { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot'), properties: [ + ClassProperty( + type: TypeName(name: r'Custom$_QueryRoot$_q'), + name: ClassPropertyName(name: r'q'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'Custom$_QueryRoot$_q'), - name: ClassPropertyName(name: r'q'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -313,15 +313,15 @@ class Custom$QueryRoot with EquatableMixin { properties: [ ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'__typename'), - annotations: [r'''JsonKey(name: '__typename')'''], + name: ClassPropertyName(name: r'e'), isNonNull: false, - isResolveType: true), + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), - name: ClassPropertyName(name: r'e'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: false) + isResolveType: true) ]) ], generateHelpers: false, @@ -335,9 +335,9 @@ import 'package:gql/ast.dart'; part 'query.graphql.g.dart'; mixin QueryResponseMixin { + String e; @JsonKey(name: '__typename') String $$typename; - String e; } @JsonSerializable(explicitToJson: true) @@ -351,7 +351,7 @@ class Custom$QueryRoot$Q with EquatableMixin, QueryResponseMixin { String $$typename; @override - List get props => [$$typename, e, $$typename]; + List get props => [e, $$typename, $$typename]; Map toJson() => _$Custom$QueryRoot$QToJson(this); } @@ -362,13 +362,13 @@ class Custom$QueryRoot with EquatableMixin { factory Custom$QueryRoot.fromJson(Map json) => _$Custom$QueryRootFromJson(json); + Custom$QueryRoot$Q q; + @JsonKey(name: '__typename') String $$typename; - Custom$QueryRoot$Q q; - @override - List get props => [$$typename, q]; + List get props => [q, $$typename]; Map toJson() => _$Custom$QueryRootToJson(this); } ''', @@ -419,17 +419,17 @@ class Custom$QueryRoot with EquatableMixin { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot$_q$_typeA'), properties: [ + ClassProperty( + type: TypeName(name: r'int'), + name: ClassPropertyName(name: r'a'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'int'), - name: ClassPropertyName(name: r'a'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], extension: ClassName(name: r'Custom$_QueryRoot$_q'), factoryPossibilities: {}, @@ -438,17 +438,17 @@ class Custom$QueryRoot with EquatableMixin { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot$_q$_typeB'), properties: [ + ClassProperty( + type: TypeName(name: r'int'), + name: ClassPropertyName(name: r'b'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'int'), - name: ClassPropertyName(name: r'b'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], extension: ClassName(name: r'Custom$_QueryRoot$_q'), factoryPossibilities: {}, @@ -475,17 +475,17 @@ class Custom$QueryRoot with EquatableMixin { ClassDefinition( name: ClassName(name: r'Custom$_QueryRoot'), properties: [ + ClassProperty( + type: TypeName(name: r'Custom$_QueryRoot$_q'), + name: ClassPropertyName(name: r'q'), + isNonNull: false, + isResolveType: false), ClassProperty( type: TypeName(name: r'String'), name: ClassPropertyName(name: r'__typename'), annotations: [r'''JsonKey(name: '__typename')'''], isNonNull: false, - isResolveType: true), - ClassProperty( - type: TypeName(name: r'Custom$_QueryRoot$_q'), - name: ClassPropertyName(name: r'q'), - isNonNull: false, - isResolveType: false) + isResolveType: true) ], factoryPossibilities: {}, typeNameField: TypeName(name: r'__typename'), @@ -508,14 +508,14 @@ class Custom$QueryRoot$Q$TypeA extends Custom$QueryRoot$Q with EquatableMixin { factory Custom$QueryRoot$Q$TypeA.fromJson(Map json) => _$Custom$QueryRoot$Q$TypeAFromJson(json); + int a; + @JsonKey(name: '__typename') @override String $$typename; - int a; - @override - List get props => [$$typename, a]; + List get props => [a, $$typename]; Map toJson() => _$Custom$QueryRoot$Q$TypeAToJson(this); } @@ -526,14 +526,14 @@ class Custom$QueryRoot$Q$TypeB extends Custom$QueryRoot$Q with EquatableMixin { factory Custom$QueryRoot$Q$TypeB.fromJson(Map json) => _$Custom$QueryRoot$Q$TypeBFromJson(json); + int b; + @JsonKey(name: '__typename') @override String $$typename; - int b; - @override - List get props => [$$typename, b]; + List get props => [b, $$typename]; Map toJson() => _$Custom$QueryRoot$Q$TypeBToJson(this); } @@ -576,16 +576,221 @@ class Custom$QueryRoot with EquatableMixin { factory Custom$QueryRoot.fromJson(Map json) => _$Custom$QueryRootFromJson(json); + Custom$QueryRoot$Q q; + @JsonKey(name: '__typename') String $$typename; - Custom$QueryRoot$Q q; - @override - List get props => [$$typename, q]; + List get props => [q, $$typename]; Map toJson() => _$Custom$QueryRootToJson(this); } ''', generateHelpers: false)); + + test( + 'Appends typename to common fragments', + () async => testGenerator( + appendTypeName: true, + query: r''' + query custom { + q { + ...QueryResponse + } + } + ''', + schema: r''' + schema { + query: QueryRoot + } + + type QueryRoot { + q: QueryResponse + } + + type QueryResponse { + e: String + } + ''', + libraryDefinition: + LibraryDefinition(basename: r'query.graphql', queries: [ + QueryDefinition( + name: QueryName(name: r'Custom$_QueryRoot'), + operationName: r'custom', + classes: [ + ClassDefinition( + name: ClassName(name: r'Custom$_QueryRoot$_QueryResponse'), + properties: [ + ClassProperty( + type: TypeName(name: r'String'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], + isNonNull: false, + isResolveType: true) + ], + mixins: [FragmentName(name: r'QueryResponseMixin')], + factoryPossibilities: {}, + typeNameField: TypeName(name: r'__typename'), + isInput: false), + ClassDefinition( + name: ClassName(name: r'Custom$_QueryRoot'), + properties: [ + ClassProperty( + type: TypeName( + name: r'Custom$_QueryRoot$_QueryResponse'), + name: ClassPropertyName(name: r'q'), + isNonNull: false, + isResolveType: false), + ClassProperty( + type: TypeName(name: r'String'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], + isNonNull: false, + isResolveType: true) + ], + factoryPossibilities: {}, + typeNameField: TypeName(name: r'__typename'), + isInput: false), + FragmentClassDefinition( + name: FragmentName(name: r'QueryResponseMixin'), + properties: [ + ClassProperty( + type: TypeName(name: r'String'), + name: ClassPropertyName(name: r'e'), + isNonNull: false, + isResolveType: false), + ClassProperty( + type: TypeName(name: r'String'), + name: ClassPropertyName(name: r'__typename'), + annotations: [r'''JsonKey(name: '__typename')'''], + isNonNull: false, + isResolveType: true) + ]) + ], + generateHelpers: true, + suffix: r'Query') + ]), + generatedFile: r'''// GENERATED CODE - DO NOT MODIFY BY HAND + +import 'package:artemis/artemis.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:equatable/equatable.dart'; +import 'package:gql/ast.dart'; +part 'query.graphql.g.dart'; + +mixin QueryResponseMixin { + String e; + @JsonKey(name: '__typename') + String $$typename; +} + +@JsonSerializable(explicitToJson: true) +class Custom$QueryRoot$QueryResponse with EquatableMixin, QueryResponseMixin { + Custom$QueryRoot$QueryResponse(); + + factory Custom$QueryRoot$QueryResponse.fromJson(Map json) => + _$Custom$QueryRoot$QueryResponseFromJson(json); + + @JsonKey(name: '__typename') + String $$typename; + + @override + List get props => [e, $$typename, $$typename]; + Map toJson() => _$Custom$QueryRoot$QueryResponseToJson(this); +} + +@JsonSerializable(explicitToJson: true) +class Custom$QueryRoot with EquatableMixin { + Custom$QueryRoot(); + + factory Custom$QueryRoot.fromJson(Map json) => + _$Custom$QueryRootFromJson(json); + + Custom$QueryRoot$QueryResponse q; + + @JsonKey(name: '__typename') + String $$typename; + + @override + List get props => [q, $$typename]; + Map toJson() => _$Custom$QueryRootToJson(this); +} + +class CustomQuery extends GraphQLQuery { + CustomQuery(); + + @override + final DocumentNode document = DocumentNode(definitions: [ + OperationDefinitionNode( + type: OperationType.query, + name: NameNode(value: 'custom'), + variableDefinitions: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'q'), + alias: null, + arguments: [], + directives: [], + selectionSet: SelectionSetNode(selections: [ + FragmentSpreadNode( + name: NameNode(value: 'QueryResponse'), directives: []), + FieldNode( + name: NameNode(value: '__typename'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])), + FieldNode( + name: NameNode(value: '__typename'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])), + FragmentDefinitionNode( + name: NameNode(value: 'QueryResponse'), + typeCondition: TypeConditionNode( + on: NamedTypeNode( + name: NameNode(value: 'QueryResponse'), isNonNull: false)), + directives: [], + selectionSet: SelectionSetNode(selections: [ + FieldNode( + name: NameNode(value: 'e'), + alias: null, + arguments: [], + directives: [], + selectionSet: null), + FieldNode( + name: NameNode(value: '__typename'), + alias: null, + arguments: [], + directives: [], + selectionSet: null) + ])) + ]); + + @override + final String operationName = 'custom'; + + @override + List get props => [document, operationName]; + @override + Custom$QueryRoot parse(Map json) => + Custom$QueryRoot.fromJson(json); +} +''', + builderOptionsMap: {'fragments_glob': '**.frag'}, + sourceAssetsMap: { + 'a|fragment.frag': r''' + fragment QueryResponse on QueryResponse { + e + } + ''' + }, + generateHelpers: true, + ), + ); }); }