graphql.normalized.FieldCollectorNormalizedQuery Maven / Gradle / Ivy
package graphql.normalized;
import graphql.Assert;
import graphql.Internal;
import graphql.execution.ConditionalNodes;
import graphql.execution.MergedField;
import graphql.execution.ValuesResolver;
import graphql.introspection.Introspection;
import graphql.language.Field;
import graphql.language.FragmentDefinition;
import graphql.language.FragmentSpread;
import graphql.language.InlineFragment;
import graphql.language.OperationDefinition;
import graphql.language.Selection;
import graphql.language.SelectionSet;
import graphql.schema.GraphQLCompositeType;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLTypeUtil;
import graphql.schema.GraphQLUnionType;
import graphql.schema.GraphQLUnmodifiedType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static graphql.Assert.assertNotNull;
import static graphql.introspection.Introspection.SchemaMetaFieldDef;
import static graphql.introspection.Introspection.TypeMetaFieldDef;
import static graphql.introspection.Introspection.TypeNameMetaFieldDef;
/**
* Creates a the direct NormalizedFields children, this means it goes only one level deep!
* This also means the NormalizedFields returned dont have any children.
*/
@Internal
public class FieldCollectorNormalizedQuery {
private final ConditionalNodes conditionalNodes = new ConditionalNodes();
private final ValuesResolver valuesResolver = new ValuesResolver();
public static class CollectFieldResult {
private final List children;
private final Map mergedFieldByNormalized;
public CollectFieldResult(List children, Map mergedFieldByNormalized) {
this.children = children;
this.mergedFieldByNormalized = mergedFieldByNormalized;
}
public List getChildren() {
return children;
}
public Map getMergedFieldByNormalized() {
return mergedFieldByNormalized;
}
}
public CollectFieldResult collectFields(FieldCollectorNormalizedQueryParams parameters, NormalizedField normalizedField, MergedField mergedField, int level) {
GraphQLUnmodifiedType fieldType = GraphQLTypeUtil.unwrapAll(normalizedField.getFieldDefinition().getType());
// if not composite we don't have any selectionSet because it is a Scalar or enum
if (!(fieldType instanceof GraphQLCompositeType)) {
return new CollectFieldResult(Collections.emptyList(), Collections.emptyMap());
}
// result key -> ObjectType -> NormalizedField
Map> subFields = new LinkedHashMap<>();
Map mergedFieldByNormalizedField = new LinkedHashMap<>();
Set possibleObjects
= new LinkedHashSet<>(resolvePossibleObjects((GraphQLCompositeType) fieldType, parameters.getGraphQLSchema()));
for (Field field : mergedField.getFields()) {
if (field.getSelectionSet() == null) {
continue;
}
this.collectFields(parameters,
field.getSelectionSet(),
subFields,
mergedFieldByNormalizedField,
possibleObjects,
level,
normalizedField);
}
List children = subFieldsToList(subFields);
return new CollectFieldResult(children, mergedFieldByNormalizedField);
}
public CollectFieldResult collectFromOperation(FieldCollectorNormalizedQueryParams parameters,
OperationDefinition operationDefinition,
GraphQLObjectType rootType) {
Map> subFields = new LinkedHashMap<>();
Map mergedFieldByNormalizedField = new LinkedHashMap<>();
Set possibleObjects = new LinkedHashSet<>();
possibleObjects.add(rootType);
this.collectFields(parameters, operationDefinition.getSelectionSet(), subFields, mergedFieldByNormalizedField, possibleObjects, 1, null);
List children = subFieldsToList(subFields);
return new CollectFieldResult(children, mergedFieldByNormalizedField);
}
private List subFieldsToList(Map> subFields) {
List children = new ArrayList<>();
subFields.values().forEach(setMergedFieldWTCMap -> {
children.addAll(setMergedFieldWTCMap.values());
});
return children;
}
private void collectFields(FieldCollectorNormalizedQueryParams parameters,
SelectionSet selectionSet,
Map> result,
Map mergedFieldByNormalizedField,
Set possibleObjects,
int level,
NormalizedField parent) {
for (Selection selection : selectionSet.getSelections()) {
if (selection instanceof Field) {
collectField(parameters, result, mergedFieldByNormalizedField, (Field) selection, possibleObjects, level, parent);
} else if (selection instanceof InlineFragment) {
collectInlineFragment(parameters, result, mergedFieldByNormalizedField, (InlineFragment) selection, possibleObjects, level, parent);
} else if (selection instanceof FragmentSpread) {
collectFragmentSpread(parameters, result, mergedFieldByNormalizedField, (FragmentSpread) selection, possibleObjects, level, parent);
}
}
}
private void collectFragmentSpread(FieldCollectorNormalizedQueryParams parameters,
Map> result,
Map mergedFieldByNormalizedField,
FragmentSpread fragmentSpread,
Set possibleObjects,
int level,
NormalizedField parent) {
if (!conditionalNodes.shouldInclude(parameters.getVariables(), fragmentSpread.getDirectives())) {
return;
}
FragmentDefinition fragmentDefinition = assertNotNull(parameters.getFragmentsByName().get(fragmentSpread.getName()));
if (!conditionalNodes.shouldInclude(parameters.getVariables(), fragmentDefinition.getDirectives())) {
return;
}
GraphQLCompositeType newCondition = (GraphQLCompositeType) parameters.getGraphQLSchema().getType(fragmentDefinition.getTypeCondition().getName());
Set newConditions = narrowDownPossibleObjects(possibleObjects, newCondition, parameters.getGraphQLSchema());
collectFields(parameters, fragmentDefinition.getSelectionSet(), result, mergedFieldByNormalizedField, newConditions, level, parent);
}
private void collectInlineFragment(FieldCollectorNormalizedQueryParams parameters,
Map> result,
Map mergedFieldByNormalizedField,
InlineFragment inlineFragment,
Set possibleObjects,
int level, NormalizedField parent) {
if (!conditionalNodes.shouldInclude(parameters.getVariables(), inlineFragment.getDirectives())) {
return;
}
Set newPossibleObjects = possibleObjects;
if (inlineFragment.getTypeCondition() != null) {
GraphQLCompositeType newCondition = (GraphQLCompositeType) parameters.getGraphQLSchema().getType(inlineFragment.getTypeCondition().getName());
newPossibleObjects = narrowDownPossibleObjects(possibleObjects, newCondition, parameters.getGraphQLSchema());
}
collectFields(parameters, inlineFragment.getSelectionSet(), result, mergedFieldByNormalizedField, newPossibleObjects, level, parent);
}
private void collectField(FieldCollectorNormalizedQueryParams parameters,
Map> result,
Map mergedFieldByNormalizedField,
Field field,
Set objectTypes,
int level,
NormalizedField parent) {
if (!conditionalNodes.shouldInclude(parameters.getVariables(), field.getDirectives())) {
return;
}
String name = field.getResultKey();
result.computeIfAbsent(name, ignored -> new LinkedHashMap<>());
Map existingFieldWTC = result.get(name);
for (GraphQLObjectType objectType : objectTypes) {
if (existingFieldWTC.containsKey(objectType)) {
NormalizedField normalizedField = existingFieldWTC.get(objectType);
MergedField mergedField1 = mergedFieldByNormalizedField.get(normalizedField);
MergedField updatedMergedField = mergedField1.transform(builder -> builder.addField(field));
mergedFieldByNormalizedField.put(normalizedField, updatedMergedField);
} else {
GraphQLFieldDefinition fieldDefinition;
if (field.getName().equals(TypeNameMetaFieldDef.getName())) {
fieldDefinition = TypeNameMetaFieldDef;
} else if (field.getName().equals(Introspection.SchemaMetaFieldDef.getName())) {
fieldDefinition = SchemaMetaFieldDef;
} else if (field.getName().equals(Introspection.TypeMetaFieldDef.getName())) {
fieldDefinition = TypeMetaFieldDef;
} else {
fieldDefinition = assertNotNull(objectType.getFieldDefinition(field.getName()), () -> String.format("no field with name %s found in object %s", field.getName(), objectType.getName()));
}
Map argumentValues = valuesResolver.getArgumentValues(fieldDefinition.getArguments(), field.getArguments(), parameters.getVariables());
NormalizedField newFieldWTC = NormalizedField.newQueryExecutionField()
.alias(field.getAlias())
.arguments(argumentValues)
.objectType(objectType)
.fieldDefinition(fieldDefinition)
.level(level)
.parent(parent)
.build();
existingFieldWTC.put(objectType, newFieldWTC);
mergedFieldByNormalizedField.put(newFieldWTC, MergedField.newMergedField(field).build());
}
}
}
private Set narrowDownPossibleObjects(Set currentOnes,
GraphQLCompositeType typeCondition,
GraphQLSchema graphQLSchema) {
List resolvedTypeCondition = resolvePossibleObjects(typeCondition, graphQLSchema);
if (currentOnes.size() == 0) {
return new LinkedHashSet<>(resolvedTypeCondition);
}
Set result = new LinkedHashSet<>(currentOnes);
result.retainAll(resolvedTypeCondition);
return result;
}
private List resolvePossibleObjects(GraphQLCompositeType type, GraphQLSchema graphQLSchema) {
if (type instanceof GraphQLObjectType) {
return Collections.singletonList((GraphQLObjectType) type);
} else if (type instanceof GraphQLInterfaceType) {
return graphQLSchema.getImplementations((GraphQLInterfaceType) type);
} else if (type instanceof GraphQLUnionType) {
List types = ((GraphQLUnionType) type).getTypes();
return new ArrayList(types);
} else {
return Assert.assertShouldNeverHappen();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy