j3d
j3d

Reputation: 9734

Play & JSON Transformations: How to deal with optional input and handle possible failures

The following find method should return any document that matches the specified selection criteria and in case sort them as specified by optional parameter sort:

class DaoComponent {

  ...

  val toObjectId = (__.json.update((__ \ '_id \ '$oid).json.copyFrom((__ \ 'id).json.pick))
    andThen (__ \ 'id).json.prune
  )

  ...

  def find(selector: JsValue, sort: Option[JsValue]): Future[Seq[A]] = {
    selector.transform(toObjectId).flatMap { s =>
    sort.map(_.transform((__ \ 'ignore).json.prune)).map { o =>

      // how do I get 'o' to be either None or Some(content of JsSuccess)?

      collection.find(s)
        .sort(o.getOrElse(Json.obj())
        .cursor[JsValue].collect[Vector](0)
    }.recoverTotal { errors =>
       Future.failed(JsError.toFlatJson(errors))
    }   
  }
}

In the code above, let's isolate the line where I need your valuable support:

sort.map(_.transform((__ \ 'ignore).json.prune)).map { o =>

Optional parameter sort has to be transformed only if defined... and this is achieved with map. Now the problem is that transform returns a JsResult, and I want o to be either Some(jsValue) when optional parameter sort is defined and transform succeeds, or None when transform fails or optional parameter sort is not defined.

Alternatively, instead of getting None when _.transform fails, it would be great if I could handle the failure in the recoverTotal block.

Upvotes: 0

Views: 564

Answers (1)

millhouse
millhouse

Reputation: 10007

Expanding on my comment -

I think that the right combination of flatMap and converting your JsResult asOpt will get what you want:

sort.flatMap(_.transform((__ \ 'ignore).json.prune).asOpt).map { o =>
  // Code in here only executed iff sort defined and transform succeeds
  ...
}

BTW in my tests I couldn't actually get transform to "fail" in this case - I think prune is quite tolerant if the given JSON is not present. I could get it to fail appropriately like this:

sort.flatMap(_.transform((__ \ 'ignore).json.pick).asOpt).map { o =>

Upvotes: 1

Related Questions