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

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?

Related

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
}

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

Count rows Android Room on Kotlin

learning Kotlin, proper app structure and stuff... Again... :)
So i have the following:
Dao
Repository
ViewModel
Dao Code
#Dao
interface ItemDao {
#Query("SELECT * from item_table ORDER BY Name ASC")
fun getSortedItems(): LiveData<List<Item>>
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(item: Item)
#Query("DELETE FROM item_table")
suspend fun deleteAll()
}
Repository
class ItemRepository (private val itemDao: ItemDao) {
val allItems: LiveData<List<Item>> = itemDao.getSortedItems()
suspend fun insert(item: Item) {
itemDao.insert(item)
}
}
ViewModel
class ItemViewModel(application: Application) : AndroidViewModel(application) {
private val repository: ItemRepository
val allItems: LiveData<List<Item>>
init {
val itemsDao = ItemDataBase.getDatabase(application, viewModelScope).itemDao()
repository = ItemRepository(itemsDao)
allItems = repository.allItems
}
fun insert(item: Item) = viewModelScope.launch {
repository.insert(item)
}
}
I need to get current amount of rows in a table and i was thinking of something like this:
add to Dao
#Query("SELECT COUNT(name) FROM item_table")
fun getAmount(): LiveData<Int>
and then in Repo
fun getAmount(): LiveData<Int>{
return itemDao.getAmount()
}
and the same in ViewModel
fun getAmount(): LiveData<Int> {
return repository.getAmount()
}
But again, should i also use an observer in Activity to get this value? Or, on the other hand, can i use just Int, while getting the table from DB as LiveData?

Room DB with coroutines insert callback

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>
}

Categories

Resources