Reputation: 267320
My services are returning Future[Option[Entity]] and I am currently doing this:
val user = userService.getById(1)
val company = userService.getById(1)
if(user.get.companyId == company.get.id) {
save(...)
if(...) {
blahService.boo();
}
return ...
} else
{
...
return ...
}
Now if I refactor this to a for-comprehension, how do I handle the else clause? Do I return something from the for-comp and then use that like the 'else' clause?
Also, how do I get rid of the .get from inside the for compr?
for {
userOption <- userService.getById(1)
companyOption <- cService.getById(2)
if (userOption.get.companyId == companyOption.get.id)
} {
..
..
saveUser(userOption.get, companyOption.get)
return ..
}
Upvotes: 1
Views: 189
Reputation: 36671
When it comes to mixing Future
s with control flow, I highly recommend scala-async. I find it to be almost strictly better than map
or for
-comprehensions for Future
s. There are some limitation to what control flow structures you can use, but for your situation, it would work great:
async {
val userOption = await(userService.getById(1))
val companyOption = await(cService.getById(2))
(userOption, companyOption) match {
case (Some(user), Some(company)) => // happy path
case _ => // sad path
}
}
This whole async {...}
block is of type Future[A]
, where A
is determined by the branches of the match
.
Upvotes: 1
Reputation: 4268
Here's a solution using Scalaz's OptionT
:
import scalaz.OptionT.optionT
(for {
user <- optionT(userService.getById(1))
company <- optionT(cService.getById(2))
if (user.companyId == company.id)
} yield {
saveUser(user, company)
}).run
See e.g. this discussion for more: http://loicdescotte.github.io/posts/scala-compose-option-future/
Upvotes: 2
Reputation: 17511
If you are restricted to vanilla Scala,
val x = for {
userOption <- userService.getById(1)
companyOption <- cService.getById(2)
} yield {
for {
user <- userOption
company <- companyOption
} yield {
if (user.id == company.id) { ... }
else { ... }
}
}
x
then this is as simple as you can get.
Note that the resulting Future
will fail if one of the two calls returns a Failure
. Also, the resulting Option
will be None
if one of the call returns None
. This comprehension is basically good only for "happy path" code, and might not be sufficient for cases where different actions need to be taken for every different branch.
Upvotes: 0