Reputation: 15385
I'm a bit struggling to get this structured. Here is what I'm trying to do:
def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = Future {
if (result.code contains 11000)
Left(ServiceError("Email already exists"))
else if (result.hasErrors)
Left(ServiceError(result.writeErrors.map(_.errmsg).toString))
else
userByEmail(encryptedEmail).map(user =>
user
).recover {
case NonFatal(ex) => Left(ServiceError(ex.getMessage))
}
}
checkResultAndFetchUser(
await(userCollection.insert(encryptedUser)), encryptedUser.email
)
I'm expecting that the checkResultAndFetchUser
returns a Future[Either[ServiceError, User]]
, but I get to see the following compiler failures:
Error:(155, 28) type mismatch;
found : scala.concurrent.Future[Either[DBService.this.ServiceError,com.inland.model.User]]
required: Either[DBService.this.ServiceError,com.inland.model.User]
Error occurred in an application involving default arguments.
checkResultAndFetchUser(
^
Error:(150, 19) type mismatch;
found : scala.concurrent.Future[Either[DBService.this.ServiceError,com.inland.model.User]]
required: Either[DBService.this.ServiceError,com.inland.model.User]
).recover {
^
The userByEmail(encryptedEmail)
method gives me a Future[Either[ServiceError, User]]
as I would expect it to, but why and where is the problem?
EDIT: I've found a solution:
def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = {
if (result.code contains 11000)
Future(Left(ServiceError("Email already exists")))
else if (result.hasErrors)
Future(Left(ServiceError(result.writeErrors.map(_.errmsg).toString)))
else
userByEmail(encryptedEmail)
}
await(checkResultAndFetchUser(
await(userCollection.insert(encryptedUser)), encryptedUser.email
))
Is that Okay? I mean, the implementation is safe as I'm using local variables to return a Future
!
Upvotes: 0
Views: 123
Reputation: 2130
Your code is ok in the sense that it produce the expected result. However as @Łukasz mentioned in the comment, doing it this way is a little bit wasteful.
The reason is that whenever you instantiate a Future like that, a new task is spawned that needs to be scheduled on some ExecutionContext. Usually whenever you just need to wrap an already computed result in a Future (or if the computation is really quick) is better to use Future.successful
so to avoid overhead.
Here's how I would modify the checkResultAndFetchUser function:
def checkResultAndFetchUser(result: WriteResult, encryptedEmail: String): Future[Either[ServiceError, User]] = {
if (result.code contains 11000)
Future.successful(Left(ServiceError("Email already exists")))
else if (result.hasErrors)
Future.successful(Left(ServiceError(result.writeErrors.map(_.errmsg).toString)))
else
userByEmail(encryptedEmail)
}
Upvotes: 2