I have this Action which should return a Future[Result] but I am unable to code it using for comprehension. This is the first time I am using for comprehension so I am also not sure if this is how I should use for.
Also, would someone comment on whether the usage of for is correct?
def verifyUser(token:String) = Action.async{
implicit request => { //the function takes a token
val tokenFutureOption:Future[Option[UserToken]] = userTokenRepo.find(UserTokenKey(UUID.fromString(token))) //checkc if the token exists in the db (db returns a Future)
for(tokenOption<- tokenFutureOption) yield { //resolve the future
tokenOption match {
case Some(userToken) =>{//token exists
val userOptionFuture = userRepo.findUser(userToken.loginInfo)//find user to which the token belongs. Another db request which returns a Future
for(userOption <- userOptionFuture) yield {//resolve future
userOption match {
case Some(user) =>{//user exists
val newInternalProfile = user.profile.internalProfileDetails.get.copy(confirmed=true) //modify user's profile
val newProfile = UserProfile(Some(newInternalProfile),user.profile.externalProfileDetails)
val confirmedUser = user.copy(profile=newProfile)
val userOptionFuture :Future[Option[User]] = userRepo.updateUser(confirmedUser) //update profile with new value. Another db operation with returns a Future
for(userOption <- userOptionFuture) yield {//resolve future
userTokenRepo.remove(UserTokenKey(UUID.fromString(token)))//remove the token
// Ok("user verified") //I WANT TO RETURN SUCCESS RESPONSE HERE BUT CODE DOESN'T COMPILE IF I UNCOMMENT THIS
}
}
case None =>{ //user doesn't exist
// Ok("user verified") //I WANT TO RETURN FAILURE RESPONSE HERE BUT CODE DOESN'T COMPILE IF I UNCOMMENT THIS
}
}
}
}
case None =>{//INVALID TOKEN RECEIVED
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config //I CAN RETURN Redirect (WHICH IS OF SAME TYPE AS OK I.E. RESULT) BUT WHY AM I NOT ABLE TO USE OK ABOVE
}
}
}//THIS IS THE END OF FIRST FOR LOOP. HOW DO I HANDLE FAILURES IN THE FUTURE?
}
}
You are using Future, Option which are Monads and the idea behind them being helpful to sequence the computations just like Functors but also with capability to specify what happens next. .flatMap is what Monads have allow that which can be used as for yield for readability.
So in your example you can compose the api using sequence of operations.
object Api {
final case class UserTokenKey(uuid: UUID)
final case class UserToken(loginInfo: String)
object userTokenRepo {
def find(u: UserTokenKey) = {
Future.successful(Some(UserToken(loginInfo = "foundLoginInfo")))
}
def remove(u: UserTokenKey) = {
Future.successful(Some(UserToken(loginInfo = "")))
}
}
final case class User(profile: String)
object userRepo {
def findUser(u: String) = {
Future.successful(Some(User("profile")))
}
def updateUser(u: User) = {
Future.successful(Some(User("updated profile")))
}
}
def verifyUser(token: String)(implicit executionContext: ExecutionContext) = {
val user: Future[Option[UserToken]] = for {
tokenMaybe: Option[UserToken] <- userTokenRepo.find(UserTokenKey(UUID.fromString(token)))
userMaybe: Option[User] <-
tokenMaybe match {
case Some(t) => userRepo.findUser(t.loginInfo)
case _ => Future.successful(Option.empty[User])
}
updatedUserMaybe: Option[User] <-
userMaybe match {
case Some(u) => userRepo.updateUser(u)
case _ => Future.successful(Option.empty[User])
}
removedUserMaybe: Option[UserToken] <- userTokenRepo.remove(UserTokenKey(UUID.fromString(token)))
} yield removedUserMaybe
user
}
def httpLayer(request: String) = {
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.mvc.Results
verifyUser(request).onComplete {
case Success(Some(user)) =>
println("user verified")
Results.Ok("user verified")
case Success(None) =>
println("user does not exist")
Results.Ok("user does not exist")
case Failure(f) =>
println("unknown error")
Results.Ok("unknown error")
}
}
}
Now you can test your api as below
def main(args: Array[String]): Unit = {
import Api._
httpLayer(UUID.randomUUID().toString) // user verified
}
Note1: you might want to use api to respond Future[Either[Error, User]] to better handle errors and use Error to determine what to respond back to the http consumers.
Note2: Since you are working with two monads Future[Option[a]], you can combine them using Monad Transformation OptionT[OuterMonad, Value Type] in scalaz or cats mtl library. Which gives a single monad OptionT.
def verifyUserV2(tokenString: String)(implicit executionContext: ExecutionContext) = {
import scalaz._
import Scalaz._
// import cats.implicits._
// import cats.data.OptionT
val userStack = for {
token <- OptionT(userTokenRepo.find(UserTokenKey(UUID.fromString(tokenString))))
user <- OptionT(userRepo.findUser(token.loginInfo))
updatedUser <- OptionT(userRepo.updateUser(user))
removedUser <- OptionT(userTokenRepo.remove(UserTokenKey(UUID.fromString(tokenString))))
} yield removedUser
userStack.run
//cats unpack stack
// userStack.value
}
Useful reads:
Futures - map vs flatmap
Using Either to process failures in Scala code
Related
I'm a beginner in Scala.
Please let me know if there is a more concise part in the code below.
To supplement, I'd like to call each Future method synchronously.
◆getUser method:
def getUser: Option[User] = {
Await.ready(
twitterService.getUser(configService.getString(TWITTER_USERNAME_CONF)),
Duration.Inf)
.value
.flatMap(x => Option(x.getOrElse(null)))
}
◆ process method:
def process : Unit =
for {
user <- getUser
} yield {
Await.ready(
twitterService.delete(user.id, configService.getString(TWITTER_SEARCH_KEYWORD)),
Duration.Inf)
.value
.foreach {
case Success(tweets) => tweets.foreach(tweet => println(s"Delete Successfully!!. $tweet"))
case Failure(exception) => println(s"Failed Delete.... Exception:[$exception]")
}
}
I made some assumptions on user and tweet data types but I would rewrite that to:
def maybeDeleteUser(userName: String, maybeUser: Option[User]): Future[String] =
maybeUser match {
case Some(user) =>
twitterService.delete(user.id, configService.getString(TWITTER_SEARCH_KEYWORD)).map {
case Failure(exception) => s"Failed Delete.... Exception:[${exception.getMessage}]"
case Success(tweets) => tweets.map(tweet => s"Delete Successfully!!. $tweet").mkString(System.lineSeparator())
}
case _ => Future.successful(s"Failed to find user $userName")
}
def getStatusLogMessage: Future[String] = {
val userName = configService.getString(TWITTER_USERNAME_CONF)
for {
maybeUser <- twitterService.getUser(configService.getString(TWITTER_USERNAME_CONF))
statusLogMessage <- maybeDeleteUser(userName, maybeUser)
} yield statusLogMessage
}
def process: Unit = {
val message = Await.result(getStatusLogMessage, Duration.Inf)
println(message)
}
That way your side effect, i.e. println is isolated and other methods can be unit tested. If you need to block the execution, do it only at the end and use map and flatMap to chain Futures if you need to order the execution of those. Also be careful with Duration.Inf, if you really need to block, then you'd want to have some defined timeout.
Let's say we have a fake data source which will return data it holds in batch
class DataSource(size: Int) {
private var s = 0
implicit val g = scala.concurrent.ExecutionContext.global
def getData(): Future[List[Int]] = {
s = s + 1
Future {
Thread.sleep(Random.nextInt(s * 100))
if (s <= size) {
List.fill(100)(s)
} else {
List()
}
}
}
object Test extends App {
val source = new DataSource(100)
implicit val g = scala.concurrent.ExecutionContext.global
def process(v: List[Int]): Unit = {
println(v)
}
def next(f: (List[Int]) => Unit): Unit = {
val fut = source.getData()
fut.onComplete {
case Success(v) => {
f(v)
v match {
case h :: t => next(f)
}
}
}
}
next(process)
Thread.sleep(1000000000)
}
I have mine, the problem here is some portion is more not pure. Ideally, I would like to wrap the Future for each batch into a big future, and the wrapper future success when last batch returned 0 size list? My situation is a little from this post, the next() there is synchronous call while my is also async.
Or is it ever possible to do what I want? Next batch will only be fetched when the previous one is resolved in the end whether to fetch the next batch depends on the size returned?
What's the best way to walk through this type of data sources? Are there any existing Scala frameworks that provide the feature I am looking for? Is play's Iteratee, Enumerator, Enumeratee the right tool? If so, can anyone provide an example on how to use those facilities to implement what I am looking for?
Edit----
With help from chunjef, I had just tried out. And it actually did work out for me. However, there was some small change I made based on his answer.
Source.fromIterator(()=>Iterator.continually(source.getData())).mapAsync(1) (f=>f.filter(_.size > 0))
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runForeach(println)
However, can someone give comparison between Akka Stream and Play Iteratee? Does it worth me also try out Iteratee?
Code snip 1:
Source.fromIterator(() => Iterator.continually(ds.getData)) // line 1
.mapAsync(1)(identity) // line 2
.takeWhile(_.nonEmpty) // line 3
.runForeach(println) // line 4
Code snip 2: Assuming the getData depends on some other output of another flow, and I would like to concat it with the below flow. However, it yield too many files open error. Not sure what would cause this error, the mapAsync has been limited to 1 as its throughput if I understood correctly.
Flow[Int].mapConcat[Future[List[Int]]](c => {
Iterator.continually(ds.getData(c)).to[collection.immutable.Iterable]
}).mapAsync(1)(identity).takeWhile(_.nonEmpty).runForeach(println)
The following is one way to achieve the same behavior with Akka Streams, using your DataSource class:
import scala.concurrent.Future
import scala.util.Random
import akka.actor.ActorSystem
import akka.stream._
import akka.stream.scaladsl._
object StreamsExample extends App {
implicit val system = ActorSystem("Sandbox")
implicit val materializer = ActorMaterializer()
val ds = new DataSource(100)
Source.fromIterator(() => Iterator.continually(ds.getData)) // line 1
.mapAsync(1)(identity) // line 2
.takeWhile(_.nonEmpty) // line 3
.runForeach(println) // line 4
}
class DataSource(size: Int) {
...
}
A simplified line-by-line overview:
line 1: Creates a stream source that continually calls ds.getData if there is downstream demand.
line 2: mapAsync is a way to deal with stream elements that are Futures. In this case, the stream elements are of type Future[List[Int]]. The argument 1 is the level of parallelism: we specify 1 here because DataSource internally uses a mutable variable, and a parallelism level greater than one could produce unexpected results. identity is shorthand for x => x, which basically means that for each Future, we pass its result downstream without transforming it.
line 3: Essentially, ds.getData is called as long as the result of the Future is a non-empty List[Int]. If an empty List is encountered, processing is terminated.
line 4: runForeach here takes a function List[Int] => Unit and invokes that function for each stream element.
Ideally, I would like to wrap the Future for each batch into a big future, and the wrapper future success when last batch returned 0 size list?
I think you are looking for a Promise.
You would set up a Promise before you start the first iteration.
This gives you promise.future, a Future that you can then use to follow the completion of everything.
In your onComplete, you add a case _ => promise.success().
Something like
def loopUntilDone(f: (List[Int]) => Unit): Future[Unit] = {
val promise = Promise[Unit]
def next(): Unit = source.getData().onComplete {
case Success(v) =>
f(v)
v match {
case h :: t => next()
case _ => promise.success()
}
case Failure(e) => promise.failure(e)
}
// get going
next(f)
// return the Future for everything
promise.future
}
// future for everything, this is a `Future[Unit]`
// its `onComplete` will be triggered when there is no more data
val everything = loopUntilDone(process)
You are probably looking for a reactive streams library. My personal favorite (and one I'm most familiar with) is Monix. This is how it will work with DataSource unchanged
import scala.concurrent.duration.Duration
import scala.concurrent.Await
import monix.reactive.Observable
import monix.execution.Scheduler.Implicits.global
object Test extends App {
val source = new DataSource(100)
val completed = // <- this is Future[Unit], completes when foreach is done
Observable.repeat(Observable.fromFuture(source.getData()))
.flatten // <- Here it's Observable[List[Int]], it has collection-like methods
.takeWhile(_.nonEmpty)
.foreach(println)
Await.result(completed, Duration.Inf)
}
I just figured out that by using flatMapConcat can achieve what I wanted to achieve. There is no point to start another question as I have had the answer already. Put my sample code here just in case someone is looking for similar answer.
This type of API is very common for some integration between traditional Enterprise applications. The DataSource is to mock the API while the object App is to demonstrate how the client code can utilize Akka Stream to consume the APIs.
In my small project the API was provided in SOAP, and I used scalaxb to transform the SOAP to Scala async style. And with the client calls demonstrated in the object App, we can consume the API with AKKA Stream. Thanks for all for the help.
class DataSource(size: Int) {
private var transactionId: Long = 0
private val transactionCursorMap: mutable.HashMap[TransactionId, Set[ReadCursorId]] = mutable.HashMap.empty
private val cursorIteratorMap: mutable.HashMap[ReadCursorId, Iterator[List[Int]]] = mutable.HashMap.empty
implicit val g = scala.concurrent.ExecutionContext.global
case class TransactionId(id: Long)
case class ReadCursorId(id: Long)
def startTransaction(): Future[TransactionId] = {
Future {
synchronized {
transactionId += transactionId
}
val t = TransactionId(transactionId)
transactionCursorMap.update(t, Set(ReadCursorId(0)))
t
}
}
def createCursorId(t: TransactionId): ReadCursorId = {
synchronized {
val c = transactionCursorMap.getOrElseUpdate(t, Set(ReadCursorId(0)))
val currentId = c.foldLeft(0l) { (acc, a) => acc.max(a.id) }
val cId = ReadCursorId(currentId + 1)
transactionCursorMap.update(t, c + cId)
cursorIteratorMap.put(cId, createIterator)
cId
}
}
def createIterator(): Iterator[List[Int]] = {
(for {i <- 1 to 100} yield List.fill(100)(i)).toIterator
}
def startRead(t: TransactionId): Future[ReadCursorId] = {
Future {
createCursorId(t)
}
}
def getData(cursorId: ReadCursorId): Future[List[Int]] = {
synchronized {
Future {
Thread.sleep(Random.nextInt(100))
cursorIteratorMap.get(cursorId) match {
case Some(i) => i.next()
case _ => List()
}
}
}
}
}
object Test extends App {
val source = new DataSource(10)
implicit val system = ActorSystem("Sandbox")
implicit val materializer = ActorMaterializer()
implicit val g = scala.concurrent.ExecutionContext.global
//
// def process(v: List[Int]): Unit = {
// println(v)
// }
//
// def next(f: (List[Int]) => Unit): Unit = {
// val fut = source.getData()
// fut.onComplete {
// case Success(v) => {
// f(v)
// v match {
//
// case h :: t => next(f)
//
// }
// }
//
// }
//
// }
//
// next(process)
//
// Thread.sleep(1000000000)
val s = Source.fromFuture(source.startTransaction())
.map { e =>
source.startRead(e)
}
.mapAsync(1)(identity)
.flatMapConcat(
e => {
Source.fromIterator(() => Iterator.continually(source.getData(e)))
})
.mapAsync(5)(identity)
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runForeach(println)
/*
val done = Source.fromIterator(() => Iterator.continually(source.getData())).mapAsync(1)(identity)
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runFold(List[List[Int]]()) { (acc, r) =>
// println("=======" + acc + r)
r :: acc
}
done.onSuccess {
case e => {
e.foreach(println)
}
}
done.onComplete(_ => system.terminate())
*/
}
I've got some code in my play framework app that parses a JSON request and uses it to update a user's data. The problem is that I need to return a Future[Result], but my userDAO.update function returns a Future[Int] so I have nested futures.
I've resorted to using Await which isn't very good. How can I rewrite this code to avoid the nested future?
def patchCurrentUser() = Action.async { request =>
Future {
request.body.asJson
}.map {
case Some(rawJson) => Json.fromJson[User](rawJson).map { newUser =>
val currentUserId = 1
logger.info(s"Retrieving users own profile for user ID $currentUserId")
val futureResult: Future[Result] = userDAO.findById(currentUserId).flatMap {
case Some(currentUser) =>
val mergedUser = currentUser.copy(
firstName = newUser.firstName // ... and the other fields
)
userDAO.update(mergedUser).map(_ => Ok("OK"))
case _ => Future { Status(404) }
}
import scala.concurrent.duration._
// this is bad. How can I get rid of this?
Await.result(futureResult, 1 seconds)
}.getOrElse(Status(400))
case _ => Status(400)
}
}
Update:
Sod's law: Just after posting this I worked it out:
Future {
request.body.asJson
}.flatMap {
case Some(rawJson) => Json.fromJson[User](rawJson).map { newUser =>
val currentUserId = 1
userDAO.findById(currentUserId).flatMap {
case Some(currentUser) =>
val updatedUser = currentUser.copy(
firstName = newUser.firstName
)
userDAO.update(updatedUser).map(_ => Ok("OK"))
case _ => Future { Status(404) }
}
}.getOrElse(Future(Status(400)))
case _ => Future(Status(400))
}
But, is there a more elegant way? It seems like I'm peppering Future() around quite liberally which seems like a code smell.
Use flatMap instead of map.
flatMap[A, B](f: A => Future[B])
map[A, B](f: A => B)
More elegant way is to use for comprehension
Using For comprehension Code looks like this
for {
jsonOpt <- Future (request.body.asJson)
result <- jsonOpt match {
case Some(json) =>
json.validate[User] match {
case JsSuccess(newUser, _ ) =>
for {
currentUser <- userDAO.findById(1)
_ <- userDAO.update(currentUser.copy(firstName = newUser.firstName))
} yield Ok("ok")
case JsError(_) => Future(Status(400))
}
case None => Future(Status(400))
}
} yield result
As #pamu said it might clear your code a bit if you would use a for comprehension.
Another interesting approach (and more pure in terms of Functional Programming) would be to use monad transformers (normally a type similar to Future[Option[T]] screams monad transformer).
You should take a look at libraries like cats (and or scalaz). I'll try to give a small "pseudo code" example using cats (because I don't have play framework locally):
import cats.data.OptionT
import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
def convertJsonToUser(json: Json): Future[Option[User]] = Json.fromJson[User](json)
def convertBodyToJson(request: Request): Future[Option[Json]] = Future {request.body.asJson}
def updateUser(user: User): Future[HttpResult] = Future {
// update user
Ok("ok")
}
def myFunction: Future[HttpResult] = {
val resultOpt: OptionT[Future, HttpResult] = for {
json <- OptionT(convertBodyToJson(request))
user <- OptionT(convertJsonToUser(json))
result <- OptionT.lift(updateUser(user))
} yield result
result.getOrElseF(Future {Status(400)})
}
As you can see, in this case the monad transformers allow to treat a type like Future[Option[T]] as a single "short-circuiting" type (e.g. the for comprehension will stop if you have either a failed future, or a future containing a None).
I have the following functions:
//retrieves record from database
def getAll: Future[List[User]] = {
try {
Logger.info("Getting all user record.")
db.run(userTableQuery.to[List].result)
}
catch {
case ex: Exception => Logger.error("Exception in getting all user record. " + ex)
Future {
List[User]()
}
}
}
//checks whethe the email exist in list or not
def checkEmail(email : String): Future[Option[User]] ={
/* userRepo.getAll.map(userList => userList.filter(user => user.email == email).map { value => println(value)
userList
})*/
userRepo.getAll.map(userList => userList.filter(user => user.email == email).headOption)
}
//allows to sign in and redirects to dashboard
def signIn() = {
Logger.debug("signingIn in progress. ")
loginForm.bindFromRequest.fold(
formWithErrors => {
Logger.error("Sign-In badRequest.")
Future(BadRequest(views.html.home(webJarAssets, formWithErrors, signUpForm)))
},
validData => {
userService.checkEmail(validData.email).map(value => {
value match {
case Some(us) =>Redirect(routes.HomeController.homePage).flashing("ERROR" -> "User exist")
case None => Redirect(routes.HomeController.homePage).flashing("ERROR" -> "User doesn't exist")
}
}
)
}
)
}
But when I call signin() it always returns None.
I used some debugger code and I guess filter() inside checkMail() is not working properly.
However getall() working properly and gives all the record in database.
I think the problem is in how you compare the user email with the provided one inside the filter in the checkMail() function.
Strings equality is a bit tricky, if you compare them using == you are comparing the objects and not the values so you should use .equals() to compare the values.
You can read more on this blog post
Try to rewrite checkMail() like this:
def checkEmail(email : String): Future[Option[User]] ={
userRepo.getAll.map(userList => userList.filter(user => user.email.equals( email ) ).headOption)
}
You can also simplify .filter() e .headOption using find(), it does the same thing only in one command. You can rewrite it like this:
def checkEmail(email : String): Future[Option[User]] ={
userRepo.getAll.map(userList => userList.find(user => user.email.equals( email ) ) )
}
Instead of using filter you may use find method under checkmail. And also, since this is scala you are using "==" correctly, please see blog here
I hope this code would fix:
//checks whethe the email exist in list or not
def checkEmail(email : String): Future[Option[User]] ={
/* userRepo.getAll.map(userList => userList.filter(user => user.email == email).map { value => println(value)
userList
})*/
userRepo.getAll.map(userList => userList.find(user => user.email == email))
}
I tried to simulate/experiment regarding your implementation in direct way using the terminal:
scala> case class User(email: String)
defined class User
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> val allUser = scala.concurrent.Future {List(User("carl#test.com"), User("los#test.com"), User("pos#test.com"))}
allUser: scala.concurrent.Future[List[User]] = scala.concurrent.impl.Promise$DefaultPromise#751d3241
scala> val checkmail = allUser.map(userlist=>userlist.find(user=>user.email == "carl#test.com"))
checkmail: scala.concurrent.Future[Option[User]] = scala.concurrent.impl.Promise$DefaultPromise#1358b28e
scala> val rslt = checkmail.map(value => value match {case Some(x) =>println(x); x.email case None => println("None"); "nothing" })
rslt: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise#18324f97
User(carl#test.com)
scala> import scala.concurrent.duration._
import scala.concurrent.duration._
scala> import scala.concurrent._
import scala.concurrent._
scala> Await.result(rslt, 3 seconds)
warning: there was one feature warning; re-run with -feature for details
res8: String = carl#test.com
I am just new to learning Scala and the related technologies.I am coming across the problem where the loadUser should return a record but its coming empty.
I am getting the following error:
java.util.NoSuchElementException: None.get
I appreciate this is not ideal Scala, so feel free to suggest me improvements.
class MongoDataAccess extends Actor {
val message = "Hello message"
override def receive: Receive = {
case data: Payload => {
val user: Future[Option[User]] = MongoDataAccess.loadUser(data.deviceId)
val twillioApiAccess = context.actorOf(Props[TwillioApiAccess], "TwillioApiAccess")
user onComplete {
case Failure(exception) => println(exception)
case p: Try[Option[User]] => p match {
case Failure(exception) => println(exception)
case u: Try[Option[User]] => twillioApiAccess ! Action(data, u.get.get.phoneNumber, message)
}
}
}
case _ => println("received unknown message")
}
}
object MongoDataAccess extends MongoDataApi {
def connect(): Future[DefaultDB] = {
// gets an instance of the driver
val driver = new MongoDriver
val connection = driver.connection(List("192.168.99.100:32768"))
// Gets a reference to the database "sensor"
connection.database("sensor")
}
def props = Props(new MongoDataAccess)
def loadUser(deviceId: UUID): Future[Option[User]] = {
println(s"Loading user from the database with device id: $deviceId")
val query = BSONDocument("deviceId" -> deviceId.toString)
// By default, you get a Future[BSONCollection].
val collection: Future[BSONCollection] = connect().map(_.collection("profile"))
collection flatMap { x => x.find(query).one[User] }
}
}
Thanks
There is no guaranty the find-one (.one[T]) matches at least one document in your DB, so you get an Option[T].
Then it's up to you to consider (or not) that having found no document is a failure (or not); e.g.
val u: Future[User] = x.find(query).one[User].flatMap[User] {
case Some(matchingUser) => Future.successful(matchingUser)
case _ => Future.failed(new MySemanticException("No matching user found"))
}
Using .get on Option is a bad idea anyway.