Skip to content

Commit 2499d6e

Browse files
[WIP] split read and write SOT types (#560)
* split read and write SOT types * all but 2 tests passing * remove extranous parameterized type on simple store factory * pr review * pr review * Passing except for UpdaterTests (#565) Signed-off-by: Matt Ramotar <mramotar@dropbox.com> * mark mutablestore experimental --------- Signed-off-by: Matt Ramotar <mramotar@dropbox.com> Co-authored-by: Matt Ramotar <mramotar@dropbox.com>
1 parent fbcd34f commit 2499d6e

34 files changed

+299
-599
lines changed

rx2/src/main/kotlin/org/mobilenativefoundation/store/rx2/RxSourceOfTruth.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import org.mobilenativefoundation.store.store5.SourceOfTruth
1919
* @param deleteAll function for deleting all records in the source of truth
2020
*
2121
*/
22-
fun <Key : Any, Local : Any> SourceOfTruth.Companion.ofMaybe(
23-
reader: (Key) -> Maybe<Local>,
24-
writer: (Key, Local) -> Completable,
25-
delete: ((Key) -> Completable)? = null,
26-
deleteAll: (() -> Completable)? = null
27-
): SourceOfTruth<Key, Local> {
22+
fun <Key : Any, Local : Any, Output:Any> SourceOfTruth.Companion.ofMaybe(
23+
reader: (Key) -> Maybe<Output>,
24+
writer: (Key, Local) -> Completable,
25+
delete: ((Key) -> Completable)? = null,
26+
deleteAll: (() -> Completable)? = null
27+
): SourceOfTruth<Key, Local, Output> {
2828
val deleteFun: (suspend (Key) -> Unit)? =
2929
if (delete != null) { key -> delete(key).await() } else null
3030
val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } }
@@ -46,12 +46,12 @@ fun <Key : Any, Local : Any> SourceOfTruth.Companion.ofMaybe(
4646
* @param deleteAll function for deleting all records in the source of truth
4747
*
4848
*/
49-
fun <Key : Any, Local : Any> SourceOfTruth.Companion.ofFlowable(
50-
reader: (Key) -> Flowable<Local>,
49+
fun <Key : Any, Local : Any, Output:Any> SourceOfTruth.Companion.ofFlowable(
50+
reader: (Key) -> Flowable<Output>,
5151
writer: (Key, Local) -> Completable,
5252
delete: ((Key) -> Completable)? = null,
5353
deleteAll: (() -> Completable)? = null
54-
): SourceOfTruth<Key, Local> {
54+
): SourceOfTruth<Key, Local, Output> {
5555
val deleteFun: (suspend (Key) -> Unit)? =
5656
if (delete != null) { key -> delete(key).await() } else null
5757
val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } }

rx2/src/test/kotlin/org/mobilenativefoundation/store/rx2/test/HotRxSingleStoreTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class HotRxSingleStoreTest {
3030
3 to FetcherResult.Data("three-1"),
3131
3 to FetcherResult.Data("three-2")
3232
)
33-
val pipeline = StoreBuilder.from<Int, String, String>(Fetcher.ofResultSingle<Int, String> { fetcher.fetch(it) })
33+
val pipeline = StoreBuilder.from(Fetcher.ofResultSingle<Int, String> { fetcher.fetch(it) })
3434
.scope(testScope)
3535
.build()
3636

rx2/src/test/kotlin/org/mobilenativefoundation/store/rx2/test/RxFlowableStoreTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class RxFlowableStoreTest {
4444
BackpressureStrategy.BUFFER
4545
)
4646
},
47-
sourceOfTruth = SourceOfTruth.ofFlowable<Int, String>(
47+
sourceOfTruth = SourceOfTruth.ofFlowable<Int, String, String>(
4848
reader = {
4949
if (fakeDisk[it] != null)
5050
Flowable.fromCallable { fakeDisk[it]!! }
Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,45 @@
11
package org.mobilenativefoundation.store.store5
22

3-
interface Converter<Network : Any, Output : Any, Local : Any> {
4-
fun fromNetworkToOutput(network: Network): Output?
5-
fun fromOutputToLocal(output: Output): Local?
6-
fun fromLocalToOutput(local: Local): Output?
7-
8-
class Builder<Network : Any, Output : Any, Local : Any> {
9-
10-
private var fromOutputToLocal: ((output: Output) -> Local)? = null
11-
private var fromNetworkToOutput: ((network: Network) -> Output)? = null
12-
private var fromLocalToOutput: ((local: Local) -> Output)? = null
13-
14-
fun build(): Converter<Network, Output, Local> =
15-
RealConverter(fromOutputToLocal, fromNetworkToOutput, fromLocalToOutput)
16-
17-
fun fromOutputToLocal(converter: (output: Output) -> Local): Builder<Network, Output, Local> {
3+
/**
4+
* Converter is a utility interface that can be used to convert a network or output model to a local model.
5+
* Network to Local conversion is needed when the network model is different what you are saving in
6+
* your Source of Truth.
7+
* Output to Local conversion is needed when you are doing local writes in a MutableStore
8+
* @param Network The network data source model type. This is the type used in [Fetcher]
9+
* @param Output The common model type emitted from Store, typically the type returend from your Source of Truth
10+
* @param Local The local data source model type. This is the type used to save to your Source of Truth
11+
*/
12+
interface Converter<Network : Any, Local : Any, Output : Any> {
13+
fun fromNetworkToLocal(network: Network): Local
14+
fun fromOutputToLocal(output: Output): Local
15+
16+
class Builder<Network : Any, Local : Any, Output : Any> {
17+
18+
lateinit var fromOutputToLocal: ((output: Output) -> Local)
19+
lateinit var fromNetworkToLocal: ((network: Network) -> Local)
20+
21+
fun build(): Converter<Network, Local, Output> =
22+
RealConverter(fromOutputToLocal, fromNetworkToLocal)
23+
24+
fun fromOutputToLocal(converter: (output: Output) -> Local): Builder<Network, Local, Output> {
1825
fromOutputToLocal = converter
1926
return this
2027
}
2128

22-
fun fromLocalToOutput(converter: (local: Local) -> Output): Builder<Network, Output, Local> {
23-
fromLocalToOutput = converter
24-
return this
25-
}
26-
27-
fun fromNetworkToOutput(converter: (network: Network) -> Output): Builder<Network, Output, Local> {
28-
fromNetworkToOutput = converter
29+
fun fromNetworkToLocal(converter: (network: Network) -> Local): Builder<Network, Local, Output> {
30+
fromNetworkToLocal = converter
2931
return this
3032
}
3133
}
3234
}
3335

34-
private class RealConverter<Network : Any, Output : Any, Local : Any>(
35-
private val fromOutputToLocal: ((output: Output) -> Local)?,
36-
private val fromNetworkToOutput: ((network: Network) -> Output)?,
37-
private val fromLocalToOutput: ((local: Local) -> Output)?,
38-
) : Converter<Network, Output, Local> {
39-
override fun fromNetworkToOutput(network: Network): Output? =
40-
fromNetworkToOutput?.invoke(network)
41-
42-
override fun fromOutputToLocal(output: Output): Local? =
43-
fromOutputToLocal?.invoke(output)
36+
private class RealConverter<Network : Any, Local : Any, Output : Any>(
37+
private val fromOutputToLocal: ((output: Output) -> Local),
38+
private val fromNetworkToLocal: ((network: Network) -> Local),
39+
) : Converter<Network, Local, Output> {
40+
override fun fromNetworkToLocal(network: Network): Local =
41+
fromNetworkToLocal.invoke(network)
4442

45-
override fun fromLocalToOutput(local: Local): Output? =
46-
fromLocalToOutput?.invoke(local)
43+
override fun fromOutputToLocal(output: Output): Local =
44+
fromOutputToLocal.invoke(output)
4745
}

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/Fetcher.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ interface Fetcher<Key : Any, Network : Any> {
145145
* Use instead of [of] if implementing fallback mechanisms.
146146
* @param name Unique name to enable differentiation of fetchers
147147
*/
148-
fun <Key : Any, Network : Any> ofWithFallback(
148+
fun <Key : Any, Network : Any> withFallback(
149149
name: String,
150150
fallback: Fetcher<Key, Network>,
151151
fetch: suspend (key: Key) -> Network

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/MutableStore.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.mobilenativefoundation.store.store5
22

3+
@ExperimentalStoreApi
34
interface MutableStore<Key : Any, Output : Any> :
45
Read.StreamWithConflictResolution<Key, Output>,
56
Write<Key, Output>,

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/MutableStoreBuilder.kt

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package org.mobilenativefoundation.store.store5
33
import kotlinx.coroutines.CoroutineScope
44
import org.mobilenativefoundation.store.store5.impl.mutableStoreBuilderFromFetcherAndSourceOfTruth
55

6-
interface MutableStoreBuilder<Key : Any, Network : Any, Output : Any, Local : Any> {
6+
interface MutableStoreBuilder<Key : Any, Network : Any, Local : Any, Output : Any> {
77

88
fun <Response : Any> build(
99
updater: Updater<Key, Output, Response>,
@@ -17,24 +17,21 @@ interface MutableStoreBuilder<Key : Any, Network : Any, Output : Any, Local : An
1717
*
1818
* @param scope - scope to use for sharing
1919
*/
20-
fun scope(scope: CoroutineScope): MutableStoreBuilder<Key, Network, Output, Local>
20+
fun scope(scope: CoroutineScope): MutableStoreBuilder<Key, Network, Local, Output>
2121

2222
/**
2323
* controls eviction policy for a store cache, use [MemoryPolicy.MemoryPolicyBuilder] to configure a TTL
2424
* or size based eviction
2525
* Example: MemoryPolicy.builder().setExpireAfterWrite(10.seconds).build()
2626
*/
27-
fun cachePolicy(memoryPolicy: MemoryPolicy<Key, Output>?): MutableStoreBuilder<Key, Network, Output, Local>
27+
fun cachePolicy(memoryPolicy: MemoryPolicy<Key, Output>?): MutableStoreBuilder<Key, Network, Local, Output>
2828

2929
/**
3030
* by default a Store caches in memory with a default policy of max items = 100
3131
*/
32-
fun disableCache(): MutableStoreBuilder<Key, Network, Output, Local>
32+
fun disableCache(): MutableStoreBuilder<Key, Network, Local, Output>
3333

34-
fun converter(converter: Converter<Network, Output, Local>):
35-
MutableStoreBuilder<Key, Network, Output, Local>
36-
37-
fun validator(validator: Validator<Output>): MutableStoreBuilder<Key, Network, Output, Local>
34+
fun validator(validator: Validator<Output>): MutableStoreBuilder<Key, Network, Local, Output, >
3835

3936
companion object {
4037
/**
@@ -43,10 +40,14 @@ interface MutableStoreBuilder<Key : Any, Network : Any, Output : Any, Local : An
4340
* @param fetcher a function for fetching a flow of network records.
4441
* @param sourceOfTruth a [SourceOfTruth] for the store.
4542
*/
46-
fun <Key : Any, Network : Any, Output : Any, Local : Any> from(
43+
fun <Key : Any, Network : Any, Local : Any, Output : Any,> from(
4744
fetcher: Fetcher<Key, Network>,
48-
sourceOfTruth: SourceOfTruth<Key, Local>
49-
): MutableStoreBuilder<Key, Network, Output, Local> =
50-
mutableStoreBuilderFromFetcherAndSourceOfTruth(fetcher = fetcher, sourceOfTruth = sourceOfTruth)
45+
sourceOfTruth: SourceOfTruth<Key, Local, Output>,
46+
converter: Converter<Network, Local, Output>
47+
): MutableStoreBuilder<Key, Network, Local, Output> =
48+
mutableStoreBuilderFromFetcherAndSourceOfTruth(
49+
fetcher = fetcher, sourceOfTruth = sourceOfTruth,
50+
converter = converter
51+
)
5152
}
5253
}

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/SourceOfTruth.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ import kotlin.jvm.JvmName
4646
* transform them to another type when placing them in local storage.
4747
*
4848
*/
49-
interface SourceOfTruth<Key : Any, Local : Any> {
49+
interface SourceOfTruth<Key : Any, Local : Any, Output : Any> {
5050

5151
/**
5252
* Used by [Store] to read records from the source of truth.
5353
*
5454
* @param key The key to read for.
5555
*/
56-
fun reader(key: Key): Flow<Local?>
56+
fun reader(key: Key): Flow<Output?>
5757

5858
/**
5959
* Used by [Store] to write records **coming in from the fetcher (network)** to the source of
@@ -90,12 +90,12 @@ interface SourceOfTruth<Key : Any, Local : Any> {
9090
* @param delete function for deleting records in the source of truth for the given key
9191
* @param deleteAll function for deleting all records in the source of truth
9292
*/
93-
fun <Key : Any, Local : Any> of(
94-
nonFlowReader: suspend (Key) -> Local?,
93+
fun <Key : Any, Local : Any, Output : Any> of(
94+
nonFlowReader: suspend (Key) -> Output?,
9595
writer: suspend (Key, Local) -> Unit,
9696
delete: (suspend (Key) -> Unit)? = null,
9797
deleteAll: (suspend () -> Unit)? = null
98-
): SourceOfTruth<Key, Local> = PersistentNonFlowingSourceOfTruth(
98+
): SourceOfTruth<Key, Local, Output> = PersistentNonFlowingSourceOfTruth(
9999
realReader = nonFlowReader,
100100
realWriter = writer,
101101
realDelete = delete,
@@ -112,12 +112,12 @@ interface SourceOfTruth<Key : Any, Local : Any> {
112112
* @param deleteAll function for deleting all records in the source of truth
113113
*/
114114
@JvmName("ofFlow")
115-
fun <Key : Any, Local : Any> of(
116-
reader: (Key) -> Flow<Local?>,
115+
fun <Key : Any, Local : Any, Output : Any> of(
116+
reader: (Key) -> Flow<Output?>,
117117
writer: suspend (Key, Local) -> Unit,
118118
delete: (suspend (Key) -> Unit)? = null,
119119
deleteAll: (suspend () -> Unit)? = null
120-
): SourceOfTruth<Key, Local> = PersistentSourceOfTruth(
120+
): SourceOfTruth<Key, Local, Output> = PersistentSourceOfTruth(
121121
realReader = reader,
122122
realWriter = writer,
123123
realDelete = delete,

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/StoreBuilder.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.mobilenativefoundation.store.store5.impl.storeBuilderFromFetcherSourc
2727
interface StoreBuilder<Key : Any, Output : Any> {
2828
fun build(): Store<Key, Output>
2929

30-
fun <Network : Any, Local : Any> toMutableStoreBuilder(): MutableStoreBuilder<Key, Network, Output, Local>
30+
fun <Network : Any, Local : Any> toMutableStoreBuilder(converter: Converter<Network, Local, Output>): MutableStoreBuilder<Key, Network, Local, Output>
3131

3232
/**
3333
* A store multicasts same [Output] value to many consumers (Similar to RxJava.share()), by default
@@ -58,9 +58,9 @@ interface StoreBuilder<Key : Any, Output : Any> {
5858
*
5959
* @param fetcher a [Fetcher] flow of network records.
6060
*/
61-
fun <Key : Any, Input : Any, Output : Any> from(
61+
fun <Key : Any, Input : Any> from(
6262
fetcher: Fetcher<Key, Input>,
63-
): StoreBuilder<Key, Output> = storeBuilderFromFetcher(fetcher = fetcher)
63+
): StoreBuilder<Key, Input> = storeBuilderFromFetcher(fetcher = fetcher)
6464

6565
/**
6666
* Creates a new [StoreBuilder] from a [Fetcher] and a [SourceOfTruth].
@@ -70,13 +70,13 @@ interface StoreBuilder<Key : Any, Output : Any> {
7070
*/
7171
fun <Key : Any, Input : Any, Output : Any> from(
7272
fetcher: Fetcher<Key, Input>,
73-
sourceOfTruth: SourceOfTruth<Key, Input>
73+
sourceOfTruth: SourceOfTruth<Key, Input, Output>
7474
): StoreBuilder<Key, Output> =
7575
storeBuilderFromFetcherAndSourceOfTruth(fetcher = fetcher, sourceOfTruth = sourceOfTruth)
7676

77-
fun <Key : Any, Network : Any, Output : Any, Local : Any> from(
77+
fun <Key : Any, Network : Any, Output : Any> from(
7878
fetcher: Fetcher<Key, Network>,
79-
sourceOfTruth: SourceOfTruth<Key, Local>,
79+
sourceOfTruth: SourceOfTruth<Key, Network, Output>,
8080
memoryCache: Cache<Key, Output>,
8181
): StoreBuilder<Key, Output> = storeBuilderFromFetcherSourceOfTruthAndMemoryCache(
8282
fetcher,

store/src/commonMain/kotlin/org/mobilenativefoundation/store/store5/impl/FetcherController.kt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import org.mobilenativefoundation.store.store5.StoreReadResponseOrigin
4040
* fetcher requests receives values dispatched by later requests even if they don't share the
4141
* request.
4242
*/
43+
@Suppress("UNCHECKED_CAST")
4344
internal class FetcherController<Key : Any, Network : Any, Output : Any, Local : Any>(
4445
/**
4546
* The [CoroutineScope] to use when collecting from the fetcher
@@ -55,7 +56,17 @@ internal class FetcherController<Key : Any, Network : Any, Output : Any, Local :
5556
*/
5657
private val sourceOfTruth: SourceOfTruthWithBarrier<Key, Network, Output, Local>?,
5758

58-
private val converter: Converter<Network, Output, Local>? = null
59+
private val converter: Converter<Network, Local, Output> = object :
60+
Converter<Network, Local, Output> {
61+
62+
override fun fromNetworkToLocal(network: Network): Local {
63+
return network as Local
64+
}
65+
66+
override fun fromOutputToLocal(output: Output): Local {
67+
throw IllegalStateException("Not used")
68+
}
69+
}
5970
) {
6071
@Suppress("USELESS_CAST", "UNCHECKED_CAST") // needed for multicaster source
6172
private val fetchers = RefCountedResource(
@@ -94,10 +105,9 @@ internal class FetcherController<Key : Any, Network : Any, Output : Any, Local :
94105
*/
95106
piggybackingDownstream = true,
96107
onEach = { response ->
97-
response.dataOrNull()?.let { network ->
98-
val output = converter?.fromNetworkToOutput(network)
99-
val input = output ?: network
100-
sourceOfTruth?.write(key, input as Output)
108+
response.dataOrNull()?.let { network: Network ->
109+
val local: Local = converter.fromNetworkToLocal(network)
110+
sourceOfTruth?.write(key, local)
101111
}
102112
}
103113
)

0 commit comments

Comments
 (0)