I was wondering if there is any equivalent of the Scala fold ifEmpty function that exists for collections and options:
fold[B](ifEmpty: => B)(f: (A) => B)
This function is powerful in that it can transform between different monad types - for example the following transforms an Option[Person] to an Observable[Person]:
case class Person(name: String)
val observable = Option(Person("Paddy")).fold
{ Observable.just[Person]() } // ifEmpty function
{ p => Observable.just(p) }
My current problem is that I'd like something similar in the Reactive Extensions land. My actual scenario calls more for a "switch if empty" type of functionality - ideally:
// getFooFromCache returns Observable[Foo] from some cache service
// getFooFromDatabase returns Observable[Foo] from some database service
val sourceObservable = getFooFromCache()
sourceObservable.switchIfEmpty { getFooFromDatabase() }
So the idea here being if the source observable completes and emits nothing, then "switch" to another observable. A practical example is as suggested above - try and fetch something from a cache, if that returns nothing then fetch it from a database.
My current workaround to achieve the above looks like so:
getFooFromCache()
.map { Option(_) }
.orElse { None }
.flatMap {
case (Some(foo)) => Observable.just(foo)
case _ => getFooFromDatabase()
}
In other words - wrap the result in an Option (so that an empty result can then be emitted as a None value) and then flatMap with pattern matching.
EDIT: Here are a couple of extension functions that I will use if nothing exists:
object RxUtils {
implicit class RxUtilExtensions[+T](val observable: Observable[T]) extends AnyVal {
def toOption[U >: T]() : Observable[Option[U]] = {
observable
.map { Option(_) }
.orElse { None }
}
def switchIfEmpty[U >: T](f: () => Observable[U]) : Observable[U] = {
observable.toOption
.flatMap {
case(Some(t)) => Observable.just(t)
case _ => f()
}
}
}
}
With the above I can now do:
getFooFromCache("item.id")
.switchIfEmpty { () => getFooFromDatabase("item.id") }