glarkou
glarkou

Reputation: 7101

Convert Future[List[String]] to List[String]

I have the following code:

Some(db.run(unionPermissionQuery.result).map(_.map(_.name).toList))

and I get the following error:

[error]  found   : scala.concurrent.Future[List[String]]
[error]  required: List[String]
[error]           Some(db.run(unionPermissionQuery.result).map(_.map(_.name).toList)),
[error]                                                       ^
[error] one error found

So I suppose I have to convert the Future[List[String]] to List[String]. I am new to scala sorry if that's too easy.

Full code:

  def find(loginInfo: LoginInfo): Future[Option[models.admin.User]] = {
val userQuery = for {
  dbLoginInfo <- loginInfoQuery(loginInfo)
  dbUserLoginInfo <- Userlogininfo.filter(_.logininfoid === dbLoginInfo.id)
  dbUser <- User.filter(_.userid === dbUserLoginInfo.userid)
} yield dbUser

db.run(userQuery.result.headOption).map { dbUserOption =>
  dbUserOption.map { user =>
    val permissionQuery = for {
      dbUserPermission <- Userpermission.filter(_.userid === user.userid)
      dbPermission <- Permission.filter(_.id === dbUserPermission.permissionid)
    } yield dbPermission

    val rolePermissionQuery = for {
      dbUserRole <- Userrole.filter(_.userid === user.userid)
      dbRole <- Role.filter(_.id === dbUserRole.roleid)
      dbRolePermission <- Rolepermission.filter(_.roleid === dbRole.id)
      dbPermission <- Permission.filter(_.id === dbRolePermission.permissionid)
    } yield dbPermission

    val unionPermissionQuery = permissionQuery union rolePermissionQuery

    models.admin.User(
      UUID.fromString(user.userid),
      user.firstname,
      user.lastname,
      user.jobtitle,
      loginInfo,
      user.email,
      user.emailconfirmed,
      Some(db.run(unionPermissionQuery.result).map(_.map(_.name).toList)),
      user.enabled)
  }
}

I just want to get the user and then fill all permissions. Individual permissions and permissions inherited by the role assigned to the user.

Is it better to get the user and then perform another request to get the permissions based on the user id? I don't think so.

Upvotes: 3

Views: 6205

Answers (2)

ziggystar
ziggystar

Reputation: 28680

I'm answering the question in the title.

The only way to implement the function Future[A] => A in a sensible way (and without access to a time-machine) is to await the completion of the future, as a value Future[A] indicates a value of type A will yield in the future.

Check your library for the correct method to wait. For the Scala std lib it is .result. As commented by Jean, the correct way for the Scala std lib is to use Await.result().

Note that waiting is a blocking method call. If you want to avoid this (and there are some good reasons to do so), you should check out Andreas' answer.

Upvotes: 2

Andreas Neumann
Andreas Neumann

Reputation: 10884

General information on futures

You will find all information on Futures you need on http://docs.scala-lang.org/overviews/core/futures.html.

A possible approach is awaiting the result, but it is not good to use in a prod application.

val myFutureResult : Future[T] = Future {...}
val myResult : T = Await.result(myFutureResult, secondsToWait seconds)

Normally instead of awaiting the result and storing it in a variable you can map the future and compose it and only use Await at the last moment.

val myFutureResult : Future[T] = Future {...}
def myFunctionOnT(in: T) = ...

for {res <- myFutureResult } yield myFunctionOnT(res)

Play and Futures

Play itself can handle Future[T]by default by using Action.async {} instead of Action{} here you can find more: https://www.playframework.com/documentation/2.5.x/ScalaAsync

This information applied to extended question

db.run(unionPermissionQuery.result).map(_.map(_.name).toList).map { permission =>

models.admin.User(
  UUID.fromString(user.userid),
  user.firstname,
  user.lastname,
  user.jobtitle,
  loginInfo,
  user.email,
  user.emailconfirmed,
  Some(permission),
  user.enabled)
  }

Upvotes: 6

Related Questions