Skip to content

Commit

Permalink
Add selectSubscribe for 5-7 properties
Browse files Browse the repository at this point in the history
  • Loading branch information
gpeal committed Oct 24, 2018
1 parent 4047426 commit 6e4022c
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 31 deletions.
123 changes: 123 additions & 0 deletions mvrx/src/main/kotlin/com/airbnb/mvrx/BaseMvRxViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,129 @@ abstract class BaseMvRxViewModel<S : MvRxState>(
.distinctUntilChanged()
.subscribeLifecycle(owner, uniqueOnly) { (a, b, c, d) -> subscriber(a, b, c, d) }

/**
* Subscribe to state changes for five properties.
*/
protected fun <A, B, C, D, E> selectSubscribe(
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
subscriber: (A, B, C, D, E) -> Unit
) = selectSubscribeInternal(null, prop1, prop2, prop3, prop4, prop5, false, subscriber)

@RestrictTo(RestrictTo.Scope.LIBRARY)
fun <A, B, C, D, E> selectSubscribe(
owner: LifecycleOwner,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
uniqueOnly: Boolean = false,
subscriber: (A, B, C, D, E) -> Unit
) = selectSubscribeInternal(owner, prop1, prop2, prop3, prop4, prop5, uniqueOnly, subscriber)

private fun <A, B, C, D, E> selectSubscribeInternal(
owner: LifecycleOwner?,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
uniqueOnly: Boolean,
subscriber: (A, B, C, D, E) -> Unit
) = stateStore.observable
.map { MvRxTuple5(prop1.get(it), prop2.get(it), prop3.get(it), prop4.get(it), prop5.get(it)) }
.distinctUntilChanged()
.subscribeLifecycle(owner, uniqueOnly) { (a, b, c, d, e) -> subscriber(a, b, c, d, e) }

/**
* Subscribe to state changes for six properties.
*/
protected fun <A, B, C, D, E, F> selectSubscribe(
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
subscriber: (A, B, C, D, E, F) -> Unit
) = selectSubscribeInternal(null, prop1, prop2, prop3, prop4, prop5, prop6, false, subscriber)

@RestrictTo(RestrictTo.Scope.LIBRARY)
fun <A, B, C, D, E, F> selectSubscribe(
owner: LifecycleOwner,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
uniqueOnly: Boolean = false,
subscriber: (A, B, C, D, E, F) -> Unit
) = selectSubscribeInternal(owner, prop1, prop2, prop3, prop4, prop5, prop6, uniqueOnly, subscriber)

private fun <A, B, C, D, E, F> selectSubscribeInternal(
owner: LifecycleOwner?,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
uniqueOnly: Boolean,
subscriber: (A, B, C, D, E, F) -> Unit
) = stateStore.observable
.map { MvRxTuple6(prop1.get(it), prop2.get(it), prop3.get(it), prop4.get(it), prop5.get(it), prop6.get(it)) }
.distinctUntilChanged()
.subscribeLifecycle(owner, uniqueOnly) { (a, b, c, d, e, f) -> subscriber(a, b, c, d, e, f) }

/**
* Subscribe to state changes for seven properties.
*/
protected fun <A, B, C, D, E, F, G> selectSubscribe(
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
prop7: KProperty1<S, G>,
subscriber: (A, B, C, D, E, F, G) -> Unit
) = selectSubscribeInternal(null, prop1, prop2, prop3, prop4, prop5, prop6, prop7, false, subscriber)

@RestrictTo(RestrictTo.Scope.LIBRARY)
fun <A, B, C, D, E, F, G> selectSubscribe(
owner: LifecycleOwner,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
prop7: KProperty1<S, G>,
uniqueOnly: Boolean = false,
subscriber: (A, B, C, D, E, F, G) -> Unit
) = selectSubscribeInternal(owner, prop1, prop2, prop3, prop4, prop5, prop6, prop7, uniqueOnly, subscriber)

private fun <A, B, C, D, E, F, G> selectSubscribeInternal(
owner: LifecycleOwner?,
prop1: KProperty1<S, A>,
prop2: KProperty1<S, B>,
prop3: KProperty1<S, C>,
prop4: KProperty1<S, D>,
prop5: KProperty1<S, E>,
prop6: KProperty1<S, F>,
prop7: KProperty1<S, G>,
uniqueOnly: Boolean,
subscriber: (A, B, C, D, E, F, G) -> Unit
) = stateStore.observable
.map { MvRxTuple7(prop1.get(it), prop2.get(it), prop3.get(it), prop4.get(it), prop5.get(it), prop6.get(it), prop7.get(it)) }
.distinctUntilChanged()
.subscribeLifecycle(owner, uniqueOnly) { (a, b, c, d, e, f, g) -> subscriber(a, b, c, d, e, f, g) }

private fun <T> Observable<T>.subscribeLifecycle(
lifecycleOwner: LifecycleOwner? = null,
uniqueOnly: Boolean,
Expand Down
5 changes: 4 additions & 1 deletion mvrx/src/main/kotlin/com/airbnb/mvrx/MvRxTuples.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ package com.airbnb.mvrx
internal data class MvRxTuple1<A>(val a: A)
internal data class MvRxTuple2<A, B>(val a: A, val b: B)
internal data class MvRxTuple3<A, B, C>(val a: A, val b: B, val c: C)
internal data class MvRxTuple4<A, B, C, D>(val a: A, val b: B, val c: C, val d: D)
internal data class MvRxTuple4<A, B, C, D>(val a: A, val b: B, val c: C, val d: D)
internal data class MvRxTuple5<A, B, C, D, E>(val a: A, val b: B, val c: C, val d: D, val e: E)
internal data class MvRxTuple6<A, B, C, D, E, F>(val a: A, val b: B, val c: C, val d: D, val e: E, val f: F)
internal data class MvRxTuple7<A, B, C, D, E, F, G>(val a: A, val b: B, val c: C, val d: D, val e: E, val f: F, val g: G)
38 changes: 19 additions & 19 deletions mvrx/src/main/kotlin/com/airbnb/mvrx/StateContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,37 @@ fun <A : BaseMvRxViewModel<B>, B : MvRxState, C : BaseMvRxViewModel<D>, D : MvRx
) = block(viewModel1.state, viewModel2.state, viewModel3.state)

/**
* Accesses ViewModel state from five ViewModels synchronously and returns the result of the block.
* Accesses ViewModel state from four ViewModels synchronously and returns the result of the block.
*/
fun <
A : BaseMvRxViewModel<B>, B : MvRxState,
C : BaseMvRxViewModel<D>, D : MvRxState,
E : BaseMvRxViewModel<F>, F : MvRxState,
G : BaseMvRxViewModel<H>, H : MvRxState,
I : BaseMvRxViewModel<J>, J : MvRxState,
K
I
> withState(
viewModel1: A,
viewModel2: C,
viewModel3: E,
viewModel4: G,
viewModel5: I,
block: (B, D, F, H, J) -> K
) = block(viewModel1.state, viewModel2.state, viewModel3.state, viewModel4.state, viewModel5.state)
block: (B, D, F, H) -> I
) = block(viewModel1.state, viewModel2.state, viewModel3.state, viewModel4.state)

/**
* Accesses ViewModel state from four ViewModels synchronously and returns the result of the block.
* Accesses ViewModel state from five ViewModels synchronously and returns the result of the block.
*/
fun <
A : BaseMvRxViewModel<B>, B : MvRxState,
C : BaseMvRxViewModel<D>, D : MvRxState,
E : BaseMvRxViewModel<F>, F : MvRxState,
G : BaseMvRxViewModel<H>, H : MvRxState,
I
> withState(
viewModel1: A,
viewModel2: C,
viewModel3: E,
viewModel4: G,
block: (B, D, F, H) -> I
) = block(viewModel1.state, viewModel2.state, viewModel3.state, viewModel4.state)
A : BaseMvRxViewModel<B>, B : MvRxState,
C : BaseMvRxViewModel<D>, D : MvRxState,
E : BaseMvRxViewModel<F>, F : MvRxState,
G : BaseMvRxViewModel<H>, H : MvRxState,
I : BaseMvRxViewModel<J>, J : MvRxState,
K
> withState(
viewModel1: A,
viewModel2: C,
viewModel3: E,
viewModel4: G,
viewModel5: I,
block: (B, D, F, H, J) -> K
) = block(viewModel1.state, viewModel2.state, viewModel3.state, viewModel4.state, viewModel5.state)
113 changes: 102 additions & 11 deletions mvrx/src/test/kotlin/com/airbnb/mvrx/ViewModelSubscriberTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test

data class ViewModelTestState(val foo: Int = 0, val bar: Int = 0, val bam: Int = 0, val list: List<Int> = emptyList(), val async: Async<String> = Uninitialized) : MvRxState
data class ViewModelTestState(
val foo: Int = 0,
val bar: Int = 0,
val bam: Int = 0,
val list: List<Int> = emptyList(),
val async: Async<String> = Uninitialized,
val prop6: Int = 0,
val prop7: Int = 0
) : MvRxState

class ViewModelTestViewModel(initialState: ViewModelTestState) : TestMvRxViewModel<ViewModelTestState>(initialState) {

var subscribeCallCount = 0
Expand Down Expand Up @@ -207,10 +216,10 @@ class ViewModelSubscriberTest : BaseTest() {
fun testSelectSubscribe3External() {
var callCount = 0
viewModel.selectSubscribe(
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam
) { _, _, _ -> callCount++ }
assertEquals(1, callCount)
viewModel.setFoo(1)
Expand All @@ -225,11 +234,11 @@ class ViewModelSubscriberTest : BaseTest() {
fun testSelectSubscribe4External() {
var callCount = 0
viewModel.selectSubscribe(
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam,
ViewModelTestState::list
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam,
ViewModelTestState::list
) { _, _, _, _ -> callCount++ }
assertEquals(1, callCount)
viewModel.setFoo(1)
Expand All @@ -238,8 +247,90 @@ class ViewModelSubscriberTest : BaseTest() {
assertEquals(3, callCount)
viewModel.setBam(2)
assertEquals(4, callCount)
viewModel.set{ copy(list = listOf(1, 2, 3)) }
viewModel.set { copy(list = listOf(1, 2, 3)) }
assertEquals(5, callCount)
}


@Test
fun testSelectSubscribe5External() {
var callCount = 0
viewModel.selectSubscribe(
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam,
ViewModelTestState::list,
ViewModelTestState::async
) { _, _, _, _, _ -> callCount++ }
assertEquals(1, callCount)
viewModel.setFoo(1)
assertEquals(2, callCount)
viewModel.setBar(2)
assertEquals(3, callCount)
viewModel.setBam(2)
assertEquals(4, callCount)
viewModel.set { copy(list = listOf(1, 2, 3)) }
assertEquals(5, callCount)
viewModel.set { copy(async = Loading()) }
assertEquals(6, callCount)
}

@Test
fun testSelectSubscribe6External() {
var callCount = 0
viewModel.selectSubscribe(
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam,
ViewModelTestState::list,
ViewModelTestState::async,
ViewModelTestState::prop6
) { _, _, _, _, _, _ -> callCount++ }
assertEquals(1, callCount)
viewModel.setFoo(1)
assertEquals(2, callCount)
viewModel.setBar(2)
assertEquals(3, callCount)
viewModel.setBam(2)
assertEquals(4, callCount)
viewModel.set { copy(list = listOf(1, 2, 3)) }
assertEquals(5, callCount)
viewModel.set { copy(async = Loading()) }
assertEquals(6, callCount)
viewModel.set { copy(prop6 = 1) }
assertEquals(7, callCount)
}

@Test
fun testSelectSubscribe7External() {
var callCount = 0
viewModel.selectSubscribe(
owner,
ViewModelTestState::foo,
ViewModelTestState::bar,
ViewModelTestState::bam,
ViewModelTestState::list,
ViewModelTestState::async,
ViewModelTestState::prop6,
ViewModelTestState::prop7
) { _, _, _, _, _, _, _ -> callCount++ }
assertEquals(1, callCount)
viewModel.setFoo(1)
assertEquals(2, callCount)
viewModel.setBar(2)
assertEquals(3, callCount)
viewModel.setBam(2)
assertEquals(4, callCount)
viewModel.set { copy(list = listOf(1, 2, 3)) }
assertEquals(5, callCount)
viewModel.set { copy(async = Loading()) }
assertEquals(6, callCount)
viewModel.set { copy(prop6 = 1) }
assertEquals(7, callCount)
viewModel.set { copy(prop7 = 1) }
assertEquals(8, callCount)
}

@Test
Expand Down

0 comments on commit 6e4022c

Please sign in to comment.