Room #Transaction and Rx Completable - android

My dao looks like
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(group: Group): Completable
#Query("DELETE FROM groups")
fun deleteAllGroups()
I would like to refresh all rows like
#Transaction
fun refreshGroups(groups: List<Group>): Completable {
deleteAllGroups()
insertAll(groups)
}
However, I can't return Completable from Transaction.
I'm using Rx so I'm expecting some kind of Observable.

Related

DAO when to use suspend function android

I am following DAO tutorial on Android developers here:
https://developer.android.com/codelabs/android-room-with-a-view-kotlin#5
They say:
By default, all queries must be executed on a separate thread.
Room has Kotlin coroutines support. This allows your queries to be annotated with the suspend modifier and then called from a coroutine or from another suspension function.
Dao interface is as follows:
#Dao
interface WordDao {
#Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): List<Word>
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
#Query("DELETE FROM word_table")
suspend fun deleteAll()
}
Why getAlphabetizedWords() is not defined as suspend function?
In coroutines, a flow is a type that can emit multiple values sequentially, as opposed to suspend functions that return only a single value. For example, you can use a flow to receive live updates from a database.
#Dao
interface WordDao {
// The flow always holds/caches latest version of data. Notifies its observers when the
// data has changed.
#Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
#Query("DELETE FROM word_table")
suspend fun deleteAll()
}
you can see source code in Github.

Is it possible to use Flow with Room delete or insert operations as it's used in RxJava with Single or Maybe that returns row ids?

Calling
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(entity: PostEntity): Flow<Long>
#Delete
fun deletePost(entity: PostEntity): Flow<Long>
returns compile error
Not sure how to handle insert method's return type.
public abstract kotlinx.coroutines.flow.Flow<java.util.List<java.lang.Long>> insertFlow(#org.jetbrains.annotations.NotNull()
Isn't possible to use Flow with Int or long to get ids for results of database operations like in RxJava?
#Insert(onConflict = REPLACE)
fun insert(entity: T): Maybe<Long>
#Insert(onConflict = REPLACE)
fun insert(entity: T): Single<Long>
As per the Async queries with Kotlin coroutines in Room, the equivalent for Maybe and Single in Kotlin coroutines is suspend:
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(entity: PostEntity): Long
#Delete
suspend fun deletePost(entity: PostEntity): Long

Obtain entity using coroutines api

What is the best way to use coroutines with LiveData for selecting some data from database using Room.
This is My Dao class with suspended selection
#Dao
interface UserDao {
#Query("SELECT * from user_table WHERE id =:id")
suspend fun getUser(id: Long): User
}
Inside of View Model class I load user with viewModelScope.
Does it correct way to obtain user entity ?
fun load(userId: Long, block: (User?) -> Unit) = viewModelScope.launch {
block(dao.getUser(userId))
}
According developer android mentioned
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
This chunk of code does not work
Your Room must return LiveData.
Use instead:
#Dao
interface UserDao {
#Query("SELECT * from user_table WHERE id =:id")
fun getUser(id: Long): LiveData<User>
}

How return completable on room transaction Android

I need your help please.
I have dao interface that save some configurations:
#Dao interface ConfigDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(config: Config)
#Update(onConflict = OnConflictStrategy.REPLACE)
fun update(config: Config)
#Query("select * from T_CONFIG where isSelected = :isSelected")
fun getConfig(isSelected: Boolean): Single<Config>
#Query("select * from t_config")
fun getConfigAll(): LiveData<MutableList<Config>>
#Query("update T_CONFIG set isSelected = :isSelected where idEnvironment = :id")
fun updateConfigById(id: String, isSelected: Boolean):Completable
#Transaction
fun updateConfigTransaction(configSelected: Config){
if (configSelected.idEnvironment == Environtment.Type.PRD.toString()){
updateConfigById(Environtment.Type.PRD.toString(), false)
updateConfigById(Environtment.Type.DEV.toString(), true)
}else{
updateConfigById(Environtment.Type.PRD.toString(), true)
updateConfigById(Environtment.Type.DEV.toString(), false)
}
}
}
I need to know when the transaction is complete with success or error.
I tried to implement Completable from io.reactivex but it's not possible.
Since Room 2.1.0
Additional Async Support: DAO methods annotated with #Insert, #Delete or #Update, along with #Query containing INSERT, DELETE or UPDATE statements, now support Rx return types Completable, Single, Maybe, and Guava's return type ListenableFuture, and they can also be suspend functions.
Source: https://developer.android.com/jetpack/androidx/releases/room#2.1.0
Older versions
Change the interface to an abstract class. You'll have to prefix all methods without implementation with abstract. Then:
abstract class ConfigDao(private val db: MyDatabase) {
private val scheduler = Schedulers.from(db.queryExecutor)
// Make sure the method is open so Room can generate the transaction handling code.
#Transaction
open fun updateConfigTransaction(configSelected: Config){
// ...
}
fun updateConfigTransactionAsync(configSelected: config): Completable {
return Completable
.fromAction { updateConfigTransaction(config) }
.subscribeOn(scheduler)
}
}
subscribeOn(db.queryExecutor) makes sure the query runs on the same thread as all other DAO methods returning RxJava types. Replace MyDatabase constructor parameter with whatever your database class is.

RxJava2 & Room: Stop emitting events on delete

I have this database
interface UserDao {
#Insert(onConflict = REPLACE)
fun insert(user : User)
#Query("SELECT * FROM user")
fun get(): Flowable<List<User>>
#Query("DELETE FROM user")
fun deleteAll()
}
Everytime a record is inserted, get() will be triggered automatically, as expected.
override fun getUsers() : Flowable<User> {
return db.userDao().get()
}
How can I stop this from happening when deleteAll() is called?
You can use Single instead of Flowable. Secondly you can use a flag in your onNext() method of the subscriber. Turn the flag off after first run. Even if it gets triggered no changes will occur to your core code in onNext().

Categories

Resources