-
Notifications
You must be signed in to change notification settings - Fork 78
Open
Labels
Description
Have you considered providing extensions for Kotlin Flows, specifically, Flow<Result<V, E>>? I'm making heavy use of these "flows-of-result" and I have some helpers of my own. However, I feel that it would be much nicer to have binding-style utilities that know about Flow. Here are some examples of helpers that we have in our project (admittedly, some of these can have better names!):
Some variants of Flow's combine operators that know about Flow<Result<V, E>>
/**
* Variant of Kotlin's [combine] that makes it easier to work with flows of [Result].
*
* Use this if [transform] never returns an error. If your transform might return an error, consider using [combineResultWithErr] instead.
*/
fun <T1, T2, E, R> combineResult(
flow: Flow<Result<T1, E>>,
flow2: Flow<Result<T2, E>>,
transform: suspend (T1, T2) -> R
): Flow<Result<R, E>> {
return combine(flow, flow2) { r1, r2 ->
binding {
val s1 = r1.bind()
val s2 = r2.bind()
transform(s1, s2)
}
}
}
/**
* Variant of Kotlin's [combine] that makes it easier to work with flows of [Result].
*
* Use this if [transform] might return an error. If your transform never returns an error, consider using [combineResult] instead.
*/
fun <T1, T2, E, R> combineResultWithErr(
flow: Flow<Result<T1, E>>,
flow2: Flow<Result<T2, E>>,
transform: suspend (T1, T2) -> Result<R, E>
): Flow<Result<R, E>> {
return combine(flow, flow2) { r1, r2 ->
binding {
val s1 = r1.bind()
val s2 = r2.bind()
transform(s1, s2).bind()
}
}
}Variant of andThen that can be applied to a Flow<Result<V, E>>
/**
* Apply [transform] on each element in this [Flow] if the element is an [Ok] otherwise return the
* error as-is into the flow.
*/
fun <V, E, U> Flow<Result<V, E>>.andThen(transform: suspend (V) -> Result<U, E>): Flow<Result<U, E>> {
return map {
when (it) {
is Ok -> transform(it.value)
is Err -> it
}
}
}Variant of flatMapLatest that makes it simpler to work with Result<V, E>
/**
* Like [andThen] but allows the [transform] to return a `Flow<Result>`. This method applies the
* [flatMapLatest] operator allowing you to return a flow from your transform
*/
fun <V, E, U> Flow<Result<V, E>>.andThenFlow(transform: suspend (V) -> Flow<Result<U, E>>): Flow<Result<U, E>> {
return flatMapLatest {
when (it) {
is Ok -> transform(it.value)
is Err -> flowOf(it)
}
}
}As you can see, these utilities work, but they can be improved a lot. Specifically, they can benefit from the equivalent of binding {} (perhaps something like flowBinding {})