I was wondering why the following function doesMsgExist() always returns false even when the results from the DB is not empty.
def doesMsgExist(name: String, age: String): Boolean = {
var result = false
val msgExistsFlag = checkExistingMessages(db.getDocument(name, age))
msgExistsFlag.foreach(isTrue => result = if(isTrue) false else true)
result
}
def checkExistingMessages(resultFromDB: Future[List[BSONDocument]]): Future[Boolean] = {
resultFromDB.map { list =>
if (list.isEmpty) {
false
}
else true
}
}
You are immediately returning the result but you are using a Future to evaluate it. That means that the object which represents the computation is being created but you have no guarantee when that computation will resolve. Hence, the value you return is false.
Think of a Future as a place holder for some action which will happen in the future. If you want to capture the actual result you should do something with a signature like this:
def doesMsgExist(name: String, age: Boolean): Future[Boolean] =
and have the evaluation returned with the Future. If not, you're going to have to surround it by an Await.
Related
I have a Future [ProductSettings] which is returned from getProductSettingsMethod. Now I need the true or false from the clearedCanLoad field
def getEmployerProductSettingsQuery(employer: Employer): DBIOAction[ProductSettings, NoStream, Effect.Read] = {
val productSettingsQ = productSettingsQuery.filter(_.employerId === employer.id).result
productSettingsQ.map(_.headOrServerException(s"Could not find ProductSettings for employer ${employer.id}"))
}
def getEmployerProductSettings(employer: Employer): Future[ProductSettings] =
db.run(getEmployerProductSettingsQuery(employer))
I tried .map, filter, flatMap etc. but none is working
def cleared (employer : Employer) :Boolean = {
val f : Future[ProductSettings] =
getEmployerProductSettings(employer)
val iscleared: Boolean = f.filter { x =>
x.clearedCanLoadSpenditCards match {
case true =>
true
case false =>
false
}
}
}
This is not working also not working is filter
val f : Future[ProductSettings] = getEmployerProductSettings(employer)
val iscleared = f .
.filter(_.clearedCanLoadSpenditCards.equals(true)).equals(true)
case class ProductSettings(id: Long,
employerId: Long,
enableCard: Boolean,
enableLt: Boolean,
enableLtRefundDays: Boolean,
enableLtConversion: Boolean,
enableLtOPayment: Boolean,
clearedCanLoad: Boolean,
clearedAt:Option[LocalDateTime]) {
equals true should return boolean but i get a Future[Boolean] back. How can i extract an Boolean
The main purpose of the Future is to execute code asynchronously. Blocking the future to get the value from it defeats the purpose of it. But if you really need the cleared method to return Boolean you can block the future until its value is resolved.
You can achieve this by using Await:
import scala.concurrent.duration._
val result: ProductSettings = scala.concurrent.Await.result(f, 1 second)
This will wait for the future be resolved. If a second passes and f is still not resolved this will throw a TimeoutException.
scala.concurrent.Await#result
I have a method that returns a Future[Boolean] in a Play controller and i want to evaluate that using async but i can't seem to get it to compile.
The following will work:
def health = Action {
logger.info("Endpoint method: health")
val isHealthy = healthCheckService.checkDynamo()
val b: Boolean = Await.result(isHealthy, scala.concurrent.duration.Duration(5, "seconds"))
Ok(Json.toJson(HealthCheckResponse(b.toString)))
}
But i don't think i want that Await in there. So i'm trying things like this with no success:
def health =
Action.async {
Future {
logger.info("Endpoint method: health")
healthCheckService.checkDynamo() match {
case Future.successful(true) => Ok(Json.toJson("false"))
case false => Ok(Json.toJson("true"))
}
val r = healthCheckService.checkDynamo() match {
case true => Ok(Json.toJson("false"))
case false => Ok(Json.toJson("true"))
}
}
}
I can't even get those to compile to test them out.
Any suggestions?
Try this:
def health = Action.async {
healthCheckService.checkDynamo().map {
case true => Ok(Json.toJson("false"))
case false => Ok(Json.toJson("true"))
}
}
Let Play handle the awaiting for you under the hood. That is, Action.async accepts a Future, which checkDynamo() already returns. All you have to do is map it to the appropriate result.
With Futures you have to use combinators like map and flatMap to express the final value. For example:
Action.async {
healthCheckService.checkDynamo()
.map { result => // boolean
HealthCheckResponse(result.toString)
}
.map(Json.toJson(_))
.map(Ok(_))
}
(You can merge maps above to one map and construct the final Ok value there; it is more or less a matter of taste)
If you have, say, two async calls which you want to execute and return a result based on their results, you can use flatMap, which could be easily expressed using a for comprehension:
Action.async {
for {
result1 <- someService.someCall()
result2 <- anotherService.anotherCall(result1.someProperty)
finalResult = SomeFinalResultType(result1, result2)
} yield Ok(Json.toJson(finalResult))
}
If you are not familiar with futures, you might want to read some tutorial which explains their nature, how to combine them and how to get useful results from them, like this one: http://hello-scala.com/920-scala-futures.html
I am a student who studies Scala in korea. I am learning about pattern matching and unapply methods. The thing I am confused about is that Emergency object has a parameter in unapply method. I can't know the reason when I don't put the parameter in the match block.
object Solution {
def main(args: Array[String]) {
val number1 = "010-123-1234"
val number2 = "119"
val number3 = "포도먹은 돼지"
val numberList = List(number1, number2, number3)
for (number <- numberList) {
number match {
case Emergency() => println("긴급전화다")
case Normal(number) => println("일반 전화다" + number)
case _ => println("판단할 수 없습니다.")
}
}
}
}
object Emergency {
def unapply(number: String): Boolean = {
if (number.length == 3 && number.forall(_.isDigit)) true
else false
}
}
object Normal {
def unapply(number: String): Option[Int] = {
try {
Some(number.replaceAll("-", "").toInt)
} catch {
case _: Throwable => None
}
}
}
Notice that return types of to unapply methods are different.
Normal.unapply returns an Option. When you do case Normal(foo), unapply is called, and, if it returns Some(number), the match is successful, and the number is assigned to local variable foo, and if it returns None, match fails.
Emergency.unapply returns a Boolean, so case Emergency() succeeds if it returns true, and fails otherwise, but there is no result to assign in case of success, thus, no "parameter".
The parameter in unapply is the object on which you are matching.
In this case the number String variable is passed to Emergency.unapply, Normal.unapply etc.
This link explains things nicely:
https://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html
I have read up on why using "null" in Scala is not encouraged. But I am having trouble with a method which I would like to return an "empty" Boolean that is neither true or false under certain conditions.
def exampleMethod (query: String): Boolean =
{
var result: Boolean = false
try
{
//This will take the input query and return "true" or "false"
//depending on the state of the database
result = boolQueryResult.evaluate()
return result
}
catch
{
case e: Throwable => logger.info(e.toString)
}
logger.info("Something is wrong! I want to return a boolean with nothing in it!")
return result
}
In the above code, I am using the evaluate() method which will return true or false, and then that value will be returned in the Boolean. But if something goes wrong and the catch block is executed, I want to return a Boolean that is not true or false, to show that there was an error with the input string. In the current version of this method, the Boolean is initialized to "false," which is not ideal because it indicates that evaluate() returned false, not that the catch block was executed. Is there a way to initialize this variable in a way that it will not return "true" or "false" if the exception is thrown?
#bipll is right. Option[Boolean] is the Scala way to do what you want. This is how it's done.
def exampleMethod(query: String): Option[Boolean] =
try {
Some(boolQueryResult.evaluate())
} catch {
case e: Throwable => logger.info(e.toString)
None
}
Although the other answers suggest an Option (returning either Some(true), Some(false), or None, you lose the error message in the case where None is returned. For this reason, I would suggest instead using Try with Either.
An example might look like this:
import scala.util.{Either, Left, Right}
import scala.util.{Failure, Success, Try}
// Notice the return type: we either return the error as a Left(...), or a Right(boolean result)
def exampleMethod (query: String): Either[Throwable, Boolean] = {
// Is this where you meant to use `query`? It's not used in your original post
Try(boolQueryResult.evaluate(query)) match {
case Success(result) => Right(result)
case Failure(exception) => Left(exception)
}
}
This way, the caller of the method can decide what to do. For example, you can pattern match on the result of this method and turn a Left(exception) into None while logging an error:
val queryResult: Option[Boolean] = exampleMethod("bad_query") match {
case Right(result) => Some(result)
case Left(exception) => {
Logger.warn(s"There was an issue with exampleMethod: ${exception.getMessage}", exception)
None
}
}
You can use the Option class:
https://www.scala-lang.org/api/current/scala/Option.html
This is a good case for the Try type
def exampleMethod (query: String): Try[Boolean] =
{
Try
{
//If this throws an exception, it will be caught within the Try as a Failure
// and can be handled later, otherwise the result is stored in a Success
boolQueryResult.evaluate()
}
}
Try can wrap an expression that can fail. It will contain the value in Success, if an exception is thrown, the then the Try will contain that exception instead in a Failure. You can then operate on the value with methods such as map, flatmap and foreach. Even better would be to modify your evaluate method to return a Try or some other appropriate type instead of throwing the exception, but that is not always possible.
return is unneccessary and not recommended in Scala. The result of the last expression in a method will be automatically returned
Another option is to not use Boolean at all. The trouble with Boolean is that it can only hold two states while you need three. Instead of using a wrapper you can create a new ADT that has three states.
sealed trait ExampleResult
case object TrueResult extends ExampleResult
case object FalseResult extends ExampleResult
case object QueryError extends ExampleResult
Because the Trait is sealed, only classes in the same file can extend the trait ExampleResult, so you know that it will always be one of those three options.
You can then write your code like this
def exampleMethod (query: String): ExampleResult =
{
try
{
//This will take the input query and return "true" or "false"
//depending on the state of the database
if(boolQueryResult.evaluate()){
return TrueResult
} else {
return FalseResult
}
}
catch
{
case e: Throwable => logger.info(e.toString)
}
logger.info("Something is wrong! I want to return a boolean with nothing in it!")
return QueryError
}
I want to update a certain column in row only if row has a valid data. Being specific: I have a table with Event which stores start, stop and isActive flag.
I would like some Events activate by setting isActive to true, however I need to check if start and stop dates are valid.
model:
case class Event {start:DateTime, stop:DateTime, isActive:Boolean}
my validation method signature :
validateEvent(ev: Event): Boolean
My first approach:
def activateEv() = Action.async(parse.json) {
request => {
...
val ev = db.run(dao.findEvById(poid, uid))
val ret = ev.flatMap {
case st: Option[Event] => if (validateEvent(st.get)) {
db.run(dao.updateActivity(poid, true).map {
case 0 => false
case other => true
}
} else Future(false)
}
...
}
}
I believe that it is not the way how this problem should be addressed.
Could you advice ?
Maybe only one db.run will be sufficient ?
This can be achieved in a single db.run using combinators (e.g. flatMap) on DBIOAction objects. Assuming that your dao methods look like that:
case object dao {
def findEvById(poid: Int, uid: Int): DBIOAction[Option[Event], NoStream, Effect.Read] = ???
// In your case `updateActivity` returns an `Int` and you're mapping it to a `Boolean`.
// That mapping could be placed here, so `updateActivity` would return `Boolean` now.
def updateActivity(poid: Int, bool: Boolean): DBIOAction[Boolean, NoStream, Effect.Write] = ???
}
This is how we can achieve the thing you're looking for:
...
val action = dao.findEvById(poid, uid).flatMap {
case Some(event) if validateEvent(event) => dao.updateActivity(poid, true)
case _ => DBIO.successful(false)
}.transactionally
db.run(action)
...
As you see we have a transaction here, which would make a selection followed by an update (only if the event is valid). Moreover, that whole select then update action could be a separate method in your dao.