Dao class must be annotated with #Dao - kotlin

#Dao
interface UserDao {
#Insert (onConflict = OnConflictStrategy.IGNORE)
suspend fun addUser(user:User)
#Query("SELECT * FROM user ORDER BY id DESC")
suspend fun getAllUser():List
#Update(onConflict = OnConflictStrategy.IGNORE)
suspend fun updateUser(user: User)
#Delete
suspend fun deleteUser(user: User)
}
Dao class must be annotated with #Dao

Related

Kotlin inline functions in Interfaces

I'd like to have an interface and implementing class/object similar to the following:
interface EventBus {
suspend fun <T : Message> publish(message: T)
suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S>
suspend fun close(): Either<EventbusError, Unit>
//? fun <T : Message> subscribe(): Flow<T>
}
object EventBusImpl : EventBus {
private val _eventBus = MutableSharedFlow<Message>()
val messages = _eventBus.asSharedFlow()
override suspend fun <T : Message> publish(message: T) {}
override suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S> {}
override suspend fun close(): Either<EventbusError, Unit> {}
inline fun <reified T:Message> subscribe():Flow<T> = messages.filterIsInstance<T>()
}
I understand that inline functions cannot be over overridden and thus cannot be part of an interface, but as the subscribe() function is an important part of the API, I'd still like to represent it somehow in the interface, without falling back to passing a Class<T> as an argument.
How could this be accomplished?
This
interface EventBus {
suspend fun <T : Message> publish(message: T)
suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S>
suspend fun close(): Either<EventbusError, Unit>
suspend fun <T : Message> subscribe(type: Class<T>): Flow<T>
}
of course works, but is not very Kotlin'ish

Spring data mongo using CoroutineCrudRepository

I am trying to use new Spring data reactive approach using CoroutineCrudRepository in a Kotlin project.
Github repository link: https://github.com/cristianprofile/spring-data-CoroutineCrudRepository-test
This is my application's code:
#SpringBootApplication
class DemoApplication
data class PersonDto(val age: Int, val name : String)
#RestController
#RequestMapping("/persons")
class PersonController (val personService: PersonService)
{
#GetMapping
suspend fun getPersons() = personService.getAll()
#PostMapping
suspend fun savePerson(#RequestBody personDto: PersonDto) = personService.save(personDto)
}
interface PersonService {
suspend fun getAll(): Flow<Person>
suspend fun getById(id: String): Person?
suspend fun save(personDto: PersonDto): Person
}
#Service
class PersonServiceImpl (private val personRepository: PersonRepository ) : PersonService
{
override suspend fun getAll(): Flow<Person> {
return personRepository.findAll()
}
override suspend fun getById(id: String): Person? {
return personRepository.findById(id)
}
override suspend fun save(personDto: PersonDto): Person
{
return personRepository.save(personDto.convertToPerson())
}
}
fun PersonDto.convertToPerson() =
Person(
name = name,
age = age
)
#Document
data class Person (#Id val id: String? = null, val age: Int, val name : String)
#Repository
interface PersonRepository: CoroutineCrudRepository<Person, String>
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
When I try to start my Spring boot project
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.lang.Object org.springframework.data.repository.kotlin.CoroutineCrudRepository.count(kotlin.coroutines.Continuation); Reason: No property 'count' found for type 'Person'; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property 'count' found for type 'Person'
at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) ~[spring-data-commons-2.7.3.jar:2.7.3]
I don't know why "No property 'count' found for type" error is thrown. Which would be the way to be able to use CoroutineCrudRepository using Spring data mongo repository?

Why My Database Column List Returning Unit

ı am trying to use a method which is getValues(). Im trying to take all my value variable from my SQL table and trying to make an addition with them. At the end, ı am trying to print my "value list" but it is just returning "Unit". The result that ı'm trying to reach: sum them all and get the total result.
var incomeList: List<Int> = mIncomeViewModel.getValues() // it is automaticly corrects me as incomeList: Unit
#Dao
interface IncomeDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addIncome(income: Income)
#Update
suspend fun updateIncome(income: Income)
#Delete
suspend fun deleteIncome(income: Income)
#Query("DELETE FROM income_table")
suspend fun deleteAllIncomes()
#Query("SELECT * FROM income_table ORDER BY id ASC")
fun readAllData(): LiveData<List<Income>>
#Query("SELECT value FROM income_table ")
fun getValues(): LiveData<List<Int>>
}
class IncomeRepository (private val incomeDao: IncomeDao) {
val readAllData: LiveData<List<Income>> = incomeDao.readAllData()
suspend fun addIncome(income: Income){
incomeDao.addIncome(income)
}
suspend fun updateIncome(income: Income){
incomeDao.updateIncome(income)
}
suspend fun deleteIncome(income: Income){
incomeDao.deleteIncome(income)
}
suspend fun deleteAllIncomes(){
incomeDao.deleteAllIncomes()
}
fun getValues(): LiveData<List<Int>> {
return incomeDao.getValues()
}
}
class IncomeViewModel(application: Application): AndroidViewModel(application) {
val readAllData: LiveData<List<Income>> //if anything happens by the private of this variable make it public again
private val repository: IncomeRepository
init {
val incomeDao = IncomeDatabase.getDatabase(application).incomeDao()
repository = IncomeRepository(incomeDao)
readAllData = repository.readAllData
}
fun addIncome(income: Income){
viewModelScope.launch(Dispatchers.IO){
repository.addIncome(income)
}
}
fun updateIncome(income: Income){
viewModelScope.launch(Dispatchers.IO){
repository.updateIncome(income)
}
}
fun deleteIncome(income: Income){
viewModelScope.launch(Dispatchers.IO) {
repository.deleteIncome(income)
}
}
fun deleteAllIncomes(){
viewModelScope.launch(Dispatchers.IO) {
repository.deleteAllIncomes()
}
}
fun getValues(){
viewModelScope.launch(Dispatchers.IO) {
repository.getValues()
}
}
}
Edit:
I fixed my problem with returning the ViewModel methods as LiveData<List>
fun getValues(): LiveData<List<Int>>{
return repository.getValues()
}

kotlin interfaces, sealed classes and generic types usage (using child classes of generic types in interface functions)

I have this sealed class
sealed class S3FileUploaderRequest {
abstract val s3Configuration: S3Configuration
data class S3UploadRequest(
val uploadData: S3UploadData,
override val s3Configuration: S3Configuration
) : S3FileUploaderRequest()
data class S3DeleteRequest(
val path: String,
override val s3Configuration: S3Configuration
) : S3FileUploaderRequest()
data class S3MultiUploadRequest(
val multiUploadData: List<S3UploadData>,
override val s3Configuration: S3Configuration
) : S3FileUploaderRequest()
data class S3MultiDeleteRequest(
val paths: List<String>,
override val s3Configuration: S3Configuration
) : S3FileUploaderRequest()
}
And this interface:
interface FileUploader<T, S> {
suspend fun multiUploadFile(request: T): S
suspend fun multiDeleteFile(request: T): List<S>
suspend fun uploadFile(request: T): S
suspend fun deleteFile(request: T): S
}
I would like to use the child classes of data class S3FileUploaderRequest es entry parameter of interface functions, somethig like this:
interface FileUploader<T, S> {
suspend fun multiUploadFile(request: out T): out S
suspend fun multiDeleteFile(request: out T): List<S>
suspend fun uploadFile(request: out T): out S
suspend fun deleteFile(request: out T): out S
}
Is possible to do this? I feel like kotlin should be able to do this but don't find the proper syntax for it.
Update:
I would like to implement the interface this way:
#Singleton
class S3FileUploader() : FileUploader<S3FileUploaderRequest, S3FileUploaderResponse> {
override suspend fun uploadFile(request: S3UploadRequest): S3UploadResponse {
//DO STUFF
}
override suspend fun deleteFile(request: S3DeleteRequest): S3DeleteResponse {
//DO STUFF
}
override suspend fun multiUploadFile(request: S3MultiUploadRequest): S3MultiUploadResponse {
//DO STUFF
}
override suspend fun multiDeleteFile(request: S3MultiDeleteRequest): List<S3DeleteResponse> {
//DO STUFF
}
}

Android Room + Kotlin pattern

the Android Room documentation says that we should follow the singleton design pattern when instantiating an AppDatabase object.
I was thinking about it, and I would like to know if its recommended to put the AppDatabase class inside my Application class. Or if I can use the Kotlin singleton for that.
Let's say I have a DAO called CarroDAO and class CarrosDatabase that is a RoomDatabase.
Is it ok to create a DatabaseManager class using a Kotlin object/singleton ?
object DatabaseManager {
private var dbInstance: CarrosDatabase
init {
val appContext = MyApplication.getInstance().applicationContext
dbInstance = Room.databaseBuilder(
appContext,
CarrosDatabase::class.java,
"mybd.sqlite")
.build()
}
fun getCarroDAO(): CarroDAO {
return dbInstance.carroDAO()
}
}
So I can get the DAO class like this:
val dao = DatabaseManager.getCarroDAO()
According to Android documentation, we can create a database instance using the singleton design pattern as follows
Create a room database entity
#Entity
data class User(
#PrimaryKey var uid: Int,
#ColumnInfo(name = "first_name") var firstName: String?,
#ColumnInfo(name = "last_name") var lastName: String?
)
Create DAO class
#Dao
interface UserDao {
#Query("SELECT * FROM user")
fun getAll(): List<User>
#Query("SELECT * FROM user WHERE uid IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
#Query("SELECT * FROM user WHERE first_name LIKE: first AND " +
"last_name LIKE :last LIMIT 1")
fun findByName(first: String, last: String): User
#Insert
fun insertAll(vararg users: User)
#Delete
fun delete(user: User)
}
Create database with singleton pattern
#Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
#Volatile
private var instance: AppDatabase? = null
fun getInstance(
context: Context
): AppDatabase = instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"database-name"
).build()
}
}
}
You can get database instance by following code
var databaseInstance=AppDatabase.getInstance(context)