2

I have a set of operations that are completed in sequence, but if an intermediate sequence returns "null" I would like to abort the operation early (skip the subsequent steps).

I conjured up a function like this which given an input parameter, performs several operations against Redis and will return a product if it exists. Since it is possible that one of the intermediate requests returns a null value, the complete operation could "fail" and I would like to short circuit the unnecessary steps that come afterwards.

The nesting here is becoming crazy, and I would like to make it more legible. Is there a proper "functional" way to perform this type of "if/else" short circuiting?

def getSingleProduct(firstSku: String): Option[Product] = {
    val jedis = pool.getResource
    val sid: Array[Byte] = jedis.get(Keys.sidForSku(firstSku, sectionId, feedId).getBytes)
    Option(sid).flatMap {
      sid: Array[Byte] =>
        Option(jedis.get(Keys.latestVersionForSid(sectionId, feedId, sid))) flatMap {
          version: Array[Byte] =>
            Option(Keys.dataForSid(sectionId, feedId, version, sid)) flatMap {
              getDataKey: Array[Byte] =>
                Option(jedis.get(getDataKey)) flatMap {
                  packedData: Array[Byte] =>
                    val data = doSomeStuffWith(packedData)
                    Option(Product(data, "more interesting things"))
                }
            }
        }
    }
  }
Avba
  • 14,822
  • 20
  • 92
  • 192

1 Answers1

5

The way to do this is to use for:

for {
  sid <- Option(jedis.get(...))
  version <- Option(jedis.get(..., sid, ...))
  getDataKey <- Option(jedis.get(...version,...))
  packedData <- Option(jedis.get(getDataKey))
} yield {
  // Do stuff with packedData
}

This will return None if any of the get calls returns None, otherwise it will return Some(x) where x is the result of the yeild expression.

You might also want to consider writing a wrapper for jedis.get which returns Option(x) rather than using null as the error result.

Tim
  • 26,753
  • 2
  • 16
  • 29