diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a95a12b..a6c7a766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Remove now-unsupported targets: `iosArm32`, `watchosX86`. +### Added + +- Add `Flow.plus` operator, it is an alias to `concatWith` operator. + ## [0.7.3] - Oct 29, 2023 ### Changed diff --git a/README.md b/README.md index 22df1265..63d7f975 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ dependencies { - [`castNullable`](#cast--castnotnull--castnullable--safeCast) - [`chunked`](#buffercount--chunked) - [`safeCast`](#cast--castnotnull--castnullable--safeCast) - - [`concatWith`](#concatwith) + - [`concatWith`](#concatwith--plus) - [`startWith`](#startwith) - [`flatMapFirst`](#flatmapfirst--exhaustmap) - [`exhaustMap`](#flatmapfirst--exhaustmap) @@ -165,6 +165,7 @@ dependencies { - [`throttleTime`](#throttletime) - [`withLatestFrom`](#withlatestfrom) - [`zipWithNext`](#pairwise--zipWithNext) + - [`plus`](#concatwith--plus) #### bufferCount / chunked @@ -211,6 +212,7 @@ bufferCount: [8, 9] to [RxJava concat](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#concat-java.lang.Iterable-) Creates an output `Flow` which sequentially emits all values from the first given `Flow` and then moves on to the next. +Note, `plus` is an alias to `concat`. ```kotlin concat( @@ -523,7 +525,7 @@ safeCast: null ---- -#### concatWith +#### concatWith / plus - Similar to [RxJS concatWith](https://rxjs.dev/api/operators/concatWith) - Similar @@ -535,6 +537,13 @@ Returns a `Flow` that emits the items emitted from the current `Flow`, then the flowOf(1, 2, 3) .concatWith(flowOf(4, 5, 6)) .collect { println("concatWith: $it") } + +println("---") + +val flow1 = flowOf(1, 2, 3) +val flow2 = flowOf(4, 5, 6) + +(flow1 + flow2).collect { println("plus: $it") } ``` Output: @@ -546,6 +555,13 @@ concatWith: 3 concatWith: 4 concatWith: 5 concatWith: 6 +--- +plus: 1 +plus: 2 +plus: 3 +plus: 4 +plus: 5 +plus: 6 ``` ---- diff --git a/api/FlowExt.api b/api/FlowExt.api index 8289218c..b052e84c 100644 --- a/api/FlowExt.api +++ b/api/FlowExt.api @@ -33,6 +33,7 @@ public final class com/hoc081098/flowext/ConcatKt { public static final fun concatWith (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; public static final fun concatWith (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; public static final fun concatWith (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;[Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; + public static final fun plus (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; public static final fun startWith (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Iterable;)Lkotlinx/coroutines/flow/Flow; public static final fun startWith (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow; public static final fun startWith (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow; diff --git a/src/commonMain/kotlin/com/hoc081098/flowext/concat.kt b/src/commonMain/kotlin/com/hoc081098/flowext/concat.kt index 882fab07..52b29b2c 100644 --- a/src/commonMain/kotlin/com/hoc081098/flowext/concat.kt +++ b/src/commonMain/kotlin/com/hoc081098/flowext/concat.kt @@ -267,3 +267,19 @@ public fun Flow.startWith(others: Sequence): Flow = concat(others.a * Returns a [Flow] that emits the items in a specified [Flow] before it begins to emit items emitted by the current [Flow]. */ public fun Flow.startWith(other: Flow): Flow = concat(other, this) + +/** + * This function is an alias to [concatWith] operator. + * + * Returns a [Flow] that emits the items emitted from this [Flow], then the next, one after the other, without interleaving them. + * + * @see concatWith + * + * Example: + * ``` kotlin + * val flow1 = flowOf(1, 2, 3) + * val flow2 = flowOf(4, 5, 6) + * val result = flow1 + flow2 // produces the following emissions 1, 2, 3, 4, 5, 6 + * ``` + */ +public operator fun Flow.plus(other: Flow): Flow = concat(this, other) diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/ConcatTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/ConcatTest.kt index aa8bcb96..3ca11c52 100644 --- a/src/commonTest/kotlin/com/hoc081098/flowext/ConcatTest.kt +++ b/src/commonTest/kotlin/com/hoc081098/flowext/ConcatTest.kt @@ -286,6 +286,63 @@ class ConcatTest : BaseTest() { ), ).test(null, expectation) } + + @Test + fun plusTwoFlow() = runTest { + val flow1 = flowOf(1, 2, 3) + val flow2 = flowOf(4, 5, 6) + + (flow1 + flow2) + .test( + listOf( + Event.Value(1), + Event.Value(2), + Event.Value(3), + Event.Value(4), + Event.Value(5), + Event.Value(6), + Event.Complete, + ), + ) + } + + @Test + fun plusTwoFlow2() = runTest { + (flowOf("a", 2, 3) + flowOf(4, 5, 6)) + .test( + listOf( + Event.Value("a"), + Event.Value(2), + Event.Value(3), + Event.Value(4), + Event.Value(5), + Event.Value(6), + Event.Complete, + ), + ) + } + + @Test + fun testPlus_firstFailureUpstream() = runTest { + val flow = flowOf(1, 2, 3) + val failureFlow = kotlinx.coroutines.flow.flow { throw TestException("Crash!") } + val expectation: suspend (List>) -> Unit = { events -> + val message = assertIs(events.single().errorOrThrow()).message + assertEquals("Crash!", message) + } + + (failureFlow + flow) + .test(null, expectation) + + (failureFlow + flow + flow) + .test(null, expectation) + + (failureFlow + flow + flow + flow) + .test(null, expectation) + + (failureFlow + flow + flow + flow + flow) + .test(null, expectation) + } } private operator fun Iterable.times(times: Int): List = (0 until times).flatMap { this }