Trying to come with a offline-first app, I managed to make a working repository pattern which first check the cache, then the database and finally, the api. I do that like this:
private fun cachedTopics(): Maybe<List<Topic>> { ... }
private fun databaseTopics(): Maybe<List<Topic>> { ... }
private fun apiTopics(): Maybe<List<Topic>> { ... }
Maybe.concat(cachedTopics(), databaseTopics(), apiTopics())
.firstOrError()
.subscribeOn(scheduler)
Now, the thing is that I save partial data in the database (not all topics). If a user is connected to internet and browse the data displayed will only be the data in the database. But that's not all the content a user should access (if they are connected to internet). I'm aware this is due to the .firstOrError()
call.
But I wonder if there is a way to concatenate the distinct results of database + api (api might fail and thus return 0 results) and return a Single.
To be clearer I want something like the following:
IF CACHE IS NOT EMPTY
RETURN DISTINCT(DB + CACHE)
ELSE
UPDATE CACHE WITH API RESULT
RETURN DISTINCT(DB + API)
Where API calls will automatically result in having nor results if it fails.
Perhaps what you want here is Maybe#switchIfEmpty
(docs here)
Then you could do something like this:
class Repository() {
fun topics() {
return cachedTopics.switchIfEmpty(databaseOrApiTopics());
}
private fun databaseOrApiTopics() = databaseTopics().switchIfEmpty(apiTopicsWithUpdate())
private fun apiTopicsWithUpdate() = apiTopics().doOnComplete {
// update db
// update cache?
}
}
UPDATE: if you want to combine results together, you can do this with the overload of Maybe.flatMap
that takes a combiner. Something like:
cachedTopics().switchIfEmpty(
databaseTopics().flatMap { dbTopics ->
apiTopics().doOnComplete { /* updateDb(it) */ }
.map { apiTopics -> apiTopics + dbTopics }
}
)