3
votes

I would like to find some object (Fight) in the DB and based on it's presence return this particular object or create a new object in DB and return the newly created object. I implemented the following function:

def findOrCreateFight(firstBoxer: BoxersRow, secondBoxer: BoxersRow, eventDate: java.sql.Date): Future[FightsRow] = {
  for {
    fight <- findByBoxersAndDate(firstBoxer, secondBoxer, eventDate)
  } yield {
    fight match {
      case Some(f) => f
      case None => createAndFindFight(firstBoxer, secondBoxer, eventDate)
    }
  }
}

findByBoxersAndDate function returns Future[Option[FightsRow]] object and createAndFindFight function returns Future[FightsRow]. Now the compiler shows an error in a line with createAndFindFight function:

type mismatch; found : scala.concurrent.Future[models.Tables.FightsRow] required: models.Tables.FightsRow

OK, so I need to get the completed result of this Future in the 'case None'. I thought about onComplete function but it returns Unit, not a desired FightsRow object. Any suggestion how to fix my function to have a best scala-able effect? :)

Best Regards

2

2 Answers

3
votes

Alright, so what you'll get out of the createAndFindFight will be another Future. Solution? flatMap it, but you'll have to pretty much 'convert & unwrap' the Option to appropriate type:

findByBoxersAndDate(firstBoxer, secondBoxer, eventDate)
    .flatMap(_.map(Future.successful).getOrElse(createAndFindFight(firstBoxer, secondBoxer, eventDate)))

or, to directly match your for-comprehension:

for {
  potentialFight <- findByBoxersAndDate(firstBoxer, secondBoxer, eventDate)
  actualFight <- potentialFight match {
      case Some(f) => Future.successful(f)
      case None => createAndFindFight(firstBoxer, secondBoxer, eventDate)
  }
} yield actualFight

Disclaimer: code above is untested :)

1
votes

I added minor improvements to Patryk Ćwiek idea:

def findOrCreateFight(first: BoxersRow, second: BoxersRow, date: java.sql.Date): Future[FightsRow] =
  findByBoxersAndDate(first, second, date).flatMap {
    case None => createAndFindFight(first, second, date)
    case Some(row) => Future.successful(row)
  }