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

graphql.schema.GraphQLFieldDefinition Maven / Gradle / Ivy

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


import com.google.common.collect.ImmutableList;
import graphql.DirectivesUtil;
import graphql.Internal;
import graphql.PublicApi;
import graphql.language.FieldDefinition;
import graphql.util.Interning;
import graphql.util.TraversalControl;
import graphql.util.TraverserContext;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;

import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertValidName;
import static graphql.schema.DataFetcherFactoryEnvironment.newDataFetchingFactoryEnvironment;
import static graphql.util.FpKit.getByName;

/**
 * Fields are the ways you get data values in graphql and a field definition represents a field, its type, the arguments it takes
 * and the {@link DataFetcher} used to get data values for that field.
 * 

* Fields can be thought of as functions in graphql, they have a name, take defined arguments and return a value. *

* Fields can also be deprecated, which indicates the consumers that a field wont be supported in the future. *

* See https://graphql.org/learn/queries/#fields for more details on the concept. */ @PublicApi public class GraphQLFieldDefinition implements GraphQLNamedSchemaElement, GraphQLDirectiveContainer { private final String name; private final String description; private final GraphQLOutputType originalType; private final DataFetcherFactory dataFetcherFactory; private final String deprecationReason; private final ImmutableList arguments; private final DirectivesUtil.DirectivesHolder directivesHolder; private final FieldDefinition definition; private GraphQLOutputType replacedType; public static final String CHILD_ARGUMENTS = "arguments"; public static final String CHILD_TYPE = "type"; @Internal private GraphQLFieldDefinition(String name, String description, GraphQLOutputType type, DataFetcherFactory dataFetcherFactory, List arguments, String deprecationReason, List directives, List appliedDirectives, FieldDefinition definition) { assertValidName(name); assertNotNull(type, () -> "type can't be null"); assertNotNull(arguments, () -> "arguments can't be null"); this.name = Interning.intern(name); this.description = description; this.originalType = type; this.dataFetcherFactory = dataFetcherFactory; this.arguments = ImmutableList.copyOf(arguments); this.directivesHolder = DirectivesUtil.DirectivesHolder.create(directives, appliedDirectives); this.deprecationReason = deprecationReason; this.definition = definition; } void replaceType(GraphQLOutputType type) { this.replacedType = type; } @Override public String getName() { return name; } public GraphQLOutputType getType() { return replacedType != null ? replacedType : originalType; } // to be removed in a future version when all code is in the code registry @Internal @Deprecated(since = "2018-12-03") DataFetcher getDataFetcher() { if (dataFetcherFactory == null) { return null; } return dataFetcherFactory.get(newDataFetchingFactoryEnvironment() .fieldDefinition(this) .build()); } public GraphQLArgument getArgument(String name) { for (GraphQLArgument argument : arguments) { if (argument.getName().equals(name)) { return argument; } } return null; } @Override public List getDirectives() { return directivesHolder.getDirectives(); } @Override public Map getDirectivesByName() { return directivesHolder.getDirectivesByName(); } @Override public Map> getAllDirectivesByName() { return directivesHolder.getAllDirectivesByName(); } @Override public GraphQLDirective getDirective(String directiveName) { return directivesHolder.getDirective(directiveName); } @Override public List getAppliedDirectives() { return directivesHolder.getAppliedDirectives(); } @Override public Map> getAllAppliedDirectivesByName() { return directivesHolder.getAllAppliedDirectivesByName(); } @Override public GraphQLAppliedDirective getAppliedDirective(String directiveName) { return directivesHolder.getAppliedDirective(directiveName); } public List getArguments() { return arguments; } public String getDescription() { return description; } public FieldDefinition getDefinition() { return definition; } public String getDeprecationReason() { return deprecationReason; } public boolean isDeprecated() { return deprecationReason != null; } @Override public String toString() { return "GraphQLFieldDefinition{" + "name='" + name + '\'' + ", type=" + getType() + ", arguments=" + arguments + ", dataFetcherFactory=" + dataFetcherFactory + ", description='" + description + '\'' + ", deprecationReason='" + deprecationReason + '\'' + ", definition=" + definition + '}'; } /** * This helps you transform the current GraphQLFieldDefinition into another one by starting a builder with all * the current values and allows you to transform it how you want. * * @param builderConsumer the consumer code that will be given a builder to transform * * @return a new field based on calling build on that builder */ public GraphQLFieldDefinition transform(Consumer builderConsumer) { Builder builder = newFieldDefinition(this); builderConsumer.accept(builder); return builder.build(); } @Override public GraphQLSchemaElement copy() { return newFieldDefinition(this).build(); } @Override public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLFieldDefinition(this, context); } @Override public List getChildren() { List children = new ArrayList<>(); children.add(getType()); children.addAll(arguments); children.addAll(directivesHolder.getDirectives()); children.addAll(directivesHolder.getAppliedDirectives()); return children; } @Override public SchemaElementChildrenContainer getChildrenWithTypeReferences() { return SchemaElementChildrenContainer.newSchemaElementChildrenContainer() .child(CHILD_TYPE, originalType) .children(CHILD_ARGUMENTS, arguments) .children(CHILD_DIRECTIVES, directivesHolder.getDirectives()) .children(CHILD_APPLIED_DIRECTIVES, directivesHolder.getAppliedDirectives()) .build(); } // Spock mocking fails with the real return type GraphQLFieldDefinition @Override public GraphQLSchemaElement withNewChildren(SchemaElementChildrenContainer newChildren) { return transform(builder -> builder.replaceArguments(newChildren.getChildren(CHILD_ARGUMENTS)) .type((GraphQLOutputType) newChildren.getChildOrNull(CHILD_TYPE)) .replaceDirectives(newChildren.getChildren(CHILD_DIRECTIVES)) .replaceAppliedDirectives(newChildren.getChildren(CHILD_APPLIED_DIRECTIVES)) ); } /** * {@inheritDoc} */ @Override public final boolean equals(Object o) { return super.equals(o); } /** * {@inheritDoc} */ @Override public final int hashCode() { return super.hashCode(); } public static Builder newFieldDefinition(GraphQLFieldDefinition existing) { return new Builder(existing); } public static Builder newFieldDefinition() { return new Builder(); } @PublicApi public static class Builder extends GraphqlDirectivesContainerTypeBuilder { private GraphQLOutputType type; private DataFetcherFactory dataFetcherFactory; private String deprecationReason; private FieldDefinition definition; private final Map arguments = new LinkedHashMap<>(); public Builder() { } public Builder(GraphQLFieldDefinition existing) { this.name = existing.getName(); this.description = existing.getDescription(); this.type = existing.originalType; this.dataFetcherFactory = DataFetcherFactories.useDataFetcher(existing.getDataFetcher()); this.deprecationReason = existing.getDeprecationReason(); this.definition = existing.getDefinition(); this.arguments.putAll(getByName(existing.getArguments(), GraphQLArgument::getName)); copyExistingDirectives(existing); } public Builder definition(FieldDefinition definition) { this.definition = definition; return this; } public Builder type(GraphQLObjectType.Builder builder) { return type(builder.build()); } public Builder type(GraphQLInterfaceType.Builder builder) { return type(builder.build()); } public Builder type(GraphQLUnionType.Builder builder) { return type(builder.build()); } public Builder type(GraphQLOutputType type) { this.type = type; return this; } /** * Sets the {@link graphql.schema.DataFetcher} to use with this field. * * @param dataFetcher the data fetcher to use * * @return this builder * * @deprecated use {@link graphql.schema.GraphQLCodeRegistry} instead */ @Deprecated(since = "2018-12-03") public Builder dataFetcher(DataFetcher dataFetcher) { assertNotNull(dataFetcher, () -> "dataFetcher must be not null"); this.dataFetcherFactory = DataFetcherFactories.useDataFetcher(dataFetcher); return this; } /** * Sets the {@link graphql.schema.DataFetcherFactory} to use with this field. * * @param dataFetcherFactory the data fetcher factory * * @return this builder * * @deprecated use {@link graphql.schema.GraphQLCodeRegistry} instead */ @Deprecated(since = "2018-12-03") public Builder dataFetcherFactory(DataFetcherFactory dataFetcherFactory) { assertNotNull(dataFetcherFactory, () -> "dataFetcherFactory must be not null"); this.dataFetcherFactory = dataFetcherFactory; return this; } /** * This will cause the data fetcher of this field to always return the supplied value * * @param value the value to always return * * @return this builder * * @deprecated use {@link graphql.schema.GraphQLCodeRegistry} instead */ @Deprecated(since = "2018-12-03") public Builder staticValue(final Object value) { this.dataFetcherFactory = DataFetcherFactories.useDataFetcher(environment -> value); return this; } public Builder argument(GraphQLArgument argument) { assertNotNull(argument, () -> "argument can't be null"); this.arguments.put(argument.getName(), argument); return this; } /** * Take an argument builder in a function definition and apply. Can be used in a jdk8 lambda * e.g.: *

         *     {@code
         *      argument(a -> a.name("argumentName"))
         *     }
         * 
* * @param builderFunction a supplier for the builder impl * * @return this */ public Builder argument(UnaryOperator builderFunction) { GraphQLArgument.Builder builder = GraphQLArgument.newArgument(); builder = builderFunction.apply(builder); return argument(builder); } /** * Same effect as the argument(GraphQLArgument). Builder.build() is called * from within * * @param builder an un-built/incomplete GraphQLArgument * * @return this */ public Builder argument(GraphQLArgument.Builder builder) { argument(builder.build()); return this; } /** * This adds the list of arguments to the field. * * @param arguments the arguments to add * * @return this * * @deprecated This is a badly named method and is replaced by {@link #arguments(java.util.List)} */ @Deprecated(since = "2019-02-06") public Builder argument(List arguments) { return arguments(arguments); } /** * This adds the list of arguments to the field. * * @param arguments the arguments to add * * @return this */ public Builder arguments(List arguments) { assertNotNull(arguments, () -> "arguments can't be null"); for (GraphQLArgument argument : arguments) { argument(argument); } return this; } public Builder replaceArguments(List arguments) { assertNotNull(arguments, () -> "arguments can't be null"); this.arguments.clear(); for (GraphQLArgument argument : arguments) { argument(argument); } return this; } /** * This is used to clear all the arguments in the builder so far. * * @return the builder */ public Builder clearArguments() { arguments.clear(); return this; } public Builder deprecate(String deprecationReason) { this.deprecationReason = deprecationReason; return this; } // -- the following are repeated to avoid a binary incompatibility problem -- @Override public Builder replaceDirectives(List directives) { return super.replaceDirectives(directives); } @Override public Builder withDirectives(GraphQLDirective... directives) { return super.withDirectives(directives); } @Override public Builder withDirective(GraphQLDirective directive) { return super.withDirective(directive); } @Override public Builder withDirective(GraphQLDirective.Builder builder) { return super.withDirective(builder); } @Override public Builder clearDirectives() { return super.clearDirectives(); } @Override public Builder name(String name) { return super.name(name); } @Override public Builder description(String description) { return super.description(description); } public GraphQLFieldDefinition build() { return new GraphQLFieldDefinition( name, description, type, dataFetcherFactory, sort(arguments, GraphQLFieldDefinition.class, GraphQLArgument.class), deprecationReason, sort(directives, GraphQLFieldDefinition.class, GraphQLDirective.class), sort(appliedDirectives, GraphQLScalarType.class, GraphQLAppliedDirective.class), definition); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy