How to avoid the flatmap after for

Viewed 132

I have the following code snippet:

(for {
  _ <- LiveUserQuery.make(DbManager.failRollback).create(user)
  - <- IO.sleep(2.seconds)
  a <- router.run(Request(GET, uri"/user/d85ec250-bb5c-11ea-b3de-0242ac130030")).value
} yield a).flatMap {
  case Some(req) =>
    req.as[User].map { u =>
      val is_uuid_valid = u.id.compareTo(UUID.fromString("d85ec250-bb5c-11ea-b3de-0242ac130030")) == 0
      expect(is_uuid_valid) && expect(u.gender == "F")
    }
  case None => expect(false)
}

and would like to avoid the flatMap after the for. How to move the code block from flatMap into for?

4 Answers

You can use a match expression:

for {
  _ <- LiveUserQuery.make(DbManager.failRollback).create(user)
  - <- IO.sleep(2.seconds)
  a <- router.run(Request(GET, uri"/user/d85ec250-bb5c-11ea-b3de-0242ac130030")).value
  result <- a match {
    case Some(req) =>
      req.as[User].map { u =>
        val is_uuid_valid = u.id.compareTo(UUID.fromString("d85ec250-bb5c-11ea-b3de-0242ac130030")) == 0
        expect(is_uuid_valid) && expect(u.gender == "F")
      }
    case None => expect(false)
  }
} yield result

Similar to Matthias but using fold instead.

for {
  _ <- LiveUserQuery.make(DbManager.failRollback).create(user)
  - <- IO.sleep(2.seconds)
  a <- router.run(Request(GET, uri"/user/d85ec250-bb5c-11ea-b3de-0242ac130030")).value
  result <- a.fold(ifEmpty = expect(false)) { req =>
    req.as[User].map { u =>
      val is_uuid_valid = u.id.compareTo(UUID.fromString("d85ec250-bb5c-11ea-b3de-0242ac130030")) == 0
      expect(is_uuid_valid) && expect(u.gender == "F")
    }
  }
} yield result

Try OptionT

(for {
  _ <- OptionT.liftF(LiveUserQuery.make(DbManager.failRollback).create(user))
  _ <- OptionT.liftF(IO.sleep(2.seconds))
  a <- OptionT(router.run(Request(GET, uri"/user/d85ec250-bb5c-11ea-b3de-0242ac130030")).value)
  u <- OptionT.liftF(a.as[User])
  is_uuid_valid = u.id.compareTo(UUID.fromString("d85ec250-bb5c-11ea-b3de-0242ac130030")) == 0
  res <- OptionT.liftF(expect(is_uuid_valid) && expect(u.gender == "F"))
} yield res).getOrElseF(expect(false))

Just another way to do it with an extra for/yield:

for {
  _ <- LiveUserQuery.make(DbManager.failRollback).create(user)
  _ <- IO.sleep(2.seconds)
  a <- router.run(Request(GET, uri"/user/d85ec250-bb5c-11ea-b3de-0242ac130030")).value
  res = (for {
    req <- a
    u <- req.as[User]
    is_uuid_valid = u.id.compareTo(UUID.fromString("d85ec250-bb5c-11ea-b3de-0242ac130030")) == 0
  } yield (expect(is_uuid_valid) && expect(u.gender == "F"))).getOrElse(expect(false))
} yield res
Related