Repository navigation
Expand file tree
/
Copy pathExecutableNormalizedOperation.java
More file actions
199 lines (180 loc) · 8.01 KB
/
Copy pathExecutableNormalizedOperation.java
File metadata and controls
199 lines (180 loc) · 8.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package graphql.normalized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import graphql.Assert;
import graphql.PublicApi;
import graphql.execution.MergedField;
import graphql.execution.ResultPath;
import graphql.execution.directives.QueryAppliedDirective;
import graphql.execution.directives.QueryDirectives;
import graphql.language.Field;
import graphql.language.OperationDefinition;
import graphql.schema.FieldCoordinates;
import graphql.schema.GraphQLFieldsContainer;
import java.util.List;
import java.util.Map;
/**
* A {@link ExecutableNormalizedOperation} represent how the text of a graphql operation (sometimes known colloquially as a query)
* will be executed at runtime according to the graphql specification. It handles complex mechanisms like merging
* duplicate fields into one and also detecting when the types of a given field may actually be for more than one possible object
* type.
* <p>
* An operation consists of a list of {@link ExecutableNormalizedField}s in a parent child hierarchy
*/
@PublicApi
public class ExecutableNormalizedOperation {
private final OperationDefinition.Operation operation;
private final Map<String, ImmutableList<QueryAppliedDirective>> operationDirectives;
private final String operationName;
private final List<ExecutableNormalizedField> topLevelFields;
private final ImmutableListMultimap<Field, ExecutableNormalizedField> fieldToNormalizedField;
private final Map<ExecutableNormalizedField, MergedField> normalizedFieldToMergedField;
private final Map<ExecutableNormalizedField, QueryDirectives> normalizedFieldToQueryDirectives;
private final ImmutableListMultimap<FieldCoordinates, ExecutableNormalizedField> coordinatesToNormalizedFields;
private final int operationFieldCount;
private final int operationDepth;
public ExecutableNormalizedOperation(
OperationDefinition.Operation operation,
String operationName,
Map<String, ImmutableList<QueryAppliedDirective>> operationDirectives,
List<ExecutableNormalizedField> topLevelFields,
ImmutableListMultimap<Field, ExecutableNormalizedField> fieldToNormalizedField,
Map<ExecutableNormalizedField, MergedField> normalizedFieldToMergedField,
Map<ExecutableNormalizedField, QueryDirectives> normalizedFieldToQueryDirectives,
ImmutableListMultimap<FieldCoordinates, ExecutableNormalizedField> coordinatesToNormalizedFields,
int operationFieldCount,
int operationDepth) {
this.operation = operation;
this.operationName = operationName;
this.operationDirectives = operationDirectives;
this.topLevelFields = topLevelFields;
this.fieldToNormalizedField = fieldToNormalizedField;
this.normalizedFieldToMergedField = normalizedFieldToMergedField;
this.normalizedFieldToQueryDirectives = normalizedFieldToQueryDirectives;
this.coordinatesToNormalizedFields = coordinatesToNormalizedFields;
this.operationFieldCount = operationFieldCount;
this.operationDepth = operationDepth;
}
/**
* @return operation AST being executed
*/
public OperationDefinition.Operation getOperation() {
return operation;
}
/**
* @return the operation name, which can be null
*/
public String getOperationName() {
return operationName;
}
/**
* This is the directives that are on the operation itself and not the fields under it for example
* <pre>
* {@code
* query opName @foo { field }
* }
* </pre>
*
* @return the directives that are on this operation itself.
*/
public Map<String, ImmutableList<QueryAppliedDirective>> getOperationDirectives() {
return operationDirectives;
}
/**
* @return This returns how many {@link ExecutableNormalizedField}s are in the operation.
*/
public int getOperationFieldCount() {
return operationFieldCount;
}
/**
* @return This returns the depth of the operation
*/
public int getOperationDepth() {
return operationDepth;
}
/**
* This multimap shows how a given {@link ExecutableNormalizedField} maps to a one or more field coordinate in the schema
*
* @return a multimap of fields to schema field coordinates
*/
public ImmutableListMultimap<FieldCoordinates, ExecutableNormalizedField> getCoordinatesToNormalizedFields() {
return coordinatesToNormalizedFields;
}
/**
* @return a list of the top level {@link ExecutableNormalizedField}s in this operation.
*/
public List<ExecutableNormalizedField> getTopLevelFields() {
return topLevelFields;
}
/**
* This is a multimap and the size of it reflects all the normalized fields in the operation
*
* @return an immutable list multimap of {@link Field} to {@link ExecutableNormalizedField}
*/
public ImmutableListMultimap<Field, ExecutableNormalizedField> getFieldToNormalizedField() {
return fieldToNormalizedField;
}
/**
* Looks up one or more {@link ExecutableNormalizedField}s given a {@link Field} AST element in the operation
*
* @param field the field to look up
*
* @return zero, one or more possible {@link ExecutableNormalizedField}s that represent that field
*/
public List<ExecutableNormalizedField> getNormalizedFields(Field field) {
return fieldToNormalizedField.get(field);
}
/**
* @return a map of {@link ExecutableNormalizedField} to {@link MergedField}s
*/
public Map<ExecutableNormalizedField, MergedField> getNormalizedFieldToMergedField() {
return normalizedFieldToMergedField;
}
/**
* Looks up the {@link MergedField} given a {@link ExecutableNormalizedField}
*
* @param executableNormalizedField the field to use the key
*
* @return a {@link MergedField} or null if its not present
*/
public MergedField getMergedField(ExecutableNormalizedField executableNormalizedField) {
return normalizedFieldToMergedField.get(executableNormalizedField);
}
/**
* @return a map of {@link ExecutableNormalizedField} to its {@link QueryDirectives}
*/
public Map<ExecutableNormalizedField, QueryDirectives> getNormalizedFieldToQueryDirectives() {
return normalizedFieldToQueryDirectives;
}
/**
* This looks up the {@link QueryDirectives} associated with the given {@link ExecutableNormalizedField}
*
* @param executableNormalizedField the executable normalised field in question
*
* @return the fields query directives or null
*/
public QueryDirectives getQueryDirectives(ExecutableNormalizedField executableNormalizedField) {
return normalizedFieldToQueryDirectives.get(executableNormalizedField);
}
/**
* This will find a {@link ExecutableNormalizedField} given a merged field and a result path. If this does not find a field it will assert with an exception
*
* @param mergedField the merged field
* @param fieldsContainer the containing type of that field
* @param resultPath the result path in play
*
* @return the ExecutableNormalizedField
*/
public ExecutableNormalizedField getNormalizedField(MergedField mergedField, GraphQLFieldsContainer fieldsContainer, ResultPath resultPath) {
List<ExecutableNormalizedField> executableNormalizedFields = fieldToNormalizedField.get(mergedField.getSingleField());
List<String> keysOnlyPath = resultPath.getKeysOnly();
for (ExecutableNormalizedField executableNormalizedField : executableNormalizedFields) {
if (executableNormalizedField.getListOfResultKeys().equals(keysOnlyPath)) {
if (executableNormalizedField.getObjectTypeNames().contains(fieldsContainer.getName())) {
return executableNormalizedField;
}
}
}
return Assert.assertShouldNeverHappen("normalized field not found");
}
}