Skip to content

Commit 3e23fea

Browse files
committed
This adds more support for Query directives in ENFs and the ability to print them back out - we need NormalisedValues for this
1 parent 08c6bb8 commit 3e23fea

18 files changed

Lines changed: 347 additions & 91 deletions

‎src/main/java/graphql/execution/Execution.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,14 @@ public CompletableFuture<ExecutionResult> execute(Document document, GraphQLSche
7777
List<VariableDefinition> variableDefinitions = operationDefinition.getVariableDefinitions();
7878

7979
CoercedVariables coercedVariables;
80+
NormalizedVariables normalizedVariableValues;
8081
try {
8182
coercedVariables = ValuesResolver.coerceVariableValues(graphQLSchema, variableDefinitions, inputVariables, executionInput.getGraphQLContext(), executionInput.getLocale());
83+
84+
normalizedVariableValues = ValuesResolver.getNormalizedVariableValues(graphQLSchema,
85+
variableDefinitions,
86+
inputVariables,
87+
executionInput.getGraphQLContext(), executionInput.getLocale());
8288
} catch (RuntimeException rte) {
8389
if (rte instanceof GraphQLError) {
8490
return completedFuture(new ExecutionResultImpl((GraphQLError) rte));
@@ -100,6 +106,7 @@ public CompletableFuture<ExecutionResult> execute(Document document, GraphQLSche
100106
.root(executionInput.getRoot())
101107
.fragmentsByName(fragmentsByName)
102108
.coercedVariables(coercedVariables)
109+
.normalizedVariableValues(normalizedVariableValues)
103110
.document(document)
104111
.operationDefinition(operationDefinition)
105112
.dataLoaderRegistry(executionInput.getDataLoaderRegistry())

‎src/main/java/graphql/execution/ExecutionContext.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class ExecutionContext {
4545
private final OperationDefinition operationDefinition;
4646
private final Document document;
4747
private final CoercedVariables coercedVariables;
48+
private final NormalizedVariables normalizedVariables;
4849
private final Object root;
4950
private final Object context;
5051
private final GraphQLContext graphQLContext;
@@ -74,6 +75,7 @@ public class ExecutionContext {
7475
this.subscriptionStrategy = builder.subscriptionStrategy;
7576
this.fragmentsByName = builder.fragmentsByName;
7677
this.coercedVariables = builder.coercedVariables;
78+
this.normalizedVariables = builder.normalizedVariables;
7779
this.document = builder.document;
7880
this.operationDefinition = builder.operationDefinition;
7981
this.context = builder.context;
@@ -127,6 +129,10 @@ public CoercedVariables getCoercedVariables() {
127129
return coercedVariables;
128130
}
129131

132+
public NormalizedVariables getNormalizedVariables() {
133+
return normalizedVariables;
134+
}
135+
130136
/**
131137
* @param <T> for two
132138
*

‎src/main/java/graphql/execution/ExecutionContextBuilder.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class ExecutionContextBuilder {
3838
Document document;
3939
OperationDefinition operationDefinition;
4040
CoercedVariables coercedVariables = CoercedVariables.emptyVariables();
41+
NormalizedVariables normalizedVariables = NormalizedVariables.emptyVariables();
4142
ImmutableMap<String, FragmentDefinition> fragmentsByName = ImmutableKit.emptyMap();
4243
DataLoaderRegistry dataLoaderRegistry;
4344
Locale locale;
@@ -170,6 +171,11 @@ public ExecutionContextBuilder coercedVariables(CoercedVariables coercedVariable
170171
return this;
171172
}
172173

174+
public ExecutionContextBuilder normalizedVariableValues(NormalizedVariables normalizedVariables) {
175+
this.normalizedVariables = normalizedVariables;
176+
return this;
177+
}
178+
173179
public ExecutionContextBuilder fragmentsByName(Map<String, FragmentDefinition> fragmentsByName) {
174180
this.fragmentsByName = ImmutableMap.copyOf(fragmentsByName);
175181
return this;

‎src/main/java/graphql/execution/ExecutionStrategy.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ Async.CombinedBuilder<FieldValueInfo> getAsyncFieldValueInfo(
464464
QueryDirectives queryDirectives = new QueryDirectivesImpl(field,
465465
executionContext.getGraphQLSchema(),
466466
executionContext.getCoercedVariables().toMap(),
467+
executionContext.getNormalizedVariables().toMap(),
467468
executionContext.getGraphQLContext(),
468469
executionContext.getLocale());
469470

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package graphql.execution;
2+
3+
import graphql.PublicApi;
4+
import graphql.collect.ImmutableKit;
5+
import graphql.collect.ImmutableMapWithNullValues;
6+
import graphql.normalized.NormalizedInputValue;
7+
8+
import java.util.Map;
9+
10+
/**
11+
* Holds coerced variables, that is their values are now in a normalized {@link graphql.normalized.NormalizedInputValue} form.
12+
*/
13+
@PublicApi
14+
public class NormalizedVariables {
15+
private final ImmutableMapWithNullValues<String, NormalizedInputValue> normalisedVariables;
16+
17+
public NormalizedVariables(Map<String, NormalizedInputValue> normalisedVariables) {
18+
this.normalisedVariables = ImmutableMapWithNullValues.copyOf(normalisedVariables);
19+
}
20+
21+
public Map<String, NormalizedInputValue> toMap() {
22+
return normalisedVariables;
23+
}
24+
25+
public boolean containsKey(String key) {
26+
return normalisedVariables.containsKey(key);
27+
}
28+
29+
public Object get(String key) {
30+
return normalisedVariables.get(key);
31+
}
32+
33+
public static NormalizedVariables emptyVariables() {
34+
return new NormalizedVariables(ImmutableKit.emptyMap());
35+
}
36+
37+
public static NormalizedVariables of(Map<String, NormalizedInputValue> normalisedVariables) {
38+
return new NormalizedVariables(normalisedVariables);
39+
}
40+
41+
@Override
42+
public String toString() {
43+
return normalisedVariables.toString();
44+
}
45+
}

‎src/main/java/graphql/execution/ValuesResolver.java‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public static CoercedVariables coerceVariableValues(GraphQLSchema schema,
101101
*
102102
* @return a map of the normalised values
103103
*/
104-
public static Map<String, NormalizedInputValue> getNormalizedVariableValues(
104+
public static NormalizedVariables getNormalizedVariableValues(
105105
GraphQLSchema schema,
106106
List<VariableDefinition> variableDefinitions,
107107
RawVariables rawVariables,
@@ -131,9 +131,7 @@ public static Map<String, NormalizedInputValue> getNormalizedVariableValues(
131131
}
132132
}
133133
}
134-
135-
return result;
136-
134+
return NormalizedVariables.of(result);
137135
}
138136

139137

‎src/main/java/graphql/execution/directives/QueryDirectives.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import graphql.PublicApi;
55
import graphql.execution.CoercedVariables;
66
import graphql.execution.MergedField;
7+
import graphql.execution.NormalizedVariables;
78
import graphql.language.Field;
9+
import graphql.normalized.NormalizedInputValue;
810
import graphql.schema.GraphQLDirective;
911
import graphql.schema.GraphQLSchema;
1012

@@ -66,6 +68,16 @@ public interface QueryDirectives {
6668
*/
6769
Map<Field, List<QueryAppliedDirective>> getImmediateAppliedDirectivesByField();
6870

71+
/**
72+
* This will return a map of {@link QueryAppliedDirective} to a map of their argument values in {@link NormalizedInputValue} form
73+
* <p>
74+
* NOTE : This will only be available when {@link graphql.normalized.ExecutableNormalizedOperationFactory} is used
75+
* to create the {@link QueryAppliedDirective} information
76+
*
77+
* @return a map of applied directive to named argument values
78+
*/
79+
Map<QueryAppliedDirective, Map<String, NormalizedInputValue>> getNormalizedInputValueByImmediateAppliedDirectives();
80+
6981
/**
7082
* This will return a list of the named directives that are immediately on this merged field.
7183
*
@@ -108,6 +120,8 @@ interface Builder {
108120

109121
Builder coercedVariables(CoercedVariables coercedVariables);
110122

123+
Builder normalizedVariables(NormalizedVariables normalizedVariables);
124+
111125
Builder graphQLContext(GraphQLContext graphQLContext);
112126

113127
Builder locale(Locale locale);

‎src/main/java/graphql/execution/directives/QueryDirectivesBuilder.java‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import graphql.Internal;
55
import graphql.execution.CoercedVariables;
66
import graphql.execution.MergedField;
7+
import graphql.execution.NormalizedVariables;
78
import graphql.language.Field;
89
import graphql.schema.GraphQLSchema;
910

@@ -15,6 +16,7 @@ public class QueryDirectivesBuilder implements QueryDirectives.Builder {
1516
private MergedField mergedField;
1617
private GraphQLSchema schema;
1718
private CoercedVariables coercedVariables = CoercedVariables.emptyVariables();
19+
private NormalizedVariables normalizedVariables = NormalizedVariables.emptyVariables();
1820
private GraphQLContext graphQLContext = GraphQLContext.getDefault();
1921
private Locale locale = Locale.getDefault();
2022

@@ -42,6 +44,12 @@ public QueryDirectives.Builder coercedVariables(CoercedVariables coercedVariable
4244
return this;
4345
}
4446

47+
@Override
48+
public QueryDirectives.Builder normalizedVariables(NormalizedVariables normalizedVariables) {
49+
this.normalizedVariables = normalizedVariables;
50+
return this;
51+
}
52+
4553
@Override
4654
public QueryDirectives.Builder graphQLContext(GraphQLContext graphQLContext) {
4755
this.graphQLContext = graphQLContext;
@@ -57,6 +65,6 @@ public QueryDirectives.Builder locale(Locale locale) {
5765

5866
@Override
5967
public QueryDirectives build() {
60-
return new QueryDirectivesImpl(mergedField, schema, coercedVariables.toMap(), graphQLContext, locale);
68+
return new QueryDirectivesImpl(mergedField, schema, coercedVariables.toMap(), normalizedVariables.toMap(), graphQLContext, locale);
6169
}
6270
}

‎src/main/java/graphql/execution/directives/QueryDirectivesImpl.java‎

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package graphql.execution.directives;
22

3+
import com.google.common.collect.BiMap;
4+
import com.google.common.collect.HashBiMap;
35
import com.google.common.collect.ImmutableList;
46
import com.google.common.collect.ImmutableMap;
57
import graphql.GraphQLContext;
68
import graphql.Internal;
7-
import graphql.collect.ImmutableKit;
89
import graphql.execution.MergedField;
10+
import graphql.execution.ValuesResolver;
911
import graphql.language.Directive;
1012
import graphql.language.Field;
13+
import graphql.normalized.NormalizedInputValue;
1114
import graphql.schema.GraphQLArgument;
1215
import graphql.schema.GraphQLDirective;
1316
import graphql.schema.GraphQLSchema;
@@ -33,7 +36,8 @@ public class QueryDirectivesImpl implements QueryDirectives {
3336
private final DirectivesResolver directivesResolver = new DirectivesResolver();
3437
private final MergedField mergedField;
3538
private final GraphQLSchema schema;
36-
private final Map<String, Object> variables;
39+
private final Map<String, Object> coercedVariables;
40+
private final Map<String, NormalizedInputValue> normalizedVariableValues;
3741
private final GraphQLContext graphQLContext;
3842
private final Locale locale;
3943

@@ -42,11 +46,13 @@ public class QueryDirectivesImpl implements QueryDirectives {
4246
private volatile ImmutableMap<String, List<GraphQLDirective>> fieldDirectivesByName;
4347
private volatile ImmutableMap<Field, List<QueryAppliedDirective>> fieldAppliedDirectivesByField;
4448
private volatile ImmutableMap<String, List<QueryAppliedDirective>> fieldAppliedDirectivesByName;
49+
private volatile ImmutableMap<QueryAppliedDirective, Map<String, NormalizedInputValue>> normalizedValuesByAppliedDirective;
4550

46-
public QueryDirectivesImpl(MergedField mergedField, GraphQLSchema schema, Map<String, Object> variables, GraphQLContext graphQLContext, Locale locale) {
51+
public QueryDirectivesImpl(MergedField mergedField, GraphQLSchema schema, Map<String, Object> coercedVariables, Map<String, NormalizedInputValue> normalizedVariableValues, GraphQLContext graphQLContext, Locale locale) {
4752
this.mergedField = mergedField;
4853
this.schema = schema;
49-
this.variables = variables;
54+
this.coercedVariables = coercedVariables;
55+
this.normalizedVariableValues = normalizedVariableValues;
5056
this.graphQLContext = graphQLContext;
5157
this.locale = locale;
5258
}
@@ -56,16 +62,32 @@ private void computeValuesLazily() {
5662

5763
final Map<Field, List<GraphQLDirective>> byField = new LinkedHashMap<>();
5864
final Map<Field, List<QueryAppliedDirective>> byFieldApplied = new LinkedHashMap<>();
65+
66+
BiMap<GraphQLDirective, Directive> directiveCounterParts = HashBiMap.create();
67+
BiMap<GraphQLDirective, QueryAppliedDirective> gqlDirectiveCounterParts = HashBiMap.create();
68+
BiMap<QueryAppliedDirective, GraphQLDirective> gqlDirectiveCounterPartsInverse = gqlDirectiveCounterParts.inverse();
5969
mergedField.getFields().forEach(field -> {
6070
List<Directive> directives = field.getDirectives();
6171
ImmutableList<GraphQLDirective> resolvedDirectives = ImmutableList.copyOf(FpKit.flatList(
6272
directivesResolver
63-
.resolveDirectives(directives, schema, variables, graphQLContext, locale)
73+
.resolveDirectives(directives, schema, coercedVariables, graphQLContext, locale)
6474
.values()
6575
));
76+
for (int i = 0; i < directives.size(); i++) {
77+
Directive directive = directives.get(i);
78+
GraphQLDirective graphQLDirective = resolvedDirectives.get(i);
79+
directiveCounterParts.put(graphQLDirective, directive);
80+
}
81+
82+
ImmutableList.Builder<QueryAppliedDirective> appliedDirectiveBuilder = ImmutableList.builder();
83+
for (GraphQLDirective resolvedDirective : resolvedDirectives) {
84+
QueryAppliedDirective appliedDirective = toAppliedDirective(resolvedDirective);
85+
gqlDirectiveCounterParts.put(resolvedDirective, appliedDirective);
86+
appliedDirectiveBuilder.add(appliedDirective);
87+
}
6688
byField.put(field, resolvedDirectives);
6789
// at some point we will only use applied
68-
byFieldApplied.put(field, ImmutableKit.map(resolvedDirectives, this::toAppliedDirective));
90+
byFieldApplied.put(field, appliedDirectiveBuilder.build());
6991
});
7092

7193
Map<String, List<GraphQLDirective>> byName = new LinkedHashMap<>();
@@ -74,13 +96,29 @@ private void computeValuesLazily() {
7496
String name = directive.getName();
7597
byName.computeIfAbsent(name, k -> new ArrayList<>()).add(directive);
7698
// at some point we will only use applied
77-
byNameApplied.computeIfAbsent(name, k -> new ArrayList<>()).add(toAppliedDirective(directive));
99+
QueryAppliedDirective appliedDirective = gqlDirectiveCounterParts.get(directive);
100+
byNameApplied.computeIfAbsent(name, k -> new ArrayList<>()).add(appliedDirective);
78101
}));
79102

103+
// create NormalizedInputValue values for directive arguments
104+
Map<QueryAppliedDirective, Map<String, NormalizedInputValue>> normalizedValuesByAppliedDirective = new LinkedHashMap<>();
105+
if (this.normalizedVariableValues != null) {
106+
byNameApplied.values().forEach(directiveList -> {
107+
for (QueryAppliedDirective queryAppliedDirective : directiveList) {
108+
GraphQLDirective graphQLDirective = gqlDirectiveCounterPartsInverse.get(queryAppliedDirective);
109+
Directive directive = directiveCounterParts.get(graphQLDirective);
110+
111+
Map<String, NormalizedInputValue> normalizedArgumentValues = ValuesResolver.getNormalizedArgumentValues(graphQLDirective.getArguments(), directive.getArguments(), this.normalizedVariableValues);
112+
normalizedValuesByAppliedDirective.put(queryAppliedDirective, normalizedArgumentValues);
113+
}
114+
});
115+
}
116+
80117
this.fieldDirectivesByName = ImmutableMap.copyOf(byName);
81118
this.fieldDirectivesByField = ImmutableMap.copyOf(byField);
82119
this.fieldAppliedDirectivesByName = ImmutableMap.copyOf(byNameApplied);
83120
this.fieldAppliedDirectivesByField = ImmutableMap.copyOf(byFieldApplied);
121+
this.normalizedValuesByAppliedDirective = ImmutableMap.copyOf(normalizedValuesByAppliedDirective);
84122
});
85123
}
86124

@@ -114,6 +152,12 @@ public Map<Field, List<QueryAppliedDirective>> getImmediateAppliedDirectivesByFi
114152
return fieldAppliedDirectivesByField;
115153
}
116154

155+
@Override
156+
public Map<QueryAppliedDirective, Map<String, NormalizedInputValue>> getNormalizedInputValueByImmediateAppliedDirectives() {
157+
computeValuesLazily();
158+
return normalizedValuesByAppliedDirective;
159+
}
160+
117161
@Override
118162
public Map<String, List<GraphQLDirective>> getImmediateDirectivesByName() {
119163
computeValuesLazily();

0 commit comments

Comments
 (0)