All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.normalized.NormalizedField Maven / Gradle / Ivy

package graphql.normalized;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import graphql.Internal;
import graphql.collect.ImmutableKit;
import graphql.language.Argument;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLSchema;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertTrue;
import static graphql.schema.GraphQLTypeUtil.unwrapAll;

/**
 * Intentionally Mutable
 */
@Internal
public class NormalizedField {
    private final String alias;
    private final ImmutableMap normalizedArguments;
    private final LinkedHashMap resolvedArguments;
    private final ImmutableList astArguments;

    // Mutable List on purpose: it is modified after creation
    private final LinkedHashSet objectTypeNames;
    private final ArrayList children;
    private NormalizedField parent;

    private final String fieldName;
    private final int level;


    private NormalizedField(Builder builder) {
        this.alias = builder.alias;
        this.resolvedArguments = builder.resolvedArguments;
        this.normalizedArguments = builder.normalizedArguments;
        this.astArguments = builder.astArguments;
        this.objectTypeNames = builder.objectTypeNames;
        this.fieldName = assertNotNull(builder.fieldName);
        this.children = builder.children;
        this.level = builder.level;
        this.parent = builder.parent;
    }

    public boolean isConditional(GraphQLSchema schema) {
        if (parent == null) {
            return false;
        }
        return objectTypeNames.size() > 1 || unwrapAll(parent.getType(schema)) != getOneObjectType(schema);
    }

    public GraphQLOutputType getType(GraphQLSchema schema) {
        return getOneFieldDefinition(schema).getType();
    }

    public GraphQLFieldDefinition getOneFieldDefinition(GraphQLSchema schema) {
        GraphQLFieldDefinition fieldDefinition;
        GraphQLFieldDefinition introspectionField = resolveIntrospectionField(fieldName, schema);
        if (introspectionField != null) {
            return introspectionField;
        }
        GraphQLObjectType type = (GraphQLObjectType) assertNotNull(schema.getType(objectTypeNames.iterator().next()));
        fieldDefinition = assertNotNull(type.getField(fieldName), () -> String.format("no field %s found for type %s", fieldName, objectTypeNames.iterator().next()));
        return fieldDefinition;
    }

    public List getFieldDefinitions(GraphQLSchema schema) {
        GraphQLFieldDefinition fieldDefinition = resolveIntrospectionField(fieldName, schema);
        if (fieldDefinition != null) {
            return ImmutableList.of(fieldDefinition);
        }
        ImmutableList.Builder builder = ImmutableList.builder();
        for (String objectTypeName : objectTypeNames) {
            GraphQLObjectType type = (GraphQLObjectType) assertNotNull(schema.getType(objectTypeName));
            builder.add(assertNotNull(type.getField(fieldName), () -> String.format("no field %s found for type %s", fieldName, objectTypeNames.iterator().next())));
        }
        return builder.build();
    }

    private static GraphQLFieldDefinition resolveIntrospectionField(String fieldName, GraphQLSchema schema) {
        if (fieldName.equals(schema.getIntrospectionTypenameFieldDefinition().getName())) {
            return schema.getIntrospectionTypenameFieldDefinition();
        } else {
            if (fieldName.equals(schema.getIntrospectionSchemaFieldDefinition().getName())) {
                return schema.getIntrospectionSchemaFieldDefinition();
            } else if (fieldName.equals(schema.getIntrospectionTypeFieldDefinition().getName())) {
                return schema.getIntrospectionTypeFieldDefinition();
            }
        }
        return null;
    }

    public void addObjectTypeNames(Collection objectTypeNames) {
        this.objectTypeNames.addAll(objectTypeNames);
    }

    public void addChild(NormalizedField normalizedField) {
        this.children.add(normalizedField);
    }

    public void clearChildren() {
        this.children.clear();
        ;
    }

    /**
     * All merged fields have the same name.
     * 

* WARNING: This is not always the key in the execution result, because of possible aliases. See {@link #getResultKey()} * * @return the name of of the merged fields. */ public String getName() { return getFieldName(); } /** * Returns the key of this MergedFieldWithType for the overall result. * This is either an alias or the FieldWTC name. * * @return the key for this MergedFieldWithType. */ public String getResultKey() { if (alias != null) { return alias; } return getName(); } public String getAlias() { return alias; } public ImmutableList getAstArguments() { return astArguments; } public NormalizedInputValue getNormalizedArgument(String name) { return normalizedArguments.get(name); } public ImmutableMap getNormalizedArguments() { return normalizedArguments; } public LinkedHashMap getResolvedArguments() { return resolvedArguments; } public static Builder newNormalizedField() { return new Builder(); } public String getFieldName() { return fieldName; } public NormalizedField transform(Consumer builderConsumer) { Builder builder = new Builder(this); builderConsumer.accept(builder); return builder.build(); } /** * @return Warning: returns a Mutable Set. No defensive copy is made for performance reasons. */ public Set getObjectTypeNames() { return objectTypeNames; } public GraphQLObjectType getOneObjectType(GraphQLSchema schema) { return (GraphQLObjectType) schema.getType(objectTypeNames.iterator().next()); } public String printDetails() { StringBuilder result = new StringBuilder(); if (getAlias() != null) { result.append(getAlias()).append(": "); } return result + objectTypeNamesToString() + "." + fieldName; } public String objectTypeNamesToString() { if (objectTypeNames.size() == 1) { return objectTypeNames.iterator().next(); } else { return objectTypeNames.toString(); } } public List getListOfResultKeys() { LinkedList list = new LinkedList<>(); NormalizedField current = this; while (current != null) { list.addFirst(current.getResultKey()); current = current.parent; } return list; } public List getChildren() { return children; } public int getLevel() { return level; } public NormalizedField getParent() { return parent; } public void replaceParent(NormalizedField newParent) { this.parent = newParent; } @Override public String toString() { return "NormalizedField{" + objectTypeNamesToString() + "." + fieldName + ", alias=" + alias + ", level=" + level + ", children=" + children.stream().map(NormalizedField::toString).collect(Collectors.joining("\n")) + '}'; } public List getChildren(int includingRelativeLevel) { List result = new ArrayList<>(); assertTrue(includingRelativeLevel >= 1, () -> "relative level must be >= 1"); this.getChildren().forEach(child -> { traverseImpl(child, result::add, 1, includingRelativeLevel); }); return result; } public void traverseSubTree(Consumer consumer) { this.getChildren().forEach(child -> { traverseImpl(child, consumer, 1, Integer.MAX_VALUE); }); } private void traverseImpl(NormalizedField root, Consumer consumer, int curRelativeLevel, int abortAfter) { if (curRelativeLevel > abortAfter) { return; } consumer.accept(root); root.getChildren().forEach(child -> { traverseImpl(child, consumer, curRelativeLevel + 1, abortAfter); }); } public static class Builder { private LinkedHashSet objectTypeNames = new LinkedHashSet<>(); private String fieldName; private ArrayList children = new ArrayList<>(); private int level; private NormalizedField parent; private String alias; private ImmutableMap normalizedArguments = ImmutableKit.emptyMap(); private LinkedHashMap resolvedArguments = new LinkedHashMap<>(); private ImmutableList astArguments = ImmutableKit.emptyList(); private Builder() { } private Builder(NormalizedField existing) { this.alias = existing.alias; this.normalizedArguments = existing.normalizedArguments; this.astArguments = existing.astArguments; this.resolvedArguments = existing.resolvedArguments; this.objectTypeNames = new LinkedHashSet<>(existing.getObjectTypeNames()); this.fieldName = existing.getFieldName(); this.children = new ArrayList<>(existing.children); this.level = existing.getLevel(); this.parent = existing.getParent(); } public Builder clearObjectTypesNames() { this.objectTypeNames.clear(); return this; } public Builder objectTypeNames(List objectTypeNames) { this.objectTypeNames.addAll(objectTypeNames); return this; } public Builder alias(String alias) { this.alias = alias; return this; } public Builder normalizedArguments(@Nullable Map arguments) { this.normalizedArguments = arguments == null ? ImmutableKit.emptyMap() : ImmutableMap.copyOf(arguments); return this; } public Builder resolvedArguments(@Nullable Map arguments) { this.resolvedArguments = arguments == null ? new LinkedHashMap<>() : new LinkedHashMap<>(arguments); return this; } public Builder astArguments(@NotNull List astArguments) { this.astArguments = ImmutableList.copyOf(astArguments); return this; } public Builder fieldName(String fieldName) { this.fieldName = fieldName; return this; } public Builder children(List children) { this.children.clear(); this.children.addAll(children); return this; } public Builder level(int level) { this.level = level; return this; } public Builder parent(NormalizedField parent) { this.parent = parent; return this; } public NormalizedField build() { return new NormalizedField(this); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy