diff --git a/.travis.yml b/.travis.yml index cecf185f0..5d6ef9087 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ android: licenses: - android-sdk-license-.+ script: -- "./gradlew check --stacktrace" +- "./gradlew clean cleanBuildCache check --stacktrace" after_success: - tools/release/deploy_snapshot.sh - bash <(curl -s https://codecov.io/bash) diff --git a/README.md b/README.md index 47fc8bca8..1b83594f7 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ Let's start by looking at what a fully configured Store looks like. We will then ```kotlin StoreBuilder .from( - fetcher = nonFlowValueFetcher { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, - sourceOfTruth = SourceOfTruth.from( + fetcher = Fetcher.of { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, + sourceOfTruth = SourceOfTruth.of( reader = db.postDao()::loadPosts, writer = db.postDao()::insertPosts, delete = db.postDao()::clearFeed, @@ -81,7 +81,7 @@ You create a Store using a builder. The only requirement is to include a `Fetche ```kotlin val store = StoreBuilder - .from(valueFetcher { articleId -> api.getArticle(articleId) }) // api returns Flow
+ .from(Fetcher.ofFlow { articleId -> api.getArticle(articleId) }) // api returns Flow
.build() ``` @@ -186,8 +186,8 @@ allows you to create offline first applications that can be used without an acti ```kotlin StoreBuilder .from( - fetcher = nonFlowValueFetcher { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, - sourceOfTruth = SourceOfTruth.from( + fetcher = Fetcher.of { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, + sourceOfTruth = SourceOfTruth.of( reader = db.postDao()::loadPosts, writer = db.postDao()::insertPosts, delete = db.postDao()::clearFeed, @@ -215,8 +215,8 @@ You can configure in-memory cache with the `MemoryPolicy`: ```kotlin StoreBuilder .from( - fetcher = nonFlowValueFetcher { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, - sourceOfTruth = SourceOfTruth.from( + fetcher = Fetcher.of { api.fetchSubreddit(it, "10").data.children.map(::toPosts) }, + sourceOfTruth = SourceOfTruth.of( reader = db.postDao()::loadPosts, writer = db.postDao()::insertPosts, delete = db.postDao()::clearFeed, @@ -244,8 +244,10 @@ You can delete a specific entry by key from a store, or clear all entries in a s ```kotlin val store = StoreBuilder - .from(nonFlowValueFetcher { api.fetchData(key) }) - .build() + .from( + fetcher = Fetcher.of { key: String -> + api.fetchData(key) + }).build() ``` The following will clear the entry associated with the key from the in-memory cache: @@ -267,8 +269,8 @@ When store has a sourceOfTruth, you'll need to provide the `delete` and `deleteA ```kotlin StoreBuilder .from( - fetcher = nonFlowValueFetcher { api.fetchData(key) }, - sourceOfTruth = SourceOfTruth.from( + fetcher = Fetcher.of { api.fetchData(key) }, + sourceOfTruth = SourceOfTruth.of( reader = dao::loadData, writer = dao::writeData, delete = dao::clearDataByKey, diff --git a/app/src/main/java/com/dropbox/android/sample/Graph.kt b/app/src/main/java/com/dropbox/android/sample/Graph.kt index a46c1aa56..5be52e428 100644 --- a/app/src/main/java/com/dropbox/android/sample/Graph.kt +++ b/app/src/main/java/com/dropbox/android/sample/Graph.kt @@ -11,13 +11,13 @@ import com.dropbox.android.external.fs3.FileSystemPersister import com.dropbox.android.external.fs3.PathResolver import com.dropbox.android.external.fs3.SourcePersisterFactory import com.dropbox.android.external.fs3.filesystem.FileSystemFactory +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.MemoryPolicy import com.dropbox.android.external.store4.Persister import com.dropbox.android.external.store4.Store import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.legacy.BarCode -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.squareup.moshi.Moshi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -46,10 +46,10 @@ object Graph { val db = provideRoom(context) return StoreBuilder .from( - nonFlowValueFetcher { key: String -> + Fetcher.of { key: String -> provideRetrofit().fetchSubreddit(key, 10).data.children.map(::toPosts) }, - sourceOfTruth = SourceOfTruth.from( + sourceOfTruth = SourceOfTruth.of( reader = db.postDao()::loadPosts, writer = db.postDao()::insertPosts, delete = db.postDao()::clearFeedBySubredditName, @@ -63,11 +63,11 @@ object Graph { val db = provideRoom(context) return StoreBuilder .from, List, List>( - nonFlowValueFetcher { (query, config) -> + Fetcher.of { (query, config) -> provideRetrofit().fetchSubreddit(query, config.limit) .data.children.map(::toPosts) }, - sourceOfTruth = SourceOfTruth.from( + sourceOfTruth = SourceOfTruth.of( reader = { (query, _) -> db.postDao().loadPosts(query) }, writer = { (query, _), posts -> db.postDao().insertPosts(query, posts) }, delete = { (query, _) -> db.postDao().clearFeedBySubredditName(query) }, @@ -99,12 +99,12 @@ object Graph { val adapter = moshi.adapter(RedditConfig::class.java) return StoreBuilder .from( - nonFlowValueFetcher { + Fetcher.of { delay(500) RedditConfig(10) }, - sourceOfTruth = SourceOfTruth.fromNonFlow( - reader = { + sourceOfTruth = SourceOfTruth.of( + nonFlowReader = { runCatching { val source = fileSystemPersister.read(Unit) source?.let { adapter.fromJson(it) } diff --git a/app/src/main/java/com/dropbox/android/sample/ui/stream/StreamFragment.kt b/app/src/main/java/com/dropbox/android/sample/ui/stream/StreamFragment.kt index f882c67f9..686577c87 100644 --- a/app/src/main/java/com/dropbox/android/sample/ui/stream/StreamFragment.kt +++ b/app/src/main/java/com/dropbox/android/sample/ui/stream/StreamFragment.kt @@ -5,12 +5,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.MemoryPolicy import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.fresh import com.dropbox.android.external.store4.get -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.sample.R import kotlinx.android.synthetic.main.fragment_stream.* import kotlinx.coroutines.CoroutineScope @@ -51,7 +51,7 @@ class StreamFragment : Fragment(), CoroutineScope { var counter = 0 val store = StoreBuilder - .from(nonFlowValueFetcher { key: Int -> + .from(Fetcher.of { key: Int -> (key * 1000 + counter++).also { delay(1_000) } }) .cachePolicy( diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 5e6504ba9..5181e98a9 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -7,6 +7,7 @@ ext.versions = [ ktlint : '0.36.0', // Plugins + androidGradlePlugin : '4.0.0', androidGradlePlugin : '4.0.0-beta05', dokkaGradlePlugin : '0.10.0', ktlintGradle : '9.1.1', diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b37f1b909..c4e242461 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-milestone-1-bin.zip diff --git a/store-rx2/api/store-rx2.api b/store-rx2/api/store-rx2.api index 194e803a4..0efd30d54 100644 --- a/store-rx2/api/store-rx2.api +++ b/store-rx2/api/store-rx2.api @@ -1,15 +1,15 @@ public final class com/dropbox/store/rx2/RxFetcherKt { - public static final fun flowableFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun flowableValueFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun singleFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun singleValueFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; + public static final fun ofFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofResultFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofResultSingle (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofSingle (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; } public final class com/dropbox/store/rx2/RxSourceOfTruthKt { - public static final fun fromFlowable (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun fromFlowable$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static final fun fromMaybe (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun fromMaybe$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static final fun ofFlowable (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun ofFlowable$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static final fun ofMaybe (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun ofMaybe$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; } public final class com/dropbox/store/rx2/RxStoreBuilderKt { diff --git a/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxFetcher.kt b/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxFetcher.kt index 46a9d1358..f264e11cc 100644 --- a/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxFetcher.kt +++ b/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxFetcher.kt @@ -3,7 +3,6 @@ package com.dropbox.store.rx2 import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.Store -import com.dropbox.android.external.store4.valueFetcher import io.reactivex.Flowable import io.reactivex.Single import kotlinx.coroutines.reactive.asFlow @@ -19,9 +18,9 @@ import kotlinx.coroutines.reactive.asFlow * * @param flowableFactory a factory for a [Flowable] source of network records. */ -fun flowableFetcher( +fun Fetcher.Companion.ofResultFlowable( flowableFactory: (key: Key) -> Flowable> -): Fetcher = { key: Key -> flowableFactory(key).asFlow() } +): Fetcher = ofResultFlow { key: Key -> flowableFactory(key).asFlow() } /** * "Creates" a [Fetcher] from a [singleFactory]. @@ -34,9 +33,9 @@ fun flowableFetcher( * * @param singleFactory a factory for a [Single] source of network records. */ -fun singleFetcher( +fun Fetcher.Companion.ofResultSingle( singleFactory: (key: Key) -> Single> -): Fetcher = { key: Key -> singleFactory(key).toFlowable().asFlow() } +): Fetcher = ofResultFlowable { key: Key -> singleFactory(key).toFlowable() } /** * "Creates" a [Fetcher] from a [flowableFactory] and translate the results to a [FetcherResult]. @@ -50,9 +49,9 @@ fun singleFetcher( * * @param flowFactory a factory for a [Flowable] source of network records. */ -fun flowableValueFetcher( +fun Fetcher.Companion.ofFlowable( flowableFactory: (key: Key) -> Flowable -): Fetcher = valueFetcher { key: Key -> flowableFactory(key).asFlow() } +): Fetcher = ofFlow { key: Key -> flowableFactory(key).asFlow() } /** * Creates a new [Fetcher] from a [singleFactory] and translate the results to a [FetcherResult]. @@ -66,6 +65,6 @@ fun flowableValueFetcher( * * @param singleFactory a factory for a [Single] source of network records. */ -fun singleValueFetcher( +fun Fetcher.Companion.ofSingle( singleFactory: (key: Key) -> Single -): Fetcher = flowableValueFetcher { key: Key -> singleFactory(key).toFlowable() } +): Fetcher = ofFlowable { key: Key -> singleFactory(key).toFlowable() } diff --git a/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxSourceOfTruth.kt b/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxSourceOfTruth.kt index bcdb0eb39..c4983f631 100644 --- a/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxSourceOfTruth.kt +++ b/store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxSourceOfTruth.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.rx2.await * @param deleteAll function for deleting all records in the source of truth * */ -fun SourceOfTruth.Companion.fromMaybe( +fun SourceOfTruth.Companion.ofMaybe( reader: (Key) -> Maybe, writer: (Key, Input) -> Completable, delete: ((Key) -> Completable)? = null, @@ -26,8 +26,8 @@ fun SourceOfTruth.Companion.fromMaybe( val deleteFun: (suspend (Key) -> Unit)? = if (delete != null) { key -> delete(key).await() } else null val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } } - return fromNonFlow( - reader = { key -> reader.invoke(key).await() }, + return of( + nonFlowReader = { key -> reader.invoke(key).await() }, writer = { key, output -> writer.invoke(key, output).await() }, delete = deleteFun, deleteAll = deleteAllFun @@ -44,7 +44,7 @@ fun SourceOfTruth.Companion.fromMaybe( * @param deleteAll function for deleting all records in the source of truth * */ -fun SourceOfTruth.Companion.fromFlowable( +fun SourceOfTruth.Companion.ofFlowable( reader: (Key) -> Flowable, writer: (Key, Input) -> Completable, delete: ((Key) -> Completable)? = null, @@ -53,7 +53,7 @@ fun SourceOfTruth.Companion.fromFlowable( val deleteFun: (suspend (Key) -> Unit)? = if (delete != null) { key -> delete(key).await() } else null val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } } - return from( + return of( reader = { key -> reader.invoke(key).asFlow() }, writer = { key, output -> writer.invoke(key, output).await() }, delete = deleteFun, diff --git a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/HotRxSingleStoreTest.kt b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/HotRxSingleStoreTest.kt index f0a48948a..895fca727 100644 --- a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/HotRxSingleStoreTest.kt +++ b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/HotRxSingleStoreTest.kt @@ -6,7 +6,7 @@ import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.store.rx2.singleFetcher +import com.dropbox.store.rx2.ofResultSingle import com.google.common.truth.Truth.assertThat import io.reactivex.Single import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -30,7 +30,7 @@ class HotRxSingleStoreTest { 3 to FetcherResult.Data("three-1"), 3 to FetcherResult.Data("three-2") ) - val pipeline = StoreBuilder.from(singleFetcher { fetcher.fetch(it) }) + val pipeline = StoreBuilder.from(Fetcher.ofResultSingle { fetcher.fetch(it) }) .scope(testScope) .build() diff --git a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxFlowableStoreTest.kt b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxFlowableStoreTest.kt index ccb763b28..15274340d 100644 --- a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxFlowableStoreTest.kt +++ b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxFlowableStoreTest.kt @@ -1,14 +1,15 @@ package com.dropbox.store.rx2.test +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.store.rx2.flowableFetcher -import com.dropbox.store.rx2.fromFlowable import com.dropbox.store.rx2.observe +import com.dropbox.store.rx2.ofFlowable +import com.dropbox.store.rx2.ofResultFlowable import io.reactivex.BackpressureStrategy import io.reactivex.Completable import io.reactivex.Flowable @@ -30,7 +31,7 @@ class RxFlowableStoreTest { private val fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - flowableFetcher { + Fetcher.ofResultFlowable { Flowable.create({ emitter -> emitter.onNext( FetcherResult.Data("$it ${atomicInteger.incrementAndGet()} occurrence") @@ -41,7 +42,7 @@ class RxFlowableStoreTest { emitter.onComplete() }, BackpressureStrategy.LATEST) }, - sourceOfTruth = SourceOfTruth.fromFlowable( + sourceOfTruth = SourceOfTruth.ofFlowable( reader = { if (fakeDisk[it] != null) Flowable.fromCallable { fakeDisk[it]!! } @@ -56,50 +57,50 @@ class RxFlowableStoreTest { @Test fun simpleTest() { - var testSubscriber = TestSubscriber>() + val testSubscriber1 = TestSubscriber>() store.observe(StoreRequest.fresh(3)) .subscribeOn(testScheduler) - .subscribe(testSubscriber) + .subscribe(testSubscriber1) testScheduler.triggerActions() - testSubscriber + testSubscriber1 .awaitCount(3) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 1 occurrence", ResponseOrigin.Fetcher), StoreResponse.Data("3 2 occurrence", ResponseOrigin.Fetcher) ) - testSubscriber = TestSubscriber>() + val testSubscriber2 = TestSubscriber>() store.observe(StoreRequest.cached(3, false)) .subscribeOn(testScheduler) - .subscribe(testSubscriber) + .subscribe(testSubscriber2) testScheduler.triggerActions() - testSubscriber + testSubscriber2 .awaitCount(2) .assertValues( StoreResponse.Data("3 2 occurrence", ResponseOrigin.Cache), StoreResponse.Data("3 2 occurrence", ResponseOrigin.SourceOfTruth) ) - testSubscriber = TestSubscriber>() + val testSubscriber3 = TestSubscriber>() store.observe(StoreRequest.fresh(3)) .subscribeOn(testScheduler) - .subscribe(testSubscriber) + .subscribe(testSubscriber3) testScheduler.triggerActions() - testSubscriber + testSubscriber3 .awaitCount(3) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 3 occurrence", ResponseOrigin.Fetcher), StoreResponse.Data("3 4 occurrence", ResponseOrigin.Fetcher) ) - testSubscriber = TestSubscriber>() + val testSubscriber4 = TestSubscriber>() store.observe(StoreRequest.cached(3, false)) .subscribeOn(testScheduler) - .subscribe(testSubscriber) + .subscribe(testSubscriber4) testScheduler.triggerActions() - testSubscriber + testSubscriber4 .awaitCount(2) .assertValues( StoreResponse.Data("3 4 occurrence", ResponseOrigin.Cache), diff --git a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreExtensionsTest.kt b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreExtensionsTest.kt index c70731205..e99d5f94e 100644 --- a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreExtensionsTest.kt +++ b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreExtensionsTest.kt @@ -1,13 +1,14 @@ package com.dropbox.store.rx2.test import com.dropbox.android.external.store4.ExperimentalStoreApi +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.store.rx2.freshSingle -import com.dropbox.store.rx2.fromMaybe +import com.dropbox.store.rx2.ofMaybe import com.dropbox.store.rx2.getSingle -import com.dropbox.store.rx2.singleFetcher +import com.dropbox.store.rx2.ofResultSingle import com.dropbox.store.rx2.withScheduler import io.reactivex.Completable import io.reactivex.Maybe @@ -29,10 +30,10 @@ class RxSingleStoreExtensionsTest { private var fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - fetcher = singleFetcher { + fetcher = Fetcher.ofResultSingle { Single.fromCallable { FetcherResult.Data("$it ${atomicInteger.incrementAndGet()}") } }, - sourceOfTruth = SourceOfTruth.fromMaybe( + sourceOfTruth = SourceOfTruth.ofMaybe( reader = { Maybe.fromCallable { fakeDisk[it] } }, writer = { key, value -> Completable.fromAction { fakeDisk[key] = value } diff --git a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreTest.kt b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreTest.kt index 171fb2f23..4c62d7c41 100644 --- a/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreTest.kt +++ b/store-rx2/src/test/kotlin/com/dropbox/store/rx2/test/RxSingleStoreTest.kt @@ -1,17 +1,18 @@ package com.dropbox.store.rx2.test import com.dropbox.android.external.store4.ExperimentalStoreApi +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse import com.dropbox.android.external.store4.SourceOfTruth -import com.dropbox.store.rx2.fromMaybe +import com.dropbox.store.rx2.ofMaybe import com.dropbox.store.rx2.observe import com.dropbox.store.rx2.observeClear import com.dropbox.store.rx2.observeClearAll -import com.dropbox.store.rx2.singleFetcher +import com.dropbox.store.rx2.ofResultSingle import com.dropbox.store.rx2.withScheduler import io.reactivex.Completable import io.reactivex.Maybe @@ -33,10 +34,10 @@ class RxSingleStoreTest { private var fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - fetcher = singleFetcher { + fetcher = Fetcher.ofResultSingle { Single.fromCallable { FetcherResult.Data("$it ${atomicInteger.incrementAndGet()}") } }, - sourceOfTruth = SourceOfTruth.fromMaybe( + sourceOfTruth = SourceOfTruth.ofMaybe( reader = { Maybe.fromCallable { fakeDisk[it] } }, writer = { key, value -> Completable.fromAction { fakeDisk[key] = value } @@ -58,7 +59,7 @@ class RxSingleStoreTest { .test() .awaitCount(2) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 1", ResponseOrigin.Fetcher) ) @@ -74,7 +75,7 @@ class RxSingleStoreTest { .test() .awaitCount(2) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 2", ResponseOrigin.Fetcher) ) @@ -97,7 +98,7 @@ class RxSingleStoreTest { .test() .awaitCount(2) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 1", ResponseOrigin.Fetcher) ) } @@ -113,7 +114,7 @@ class RxSingleStoreTest { .test() .awaitCount(2) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("3 1", ResponseOrigin.Fetcher) ) @@ -121,7 +122,7 @@ class RxSingleStoreTest { .test() .awaitCount(2) .assertValues( - StoreResponse.Loading(ResponseOrigin.Fetcher), + StoreResponse.Loading(ResponseOrigin.Fetcher), StoreResponse.Data("4 2", ResponseOrigin.Fetcher) ) } diff --git a/store-rx3/api/store-rx3.api b/store-rx3/api/store-rx3.api index a6e6a2ca6..ea0e93542 100644 --- a/store-rx3/api/store-rx3.api +++ b/store-rx3/api/store-rx3.api @@ -1,15 +1,15 @@ public final class com/dropbox/store/rx3/RxFetcherKt { - public static final fun flowableFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun flowableValueFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun singleFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun singleValueFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; + public static final fun ofFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofResultFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofResultSingle (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public static final fun ofSingle (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; } public final class com/dropbox/store/rx3/RxSourceOfTruthKt { - public static final fun fromFlowable (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun fromFlowable$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static final fun fromMaybe (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun fromMaybe$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static final fun ofFlowable (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun ofFlowable$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static final fun ofMaybe (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun ofMaybe$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; } public final class com/dropbox/store/rx3/RxStoreBuilderKt { diff --git a/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxFetcher.kt b/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxFetcher.kt index a7e754026..38087c60a 100644 --- a/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxFetcher.kt +++ b/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxFetcher.kt @@ -3,7 +3,6 @@ package com.dropbox.store.rx3 import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.Store -import com.dropbox.android.external.store4.valueFetcher import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Single import kotlinx.coroutines.reactive.asFlow @@ -19,9 +18,9 @@ import kotlinx.coroutines.reactive.asFlow * * @param flowableFactory a factory for a [Flowable] source of network records. */ -fun flowableFetcher( +fun Fetcher.Companion.ofResultFlowable( flowableFactory: (key: Key) -> Flowable> -): Fetcher = { key: Key -> flowableFactory(key).asFlow() } +): Fetcher = ofResultFlow { key: Key -> flowableFactory(key).asFlow() } /** * "Creates" a [Fetcher] from a [singleFactory]. @@ -34,9 +33,9 @@ fun flowableFetcher( * * @param singleFactory a factory for a [Single] source of network records. */ -fun singleFetcher( +fun Fetcher.Companion.ofResultSingle( singleFactory: (key: Key) -> Single> -): Fetcher = { key: Key -> singleFactory(key).toFlowable().asFlow() } +): Fetcher = ofResultFlowable { key: Key -> singleFactory(key).toFlowable() } /** * "Creates" a [Fetcher] from a [flowableFactory] and translate the results to a [FetcherResult]. @@ -50,9 +49,9 @@ fun singleFetcher( * * @param flowFactory a factory for a [Flowable] source of network records. */ -fun flowableValueFetcher( +fun Fetcher.Companion.ofFlowable( flowableFactory: (key: Key) -> Flowable -): Fetcher = valueFetcher { key: Key -> flowableFactory(key).asFlow() } +): Fetcher = ofFlow { key: Key -> flowableFactory(key).asFlow() } /** * Creates a new [Fetcher] from a [singleFactory] and translate the results to a [FetcherResult]. @@ -66,6 +65,6 @@ fun flowableValueFetcher( * * @param singleFactory a factory for a [Single] source of network records. */ -fun singleValueFetcher( +fun Fetcher.Companion.ofSingle( singleFactory: (key: Key) -> Single -): Fetcher = flowableValueFetcher { key: Key -> singleFactory(key).toFlowable() } +): Fetcher = ofFlowable { key: Key -> singleFactory(key).toFlowable() } diff --git a/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxSourceOfTruth.kt b/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxSourceOfTruth.kt index 262076a6b..36f5c09be 100644 --- a/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxSourceOfTruth.kt +++ b/store-rx3/src/main/kotlin/com/dropbox/store/rx3/RxSourceOfTruth.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.rx3.await * @param deleteAll function for deleting all records in the source of truth * */ -fun SourceOfTruth.Companion.fromMaybe( +fun SourceOfTruth.Companion.ofMaybe( reader: (Key) -> Maybe, writer: (Key, Input) -> Completable, delete: ((Key) -> Completable)? = null, @@ -26,8 +26,8 @@ fun SourceOfTruth.Companion.fromMaybe( val deleteFun: (suspend (Key) -> Unit)? = if (delete != null) { key -> delete(key).await() } else null val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } } - return fromNonFlow( - reader = { key -> reader.invoke(key).await() }, + return of( + nonFlowReader = { key -> reader.invoke(key).await() }, writer = { key, output -> writer.invoke(key, output).await() }, delete = deleteFun, deleteAll = deleteAllFun @@ -44,7 +44,7 @@ fun SourceOfTruth.Companion.fromMaybe( * @param deleteAll function for deleting all records in the source of truth * */ -fun SourceOfTruth.Companion.fromFlowable( +fun SourceOfTruth.Companion.ofFlowable( reader: (Key) -> Flowable, writer: (Key, Input) -> Completable, delete: ((Key) -> Completable)? = null, @@ -53,7 +53,7 @@ fun SourceOfTruth.Companion.fromFlowable( val deleteFun: (suspend (Key) -> Unit)? = if (delete != null) { key -> delete(key).await() } else null val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } } - return from( + return of( reader = { key -> reader.invoke(key).asFlow() }, writer = { key, output -> writer.invoke(key, output).await() }, delete = deleteFun, diff --git a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/HotRxSingleStoreTest.kt b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/HotRxSingleStoreTest.kt index 9bbbc64a7..a42a403b4 100644 --- a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/HotRxSingleStoreTest.kt +++ b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/HotRxSingleStoreTest.kt @@ -1,11 +1,12 @@ package com.dropbox.store.rx3.test +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.store.rx3.singleFetcher +import com.dropbox.store.rx3.ofResultSingle import com.google.common.truth.Truth.assertThat import io.reactivex.rxjava3.core.Single import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -30,9 +31,10 @@ class HotRxSingleStoreTest { 3 to FetcherResult.Data("three-1"), 3 to FetcherResult.Data("three-2") ) - val pipeline = StoreBuilder.from(singleFetcher { fetcher.fetch(it) }) - .scope(testScope) - .build() + val pipeline = + StoreBuilder.from(Fetcher.ofResultSingle { fetcher.fetch(it) }) + .scope(testScope) + .build() assertThat(pipeline.stream(StoreRequest.cached(3, refresh = false))) .emitsExactly( diff --git a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxFlowableStoreTest.kt b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxFlowableStoreTest.kt index e901ec020..640473703 100644 --- a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxFlowableStoreTest.kt +++ b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxFlowableStoreTest.kt @@ -1,14 +1,15 @@ package com.dropbox.store.rx3.test +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.store.rx3.flowableFetcher -import com.dropbox.store.rx3.fromFlowable +import com.dropbox.store.rx3.ofFlowable import com.dropbox.store.rx3.observe +import com.dropbox.store.rx3.ofResultFlowable import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable @@ -30,7 +31,7 @@ class RxFlowableStoreTest { private val fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - flowableFetcher { + Fetcher.ofResultFlowable { Flowable.create({ emitter -> emitter.onNext( FetcherResult.Data("$it ${atomicInteger.incrementAndGet()} occurrence") @@ -41,7 +42,7 @@ class RxFlowableStoreTest { emitter.onComplete() }, BackpressureStrategy.LATEST) }, - sourceOfTruth = SourceOfTruth.fromFlowable( + sourceOfTruth = SourceOfTruth.ofFlowable( reader = { if (fakeDisk[it] != null) Flowable.fromCallable { fakeDisk[it]!! } diff --git a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreExtensionsTest.kt b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreExtensionsTest.kt index 798ea7d99..62a15614c 100644 --- a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreExtensionsTest.kt +++ b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreExtensionsTest.kt @@ -1,13 +1,14 @@ package com.dropbox.store.rx3.test import com.dropbox.android.external.store4.ExperimentalStoreApi +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.store.rx3.freshSingle -import com.dropbox.store.rx3.fromMaybe +import com.dropbox.store.rx3.ofMaybe import com.dropbox.store.rx3.getSingle -import com.dropbox.store.rx3.singleFetcher +import com.dropbox.store.rx3.ofResultSingle import com.dropbox.store.rx3.withScheduler import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Maybe @@ -29,10 +30,10 @@ class RxSingleStoreExtensionsTest { private var fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - fetcher = singleFetcher { + fetcher = Fetcher.ofResultSingle { Single.fromCallable { FetcherResult.Data("$it ${atomicInteger.incrementAndGet()}") } }, - sourceOfTruth = SourceOfTruth.fromMaybe( + sourceOfTruth = SourceOfTruth.ofMaybe( reader = { Maybe.fromCallable { fakeDisk[it] } }, writer = { key, value -> Completable.fromAction { fakeDisk[key] = value } diff --git a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreTest.kt b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreTest.kt index 85a4e049a..85fa1e176 100644 --- a/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreTest.kt +++ b/store-rx3/src/test/kotlin/com/dropbox/store/rx3/test/RxSingleStoreTest.kt @@ -1,17 +1,18 @@ package com.dropbox.store.rx3.test import com.dropbox.android.external.store4.ExperimentalStoreApi +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.SourceOfTruth import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.store.rx3.fromMaybe +import com.dropbox.store.rx3.ofMaybe import com.dropbox.store.rx3.observe import com.dropbox.store.rx3.observeClear import com.dropbox.store.rx3.observeClearAll -import com.dropbox.store.rx3.singleFetcher +import com.dropbox.store.rx3.ofResultSingle import com.dropbox.store.rx3.withScheduler import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Maybe @@ -33,10 +34,10 @@ class RxSingleStoreTest { private var fakeDisk = mutableMapOf() private val store = StoreBuilder.from( - fetcher = singleFetcher { + fetcher = Fetcher.ofResultSingle { Single.fromCallable { FetcherResult.Data("$it ${atomicInteger.incrementAndGet()}") } }, - sourceOfTruth = SourceOfTruth.fromMaybe( + sourceOfTruth = SourceOfTruth.ofMaybe( reader = { Maybe.fromCallable { fakeDisk[it] } }, writer = { key, value -> Completable.fromAction { fakeDisk[key] = value } diff --git a/store/api/store.api b/store/api/store.api index 0a99cd5ca..ad27db175 100644 --- a/store/api/store.api +++ b/store/api/store.api @@ -9,11 +9,16 @@ public abstract interface class com/dropbox/android/external/store4/DiskWrite { public abstract interface annotation class com/dropbox/android/external/store4/ExperimentalStoreApi : java/lang/annotation/Annotation { } -public final class com/dropbox/android/external/store4/FetcherKt { - public static final fun fetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; - public static final fun nonFlowFetcher (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1; - public static final fun nonFlowValueFetcher (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function1; - public static final fun valueFetcher (Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function1; +public abstract interface class com/dropbox/android/external/store4/Fetcher { + public static final field Companion Lcom/dropbox/android/external/store4/Fetcher$Companion; + public abstract fun invoke (Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow; +} + +public final class com/dropbox/android/external/store4/Fetcher$Companion { + public final fun of (Lkotlin/jvm/functions/Function2;)Lcom/dropbox/android/external/store4/Fetcher; + public final fun ofFlow (Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; + public final fun ofResult (Lkotlin/jvm/functions/Function2;)Lcom/dropbox/android/external/store4/Fetcher; + public final fun ofResultFlow (Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher; } public abstract class com/dropbox/android/external/store4/FetcherResult { @@ -102,10 +107,10 @@ public abstract interface class com/dropbox/android/external/store4/SourceOfTrut } public final class com/dropbox/android/external/store4/SourceOfTruth$Companion { - public final fun from (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun from$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public final fun fromNonFlow (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/SourceOfTruth; - public static synthetic fun fromNonFlow$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public final fun of (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun of$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public final fun ofFlow (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/SourceOfTruth; + public static synthetic fun ofFlow$default (Lcom/dropbox/android/external/store4/SourceOfTruth$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/dropbox/android/external/store4/SourceOfTruth; } public abstract interface class com/dropbox/android/external/store4/Store { @@ -123,8 +128,8 @@ public abstract interface class com/dropbox/android/external/store4/StoreBuilder } public final class com/dropbox/android/external/store4/StoreBuilder$Companion { - public final fun from (Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/StoreBuilder; - public final fun from (Lkotlin/jvm/functions/Function1;Lcom/dropbox/android/external/store4/SourceOfTruth;)Lcom/dropbox/android/external/store4/StoreBuilder; + public final fun from (Lcom/dropbox/android/external/store4/Fetcher;)Lcom/dropbox/android/external/store4/StoreBuilder; + public final fun from (Lcom/dropbox/android/external/store4/Fetcher;Lcom/dropbox/android/external/store4/SourceOfTruth;)Lcom/dropbox/android/external/store4/StoreBuilder; } public final class com/dropbox/android/external/store4/StoreKt { diff --git a/store/src/main/java/com/dropbox/android/external/store4/Fetcher.kt b/store/src/main/java/com/dropbox/android/external/store4/Fetcher.kt index 515473b4a..720ef3be0 100644 --- a/store/src/main/java/com/dropbox/android/external/store4/Fetcher.kt +++ b/store/src/main/java/com/dropbox/android/external/store4/Fetcher.kt @@ -1,5 +1,8 @@ package com.dropbox.android.external.store4 +import com.dropbox.android.external.store4.Fetcher.Companion.of +import com.dropbox.android.external.store4.Fetcher.Companion.ofFlow +import com.dropbox.android.external.store4.Fetcher.Companion.ofResult import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow @@ -20,80 +23,93 @@ sealed class FetcherResult { * Note: Store does not catch exceptions thrown by a [Fetcher]. This is done in order to avoid * silently swallowing NPEs and such. Use [FetcherResult.Error] to communicate expected errors. * - * See [nonFlowFetcher] for easily translating from a regular `suspend` function. - * See [valueFetcher], [nonFlowValueFetcher] for easily translating to [FetcherResult] (and + * See [ofResult] for easily translating from a regular `suspend` function. + * See [ofFlow], [of] for easily translating to [FetcherResult] (and * automatically transforming exceptions into [FetcherResult.Error]. */ -typealias Fetcher = (key: Key) -> Flow> +interface Fetcher { + operator fun invoke(key: Key): Flow> -/** - * "Creates" a [Fetcher] from a [flowFactory]. - * - * Use when creating a [Store] that fetches objects in a multiple responses per request - * network protocol (e.g Web Sockets). - * - * [Store] does not catch exception thrown in [flowFactory] or in the returned [Flow]. These - * exception will be propagated to the caller. - * - * @param flowFactory a factory for a [Flow]ing source of network records. - */ -fun fetcher( - flowFactory: (Key) -> Flow> -): Fetcher = flowFactory + /** + * Returns a flow of the item represented by the given [key]. + */ + companion object { + /** + * "Creates" a [Fetcher] from a [flowFactory]. + * + * Use when creating a [Store] that fetches objects in a multiple responses per request + * network protocol (e.g Web Sockets). + * + * [Store] does not catch exception thrown in [flowFactory] or in the returned [Flow]. These + * exception will be propagated to the caller. + * + * @param flowFactory a factory for a [Flow]ing source of network records. + */ + fun ofResultFlow( + flowFactory: (Key) -> Flow> + ): Fetcher = FactoryFetcher(flowFactory) -/** - * "Creates" a [Fetcher] from a non-[Flow] source. - * - * Use when creating a [Store] that fetches objects in a single response per request network - * protocol (e.g Http). - * - * [Store] does not catch exception thrown in [doFetch]. These exception will be propagated to the - * caller. - * - * @param doFetch a source of network records. - */ -fun nonFlowFetcher( - doFetch: suspend (Key) -> FetcherResult -): Fetcher = doFetch.asFlow() + /** + * "Creates" a [Fetcher] from a non-[Flow] source. + * + * Use when creating a [Store] that fetches objects in a single response per request network + * protocol (e.g Http). + * + * [Store] does not catch exception thrown in [doFetch]. These exception will be propagated to the + * caller. + * + * @param doFetch a source of network records. + */ + fun ofResult( + doFetch: suspend (Key) -> FetcherResult + ): Fetcher = ofResultFlow(doFetch.asFlow()) -/** - * "Creates" a [Fetcher] from a [flowFactory] and translate the results to a [FetcherResult]. - * - * Emitted values will be wrapped in [FetcherResult.Data]. if an exception disrupts the flow then - * it will be wrapped in [FetcherResult.Error]. Exceptions thrown in [flowFactory] itself are not - * caught and will be returned to the caller. - * - * Use when creating a [Store] that fetches objects in a multiple responses per request - * network protocol (e.g Web Sockets). - * - * @param flowFactory a factory for a [Flow]ing source of network records. - */ -fun valueFetcher( - flowFactory: (Key) -> Flow -): Fetcher = { key: Key -> - flowFactory(key).map { FetcherResult.Data(it) as FetcherResult } - .catch { th: Throwable -> - emit(FetcherResult.Error.Exception(th)) - } -} + /** + * "Creates" a [Fetcher] from a [flowFactory] and translate the results to a [FetcherResult]. + * + * Emitted values will be wrapped in [FetcherResult.Data]. if an exception disrupts the flow then + * it will be wrapped in [FetcherResult.Error]. Exceptions thrown in [flowFactory] itself are not + * caught and will be returned to the caller. + * + * Use when creating a [Store] that fetches objects in a multiple responses per request + * network protocol (e.g Web Sockets). + * + * @param flowFactory a factory for a [Flow]ing source of network records. + */ + fun ofFlow( + flowFactory: (Key) -> Flow + ): Fetcher = FactoryFetcher { key: Key -> + flowFactory(key).map { FetcherResult.Data(it) as FetcherResult } + .catch { th: Throwable -> + emit(FetcherResult.Error.Exception(th)) + } + } -/** - * "Creates" a [Fetcher] from a non-[Flow] source and translate the results to a [FetcherResult]. - * - * Emitted values will be wrapped in [FetcherResult.Data]. if an exception disrupts the flow then - * it will be wrapped in [FetcherResult.Error] - * - * Use when creating a [Store] that fetches objects in a single response per request - * network protocol (e.g Http). - * - * @param doFetch a source of network records. - */ -fun nonFlowValueFetcher( - doFetch: suspend (key: Key) -> Output -): Fetcher = valueFetcher(doFetch.asFlow()) + /** + * "Creates" a [Fetcher] from a non-[Flow] source and translate the results to a [FetcherResult]. + * + * Emitted values will be wrapped in [FetcherResult.Data]. if an exception disrupts the flow then + * it will be wrapped in [FetcherResult.Error] + * + * Use when creating a [Store] that fetches objects in a single response per request + * network protocol (e.g Http). + * + * @param doFetch a source of network records. + */ + fun of( + doFetch: suspend (key: Key) -> Output + ): Fetcher = ofFlow(doFetch.asFlow()) + + private fun (suspend (key: Key) -> Value).asFlow() = { key: Key -> + flow { + emit(invoke(key)) + } + } -private fun (suspend (key: Key) -> Value).asFlow() = { key: Key -> - flow { - emit(invoke(key)) + private class FactoryFetcher( + private val factory: (Key) -> Flow> + ) : Fetcher { + override fun invoke(key: Key): Flow> = factory(key) + } } } diff --git a/store/src/main/java/com/dropbox/android/external/store4/SourceOfTruth.kt b/store/src/main/java/com/dropbox/android/external/store4/SourceOfTruth.kt index 26fb7d84e..2c1301ca2 100644 --- a/store/src/main/java/com/dropbox/android/external/store4/SourceOfTruth.kt +++ b/store/src/main/java/com/dropbox/android/external/store4/SourceOfTruth.kt @@ -84,37 +84,37 @@ interface SourceOfTruth { companion object { /** - * Creates a (non-[Flow]) source of truth that is accessible via [reader], [writer], + * Creates a (non-[Flow]) source of truth that is accessible via [nonFlowReader], [writer], * [delete] and [deleteAll]. * - * @param reader function for reading records from the source of truth + * @param nonFlowReader function for reading records from the source of truth * @param writer function for writing updates to the backing source of truth * @param delete function for deleting records in the source of truth for the given key * @param deleteAll function for deleting all records in the source of truth */ - fun fromNonFlow( - reader: suspend (Key) -> Output?, + fun of( + nonFlowReader: suspend (Key) -> Output?, writer: suspend (Key, Input) -> Unit, delete: (suspend (Key) -> Unit)? = null, deleteAll: (suspend () -> Unit)? = null ): SourceOfTruth = PersistentNonFlowingSourceOfTruth( - realReader = reader, + realReader = nonFlowReader, realWriter = writer, realDelete = delete, realDeleteAll = deleteAll ) /** - * Creates a ([Flow]) source of truth that is accessed via [reader], [writer], [delete] and - * [deleteAll]. + * Creates a ([Flow]) source of truth that is accessed via [reader], [writer], + * [delete] and [deleteAll]. * * @param reader function for reading records from the source of truth * @param writer function for writing updates to the backing source of truth * @param delete function for deleting records in the source of truth for the given key * @param deleteAll function for deleting all records in the source of truth - * */ - fun from( + @JvmName("ofFlow") + fun of( reader: (Key) -> Flow, writer: suspend (Key, Input) -> Unit, delete: (suspend (Key) -> Unit)? = null, diff --git a/store/src/main/java/com/dropbox/android/external/store4/impl/FetcherController.kt b/store/src/main/java/com/dropbox/android/external/store4/impl/FetcherController.kt index d3038bf14..e29a174d3 100644 --- a/store/src/main/java/com/dropbox/android/external/store4/impl/FetcherController.kt +++ b/store/src/main/java/com/dropbox/android/external/store4/impl/FetcherController.kt @@ -60,6 +60,7 @@ internal class FetcherController( */ private val enablePiggyback: Boolean = sourceOfTruth == null ) { + @Suppress("USELESS_CAST") // needed for multicaster source private val fetchers = RefCountedResource( create = { key: Key -> Multicaster( diff --git a/store/src/test/java/com/dropbox/android/external/store3/DontCacheErrorsTest.kt b/store/src/test/java/com/dropbox/android/external/store3/DontCacheErrorsTest.kt index 160bc7942..24baa54f8 100644 --- a/store/src/test/java/com/dropbox/android/external/store3/DontCacheErrorsTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store3/DontCacheErrorsTest.kt @@ -2,7 +2,8 @@ package com.dropbox.android.external.store3 import com.dropbox.android.external.store4.get import com.dropbox.android.external.store4.legacy.BarCode -import com.dropbox.android.external.store4.nonFlowValueFetcher +import com.dropbox.android.external.store4.Fetcher + import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.test.TestCoroutineScope @@ -24,7 +25,7 @@ class DontCacheErrorsTest( // TODO move to test coroutine scope private val store = TestStoreBuilder.from( testScope, - fetcher = nonFlowValueFetcher { + fetcher = Fetcher.of { if (shouldThrow) { throw RuntimeException() } else { diff --git a/store/src/test/java/com/dropbox/android/external/store3/NoNetworkTest.kt b/store/src/test/java/com/dropbox/android/external/store3/NoNetworkTest.kt index a2db5ebf2..24269f543 100644 --- a/store/src/test/java/com/dropbox/android/external/store3/NoNetworkTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store3/NoNetworkTest.kt @@ -1,9 +1,9 @@ package com.dropbox.android.external.store3 +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.Store import com.dropbox.android.external.store4.get import com.dropbox.android.external.store4.legacy.BarCode -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -23,7 +23,7 @@ class NoNetworkTest( private val testScope = TestCoroutineScope() private val store: Store = TestStoreBuilder.from( testScope, - fetcher = nonFlowValueFetcher { + fetcher = Fetcher.of { throw EXCEPTION }).build(storeType) diff --git a/store/src/test/java/com/dropbox/android/external/store3/SequentialTest.kt b/store/src/test/java/com/dropbox/android/external/store3/SequentialTest.kt index 6c67fa0eb..49589a5cd 100644 --- a/store/src/test/java/com/dropbox/android/external/store3/SequentialTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store3/SequentialTest.kt @@ -1,8 +1,8 @@ package com.dropbox.android.external.store3 +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.get import com.dropbox.android.external.store4.legacy.BarCode -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -25,7 +25,7 @@ class SequentialTest( private val store = TestStoreBuilder.from( scope = testScope, cached = true, - fetcher = nonFlowValueFetcher { + fetcher = Fetcher.of { networkCalls++ }).build(storeType) diff --git a/store/src/test/java/com/dropbox/android/external/store4/FetcherControllerTest.kt b/store/src/test/java/com/dropbox/android/external/store4/FetcherControllerTest.kt index 06ac5a6d6..820b6f7f4 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/FetcherControllerTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/FetcherControllerTest.kt @@ -41,7 +41,7 @@ class FetcherControllerTest { fun simple() = testScope.runBlockingTest { val fetcherController = FetcherController( scope = testScope, - realFetcher = { key: Int -> + realFetcher = Fetcher.ofResultFlow { key: Int -> flow { emit(FetcherResult.Data(key * key) as FetcherResult) } @@ -67,7 +67,7 @@ class FetcherControllerTest { var createdCnt = 0 val fetcherController = FetcherController( scope = testScope, - realFetcher = { key: Int -> + realFetcher = Fetcher.ofResultFlow { key: Int -> createdCnt++ flow { // make sure it takes time, otherwise, we may not share diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/ClearAllStoreTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/ClearAllStoreTest.kt index 8e9383d23..00c376bfc 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/ClearAllStoreTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/ClearAllStoreTest.kt @@ -1,10 +1,10 @@ package com.dropbox.android.external.store4.impl import com.dropbox.android.external.store4.ExperimentalStoreApi +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreResponse.Data -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.testutil.InMemoryPersister import com.dropbox.android.external.store4.testutil.asSourceOfTruth import com.dropbox.android.external.store4.testutil.getData @@ -30,7 +30,7 @@ class ClearAllStoreTest { private val value1 = 1 private val value2 = 2 - private val fetcher = nonFlowValueFetcher { key: String -> + private val fetcher = Fetcher.of { key: String -> when (key) { key1 -> value1 key2 -> value2 diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/ClearStoreByKeyTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/ClearStoreByKeyTest.kt index 89d2a64c2..5d170cb5f 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/ClearStoreByKeyTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/ClearStoreByKeyTest.kt @@ -1,9 +1,9 @@ package com.dropbox.android.external.store4.impl +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreResponse.Data -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.testutil.InMemoryPersister import com.dropbox.android.external.store4.testutil.asSourceOfTruth import com.dropbox.android.external.store4.testutil.getData @@ -31,7 +31,7 @@ class ClearStoreByKeyTest { val key = "key" val value = 1 val store = StoreBuilder.from( - fetcher = nonFlowValueFetcher { value }, + fetcher = Fetcher.of { value }, sourceOfTruth = persister.asSourceOfTruth() ).scope(testScope) .disableCache() @@ -76,7 +76,7 @@ class ClearStoreByKeyTest { val key = "key" val value = 1 val store = StoreBuilder.from( - fetcher = nonFlowValueFetcher { value } + fetcher = Fetcher.of { value } ).scope(testScope).build() // should receive data from network first time @@ -118,7 +118,7 @@ class ClearStoreByKeyTest { val value1 = 1 val value2 = 2 val store = StoreBuilder.from( - fetcher = nonFlowValueFetcher { key -> + fetcher = Fetcher.of { key -> when (key) { key1 -> value1 key2 -> value2 diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/FetcherResponseTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/FetcherResponseTest.kt index 62267a326..115c955c9 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/FetcherResponseTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/FetcherResponseTest.kt @@ -1,14 +1,12 @@ package com.dropbox.android.external.store4.impl +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.StoreBuilder import com.dropbox.android.external.store4.StoreRequest import com.dropbox.android.external.store4.StoreResponse -import com.dropbox.android.external.store4.nonFlowFetcher -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.testutil.assertThat -import com.dropbox.android.external.store4.valueFetcher import com.google.common.truth.Truth import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -29,7 +27,7 @@ class FetcherResponseTest { val result = kotlin.runCatching { testScope.runBlockingTest { val store = StoreBuilder.from( - nonFlowFetcher { + Fetcher.ofResult { throw RuntimeException("don't catch me") } ).buildWithTestScope() @@ -48,12 +46,14 @@ class FetcherResponseTest { fun `GIVEN a Fetcher that emits Error and Data WHEN steaming THEN it can emit value after an error`() { val exception = RuntimeException("first error") testScope.runBlockingTest { - val store = StoreBuilder.from { key: Int -> - flowOf( - FetcherResult.Error.Exception(exception), - FetcherResult.Data("$key") - ) - }.buildWithTestScope() + val store = StoreBuilder.from( + fetcher = Fetcher.ofResultFlow { key: Int -> + flowOf>( + FetcherResult.Error.Exception(exception), + FetcherResult.Data("$key") + ) + } + ).buildWithTestScope() assertThat(store.stream(StoreRequest.fresh(1))) .emitsExactly( @@ -67,7 +67,7 @@ class FetcherResponseTest { @Test fun `GIVEN transformer WHEN raw value THEN unwrapped value returned AND value is cached`() = testScope.runBlockingTest { - val fetcher = valueFetcher { flowOf(it * it) } + val fetcher = Fetcher.ofFlow { flowOf(it * it) } val pipeline = StoreBuilder .from(fetcher).buildWithTestScope() @@ -94,7 +94,7 @@ class FetcherResponseTest { fun `GIVEN transformer WHEN error message THEN error returned to user AND error isn't cached`() = testScope.runBlockingTest { var count = 0 - val fetcher = { _: Int -> + val fetcher = Fetcher.ofResultFlow { _: Int -> flowOf(count++).map { if (it > 0) { FetcherResult.Data(it) @@ -132,7 +132,7 @@ class FetcherResponseTest { testScope.runBlockingTest { val e = Exception() var count = 0 - val fetcher = { _: Int -> + val fetcher = Fetcher.ofResultFlow { _: Int -> flowOf(count++).map { if (it > 0) { FetcherResult.Data(it) @@ -171,7 +171,7 @@ class FetcherResponseTest { testScope.runBlockingTest { var count = 0 val e = Exception() - val fetcher = nonFlowValueFetcher { + val fetcher = Fetcher.of { count++ if (count == 1) { throw e diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/FlowStoreTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/FlowStoreTest.kt index 127c86541..287e9f7e6 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/FlowStoreTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/FlowStoreTest.kt @@ -15,6 +15,7 @@ */ package com.dropbox.android.external.store4.impl +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.ResponseOrigin import com.dropbox.android.external.store4.Store import com.dropbox.android.external.store4.StoreBuilder @@ -23,14 +24,12 @@ import com.dropbox.android.external.store4.StoreResponse import com.dropbox.android.external.store4.StoreResponse.Data import com.dropbox.android.external.store4.StoreResponse.Loading import com.dropbox.android.external.store4.fresh -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.testutil.FakeFetcher import com.dropbox.android.external.store4.testutil.FakeFlowingFetcher import com.dropbox.android.external.store4.testutil.InMemoryPersister import com.dropbox.android.external.store4.testutil.asFlowable import com.dropbox.android.external.store4.testutil.asSourceOfTruth import com.dropbox.android.external.store4.testutil.assertThat -import com.dropbox.android.external.store4.valueFetcher import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -326,7 +325,7 @@ class FlowStoreTest { fun diskChangeWhileNetworkIsFlowing_simple() = testScope.runBlockingTest { val persister = InMemoryPersister().asFlowable() val pipeline = StoreBuilder.from( - valueFetcher { flow {} }, + Fetcher.ofFlow { flow {} }, sourceOfTruth = persister.asSourceOfTruth() ) .disableCache() @@ -352,7 +351,7 @@ class FlowStoreTest { fun diskChangeWhileNetworkIsFlowing_overwrite() = testScope.runBlockingTest { val persister = InMemoryPersister().asFlowable() val pipeline = StoreBuilder.from( - fetcher = valueFetcher { + fetcher = Fetcher.ofFlow { flow { delay(10) emit("three-1") @@ -400,7 +399,7 @@ class FlowStoreTest { val exception = IllegalArgumentException("wow") val persister = InMemoryPersister().asFlowable() val pipeline = StoreBuilder.from( - nonFlowValueFetcher { + Fetcher.of { throw exception }, sourceOfTruth = persister.asSourceOfTruth() diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/HotFlowStoreTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/HotFlowStoreTest.kt index 55c1d8d12..6230d971c 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/HotFlowStoreTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/HotFlowStoreTest.kt @@ -72,7 +72,6 @@ class FakeFlowFetcher( ) : Fetcher { private var index = 0 - @Suppress("RedundantSuspendModifier") // needed for function reference override fun invoke(key: Key): Flow> { if (index >= responses.size) { throw AssertionError("unexpected fetch request") diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/StoreWithInMemoryCacheTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/StoreWithInMemoryCacheTest.kt index 437979434..a0885b8e1 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/StoreWithInMemoryCacheTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/StoreWithInMemoryCacheTest.kt @@ -1,8 +1,8 @@ package com.dropbox.android.external.store4.impl +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.MemoryPolicy import com.dropbox.android.external.store4.StoreBuilder -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.get import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview @@ -22,7 +22,7 @@ class StoreWithInMemoryCacheTest { @Test fun `store requests can complete when its in-memory cache (with access expiry) is at the maximum size`() { val store = StoreBuilder - .from(nonFlowValueFetcher { _: Int -> "result" }) + .from(Fetcher.of { _: Int -> "result" }) .cachePolicy( MemoryPolicy .builder() diff --git a/store/src/test/java/com/dropbox/android/external/store4/impl/ValueFetcherTest.kt b/store/src/test/java/com/dropbox/android/external/store4/impl/ValueFetcherTest.kt index 337cef43d..fef600b5b 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/impl/ValueFetcherTest.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/impl/ValueFetcherTest.kt @@ -1,9 +1,8 @@ package com.dropbox.android.external.store4.impl +import com.dropbox.android.external.store4.Fetcher import com.dropbox.android.external.store4.FetcherResult -import com.dropbox.android.external.store4.nonFlowValueFetcher import com.dropbox.android.external.store4.testutil.assertThat -import com.dropbox.android.external.store4.valueFetcher import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.flow @@ -21,7 +20,7 @@ class ValueFetcherTest { @Test fun `GIVEN valueFetcher WHEN invoke THEN result is wrapped`() = testScope.runBlockingTest { - val fetcher = valueFetcher { flowOf(it * it) } + val fetcher = Fetcher.ofFlow { flowOf(it * it) } assertThat(fetcher(3)) .emitsExactly(FetcherResult.Data(value = 9)) @@ -31,7 +30,7 @@ class ValueFetcherTest { fun `GIVEN valueFetcher WHEN exception in flow THEN exception returned as result`() = testScope.runBlockingTest { val e = Exception() - val fetcher = valueFetcher { + val fetcher = Fetcher.ofFlow { flow { throw e } @@ -43,7 +42,7 @@ class ValueFetcherTest { @Test fun `GIVEN nonFlowValueFetcher WHEN invoke THEN result is wrapped`() = testScope.runBlockingTest { - val fetcher = nonFlowValueFetcher { it * it } + val fetcher = Fetcher.of { it * it } assertThat(fetcher(3)) .emitsExactly(FetcherResult.Data(value = 9)) @@ -53,7 +52,7 @@ class ValueFetcherTest { fun `GIVEN nonFlowValueFetcher WHEN exception in flow THEN exception returned as result`() = testScope.runBlockingTest { val e = Exception() - val fetcher = nonFlowValueFetcher { + val fetcher = Fetcher.of { throw e } assertThat(fetcher(3)) diff --git a/store/src/test/java/com/dropbox/android/external/store4/testutil/FakeFetcher.kt b/store/src/test/java/com/dropbox/android/external/store4/testutil/FakeFetcher.kt index f53db4741..c5c2d3e18 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/testutil/FakeFetcher.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/testutil/FakeFetcher.kt @@ -27,7 +27,8 @@ class FakeFetcher( private vararg val responses: Pair ) : Fetcher { private var index = 0 - override operator fun invoke(key: Key): Flow> { + + override fun invoke(key: Key): Flow> { if (index >= responses.size) { throw AssertionError("unexpected fetch request") } @@ -40,7 +41,7 @@ class FakeFetcher( class FakeFlowingFetcher( private vararg val responses: Pair ) : Fetcher { - override operator fun invoke(key: Key) = flow { + override fun invoke(key: Key) = flow { responses.filter { it.first == key }.forEach { diff --git a/store/src/test/java/com/dropbox/android/external/store4/testutil/InMemoryPersister.kt b/store/src/test/java/com/dropbox/android/external/store4/testutil/InMemoryPersister.kt index 07ba55fa5..0c50a9244 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/testutil/InMemoryPersister.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/testutil/InMemoryPersister.kt @@ -32,8 +32,8 @@ class InMemoryPersister { } fun InMemoryPersister.asSourceOfTruth() = - SourceOfTruth.fromNonFlow( - reader = ::read, + SourceOfTruth.of( + nonFlowReader = ::read, writer = ::write, delete = ::deleteByKey, deleteAll = ::deleteAll diff --git a/store/src/test/java/com/dropbox/android/external/store4/testutil/SimplePersisterAsFlowable.kt b/store/src/test/java/com/dropbox/android/external/store4/testutil/SimplePersisterAsFlowable.kt index eb49b3420..e80a77a3f 100644 --- a/store/src/test/java/com/dropbox/android/external/store4/testutil/SimplePersisterAsFlowable.kt +++ b/store/src/test/java/com/dropbox/android/external/store4/testutil/SimplePersisterAsFlowable.kt @@ -62,7 +62,7 @@ class SimplePersisterAsFlowable( @ExperimentalCoroutinesApi fun SimplePersisterAsFlowable.asSourceOfTruth() = - SourceOfTruth.from( + SourceOfTruth.of( reader = ::flowReader, writer = ::flowWriter, delete = ::flowDelete.takeIf { supportsDelete }