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

graphql.execution.defer.DeferSupport Maven / Gradle / Ivy

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

import graphql.Directives;
import graphql.ExecutionResult;
import graphql.Internal;
import graphql.execution.MergedField;
import graphql.execution.reactive.SingleSubscriberPublisher;
import graphql.language.Field;
import org.reactivestreams.Publisher;

import java.util.Deque;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * This provides support for @defer directives on fields that mean that results will be sent AFTER
 * the main result is sent via a Publisher stream.
 */
@Internal
public class DeferSupport {

    private final AtomicBoolean deferDetected = new AtomicBoolean(false);
    private final Deque deferredCalls = new ConcurrentLinkedDeque<>();
    private final SingleSubscriberPublisher publisher = new SingleSubscriberPublisher<>();

    public boolean checkForDeferDirective(MergedField currentField) {
        for (Field field : currentField.getFields()) {
            if (field.getDirective(Directives.DeferDirective.getName()) != null) {
                return true;
            }
        }
        return false;
    }

    @SuppressWarnings("FutureReturnValueIgnored")
    private void drainDeferredCalls() {
        if (deferredCalls.isEmpty()) {
            publisher.noMoreData();
            return;
        }
        DeferredCall deferredCall = deferredCalls.pop();
        CompletableFuture future = deferredCall.invoke();
        future.whenComplete((executionResult, exception) -> {
            if (exception != null) {
                publisher.offerError(exception);
                return;
            }
            publisher.offer(executionResult);
            drainDeferredCalls();
        });
    }

    public void enqueue(DeferredCall deferredCall) {
        deferDetected.set(true);
        deferredCalls.offer(deferredCall);
    }

    public boolean isDeferDetected() {
        return deferDetected.get();
    }

    /**
     * When this is called the deferred execution will begin
     *
     * @return the publisher of deferred results
     */
    public Publisher startDeferredCalls() {
        drainDeferredCalls();
        return publisher;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy