Give then following code:
AccountsDAO.scala:
def find(id: EntityId): Future[Option[Account]] =
collection.find(Json.obj(Fields.Id -> id)).one[Account]
And AccountService.scala:
def getAccount(id: Option[Credentials]) = id.flatMap {
accountId => accountDAO.find(accountId.accountId) //Throws an error
}
The commented line above throws this error:
type mismatch; found : scala.concurrent.Future[Option[models.Account]] required: Option[?]
What am I missing? Why does flattop return an Option[?]
. If I change the return type of the getAccount
method as:
def getAccount(id: Option[Credentials]): Future[Option[Account]] = id.flatMap {
accountId => accountDAO.find(accountId.accountId) //Still throws an error
}
I get the error below:
type mismatch; found : Option[Nothing] required: scala.concurrent.Future[Option[models.Account]]
What is going on? What am I missing?
Thanks in advance.
Edit : Here's the code in the controller and what I'm trying to do:
def auth = Action.async(parse.json) { request =>
{
val authRequest = request.body.validate[AuthRequest]
authRequest.fold(
errors => Future(BadRequest),
auth => {
//First verify username and password
val authRequestResult = for {
validCredentials <- credentialsManager.checkEmailPassword(auth.email, auth.password)
account:Option[Account] <- accountManager.getAccount(validCredentials)
session:Session <- sessionManager.createSession(account.get.id, account.get.roles)
touchedSession <- sessionManager.TouchSession(session.id)
} yield AuthResponse(session.id, session.token, account.get.id, account.get.roles)
authRequestResult map {
case res: AuthResponse => Ok(Json.toJson(res))
case _ => NotFound
}
})
}
}
The checkEmailPassword method above returns a Future[Option]:
def checkEmailPassword(email: String, password: String) =
for {
credentials <- credentialsDAO.find(AuthType.EmailPassword, email)
validPassword <- BCrypt.checkFuture(password, credentials)
} yield (credentials)
And credentialsDAO.find:
def find(authType: AuthType.Value, authAccountId: String) =
collection.find(
Json.obj(Fields.AuthType → authType,
Fields.AuthAccountId → authAccountId)).one[Credentials].recover(wrapLastError)
So when checkEmailPassword
returns an Option[Credentials] object, is it okay to assume the for comprehension
in the controller will not execute any further if it returns a None
? Then I could just say something like account:Option[Account] <- accountManager.getAccount(validCredentials.get.id)
. Is there a better way to structure/organize this code? Any patterns that I can follow/use?