How to deal with Future[Option[value]] scala - scala

Below is this code snippet working well but with Await.result
def validate(loginRequest: LoginRequest): Option[AuthResponse] = {
val response:Option[User] = Await.result(userDao.getUserByUsernameAndPassword(loginRequest.username,Utilities.encrypt(loginRequest.password)),Duration.Inf )
response match {
case Some(value) =>populateResponse(value)
case None => None
}
}
I want to use Futures instead of await but then return the response. below is a non blocking snippet
val response:Future[Option[User]]= userDao.getUserByUsernameAndPassword(loginRequest.username,Utilities.encrypt(loginRequest.password))
How would u get a similar response without blocking
response match {
case Some(value) =>populateResponse(value)
case None => None
}

You just need to call map on the Future to change the result, and inside that call map on the Option to change the contents of the option:
response.map(_.map(populateResponse))
If the Option is None then the second map will do nothing, and if the Future had failed then the first map will do nothing.

so based on your great answers I came up with a solution. because it was an Option response.
response.map{
res => res match {
case Some(value) =>populateResponse(value)
case None => None
}

Related

How to check for None when returning data

I am fetching my data like this
case class MyClass(s: Option[Safe] = None, t: Option[Threat] = None)
val myCheck = for {
t <- fT
s <- fS
} yield MyClass(s, t)
onComplete(myCheck) {
case Success(check) =>
check match {
case (maybeMyClass) =>
complete(ToResponseMarshallable(maybeMyClass))
}
This works well when my records are found, however, when no records are found I get a MyClass(None, None). I would like to catch that using pattern matting and throw an appropriate message. How can I use pattern matching here to catch when the data is null?
If you are dealing with values that might be null it is important to wrap them using Option. The Option object will check for null values and return None.
However, using Some will not check for null and you can get Some(null).
If you have an option that might be Some(null) you can clean it up by wrapping it in Option again by using flatMap(Option(_))
For example:
val s: String = "x"
val n: String = null
Option(s) // Some("x")
Option(n) // None
Some(s) // Some("x")
Some(n) // Some(null) <- NB
Some(n).flatMap(Option(_)) // None
Update after comments
From the comments it appears that the null is actually in JSON, and is presumably coming from parsing None rather than a Scala null. In that case you can just check for None as usual:
check match {
case MyClass(None, _) =>
// Error: missing Safe value
case MyClass(_, None) =>
// Error: missing Threat value
case _ =>
complete(ToResponseMarshallable(check))
}

Using a Future's response

Hoping someone can offer an opinion on a solution for this issue I'm having.
I'll try to simplify the issue so save bringing in domain issues, etc.
I have a list of Optional strings. I'm using the collect method to basically filter out strings that don't exist.
names collect {
case Some(value) => value
}
Simple enough. I'm homing to actually go one further. If a value is a None I'd like to call a function and use its response in place of the None. For example
names collect {
case Some(value) => value
case _ => getData(_)
}
The catch is the getData method returns a future. I understand that conventions for futures advise accessing the value within a callback, so something like the map method or on complete, but the issue is that I don't know if I need to call the getData method until I'm in the collect and have the value, so I can't simply wrap all my logic in a map method on getData. It doesn't feel like using Await and blocking is a good idea.
Any idea how I could reasonably handle this would be greatly appreciated. Very new to Scala, so I'd love to hear opinions and options.
EDIT:
I was trying to simplify the problem but I think I've instead missed out on key information.
Below is the actual implementation of my method:
def calculateTracksToExport()(
implicit exportRequest: ExportRequest,
lastExportOption: Option[String]
): Future[List[String]] = {
val vendorIds = getAllFavouritedTracks().flatMap { favTracks =>
Future.sequence {
favTracks.map { track =>
musicClient.getMusicTrackDetailsExternalLinks(
track,
exportRequest.vendor.toString.toLowerCase
).map { details =>
details.data.flatMap { data =>
data.`external-links`.map { link =>
link.map(_.value).collect {
case Some(value) => value
case None => getData(track)
}
}
}.getOrElse(List())
}
}
}.map(_.flatten)
}
vendorIds
}
You can use Future.sequence for collecting values:
def collect(list:List[Option[String]]):Future[List[String]] = Future.sequence(
list.map {
case Some(item) => Future.successful(item)
case _ => getData()
}
)
If something can be in future, you will have to always treat it like future. So have sequence of Futures as return value:
def resolve[T](input: Seq[Option[T]], supplier: => Future[T]): Seq[Future[T]] = {
input.map(option => option.map(Future.successful).getOrElse(supplier))
}
Usage example:
// Input to process
val data = Seq(Some(1), None, Some(2), None, Some(5))
//Imitates long-running background process producing data
var count = 6
def getData: Future[Int] = Future( {
Thread sleep (1000)
count += 1
count
})
resolve(data, getData) // Resolve Nones
.map(Await.result(_, 10.second)).foreach( println ) // Use result
Outputs:
1
8
2
7
5
http://ideone.com/aa8nJ9

Why do futures get called in a for comprehension if they aren't used?

I'm trying to implement a system that caches requests to an external API. If the response is in cache, then no request should be made to the external site.
I have two methods:
// Check to see if the response is in the database
def checkCache(searchParameters: JsValue): Future[Option[JsValue]]
// Call the external API and get the JSON response
def getResponse(path: String): Future[JsValue]
And then I try to do the following:
val json: Future[JsValue] = for {
databaseJson <- checkCache(searchParameters)
externalJson <- getResponse(path)
} yield databaseJson match {
case None => externalJson
case Some(x) => x
}
This works, but a request to the external API is made all the time, even when the cached result is returned. This is obviously not what I want because it's slow.
How do I fix this?
The for comprehension maps over the futures, not the Option within it. Your code would translate to this
checkCache(searchParameters) flatMap { databaseJson =>
getResponse(path) map { externalJson =>
databaseJson match {
case None => externalJson
case Some(x) => x
}
}
}
So you are always calling getResponse() obviously.
You need something along the lines of this (not tested):
checkCache(searchParameters) flatMap { databaseJson =>
databaseJson match {
case None => getResponse(path)
case Some(x) => Future.successful(x)
}
}
You could also give this a shot:
val json: Future[JsValue] = for {
databaseJson <- checkCache(searchParameters)
json <- databaseJson.fold(getResponse(path))(js =>Future.successful(js))
} yield json
Similar in spirit to Marius Soutier's answer, but doing the Option checking via a fold right in the for comprehension.
This is a little cheesy, but still:
checkCache(params) map (_.get) fallbackTo getResponse(path)
Also not tested.
Update:
I didn't like the conversion to failure by None.get, but actually this isn't cheesy at all but is very natural. More naturally:
checkCache(params) filter (_.nonEmpty) map (_.get) fallbackTo getResponse(path)
The Some.get is now just a wart due to the asymmetry in the two futures (that they are not both Option).

Avoiding default logic for case partial function

I have the following code in multiple places in my application
(i: Option) => {
case Some(i) => // doSomething with i
case None =>
}
The doSomething will vary in each location, but any time I have a None I don't want to do anything.
Is there an easy way to avoid the use of case None => using implicits or otherwise?
If you are discarding the result, then you can use foreach:
o.foreach(i => doSomething(i))
If you need the result of doSomething, then use map:
o.map(i => doSomething(i))
You can use a map or a foreach - these won't do anything if your Option is a None. The difference between the two is that map will return an Option while foreach returns a Unit
iOpt.map(i => /* doSomething with i */) // does nothing and returns a None if iOpt is a None

Is there a way to chain methods which return an Option-Type in a way like getOrElse does but keeps the option-type

Given snippet composes of method calls, which return an option type. I'd like to call the next method if previous call returned None. I'm able to accomplish this with this snippet
def amountToPay : Option[TextBoxExtraction] =
getMaxByFontsize(keywordAmountsWithCurrency) match {
case None => getMaxByFontsize(keywordAmounts) match {
case None => highestKeywordAmount match {
case None => getMaxByFontsize(amountsWithCurrency) match {
case None => highestAmount
case some => some
}
case some => some
}
case some => some
}
case some => some
}
but it looks quite messy. So I hope there is abetter way to do it.
Yep, orElse is a little cleaner:
def amountToPay : Option[TextBoxExtraction] =
getMaxByFontsize(keywordAmountsWithCurrency)
.orElse(getMaxByFontsize(keywordAmounts))
.orElse(highestKeywordAmount)
.orElse(getMaxByFontsize(amountsWithCurrency))
.orElse(highestAmount)
You could also just put the items in a Seq and then use something like xs.reduceLeft(_ orElse _) or xs.flatten.headOption.getOrElse(highestAmount).