Return Map object by DAO method

Viewed 2432

I would like to have method like this in my dao object

@Query("SELECT c.name, sum(p.value) FROM payments p, paymentCategories c WHERE p.categoryId = c.id GROUP BY c.name")
fun getCategoryStats(): Map<String, Float>

but i get the error

error: Not sure how to convert a Cursor to this method's return type public abstract java.util.Map

Is it possible to change it to working version?

So it can be different type to return but the main conditions are

  1. It must be only one query in db
  2. I would like to avoid extra code like creating additional data structure only for this method
2 Answers

I'm little late for a party but maybe someone will still search for it.

From Room 2.4 we are able to use multimap return type with annotation @MapInfo which allow us to define the mapping for key and value.

In your case it will be sth like this:

@MapInfo(keyColumn = "name", valueColumn = "sum")    
@Query("SELECT c.name AS name, sum(p.value) AS sum FROM payments p, paymentCategories c WHERE p.categoryId = c.id GROUP BY c.name")
fun getCategoryStats(): Map<String, Float>

More info: https://developer.android.com/training/data-storage/room/accessing-data#multimap

While I don't think this can be done in the Dao it can easily be done when querying the LiveData in the repository or the viewModel (or where ever you are querying the list) using a transformation. Since I don't know your datanames I'm using made up ones:

val categoryStatsMap: LiveData<Map<String, Float>> = 
    Transformations.map(
        database.categoryStatsDao.getCategoryStats()) {it ->
            it.map {it.key to it.value}.toMap()
}

'it.key' and 'it.value' are the fields in the entity object that you want to use as... key and value pairs in the map. Transformations give you a live data object based on another live data object. I don't know what the overhead is, but I assume it shouldn't be too big.

Related