From 8bfe8aac16d1d52d10399bf39842342a64cea8a2 Mon Sep 17 00:00:00 2001 From: JoseLion Date: Wed, 6 Dec 2023 00:14:12 -0500 Subject: [PATCH] feat(core): Add SolveHandler flatmap --- .../github/joselion/maybe/SolveHandler.java | 38 +++++++++++++++---- .../joselion/maybe/SolveHandlerTests.java | 22 +++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/github/joselion/maybe/SolveHandler.java b/src/main/java/io/github/joselion/maybe/SolveHandler.java index d4d8768..04385f9 100644 --- a/src/main/java/io/github/joselion/maybe/SolveHandler.java +++ b/src/main/java/io/github/joselion/maybe/SolveHandler.java @@ -341,13 +341,14 @@ public EffectHandler runEffect(// NOSONAR } /** - * If the value is present, map it to another value through the {@code mapper} - * function. If the error is present, the {@code mapper} is never applied and - * the next handler will still contain the error. - * - * @param the type the value will be mapped to - * @param mapper a function that receives the solved value and produces another - * @return a new handler with either the mapped value, or the previous error + * If the value is present, map it to another value using the {@code mapper} + * function. If an error is present, the {@code mapper} function is never + * applied and the next handler will still contain the error. + * + * @param the type the value is mapped to + * @param mapper a function which takes the value as argument and returns + * another value + * @return a new handler with either the mapped value or an error */ public SolveHandler map(final Function mapper) { return this.value @@ -358,6 +359,29 @@ public SolveHandler map(final Function mapper) ); } + /** + * If the value is present, map it to another value using the {@code mapper} + * function. If an error is present, the {@code mapper} function is never + * applied and the next handler will still contain the error. + * + * This method is similar to {@link #map(Function)}, but the mapping function is + * one whose result is a {@code Maybe}, and if invoked, flatMap does not wrap + * it within an additional {@code Maybe}. + * + * @param the type the value is mapped to + * @param mapper a function which takes the value as argument and returns a + * {@code Maybe} with another value + * @return a new handler with either the mapped value or an error + */ + public SolveHandler flatMap(final Function> mapper) { + return this.value + .mapRight(mapper) + .unwrap( + SolveHandler::failure, + maybe -> maybe.solve(ThrowingFunction.identity()) + ); + } + /** * If the value is present, cast the value to anoter type. If the cast fails * or if the error is present, it returns a new handler which contains a diff --git a/src/test/java/io/github/joselion/maybe/SolveHandlerTests.java b/src/test/java/io/github/joselion/maybe/SolveHandlerTests.java index 25e108d..ae236e2 100644 --- a/src/test/java/io/github/joselion/maybe/SolveHandlerTests.java +++ b/src/test/java/io/github/joselion/maybe/SolveHandlerTests.java @@ -383,6 +383,28 @@ } } + @Nested class flatMap { + @Nested class when_the_value_is_present { + @Test void returns_a_handler_applying_the_mapper_function() { + final var handler = SolveHandler.from("Hello world!") + .flatMap(x -> Maybe.of(x.length())); + + assertThat(handler.success()).contains(12); + assertThat(handler.error()).isEmpty(); + } + } + + @Nested class when_the_error_is_present { + @Test void returns_a_handler_with_the_previous_error() { + final var handler = SolveHandler.failure(FAIL_EXCEPTION) + .flatMap(x -> Maybe.of(x.toString())); + + assertThat(handler.success()).isEmpty(); + assertThat(handler.error()).contains(FAIL_EXCEPTION); + } + } + } + @Nested class cast { @Nested class when_the_value_is_present { @Nested class and_the_object_can_be_cast {