Skip to content

Commit

Permalink
Add the then() shortcut
Browse files Browse the repository at this point in the history
  • Loading branch information
cescoffier committed Jul 9, 2020
1 parent 0550140 commit 67f615a
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 4 deletions.
25 changes: 25 additions & 0 deletions documentation/src/main/docs/faq.adoc
Expand Up @@ -117,6 +117,31 @@ include::../../../src/test/java/snippets/EventsTest.java[tags=invoke-uni]

`invokeUni` is a shortcut for `onItem().invokeUni(...)`.


.List of the shortcuts offered by the Uni class
|===
|Shortcut | Equivalent

|`uni.map(x -> y)`
|`uni.onItem().transform(x -> y)`

|`uni.flatMap(x -> uni2)`
|`uni.onItem().transformToUni(x -> uni2)`

|`uni.chain(x -> uni2)`
|`uni.onItem().transformToUni(x -> uni2)`

|`uni.then(() -> uni2)`
|`uni.onItem().transformToUni(ignored -> uni2)`

|`uni.invoke(x -> System.out.println(x))`
|`uni.onItem().invoke(x -> System.out.println(x))`

|`uni.invokeUni(x -> uni2)`
|`uni.onItem().invokeUni(x -> uni2)`
|===


=== How do I merge, concatenate or combine Multis?

You can create instances of `Multi` by concatenating, merging, or combining ``Multi``s and ``Publisher``s:
Expand Down
40 changes: 38 additions & 2 deletions implementation/src/main/java/io/smallrye/mutiny/Uni.java
Expand Up @@ -8,6 +8,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import io.smallrye.mutiny.groups.*;
import io.smallrye.mutiny.subscription.UniEmitter;
Expand Down Expand Up @@ -463,7 +464,7 @@ default <O> Uni<O> flatMap(Function<? super T, Uni<? extends O>> mapper) {
* {@code Uni}. The downstream receives the events emitted by this produced {@code Uni}.
*
* This operation allows <em>chaining</em> asynchronous operations: when the upstream completes with an item, run
* the mapper and emits the item (or failure) send by the produced {@code Uni}:
* the mapper and emits the item (or failure) sent by the produced {@code Uni}:
*
* <pre>
* Uni&lt;Session&gt; uni = getSomeSession();
Expand All @@ -477,18 +478,53 @@ default <O> Uni<O> flatMap(Function<? super T, Uni<? extends O>> mapper) {
* {@link Uni} returned by this method.
* <p>
* This operation is generally named {@code flatMap}.
* This method is a shortcut for {@link UniOnItem#transformToUni(Function)} onItem().transformToUni(mapper)}.
* This method is a shortcut for {@link UniOnItem#transformToUni(Function) onItem().transformToUni(mapper)}.
*
* @param mapper the function called with the item of the this {@link Uni} and producing the {@link Uni},
* must not be {@code null}, must not return {@code null}.
* @param <O> the type of item
* @return a new {@link Uni} that would fire events from the uni produced by the mapper function, possibly
* in an asynchronous manner.
* @see #then(Supplier)
*/
default <O> Uni<O> chain(Function<? super T, Uni<? extends O>> mapper) {
return onItem().transformToUni(nonNull(mapper, "mapper"));
}

/**
* One the observed {@code Uni} emits an item, execute the given {@code supplier}. Unlike {@link #chain(Function)},
* the received item is not required to run the {@code supplier}, and so omitted. The supplier produces another
* {@code Uni}. The downstream receives the events emitted by this produced {@code Uni}.
*
* This operation allows <em>chaining</em> asynchronous operation when you don't need the previous result: when the
* upstream completes with an item, run the supplier and emits the item (or failure) sent by the produced
* {@code Uni}:
*
* <pre>
* {@code
* String id = ...;
* Session session = getSomeSession();
* session.find(Fruit.class, id)
* .chain(fruit -> session.remove(fruit)
* .then(() -> session.flush());
* }
* </pre>
*
* This method is a shortcut for {@link UniOnItem#transformToUni(Function)
* onItem().transformToUni(ignored -> supplier.get())}.
*
* @param supplier the function called when the item of the this {@link Uni} is emitted and producing the {@link Uni},
* must not be {@code null}, must not return {@code null}.
* @param <O> the type of item
* @return a new {@link Uni} that would fire events from the uni produced by the mapper function, possibly
* in an asynchronous manner.
* @see #chain(Function)
*/
default <O> Uni<O> then(Supplier<Uni<? extends O>> supplier) {
Supplier<Uni<? extends O>> actual = nonNull(supplier, "supplier");
return onItem().transformToUni(ignored -> actual.get());
}

/**
* Converts an {@link Uni} to other types such as {@link CompletionStage}
*
Expand Down
Expand Up @@ -7,6 +7,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;

import org.testng.annotations.Test;

Expand Down Expand Up @@ -44,6 +45,23 @@ public void testTransformToUniShortcutChain() {
test.assertCompletedSuccessfully().assertItem(2).assertNoFailure();
}

@Test
public void testTransformToUniShortcutThen() {
UniAssertSubscriber<Integer> test = UniAssertSubscriber.create();
Uni.createFrom().item(1).then(() -> Uni.createFrom().item(2)).subscribe().withSubscriber(test);
test.assertCompletedSuccessfully().assertItem(2).assertNoFailure();
}

@Test(expectedExceptions = IllegalArgumentException.class)
public void testTransformToUniShortcutThenWithNullSupplier() {
Uni.createFrom().item(1).then((Supplier<Uni<?>>) null);
}

@Test(expectedExceptions = IllegalArgumentException.class)
public void testTransformToUniShortcutChainWithNullMApper() {
Uni.createFrom().item(1).chain(null);
}

@Test
public void testWithImmediateCancellation() {
UniAssertSubscriber<Integer> test = new UniAssertSubscriber<>(true);
Expand Down
@@ -1,7 +1,6 @@
package io.smallrye.mutiny.unchecked;

import static io.smallrye.mutiny.unchecked.Unchecked.function;
import static io.smallrye.mutiny.unchecked.Unchecked.unchecked;
import static io.smallrye.mutiny.unchecked.Unchecked.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

Expand Down Expand Up @@ -51,6 +50,10 @@ interface UniReader {
Uni<Integer> read(int i) throws IOException;
}

interface UniSupplier {
Uni<Integer> get() throws IOException;
}

@Test
public void testWithInterfaceMap() {
Reader reader = i -> i;
Expand Down Expand Up @@ -78,6 +81,15 @@ public void testWithChain() {
assertThat(res).isEqualTo(1);
}

@Test
public void testWithThen() {
UniSupplier reader = () -> Uni.createFrom().item(23);
int res = Uni.createFrom().item(1)
.then(supplier(reader::get))
.await().indefinitely();
assertThat(res).isEqualTo(23);
}

private int validate(int i) throws IOException {
if (i != 0) {
return i;
Expand Down

0 comments on commit 67f615a

Please sign in to comment.