Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Maybe to Single from another source if Maybe completes

I would like to build a Repository class that returns a Single<Something>.

The class should first look in a Cache which returns Maybe<Something> and if the Maybe completes go off to my Service that returns Single<Something>

interface Cache {
    fun getSomething(): Maybe<Something>   
}

interface Service {
    fun getSomething(): Single<Something>   
}

class Repository (
    private val cache: Cache,
    private val service: Service
) {

    fun getSomething(): Single<Something> {
      return cache.getSomething()
               .????(feed.getSomething()) //onCompleteTransformToSingle() or similar
    }
}    

I have searched through the JavaDoc but it does not seem that a transformer for this scenario exists.

Is there a nice way of handling this?

like image 499
JDurstberger Avatar asked Dec 11 '17 16:12

JDurstberger


People also ask

How do I convert Observable to maybe?

Unfortunately, there is no straightforward way to convert an Observable to Maybe (unless you are interested in just the firstElement ). You can convert it to Single first though and then to Maybe using toMaybe . This observable is only concerned about two things, if some action is executed or an error is encountered.

What's the difference between a Observable and a Single?

Single and Completable are new types introduced exclusively at RxJava that represent reduced types of Observable , that have more concise API. Single represent Observable that emit single value or error. You can think of the differences like the differences of a method that returns: Collection of Objects - Observable.

What is Single RxJava?

Single is an Observable which only emits one item or throws an error. Single emits only one value and applying some of the operator makes no sense. Like we don't want to take value and collect it to a list.


2 Answers

Here are two fairly simple options you could use. The first I find more explicit. The second has the benefit that you will call the network on any error in the cache.

These assume a Maybe is returned from the cache. For example if no value is found in the cache, return Maybe.empty()

1) If there is an empty in the stream, switchIfEmpty() will use the alternate observable which calls the network. If no empty is in the stream, the network will never be called.

override fun getSomething(): Single<Something> {
      return cache.getSomething()
        .switchIfEmpty(
          Maybe.defer {
            feed.getSomething().toMaybe()
          }
        )
        .toSingle()
  }

2) An empty maybe will return an error when cast toSingle(), triggering the network call.

override fun getSomething(): Single<Something> {
      return cache.getSomething()
        .toSingle()
        .onErrorResumeNext {
           feed.getSomething()
        }
  }
like image 132
enyciaa Avatar answered Sep 20 '22 17:09

enyciaa


When you need to perform RxJava operations using metadata (absence of cached result), you may have to transform your observer chain into a metadata stream, using materialize().

(Apologies for my lack of fluency in Kotlin)

fun getSomething(): Single<Something> {
  return cache.getSomething()
    .toObservable()
    .materialize()
    .take(1)
    .flatMap( it.hasValue() ? Single.just( it.getValue() )
              : Single.fromCallable( apiCall() )
      );
}

The materialize() operator turns the observer stream into a stream of Notifications. You can then inspect the first notification, and if it has a value, use that. Otherwise, make your network call.

like image 39
Bob Dalgleish Avatar answered Sep 21 '22 17:09

Bob Dalgleish