Skip to content

Commit c508ac3

Browse files
authored
Merge pull request #1884 from felipe-gdr/1764_allow-interfaces-to-implement-other-interfaces
1764 allow interfaces to implement other interfaces
2 parents 000eb52 + 7601889 commit c508ac3

38 files changed

Lines changed: 2141 additions & 216 deletions

src/main/antlr/GraphqlSDL.g4

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ argumentsDefinition : '(' inputValueDefinition+ ')';
7272

7373
inputValueDefinition : description? name ':' type defaultValue? directives?;
7474

75-
interfaceTypeDefinition : description? INTERFACE name directives? fieldsDefinition?;
75+
interfaceTypeDefinition : description? INTERFACE name implementsInterfaces? directives? fieldsDefinition?;
7676

7777
interfaceTypeExtensionDefinition :
78-
EXTEND INTERFACE name directives? extensionFieldsDefinition |
79-
EXTEND INTERFACE name directives emptyParentheses?
78+
EXTEND INTERFACE name implementsInterfaces? directives? extensionFieldsDefinition |
79+
EXTEND INTERFACE name implementsInterfaces? directives emptyParentheses? |
80+
EXTEND INTERFACE name implementsInterfaces
8081
;
8182

8283

src/main/java/graphql/introspection/Introspection.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ private static String print(Object value, GraphQLInputType type) {
256256
if (type instanceof GraphQLObjectType) {
257257
return ((GraphQLObjectType) type).getInterfaces();
258258
}
259+
if (type instanceof GraphQLInterfaceType) {
260+
return ((GraphQLInterfaceType) type).getInterfaces();
261+
}
259262
return null;
260263
};
261264

src/main/java/graphql/introspection/IntrospectionResultToSchema.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
import graphql.language.OperationTypeDefinition;
2121
import graphql.language.ScalarTypeDefinition;
2222
import graphql.language.SchemaDefinition;
23-
import graphql.language.SourceLocation;
2423
import graphql.language.StringValue;
2524
import graphql.language.Type;
2625
import graphql.language.TypeDefinition;
2726
import graphql.language.TypeName;
2827
import graphql.language.UnionTypeDefinition;
2928
import graphql.language.Value;
3029
import graphql.schema.idl.ScalarInfo;
30+
import graphql.util.FpKit;
3131

3232
import java.util.ArrayList;
3333
import java.util.Collections;
@@ -186,6 +186,14 @@ InterfaceTypeDefinition createInterface(Map<String, Object> input) {
186186

187187
InterfaceTypeDefinition.Builder interfaceTypeDefinition = InterfaceTypeDefinition.newInterfaceTypeDefinition().name((String) input.get("name"));
188188
interfaceTypeDefinition.description(toDescription(input));
189+
if (input.containsKey("interfaces") && input.get("interfaces") != null) {
190+
interfaceTypeDefinition.implementz(
191+
FpKit.map(
192+
(List<Map<String, Object>>) input.get("interfaces"),
193+
this::createTypeIndirection
194+
)
195+
);
196+
}
189197
List<Map<String, Object>> fields = (List<Map<String, Object>>) input.get("fields");
190198
interfaceTypeDefinition.definitions(createFields(fields));
191199

src/main/java/graphql/language/AstPrinter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ private NodePrinter<InterfaceTypeDefinition> interfaceTypeDefinition() {
261261
out.printf("%s", spaced(
262262
"interface",
263263
node.getName(),
264+
wrap("implements ", join(node.getImplements(), " & "), ""),
264265
directives(node.getDirectives()),
265266
block(node.getFieldDefinitions())
266267
)

src/main/java/graphql/language/AstSorter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ public TraversalControl visitObjectTypeDefinition(ObjectTypeDefinition node, Tra
178178
public TraversalControl visitInterfaceTypeDefinition(InterfaceTypeDefinition node, TraverserContext<Node> context) {
179179
InterfaceTypeDefinition changedNode = node.transform(builder -> {
180180
builder.directives(sort(node.getDirectives(), comparing(Directive::getName)));
181+
builder.implementz(sort(node.getImplements(), comparingTypes()));
181182
builder.definitions(sort(node.getFieldDefinitions(), comparing(FieldDefinition::getName)));
182183
});
183184
return changeNode(context, changedNode);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package graphql.language;
2+
3+
4+
import graphql.PublicApi;
5+
6+
import java.util.List;
7+
8+
/**
9+
* A {@link TypeDefinition} that might implement interfaces
10+
*
11+
* @param <T>
12+
*/
13+
@PublicApi
14+
public interface ImplementingTypeDefinition<T extends TypeDefinition> extends TypeDefinition<T> {
15+
16+
List<Type> getImplements();
17+
18+
List<FieldDefinition> getFieldDefinitions();
19+
}

src/main/java/graphql/language/InterfaceTypeDefinition.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@
1717
import static java.util.Collections.emptyMap;
1818

1919
@PublicApi
20-
public class InterfaceTypeDefinition extends AbstractDescribedNode<InterfaceTypeDefinition> implements TypeDefinition<InterfaceTypeDefinition>, DirectivesContainer<InterfaceTypeDefinition>, NamedNode<InterfaceTypeDefinition> {
20+
public class InterfaceTypeDefinition extends AbstractDescribedNode<InterfaceTypeDefinition> implements ImplementingTypeDefinition<InterfaceTypeDefinition>, DirectivesContainer<InterfaceTypeDefinition>, NamedNode<InterfaceTypeDefinition> {
2121

2222
private final String name;
23+
private final List<Type> implementz;
2324
private final List<FieldDefinition> definitions;
2425
private final List<Directive> directives;
2526

27+
public static final String CHILD_IMPLEMENTZ = "implementz";
2628
public static final String CHILD_DEFINITIONS = "definitions";
2729
public static final String CHILD_DIRECTIVES = "directives";
2830

2931
@Internal
3032
protected InterfaceTypeDefinition(String name,
33+
List<Type> implementz,
3134
List<FieldDefinition> definitions,
3235
List<Directive> directives,
3336
Description description,
@@ -37,6 +40,7 @@ protected InterfaceTypeDefinition(String name,
3740
Map<String, String> additionalData) {
3841
super(sourceLocation, comments, ignoredChars, additionalData, description);
3942
this.name = name;
43+
this.implementz = implementz;
4044
this.definitions = definitions;
4145
this.directives = directives;
4246
}
@@ -47,9 +51,15 @@ protected InterfaceTypeDefinition(String name,
4751
* @param name of the interface
4852
*/
4953
public InterfaceTypeDefinition(String name) {
50-
this(name, new ArrayList<>(), new ArrayList<>(), null, null, new ArrayList<>(), IgnoredChars.EMPTY, emptyMap());
54+
this(name, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null, null, new ArrayList<>(), IgnoredChars.EMPTY, emptyMap());
5155
}
5256

57+
@Override
58+
public List<Type> getImplements() {
59+
return new ArrayList<>(implementz);
60+
}
61+
62+
@Override
5363
public List<FieldDefinition> getFieldDefinitions() {
5464
return new ArrayList<>(definitions);
5565
}
@@ -67,6 +77,7 @@ public String getName() {
6777
@Override
6878
public List<Node> getChildren() {
6979
List<Node> result = new ArrayList<>();
80+
result.addAll(implementz);
7081
result.addAll(definitions);
7182
result.addAll(directives);
7283
return result;
@@ -75,6 +86,7 @@ public List<Node> getChildren() {
7586
@Override
7687
public NodeChildrenContainer getNamedChildren() {
7788
return newNodeChildrenContainer()
89+
.children(CHILD_IMPLEMENTZ, implementz)
7890
.children(CHILD_DEFINITIONS, definitions)
7991
.children(CHILD_DIRECTIVES, directives)
8092
.build();
@@ -83,6 +95,7 @@ public NodeChildrenContainer getNamedChildren() {
8395
@Override
8496
public InterfaceTypeDefinition withNewChildren(NodeChildrenContainer newChildren) {
8597
return transform(builder -> builder
98+
.implementz(newChildren.getChildren(CHILD_IMPLEMENTZ))
8699
.definitions(newChildren.getChildren(CHILD_DEFINITIONS))
87100
.directives(newChildren.getChildren(CHILD_DIRECTIVES))
88101
);
@@ -105,6 +118,7 @@ public boolean isEqualTo(Node o) {
105118
@Override
106119
public InterfaceTypeDefinition deepCopy() {
107120
return new InterfaceTypeDefinition(name,
121+
deepCopy(implementz),
108122
deepCopy(definitions),
109123
deepCopy(directives),
110124
description,
@@ -118,6 +132,7 @@ public InterfaceTypeDefinition deepCopy() {
118132
public String toString() {
119133
return "InterfaceTypeDefinition{" +
120134
"name='" + name + '\'' +
135+
", implements=" + implementz +
121136
", fieldDefinitions=" + definitions +
122137
", directives=" + directives +
123138
'}';
@@ -144,6 +159,7 @@ public static final class Builder implements NodeBuilder {
144159
private List<Comment> comments = new ArrayList<>();
145160
private String name;
146161
private Description description;
162+
private List<Type> implementz = new ArrayList<>();
147163
private List<FieldDefinition> definitions = new ArrayList<>();
148164
private List<Directive> directives = new ArrayList<>();
149165
private IgnoredChars ignoredChars = IgnoredChars.EMPTY;
@@ -185,6 +201,17 @@ public Builder description(Description description) {
185201
return this;
186202
}
187203

204+
public Builder implementz(List<Type> implementz) {
205+
this.implementz = implementz;
206+
return this;
207+
}
208+
209+
public Builder implementz(Type implement) {
210+
this.implementz.add(implement);
211+
return this;
212+
}
213+
214+
188215
public Builder definitions(List<FieldDefinition> definitions) {
189216
this.definitions = definitions;
190217
return this;
@@ -223,6 +250,7 @@ public Builder additionalData(String key, String value) {
223250

224251
public InterfaceTypeDefinition build() {
225252
return new InterfaceTypeDefinition(name,
253+
implementz,
226254
definitions,
227255
directives,
228256
description,

src/main/java/graphql/language/InterfaceTypeExtensionDefinition.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,21 @@ public class InterfaceTypeExtensionDefinition extends InterfaceTypeDefinition {
1616

1717
@Internal
1818
protected InterfaceTypeExtensionDefinition(String name,
19+
List<Type> implementz,
1920
List<FieldDefinition> definitions,
2021
List<Directive> directives,
2122
Description description,
2223
SourceLocation sourceLocation,
2324
List<Comment> comments,
2425
IgnoredChars ignoredChars,
2526
Map<String, String> additionalData) {
26-
super(name, definitions, directives, description, sourceLocation, comments, ignoredChars, additionalData);
27+
super(name, implementz, definitions, directives, description, sourceLocation, comments, ignoredChars, additionalData);
2728
}
2829

2930
@Override
3031
public InterfaceTypeExtensionDefinition deepCopy() {
3132
return new InterfaceTypeExtensionDefinition(getName(),
33+
getImplements(),
3234
deepCopy(getFieldDefinitions()),
3335
deepCopy(getDirectives()),
3436
getDescription(),
@@ -63,6 +65,7 @@ public static final class Builder implements NodeBuilder {
6365
private List<Comment> comments = new ArrayList<>();
6466
private String name;
6567
private Description description;
68+
private List<Type> implementz = new ArrayList<>();
6669
private List<FieldDefinition> definitions = new ArrayList<>();
6770
private List<Directive> directives = new ArrayList<>();
6871
private IgnoredChars ignoredChars = IgnoredChars.EMPTY;
@@ -77,6 +80,7 @@ private Builder(InterfaceTypeExtensionDefinition existing) {
7780
this.name = existing.getName();
7881
this.description = existing.getDescription();
7982
this.directives = existing.getDirectives();
83+
this.implementz = existing.getImplements();
8084
this.definitions = existing.getFieldDefinitions();
8185
this.ignoredChars = existing.getIgnoredChars();
8286
this.additionalData = new LinkedHashMap<>(existing.getAdditionalData());
@@ -102,6 +106,16 @@ public Builder description(Description description) {
102106
return this;
103107
}
104108

109+
public Builder implementz(List<Type> implementz) {
110+
this.implementz = implementz;
111+
return this;
112+
}
113+
114+
public Builder implementz(Type implementz) {
115+
this.implementz.add(implementz);
116+
return this;
117+
}
118+
105119
public Builder definitions(List<FieldDefinition> definitions) {
106120
this.definitions = definitions;
107121
return this;
@@ -130,6 +144,7 @@ public Builder additionalData(String key, String value) {
130144

131145
public InterfaceTypeExtensionDefinition build() {
132146
return new InterfaceTypeExtensionDefinition(name,
147+
implementz,
133148
definitions,
134149
directives,
135150
description,

src/main/java/graphql/language/ObjectTypeDefinition.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import static java.util.Collections.emptyMap;
1818

1919
@PublicApi
20-
public class ObjectTypeDefinition extends AbstractDescribedNode<ObjectTypeDefinition> implements TypeDefinition<ObjectTypeDefinition>, DirectivesContainer<ObjectTypeDefinition>, NamedNode<ObjectTypeDefinition> {
20+
public class ObjectTypeDefinition extends AbstractDescribedNode<ObjectTypeDefinition> implements ImplementingTypeDefinition<ObjectTypeDefinition>, DirectivesContainer<ObjectTypeDefinition>, NamedNode<ObjectTypeDefinition> {
2121
private final String name;
2222
private final List<Type> implementz;
2323
private final List<Directive> directives;
@@ -53,6 +53,7 @@ public ObjectTypeDefinition(String name) {
5353
this(name, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null, null, new ArrayList<>(), IgnoredChars.EMPTY, emptyMap());
5454
}
5555

56+
@Override
5657
public List<Type> getImplements() {
5758
return new ArrayList<>(implementz);
5859
}
@@ -62,6 +63,7 @@ public List<Directive> getDirectives() {
6263
return new ArrayList<>(directives);
6364
}
6465

66+
@Override
6567
public List<FieldDefinition> getFieldDefinitions() {
6668
return new ArrayList<>(fieldDefinitions);
6769
}

src/main/java/graphql/parser/GraphqlAntlrToLanguage.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import graphql.language.VariableReference;
6161
import graphql.parser.antlr.GraphqlLexer;
6262
import graphql.parser.antlr.GraphqlParser;
63+
import graphql.util.FpKit;
6364
import org.antlr.v4.runtime.CommonTokenStream;
6465
import org.antlr.v4.runtime.ParserRuleContext;
6566
import org.antlr.v4.runtime.Token;
@@ -432,12 +433,7 @@ protected ObjectTypeDefinition createObjectTypeDefinition(GraphqlParser.ObjectTy
432433
def.description(newDescription(ctx.description()));
433434
def.directives(createDirectives(ctx.directives()));
434435
GraphqlParser.ImplementsInterfacesContext implementsInterfacesContext = ctx.implementsInterfaces();
435-
List<Type> implementz = new ArrayList<>();
436-
while (implementsInterfacesContext != null) {
437-
List<TypeName> typeNames = implementsInterfacesContext.typeName().stream().map(this::createTypeName).collect(toList());
438-
implementz.addAll(0, typeNames);
439-
implementsInterfacesContext = implementsInterfacesContext.implementsInterfaces();
440-
}
436+
List<Type> implementz = getImplementz(implementsInterfacesContext);
441437
def.implementz(implementz);
442438
if (ctx.fieldsDefinition() != null) {
443439
def.fieldDefinitions(createFieldDefinitions(ctx.fieldsDefinition()));
@@ -451,12 +447,7 @@ protected ObjectTypeExtensionDefinition createObjectTypeExtensionDefinition(Grap
451447
addCommonData(def, ctx);
452448
def.directives(createDirectives(ctx.directives()));
453449
GraphqlParser.ImplementsInterfacesContext implementsInterfacesContext = ctx.implementsInterfaces();
454-
List<Type> implementz = new ArrayList<>();
455-
while (implementsInterfacesContext != null) {
456-
List<TypeName> typeNames = implementsInterfacesContext.typeName().stream().map(this::createTypeName).collect(toList());
457-
implementz.addAll(0, typeNames);
458-
implementsInterfacesContext = implementsInterfacesContext.implementsInterfaces();
459-
}
450+
List<Type> implementz = getImplementz(implementsInterfacesContext);
460451
def.implementz(implementz);
461452
if (ctx.extensionFieldsDefinition() != null) {
462453
def.fieldDefinitions(createFieldDefinitions(ctx.extensionFieldsDefinition()));
@@ -516,6 +507,9 @@ protected InterfaceTypeDefinition createInterfaceTypeDefinition(GraphqlParser.In
516507
addCommonData(def, ctx);
517508
def.description(newDescription(ctx.description()));
518509
def.directives(createDirectives(ctx.directives()));
510+
GraphqlParser.ImplementsInterfacesContext implementsInterfacesContext = ctx.implementsInterfaces();
511+
List<Type> implementz = getImplementz(implementsInterfacesContext);
512+
def.implementz(implementz);
519513
def.definitions(createFieldDefinitions(ctx.fieldsDefinition()));
520514
return def.build();
521515
}
@@ -525,6 +519,9 @@ protected InterfaceTypeExtensionDefinition createInterfaceTypeExtensionDefinitio
525519
def.name(ctx.name().getText());
526520
addCommonData(def, ctx);
527521
def.directives(createDirectives(ctx.directives()));
522+
GraphqlParser.ImplementsInterfacesContext implementsInterfacesContext = ctx.implementsInterfaces();
523+
List<Type> implementz = getImplementz(implementsInterfacesContext);
524+
def.implementz(implementz);
528525
def.definitions(createFieldDefinitions(ctx.extensionFieldsDefinition()));
529526
return def.build();
530527
}
@@ -881,4 +878,15 @@ protected List<Comment> getCommentOnChannel(List<Token> refChannel) {
881878
return comments;
882879
}
883880

881+
882+
private List<Type> getImplementz(GraphqlParser.ImplementsInterfacesContext implementsInterfacesContext) {
883+
List<Type> implementz = new ArrayList<>();
884+
while (implementsInterfacesContext != null) {
885+
List<TypeName> typeNames = FpKit.map(implementsInterfacesContext.typeName(), this::createTypeName);
886+
887+
implementz.addAll(0, typeNames);
888+
implementsInterfacesContext = implementsInterfacesContext.implementsInterfaces();
889+
}
890+
return implementz;
891+
}
884892
}

0 commit comments

Comments
 (0)