Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ 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) },
fetcher = Fetcher.from { api.fetchSubreddit(it, "10").data.children.map(::toPosts) },
sourceOfTruth = SourceOfTrue.from(
reader = db.postDao()::loadPosts,
flowReader = db.postDao()::loadPosts,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure how discoverable it is to use parameter names do distinguish between the 2 functions. what happens if you call it without parameter names?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without names this does work:

sourceOfTruth = SourceOfTruth.of(
                    db.postDao()::loadPosts,
                    db.postDao()::insertPosts,
                    db.postDao()::clearFeedBySubredditName,
                    db.postDao()::clearAllFeeds
                )

While this doesn't:

sourceOfTruth = SourceOfTruth.of(
                    {
                        db.postDao().loadPosts(it)
                    },
                    db.postDao()::insertPosts,
                    db.postDao()::clearFeedBySubredditName,
                    db.postDao()::clearAllFeeds
                )

re-naming: part of the challange is that this receives 4 methods, only 1 parameter's type is different so ofFlow wouldn't look very good imo either :/.

writer = db.postDao()::insertPosts,
delete = db.postDao()::clearFeed,
deleteAll = db.postDao()::clearAllFeeds
Expand All @@ -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<Article>
.from(Fetcher.fromFlow { articleId -> api.getArticle(articleId) }) // api returns Flow<Article>
.build()
```

Expand Down Expand Up @@ -186,9 +186,9 @@ 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) },
fetcher = Fetcher.from { api.fetchSubreddit(it, "10").data.children.map(::toPosts) },
sourceOfTruth = SourceOfTrue.from(
reader = db.postDao()::loadPosts,
flowReader = db.postDao()::loadPosts,
writer = db.postDao()::insertPosts,
delete = db.postDao()::clearFeed,
deleteAll = db.postDao()::clearAllFeeds
Expand All @@ -215,9 +215,9 @@ You can configure in-memory cache with the `MemoryPolicy`:
```kotlin
StoreBuilder
.from(
fetcher = nonFlowValueFetcher { api.fetchSubreddit(it, "10").data.children.map(::toPosts) },
fetcher = Fetcher.from { api.fetchSubreddit(it, "10").data.children.map(::toPosts) },
sourceOfTruth = SourceOfTrue.from(
reader = db.postDao()::loadPosts,
flowReader = db.postDao()::loadPosts,
writer = db.postDao()::insertPosts,
delete = db.postDao()::clearFeed,
deleteAll = db.postDao()::clearAllFeeds
Expand All @@ -244,8 +244,9 @@ 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.from { key: String ->
api.fetchData(key)
}).build()
```

The following will clear the entry associated with the key from the in-memory cache:
Expand All @@ -267,9 +268,9 @@ When store has a sourceOfTruth, you'll need to provide the `delete` and `deleteA
```kotlin
StoreBuilder
.from(
fetcher = nonFlowValueFetcher { api.fetchData(key) },
fetcher = Fetcher.from { api.fetchData(key) },
sourceOfTruth = SourceOfTrue.from(
reader = dao::loadData,
flowReader = dao::loadData,
writer = dao::writeData,
delete = dao::clearDataByKey,
deleteAll = dao::clearAllData
Expand Down
14 changes: 7 additions & 7 deletions app/src/main/java/com/dropbox/android/sample/Graph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -46,11 +46,11 @@ object Graph {
val db = provideRoom(context)
return StoreBuilder
.from(
nonFlowValueFetcher { key: String ->
Fetcher.from { key: String ->
provideRetrofit().fetchSubreddit(key, 10).data.children.map(::toPosts)
},
sourceOfTruth = SourceOfTruth.from(
reader = db.postDao()::loadPosts,
flowReader = db.postDao()::loadPosts,
writer = db.postDao()::insertPosts,
delete = db.postDao()::clearFeedBySubredditName,
deleteAll = db.postDao()::clearAllFeeds
Expand All @@ -63,12 +63,12 @@ object Graph {
val db = provideRoom(context)
return StoreBuilder
.from<Pair<String, RedditConfig>, List<Post>, List<Post>>(
nonFlowValueFetcher { (query, config) ->
Fetcher.from { (query, config) ->
provideRetrofit().fetchSubreddit(query, config.limit)
.data.children.map(::toPosts)
},
sourceOfTruth = SourceOfTruth.from(
reader = { (query, _) -> db.postDao().loadPosts(query) },
flowReader = { (query, _) -> db.postDao().loadPosts(query) },
writer = { (query, _), posts -> db.postDao().insertPosts(query, posts) },
delete = { (query, _) -> db.postDao().clearFeedBySubredditName(query) },
deleteAll = db.postDao()::clearAllFeeds
Expand Down Expand Up @@ -99,11 +99,11 @@ object Graph {
val adapter = moshi.adapter<RedditConfig>(RedditConfig::class.java)
return StoreBuilder
.from<Unit, RedditConfig, RedditConfig>(
nonFlowValueFetcher {
Fetcher.from {
delay(500)
RedditConfig(10)
},
sourceOfTruth = SourceOfTruth.fromNonFlow(
sourceOfTruth = SourceOfTruth.from(
reader = {
runCatching {
val source = fileSystemPersister.read(Unit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -51,7 +51,7 @@ class StreamFragment : Fragment(), CoroutineScope {
var counter = 0

val store = StoreBuilder
.from(nonFlowValueFetcher { key: Int ->
.from(Fetcher.from { key: Int ->
(key * 1000 + counter++).also { delay(1_000) }
})
.cachePolicy(
Expand Down
8 changes: 4 additions & 4 deletions store-rx2/api/store-rx2.api
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
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 from (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher;
public static final fun fromFetcherResultFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher;
public static final fun fromFlowable (Lcom/dropbox/android/external/store4/Fetcher$Companion;Lkotlin/jvm/functions/Function1;)Lcom/dropbox/android/external/store4/Fetcher;
public static final fun fromSingleFetcherResult (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 {
Expand Down
17 changes: 8 additions & 9 deletions store-rx2/src/main/kotlin/com/dropbox/store/rx2/RxFetcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -19,9 +18,9 @@ import kotlinx.coroutines.reactive.asFlow
*
* @param flowableFactory a factory for a [Flowable] source of network records.
*/
fun <Key : Any, Output : Any> flowableFetcher(
fun <Key : Any, Output : Any> Fetcher.Companion.fromFetcherResultFlowable(
flowableFactory: (key: Key) -> Flowable<FetcherResult<Output>>
): Fetcher<Key, Output> = { key: Key -> flowableFactory(key).asFlow() }
): Fetcher<Key, Output> = Fetcher.fromFetcherResultFlow { key: Key -> flowableFactory(key).asFlow() }

/**
* "Creates" a [Fetcher] from a [singleFactory].
Expand All @@ -34,9 +33,9 @@ fun <Key : Any, Output : Any> flowableFetcher(
*
* @param singleFactory a factory for a [Single] source of network records.
*/
fun <Key : Any, Output : Any> singleFetcher(
fun <Key : Any, Output : Any> Fetcher.Companion.fromSingleFetcherResult(
singleFactory: (key: Key) -> Single<FetcherResult<Output>>
): Fetcher<Key, Output> = { key: Key -> singleFactory(key).toFlowable().asFlow() }
): Fetcher<Key, Output> = Fetcher.fromFetcherResultFlow { key: Key -> singleFactory(key).toFlowable().asFlow() }

/**
* "Creates" a [Fetcher] from a [flowableFactory] and translate the results to a [FetcherResult].
Expand All @@ -50,9 +49,9 @@ fun <Key : Any, Output : Any> singleFetcher(
*
* @param flowFactory a factory for a [Flowable] source of network records.
*/
fun <Key : Any, Output : Any> flowableValueFetcher(
fun <Key : Any, Output : Any> Fetcher.Companion.fromFlowable(
flowableFactory: (key: Key) -> Flowable<Output>
): Fetcher<Key, Output> = valueFetcher { key: Key -> flowableFactory(key).asFlow() }
): Fetcher<Key, Output> = Fetcher.fromFlow { key: Key -> flowableFactory(key).asFlow() }

/**
* Creates a new [Fetcher] from a [singleFactory] and translate the results to a [FetcherResult].
Expand All @@ -66,6 +65,6 @@ fun <Key : Any, Output : Any> flowableValueFetcher(
*
* @param singleFactory a factory for a [Single] source of network records.
*/
fun <Key : Any, Output : Any> singleValueFetcher(
fun <Key : Any, Output : Any> Fetcher.Companion.from(
singleFactory: (key: Key) -> Single<Output>
): Fetcher<Key, Output> = flowableValueFetcher { key: Key -> singleFactory(key).toFlowable() }
): Fetcher<Key, Output> = fromFlowable { key: Key -> singleFactory(key).toFlowable() }
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fun <Key : Any, Input : Any, Output : Any> 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(
return from(
reader = { key -> reader.invoke(key).await() },
writer = { key, output -> writer.invoke(key, output).await() },
delete = deleteFun,
Expand Down Expand Up @@ -54,7 +54,7 @@ fun <Key : Any, Input : Any, Output : Any> SourceOfTruth.Companion.fromFlowable(
if (delete != null) { key -> delete(key).await() } else null
val deleteAllFun: (suspend () -> Unit)? = deleteAll?.let { { deleteAll().await() } }
return from(
reader = { key -> reader.invoke(key).asFlow() },
flowReader = { key -> reader.invoke(key).asFlow() },
writer = { key, output -> writer.invoke(key, output).await() },
delete = deleteFun,
deleteAll = deleteAllFun
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.fromSingleFetcherResult
import com.google.common.truth.Truth.assertThat
import io.reactivex.Single
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -30,7 +30,7 @@ class HotRxSingleStoreTest {
3 to FetcherResult.Data("three-1"),
3 to FetcherResult.Data("three-2")
)
val pipeline = StoreBuilder.from(singleFetcher<Int, String> { fetcher.fetch(it) })
val pipeline = StoreBuilder.from(Fetcher.fromSingleFetcherResult<Int, String> { fetcher.fetch(it) })
.scope(testScope)
.build()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
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.fromFetcherResultFlowable
import com.dropbox.store.rx2.fromFlowable
import com.dropbox.store.rx2.observe
import io.reactivex.BackpressureStrategy
Expand All @@ -30,7 +31,7 @@ class RxFlowableStoreTest {
private val fakeDisk = mutableMapOf<Int, String>()
private val store =
StoreBuilder.from<Int, String, String>(
flowableFetcher {
Fetcher.fromFetcherResultFlowable {
Flowable.create({ emitter ->
emitter.onNext(
FetcherResult.Data("$it ${atomicInteger.incrementAndGet()} occurrence")
Expand Down Expand Up @@ -64,12 +65,12 @@ class RxFlowableStoreTest {
testSubscriber
.awaitCount(3)
.assertValues(
StoreResponse.Loading<String>(ResponseOrigin.Fetcher),
StoreResponse.Loading(ResponseOrigin.Fetcher),
StoreResponse.Data("3 1 occurrence", ResponseOrigin.Fetcher),
StoreResponse.Data("3 2 occurrence", ResponseOrigin.Fetcher)
)

testSubscriber = TestSubscriber<StoreResponse<String>>()
testSubscriber = TestSubscriber()
store.observe(StoreRequest.cached(3, false))
.subscribeOn(testScheduler)
.subscribe(testSubscriber)
Expand All @@ -81,20 +82,20 @@ class RxFlowableStoreTest {
StoreResponse.Data("3 2 occurrence", ResponseOrigin.SourceOfTruth)
)

testSubscriber = TestSubscriber<StoreResponse<String>>()
testSubscriber = TestSubscriber()
store.observe(StoreRequest.fresh(3))
.subscribeOn(testScheduler)
.subscribe(testSubscriber)
testScheduler.triggerActions()
testSubscriber
.awaitCount(3)
.assertValues(
StoreResponse.Loading<String>(ResponseOrigin.Fetcher),
StoreResponse.Loading(ResponseOrigin.Fetcher),
StoreResponse.Data("3 3 occurrence", ResponseOrigin.Fetcher),
StoreResponse.Data("3 4 occurrence", ResponseOrigin.Fetcher)
)

testSubscriber = TestSubscriber<StoreResponse<String>>()
testSubscriber = TestSubscriber()
store.observe(StoreRequest.cached(3, false))
.subscribeOn(testScheduler)
.subscribe(testSubscriber)
Expand Down
Original file line number Diff line number Diff line change
@@ -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.getSingle
import com.dropbox.store.rx2.singleFetcher
import com.dropbox.store.rx2.fromSingleFetcherResult
import com.dropbox.store.rx2.withScheduler
import io.reactivex.Completable
import io.reactivex.Maybe
Expand All @@ -29,7 +30,7 @@ class RxSingleStoreExtensionsTest {
private var fakeDisk = mutableMapOf<Int, String>()
private val store =
StoreBuilder.from<Int, String, String>(
fetcher = singleFetcher {
fetcher = Fetcher.fromSingleFetcherResult {
Single.fromCallable { FetcherResult.Data("$it ${atomicInteger.incrementAndGet()}") }
},
sourceOfTruth = SourceOfTruth.fromMaybe(
Expand Down
Loading