Currently, my goal is to communicate with DB using CRUD approach. Between simple operation i may have some extra steps (additional business-logic which may throw some errors).
import cats.effect.IO
import scalikejdbc._
IO(NamedDB(MyDB) localTx {
implicit session => {
val x = for {
a <- IO(select()) // Option[Something] (1)
_ <- IO(log(a)) // Option[Something] (2)
_ <- IO(insert()) // Something (3)
_ <- IO(insert()) // Something (4)
c <- IO(select()) // Option[Something] (5)
r <- IO(fileSystemOperation(a, c)) // (6)
_ <- operation(r) // Either[Throwable, Unit] (7)
} yield ()
x.unsafeRunSync() // (8)
}
}).attempt.unsafeRunSync() match { // (9)
case Left(value) => println("Error")
case Right(value) => println("Success") // in reality i want to return some result here
}
The first problem comes in (2)
: i got error:
Error type mismatch; found : cats.effect.IO[Unit] required: Option[?] _ <- IO(log(a))
But if i log result of any insert ((3)
or (4)
) then all is ok. Probably, it's because of difference in result type Option[Something]
vs Something
, but i thought that it would be the same as this:
for {
a <- Option(1)
....
}
The second question is how to correcly handle errors in (7)
to rollback transaction? Do i have to use pattern matching and do something like this:
operation(r) match {
case Left(e) => throw e
}
or i can throw error inside my operation
and return Unit
instead of Either[Throwable, Unit]
?
Also, i have question about (8)
and (9)
. Is it a correct way to start actual processing and handle any error or not?
I tried to do the same steps using this approach:
select() match {
case Some(_) =>
.....
operation(r) match {
case Left(e) => throw e
case Right(_) => ....
}
case None => ....
}
But in result i got too deep match-case
clauses and it was hard to read and understand.
I'm new to FP, but i want to implement this in FP way.