Skip to content

Commit

Permalink
Merge pull request #2 from VirtusLab/no-exceptions
Browse files Browse the repository at this point in the history
remove exceptions + add arrow compatibility
  • Loading branch information
krzykrucz committed Jan 7, 2020
2 parents 986a25b + cbdefed commit 27bf5d6
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,55 @@ import com.virtuslab.basetypes.result.mapError

typealias AsyncResult<T, E> = IO<Result<T, E>>

fun <S : Any, E : Exception, S2 : Any> AsyncResult<S, E>.mapSuccess(mapper: (S) -> S2): AsyncResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> AsyncResult<S, E>.mapSuccess(mapper: (S) -> S2): AsyncResult<S2, E> =
this.map {
it.map(mapper)
}

fun <S : Any, E : Exception, E2 : java.lang.Exception> AsyncResult<S, E>.mapFailure(mapper: (E) -> E2): AsyncResult<S, E2> =
fun <S : Any, E : Any, E2 : Any> AsyncResult<S, E>.mapFailure(mapper: (E) -> E2): AsyncResult<S, E2> =
this.map {
it.mapError(mapper)
}

fun <S : Any, E : Exception, S2 : Any> AsyncResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): AsyncResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> AsyncResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): AsyncResult<S2, E> =
this.map {
it.flatMap(mapper)
}

fun <S : Any, E : Exception, S2 : Any> AsyncResult<S, E>.flatMapSuccess(mapper: (S) -> AsyncResult<S2, E>): AsyncResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> AsyncResult<S, E>.flatMapSuccess(mapper: (S) -> AsyncResult<S2, E>): AsyncResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value)
is Failure -> Failure(result1.error).toAsync()
}
}

fun <S : Any, E : Exception, S2 : Any> AsyncResult<S, E>.flatMapSuccess(mapper: (S) -> IO<S2>, errorMapper: (Throwable) -> E): AsyncResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> AsyncResult<S, E>.flatMapSuccess(mapper: (S) -> IO<S2>, errorMapper: (Throwable) -> E): AsyncResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value).liftResult(errorMapper)
is Failure -> Failure(result1.error).toAsync()
}
}

fun <S : Any, E : Exception, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> AsyncResult<S2, E>): AsyncResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> AsyncResult<S2, E>): AsyncResult<S2, E> =
when (this) {
is Success -> mapper(value)
is Failure -> Failure(error).toAsync()
}

fun <S : Any, E : Exception> S.justAsyncResult(): AsyncResult<S, E> =
fun <S : Any, E : Any> S.justAsyncResult(): AsyncResult<S, E> =
Result.of<S, E> { this }
.let { IO.just(it) }

fun <S : Any, E : Exception> E.failedAsyncResult(): AsyncResult<S, E> =
fun <S : Any, E : Any> E.failedAsyncResult(): AsyncResult<S, E> =
Result.error(this)
.let { IO.just(it) }

fun <S : Any, E : Exception> IO<S>.liftResult(errorMapper: (Throwable) -> E): AsyncResult<S, E> =
fun <S : Any, E : Any> IO<S>.liftResult(errorMapper: (Throwable) -> E): AsyncResult<S, E> =
this.map { Result.success(it) as Result<S, E> }
.handleError { Result.error(errorMapper(it)) }

fun <S> S.toAsync(): IO<S> = IO.just(this)

fun <T : Any, E : Exception> Result<T, E>.liftAsync(): AsyncResult<T, E> = IO.just(this)
fun <T : Any, E : Any> Result<T, E>.liftAsync(): AsyncResult<T, E> = IO.just(this)
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ internal class AsyncResultInfixExtensionsKtTest {
fun `Successful Result should be thenable`() {
Result.success("Some success value")
.then { Result.success("Some other value") }
.get() shouldBe "Some other value"
.getSuccessUnsafe() shouldBe "Some other value"
}

@Test
fun `given first Result is failure when doing then then it whole should return failure`() {
shouldThrow<RuntimeException> {
Result.error(RuntimeException("Boo"))
.then { Result.success("Some other value") }
.get()
.getSuccessUnsafe()
}
}

Expand All @@ -29,7 +29,7 @@ internal class AsyncResultInfixExtensionsKtTest {
shouldThrow<RuntimeException> {
Result.success("Some value")
.then { Result.error(RuntimeException("Boo")) }
.get()
.getSuccessUnsafe()
}
}

Expand All @@ -39,7 +39,7 @@ internal class AsyncResultInfixExtensionsKtTest {
Result.error(RuntimeException("Boo")).liftAsync()
.then { Result.success("Some other value").liftAsync() }
.unsafeRunSync()
.get()
.getSuccessUnsafe()
}
}

Expand All @@ -49,7 +49,7 @@ internal class AsyncResultInfixExtensionsKtTest {
Result.success("Some value").liftAsync()
.thenSync { Result.error(RuntimeException("Boo")) }
.unsafeRunSync()
.get()
.getSuccessUnsafe()
}
}

Expand All @@ -59,7 +59,7 @@ internal class AsyncResultInfixExtensionsKtTest {
Result.error(RuntimeException("Boo"))
.thenAsync { Result.success("Some other value").liftAsync() }
.unsafeRunSync()
.get()
.getSuccessUnsafe()
}
}

Expand All @@ -68,32 +68,32 @@ internal class AsyncResultInfixExtensionsKtTest {
fun `AsyncResult should be thenable with Result`() {
Result.success("Some success value").liftAsync()
.thenSync { Result.success("Some other value") }
.unsafeRunSync().get() shouldBe "Some other value"
.unsafeRunSync().getSuccessUnsafe() shouldBe "Some other value"
}

@Test
fun `AsyncResult should be thenable with AsyncResult`() {
Result.success("Some success value").liftAsync()
.then { Result.success("Some other value").liftAsync() }
.unsafeRunSync().get() shouldBe "Some other value"
.unsafeRunSync().getSuccessUnsafe() shouldBe "Some other value"
}

@Test
fun `Result should be thenable with AsyncResult`() {
Result.success("Some success value")
.thenAsync { Result.success("Some other value").liftAsync() }
.unsafeRunSync().get() shouldBe "Some other value"
.unsafeRunSync().getSuccessUnsafe() shouldBe "Some other value"
}

@Test
fun `any type should be thenable to Result`() {
val result = "Success" to { Result.success("A") }
result.get() shouldBe "A"
result.getSuccessUnsafe() shouldBe "A"
}

@Test
fun `any type should be thenable to AsyncResult`() {
val result = "Success" toAsyncResult { Result.success("A").liftAsync() }
result.unsafeRunSync().get() shouldBe "A"
result.unsafeRunSync().getSuccessUnsafe() shouldBe "A"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,61 +13,61 @@ typealias MonoResult<S, E> = Mono<Result<S, E>>

typealias Completable<E> = Mono<Result<Unit, E>>

fun <S : Any, E : Exception, S2 : Any> MonoResult<S, E>.mapSuccess(mapper: (S) -> S2): MonoResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> MonoResult<S, E>.mapSuccess(mapper: (S) -> S2): MonoResult<S2, E> =
this.map {
it.map(mapper)
}

fun <S : Any, E : Exception, E2 : java.lang.Exception> MonoResult<S, E>.mapFailure(mapper: (E) -> E2): MonoResult<S, E2> =
fun <S : Any, E : Any, E2 : Any> MonoResult<S, E>.mapFailure(mapper: (E) -> E2): MonoResult<S, E2> =
this.map {
it.mapError(mapper)
}

fun <S : Any, E : Exception, S2 : Any> MonoResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): MonoResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> MonoResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): MonoResult<S2, E> =
this.map {
it.flatMap(mapper)
}

fun <S : Any, E : Exception, S2 : Any> MonoResult<S, E>.flatMapSuccess(mapper: (S) -> MonoResult<S2, E>): MonoResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> MonoResult<S, E>.flatMapSuccess(mapper: (S) -> MonoResult<S2, E>): MonoResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value)
is Failure -> Failure(result1.error).toMono()
}
}

//fun <S : Any, E : Exception, S2 : Any, E2 : Exception> MonoResult<S, E>.flatMap(mapper: (S) -> MonoResult<S2, E2>, errorMapper: (E) -> E2): MonoResult<S2, E2> = TODO()
//fun <S : Any, E : Any, S2 : Any, E2 : Any> MonoResult<S, E>.flatMap(mapper: (S) -> MonoResult<S2, E2>, errorMapper: (E) -> E2): MonoResult<S2, E2> = TODO()
//
//fun <S : Any, E : Exception, S2 : Any, E2 : Exception> MonoResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E2>, errorMapper: (E) -> E2): MonoResult<S2, E2> = TODO()
//fun <S : Any, E : Any, S2 : Any, E2 : Any> MonoResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E2>, errorMapper: (E) -> E2): MonoResult<S2, E2> = TODO()


fun <S : Any, E : Exception, S2 : Any> MonoResult<S, E>.flatMapSuccess(mapper: (S) -> Mono<S2>, errorMapper: (Throwable) -> E): MonoResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> MonoResult<S, E>.flatMapSuccess(mapper: (S) -> Mono<S2>, errorMapper: (Throwable) -> E): MonoResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value).liftResult(errorMapper)
is Failure -> Failure(result1.error).toMono()
}
}

fun <S : Any, E : Exception, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> MonoResult<S2, E>): MonoResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> MonoResult<S2, E>): MonoResult<S2, E> =
when (this) {
is Success -> mapper(value)
is Failure -> Failure(error).toMono()
}

fun <S : Any, E : Exception> S.justMonoResult(): MonoResult<S, E> =
fun <S : Any, E : Any> S.justMonoResult(): MonoResult<S, E> =
Result.of<S, E> { this }
.let { Mono.just(it) }

fun <S : Any, E : Exception> E.failedMonoResult(): MonoResult<S, E> =
fun <S : Any, E : Any> E.failedMonoResult(): MonoResult<S, E> =
Result.error(this)
.let { Mono.just(it) }

fun <S : Any, E : Exception> Result<S, E>.liftMono(): MonoResult<S, E> =
fun <S : Any, E : Any> Result<S, E>.liftMono(): MonoResult<S, E> =
this.toMono()

fun <S : Any, E : Exception> Mono<S>.liftResult(errorMapper: (Throwable) -> E): MonoResult<S, E> =
fun <S : Any, E : Any> Mono<S>.liftResult(errorMapper: (Throwable) -> E): MonoResult<S, E> =
this.map { Result.success(it) as Result<S, E> }
.onErrorResume { Result.error(errorMapper(it)).toMono() }

//fun <V : Any, E : Exception> MonoResult<V, E>.any(predicate: (V) -> Boolean): Boolean = TODO()
//fun <V : Any, E : Any> MonoResult<V, E>.any(predicate: (V) -> Boolean): Boolean = TODO()
Original file line number Diff line number Diff line change
Expand Up @@ -14,74 +14,74 @@ import io.reactivex.Single
typealias SingleResult<T, E> = Single<Result<T, E>>


fun <S : Any, E : Exception, S2 : Any> SingleResult<S, E>.mapSuccess(mapper: (S) -> S2): SingleResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> SingleResult<S, E>.mapSuccess(mapper: (S) -> S2): SingleResult<S2, E> =
this.map {
it.map(mapper)
}

fun <S : Any, E : Exception, E2 : java.lang.Exception> SingleResult<S, E>.mapFailure(mapper: (E) -> E2): SingleResult<S, E2> =
fun <S : Any, E : Any, E2 : Any> SingleResult<S, E>.mapFailure(mapper: (E) -> E2): SingleResult<S, E2> =
this.map {
it.mapError(mapper)
}

fun <S : Any, E : Exception, S2 : Any> SingleResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): SingleResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> SingleResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E>): SingleResult<S2, E> =
this.map {
it.flatMap(mapper)
}

fun <S : Any, E : Exception, S2 : Any> SingleResult<S, E>.flatMapSuccess(mapper: (S) -> SingleResult<S2, E>): SingleResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> SingleResult<S, E>.flatMapSuccess(mapper: (S) -> SingleResult<S2, E>): SingleResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value)
is Failure -> Failure(result1.error).toSingle()
}
}

//fun <S : Any, E : Exception, S2 : Any, E2 : Exception> SingleResult<S, E>.flatMap(mapper: (S) -> SingleResult<S2, E2>, errorMapper: (E) -> E2): SingleResult<S2, E2> = TODO()
//fun <S : Any, E : Any, S2 : Any, E2 : Any> SingleResult<S, E>.flatMap(mapper: (S) -> SingleResult<S2, E2>, errorMapper: (E) -> E2): SingleResult<S2, E2> = TODO()
//
//fun <S : Any, E : Exception, S2 : Any, E2 : Exception> SingleResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E2>, errorMapper: (E) -> E2): SingleResult<S2, E2> = TODO()
//fun <S : Any, E : Any, S2 : Any, E2 : Any> SingleResult<S, E>.flatMapResult(mapper: (S) -> Result<S2, E2>, errorMapper: (E) -> E2): SingleResult<S2, E2> = TODO()


fun <S : Any, E : Exception, S2 : Any> SingleResult<S, E>.flatMapSuccess(mapper: (S) -> Single<S2>, errorMapper: (Throwable) -> E): SingleResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> SingleResult<S, E>.flatMapSuccess(mapper: (S) -> Single<S2>, errorMapper: (Throwable) -> E): SingleResult<S2, E> =
this.flatMap { result1 ->
when (result1) {
is Success -> mapper(result1.value).liftResult(errorMapper)
is Failure -> Failure(result1.error).toSingle()
}
}

fun <S : Any, E : Exception, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> SingleResult<S2, E>): SingleResult<S2, E> =
fun <S : Any, E : Any, S2 : Any> Result<S, E>.liftMap(mapper: (S) -> SingleResult<S2, E>): SingleResult<S2, E> =
when (this) {
is Success -> mapper(value)
is Failure -> Failure(error).toSingle()
}

fun <S : Any, E : Exception> S.justSingleResult(): SingleResult<S, E> =
fun <S : Any, E : Any> S.justSingleResult(): SingleResult<S, E> =
Result.of<S, E> { this }
.let { Single.just(it) }


fun <S : Any, E : Exception> E.failedSingleResult(): SingleResult<S, E> =
fun <S : Any, E : Any> E.failedSingleResult(): SingleResult<S, E> =
Result.error(this)
.let { Single.just(it) }

fun <S : Any, E : Exception> Result<S, E>.liftSingle(): SingleResult<S, E> =
fun <S : Any, E : Any> Result<S, E>.liftSingle(): SingleResult<S, E> =
this.toSingle()

fun <S : Any, E : Exception> Single<S>.liftResult(errorMapper: (Throwable) -> E): SingleResult<S, E> =
fun <S : Any, E : Any> Single<S>.liftResult(errorMapper: (Throwable) -> E): SingleResult<S, E> =
this.map { Result.success(it) as Result<S, E> }
.onErrorReturn { Result.error(errorMapper(it)) }

fun <S> S.toSingle(): Single<S> = Single.just(this)

// TODO test
fun <S : Any, E : Exception> Result<S, E>.toFailure(): Option<E> = this.fold({ None }, { Some(it) })
fun <S : Any, E : Any> Result<S, E>.toFailure(): Option<E> = this.fold({ None }, { Some(it) })

// TODO test
fun <S : Any, E : Exception> SingleResult<S, E>.toFailure(): Single<Option<E>> = this.map { it.toFailure() }
fun <S : Any, E : Any> SingleResult<S, E>.toFailure(): Single<Option<E>> = this.map { it.toFailure() }

// TODO test
fun <S : Any, E : Exception> Result<S, E>.toSuccess(): Option<S> = this.fold({ Some(it) }, { None })
fun <S : Any, E : Any> Result<S, E>.toSuccess(): Option<S> = this.fold({ Some(it) }, { None })

// TODO test
fun <S : Any, E : Exception> SingleResult<S, E>.toSuccess(): Single<Option<S>> = this.map { it.toSuccess() }
fun <S : Any, E : Any> SingleResult<S, E>.toSuccess(): Single<Option<S>> = this.map { it.toSuccess() }
2 changes: 2 additions & 0 deletions result/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ sourceSets {
dependencies {
val kotlinVersion: String by project
val junit: String by project
val arrow: String by project

implementation(kotlin("stdlib", kotlinVersion))
implementation("io.arrow-kt:arrow-core:$arrow")

testImplementation("junit:junit:4.12")

Expand Down
Loading

0 comments on commit 27bf5d6

Please sign in to comment.