Search code examples
androidkotlinrx-java2android-room

Incorrect behavior of Maybe<List<T>> in Room?


I have the following query method definition:

@Query("SELECT * FROM box_jobs")
fun getAll(): Maybe<List<BoxJob>>

I want to return the result of this query if it's not empty or the result of the REST API call otherwise. This is my code for this logic:

override fun loadTasks(): Maybe<List<Task>> {
    Log.d(TAG, "Searching tasks in database")
    return boxJobDao.getAll()
            .map { boxJobs -> boxJobMapper.entityListToTaskList(boxJobs) }
            .switchIfEmpty(syncTasks())
}

private fun syncTasks(): Maybe<List<Task>> {
    Log.d(TAG, "Loading tasks from server")
    return api.boxJobs(DEVICE_ID)
            .doOnSuccess({ boxJobDtoList ->
                Log.d(TAG, "${boxJobDtoList.size} box jobs loaded from server")
                saveToDb(boxJobDtoList)
            })
            .doOnError({ error -> Log.d(TAG, "Error during tasks loading", error) })
            .map { boxJobDtoList -> boxJobMapper.dtoListToTaskList(boxJobDtoList) }
            .toMaybe()
}

The problem is that on empty database Maybe returned by getAll() always calls onSuccess() with empty List<BoxJob>, so switchIfEmpty() operator doesn't work.

I think that this is incorrect behavior. Am I right or am I doing something wrong? Is there a workaround for this problem?


Solution

  • An empty list seems to be an appropriate result. Even if it might be better to have an empty Maybe instead, you can achieve this easily using filter():

    boxJobDao.getAll()
             .filter { !it.isEmpty() }
             .map { boxJobMapper.entityListToTaskList(it) }
             .switchIfEmpty(syncTasks())