graphql.execution.Async Maven / Gradle / Ivy
package graphql.execution;
import graphql.Assert;
import graphql.Internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@Internal
@SuppressWarnings("FutureReturnValueIgnored")
public class Async {
@FunctionalInterface
public interface CFFactory {
CompletableFuture apply(T input, int index, List previousResults);
}
public static CompletableFuture> each(List> futures) {
CompletableFuture> overallResult = new CompletableFuture<>();
CompletableFuture
.allOf(futures.toArray(new CompletableFuture[0]))
.whenComplete((noUsed, exception) -> {
if (exception != null) {
overallResult.completeExceptionally(exception);
return;
}
List results = new ArrayList<>();
for (CompletableFuture future : futures) {
results.add(future.join());
}
overallResult.complete(results);
});
return overallResult;
}
public static CompletableFuture> each(Iterable list, BiFunction> cfFactory) {
List> futures = new ArrayList<>();
int index = 0;
for (T t : list) {
CompletableFuture cf;
try {
cf = cfFactory.apply(t, index++);
Assert.assertNotNull(cf, () -> "cfFactory must return a non null value");
} catch (Exception e) {
cf = new CompletableFuture<>();
// Async.each makes sure that it is not a CompletionException inside a CompletionException
cf.completeExceptionally(new CompletionException(e));
}
futures.add(cf);
}
return each(futures);
}
public static CompletableFuture> eachSequentially(Iterable list, CFFactory cfFactory) {
CompletableFuture> result = new CompletableFuture<>();
eachSequentiallyImpl(list.iterator(), cfFactory, 0, new ArrayList<>(), result);
return result;
}
private static void eachSequentiallyImpl(Iterator iterator, CFFactory cfFactory, int index, List tmpResult, CompletableFuture> overallResult) {
if (!iterator.hasNext()) {
overallResult.complete(tmpResult);
return;
}
CompletableFuture cf;
try {
cf = cfFactory.apply(iterator.next(), index, tmpResult);
Assert.assertNotNull(cf, () -> "cfFactory must return a non null value");
} catch (Exception e) {
cf = new CompletableFuture<>();
cf.completeExceptionally(new CompletionException(e));
}
cf.whenComplete((cfResult, exception) -> {
if (exception != null) {
overallResult.completeExceptionally(exception);
return;
}
tmpResult.add(cfResult);
eachSequentiallyImpl(iterator, cfFactory, index + 1, tmpResult, overallResult);
});
}
/**
* Turns an object T into a CompletableFuture if its not already
*
* @param t - the object to check
* @param for two
*
* @return a CompletableFuture
*/
public static CompletableFuture toCompletableFuture(T t) {
if (t instanceof CompletionStage) {
//noinspection unchecked
return ((CompletionStage) t).toCompletableFuture();
} else {
return CompletableFuture.completedFuture(t);
}
}
public static CompletableFuture tryCatch(Supplier> supplier) {
try {
return supplier.get();
} catch (Exception e) {
CompletableFuture result = new CompletableFuture<>();
result.completeExceptionally(e);
return result;
}
}
public static CompletableFuture exceptionallyCompletedFuture(Throwable exception) {
CompletableFuture result = new CompletableFuture<>();
result.completeExceptionally(exception);
return result;
}
public static void copyResults(CompletableFuture source, CompletableFuture target) {
source.whenComplete((o, throwable) -> {
if (throwable != null) {
target.completeExceptionally(throwable);
return;
}
target.complete(o);
});
}
public static CompletableFuture reduce(List> values, U initialValue, BiFunction aggregator) {
CompletableFuture result = new CompletableFuture<>();
reduceImpl(values, 0, initialValue, aggregator, result);
return result;
}
public static CompletableFuture reduce(CompletableFuture> values, U initialValue, BiFunction aggregator) {
return values.thenApply(list -> {
U result = initialValue;
for (T value : list) {
result = aggregator.apply(result, value);
}
return result;
});
}
public static CompletableFuture> flatMap(List inputs, Function> mapper) {
List> collect = inputs
.stream()
.map(mapper)
.collect(Collectors.toList());
return Async.each(collect);
}
private static void reduceImpl(List> values, int curIndex, U curValue, BiFunction aggregator, CompletableFuture result) {
if (curIndex == values.size()) {
result.complete(curValue);
return;
}
values.get(curIndex).
thenApply(oneValue -> aggregator.apply(curValue, oneValue))
.thenAccept(newValue -> reduceImpl(values, curIndex + 1, newValue, aggregator, result));
}
public static CompletableFuture> map(CompletableFuture> values, Function mapper) {
return values.thenApply(list -> list.stream().map(mapper).collect(Collectors.toList()));
}
public static List> map(List> values, Function mapper) {
return values
.stream()
.map(cf -> cf.thenApply(mapper::apply)).collect(Collectors.toList());
}
public static List> mapCompose(List> values, Function> mapper) {
return values
.stream()
.map(cf -> cf.thenCompose(mapper::apply)).collect(Collectors.toList());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy