-
Notifications
You must be signed in to change notification settings - Fork 1.2k
READY- Applied Directives #2562
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
Conversation
| * However with directives on SDL elements, the value is specified in AST only and transferred into the GraphQLArgument object and the | ||
| * 'defaultValue' comes instead from the directive definition elsewhere in the SDL. You can think of them as 'instances' of arguments, their shape and their | ||
| * specific value on that directive. | ||
| */ |
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.
TODO - fix up JavaDoc - currently copied
| * | ||
| * @return a value of type T which is the java value of the argument | ||
| */ | ||
| public static <T> T getArgumentValue(GraphQLInputType argumentType, GraphQLAppliedDirectiveArgument argument) { |
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.
Help needed here @andimarek
| * specific value on that directive. | ||
| */ | ||
| @PublicApi | ||
| public class GraphQLAppliedDirectiveArgument implements GraphQLNamedSchemaElement { |
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.
regarding naming: so the question is: has this actually anything todo with directives? How about GraphQLArgumentValue?
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.
In some ways they dont have anything to do with directives - HOWEVER the only place where we have a "name" and value is in directives in SDL and "args" in queries
We never created a GraphQLArgumentValue in queries (just map<string,object> but yeah we could.
So I like GraphQLArgumentValue or maybe GraphqlAppliedArgument
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.
renamed
| return name; | ||
| } | ||
|
|
||
| @Override |
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.
does an applied directive actually have a description? Not 100% sure out of my head.
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.
They do no have descriptions and the grammar does not allow it
However out interfaces call for it
public interface GraphQLNamedSchemaElement extends GraphQLSchemaElement {
String getName();
String getDescription();
Node getDefinition();
}
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.
probably should add Nullable then to it or add a comment
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.
done
| public String getDescription() { | ||
| return null; | ||
| } | ||
|
|
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.
This is @nullable
| public static <T> T getArgumentValue(GraphQLInputType argumentType, GraphQLAppliedDirectiveArgument argument) { | ||
| return getInputValueImpl(argumentType, argument.getArgumentValue()); | ||
| } | ||
|
|
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.
some question as above: do we actually have a Description?
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.
See above - no
# Conflicts: # src/main/java/graphql/DirectivesUtil.java # src/main/java/graphql/schema/GraphQLArgument.java # src/main/java/graphql/schema/GraphQLEnumType.java # src/main/java/graphql/schema/GraphQLEnumValueDefinition.java # src/main/java/graphql/schema/GraphQLFieldDefinition.java # src/main/java/graphql/schema/GraphQLInputObjectField.java # src/main/java/graphql/schema/GraphQLInputObjectType.java # src/main/java/graphql/schema/GraphQLInterfaceType.java # src/main/java/graphql/schema/GraphQLObjectType.java # src/main/java/graphql/schema/GraphQLScalarType.java # src/main/java/graphql/schema/GraphQLUnionType.java
| * @return the directive to be included | ||
| */ | ||
| GraphQLDirective getDirective(); | ||
| String getDirectiveName(); |
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.
BREAKING CHANGE!!
We could put in a shimand defaulted method but do we want to? I dont think its use enough to warrant it
Thoughts?
| directives.clear(); | ||
| return this; | ||
| } | ||
|
|
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.
All these are moved to a common Builder that is type safe
|
|
||
| @SuppressWarnings("unchecked") | ||
| @Internal | ||
| public abstract class GraphqlDirectivesContainerTypeBuilder<B extends GraphqlDirectivesContainerTypeBuilder<B, BASE>, BASE extends GraphqlTypeBuilder<BASE>> extends GraphqlTypeBuilder<BASE> { |
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.
Cool generics tricks to make sure they return the right type
| import graphql.Internal; | ||
|
|
||
| @Internal | ||
| public final class Pair<T, U> { |
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.
A simple Pair class
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.
think about guava code instead of home grown
| * @return new instance of options | ||
| */ | ||
| public Options includeDirectives(Predicate<GraphQLDirective> includeDirective) { | ||
| return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeSchemaDefinition, this.includeDirectiveDefinitions, this.useAstDefinitions, this.descriptionsAsHashComments, includeDirective, this.includeSchemaElement, this.comparatorRegistry); |
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.
BREAKING CHANGE - again we could do work to make this NOT a breaking change BUT I dont think its worth it.
Thoughts?
| directivesOriginalToNewNameMap.put(directiveName, newName); | ||
| return CONTINUE; | ||
| } | ||
|
|
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.
moved upwards and made common
| * | ||
| * @return a map of all the applied directives immediately on this merged field | ||
| */ | ||
| Map<String, List<GraphQLAppliedDirective>> getImmediateAppliedDirectivesByName(); |
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.
so here the order of the keys matter, right? We should communicate this clearly that the Map keys order reflects the order of the directives found.
Mh ... actually is that true with a merged field?
Maybe it is time to make this more explicit with a Field -> AppliedDirectives result value or so
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.
Field -> AppliedDirectives is super weird in another way. That is we are kinda saying - we can't decide so.... here you go.
I mean we are more correct - only because we are no overly useful.
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.
The code is
final Map<Field, List<GraphQLDirective>> byField = new LinkedHashMap<>();
final Map<Field, List<GraphQLAppliedDirective>> byFieldApplied = new LinkedHashMap<>();
mergedField.getFields().forEach(field -> {
List<Directive> directives = field.getDirectives();
ImmutableList<GraphQLDirective> resolvedDirectives = ImmutableList.copyOf(
directivesResolver
.resolveDirectives(directives, schema, variables)
.values()
);
byField.put(field, resolvedDirectives);
// at some point we will only use applied
byFieldApplied.put(field, ImmutableKit.map(resolvedDirectives, GraphQLDirective::toAppliedDirective));
});
So its in Merged field order - but that in itself might not be meaningful.
I guess this is NO worse than before in directive terms - so we can improve it later with a Field -> AppliedDirectives if we choose
| return name; | ||
| } | ||
|
|
||
| @Override |
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.
probably should add Nullable then to it or add a comment
| return null; | ||
| } | ||
|
|
||
| public List<GraphQLAppliedArgument> getArguments() { |
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.
calling it getAppliedArguments maybe?
| import static graphql.execution.ValuesResolver.getInputValueImpl; | ||
|
|
||
| /** | ||
| * This defines an argument and its value that can be supplied to a graphql field (via {@link GraphQLFieldDefinition} during |
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.
I don't think this is a true this is used for field argument values. conceptually this might be true, but a GraphQLSchemaElement is not concerned with queries/
| return null; | ||
| } | ||
|
|
||
| public Argument getDefinition() { |
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.
Can be null
| * | ||
| * @return a map of all the applied directives immediately on this merged field | ||
| */ | ||
| Map<String, List<GraphQLAppliedDirective>> getImmediateAppliedDirectivesByName(); |
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.
I think the bigger question is actually if applied directives should be used for queries AND schemas? conceptually they are the same, but code wise GraphQLApplieDirective is a schema element and not a query element
…finitions never need this
New behavior introduced in graphql-java/graphql-java#2562
* Better union exclusion * Fix tests * Ignore applied directives New behavior introduced in graphql-java/graphql-java#2562 * Fix counter * Add tests
GraphQLDirective has been designed wrong. It's really the representation of the directive definition. Yet it and GraphqlArgument have been shoe horned into representing the instances of a directives applied to schema elements.
So this PR is s start to support for this. For backwards compat reasons the old information will be present and side by side
GraphQLAppliedDirectives will be made available along with old wrongGraphQLDirectivesThis is not done yet but I am putting up a PR for early feedback.
What needs to be done
✅ means its done
👍 means its QA checked
👎 means tis not right
Go through all the GraphqlDirectiveContainers and fix them up
Make sure the schema validation catches non repeatable directive violations ✅ 👍
Go to schema gen and put in duplicate generation for applied directives along side the current directive code ✅
Put in a SchemaGen option that will NOT put in any old school objects - this will be opt in. ✅
Make sure the Schema Visitor code works and visits these elements ✅
Make sure the SchemaPrinter is working ✅
Make sure the Introspection gets the new applied directives ✅
Make sure graphql.execution.directives.QueryDirectives is working ✅