Cion
Cion

Reputation: 85

How to implement a Room LiveData filter

I do not know how to implement a filter query properly inside the Repository and the ViewModel to use it to display the filtered string in a Textview or anything else really. My Entity, Dao, Repository, and ViewModel are as follows:

User.kt

@Entity(tableName = "user_data")
data class User (
    @PrimaryKey(autoGenerate = true) val id: Int,
    @ColumnInfo(name = "name") val name: String
)

UserDao.kt

@Dao
interface UserDao {
    @Insert
    fun addUser(user: User)

    @Query("SELECT name FROM user_data WHERE name LIKE :filter LIMIT 1")
    fun getFilteredUser(filter: String): LiveData<String>
}

UserRepository.kt

class UserRepository(private val userDao: UserDao) {

     fun addUser(user: User) { userDao.addUser(User) }

     fun getFilteredUser(filter: String) {userDao.getFilteredUser(filter)}
}

UserViewModel.kt

class UserViewModel(application: Application): AndroidViewModel(application) {

    private val repository: UserRepository

    init {
        val userDao = UserDatabase.getDatabase(application).userDao()
        repository = UserRepository(userDao )    
    }

    fun addUser(user: User) {
        viewModelScope.launch(Dispatchers.IO){
            repository.addUser(user)
        }
    }

    fun getFilteredUser(filter: String){
        return repository.getFilteredUser(filter)
    }
}

How would I proceed from here to make it possible to e.g. display the filtered User String in a textview or anything like that and how do I write the method correctly inside the repository and the viewmodel? Thank you for your help!

Upvotes: 1

Views: 1253

Answers (2)

HSMKU
HSMKU

Reputation: 356

Easiest way I have found :

1 - In your DAO interface, add a parameter for the SQL query you want to use. For example:

@Dao
interface CrPairsDao {
    @Query("SELECT * FROM CrPairsModel WHERE columnName = :queryParam")
    fun getCrPairs(queryParam: String): Flow<List<CrPairsModel>>
}

In this example, columnName represents the column name in the table where you want to apply the query condition, and queryParam is the parameter for the query.

2 - Update your repository to pass the parameter value to the DAO method. Here's an example:

class CrPairsRepository(private val crPairsDao: CrPairsDao) {
    fun getCrPairsWithQuery(queryParam: String): Flow<List<CrPairsModel>> {
        return crPairsDao.getCrPairs(queryParam)
    }
}

In this example, the getCrPairsWithQuery function in the repository accepts the queryParam parameter and directly calls the DAO's getCrPairs method with the parameter value.

3 - Finally, in your ViewModel, update the function that fetches the data to include the parameter value. Here's an example:

class CrPairsViewModel(private val crPairsRepository: CrPairsRepository) : ViewModel() {
    private val _crPairsLiveData = MutableLiveData<List<CrPairsModel>>()
    val crPairsLiveData: LiveData<List<CrPairsModel>> = _crPairsLiveData

    fun fetchCrPairsWithQuery(queryParam: String) {
        viewModelScope.launch {
            crPairsRepository.getCrPairsWithQuery(queryParam).collect {
                _crPairsLiveData.value = it
            }
        }
    }
}

In this example, the fetchCrPairsWithQuery function in the ViewModel triggers the repository's getCrPairsWithQuery function with the provided query parameter. The resulting Flow is collected using collect, and the emitted value is set to the crPairsLiveData using the _crPairsLiveData.value.

With these changes, you can now pass a parameter to the SQL query in the DAO method and retrieve the filtered Flow<List> in your ViewModel with crPairsLiveData.observeAsState() and .value?.let

Upvotes: 0

Dhanuesh
Dhanuesh

Reputation: 1596

Try the following

UserDao

change getFilteredUser as follows

    @Query("SELECT name FROM user_data WHERE name LIKE '%' || :filter || '%' LIMIT 1")
    fun getFilteredUser(filter: String): Stringl̥

UserRepo

use coroutines to perform the database I/O operations

    suspend fun addUser(user: User) {
        withContext(Dispatchers.IO) {
            userDao.addUser(user)
        }
    }

    suspend fun getFilteredUser(filter: String): String {
        return withContext(Dispatchers.IO) {
            userDao.getFilteredUser(filter)
        }
    }

ViewModel

    fun addUser(user: User) {
        viewModelScope.launch {
            repository.addUser(user)
        }
    }

    private val _dataToUi = MutableLiveData<String>()
    val dataToUi: LiveData<String>
        get() = _dataToUi

    suspend fun getFilteredUser(filter: String): String? {
        return withContext(Dispatchers.IO) {
            repository.getFilteredUser(filter)
        }
    }

    // to set the filterquery from the fragment/activity
    fun setFliterQuery(query: String) {
        viewModelScope.launch {
            _dataToUi.value = getFilteredUser(query)
        }
    }

Activity

        binding.button.setOnClickListener {
            val queryKey = binding.queryKey.text.toString()
            Log.i("activity", queryKey)
            userViewModel.setFliterQuery(queryKey)
        }

        userViewModel.dataToUi.observe(this) { result ->
            result?.apply {
                Log.i("activity", result)
                binding.resultText.text = result
            }
        }

Upvotes: 3

Related Questions