Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds OutcomeOf::asResult with an onAbsent conversion #114

Merged
merged 2 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/api/lib.api
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public final class app/cash/quiver/OutcomeKt {
public static final fun asOption (Lapp/cash/quiver/Outcome;)Larrow/core/Option;
public static final fun asOutcome (Larrow/core/Either;)Lapp/cash/quiver/Outcome;
public static final fun asResult (Lapp/cash/quiver/Outcome;)Ljava/lang/Object;
public static final fun asResult (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object;
public static final fun failure (Ljava/lang/Object;)Lapp/cash/quiver/Outcome;
public static final fun filter (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function1;)Lapp/cash/quiver/Outcome;
public static final fun flatMap (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function1;)Lapp/cash/quiver/Outcome;
Expand Down
22 changes: 17 additions & 5 deletions lib/src/main/kotlin/app/cash/quiver/Outcome.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
package app.cash.quiver

import app.cash.quiver.extensions.OutcomeOf
import app.cash.quiver.extensions.orThrow
import app.cash.quiver.extensions.toResult
import app.cash.quiver.raise.OutcomeRaise
import app.cash.quiver.raise.outcome
import arrow.core.Either
import arrow.core.Either.Left
import arrow.core.Either.Right
Expand All @@ -14,14 +18,10 @@ import arrow.core.flatMap
import arrow.core.getOrElse
import arrow.core.identity
import arrow.core.left
import arrow.core.raise.catch
import arrow.core.right
import arrow.core.some
import arrow.core.valid
import app.cash.quiver.extensions.orThrow
import app.cash.quiver.extensions.toResult
import app.cash.quiver.raise.OutcomeRaise
import app.cash.quiver.raise.outcome
import arrow.core.raise.catch
import kotlin.experimental.ExperimentalTypeInference

/**
Expand Down Expand Up @@ -247,6 +247,18 @@ inline fun <E, A> Outcome<E, A>.asEither(onAbsent: () -> E): Either<E, A> =
*/
fun <A> OutcomeOf<A>.asResult(): Result<Option<A>> = inner.toResult()

/**
* Converts an OutcomeOf<A> to a Result<A>, converting Absent to a Failure.
*/
inline fun <A> OutcomeOf<A>.asResult(onAbsent: () -> Throwable): Result<A> =
inner.toResult()
.flatMap { maybeValue ->
maybeValue.fold(
{ Result.failure(onAbsent()) },
{ Result.success(it) }
)
}

inline fun <E, A, B> Outcome<E, A>.foldOption(onAbsent: () -> B, onPresent: (A) -> B): Either<E, B> =
inner.map { it.fold(onAbsent, onPresent) }

Expand Down
12 changes: 11 additions & 1 deletion lib/src/test/kotlin/app/cash/quiver/OutcomeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import io.kotest.assertions.throwables.shouldThrow
import io.kotest.common.runBlocking
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.result.shouldBeFailure
import io.kotest.matchers.result.shouldBeSuccess
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
Expand All @@ -40,6 +41,7 @@ import io.kotest.property.arrow.core.either
import io.kotest.property.arrow.core.option
import io.kotest.property.checkAll
import kotlinx.coroutines.coroutineScope
import java.lang.IllegalStateException

class OutcomeTest : StringSpec({
"Present flatMap" {
Expand Down Expand Up @@ -475,6 +477,7 @@ class OutcomeTest : StringSpec({
absent.recover { fallback.bind() }.shouldBeAbsent()
}
}

"recover can recover from Failure" {
checkAll(Arb.either(Arb.long(), Arb.int())) { either ->
val failed: Outcome<String, Int> = "failure".failure()
Expand All @@ -495,9 +498,16 @@ class OutcomeTest : StringSpec({
}
}

"Converting to Result" {
"converting to Result" {
Absent.asResult() shouldBe Result.success(None)
1.present().asResult() shouldBe Result.success(Some(1))
Throwable("sad").failure().asResult().shouldBeFailure().message shouldBe "sad"
}

"asResult converts to Either converting Absent to an error" {
1.present().asResult { IllegalStateException("nup") }.shouldBeSuccess(1)
Absent.asEither { IllegalStateException("nup") }.shouldBeLeft().message shouldBe "nup"
"bad".failure().asEither { IllegalStateException("nup") }.shouldBeLeft("bad")
}

})
Loading