Allowing document compiler to handles directives and values down in the field tree#3757
Allowing document compiler to handles directives and values down in the field tree#3757
Conversation
| when: | ||
| def result = localCompileToDocument(schema, QUERY, null, fields, noVariables) | ||
| def printed = AstPrinter.printAst(new AstSorter().sort(result.document)) | ||
| def printed = printDoc(result.document) |
There was a problem hiding this comment.
just to clean up the tests a little
|
|
||
|
|
||
| def "test a combination of plain objects and interfaces will be all variables"() { | ||
| def "test a combination of plain objects and interfaces with all variables and no variables"() { |
There was a problem hiding this comment.
I added two test states here - with all variables and with no variables
| v3: [arg1: "barFragArg"], | ||
| v4: [arg1: "barArg"], | ||
| v5: [arg1: "fooArg"]] | ||
|
|
There was a problem hiding this comment.
This is the extra test state. Using no variables
| listField1(arg: [1, 2, 3]) | ||
| listField2(arg: [{arg1 : "v1", arg2 : [{arg1 : "v1.1"}]}, {arg1 : "v2"}, {arg1 : "v3"}]) | ||
| } | ||
| ''' |
There was a problem hiding this comment.
This works - all the values are inlined as expected
| } | ||
|
|
||
| private ExecutableNormalizedOperation createNormalizedTree(GraphQLSchema schema, String query, Map<String, Object> variables = [:]) { | ||
| def "can extract variables or inline values for directives on the query"() { |
There was a problem hiding this comment.
Added this test for directives - it does NOT work - directives are ignored and removed
Test Results 311 files 311 suites 47s ⏱️ Results for commit 053aac4. ♻️ This comment has been updated with latest results. |
| bar(barArg: "barArgVar") @optIn(to: ["optToX"]) | ||
| } | ||
| } | ||
| ''' |
There was a problem hiding this comment.
This currently produces
query named {
foo(fooArg: "fooArgVar") {
bar(barArg: "barArgVar")
}
}
Which is wrong!!
| bar(barArg: $v0) | ||
| } | ||
| } | ||
| ''' |
There was a problem hiding this comment.
The above is also wrong but I made the assertion pass for now - so I can run both tests. But I know this to be wrong
…o print them back out - we need NormalisedValues for this
| Directive directive = directives.get(i); | ||
| GraphQLDirective graphQLDirective = resolvedDirectives.get(i); | ||
| directiveCounterParts.put(graphQLDirective, directive); | ||
| } |
There was a problem hiding this comment.
Question - this is mapping the AST directive to its GraphQLDirective counter part by index - does directivesResolver return the list in the same order and size.
| * argument value making. | ||
| */ | ||
| @Internal | ||
| class ArgumentMaker { |
There was a problem hiding this comment.
as the comment says - breaking out code into its own class
There was a problem hiding this comment.
I like the class name, reminds me of this Monty Python sketch https://www.youtube.com/watch?v=uLlv_aZjHXc
I'd like to have an argument please
| String argName, | ||
| NormalizedInputValue normalizedInputValue) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
since this is a SPI - we cant require them to implement this. Or we could make it a breaking change say
| normalizedVariableValues = ValuesResolver.getNormalizedVariableValues(graphQLSchema, | ||
| variableDefinitions, | ||
| inputVariables, | ||
| executionInput.getGraphQLContext(), executionInput.getLocale()); |
There was a problem hiding this comment.
This is new - we will coerce variables into rutime form AND Normalised literal form so that the ExecutionContext can have them AND the QueryDirectives can have them in the DFE
| public NormalizedVariables getNormalizedVariables() { | ||
| return normalizedVariables; | ||
| } | ||
|
|
There was a problem hiding this comment.
just passing on NormalizedVariables
| QueryDirectives queryDirectives = new QueryDirectivesImpl(field, | ||
| executionContext.getGraphQLSchema(), | ||
| executionContext.getCoercedVariables().toMap(), | ||
| executionContext.getNormalizedVariables().toMap(), |
There was a problem hiding this comment.
needed inside to make normalized values where they refeference operation variables
| public String toString() { | ||
| return normalisedVariables.toString(); | ||
| } | ||
| } |
There was a problem hiding this comment.
We have Raw, Coerced and NormalizedVariables now as distinct classes
|
|
||
| return result; | ||
|
|
||
| return NormalizedVariables.of(result); |
There was a problem hiding this comment.
distinct class now used
| } | ||
|
|
||
| public Map<String, List<GraphQLDirective>> resolveDirectives(List<Directive> directives, GraphQLSchema schema, Map<String, Object> variables, GraphQLContext graphQLContext, Locale locale) { | ||
| public BiMap<GraphQLDirective, Directive> resolveDirectives(List<Directive> directives, GraphQLSchema schema, Map<String, Object> variables, GraphQLContext graphQLContext, Locale locale) { |
There was a problem hiding this comment.
The only use of this internal class is QueryDirectivesImpl - so we can change this with impunity
There was a problem hiding this comment.
Map<String, List> was a pointless modelling - BiMap<GraphQLDirective, Directive is what we need
| * | ||
| * @return a map of applied directive to named argument values | ||
| */ | ||
| Map<QueryAppliedDirective, Map<String, NormalizedInputValue>> getNormalizedInputValueByImmediateAppliedDirectives(); |
There was a problem hiding this comment.
for a given QueryAppliedDirective - we can get a normalised view of its argument values
| @@ -407,59 +416,6 @@ private static SelectionSet selectionSet(List<Field> fields) { | |||
| return newSelectionSet().selections(fields).build(); | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
The code below got moved into ArgumentMaker
| .graphQLContext({ it.put(InputInterceptor.class, interceptor) }) | ||
| .variables( | ||
| "booleanArg": "truthy", | ||
| "booleanArg": false, |
There was a problem hiding this comment.
This was never a valid boolean value
| @Override | ||
| StringValue valueToLiteral(@NotNull Object input, @NotNull GraphQLContext graphQLContext, @NotNull Locale locale) { | ||
| return new StringValue(input.toString()) | ||
| } |
There was a problem hiding this comment.
This is now needed because during "execution" we create normalised values.
This is something contentious. If a SCALAR did not previously have this, they require it now to work.
So we want this. We need to discuss but I think so otherwise I would not have put it in place
There was a problem hiding this comment.
That's very interesting! I want to chat about this too
| import static graphql.normalized.ExecutableNormalizedOperationToAstCompiler.compileToDocumentWithDeferSupport | ||
|
|
||
| abstract class ExecutableNormalizedOperationToAstCompilerTest extends Specification { | ||
| abstract class ENOToAstCompilerTestBase extends Specification { |
There was a problem hiding this comment.
made a common base - this class is getting WAY to big
| static printDoc(Document doc) { | ||
| return AstPrinter.printAst(sortDoc(doc)) | ||
| } | ||
| } |
There was a problem hiding this comment.
most of the above is moving common test helper code around
| name @optIn(to: "devOps") | ||
| foo1(arg: {arg1 : "Subscription"}) @optIn(to: ["foo"]) { | ||
| name @optIn(to: ["devOps"]) | ||
| } |
| executionInput.getGraphQLContext(), | ||
| executionInput.getLocale()); | ||
|
|
||
| normalizedVariableValues = FpKit.intraThreadMemoize(() -> |
There was a problem hiding this comment.
I made this a supplier - if not one asks for normalised values of directives - then no work will be done.
QueryDirectivesIpl is also lazy by design -so this wont be asked for until some one asks for QueryDirectives
| return variablePredicate != null && variablePredicate.shouldMakeVariable(executableNormalizedField, queryAppliedDirective, argName, normalizedInputValue); | ||
| } else { | ||
| return variablePredicate != null && variablePredicate.shouldMakeVariable(executableNormalizedField, argName, normalizedInputValue); | ||
| } |
There was a problem hiding this comment.
this internal call back is the same - when queryAppliedDirective is null - it must be just for a field
There was a problem hiding this comment.
This could be added as a comment in the code, that the else branch is only for a field
| } | ||
| } | ||
| } | ||
| ''' |
There was a problem hiding this comment.
notice all the fragment directives
fragment InnerDetails on Book @timeout(afterMillis: 27)
well they dont get picked up as "immediate" query directives. This is NOT new behavior
Only immediate field directives are captured
| * Test related to ENO and directives | ||
| */ | ||
| class ENOToAstCompilerDirectivesTest extends ENOToAstCompilerTestBase { | ||
| class ExecutableNormalizedOperationToAstCompilerDirectivesTest extends ENOToAstCompilerTestBase { |
There was a problem hiding this comment.
name line up better in IDEA - even though its TOO long a class name
| vars == [v0: "barArgVar", v1: ["optToX"], v2: ["optToY"], v3: "fooArgVar", v4: false] | ||
| // | ||
| // the below is what ir currently produces but its WRONG | ||
| // fix up when the other tests starts to work |
There was a problem hiding this comment.
Is this test working as expected now?
…ument-compiler # Conflicts: # src/main/java/graphql/execution/Execution.java
…ument-compiler # Conflicts: # src/main/java/graphql/execution/Execution.java # src/main/java/graphql/normalized/ExecutableNormalizedOperationToAstCompiler.java
Previously the ENO compiler would not respect "immediate" directives on a field.
While it has the
QueryDirectivesobject - this doe not have "Normalised" values for directive arguments.This PR adds that. This PR is more extensive that I had hoped - but adding Normalised values in multiple places will set us up for betterness later