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

graphql.validation.ValidationUtil Maven / Gradle / Ivy

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


import com.google.common.collect.ImmutableSet;
import graphql.Assert;
import graphql.GraphQLError;
import graphql.Internal;
import graphql.language.ArrayValue;
import graphql.language.ListType;
import graphql.language.NonNullType;
import graphql.language.NullValue;
import graphql.language.ObjectField;
import graphql.language.ObjectValue;
import graphql.language.Type;
import graphql.language.TypeName;
import graphql.language.Value;
import graphql.language.VariableReference;
import graphql.schema.Coercing;
import graphql.schema.CoercingParseLiteralException;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLType;
import graphql.schema.visibility.GraphqlFieldVisibility;

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

import static graphql.schema.GraphQLTypeUtil.isList;
import static graphql.schema.GraphQLTypeUtil.isNonNull;
import static graphql.schema.GraphQLTypeUtil.unwrapOne;

@Internal
public class ValidationUtil {

    public TypeName getUnmodifiedType(Type type) {
        if (type instanceof ListType) {
            return getUnmodifiedType(((ListType) type).getType());
        } else if (type instanceof NonNullType) {
            return getUnmodifiedType(((NonNullType) type).getType());
        } else if (type instanceof TypeName) {
            return (TypeName) type;
        }
        return Assert.assertShouldNeverHappen();
    }

    protected void handleNullError(Value value, GraphQLType type) {
    }

    protected void handleScalarError(Value value, GraphQLScalarType type, GraphQLError invalid) {
    }

    protected void handleEnumError(Value value, GraphQLEnumType type, GraphQLError invalid) {
    }

    protected void handleNotObjectError(Value value, GraphQLInputObjectType type) {
    }

    protected void handleMissingFieldsError(Value value, GraphQLInputObjectType type, Set missingFields) {
    }

    protected void handleExtraFieldError(Value value, GraphQLInputObjectType type, ObjectField objectField) {
    }

    protected void handleFieldNotValidError(ObjectField objectField, GraphQLInputObjectType type) {
    }

    protected void handleFieldNotValidError(Value value, GraphQLType type, int index) {
    }

    public boolean isValidLiteralValue(Value value, GraphQLType type, GraphQLSchema schema) {
        if (value == null || value instanceof NullValue) {
            boolean valid = !(isNonNull(type));
            if (!valid) {
                handleNullError(value, type);
            }
            return valid;
        }
        if (value instanceof VariableReference) {
            return true;
        }
        if (isNonNull(type)) {
            return isValidLiteralValue(value, unwrapOne(type), schema);
        }

        if (type instanceof GraphQLScalarType) {
            Optional invalid = parseLiteral(value, ((GraphQLScalarType) type).getCoercing());
            invalid.ifPresent(graphQLError -> handleScalarError(value, (GraphQLScalarType) type, graphQLError));
            return !invalid.isPresent();
        }
        if (type instanceof GraphQLEnumType) {
            Optional invalid = parseLiteralEnum(value, (GraphQLEnumType) type);
            invalid.ifPresent(graphQLError -> handleEnumError(value, (GraphQLEnumType) type, graphQLError));
            return !invalid.isPresent();
        }

        if (isList(type)) {
            return isValidLiteralValue(value, (GraphQLList) type, schema);
        }
        return type instanceof GraphQLInputObjectType && isValidLiteralValue(value, (GraphQLInputObjectType) type, schema);

    }

    private Optional parseLiteralEnum(Value value, GraphQLEnumType graphQLEnumType) {
        try {
            graphQLEnumType.parseLiteral(value);
            return Optional.empty();
        } catch (CoercingParseLiteralException e) {
            return Optional.of(e);
        }
    }

    private Optional parseLiteral(Value value, Coercing coercing) {
        try {
            coercing.parseLiteral(value);
            return Optional.empty();
        } catch (CoercingParseLiteralException e) {
            return Optional.of(e);
        }
    }

    private boolean isValidLiteralValue(Value value, GraphQLInputObjectType type, GraphQLSchema schema) {
        if (!(value instanceof ObjectValue)) {
            handleNotObjectError(value, type);
            return false;
        }
        GraphqlFieldVisibility fieldVisibility = schema.getCodeRegistry().getFieldVisibility();
        ObjectValue objectValue = (ObjectValue) value;
        Map objectFieldMap = fieldMap(objectValue);

        Set missingFields = getMissingFields(type, objectFieldMap, fieldVisibility);
        if (!missingFields.isEmpty()) {
            handleMissingFieldsError(value, type, missingFields);
            return false;
        }

        for (ObjectField objectField : objectValue.getObjectFields()) {

            GraphQLInputObjectField inputObjectField = fieldVisibility.getFieldDefinition(type, objectField.getName());
            if (inputObjectField == null) {
                handleExtraFieldError(value, type, objectField);
                return false;
            }
            if (!isValidLiteralValue(objectField.getValue(), inputObjectField.getType(), schema)) {
                handleFieldNotValidError(objectField, type);
                return false;
            }

        }
        return true;
    }

    private Set getMissingFields(GraphQLInputObjectType type, Map objectFieldMap, GraphqlFieldVisibility fieldVisibility) {
        return fieldVisibility.getFieldDefinitions(type).stream()
                .filter(field -> isNonNull(field.getType()))
                .filter(value -> (value.getInputFieldDefaultValue().isNotSet()) && !objectFieldMap.containsKey(value.getName()))
                .map(GraphQLInputObjectField::getName)
                .collect(ImmutableSet.toImmutableSet());
    }

    private Map fieldMap(ObjectValue objectValue) {
        Map result = new LinkedHashMap<>();
        for (ObjectField objectField : objectValue.getObjectFields()) {
            result.put(objectField.getName(), objectField);
        }
        return result;
    }

    private boolean isValidLiteralValue(Value value, GraphQLList type, GraphQLSchema schema) {
        GraphQLType wrappedType = type.getWrappedType();
        if (value instanceof ArrayValue) {
            List values = ((ArrayValue) value).getValues();
            for (int i = 0; i < values.size(); i++) {
                if (!isValidLiteralValue(values.get(i), wrappedType, schema)) {
                    handleFieldNotValidError(values.get(i), wrappedType, i);
                    return false;
                }
            }
            return true;
        } else {
            return isValidLiteralValue(value, wrappedType, schema);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy