Store
Store copied to clipboard
"The MaybeSource is empty" error occurs with persister
In README.md, there's a sample code contains:
.persister(new Persister<BufferedSource>() {
@Override
public Maybe<BufferedSource> read(Integer key) {
if (dataIsCached) {
return Observable.fromCallable(() -> userImplementedCache.get(key));
} else {
return Observable.**empty**();
}
}
With this reference code, I wrote my own persister like:
StoreBuilder.
.key<ApiKey<API, Any>, Any>()
.persister(object : Persister<Any, ApiKey<API, Any>> {
override fun read(key: ApiKey<API, Any>): Maybe<Any> {
if (key.haveLocal()) {
return key.local()
}
// Nothing is saved for the key, returns empty
return Maybe.empty()
}
....
})
.fetcher({ it.request(api).computation() })
.open()
and then i made a request like
store.fetch(key)
But it occurs java.util.NoSuchElementException: The MaybeSource is empty
I followed inside RealInternalStore.java,
there's weird code in RealInternalStore.response()
@Nonnull
Single<Parsed> response(@Nonnull final Key key) {
return fetcher()
...
.flatMap(aBoolean -> readDisk(key).toSingle()))
...
readDisk()
doesn't have code for handling empty state,
readDisk(key).toSingle()
can occurs NoSuchElementException
How can I return "empty, there's no saved response" state in Persister.read()
?
That's what confuses me most, why return Maybe
when you should convert it to Single
?
I'm confused how it can be empty when you do store.fetch. Fetch should get a new element from your fetcher save it to disk and then return. Could you post a failing test or sample please.
@digitalbuddha What if what the fetch
result is empty from very beginning?
What we normally would do is get
and the get
would fetch
when it gets nothing (that's Maybe.empty()) from persister. That what the API designed for.
Now, if we could fetch nothing from network etc. (of course there's a response but nothing we could write into persister and use case like this is not rare), the fetch
would let persister write (which would write nothing) and read( also read nothing just like when it get
) and error is coming?
One may say hey, why don't you return a empty object (not null) from persister for the situation like this. If we do that, when we get
, we get a empty object and that's all, we have to do the "get
then fetch
" ourselves which should be done by store itself.
So the problem is why should we assume that fetch
could always get new stuff and not empty?
Using Maybe.just(Unit)
for empty state inside Persister
will remove Fetcher
's result.
So, i have no choice but to implement my own persister on Fetcher
like
StoreBuilder.
.key<ApiKey<API, Any>, Any>()
.fetcher({ key ->
key.load(context)
.switchIfEmpty(key.fetch(api))
.switchIfEmpty(Maybe.error<Any>(Exception("No response")))
.doOnSuccess { key.save(context, it).subscribe() }
.toSingle()
})
.open()
I have same problem - how to distinguish between "not found in cache" and "not found on API" (both should return list of items) in persister's read
method without throwing this excepion?
Thanks for explaining! We are working on store4 and will make an elegant solution. I'll post possible solutions here. Open to suggestions as well