Skip to content

Commit

Permalink
Add async result for completable futures
Browse files Browse the repository at this point in the history
  • Loading branch information
chiquitinxx committed Feb 5, 2024
1 parent 7757f55 commit b7d03be
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
82 changes: 82 additions & 0 deletions src/main/java/dev/yila/functional/AsyncResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package dev.yila.functional;

import dev.yila.functional.failure.Failure;
import dev.yila.functional.failure.LazyResultException;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Consumer;
import java.util.function.Function;

public class AsyncResult <T, F extends Failure> implements Result<T, F> {

private final CompletableFuture<DirectResult<T, F>> completableFuture;

private AsyncResult(CompletableFuture<T> future) {
this.completableFuture = future.handleAsync((result, throwable) -> {
if (throwable != null) {
return DirectResult.failure(throwable);
}
return DirectResult.ok(result);
});
}

public static <T, F extends Failure> AsyncResult<T, F> create(CompletableFuture<T> future) {
return new AsyncResult<>(future);
}

@Override
public boolean hasFailure() {
return getResult().hasFailure();
}

@Override
public T getOrThrow() {
return getResult().getOrThrow();
}

@Override
public T orElse(Function<Result<T, F>, T> function) {
return getResult().orElse(function);
}

@Override
public Optional<F> failure() {
return getResult().failure();
}

@Override
public <R> Result<R, F> map(Function<T, R> function) {
return getResult().map(function);
}

@Override
public <R> Result<R, F> flatMap(Function<T, Result<R, F>> function) {
return getResult().flatMap(function);
}

@Override
public <R, K extends Throwable> Result<R, F> flatMap(ThrowingFunction<T, R, K> function, Class<K> throwableClass) {
return getResult().flatMap(function, throwableClass);
}

@Override
public Result<T, F> onSuccess(Consumer<T> consumer) {
return getResult().onSuccess(consumer);
}

@Override
public Result<T, F> onFailure(Consumer<Result<T, F>> consumer) {
return getResult().onFailure(consumer);
}

@Override
public Optional<T> value() {
return getResult().value();
}

private Result<T, F> getResult() {
return this.completableFuture.join();
}
}
49 changes: 49 additions & 0 deletions src/test/java/dev/yila/functional/AsyncResultTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.yila.functional;

import dev.yila.functional.failure.Failure;
import org.junit.jupiter.api.Test;

import java.util.concurrent.CompletableFuture;

import static org.junit.jupiter.api.Assertions.*;

public class AsyncResultTest extends ResultTest {

private final RuntimeException runtimeException = new RuntimeException("exception");

@Test
void createAsyncResultFromFuture() {
AsyncResult<Integer, ?> result = AsyncResult.create(CompletableFuture.completedFuture(5));
assertEquals(5, result.getOrThrow());
}

@Test
void asyncFailedWithRuntimeException() {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
AsyncResult<String, ?> result = AsyncResult.create(completableFuture);
completableFuture.completeExceptionally(runtimeException);
assertTrue(result.hasFailure());
Failure failure = result.failure().get();
assertEquals(runtimeException, failure.toThrowable());
}

@Override
Result<Integer, Failure> number(Integer integer) {
return AsyncResult.create(CompletableFuture.completedFuture(integer));
}

@Override
Result<String, Failure> string(String string) {
return AsyncResult.create(CompletableFuture.completedFuture(string));
}

@Override
Result<Integer, Failure> failure(Failure failure) {
return DirectResult.failure(failure);
}

@Override
Result<Integer, Failure> failure(Throwable throwable) {
return DirectResult.failure(throwable);
}
}

0 comments on commit b7d03be

Please sign in to comment.