John Doe John Doe - 2 months ago 13
Scala Question

How to unpack Option in Future?

I want to implement a method which creates a user if it does not exist yet. If it does exist, the user should be returned.

Here's my code:

def createUserIfNotExists(user: User) = {
for {
count <- userService.count(Some(user))
user <- if (count == 0) createUser(user) else userService.findOneByName(user.name)
} yield user
}


My problem is that
findOneByName
returns
Future[Option[User]]
and
createUser
returns
Future[User]
so the types don't match.

How can I unpack
Future[Option[User]]
to
Future[User]
or throw an exception in case there is
None
?

Answer

make createUser also return Future[Option[_]]

def createUserIfNotExists(user: User) = {
  for {
   count <- userService.count(Some(user))
   userOpt <- if (count == 0) createUser(user).map(Some(_)) else userService.findOneByName(user.name)
  } yield userOpt
}

or

You can do .get on the option because if count is not zero that means user is definitely available in the database.

def createUserIfNotExists(user: User) = {
  for {
   count <- userService.count(Some(user))
   user <- if (count == 0) createUser(user) else userService.findOneByName(user.name).map(_.get)
  } yield user
}

or

First try to retrieve the user if not create the user

def createUserIfNotExists(user: User) = {
 for {
   userOpt <- userService.findOneByName(user.name)
   user <-  userOpt match {
      case Some(value) => value
      case None => createUser(user).map(_ => user)
   }
 } yield user
}

Note that to ensure correctness in case of parallel database operations it is highly recommended to execute the above code in a transaction