0

I am trying to find an available slug in mongodb using Play2 and reactivemongo. I came up with the following recursive method.

  private def findSlug(base: String, index: Int): String = {
    val slug: String = Slug({
      base + "-" + index
    })
    for {
      user <- findOne(BSONDocument("slug" -> slug))
    } yield {
      user match {
        case None => slug
        case Some(user) => findSlug(base, index+1)

      }
    }
  }

I get the following error

found   : scala.concurrent.Future[String]
required: String
        user <- findOne(BSONDocument("slug" -> slug))
             ^

I played around a lot with changing return types, mapping the result of the yield, etc. but somehow I think there might be a far simpler, concise and correct solution. It all boils down to having a recursive function that calls another asynchronous function I think.

If I change the return type of findSlug to Future[String] I get

[error]  found   : scala.concurrent.Future[String]
[error]  required: String
[error]         case Some(user) => findSlug(base, index+1)
[error]                                    ^

What would be the correct and idiomatic solution?

DanielKhan
  • 1,190
  • 1
  • 9
  • 18

1 Answers1

1

I personally think that making the return type a Future[String] is the right way to go - it means you can keep that whole "Reactive", monadic, chain-of-Futures thing going for as long as possible (and with Play 2, that can be all the way to the Controller level - awesome).

I'm assuming that your findOne() method is just a wrapper for some Reactive Mongo query that will return a Future[Option[T]] at some point?

With that in mind, the only real problem is that there are differing levels of Futurey-ness coming from your two different cases.

Here's what I came up with. It works; is it idiomatic? You tell me ...

private def findSlug(base: String, index: Int): Future[String] = {

  // Slug stuff omitted

  findOne(BSONDocument("slug" -> slug)).flatMap { _ match {
      case None => Future.successful(slug)
      case Some(_) => findSlug(base, index+1)
    } 
  }
}
millhouse
  • 9,817
  • 4
  • 32
  • 40