Search code examples
android-roomdaoandroid-livedatamutablelivedata

Pass multiple Filters to Android Room Dao SQL Query from ViewModel with Repository


I am using the below to fetch Database rows to my Adapter, however I want to return rows from multi-filtered single query using either "LIKE" and/or "WHERE" and basically all sql query filter types, I can do one filter via MutableLiveData<String>();

end result would be like ...

@Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%' postcode LIKE '%' || :postcode || '%' BETWEEN firstDate AND lastDate")
fun getFilteredRows(
    suburb: String?, 
    postcode: String?, 
    firstDate: String?, 
    lastDate: String?): LiveData<List<MyTable>>

As per below, currently way only can pass one filter var.

ViewModel Class

 class MyViewModel internal constructor(repository: MyRepository) : ViewModel()

 //filter by suburb
 var suburb = MutableLiveData<String>().apply { 
    //do I set as HashMap??
    value = SUBURB 
 }

 //LiveData Observer access
 val filteredRows: LiveData<List<MyTable>> = suburb.switchMap {

    //pass multiple filters to repository here
    //but currently only can pass one string to repository
    repository.getFilteredRows(it)

 }

 //MyViewModel function to set the suburb value
 fun setSuburb(_suburb: String) {
    suburb.value = _suburb
 }

 //companion object
 companion object {
    var SUBURB: String? = null
 }

Repository Class

class Repository private constructor(private val dao: Dao)

//basic repo to dao communtication
fun getFilteredRows(suburb: String?) = dao.getFilteredRows(suburb)

Dao Interface

@Dao
interface Dao

//here I want to receive multiple Strings to do filtering within the query
@Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%'")
fun getFilteredRows(suburb: String?): LiveData<List<MyTable>>

I have tried with passing basic var Strings with no luck, seems only MutableLiveData is the way to pass variable to the Dao via ViewModel & Repository


Solution

  • ** See Edit Below **

    Not ideal to say the least, actually would not recommend, however, current work around is to "loop" through multiple MutableLiveData variables

    ViewModel Class

    var suburb = MutableLiveData<String>().apply { value = SUBURB }
    var postcode = MutableLiveData<String>().apply { value = POSTCODE }
    var limit = MutableLiveData<Int>().apply { value = LIMIT }
    
    val filteredRows: LiveData<List<MyTable>> = 
        suburb.switchMap {
    
               //set suburb MutableLiveData
               var suburb = it
    
               postcode.switchMap {
                  //set postcode MutableLiveData
                  var postcode = it
    
    
                }
    
                limit.switchMap {
                  //set limit MutableLiveData
                  var limit = it
    
    
                }
    
        repository.getFilteredRows(suburb, postcode, limit)
    
    } 
    

    /// EDIT ANSWER ///

    Using HashMap to pass multiple filters (Strings) to Dao SQl Query. Tested a returned what was expected, so confirming this works.

    Foreseeable issue is when needing to pass Strings & Int etc, may have to refer back to passing as Strings only & then do parse.ToInt() etc on Int String Values

    build HashMap in my Fragment to pass to MyViewModel

    lateinit var myModel: LiveData<MyTable>
    
    var filters = HashMap<String, String>()
    filters.put("suburb", myModel.value!!.suburb)
    filters.put("postcode", myModel.value!!.postcode)
    
    
     with(viewModel) {
    
            //pass my HashMap to my ViewModel for update/change/set on filters MutableLiveData HashMap variable
            setFilters(filters)
    
     }
    

    MyViewModel Class

     //initilise filters MutableLiveData HashMap variable
     var filters = MutableLiveData<HashMap<String, String>>().apply { value = FILTERS }
    
    
     //function to update/change/set filters MutableLiveData HashMap variable
     //see setFilters(filters) used in above Fragment
     fun setFilters(_filters: HashMap<String, String>) {
        filters.value = _filters
     }
    
    
     //foreach on passed HashMap via switchMap{}
     val filtered: LiveData<List<MyTable>> = filters.switchMap {
    
        //initilise variables
        var suburb = ""
        var postcode = ""
    
        //foreach loop on HashCookie :)
        for (filter in it) {
            if(filter.key.equals("suburb")){
                suburb = filter.value
            }else if(filter.key.equals("postcode")) {
                postcode = filter.value
            }
        }
    
        //pass strings to Dao
        repository.getFiltered(suburb, postcode)
    
     }
    
    //companion object
    companion object {
        var FILTERS: HashMap<String, String>? = null
     }
    

    Repository Class

    //send variables to the Dao Interface
    fun getFiltered(suburb: String?, postcode: String?) = dao.getFiltered(suburb, postcode)
    

    Dao Interface

    @Query("SELECT * FROM mytable WHERE suburb LIKE '%' || :suburb || '%' AND postcode LIKE '%' || :postcode || '%' ")
    fun getFiltered(suburb: String?, postcode: String?): LiveData<List<MyTable>>