-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Repeatable directives support #2015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
7a5f652
Repeatable directives support
bbakerman 1a524c3
Repeatable directives support
bbakerman 466de8a
fixed test
bbakerman d49f54f
Better documentation and more tests
bbakerman b11d16f
Now has runtime types included
bbakerman fc337e6
Fixing up tests
bbakerman c9a9d07
SchemaPrinter and AstPrinter support
bbakerman b73c100
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman 5adf520
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman f81fe14
Fixing builds after bad merge
bbakerman e9deb31
PR feedback
bbakerman af3d667
Removed the getDirectiveByName on AST area
bbakerman fed5321
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman cb1bd84
Killed nonRepeatableDirectivesByName
bbakerman 99c3be2
Killed nonRepeatableDirectivesByName
bbakerman 483d447
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman cf753b9
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman 27597de
Added extra tests for printing repeatable directives
bbakerman 6d53462
Moved to a directive holder
bbakerman ec7fa8a
Merge remote-tracking branch 'origin/master' into repeatable-directiv…
bbakerman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,152 @@ | ||
| package graphql; | ||
|
|
||
| import com.google.common.collect.ImmutableList; | ||
| import com.google.common.collect.ImmutableMap; | ||
| import graphql.schema.GraphQLArgument; | ||
| import graphql.schema.GraphQLDirective; | ||
| import graphql.util.FpKit; | ||
|
|
||
| import java.util.Collection; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static graphql.Assert.assertNotNull; | ||
| import static graphql.collect.ImmutableKit.emptyList; | ||
|
|
||
| @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, GraphQLDirective> nonRepeatableDirectivesByName(List<GraphQLDirective> directives) { | ||
| // filter the repeatable directives | ||
| List<GraphQLDirective> singletonDirectives = directives.stream() | ||
| .filter(d -> !d.isRepeatable()).collect(Collectors.toList()); | ||
|
|
||
| return FpKit.getByName(singletonDirectives, GraphQLDirective::getName); | ||
| } | ||
|
|
||
| public static Optional<GraphQLDirective> directiveByName(List<GraphQLDirective> directives, String directiveName) { | ||
| for (GraphQLDirective directive : directives) { | ||
| if (directive.getName().equals(directiveName)) { | ||
| return Optional.of(directive); | ||
| } | ||
| public static Map<String, ImmutableList<GraphQLDirective>> allDirectivesByName(List<GraphQLDirective> directives) { | ||
|
|
||
| return ImmutableMap.copyOf(FpKit.groupingBy(directives, GraphQLDirective::getName)); | ||
| } | ||
|
|
||
| public static GraphQLDirective nonRepeatedDirectiveByNameWithAssert(Map<String, List<GraphQLDirective>> directives, String directiveName) { | ||
| List<GraphQLDirective> directiveList = directives.get(directiveName); | ||
| if (directiveList == null || directiveList.isEmpty()) { | ||
| return null; | ||
| } | ||
| return Optional.empty(); | ||
| Assert.assertTrue(isAllNonRepeatable(directiveList), () -> String.format("'%s' is a repeatable directive and you have used a non repeatable access method", directiveName)); | ||
| return directiveList.get(0); | ||
| } | ||
|
|
||
| public static Optional<GraphQLArgument> directiveWithArg(List<GraphQLDirective> directiveList, String directiveName, String argumentName) { | ||
| GraphQLDirective directive = directiveByName(directiveList, directiveName).orElse(null); | ||
| public static Optional<GraphQLArgument> directiveWithArg(List<GraphQLDirective> directives, String directiveName, String argumentName) { | ||
| GraphQLDirective directive = nonRepeatableDirectivesByName(directives).get(directiveName); | ||
| GraphQLArgument argument = null; | ||
| if (directive != null) { | ||
| argument = directive.getArgument(argumentName); | ||
| } | ||
| return Optional.ofNullable(argument); | ||
| } | ||
|
|
||
|
|
||
| public static boolean isAllNonRepeatable(List<GraphQLDirective> directives) { | ||
| if (directives == null || directives.isEmpty()) { | ||
| return false; | ||
| } | ||
| for (GraphQLDirective graphQLDirective : directives) { | ||
| if (graphQLDirective.isRepeatable()) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| public static List<GraphQLDirective> enforceAdd(List<GraphQLDirective> targetList, GraphQLDirective newDirective) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think this is an more efficient way to implement public static List<GraphQLDirective> enforceAdd(List<GraphQLDirective> targetList, GraphQLDirective newDirective) {
assertNotNull(targetList, () -> "directive list can't be null");
assertNotNull(newDirective, () -> "directive can't be null");
// check whether the newDirective is repeatable in advance, to avoid needless operations
if(newDirective.isNonRepeatable()){
Map<String, List<GraphQLDirective>> map = allDirectivesByName(targetList);
assertNonRepeatable(newDirective, map);
}
targetList.add(newDirective);
return targetList;
} |
||
| assertNotNull(targetList, () -> "directive list can't be null"); | ||
| assertNotNull(newDirective, () -> "directive can't be null"); | ||
|
|
||
| // check whether the newDirective is repeatable in advance, to avoid needless operations | ||
| if (newDirective.isNonRepeatable()) { | ||
| Map<String, ImmutableList<GraphQLDirective>> map = allDirectivesByName(targetList); | ||
| assertNonRepeatable(newDirective, map); | ||
| } | ||
| targetList.add(newDirective); | ||
| return targetList; | ||
| } | ||
|
|
||
| public static List<GraphQLDirective> enforceAddAll(List<GraphQLDirective> targetList, List<GraphQLDirective> newDirectives) { | ||
| assertNotNull(targetList, () -> "directive list can't be null"); | ||
| assertNotNull(newDirectives, () -> "directive list can't be null"); | ||
| Map<String, ImmutableList<GraphQLDirective>> map = allDirectivesByName(targetList); | ||
| for (GraphQLDirective newDirective : newDirectives) { | ||
| assertNonRepeatable(newDirective, map); | ||
| targetList.add(newDirective); | ||
| } | ||
| return targetList; | ||
| } | ||
|
|
||
| private static void assertNonRepeatable(GraphQLDirective directive, Map<String, ImmutableList<GraphQLDirective>> mapOfDirectives) { | ||
| if (directive.isNonRepeatable()) { | ||
| List<GraphQLDirective> currentDirectives = mapOfDirectives.getOrDefault(directive.getName(), emptyList()); | ||
| int currentSize = currentDirectives.size(); | ||
| if (currentSize > 0) { | ||
| Assert.assertShouldNeverHappen("%s is a non repeatable directive but there is already one present in this list", directive.getName()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static GraphQLDirective getFirstDirective(String name, Map<String, List<GraphQLDirective>> allDirectivesByName) { | ||
| List<GraphQLDirective> directives = allDirectivesByName.getOrDefault(name, emptyList()); | ||
| if (directives.isEmpty()) { | ||
| return null; | ||
| } | ||
| return directives.get(0); | ||
| } | ||
|
|
||
| /** | ||
| * A holder class that breaks a list of directives into maps to be more easily accessible in using classes | ||
| */ | ||
| public static class DirectivesHolder { | ||
|
|
||
| private final ImmutableMap<String, List<GraphQLDirective>> allDirectivesByName; | ||
| private final ImmutableMap<String, GraphQLDirective> nonRepeatableDirectivesByName; | ||
| private final List<GraphQLDirective> allDirectives; | ||
|
|
||
| public DirectivesHolder(Collection<GraphQLDirective> allDirectives) { | ||
| this.allDirectives = ImmutableList.copyOf(allDirectives); | ||
| this.allDirectivesByName = ImmutableMap.copyOf(FpKit.groupingBy(allDirectives, GraphQLDirective::getName)); | ||
| // filter out the repeatable directives | ||
| List<GraphQLDirective> nonRepeatableDirectives = allDirectives.stream() | ||
| .filter(d -> !d.isRepeatable()).collect(Collectors.toList()); | ||
| this.nonRepeatableDirectivesByName = ImmutableMap.copyOf(FpKit.getByName(nonRepeatableDirectives, GraphQLDirective::getName)); | ||
| } | ||
|
|
||
| public ImmutableMap<String, List<GraphQLDirective>> getAllDirectivesByName() { | ||
| return allDirectivesByName; | ||
| } | ||
|
|
||
| public ImmutableMap<String, GraphQLDirective> getDirectivesByName() { | ||
| return nonRepeatableDirectivesByName; | ||
| } | ||
|
|
||
| public List<GraphQLDirective> getDirectives() { | ||
| return allDirectives; | ||
| } | ||
|
|
||
| public GraphQLDirective getDirective(String directiveName) { | ||
| List<GraphQLDirective> directiveList = allDirectivesByName.get(directiveName); | ||
| if (directiveList == null || directiveList.isEmpty()) { | ||
| return null; | ||
| } | ||
| Assert.assertTrue(isAllNonRepeatable(directiveList), () -> String.format("'%s' is a repeatable directive and you have used a non repeatable access method", directiveName)); | ||
| return directiveList.get(0); | ||
|
|
||
| } | ||
|
|
||
| public List<GraphQLDirective> getDirectives(String directiveName) { | ||
| return allDirectivesByName.getOrDefault(directiveName, emptyList()); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nonRepeatableDirectivesByNamewill travel directives three times. The code below seem to be faster: