scalascala-2.9

more readable scala pattern for matching success


I find the Success case is frequently buried in a match of many errors and one success. Is there another way to write this more cleanly such that sucess stands out perhaps by having all errors in a partial function? Or perhaps, there is another way to write it but just cleaner. I am in general just looking for other ideas/solutions that could be done.

results.responseCode match {
  case Success =>
    // TODO make this less smelly. can results.results be None?
    val searchResults = results.results.get.results
    SomeService.getUsersFromThriftResults(
      userRepo,
      searchResults,
      Seq(WithCounts)) map { userResults =>
      val renderableStatuses = getStatuses(searchResults, userResults.userMap)
      new JsonAction(transformedQuery, renderableStatuses)
    }
  case ErrorInvalidQuery =>
    throw new SomeBadRequestException("invalid query")
  case ErrorOverCapacity |
       ErrorTimeout =>
    throw new SomeServiceUnavailableException("service unavailable")
  //TODO: take care of these errors differently
  //          case ErrorInvalidWorkflow |
  //               ErrorBackendFailure |
  //               ErrorEventNotFound |
  //               PartialSuccess |
  case _ =>
    throw new SomeApplicationException("internal server error")
}

Solution

  • You can chain partial functions with orElse.

    Something like

    type ResponseCode = Int // This would be the type of the results.responseCode.
    type RespHandler = PartialFunction[ResponseCode, JsonAction]
    
    val invalidQuery: RespHandler =
      { case ErrorInvalidQuery => ... }
    
    val overCapacity: RespHandler =
      { case ErrorOverCapacity => ... }
    
    results.responseCode match {
      case Success => ...
    } orElse invalidQuery orElse overCapacity orElse ...
    

    You can see more about this at this blog post: Chaining Partial Functions with orElse

    Edit: This doesn't work as written, you'll need to compose the handling and then apply it (eg (success orElse invalidQuery ..)(results.getResponseCode)).

    A better solution is to change it to return a Try[ResponseCode] and handle the exception in a Failure match block.