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

graphql.schema.DataFetchingFieldSelectionSetImpl Maven / Gradle / Ivy

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

import graphql.Internal;
import graphql.execution.ExecutionContext;
import graphql.execution.ExecutionTypeInfo;
import graphql.execution.FieldCollector;
import graphql.execution.FieldCollectorParameters;
import graphql.execution.ValuesResolver;
import graphql.introspection.Introspection;
import graphql.language.Field;
import graphql.language.FragmentDefinition;

import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.util.Collections.emptyMap;

@Internal
public class DataFetchingFieldSelectionSetImpl implements DataFetchingFieldSelectionSet {

    private final static DataFetchingFieldSelectionSet NOOP = new DataFetchingFieldSelectionSet() {
        @Override
        public Map> get() {
            return emptyMap();
        }

        @Override
        public Map> getArguments() {
            return emptyMap();
        }

        @Override
        public Map getDefinitions() {
            return emptyMap();
        }

        @Override
        public boolean contains(String fieldGlobPattern) {
            return false;
        }
    };

    public static DataFetchingFieldSelectionSet newCollector(ExecutionContext executionContext, GraphQLType fieldType, List fields) {
        GraphQLType unwrappedType = ExecutionTypeInfo.unwrapBaseType(fieldType);
        if (unwrappedType instanceof GraphQLFieldsContainer) {
            return new DataFetchingFieldSelectionSetImpl(executionContext, (GraphQLFieldsContainer) unwrappedType, fields);
        } else {
            // we can only collect fields on object types and interfaces.  Scalars, Unions etc... cant be done.
            return NOOP;
        }
    }

    private static GraphQLObjectType asObjectTypeOrNull(GraphQLType unwrappedType) {
        return unwrappedType instanceof GraphQLObjectType ? (GraphQLObjectType) unwrappedType : null;
    }

    private final List parentFields;
    private final GraphQLSchema graphQLSchema;
    private final GraphQLFieldsContainer parentFieldType;
    private final Map variables;
    private final Map fragmentsByName;

    private Map> selectionSetFields;
    private Map selectionSetFieldDefinitions;
    private Map> selectionSetFieldArgs;
    private Set flattenedFields;

    private DataFetchingFieldSelectionSetImpl(ExecutionContext executionContext, GraphQLFieldsContainer parentFieldType, List parentFields) {
        this.parentFields = parentFields;
        this.graphQLSchema = executionContext.getGraphQLSchema();
        this.parentFieldType = parentFieldType;
        this.variables = executionContext.getVariables();
        this.fragmentsByName = executionContext.getFragmentsByName();
    }


    @Override
    public Map> get() {
        // by having a .get() method we get lazy evaluation.
        computeValuesLazily();
        return selectionSetFields;
    }

    public Map> getArguments() {
        computeValuesLazily();
        return selectionSetFieldArgs;
    }

    public Map getDefinitions() {
        computeValuesLazily();
        return selectionSetFieldDefinitions;
    }

    @Override
    public boolean contains(String fieldGlobPattern) {
        if (fieldGlobPattern == null || fieldGlobPattern.isEmpty()) {
            return false;
        }
        computeValuesLazily();
        PathMatcher globMatcher = FileSystems.getDefault().getPathMatcher("glob:" + fieldGlobPattern);
        for (String flattenedField : flattenedFields) {
            Path path = Paths.get(flattenedField);
            if (globMatcher.matches(path)) {
                return true;
            }
        }
        return false;
    }

    private void computeValuesLazily() {
        synchronized (this) {
            if (selectionSetFields != null) {
                return;
            }

            selectionSetFields = new LinkedHashMap<>();
            selectionSetFieldDefinitions = new LinkedHashMap<>();
            selectionSetFieldArgs = new LinkedHashMap<>();
            flattenedFields = new LinkedHashSet<>();

            traverseFields(parentFields, parentFieldType, "");
        }
    }

    private final static String SEP = FileSystems.getDefault().getSeparator();


    private void traverseFields(List fieldList, GraphQLFieldsContainer parentFieldType, String fieldPrefix) {
        FieldCollector fieldCollector = new FieldCollector();
        ValuesResolver valuesResolver = new ValuesResolver();

        FieldCollectorParameters parameters = FieldCollectorParameters.newParameters()
                .schema(graphQLSchema)
                .objectType(asObjectTypeOrNull(parentFieldType))
                .fragments(fragmentsByName)
                .variables(variables)
                .build();

        Map> collectedFields = fieldCollector.collectFields(parameters, fieldList);
        for (Map.Entry> entry : collectedFields.entrySet()) {
            String fieldName = mkFieldName(fieldPrefix, entry.getKey());
            List collectedFieldList = entry.getValue();
            selectionSetFields.put(fieldName, collectedFieldList);

            Field field = collectedFieldList.get(0);
            GraphQLFieldDefinition fieldDef = Introspection.getFieldDef(graphQLSchema, (GraphQLCompositeType) parentFieldType, field.getName());
            GraphQLType unwrappedType = ExecutionTypeInfo.unwrapBaseType(fieldDef.getType());
            Map argumentValues = valuesResolver.getArgumentValues(fieldDef.getArguments(), field.getArguments(), variables);

            selectionSetFieldArgs.put(fieldName, argumentValues);
            selectionSetFieldDefinitions.put(fieldName, fieldDef);
            flattenedFields.add(fieldName);

            if (unwrappedType instanceof GraphQLFieldsContainer) {
                traverseFields(collectedFieldList, (GraphQLFieldsContainer) unwrappedType, fieldName);
            }
        }
    }

    private String mkFieldName(String fieldPrefix, String fieldName) {
        return (!fieldPrefix.isEmpty() ? fieldPrefix + SEP : "") + fieldName;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy