In Slick 2.1 I had the code below to execute an sql-query from a file:
def fetchResult[T](sql: String)(implicit getResult: GetResult[T]): List[T] = {
val query = Q.queryNA[T](sql)
try {
Database.forDataSource(DB.getDataSource())
.withSession { implicit session => query.list }
}
catch {
case e: Throwable =>
throw new RunSqlException(s"Query $name execution error", e)
}
}
In Slick 3.0.0 you use dbConfig.db.run method to execute DBIOAction and get a future of the result. But I can't find a way to transform result of Q.queryNA (which is StaticQuery[Unit, R]) into DBIOAction. Does such a way exist?
I ended up with deprecated calls for now. Help me be better!
def fetchResult[T](sql: String)(implicit getResult: GetResult[T]): Future[List[T]] = Future {
val query = Q.queryNA[T](sql)
try {
this.dbConfig.db.withSession { implicit session => query.list }
}
catch {
case e: Throwable =>
throw new RunSqlException(s"Query $name execution error", e)
}
}
Only solution I managed to find was a bit hackish:
import slick.driver.HsqldbDriver.api._
def fetchResult[T](sql: String) = {
database.run(sqlu"""#$sql""")
}
Related
I wrote the following piece of code
def info(): MyCaseClass = {
Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} match {
case Failure(f) => {
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}
case Success(s) => s
}
}
Is there an even shorter way to deal with the fact that the file system operation could result in an exception so I handle it as above. Like can I not just somehow have to deal with failure case only. Like in case of Future exceptions, the future just does what it has to but for exceptions only we define recover and recoverWith. Something analogous is possible here?
Simply use try instead of Try:
def info(): MyCaseClass = {
try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} catch {
case f: Throwable => {
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}
}
}
Try has recover as well:
def info(): MyCaseClass = {
(Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} recover {
case f =>
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}).get
}
.getOrElse seems to be what you are looking for:
def info(): MyCaseClass = {
Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
}.getOrElse({
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
})
}
This question already has answers here:
Simple Scala pattern for "using/try-with-resources" (Automatic Resource Management)
(9 answers)
Closed 5 years ago.
I'm new to Scala and looked at source code of Try::apply
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
It simply catches non-fatal exceptions. But what if I need finally clause? Is it possible to emulate it with Try in a functional way? I mean something like
try{
//acquire lock
//do some
} finally {
// release lock
}
with
Try{
//acquire lock
//do some
}
//Now how to release?
Something similar was already answered here.
TLTR;
There is no standard way to do that with the Try monad.
The usual workaround is something like this:
def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B =
try {
code(resource)
} finally {
resource.close()
}
That you can use like:
val path = Paths get "/etc/myfile"
use(Files.newInputStream(path)) { inputStream ⇒
val firstByte = inputStream.read()
....
}
Another approach which is explained here, implies that you "extend" the standard 'Try' by adding an additional method 'withRelease'
implicit class TryOps[A <: { def close(): Unit }](res: Try[A]) {
def withRelease() = res match {
case Success(s) => res.close(); res
case Failure(f) => res.close(); res
}
}
Then,
Try {
val inputStream = Files.newInputStream(path))
...
inputStream
}.withRelease()
Since Try resolves to a value and it doesn't unwind the stack when something fails, you can simply perform the cleanup operations after Try has executed. For example:
val someLock = ??? // acquire some lock
val result = Try {
// do something and return a result
}
someLock.release()
If you prefer, you can roll your own helper to keep everything into a single expression:
def withLock[A](f: Lock => A): Try[A] = {
val lock = ??? // acquire the lock
val res = f(lock)
lock.release()
}
and then you can write:
val res = withLock { lock =>
// some operation
}
This is usually refered to as loan pattern.
Apache has IOUtils.closeQuietly(Closeable). In Scala, I'd like to generalize this: execute a block and ingore exceptions, while at the same time logging them. Something like this:
import LogUtils._
object Playground extends App {
implicit val logger_ = LoggerFactory.getLogger(getClass)
silentLog {
println("block")
throw new Exception("an exception")
}
println("end")
}
import org.slf4j.{Logger, LoggerFactory}
import scala.util.control.NonFatal
object LogUtils {
def silentLog[U](f: => U)(implicit log: Logger) {
try f
catch {
case NonFatal(e) => log.error(null, e)
}
}
}
Is this already implemented in some common library?
Try[T] does this to some extent but does not log the exception. Try does try .. catch ... inside
def LoggingTry[T](f: => T)(implicit logger: Logger): Try[T] = Try(f()).recoverWith {
case th =>
logger.log(th)
Try { throw th }
}
Use getOrElse(()) if you want to get value in case of success and default value (Unit) in case of failure
I'm using Play framework by Scala. I have Postgresql database. It fetches data by following code:-
def eventById(id: Long): Option[EventRow] = {
val action = events.filter(_.id === id)
val results = db.run(action.result.head)
val notFound = None: Option[EventRow]
try {
Some(Await.result(results, Duration.Inf))
} catch {
case e: Exception => Logger.info(s"Failed to fetch event by id: $e.")
notFound
} finally {
}
}
}
Here in case data not bound it throws exception. Here I don't want to throw exception.I want to return notFound. I cannot even compile without throwing Exception.
Is there a way to return notFound if event not found in database?
Please let me know? Thanks!
Try:
def eventById(id: Long): Option[EventRow] = {
val action = events.filter(_.id === id)
val res: Future[Option[EventRow]] = db.run(action.result.headOption)
Await.result(res, Duration.Inf)
}
In my current method, I am trying to make a series of calls and if any of them fail, I want to be able to continue running the remainder (while capturing the Exception that was thrown). I am having a hard time figuring this out in Scala.
So in this example, I want to kick off each of these calls - RunA, RunB and RunC but if RunB throws an exception, I want to print that and continue kicking off RunC after that.
var result = Try {
new RunA()
new RunB()
new RunC()
} catch {
case e: Throwable => e.printStackTrace()
false
}
Outside of having them all individually wrapped in a Try/Catch, I am sure there are better ways to do this which is why I am hoping someone can help with this.
I looked at the 'Ignoring' exception but it appears to completely ignore the exception which I want to atleast log.
Thanks!
First, don't mix try { ... } catch { ... } up with scala.util.Try{ ... }.
You can
import scala.util._
val runA = Try{ new RunA }
val runB = Try{ new RunB }
val runC = Try{ new RunC }
and then deal with the exceptions as you see fit. For instance, if you want to print and continue, you could deal with the try statements right there:
def getOrPrint[A](f: => A): Option[A] = Try{ f } match {
case Success(x) => Some(x)
case Failure(e) => e.printStackTrace; None
}
getOrPrint{ new RunA }
...
There can be more elegant ways for such things with scalaz (e.g. read an article here for some inspiration: http://johnkurkowski.com/posts/accumulating-multiple-failures-in-a-ValidationNEL/), but with "only" Scala you can do something like this:
import scala.reflect.ClassTag
import scala.util.{Try, Success, Failure}
def tryAndLog[T: ClassTag] = Try {
implicitly[ClassTag[T]].runtimeClass.newInstance.asInstanceOf[T] // new instance
} match {
case Success(_) => true
case Failure(ex) => ex.printStackTrace ; false
}
def tryRunAll = {
val A = tryAndLog[RunA]
val B = tryAndLog[RunB]
val C = tryAndLog[RunC]
A && B && C // returns true if all invocations succeeded, false otherwise
}
You are mixing scala.util.Try with try {} catch {} which are different concepts. Try wraps function into Success(result) or Failure(error) class, and try-catch is like Java try-catch. I suggest you something like this:
class RunA
class RunB
class RunC
class Result(a: RunA, b: RunB, c: RunC)
implicit class LogFailure[T](t: Try[T]) {
def logFailure: Try[T] = t match {
case scala.util.Failure(err) => err.printStackTrace(); t
case _ => t
}
}
val tryA= Try(new RunA())
val tryB= Try(new RunB())
val tryC = Try(new RunC())
val result: Try[Result] = for {
a <- tryA.logFailure
b <- tryB.logFailure
c <- tryC.logFailure
} yield {
// do smth with a, b, c
new Result(a, b, c)
}
If A, B, C will be successful you'll get Success(Result) if one of them failure you'll get Failure with first exception, however all of them will be logged (printed stack trace)