1

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!

Cion
  • 85
  • 8

2 Answers2

3

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
            }
        }
Sekiro
  • 1,537
  • 1
  • 7
  • 21
  • Hey, thank you for your answer. I tried it with your solution and I got two problems. First I don't have a fragment class I'm doing everything from the Main Activity, so ```viewLifeCycleOwner``` throws an error. I tried doing ```myViewModel.dataToUi.observe(this, { result -> {result.apply {tv2.text = result}}})``` instead but unfortunately there is a type mismatch between tv2.text which requires a ```Charsequence``` and result which is of type ```Unit```. Do you know how to deal with this? – Cion Jan 09 '21 at 09:38
  • try the answer now – Sekiro Jan 09 '21 at 09:56
  • Using everything like described, nothing changes inside the textview and android studio tells me that the lambda expression is unused. – Cion Jan 09 '21 at 11:13
  • @Cion, try the latest code, worked successfully on my device – Sekiro Jan 09 '21 at 13:54
  • This might work unfortunately I never worked before with binding so I have to look into that first, but thank you very much! – Cion Jan 09 '21 at 14:48
  • check the [official docs](https://developer.android.com/topic/libraries/data-binding) too and if the code is helpful, leave a upvote :) – Sekiro Jan 09 '21 at 14:54
  • Alright I read into it and got it working and your solution works perfectly, a big thanks for your help, time and patience :) – Cion Jan 09 '21 at 15:19
0

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

HSMKU
  • 81
  • 10