package graphql.schema.idl; import graphql.Assert; import graphql.PublicApi; import graphql.schema.DataFetcher; import graphql.schema.GraphQLScalarType; import graphql.schema.GraphQLSchema; import graphql.schema.TypeResolver; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.UnaryOperator; /** * A runtime wiring is a specification of data fetchers, type resolves and custom scalars that are needed * to wire together a functional {@link GraphQLSchema} */ @PublicApi public class RuntimeWiring { private final Map<String, Map<String, DataFetcher>> dataFetchers; private final Map<String, GraphQLScalarType> scalars; private final Map<String, TypeResolver> typeResolvers; private final WiringFactory wiringFactory; private RuntimeWiring(Map<String, Map<String, DataFetcher>> dataFetchers, Map<String, GraphQLScalarType> scalars, Map<String, TypeResolver> typeResolvers, WiringFactory wiringFactory) { this.dataFetchers = dataFetchers; this.scalars = scalars; this.typeResolvers = typeResolvers; this.wiringFactory = wiringFactory; } public Map<String, GraphQLScalarType> getScalars() { return new LinkedHashMap<>(scalars); } public Map<String, Map<String, DataFetcher>> getDataFetchers() { return dataFetchers; } public Map<String, DataFetcher> getDataFetcherForType(String typeName) { return dataFetchers.computeIfAbsent(typeName, k -> new LinkedHashMap<>()); } public Map<String, TypeResolver> getTypeResolvers() { return typeResolvers; } public WiringFactory getWiringFactory() { return wiringFactory; } /** * @return a builder of Runtime Wiring */ public static Builder newRuntimeWiring() { return new Builder(); } @PublicApi public static class Builder { private final Map<String, Map<String, DataFetcher>> dataFetchers = new LinkedHashMap<>(); private final Map<String, GraphQLScalarType> scalars = new LinkedHashMap<>(); private final Map<String, TypeResolver> typeResolvers = new LinkedHashMap<>(); private WiringFactory wiringFactory = new NoopWiringFactory(); private Builder() { ScalarInfo.STANDARD_SCALARS.forEach(this::scalar); } /** * Adds a wiring factory into the runtime wiring * * @param wiringFactory the wiring factory to add * * @return this outer builder */ public Builder wiringFactory(WiringFactory wiringFactory) { Assert.assertNotNull(wiringFactory, "You must provide a wiring factory"); this.wiringFactory = wiringFactory; return this; } /** * This allows you to add in new custom Scalar implementations beyond the standard set. * * @param scalarType the new scalar implementation * * @return the runtime wiring builder */ public Builder scalar(GraphQLScalarType scalarType) { scalars.put(scalarType.getName(), scalarType); return this; } /** * This allows you to add a new type wiring via a builder * * @param builder the type wiring builder to use * * @return this outer builder */ public Builder type(TypeRuntimeWiring.Builder builder) { return type(builder.build()); } /** * This form allows a lambda to be used as the builder of a type wiring * * @param typeName the name of the type to wire * @param builderFunction a function that will be given the builder to use * * @return the runtime wiring builder */ public Builder type(String typeName, UnaryOperator<TypeRuntimeWiring.Builder> builderFunction) { TypeRuntimeWiring.Builder builder = builderFunction.apply(TypeRuntimeWiring.newTypeWiring(typeName)); return type(builder.build()); } /** * This adds a type wiring * * @param typeRuntimeWiring the new type wiring * * @return the runtime wiring builder */ public Builder type(TypeRuntimeWiring typeRuntimeWiring) { String typeName = typeRuntimeWiring.getTypeName(); Map<String, DataFetcher> typeDataFetchers = dataFetchers.computeIfAbsent(typeName, k -> new LinkedHashMap<>()); typeRuntimeWiring.getFieldDataFetchers().forEach(typeDataFetchers::put); TypeResolver typeResolver = typeRuntimeWiring.getTypeResolver(); if (typeResolver != null) { this.typeResolvers.put(typeName, typeResolver); } return this; } /** * @return the built runtime wiring */ public RuntimeWiring build() { return new RuntimeWiring(dataFetchers, scalars, typeResolvers, wiringFactory); } } }