Skip to content

Commit

Permalink
Merge pull request #303 from comigor/bugfix/union-generation
Browse files Browse the repository at this point in the history
Bugfix/union generation
  • Loading branch information
vasilich6107 committed May 4, 2021
2 parents aa066f6 + 8173c7b commit d92d3f2
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 57 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 7.0.0-beta.10

- union generation fix for https://github.com/comigor/artemis/issues/284

## 7.0.0-beta.9

- nullable scalar_mapping types
Expand Down
19 changes: 8 additions & 11 deletions lib/generator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/data/enum_value_definition.dart';
import 'package:artemis/generator/data/nullable.dart';
import 'package:artemis/visitor/canonical_visitor.dart';
import 'package:artemis/visitor/generator_visitor.dart';
import 'package:artemis/visitor/object_type_definition_visitor.dart';
Expand Down Expand Up @@ -179,19 +180,15 @@ Iterable<QueryDefinition> generateDefinitions(
.value ??
suffix;

// if (rootTypeName == null) {
// throw Exception(
// '''No root type was found for ${operation.type} $operationName.''');
// }

final TypeDefinitionNode parentType =
objectVisitor.getByName(rootTypeName)!;

final name = QueryName.fromPath(
path: createPathName([
ClassName(name: operationName),
ClassName(name: parentType.name.value)
], schemaMap.namingScheme));
path: createPathName([
ClassName(name: operationName),
ClassName(name: parentType.name.value)
], schemaMap.namingScheme),
);

final context = Context(
schema: schema,
Expand Down Expand Up @@ -298,8 +295,7 @@ ClassProperty createClassProperty({
Make sure your query is correct and your schema is updated.''');
}

final nextType =
gql.getTypeByName(context.schema, fieldType, context: 'field node');
final nextType = gql.getTypeByName(context.schema, fieldType);

final aliasedContext = context.withAlias(
nextFieldName: fieldName,
Expand Down Expand Up @@ -335,6 +331,7 @@ Make sure your query is correct and your schema is updated.''');
nextFieldName: nextFieldName,
nextClassName: ClassName(name: nextType.name.value),
alias: fieldAlias,
ofUnion: Nullable<TypeDefinitionNode?>(null),
),
);
}
Expand Down
12 changes: 12 additions & 0 deletions lib/generator/data/nullable.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// Allows to reset values back to null in `copyWith` pattern
class Nullable<T> {
final T _value;

/// Sets desired value
Nullable(this._value);

/// Gets the real value
T get value {
return _value;
}
}
21 changes: 11 additions & 10 deletions lib/generator/ephemeral_data.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/data/nullable.dart';
import 'package:gql/ast.dart';
import '../schema/options.dart';

Expand Down Expand Up @@ -113,7 +114,7 @@ class Context {
required TypeDefinitionNode nextType,
required Name? nextFieldName,
required Name? nextClassName,
TypeDefinitionNode? ofUnion,
Nullable<TypeDefinitionNode?>? ofUnion,
Name? alias,
List<Definition>? generatedClasses,
List<QueryInput>? inputsClasses,
Expand All @@ -127,7 +128,7 @@ class Context {
currentType: nextType,
currentFieldName: nextFieldName,
currentClassName: nextClassName,
ofUnion: ofUnion ?? this.ofUnion,
ofUnion: ofUnion == null ? this.ofUnion : ofUnion.value,
generatedClasses: generatedClasses ?? this.generatedClasses,
inputsClasses: inputsClasses ?? this.inputsClasses,
fragments: fragments ?? this.fragments,
Expand All @@ -142,7 +143,7 @@ class Context {
Name? nextFieldName,
Name? nextClassName,
Name? alias,
TypeDefinitionNode? ofUnion,
Nullable<TypeDefinitionNode?>? ofUnion,
List<Definition>? generatedClasses,
List<QueryInput>? inputsClasses,
List<FragmentDefinitionNode>? fragments,
Expand All @@ -163,7 +164,7 @@ class Context {
currentType: nextType,
currentFieldName: nextFieldName,
currentClassName: nextClassName,
ofUnion: ofUnion ?? this.ofUnion,
ofUnion: ofUnion == null ? this.ofUnion : ofUnion.value,
generatedClasses: generatedClasses ?? this.generatedClasses,
inputsClasses: inputsClasses ?? this.inputsClasses,
fragments: fragments ?? this.fragments,
Expand Down Expand Up @@ -202,7 +203,7 @@ class Context {
Name? nextFieldName,
Name? nextClassName,
Name? alias,
TypeDefinitionNode? ofUnion,
Nullable<TypeDefinitionNode?>? ofUnion,
List<Definition>? generatedClasses,
List<QueryInput>? inputsClasses,
List<FragmentDefinitionNode>? fragments,
Expand All @@ -224,7 +225,7 @@ class Context {
currentType: currentType,
currentFieldName: nextFieldName ?? currentFieldName,
currentClassName: nextClassName ?? currentClassName,
ofUnion: ofUnion ?? this.ofUnion,
ofUnion: ofUnion == null ? this.ofUnion : ofUnion.value,
alias: alias ?? this.alias,
generatedClasses: generatedClasses ?? this.generatedClasses,
inputsClasses: inputsClasses ?? this.inputsClasses,
Expand Down Expand Up @@ -260,7 +261,7 @@ class Context {
/// Returns a copy of this context, with the same type, but on the first path.
Context sameTypeWithNoPath({
Name? alias,
TypeDefinitionNode? ofUnion,
Nullable<TypeDefinitionNode?>? ofUnion,
List<Definition>? generatedClasses,
List<QueryInput>? inputsClasses,
List<FragmentDefinitionNode>? fragments,
Expand All @@ -273,7 +274,7 @@ class Context {
currentType: currentType,
currentFieldName: currentFieldName,
currentClassName: currentClassName,
ofUnion: ofUnion ?? this.ofUnion,
ofUnion: ofUnion == null ? this.ofUnion : ofUnion.value,
alias: alias ?? this.alias,
generatedClasses: generatedClasses ?? this.generatedClasses,
inputsClasses: inputsClasses ?? this.inputsClasses,
Expand All @@ -288,7 +289,7 @@ class Context {
required TypeDefinitionNode nextType,
required Name nextFieldName,
required Name nextClassName,
TypeDefinitionNode? ofUnion,
Nullable<TypeDefinitionNode?>? ofUnion,
Name? alias,
List<Definition>? generatedClasses,
List<QueryInput>? inputsClasses,
Expand All @@ -302,7 +303,7 @@ class Context {
currentType: nextType,
currentFieldName: nextFieldName,
currentClassName: nextClassName,
ofUnion: ofUnion ?? this.ofUnion,
ofUnion: ofUnion == null ? this.ofUnion : ofUnion.value,
alias: alias ?? this.alias,
generatedClasses: generatedClasses ?? this.generatedClasses,
inputsClasses: inputsClasses ?? this.inputsClasses,
Expand Down
5 changes: 2 additions & 3 deletions lib/generator/graphql_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import '../schema/options.dart';
import 'data/definition.dart';

/// Get a full [TypeDefinitionNode] from a type node.
TypeDefinitionNode getTypeByName(DocumentNode schema, TypeNode typeNode,
{String? context}) {
TypeDefinitionNode getTypeByName(DocumentNode schema, TypeNode typeNode) {
late NamedTypeNode namedNode;

if (typeNode is ListTypeNode) {
return getTypeByName(schema, typeNode.type, context: context);
return getTypeByName(schema, typeNode.type);
}

if (typeNode is NamedTypeNode) {
Expand Down
12 changes: 10 additions & 2 deletions lib/visitor/canonical_visitor.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:artemis/generator.dart';
import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/data/enum_value_definition.dart';
import 'package:artemis/generator/data/nullable.dart';
import 'package:artemis/generator/ephemeral_data.dart';
import 'package:artemis/generator/helpers.dart';
import 'package:artemis/generator/graphql_helpers.dart' as gql;
Expand All @@ -26,7 +27,10 @@ class CanonicalVisitor extends RecursiveVisitor {
void visitEnumTypeDefinitionNode(EnumTypeDefinitionNode node) {
final enumName = EnumName(name: node.name.value);

final nextContext = context.sameTypeWithNoPath(alias: enumName);
final nextContext = context.sameTypeWithNoPath(
alias: enumName,
ofUnion: Nullable<TypeDefinitionNode?>(null),
);

logFn(context, nextContext.align, '-> Enum');
logFn(context, nextContext.align,
Expand All @@ -47,7 +51,10 @@ class CanonicalVisitor extends RecursiveVisitor {
@override
void visitInputObjectTypeDefinitionNode(InputObjectTypeDefinitionNode node) {
final name = ClassName(name: node.name.value);
final nextContext = context.sameTypeWithNoPath(alias: name);
final nextContext = context.sameTypeWithNoPath(
alias: name,
ofUnion: Nullable<TypeDefinitionNode?>(null),
);

logFn(context, nextContext.align, '-> Input class');
logFn(context, nextContext.align,
Expand All @@ -62,6 +69,7 @@ class CanonicalVisitor extends RecursiveVisitor {
nextType: node,
nextClassName: ClassName(name: nextType.name.value),
nextFieldName: ClassName(name: i.name.value),
ofUnion: Nullable<TypeDefinitionNode?>(null),
),
markAsUsed: false,
);
Expand Down
28 changes: 17 additions & 11 deletions lib/visitor/generator_visitor.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:artemis/generator.dart';
import 'package:artemis/generator/data/data.dart';
import 'package:artemis/generator/data/nullable.dart';
import 'package:artemis/generator/ephemeral_data.dart';
import 'package:artemis/generator/graphql_helpers.dart' as gql;
import 'package:artemis/generator/helpers.dart';
Expand Down Expand Up @@ -93,16 +94,15 @@ class GeneratorVisitor extends RecursiveVisitor {
void visitInlineFragmentNode(InlineFragmentNode node) {
logFn(context, context.align + 1,
'${context.path}: ... on ${node.typeCondition!.on.name.value}');
final nextType = gql.getTypeByName(context.schema, node.typeCondition!.on,
context: 'inline fragment');
final nextType = gql.getTypeByName(context.schema, node.typeCondition!.on);

if (nextType.name.value == context.currentType!.name.value) {
final visitor = GeneratorVisitor(
context: context.nextTypeWithSamePath(
nextType: nextType,
nextClassName: null,
nextFieldName: null,
ofUnion: context.currentType,
ofUnion: Nullable<TypeDefinitionNode?>(context.currentType),
inputsClasses: [],
fragments: [],
),
Expand All @@ -114,7 +114,7 @@ class GeneratorVisitor extends RecursiveVisitor {
nextType: nextType,
nextClassName: ClassName(name: nextType.name.value),
nextFieldName: ClassPropertyName(name: nextType.name.value),
ofUnion: context.currentType,
ofUnion: Nullable<TypeDefinitionNode?>(context.currentType),
inputsClasses: [],
fragments: [],
),
Expand Down Expand Up @@ -142,14 +142,14 @@ class GeneratorVisitor extends RecursiveVisitor {

@override
void visitVariableDefinitionNode(VariableDefinitionNode node) {
final leafType = gql.getTypeByName(context.schema, node.type,
context: 'variable definition');
final leafType = gql.getTypeByName(context.schema, node.type);

final nextClassName = context
.nextTypeWithNoPath(
nextType: leafType,
nextClassName: ClassName(name: leafType.name.value),
nextFieldName: ClassName(name: node.variable.name.value),
ofUnion: Nullable<TypeDefinitionNode?>(null),
)
.fullPathName();

Expand Down Expand Up @@ -232,13 +232,17 @@ class GeneratorVisitor extends RecursiveVisitor {
'${context.path}: ... expanding ${node.name.value}');
final fragmentName = FragmentName.fromPath(
path: context
.sameTypeWithNoPath(alias: FragmentName(name: node.name.value))
.sameTypeWithNoPath(
alias: FragmentName(name: node.name.value),
ofUnion: Nullable<TypeDefinitionNode?>(null),
)
.fullPathName());

final visitor = GeneratorVisitor(
context: context.sameTypeWithNextPath(
alias: fragmentName,
generatedClasses: [],
ofUnion: Nullable<TypeDefinitionNode?>(null),
log: false,
),
);
Expand All @@ -254,16 +258,18 @@ class GeneratorVisitor extends RecursiveVisitor {
@override
void visitFragmentDefinitionNode(FragmentDefinitionNode node) {
final partName = FragmentName(name: node.name.value);
final nextContext = context.sameTypeWithNoPath(alias: partName);
final nextContext = context.sameTypeWithNoPath(
alias: partName,
ofUnion: Nullable<TypeDefinitionNode?>(null),
);

logFn(context, nextContext.align, '-> Fragment');
logFn(context, nextContext.align,
'┌ ${nextContext.path}[${node.name.value}]');
nextContext.fragments.add(node);

final nextType = gql.getTypeByName(
nextContext.schema, node.typeCondition.on,
context: 'fragment definition');
final nextType =
gql.getTypeByName(nextContext.schema, node.typeCondition.on);

final visitorContext = Context(
schema: context.schema,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: artemis
version: 7.0.0-beta.9
version: 7.0.0-beta.10

description: Build dart types from GraphQL schemas and queries (using Introspection Query).
homepage: https://github.com/comigor/artemis
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ final LibraryDefinition libraryDefinition =
isInput: false),
ClassDefinition(
name: ClassName(name: r'Custom$_Query$_Node$_ChatMessage$_User'),
extension: ClassName(name: r'Custom$_Query$_Node$_ChatMessage'),
mixins: [FragmentName(name: r'UserFragMixin')],
factoryPossibilities: {},
typeNameField: ClassPropertyName(name: r'__typename'),
Expand Down Expand Up @@ -191,7 +190,7 @@ class Custom$Query$Node$User extends Custom$Query$Node
}
@JsonSerializable(explicitToJson: true)
class Custom$Query$Node$ChatMessage$User extends Custom$Query$Node$ChatMessage
class Custom$Query$Node$ChatMessage$User extends JsonSerializable
with EquatableMixin, UserFragMixin {
Custom$Query$Node$ChatMessage$User();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ final LibraryDefinition libraryDefinition =
ClassDefinition(
name:
ClassName(name: r'Custom$_Query$_nodeById$_chatMessage$_user'),
extension: ClassName(name: r'Custom$_Query$_nodeById$_chatMessage'),
mixins: [FragmentName(name: r'UserFragMixin')],
factoryPossibilities: {},
typeNameField: ClassPropertyName(name: r'__typename'),
Expand Down Expand Up @@ -196,8 +195,7 @@ class Custom$Query$NodeById$User extends Custom$Query$NodeById
}
@JsonSerializable(explicitToJson: true)
class Custom$Query$NodeById$ChatMessage$User
extends Custom$Query$NodeById$ChatMessage
class Custom$Query$NodeById$ChatMessage$User extends JsonSerializable
with EquatableMixin, UserFragMixin {
Custom$Query$NodeById$ChatMessage$User();
Expand Down
3 changes: 1 addition & 2 deletions test/query_generator/interfaces/interface_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ final LibraryDefinition libraryDefinition =
isInput: false),
ClassDefinition(
name: ClassName(name: r'Custom$_Query$_Node$_ChatMessage$_User'),
extension: ClassName(name: r'Custom$_Query$_Node$_ChatMessage'),
mixins: [FragmentName(name: r'UserFragMixin')],
factoryPossibilities: {},
typeNameField: ClassPropertyName(name: r'__typename'),
Expand Down Expand Up @@ -187,7 +186,7 @@ class Custom$Query$Node$User extends Custom$Query$Node
}
@JsonSerializable(explicitToJson: true)
class Custom$Query$Node$ChatMessage$User extends Custom$Query$Node$ChatMessage
class Custom$Query$Node$ChatMessage$User extends JsonSerializable
with EquatableMixin, UserFragMixin {
Custom$Query$Node$ChatMessage$User();
Expand Down
Loading

0 comments on commit d92d3f2

Please sign in to comment.