Get user and fill all permissions
Asked Answered
K

1

7

I am new to Scala and even what I am trying to achieve is too simple with Java, i feel confused with Scala.

What I want is to get a User and then fill his Permission using another query and based to his Role and his individual Permissions.

Until know I have the following code:

/**
* Finds a user by its loginInfo.
*
* @param loginInfo The loginInfo of the user to find.
* @return The found user or None if no user for the given login info could be found.
*/
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)
  user <- dbUser match {
    case u =>
      val permissionQuery = for {
        dbUserPermission <- Userpermission.filter(_.userid === u.userid)
        dbPermission <- Permission.filter(_.id === dbUserPermission.permissionid)
      } yield dbPermission

      val rolePermissionQuery = for {
        dbUserRole <- Userrole.filter(_.userid === u.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

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

        models.admin.User(
          UUID.fromString(u.userid.toString),
          u.firstname.toString,
          u.lastname.toString,
          u.jobtitle.toString,
          loginInfo,
          u.email.toString,
          false,
          Some(permission),
          false)
      }
    case None => None
  }
} yield user

db.run(userQuery.result.headOption)

}

I got the following errors:

pattern type is incompatible with expected type;
[error]  found   : None.type
[error]  required: UserDAOImpl.this.User
[error]         case None => None
[error]              ^
[error] play/modules/admin/app/models/daos/impl/UserDAOImpl.scala:36: value map is not a member of Object
[error]       user <- dbUser match {
[error]                      ^
[error] play/modules/admin/app/models/daos/impl/UserDAOImpl.scala:34: type mismatch;
[error]  found   : UserDAOImpl.this.Userlogininfo => slick.lifted.Query[Nothing,Nothing,Seq]
[error]  required: UserDAOImpl.this.Userlogininfo => slick.lifted.Query[Nothing,T,Seq]
[error]       dbUserLoginInfo <- Userlogininfo.filter(_.logininfoid === dbLoginInfo.id)
[error]                       ^
[error] play/modules/admin/app/models/daos/impl/UserDAOImpl.scala:33: type mismatch;
[error]  found   : UserDAOImpl.this.Logininfo => slick.lifted.Query[Nothing,Nothing,Seq]
[error]  required: UserDAOImpl.this.Logininfo => slick.lifted.Query[Nothing,T,Seq]
[error]       dbLoginInfo <- loginInfoQuery(loginInfo)
[error]                   ^
[error] play/modules/admin/app/models/daos/impl/UserDAOImpl.scala:69: value headOption is not a member of UserDAOImpl.this.driver.DriverAction[Seq[Nothing],UserDAOImpl.this.driver.api.NoStream,slick.dbio.Effect.Read]
[error]     db.run(userQuery.result.headOption)
[error]                             ^
[error] 5 errors found
Kinsfolk answered 4/12, 2015 at 14:16 Comment(3)
case u => will match anything. If you want to modify Option if it's Some and leave it None otherways you can use map . I don't really know how to help with other things as I don't know slick but maybe try to annotate types you expect and let compiler tell you where you fail.Exegetic
The error messages you are getting, if you read them closely, are already telling you what your problems are. Is there a particular error message you're having difficulty interpreting...?Regulable
It will be easier to debug if you can give the schemas of your tables and the methods ..Torrence
M
0

Whenever you work with a for-comprehension with a yield you have to understand that you a working with some sort of "wrapped" value (monad). It can be a Future, a List, an Option, or anything else that is monadic.

So the pattern is kind of like this:

for {
  someValue <- someWrappedValue()
  someOtherValue <- someWrappedOtherValue(someValue)
} yield someOtherValue

If you are working with Future, then you can use these rules:

  • Everything to the right of a <- must be a Future
  • Everything to the left of a <- is the "unwrapped" value
  • The value of the entire for-comprehension will be whatever is on the yield wrapped in a Future

The rules are the same for List, Option, etc. But you cannot mix and match within the same for-comprehension.

One of the errors hints that the result of your match statement is of type Object, which means scala couldn't figure out a common type for all the cases in the match. You want all of the cases to produce a Future (since that's what we're working with in this for-comprehension).

My guess, you need to replace:

case None => None

with:

case None => Future.successful(None)

But it's hard to know for sure without more info.

Regarding it being simpler in Java: Not exactly. What makes it a bit more complex is not the language, but the fact that a lot of the methods are asynchronous. If you were to do it synchronously in scala, it would be just as simple as java, if not more. But then you would be blocking a thread every time you are waiting for results, which is the case with java (assuming synchronous calls).

Malraux answered 11/12, 2015 at 22:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.