Clément Jean
Clément Jean

Reputation: 1916

Repository pattern concatenating results in RXKotlin

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.

Edit

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.

Upvotes: 1

Views: 142

Answers (1)

David Rawson
David Rawson

Reputation: 21447

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 }
    }
)

Upvotes: 1

Related Questions