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

graphql.schema.SchemaUtil Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.schema;


import graphql.Assert;
import graphql.AssertException;
import graphql.Internal;
import graphql.introspection.Introspection;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.lang.String.format;

@Internal
public class SchemaUtil {

    public boolean isLeafType(GraphQLType type) {
        GraphQLUnmodifiedType unmodifiedType = getUnmodifiedType(type);
        return
                unmodifiedType instanceof GraphQLScalarType
                        || unmodifiedType instanceof GraphQLEnumType;
    }

    public boolean isInputType(GraphQLType graphQLType) {
        GraphQLUnmodifiedType unmodifiedType = getUnmodifiedType(graphQLType);
        return
                unmodifiedType instanceof GraphQLScalarType
                        || unmodifiedType instanceof GraphQLEnumType
                        || unmodifiedType instanceof GraphQLInputObjectType;
    }

    public GraphQLUnmodifiedType getUnmodifiedType(GraphQLType graphQLType) {
        if (graphQLType instanceof GraphQLModifiedType) {
            return getUnmodifiedType(((GraphQLModifiedType) graphQLType).getWrappedType());
        }
        return (GraphQLUnmodifiedType) graphQLType;
    }


    @SuppressWarnings("StatementWithEmptyBody")
    private void collectTypes(GraphQLType root, Map result) {
        if (root instanceof GraphQLNonNull) {
            collectTypes(((GraphQLNonNull) root).getWrappedType(), result);
        } else if (root instanceof GraphQLList) {
            collectTypes(((GraphQLList) root).getWrappedType(), result);
        } else if (root instanceof GraphQLEnumType) {
            assertTypeUniqueness(root, result);
            result.put(root.getName(), root);
        } else if (root instanceof GraphQLScalarType) {
            assertTypeUniqueness(root, result);
            result.put(root.getName(), root);
        } else if (root instanceof GraphQLObjectType) {
            collectTypesForObjects((GraphQLObjectType) root, result);
        } else if (root instanceof GraphQLInterfaceType) {
            collectTypesForInterfaces((GraphQLInterfaceType) root, result);
        } else if (root instanceof GraphQLUnionType) {
            collectTypesForUnions((GraphQLUnionType) root, result);
        } else if (root instanceof GraphQLInputObjectType) {
            collectTypesForInputObjects((GraphQLInputObjectType) root, result);
        } else if (root instanceof GraphQLTypeReference) {
            // nothing to do
        } else {
            Assert.assertShouldNeverHappen("Unknown type %s", root);
        }
    }

    /*
        From http://facebook.github.io/graphql/#sec-Type-System

           All types within a GraphQL schema must have unique names. No two provided types may have the same name.
           No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).

        Enforcing this helps avoid problems later down the track fo example https://github.com/graphql-java/graphql-java/issues/373
     */
    private void assertTypeUniqueness(GraphQLType type, Map result) {
        GraphQLType existingType = result.get(type.getName());
        // do we have an existing definition
        if (existingType != null) {
            // type references are ok
            if (!(existingType instanceof GraphQLTypeReference || type instanceof GraphQLTypeReference))
                // object comparison here is deliberate
                if (existingType != type) {
                    throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" +
                                    "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" +
                                    "You have redefined the type '%s' from being a '%s' to a '%s'",
                            type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName()));
                }
        }
    }

    private void collectTypesForUnions(GraphQLUnionType unionType, Map result) {
        assertTypeUniqueness(unionType, result);

        result.put(unionType.getName(), unionType);
        for (GraphQLType type : unionType.getTypes()) {
            collectTypes(type, result);
        }

    }

    private void collectTypesForInterfaces(GraphQLInterfaceType interfaceType, Map result) {
        if (result.containsKey(interfaceType.getName()) && !(result.get(interfaceType.getName()) instanceof GraphQLTypeReference)) {
            assertTypeUniqueness(interfaceType, result);
            return;
        }
        result.put(interfaceType.getName(), interfaceType);

        // this deliberately has open field visibility as its collecting on the whole schema
        for (GraphQLFieldDefinition fieldDefinition : interfaceType.getFieldDefinitions()) {
            collectTypes(fieldDefinition.getType(), result);
            for (GraphQLArgument fieldArgument : fieldDefinition.getArguments()) {
                collectTypes(fieldArgument.getType(), result);
            }
        }
    }


    private void collectTypesForObjects(GraphQLObjectType objectType, Map result) {
        if (result.containsKey(objectType.getName()) && !(result.get(objectType.getName()) instanceof GraphQLTypeReference)) {
            assertTypeUniqueness(objectType, result);
            return;
        }
        result.put(objectType.getName(), objectType);

        // this deliberately has open field visibility as its collecting on the whole schema
        for (GraphQLFieldDefinition fieldDefinition : objectType.getFieldDefinitions()) {
            collectTypes(fieldDefinition.getType(), result);
            for (GraphQLArgument fieldArgument : fieldDefinition.getArguments()) {
                collectTypes(fieldArgument.getType(), result);
            }
        }
        for (GraphQLOutputType interfaceType : objectType.getInterfaces()) {
            collectTypes(interfaceType, result);
        }
    }

    private void collectTypesForInputObjects(GraphQLInputObjectType objectType, Map result) {
        if (result.containsKey(objectType.getName()) && !(result.get(objectType.getName()) instanceof GraphQLTypeReference)) {
            assertTypeUniqueness(objectType, result);
            return;
        }
        result.put(objectType.getName(), objectType);

        for (GraphQLInputObjectField fieldDefinition : objectType.getFields()) {
            collectTypes(fieldDefinition.getType(), result);
        }
    }


    public Map allTypes(GraphQLSchema schema, Set additionalTypes) {
        Map typesByName = new LinkedHashMap<>();
        collectTypes(schema.getQueryType(), typesByName);
        if (schema.isSupportingMutations()) {
            collectTypes(schema.getMutationType(), typesByName);
        }
        if (schema.isSupportingSubscriptions()) {
            collectTypes(schema.getSubscriptionType(), typesByName);
        }
        if (additionalTypes != null) {
            for (GraphQLType type : additionalTypes) {
                collectTypes(type, typesByName);
            }
        }
        collectTypes(Introspection.__Schema, typesByName);
        return typesByName;
    }

    public List findImplementations(GraphQLSchema schema, GraphQLInterfaceType interfaceType) {
        Map allTypes = allTypes(schema, schema.getAdditionalTypes());
        List result = new ArrayList<>();
        for (GraphQLType type : allTypes.values()) {
            if (!(type instanceof GraphQLObjectType)) {
                continue;
            }
            GraphQLObjectType objectType = (GraphQLObjectType) type;
            if ((objectType).getInterfaces().contains(interfaceType)) result.add(objectType);
        }
        return result;
    }


    void replaceTypeReferences(GraphQLSchema schema) {
        Map typeMap = allTypes(schema, schema.getAdditionalTypes());
        for (GraphQLType type : typeMap.values()) {
            if (type instanceof GraphQLFieldsContainer) {
                resolveTypeReferencesForFieldsContainer((GraphQLFieldsContainer) type, typeMap);
            }
            if (type instanceof GraphQLInputFieldsContainer) {
                resolveTypeReferencesForInputFieldsContainer((GraphQLInputFieldsContainer) type, typeMap);
            }
            if (type instanceof GraphQLObjectType) {
                ((GraphQLObjectType) type).replaceTypeReferences(typeMap);
            }
            if (type instanceof GraphQLUnionType) {
                ((GraphQLUnionType) type).replaceTypeReferences(typeMap);
            }
        }
    }

    private void resolveTypeReferencesForFieldsContainer(GraphQLFieldsContainer fieldsContainer, Map typeMap) {
        for (GraphQLFieldDefinition fieldDefinition : fieldsContainer.getFieldDefinitions()) {
            fieldDefinition.replaceTypeReferences(typeMap);
            for (GraphQLArgument argument : fieldDefinition.getArguments()) {
                argument.replaceTypeReferences(typeMap);
            }
        }
    }

    private void resolveTypeReferencesForInputFieldsContainer(GraphQLInputFieldsContainer fieldsContainer, Map typeMap) {
        for (GraphQLInputObjectField fieldDefinition : fieldsContainer.getFieldDefinitions()) {
            fieldDefinition.replaceTypeReferences(typeMap);
        }
    }

    GraphQLType resolveTypeReference(GraphQLType type, Map typeMap) {
        if (type instanceof GraphQLTypeReference || typeMap.containsKey(type.getName())) {
            GraphQLType resolvedType = typeMap.get(type.getName());
            Assert.assertTrue(resolvedType != null, "type %s not found in schema", type.getName());
            return resolvedType;
        }
        if (type instanceof GraphQLList) {
            ((GraphQLList) type).replaceTypeReferences(typeMap);
        }
        if (type instanceof GraphQLNonNull) {
            ((GraphQLNonNull) type).replaceTypeReferences(typeMap);
        }
        return type;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy