graphql.normalized.ExecutableNormalizedOperationToAstCompiler Maven / Gradle / Ivy
package graphql.normalized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import graphql.Assert;
import graphql.Internal;
import graphql.introspection.Introspection;
import graphql.language.Argument;
import graphql.language.ArrayValue;
import graphql.language.Document;
import graphql.language.Field;
import graphql.language.InlineFragment;
import graphql.language.NullValue;
import graphql.language.ObjectField;
import graphql.language.ObjectValue;
import graphql.language.OperationDefinition;
import graphql.language.Selection;
import graphql.language.SelectionSet;
import graphql.language.TypeName;
import graphql.language.Value;
import graphql.schema.GraphQLCompositeType;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLUnmodifiedType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static graphql.collect.ImmutableKit.emptyList;
import static graphql.collect.ImmutableKit.map;
import static graphql.language.Argument.newArgument;
import static graphql.language.Field.newField;
import static graphql.language.InlineFragment.newInlineFragment;
import static graphql.language.SelectionSet.newSelectionSet;
import static graphql.language.TypeName.newTypeName;
import static graphql.schema.GraphQLTypeUtil.unwrapAll;
@Internal
public class ExecutableNormalizedOperationToAstCompiler {
public static class CompilerResult {
private final Document document;
private final Map variables;
public CompilerResult(Document document, Map variables) {
this.document = document;
this.variables = variables;
}
public Document getDocument() {
return document;
}
public Map getVariables() {
return variables;
}
}
public static CompilerResult compileToDocument(@NotNull GraphQLSchema schema,
@NotNull OperationDefinition.Operation operationKind,
@Nullable String operationName,
@NotNull List topLevelFields,
@Nullable VariablePredicate variablePredicate) {
GraphQLObjectType operationType = getOperationType(schema, operationKind);
VariableAccumulator variableAccumulator = new VariableAccumulator(variablePredicate);
List> selections = subselectionsForNormalizedField(schema, operationType.getName(), topLevelFields, variableAccumulator);
SelectionSet selectionSet = new SelectionSet(selections);
OperationDefinition.Builder definitionBuilder = OperationDefinition.newOperationDefinition()
.name(operationName)
.operation(operationKind)
.selectionSet(selectionSet);
definitionBuilder.variableDefinitions(variableAccumulator.getVariableDefinitions());
return new CompilerResult(
Document.newDocument()
.definition(definitionBuilder.build())
.build(),
variableAccumulator.getVariablesMap()
);
}
private static List> subselectionsForNormalizedField(GraphQLSchema schema,
@NotNull String parentOutputType,
List executableNormalizedFields,
VariableAccumulator variableAccumulator) {
ImmutableList.Builder> selections = ImmutableList.builder();
// All conditional fields go here instead of directly to selections, so they can be grouped together
// in the same inline fragment in the output
Map> fieldsByTypeCondition = new LinkedHashMap<>();
for (ExecutableNormalizedField nf : executableNormalizedFields) {
if (nf.isConditional(schema)) {
selectionForNormalizedField(schema, nf, variableAccumulator)
.forEach((objectTypeName, field) ->
fieldsByTypeCondition
.computeIfAbsent(objectTypeName, ignored -> new ArrayList<>())
.add(field));
} else {
selections.add(selectionForNormalizedField(schema, parentOutputType, nf, variableAccumulator));
}
}
fieldsByTypeCondition.forEach((objectTypeName, fields) -> {
TypeName typeName = newTypeName(objectTypeName).build();
InlineFragment inlineFragment = newInlineFragment()
.typeCondition(typeName)
.selectionSet(selectionSet(fields))
.build();
selections.add(inlineFragment);
});
return selections.build();
}
/**
* @return Map of object type names to list of fields
*/
private static Map selectionForNormalizedField(GraphQLSchema schema,
ExecutableNormalizedField executableNormalizedField,
VariableAccumulator variableAccumulator) {
Map groupedFields = new LinkedHashMap<>();
for (String objectTypeName : executableNormalizedField.getObjectTypeNames()) {
groupedFields.put(objectTypeName, selectionForNormalizedField(schema, objectTypeName, executableNormalizedField, variableAccumulator));
}
return groupedFields;
}
/**
* @return Map of object type names to list of fields
*/
private static Field selectionForNormalizedField(GraphQLSchema schema,
String objectTypeName,
ExecutableNormalizedField executableNormalizedField,
VariableAccumulator variableAccumulator) {
final List> subSelections;
if (executableNormalizedField.getChildren().isEmpty()) {
subSelections = emptyList();
} else {
GraphQLFieldDefinition fieldDef = getFieldDefinition(schema, objectTypeName, executableNormalizedField);
GraphQLUnmodifiedType fieldOutputType = unwrapAll(fieldDef.getType());
subSelections = subselectionsForNormalizedField(
schema,
fieldOutputType.getName(),
executableNormalizedField.getChildren(),
variableAccumulator
);
}
SelectionSet selectionSet = selectionSetOrNullIfEmpty(subSelections);
List arguments = createArguments(executableNormalizedField, variableAccumulator);
return newField()
.name(executableNormalizedField.getFieldName())
.alias(executableNormalizedField.getAlias())
.selectionSet(selectionSet)
.arguments(arguments)
.build();
}
@Nullable
private static SelectionSet selectionSetOrNullIfEmpty(List> selections) {
return selections.isEmpty() ? null : newSelectionSet().selections(selections).build();
}
private static SelectionSet selectionSet(List fields) {
return newSelectionSet().selections(fields).build();
}
private static List createArguments(ExecutableNormalizedField executableNormalizedField,
VariableAccumulator variableAccumulator) {
ImmutableList.Builder result = ImmutableList.builder();
ImmutableMap normalizedArguments = executableNormalizedField.getNormalizedArguments();
for (String argName : normalizedArguments.keySet()) {
NormalizedInputValue normalizedInputValue = normalizedArguments.get(argName);
Value> value = argValue(executableNormalizedField, argName, normalizedInputValue, variableAccumulator);
Argument argument = newArgument()
.name(argName)
.value(value)
.build();
result.add(argument);
}
return result.build();
}
@SuppressWarnings("unchecked")
private static Value> argValue(ExecutableNormalizedField executableNormalizedField,
String argName,
@Nullable Object value,
VariableAccumulator variableAccumulator) {
if (value instanceof List) {
ArrayValue.Builder arrayValue = ArrayValue.newArrayValue();
arrayValue.values(map((List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy