package com.raizlabs.android.dbflow.rx.language;
import android.support.annotation.NonNull;
import com.raizlabs.android.dbflow.config.FlowLog;
import com.raizlabs.android.dbflow.list.FlowCursorIterator;
import com.raizlabs.android.dbflow.sql.language.CursorResult;
import java.util.concurrent.atomic.AtomicLong;
import rx.Observable;
import rx.Producer;
import rx.Subscriber;
import rx.functions.Action1;
import rx.internal.operators.BackpressureUtils;
/**
* Description: Wraps a {@link RXModelQueriable} into a {@link Observable.OnSubscribe}
* for each element represented by the query.
*/
public class CursorResultSubscriber<T> implements Observable.OnSubscribe<T> {
@NonNull
private final RXModelQueriable<T> modelQueriable;
public CursorResultSubscriber(@NonNull RXModelQueriable<T> modelQueriable) {
this.modelQueriable = modelQueriable;
}
@Override
public void call(Subscriber<? super T> subscriber) {
subscriber.setProducer(new ElementProducer(subscriber));
}
private class ElementProducer implements Producer {
private final Subscriber<? super T> subscriber;
private final AtomicLong emitted;
private final AtomicLong requested;
ElementProducer(Subscriber<? super T> subscriber) {
this.subscriber = subscriber;
requested = new AtomicLong();
emitted = new AtomicLong();
}
@Override
public void request(final long n) {
if (n == Long.MAX_VALUE && requested.compareAndSet(0, Long.MAX_VALUE)
|| n > 0 && BackpressureUtils.getAndAddRequest(requested, n) == 0) {
// emitting all elements
modelQueriable.queryResults().subscribe(new CursorResultAction(n));
}
}
private class CursorResultAction implements Action1<CursorResult<T>> {
private final long limit;
private CursorResultAction(long limit) {
this.limit = limit;
}
@Override
public void call(CursorResult<T> ts) {
final int starting = limit == Long.MAX_VALUE && requested.compareAndSet(0, Long.MAX_VALUE)
? 0 : emitted.intValue();
long limit = this.limit + starting;
while (limit > 0) {
FlowCursorIterator<T> iterator = ts.iterator(starting, limit);
try {
long i = 0;
while (!subscriber.isUnsubscribed() && iterator.hasNext() && i++ < limit) {
subscriber.onNext(iterator.next());
}
emitted.addAndGet(i);
// no more items
if (!subscriber.isUnsubscribed() && i < limit) {
subscriber.onCompleted();
break;
}
limit = requested.addAndGet(-limit);
} catch (Exception e) {
FlowLog.logError(e);
subscriber.onError(e);
} finally {
try {
iterator.close();
} catch (Exception e) {
FlowLog.logError(e);
subscriber.onError(e);
}
}
}
}
}
}
}