Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/antlr/GraphqlCommon.g4
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ INPUT: 'input';
EXTEND: 'extend';
DIRECTIVE: 'directive';
ON_KEYWORD: 'on';
REPEATABLE: 'repeatable';
NAME: [_A-Za-z][_0-9A-Za-z]*;


Expand Down
2 changes: 1 addition & 1 deletion src/main/antlr/GraphqlSDL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ inputObjectValueDefinitions : '{' inputValueDefinition* '}';
extensionInputObjectValueDefinitions : '{' inputValueDefinition+ '}';


directiveDefinition : description? DIRECTIVE '@' name argumentsDefinition? 'on' directiveLocations;
directiveDefinition : description? DIRECTIVE '@' name argumentsDefinition? REPEATABLE? ON_KEYWORD directiveLocations;

directiveLocation : name;

Expand Down
11 changes: 6 additions & 5 deletions src/main/java/graphql/DirectivesUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
@Internal
public class DirectivesUtil {

public static Map<String, GraphQLDirective> directivesByName(List<GraphQLDirective> directiveList) {
return FpKit.getByName(directiveList, GraphQLDirective::getName, FpKit.mergeFirst());
public static Map<String, List<GraphQLDirective>> directivesByName(List<GraphQLDirective> directiveList) {
return FpKit.groupingBy(directiveList, gd -> gd.getName());
}

public static Optional<GraphQLArgument> directiveWithArg(List<GraphQLDirective> directiveList, String directiveName, String argumentName) {
GraphQLDirective directive = directivesByName(directiveList).get(directiveName);
GraphQLDirective graphQLDirective = FpKit.findOneOrNull(directiveList, d -> d.getName().equals(directiveName));

GraphQLArgument argument = null;
if (directive != null) {
argument = directive.getArgument(argumentName);
if (graphQLDirective != null) {
argument = graphQLDirective.getArgument(argumentName);
}
return Optional.ofNullable(argument);
}
Expand Down
12 changes: 3 additions & 9 deletions src/main/java/graphql/execution/ConditionalNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import graphql.Internal;
import graphql.VisibleForTesting;
import graphql.language.Directive;
import graphql.util.FpKit;

import java.util.List;
import java.util.Map;

import static graphql.Directives.IncludeDirective;
import static graphql.Directives.SkipDirective;
import static graphql.language.NodeUtil.directivesByName;


@Internal
Expand All @@ -25,15 +25,9 @@ public boolean shouldInclude(Map<String, Object> variables, List<Directive> dire
return !skip && include;
}

private Directive getDirectiveByName(List<Directive> directives, String name) {
if (directives.isEmpty()) {
return null;
}
return directivesByName(directives).get(name);
}

private boolean getDirectiveResult(Map<String, Object> variables, List<Directive> directives, String directiveName, boolean defaultValue) {
Directive directive = getDirectiveByName(directives, directiveName);
Directive directive = FpKit.findOneOrNull(directives, d -> d.getName().equals(directiveName));

if (directive != null) {
Map<String, Object> argumentValues = valuesResolver.getArgumentValues(SkipDirective.getArguments(), directive.getArguments(), variables);
return (Boolean) argumentValues.get("if");
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/graphql/execution/defer/DeferSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import graphql.execution.reactive.SingleSubscriberPublisher;
import graphql.language.Directive;
import graphql.language.Field;
import graphql.util.FpKit;
import org.reactivestreams.Publisher;

import java.util.Deque;
Expand All @@ -34,7 +35,12 @@ public class DeferSupport {

public boolean checkForDeferDirective(MergedField currentField, Map<String,Object> variables) {
for (Field field : currentField.getFields()) {
Directive directive = field.getDirective(DeferDirective.getName());
List<Directive> directives = field.getDirectives();
if (directives == null || directives.isEmpty()) {
return false;
}

Directive directive = FpKit.findOneOrNull(directives, d -> d.getName().equals(DeferDirective.getName()));
if (directive != null) {
Map<String, Object> argumentValues = valuesResolver.getArgumentValues(DeferDirective.getArguments(), directive.getArguments(), variables);
return (Boolean) argumentValues.get("if");
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/graphql/introspection/Introspection.java
Original file line number Diff line number Diff line change
Expand Up @@ -416,18 +416,22 @@ public enum DirectiveLocation {
@SuppressWarnings("deprecation") // because graphql spec still has the deprecated fields
public static final GraphQLObjectType __Directive = newObject()
.name("__Directive")
.description("The __Directive type represents a Directive that a server supports.")
.field(newFieldDefinition()
.name("name")
.type(GraphQLString))
.type(nonNull(GraphQLString)))
.field(newFieldDefinition()
.name("description")
.type(GraphQLString))
.field(newFieldDefinition()
.name("locations")
.type(list(nonNull(__DirectiveLocation))))
.type(nonNull(list(nonNull(__DirectiveLocation)))))
.field(newFieldDefinition()
.name("args")
.type(nonNull(list(nonNull(__InputValue)))))
.field(newFieldDefinition()
.name("isRepeatable")
.type(nonNull(GraphQLBoolean)))
.field(newFieldDefinition()
.name("onOperation")
.type(GraphQLBoolean)
Expand Down
20 changes: 18 additions & 2 deletions src/main/java/graphql/language/DirectiveDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class DirectiveDefinition extends AbstractDescribedNode<DirectiveDefiniti
private final String name;
private final List<InputValueDefinition> inputValueDefinitions;
private final List<DirectiveLocation> directiveLocations;
private final boolean isRepeatable;

public static final String CHILD_INPUT_VALUE_DEFINITIONS = "inputValueDefinitions";
public static final String CHILD_DIRECTIVE_LOCATION = "directiveLocation";
Expand All @@ -30,6 +31,7 @@ protected DirectiveDefinition(String name,
Description description,
List<InputValueDefinition> inputValueDefinitions,
List<DirectiveLocation> directiveLocations,
boolean isRepeatable,
SourceLocation sourceLocation,
List<Comment> comments,
IgnoredChars ignoredChars,
Expand All @@ -38,6 +40,7 @@ protected DirectiveDefinition(String name,
this.name = name;
this.inputValueDefinitions = inputValueDefinitions;
this.directiveLocations = directiveLocations;
this.isRepeatable = isRepeatable;
}

/**
Expand All @@ -46,7 +49,7 @@ protected DirectiveDefinition(String name,
* @param name of the directive definition
*/
public DirectiveDefinition(String name) {
this(name, null, new ArrayList<>(), new ArrayList<>(), null, new ArrayList<>(), IgnoredChars.EMPTY, emptyMap());
this(name, null, new ArrayList<>(), new ArrayList<>(), false, null, new ArrayList<>(), IgnoredChars.EMPTY, emptyMap());
}

@Override
Expand All @@ -62,6 +65,10 @@ public List<DirectiveLocation> getDirectiveLocations() {
return new ArrayList<>(directiveLocations);
}

public boolean isRepeatable() {
return isRepeatable;
}

@Override
public List<Node> getChildren() {
List<Node> result = new ArrayList<>();
Expand Down Expand Up @@ -106,6 +113,7 @@ public DirectiveDefinition deepCopy() {
description,
deepCopy(inputValueDefinitions),
deepCopy(directiveLocations),
isRepeatable,
getSourceLocation(),
getComments(),
getIgnoredChars(),
Expand All @@ -118,6 +126,7 @@ public String toString() {
"name='" + name + "'" +
", inputValueDefinitions=" + inputValueDefinitions +
", directiveLocations=" + directiveLocations +
", isRepeatable=" + isRepeatable +
"}";
}

Expand All @@ -143,6 +152,7 @@ public static final class Builder implements NodeBuilder {
private Description description;
private List<InputValueDefinition> inputValueDefinitions = new ArrayList<>();
private List<DirectiveLocation> directiveLocations = new ArrayList<>();
private boolean isRepeatable;
private IgnoredChars ignoredChars = IgnoredChars.EMPTY;
private Map<String, String> additionalData = new LinkedHashMap<>();

Expand All @@ -156,6 +166,7 @@ private Builder(DirectiveDefinition existing) {
this.description = existing.getDescription();
this.inputValueDefinitions = existing.getInputValueDefinitions();
this.directiveLocations = existing.getDirectiveLocations();
this.isRepeatable = existing.isRepeatable();
this.ignoredChars = existing.getIgnoredChars();
this.additionalData = new LinkedHashMap<>(existing.getAdditionalData());
}
Expand Down Expand Up @@ -200,6 +211,11 @@ public Builder directiveLocation(DirectiveLocation directiveLocation) {
return this;
}

public Builder isRepeatable(boolean isRepeatable) {
this.isRepeatable = isRepeatable;
return this;
}

public Builder ignoredChars(IgnoredChars ignoredChars) {
this.ignoredChars = ignoredChars;
return this;
Expand All @@ -217,7 +233,7 @@ public Builder additionalData(String key, String value) {


public DirectiveDefinition build() {
return new DirectiveDefinition(name, description, inputValueDefinitions, directiveLocations, sourceLocation, comments, ignoredChars, additionalData);
return new DirectiveDefinition(name, description, inputValueDefinitions, directiveLocations, isRepeatable, sourceLocation, comments, ignoredChars, additionalData);
}
}
}
10 changes: 5 additions & 5 deletions src/main/java/graphql/language/DirectivesContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ public interface DirectivesContainer<T extends DirectivesContainer> extends Node
List<Directive> getDirectives();

/**
* @return a a map of directives by directive name
* @return a map of directives by directive name
*/
default Map<String, Directive> getDirectivesByName() {
default Map<String, List<Directive>> getDirectivesByName() {
return directivesByName(getDirectives());
}

/**
* Returns a directive with the provided name
* Returns a directive list with the provided name
*
* @param directiveName the name of the directive to retrieve
*
* @return the directive or null if there is one one with that name
* @return the directive list or null if there is one one with that name
*/
default Directive getDirective(String directiveName) {
default List<Directive> getDirective(String directiveName) {
return getDirectivesByName().get(directiveName);
}
}
4 changes: 2 additions & 2 deletions src/main/java/graphql/language/InlineFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ public List<Directive> getDirectives() {
return new ArrayList<>(directives);
}

public Map<String, Directive> getDirectivesByName() {
public Map<String, List<Directive>> getDirectivesByName() {
return directivesByName(directives);
}

public Directive getDirective(String directiveName) {
public List<Directive> getDirective(String directiveName) {
return getDirectivesByName().get(directiveName);
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/graphql/language/NodeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public static boolean isEqualTo(String thisStr, String thatStr) {
}


public static Map<String, Directive> directivesByName(List<Directive> directives) {
return FpKit.getByName(directives, Directive::getName, mergeFirst());
public static Map<String, List<Directive>> directivesByName(List<Directive> directives) {
return FpKit.groupingBy(directives, Directive::getName);
}

public static Map<String, Argument> argumentsByName(List<Argument> arguments) {
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/graphql/language/SchemaDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import static graphql.language.NodeUtil.directivesByName;

@PublicApi
public class SchemaDefinition extends AbstractNode<SchemaDefinition> implements SDLDefinition<SchemaDefinition> {
public class SchemaDefinition extends AbstractNode<SchemaDefinition> implements DirectivesContainer<SchemaDefinition>, SDLDefinition<SchemaDefinition> {

private final List<Directive> directives;
private final List<OperationTypeDefinition> operationTypeDefinitions;
Expand All @@ -37,15 +37,18 @@ protected SchemaDefinition(List<Directive> directives,
this.operationTypeDefinitions = operationTypeDefinitions;
}

@Override
public List<Directive> getDirectives() {
return new ArrayList<>(directives);
}

public Map<String, Directive> getDirectivesByName() {
@Override
public Map<String, List<Directive>> getDirectivesByName() {
return directivesByName(directives);
}

public Directive getDirective(String directiveName) {
@Override
public List<Directive> getDirective(String directiveName) {
return getDirectivesByName().get(directiveName);
}

Expand Down
1 change: 1 addition & 0 deletions src/main/java/graphql/parser/GraphqlAntlrToLanguage.java
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ protected DirectiveDefinition createDirectiveDefinition(GraphqlParser.DirectiveD
if (ctx.argumentsDefinition() != null) {
def.inputValueDefinitions(createInputValueDefinitions(ctx.argumentsDefinition().inputValueDefinition()));
}
def.isRepeatable(ctx.REPEATABLE() != null);
return def.build();
}

Expand Down
21 changes: 19 additions & 2 deletions src/main/java/graphql/schema/GraphQLDirective.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class GraphQLDirective implements GraphQLNamedSchemaElement {

private final String name;
private final String description;
private final boolean isRepeatable;
private final EnumSet<DirectiveLocation> locations;
private final List<GraphQLArgument> arguments = new ArrayList<>();
private final DirectiveDefinition definition;
Expand All @@ -44,20 +45,23 @@ public class GraphQLDirective implements GraphQLNamedSchemaElement {
@Deprecated
public GraphQLDirective(String name,
String description,
boolean isRepeatable,
EnumSet<DirectiveLocation> locations,
List<GraphQLArgument> arguments) {
this(name, description, locations, arguments, null);
this(name, description, isRepeatable, locations, arguments, null);
}

private GraphQLDirective(String name,
String description,
boolean isRepeatable,
EnumSet<DirectiveLocation> locations,
List<GraphQLArgument> arguments,
DirectiveDefinition definition) {
assertValidName(name);
assertNotNull(arguments, () -> "arguments can't be null");
this.name = name;
this.description = description;
this.isRepeatable = isRepeatable;
this.locations = locations;
this.arguments.addAll(arguments);
this.definition = definition;
Expand Down Expand Up @@ -89,6 +93,10 @@ public String getDescription() {
return description;
}

public boolean isRepeatable() {
return isRepeatable;
}

public DirectiveDefinition getDefinition() {
return definition;
}
Expand All @@ -97,6 +105,7 @@ public DirectiveDefinition getDefinition() {
public String toString() {
return "GraphQLDirective{" +
"name='" + name + '\'' +
", isRepeatable=" + isRepeatable +
", arguments=" + arguments +
", locations=" + locations +
'}';
Expand Down Expand Up @@ -150,6 +159,7 @@ public static Builder newDirective(GraphQLDirective existing) {

public static class Builder extends GraphqlTypeBuilder {

private boolean isRepeatable;
private EnumSet<DirectiveLocation> locations = EnumSet.noneOf(DirectiveLocation.class);
private final Map<String, GraphQLArgument> arguments = new LinkedHashMap<>();
private DirectiveDefinition definition;
Expand All @@ -161,6 +171,7 @@ public Builder() {
public Builder(GraphQLDirective existing) {
this.name = existing.getName();
this.description = existing.getDescription();
this.isRepeatable = existing.isRepeatable();
this.locations = existing.validLocations();
this.arguments.putAll(getByName(existing.getArguments(), GraphQLArgument::getName));
}
Expand All @@ -183,6 +194,11 @@ public Builder comparatorRegistry(GraphqlTypeComparatorRegistry comparatorRegist
return this;
}

public Builder isRepeatable(boolean isRepeatable) {
this.isRepeatable = isRepeatable;
return this;
}

public Builder validLocations(DirectiveLocation... validLocations) {
Collections.addAll(locations, validLocations);
return this;
Expand Down Expand Up @@ -264,11 +280,12 @@ public GraphQLDirective build() {
return new GraphQLDirective(
name,
description,
isRepeatable,
locations,
sort(arguments, GraphQLDirective.class, GraphQLArgument.class),
definition);
}


}
}
}
Loading