graphql.execution.SubscriptionExecutionStrategy Maven / Gradle / Ivy
package graphql.execution;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.execution.reactive.CompletionStageMappingPublisher;
import graphql.language.Field;
import org.reactivestreams.Publisher;
import java.util.concurrent.CompletableFuture;
import static graphql.Assert.assertTrue;
import static java.util.Collections.singletonMap;
/**
* An execution strategy that implements graphql subscriptions by using reactive-streams
* as the output result of the subscription query.
*
* Afterwards each object delivered on that stream will be mapped via running the original selection set over that object and hence producing an ExecutionResult
* just like a normal graphql query.
*
* See https://github.com/facebook/graphql/blob/master/spec/Section%206%20--%20Execution.md
* See http://www.reactive-streams.org/
*/
public class SubscriptionExecutionStrategy extends ExecutionStrategy {
public SubscriptionExecutionStrategy() {
super();
}
public SubscriptionExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHandler) {
super(dataFetcherExceptionHandler);
}
@Override
public CompletableFuture execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
CompletableFuture> sourceEventStream = createSourceEventStream(executionContext, parameters);
//
// when the upstream source event stream completes, subscribe to it and wire in our adapter
return sourceEventStream.thenApply((publisher) -> {
if (publisher == null) {
return new ExecutionResultImpl(null, executionContext.getErrors());
}
CompletionStageMappingPublisher mapSourceToResponse = new CompletionStageMappingPublisher<>(
publisher,
eventPayload -> executeSubscriptionEvent(executionContext, parameters, eventPayload)
);
return new ExecutionResultImpl(mapSourceToResponse, executionContext.getErrors());
});
}
/*
https://github.com/facebook/graphql/blob/master/spec/Section%206%20--%20Execution.md
CreateSourceEventStream(subscription, schema, variableValues, initialValue):
Let {subscriptionType} be the root Subscription type in {schema}.
Assert: {subscriptionType} is an Object type.
Let {selectionSet} be the top level Selection Set in {subscription}.
Let {rootField} be the first top level field in {selectionSet}.
Let {argumentValues} be the result of {CoerceArgumentValues(subscriptionType, rootField, variableValues)}.
Let {fieldStream} be the result of running {ResolveFieldEventStream(subscriptionType, initialValue, rootField, argumentValues)}.
Return {fieldStream}.
*/
private CompletableFuture> createSourceEventStream(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
ExecutionStrategyParameters newParameters = firstFieldOfSubscriptionSelection(parameters);
CompletableFuture fieldFetched = fetchField(executionContext, newParameters);
return fieldFetched.thenApply(fetchedValue -> {
Object publisher = fetchedValue.getFetchedValue();
if (publisher != null) {
assertTrue(publisher instanceof Publisher, "You data fetcher must return a Publisher of events when using graphql subscriptions");
}
//noinspection unchecked
return (Publisher
© 2015 - 2025 Weber Informatics LLC | Privacy Policy