How i get Boolean From a Future[Settings] - scala

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

Related

.map or match returning Future[List] when expected to return List

I am kind of failing this weird behaviour not sure where i am wrong exactly. So the situation is that tester2 function is returning a Future[Boolean]] now I want to wait for this to complete and when it gets completed I want it to return a List[String] based on different cases inside reset function, now the problem is instead of returning up a List[String] it is returning Future[List[String]] , not able to understand why match function behaving like this
I am getting this error to be exact
val les = Await.ready(tester2(5),Duration.Inf).map(reset).forEach(println)
object HelloWorld {
def main(args: Array[String]) {
val exp = tester2(5).map(reset)
val les = Await.ready(tester2(5),Duration.Inf).map(reset).forEach(println)
println(s"what do you say ${les}")
}
def reset (x: Option[Boolean]): List[String] =
x match {
case None => List("abc","def")
case Some(false) => List("abc","def")
case Some(true) => List("def","abc")
}
def tester():Future[Option[Message]]={
Future{
Thread.sleep(5000)
Option(Message("abc","def","ghi"))
}
}
def tester2(param:Int):Future[Option[Boolean]]={
Future{
Thread.sleep(5000)
if(param>10){
Some(true)
}else{
Some(false)
}
}
}
If tester2 returns a Future of an Option of a Boolean
def tester2(param:Int):Future[Option[Boolean] = ???
and you want to change the value to a string you need to say "when this future completes and there is a real Option[Boolean].. then do this thing. This is what "map" does on a future. It says "once the future completes, run this code". So you can do this:
def reset (in :Future[Option[Boolean]]) = in.map { optionOfBoolean :Option[Boolean] =>
optionOfBoolean match {
case None => ...
case Some(true) ...
}
}
Scala also allows you to short cut having the map and match together and just write:
def reset (in :Future[Option[Boolean]]) = in map {
case None => List("abc", "bcd")
case Some(true) => List("d3", "d4")
case Some(false) => List("sds", "dssds")
}
Since I can't see your error I can't help you further but something like this should work.
val booleanResult :Future[Option[Boolean]] = tester2(...)
val futureListStr :Future[List[String]] = reset(booleanResult)
val answer :List[String] = Await.result(futureListStr, scala.concurrent.duration.Duration.Inf)
Use Await.result to extract the result value.
final def result[T](awaitable: Awaitable[T], atMost: Duration): T
Await and return the result (of type T) of an Awaitable.
awaitable the Awaitable to be awaited
atMost maximum wait time, which may be negative (no waiting is done), >Duration.Inf for unbounded waiting, or a finite positive duration
returns the result value if awaitable is completed within the specific maximum wait time

MVar tryPut returns true and isEmpty also returns true

I wrote simple callback(handler) function which i pass to async api and i want to wait for result:
object Handlers {
val logger: Logger = Logger("Handlers")
implicit val cs: ContextShift[IO] =
IO.contextShift(ExecutionContext.Implicits.global)
class DefaultHandler[A] {
val response: IO[MVar[IO, A]] = MVar.empty[IO, A]
def onResult(obj: Any): Unit = {
obj match {
case obj: A =>
println(response.flatMap(_.tryPut(obj)).unsafeRunSync())
println(response.flatMap(_.isEmpty).unsafeRunSync())
case _ => logger.error("Wrong expected type")
}
}
def getResponse: A = {
response.flatMap(_.take).unsafeRunSync()
}
}
But for some reason both tryPut and isEmpty(when i'd manually call onResult method) returns true, therefore when i calling getResponse it sleeps forever.
This is the my test:
class HandlersTest extends FunSuite {
test("DefaultHandler.test") {
val handler = new DefaultHandler[Int]
handler.onResult(3)
val response = handler.getResponse
assert(response != 0)
}
}
Can somebody explain why tryPut returns true, but nothing puts. And what is the right way to use Mvar/channels in scala?
IO[X] means that you have the recipe to create some X. So on your example, yuo are putting in one MVar and then asking in another.
Here is how I would do it.
object Handlers {
trait DefaultHandler[A] {
def onResult(obj: Any): IO[Unit]
def getResponse: IO[A]
}
object DefaultHandler {
def apply[A : ClassTag]: IO[DefaultHandler[A]] =
MVar.empty[IO, A].map { response =>
new DefaultHandler[A] {
override def onResult(obj: Any): IO[Unit] = obj match {
case obj: A =>
for {
r1 <- response.tryPut(obj)
_ <- IO(println(r1))
r2 <- response.isEmpty
_ <- IO(println(r2))
} yield ()
case _ =>
IO(logger.error("Wrong expected type"))
}
override def getResponse: IO[A] =
response.take
}
}
}
}
The "unsafe" is sort of a hint, but every time you call unsafeRunSync, you should basically think of it as an entire new universe. Before you make the call, you can only describe instructions for what will happen, you can't actually change anything. During the call is when all the changes occur. Once the call completes, that universe is destroyed, and you can read the result but no longer change anything. What happens in one unsafeRunSync universe doesn't affect another.
You need to call it exactly once in your test code. That means your test code needs to look something like:
val test = for {
handler <- TestHandler.DefaultHandler[Int]
_ <- handler.onResult(3)
response <- handler.getResponse
} yield response
assert test.unsafeRunSync() == 3
Note this doesn't really buy you much over just using the MVar directly. I think you're trying to mix side effects inside IO and outside it, but that doesn't work. All the side effects need to be inside.

Update a row only if condition is met

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.

Scala boolean always returning false

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.

scala store method in set with possibility of removal

Here's some test code to demonstrate the problem:
import scala.collection.mutable.HashSet
import scala.collection.mutable.Set
object Test extends App
{
val set: Set[Int => Boolean] = new HashSet()
def test(i: Int): Boolean = {
false
}
Console.println(set.add(test)) // true
Console.println(set.remove(test)) // false
Console.println(set.add(test _)) // true
Console.println(set.remove(test _)) // false
}
What options are there for making this work?
Edit: I also want this to support lambdas.
Every time you perform "add" or "remove" operation Scala compiler creates new AbstractFunction1.mcZI.sp object instance:
Console..MODULE$.println(BoxesRunTime.boxToBoolean(set().add(
new AbstractFunction1.mcZI.sp() {
public final boolean apply(int i) { return apply$mcZI$sp(i); }
public boolean apply$mcZI$sp(int i) { return Test..MODULE$.test(i); }
})));
As I understand this object instance doesn't contain information about enclosing object and 'test' method which can be used for 'hashCode' and 'equals' methods.
I think as a workaround you may consider this:
import scala.collection.mutable.HashSet
import scala.collection.mutable.Set
object Test extends App
{
val set: Set[Int => Boolean] = new HashSet()
def test(i: Int): Boolean = {
false
}
val testFunc: Function1[Int, Boolean] = test
Console.println(set.add(testFunc)) // true
Console.println(set.remove(testFunc)) // true
val testPartFunc = test _
Console.println(set.add(testPartFunc)) // true
Console.println(set.remove(testPartFunc)) // true
}
If instead of passing methods you pass function it works:
val testFun: Int => Boolean = i => i > 10
set.add(testFun) // true
set.remove(testFun) // true
it will also work for anonymous functions:
set.add { _ => false }
but then I don't know how you would like to remove such function from the set.