Room DB with coroutines insert callback - android

I am using RoomDB with Coroutines. My code looks like below -
#Dao
interface AccountDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAccountData(accountModel: AccountModel)
#Query("DELETE FROM accountTable")
suspend fun deleteAccountData()
#Query("SELECT * FROM accountTable")
suspend fun getAccountData(): Deferred<AccountModel>
}
//From my class
override suspend fun retrieveAccountData(): AccountModel {
return accountDao.getAccountData().await()
}
How do I return or what do I return for insert or delete from the DAO so that I know insert or delete was successful?

If the #Insert method receives only 1 parameter, it can return a Long, which is the new rowId for the inserted item. If the parameter is an array or a collection, it should return Long[] or List<Long> instead.
#Delete method returns an Int indicating the number of rows removed from the database.
So, your Dao should be like following:
#Dao
interface AccountDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAccountData(accountModel: AccountModel): Long
#Delete
suspend fun deleteAccountData(accountModel: AccountModel): Int
#Query("SELECT * FROM accountTable")
suspend fun getAccountData(): Deferred<AccountModel>
}

Related

How to set getAll and nukeData as inheritance in Android Room?

I have
#Dao
interface ContactDao {
#Query("SELECT * FROM ContactItem")
fun getAll(): Flow<List<ContactItem>>
#Insert
fun insertAll(vararg todos: ContactItem)
#Delete
fun delete(todo: ContactItem)
#Update
fun update(note: ContactItem)
#Query("DELETE FROM ContactItem")
fun nukeTable()
}
Dao
interface TodoDao {
#Query("SELECT * FROM TodoItem")
fun getAll(): Flow<List<TodoItem>>
#Insert
fun insertAll(vararg todos: TodoItem)
#Delete
fun delete(todo: TodoItem)
#Update
fun update(note: TodoItem)
#Query("DELETE FROM TodoItem")
fun nukeTable()
}
And I can make some of them in base interface to shrink both of them
interface BaseDao<T> {
#Insert
fun insertAll(vararg obj: T)
#Delete
fun delete(obj: T)
#Update
fun update(obj: T)
}
#Dao
interface ContactDao: BaseDao<ContactItem> {
#Query("SELECT * FROM ContactItem")
fun getAll(): Flow<List<ContactItem>>
#Query("DELETE FROM ContactItem")
fun nukeTable()
}
#Dao
interface TodoDao: BaseDao<TodoItem> {
#Query("SELECT * FROM TodoItem")
fun getAll(): Flow<List<TodoItem>>
#Query("DELETE FROM TodoItem")
fun nukeTable()
}
But you can see that both getAll and nukeTable is still there. I hope to also make it into the BaseDao. Is there any way to do that?

Not sure how to handle insert method's return type. public abstract java.lang.Object insert(#org.jetbrains.annotations.NotNull()

I am complete new to kotlin, and trying to build a notes app using MVVM architecture. But somewhere I go wrong and end up with this error. My kotlin version is 1.5.31
NoteDao.java:11: error: Not sure how to handle insert method's return type.
public abstract java.lang.Object insert(#org.jetbrains.annotations.NotNull()
NoteDao.kt
#Dao
interface NoteDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(note:Note): Note
#Delete
suspend fun delete(note: Note): Note
#Query("SELECT * FROM notes_table ORDER BY primary_key ASC")
fun getAllNotes(): LiveData<List<Note>>
}
Note.kt
#Entity(tableName = "notes_table")
class Note(#ColumnInfo(name = "note_text", typeAffinity = TEXT) val text: String){
#PrimaryKey(autoGenerate = true) #ColumnInfo(name="primary_key", typeAffinity = INTEGER) var id = 0
}
I am not sure how to handle this.
Try doing this:
#Dao
abstract class BaseDao<T : BaseEntity>(private val tableName: String) {
#Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun insert(entity: T): Long
#Update
abstract suspend fun update(entity: T)
#Delete
abstract suspend fun delete(entity: T)
}
abstract class BaseEntity {
abstract val id: Long
}

How to pass parameters to a query on the Dao from the Repository?

Dao code:
#Query("SELECT * FROM word_table WHERE transaction_date BETWEEN :from_date AND :to_date")
fun findTransactionsBetweenDates(from_date: Long, to_date: Long): LiveData<List<Word>>
Repository Code:
public var from_date: Long = 0
public var to_date: Long = 0
val allWordsByDates: LiveData<List<Word>> = wordDao.findTransactionsBetweenDates(from_date, to_date)
#Suppress("RedundantSuspendModifier")
#WorkerThread
suspend fun WordsByDates(from_date:Long, to_date:Long): LiveData<List<Word>> {
return wordDao.findTransactionsBetweenDates(from_date, to_date)
}
I am suppose to observe the allWordsByDates from MyMainActivity, from there I am calling WordsByDates function through the viewModel with from and to dates, but they never change at the Repository they always 0. I tried to change the from_date and to_date from inside the WordsByDates function but that did not work, My last attempt was to assign the return value of WordsByDates function to allWordsByDates but that didn't work too. Any help with code will be appreciated.
it seems like the list is not static and changes by the selection, so I would change the Repository like this:
private val allWordsByDatesMLD = MutableLiveData<List<Word>>()
val allWordsByDates: LiveData<List<Word>> = allWordsByDatesMLD
#WorkerThread
suspend fun WordsByDates(from_date: Long, to_date: Long) {
allWordsByDatesMLD.postValue(wordDao.findTransactionsBetweenDates(from_date, to_date))
}
to work with Dao like this
#Query("SELECT * FROM word_table WHERE transaction_date BETWEEN :from_date AND :to_date")
suspend fun findTransactionsBetweenDates(from_date: Long, to_date: Long): List<Word>

Inheriting from a room DAO interface

I have following interface where I have created the standard crud methods and annotated the methods with insert, update, and delete.
interface BaseDao<T> {
#Insert
fun insert(table: T): Single<Long>
#Insert
fun insert(vararg table: T): Single<List<Long>>
#Update
fun update(table: T): Single<Int>
#Delete
fun delete(table: T): Single<Int>
}
I then create a interface for the DAO
#Dao
interface WeatherDao : BaseDao<WeatherTable> {
override fun insert(table: WeatherTable): Single<Long>
override fun insert(vararg table: WeatherTable): Single<List<Long>>
override fun update(table: WeatherTable): Single<Int>
override fun delete(table: WeatherTable): Single<Int>
#Query("SELECT * FROM weatherTable")
fun getAllWeather(): Single<List<WeatherTable>>
#Query("SELECT * FROM weatherTable WHERE id = :id LIMIT 1")
fun getWeatherById(id: Long): Single<WeatherTable>
#Query("SELECT count(*) FROM weatherTable")
fun count(): Single<Int>
}
When I compile I get a lot of error like this following:
error: An abstract DAO method must be annotated with one and only one of the following annotations: Insert,Delete,Query,Update,RawQuery
public abstract io.reactivex.Single<java.lang.Long> delete(#org.jetbrains.annotations.NotNull()
Because when I inherited from the interface. I have to manually add the #Insert, #Update, and #Delete.
Just wondering why these annontations are added automatically in the my WeatherDao interface.
So I now have to manually add them like this:
#Dao
interface WeatherDao : BaseDao<WeatherTable> {
#Insert
override fun insert(table: WeatherTable): Single<Long>
#Insert
override fun insert(vararg table: WeatherTable): Single<List<Long>>
#Update
override fun update(table: WeatherTable): Single<Int>
#Delete
override fun delete(table: WeatherTable): Single<Int>
#Query("SELECT * FROM weatherTable")
fun getAllWeather(): Single<List<WeatherTable>>
#Query("SELECT * FROM weatherTable WHERE id = :id LIMIT 1")
fun getWeatherById(id: Long): Single<WeatherTable>
#Query("SELECT count(*) FROM weatherTable")
fun count(): Single<Int>
}
Just wondering if I am using this wrong:
Following this google repo, you are not doing the abstractation correctly. To sum up, you do not need to have the inserts/updates/deletes in your #Dao Interface and it should be abstract.
interface BaseDao<T> {
/**
* Insert an object in the database.
*
* #param obj the object to be inserted.
*/
#Insert
fun insert(obj: T)
/**
* Insert an array of objects in the database.
*
* #param obj the objects to be inserted.
*/
#Insert
fun insert(vararg obj: T)
/**
* Update an object from the database.
*
* #param obj the object to be updated
*/
#Update
fun update(obj: T)
/**
* Delete an object from the database
*
* #param obj the object to be deleted
*/
#Delete
fun delete(obj: T)
}
#Entity(tableName = "data")
data class Data(#PrimaryKey val id: String, val value: String)
#Dao
abstract class DataDao : BaseDao<Data>() {
/**
* Get all data from the Data table.
*/
#Query("SELECT * FROM Data")
abstract fun getData(): List<Data>
}

How to create a generic Repository class? (Android)

in my Android app I use MVVM model with repositories
most of my DAO and Repositories classes are almost identical, so I figured I could reuse some code by creating generic equivalents that are later extended
this worked fine for my DAO classes:
#Dao
interface BaseDao<T> {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(vararg entity: T)
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertList(entities: List<T>)
#Update
suspend fun update(entity: T)
#Delete
suspend fun delete(entity: T)
}
#Dao
interface SettingDao : BaseDao<Setting> {
#Query("SELECT value FROM settings WHERE id = :settingName")
fun get(settingName: String): LiveData<String>
#Query("SELECT * FROM settings ORDER BY id ASC")
fun getAll(): LiveData<List<Setting>>
#Query("DELETE FROM settings")
suspend fun deleteAll()
}
now I want to do something similar for repository, but I cannot figure out how
this is what I've tried (I get error java.lang.ClassCastException: java.lang.Object[] cannot be cast to: Setting[]) in BaseRepository$insert$2.invokeSuspend
abstract class BaseRepository<T>(private val baseDao: BaseDao<T>) {
suspend fun update(entity: T) {
withContext(Dispatchers.IO) { baseDao.update(entity) }
}
suspend fun insert(entity: T) {
withContext(Dispatchers.IO) { baseDao.insert(entity) }
}
suspend fun delete(entity: T) {
withContext(Dispatchers.IO) { baseDao.delete(entity) }
}
}
class SettingRepository(private val settingDao: SettingDao) : BaseRepository<Setting>(settingDao) {
val company = settingDao.get("company")
val ip = settingDao.get("ip")
suspend fun deleteAll() {
withContext(Dispatchers.IO) { settingDao.deleteAll() }
}
}
My intuition is that I have to adjust this bit private val baseDao: BaseDao<T> in BaseRepository, but I cannot figure out how
And 2nd question - is there a way to get a generic table name in DAO, so I could put
#Query("DELETE FROM settings")
suspend fun deleteAll()
in the generic interface as well (in this case replace settings with entity's tableName

Categories

Resources