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

graphql.schema.validation.NoUnbrokenInputCycles Maven / Gradle / Ivy

The newest version!
package graphql.schema.validation;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import graphql.schema.GraphQLArgument;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLInputType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLModifiedType;
import graphql.schema.GraphQLNonNull;
import graphql.schema.GraphQLType;

/**
 * Schema validation rule ensuring no input type forms an unbroken non-nullable recursion,
 * as such a type would be impossible to satisfy
 */
public class NoUnbrokenInputCycles implements ValidationRule {

    public void check(GraphQLFieldDefinition fieldDef, ValidationErrorCollector validationErrorCollector) {
        for (GraphQLArgument argument : fieldDef.getArguments()) {
            GraphQLInputType argumentType = argument.getType();
            if (argumentType instanceof GraphQLInputObjectType) {
                List path = new ArrayList<>();
                path.add(argumentType.getName());
                check((GraphQLInputObjectType) argumentType, new HashSet<>(), path, validationErrorCollector);
            }
        }
    }

    private void check(GraphQLInputObjectType type, Set seen, List path, ValidationErrorCollector validationErrorCollector) {
        if (seen.contains(type)) {
            validationErrorCollector.addError(new ValidationError(ValidationErrorType.UnbrokenInputCycle, getErrorMessage(path)));
            return;
        }
        seen.add(type);

        for (GraphQLInputObjectField field : type.getFieldDefinitions()) {
            if (field.getType() instanceof GraphQLNonNull) {
                GraphQLType unwrapped = unwrapNonNull((GraphQLNonNull) field.getType());
                if (unwrapped instanceof GraphQLInputObjectType) {
                    path = new ArrayList<>(path);
                    path.add(field.getName() + "!");
                    check((GraphQLInputObjectType) unwrapped, new HashSet<>(seen), path, validationErrorCollector);
                }
            }
        }
    }

    private GraphQLType unwrapNonNull(GraphQLNonNull type) {
        if (type.getWrappedType() instanceof GraphQLList) {
            //we only care about [type!]! i.e. non-null lists of non-nulls
            if (((GraphQLList) type.getWrappedType()).getWrappedType() instanceof GraphQLNonNull) {
                return unwrap(((GraphQLList) type.getWrappedType()).getWrappedType());
            } else {
                return type.getWrappedType();
            }
        } else {
            return unwrap(type.getWrappedType());
        }
    }

    private GraphQLType unwrap(GraphQLType type) {
        if (type instanceof GraphQLModifiedType) {
            return unwrap(((GraphQLModifiedType) type).getWrappedType());
        }
        return type;
    }
    
    private String getErrorMessage(List path) {
        StringBuilder message = new StringBuilder();
        message.append("[");
        for (int i  = 0; i < path.size(); i++) {
            if (i != 0) {
                message.append(".");
            }
            message.append(path.get(i));
        }
        message.append("] forms an unsatisfiable cycle");
        return message.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy