bonez
bonez

Reputation: 695

Scala for comprehension and options

I'm using Scala / Slick 3.1 (This is all through the spray-slick-swagger typesafe activator) and have 4 different queries running that I want to return as one object. I'm trying to compose all the futures together into one future.

It works, but the problem is if a query fails (I.e., we search for something that doesn't exist) there is a runtime exception.

What I think I really is to fail the whole thing if one query fails and ultimately return a Future[Option]

The whole thing is hooked up through spray

so the query code looks like :

// .. snip .. FindById() 
      val a = db.run(q1.result) // Future[Seq[Tuple]]]
      val b = db.run(q2.result)
      val c = db.run(q3.result)
      val d = db.run(q4.result)

      // compose the futures together into one future
      val res = for {
    resA <- a
    resB <- b
    resC <- c
    resD <- d
  } yield {
       PhoneMerged(resA.head._1, resA.head._2, resB.map( x  => FeaturesSimple(x.featurename)).toList, resD.map(x => FeaturesvaluepairSimple(x.featuretype, x.featurevalue)).toList,
          resC.map(x => IncludedaccessorySimple(x.accessoryvalue)).toList, createPhoneImage(resA.head._1.devicemcd))
    }

It gets called with

 onComplete((modules.phonesDAA ? FindById(id)).mapTo[Future[PhoneMerged]]) {
          case Success(phoneOption) =>  {
            println(phoneOption)
            complete(phoneOption)
            }
          case Failure(ex) => {
            println("uh oh")
            complete("{}")
          }
        }

ultimately I want to return either the JSON serialized PhoneMerged object ( which works if I search for a valid id ) or "{}" empty json ...

Anybody have any thoughts on how to properly process the result / handle the error ?

Upvotes: 0

Views: 570

Answers (1)

Vered Rosen
Vered Rosen

Reputation: 381

You could make the FindById function return a Future[Option[PhoneMerged]] and handle the failure case inside using a Future combinator such as recover.
For example:

  val a = db.run(q1.result)
  // Future[Seq[Tuple]]]
  val b = db.run(q2.result)
  val c = db.run(q3.result)
  val d = db.run(q4.result)

  // compose the futures together into one future
  val res = for {
    resA <- a
    resB <- b
    resC <- c
    resD <- d
  } yield {
      Some(PhoneMerged(resA.head._1, resA.head._2, resB.map(x => FeaturesSimple(x.featurename)).toList, resD.map(x => FeaturesvaluepairSimple(x.featuretype, x.featurevalue)).toList,
        resC.map(x => IncludedaccessorySimple(x.accessoryvalue)).toList, createPhoneImage(resA.head._1.devicemcd)))
    } recover {case e: YourExceptionType => None}

Upvotes: 1

Related Questions