Kotlin Spring JPA Reactive overcoming the default exception - kotlin

I had a problem which was,
When have a unique constraint in the DB query,
and then want to insert it again,
I wanted to override the default exception.
like when having a DB table like this
CREATE TABLE IF NOT EXISTS $ENROLLED_USERS_TABLE (
id INT AUTO_INCREMENT PRIMARY KEY,
$USERS_FIELD VARCHAR(250) NOT NULL UNIQUE
);
and the repo like this
#Repository
interface UserRepository: ReactiveCrudRepository<User, Int>{
#Modifying
#Query("insert into $ENROLLED_USERS_TABLE ($USERS_FIELD) values (:user)")
fun insertUser(#Param("user") user: String?): Mono<Void?>?
}
this is my controller
#PostMapping("/{user}")
suspend fun add(#PathVariable user:String): Void? = userRepository.insertUser(user)?.awaitFirstOrNull()
I have tried to put them in try and catch but it didn't work
to catch the
#Service
class UserService(val userRepository: UserRepository) {
suspend fun add(user:String) {
try {
// some code
userRepository.insertUser(user)?.onErrorReturn(throw ResourceAlreadyExists("User Already exists"))
}
catch (e: SQLException) {
println("Custome Message")
}
}
}
nothing worked I still get the exception that shows my database query :/

the solution was simple
#PostMapping("/{user}")
suspend fun add(#PathVariable user:String): Void? = userRepository.insertUser(user)?.onErrorMap { throw ResourceAlreadyExists("User Already Exists") }?.awaitFirstOrNull()
mapping the error was the right one

Related

Transaction with room to update multiple rows doesn't update

I'm facing an issue with Room on Android.
I have a DAO with multiple methods
#Insert(onConflict = OnConflictStrategy.ABORT)
suspend fun insertEntity(entity: Entity)
#Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun updateEntity(entity: Entity)
#Transaction
suspend fun insertOrUpdateEntities(entities: List<Entity>) {
entities.forEach { entity ->
try {
insertEntity(entity)
} catch (sqlException: SQLiteConstraintException) {
updateEntity(entity)
}
}
(I simplify the catch part, I change the object entity to do some merge of fields)
But, while the entity object in "updateEntity" is correct, the database is not update with the new values.
Do you have an idea why?
Thanks!
I would suggest not raising an ABORT but instead using
#Insert
suspend fun insertEntity(entity: Entity): Long
#Update
suspend fun updateEntity(entity: Entity): Int
#Transaction
suspend fun insertOrUpdateEntities(entities: List<Entity>) {
entities.forEach { entity ->
if (insertEntity(entity) < 1) {
updateEntity(entity)
}
}
}
by default #Insert has onConflictStrategy.IGNORE, so PRIMARY KEY, UNIQUE, NULL and CHECK conflicts will be ignored.
the #Insert method can return a long (the rowid of the inserted row, or -1 if the row was not inserted), so obtaining that can be used to determine whether or not the row was inserted.

Room + Kotlin Flow not emitting result

i'm trying to fetch some data from api, and them store on room database, so the main data source is roomDatabase.
my repository code looks like:
suspend fun fetchData(): Flow<Response<List<Foo>>> {
val shouldRequestData = dao.getFoo().isEmpty()
return if (shouldRequestData) {
getFoo()
} else getLocalFoo()
}
override suspend fun getFoo(): Flow<Response<List<Foo>>> {
return ....... request done normally... inserting normally on database (and showing
on database inspector)
}
override suspend fun getLocalFoo(): Flow<Response<List<Foo>>> = flow {
dao.getFoo().transform<List<FooLocal>, Response<List<Foo>>> {
Response.Success(
it.map {
it.toDomainModel()
}
)
}
}
on Dao:
#Query("SELECT * FROM localdb")
fun getFoo(): Flow<List<Foo>>
and then collecting it normally on viewmodel...
The problem is: the data is not appearing.. how could i solve this? The non-flow version works :/
I already searched for this problem, but nothing seems to work.
Solved by putting this on getLocalFoo() ->
val result: Flow<Response<List<Foo>>> =
Transformations.map(dao.getFoo()) {
Response.Success(it?.map {
it.asDomainModel()
} ?: emptyList()
}.asFlow()
return result
I have found a solution to investing so much time.
Solution: Same Dao Object should be used when we insert details into the room database and get information from DB.
If you are using dagger hilt then
#Singleton annotation will work.
I hope this will solve your problem.

Kotlin Null pointer exception

I'm trying to display emails of users stored in firebase database.
I've this below code
snapsListView = findViewById(R.id.snapsList)
val adapter = emails?.let { ArrayAdapter(this, android.R.layout.simple_list_item_1, it) }
snapsListView?.adapter = adapter
auth.currentUser?.uid?.let { FirebaseDatabase.getInstance().getReference().child("users").child(it).child("snaps").addChildEventListener(object: ChildEventListener{
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
emails?.add(snapshot.child("from").value as String)
adapter?.notifyDataSetChanged()
try {
for(x in emails!!){
Log.i("Emails", x)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
Emails are present in the database and as per the hierrarchy also, users-> uid->snaps and snaps contains the email in "from"
Don't know what is causing this error, or how do i resolve this.
Always getting null pointer exception
By using !! operator you have asserted that emails is not null. However, Kotlin thrown runtime exception because emails is null actually. Consider replacing !! with safe-access:
emails?.let { for (x in it) Log.i("Emails", x) }

Kotlin functional way

I'm trying to perfect myself in Kotlin with functional programming. And then I did this:
I was tired of the way I write try - catch, and created the following function:
package com.learning.functionalway
fun <T> tryCatch(t: T?, excpetion: (Throwable)): T? = try {
t
} catch (e: Exception) {
throw excpetion
}
And I used it like this:
#Service
class ProductService(val repository: IProductRepository, val repositoryS: IStockRepository) : IService<Product, ProductModel> {
override fun find(id: Long) = tryCatch(
repository.find(id),
DataNotFound("Product not found"))
other methods ..
}
And my exception that I deal in the "Exception Handler"
class DataNotFound(message: String?) : Exception(message) {
}
Is this a correct way I used to modify the way I use try - catch?
Or are there better ways to do it?
Your solution is not a "more functional" way of doing error handling but rather just arguably a slight improvement in try-catch syntax.
If you truly want to embrace functional programming, I'd recommend you to check out Arrow. The standard Kotlin library is not enough for advanced functional programming concepts (such as error handling) and Arrow fills that gap.
You can read their documentation on how to do proper error handling.
If you fancy a talk about it, I'd recommend you to check out this video (topic of error handling starts here) which is about Kotlin and functional programming.
One way to remake the try-catch syntax to make it more functional is like this:
sealed class Try<out Output> {
class Some<Output>(val output: Output) : Try<Output>()
class None(val exception: Exception) : Try<Nothing>()
companion object {
operator fun <Output> invoke(toTry: () -> Output) = try {
Some(toTry())
} catch (e: Exception) {
None(e)
}
}
val value get() = when(this) {
is Some -> output
is None -> null
}
infix fun catch(onException: (Exception) -> Unit): Output? = when (this) {
is Some -> output
is None -> {
onException(exception)
null
}
}
}
class ProductService(val repository: IProductRepository, val repositoryS: IStockRepository) : IService<Product, ProductModel> {
override fun find(id: Long): Product? = Try {
repository.find(id)
} catch { exception ->
println("Error trying to get product $exception")
}
//other methods ..
}
The key advantage here is that unlike in the original syntax you can do things by parts. So if you have a lot of tries to do and want to handle all the results at the end, with this syntax you can.

Wrapping all inner methods with the same try-catch in Kotlin

Consider this simple class:
class Foo {
fun a(x: Int) = ...
fun b(x: Int) = ...
fun c(x: Int, y: Int) = ...
}
Any of the class functions might throw an exception. In that case I would like to log the input parameters of the method. I could either manually write the try-catch blocks in every single method - but they would make the code ugly and duplicate. Or - I could try to find some nice solution to keep the code tidy.
Is there a way to generate the try-catch block automatically and define what it should do? Something like:
class Foo {
#WithTryCatch fun a(x: Int) = ...
#WithTryCatch fun b(x: Int) = ...
#WithTryCatch fun c(x: Int, y: Int) = ...
fun executeOnCatch() {
log.fatal(...)
}
}
You could create an higher order function which you pass your code block to and handle the exception there:
inline fun <T,R> safeExecute(block: (T)->R): R {
try{
return block()
} catch (e: Exception){
// do your handle actions
}
}
Now you can use it in your functions:
fun a(x: Int) = safeExecute{
//todo
}
It’s an easy, clean and readable solution using simple concepts.
EDIT:
For enabling the error logging, you can pass a second argument of type ()->String which will provide a message in case of an error.
inline fun <T,R> safeExecute(errorMsgSupplier: () -> String, block: (T) -> R): R {
try{
return block()
} catch (e: Exception){
// do your handle actions
log.fatal(errorMsgSupplier())
}
}