Reputation: 1105
Sorry for the bad title
Basically I have a db query that returns None
or Some
I want to do a for comprehension over it
val sentMessage = for {
action <- actionO;
user <- userO;
message <- messageModel.findByActionID(action.id)
}
But the "extra" something for None; is to do some logging
So (psuedo code)
val sentMessage = for {
action <- actionO if actionO is undefined Log("We could not find user)
Lift web has the type Box; which has this feature http://simply.liftweb.net/index-7.2.html
id <- S.param("id") ?~ "id param missing" ~> 401
I'm currently using Play - so perhaps there is somthing in there I could leverage?
EDIT - using orElse I now have; can this be cleaned up any more?
val sentMessage = for {
action <- findByName(actionName).orElse({Logger.error("Can't find action by name " + actionName); None});
user <- userModel.findByPk(userID).orElse({Logger.error("Can't find user by id " + userID); None});
} yield {
val channels
Thanks
Upvotes: 1
Views: 302
Reputation: 16324
You might consider using an Either
is this case. By convention you often hold an error message in Left
and the successful value in Right
. You can convert an Option
to an Either
by doing:
val myEither = myOption.toRight("This is an error message")
Then you can use an Either
in a for comprehension as:
val transformed = for {
x <- myEither.right
} yield x * 3
And then you can propagate this error message for as long as you want, and print it when it suits you.
Upvotes: 1
Reputation: 1849
You can use a fold to convert an Option
to a Try
:
intOpt.fold[Try[Int]](Failure(<some exception>))(Success(_))
Then when you're processing your results you just match on the Try
, act on the successes, and log on the failures.
// dummy function acting like your db lookup
def sometimesWorks(i: Int): Option[Int] = i match {
case 1 => Some(i)
case _ => None
}
// function to convert an Option bearing something to a Try
def asTry[T](in: => Option[T], reason: String): Try[T] = {
in.fold[Try[T]](Failure(new RuntimeException(reason)))(Success(_))
}
val ints = Vector(0,1,2)
val trys = ints.map((x) => asTry(sometimesWorks(x), "Failed due to sometimesWorks."))
trys.map { t =>
// Try can be used in the comprehension as well, will propogate errors.
val result = for {
x <- t
y = x * 3
z = y + 20
} yield z
// use a match on the results
result match {
case Success(v) => println(s"Worked: $v")
case Failure(e) => println(s"Logging failure: ${e.getMessage}")
}
}
Results in:
Logging failure: Failed due to sometimesWorks.
Worked: 23
Logging failure: Failed due to sometimesWorks.
Upvotes: 1