Reputation: 2800
Given a UserRepository
:
class UserRepository {
val collection = Mongo.connect("users")
def findBy(key: String, value: String): Future[Option[User]] = {
collection.flatMap(
_.find(document(key -> value)).one[User]
)
}
}
And I want to write a login
method:
def login(email: String, password: String): Future[Option[User]] = {
import scala.concurrent.ExecutionContext.Implicits.global
repo.findBy("email", email)
// .filter { user => BCrypt.checkpw(password, user.password) }
}
How would I write a mapping on the result of findBy
to transform all Some(user)
's into None
's if they fail the test BCrypt.checkpw(password, user.password)
? Is there some kind of transform I can do to turn any of the Some
's that fail that check into None
's?
Upvotes: 0
Views: 309
Reputation: 3921
You probably don't want to do filter
/collect
on the Future
because you'll get a failed Future (with exception), and then you need to .recover
etc. Because result of your operation is already stated in it's signature (Option[User]
) you probably want this:
repo.findBy("email", email).map { userOpt =>
val maybeUser1 = userOpt.filter { user => BCrypt.checkpw(password, user.password) }
// or like this:
// longer form, if more than one options or whatever
val maybeUser2 = for {
user <- userOpt
if(BCrypt.checkpw(password, user.password))
} yield user
}
Upvotes: 3
Reputation: 14825
Use collect and use the pattern matching guard to check the user. If user fails then return a None
findBy(key, value).collect {
case Some(user) if ! BCrypt.checkpw(password, user.password) => None
}
Suggestion
It would be good to collect user which satisfy the condition this way your final output type would be Future[user]
instead of Future[Option[User]]
. Of course after the above collect your Future[Option[User]]
would contain Some(user)
where is the user
is valid user.
findBy(key, value).collect {
case Some(user) if BCrypt.checkpw(password, user.password) => user
}
The line gives only valid users and the final type would be Future[User]
instead of Future[Option[User]]
Upvotes: 2
Reputation: 28056
You need to map over the Future
to transform its value from a Some
to a None
. The call to filter needs to go inside the function passed to the map-function. Try this:
def login(email: String, password: String): Future[Option[User]] = {
import scala.concurrent.ExecutionContext.Implicits.global
repo.findBy("email", email)
.map { userOpt => userOpt.filter(user => BCrypt.checkpw(password, user.password)) }
}
Upvotes: 3