com.databricks.sdk.support.Paginator Maven / Gradle / Ivy
package com.databricks.sdk.support;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Function;
/**
* Consistent pagination support for all APIs
*
* @param request type
* @param response type
* @param item type
*/
public class Paginator implements Iterable {
private final Function requestFn;
private final Function> itemsFn;
private final Function nextPageFn;
private RS response;
private Iterator currentPage;
private Iterator all;
/**
* Repeatedly call `requestFn` until `nextPageFn` returns non-null result.
*
* Example:
* return new Paginator<>(request, impl::listRuns, ListRunsResponse::getRuns, response -> {
* Long offset = request.getOffset();
* if (offset == null) {
* offset = 0L;
* }
* offset += response.getRuns().size();
* return request.setOffset(offset);
* }).withDedupe(BaseRun::getRunId);
*
*
* @param request initial request to `requestFn` implementation, possibly with filters.
* @param requestFn implementation of request, that takes modified `request` and returns some
* results.
* @param itemsFn reference to the getter method, that returns `Collection` of results.
* @param nextPageFn return non-null request in case we need to fetch another page of results.
*/
public Paginator(
RQ request,
Function requestFn,
Function> itemsFn,
Function nextPageFn) {
this.requestFn = requestFn;
this.itemsFn = itemsFn;
this.nextPageFn = nextPageFn;
all = outerIterator();
flipNextPage(request, true);
}
private boolean flipNextPage(RQ request, boolean firstRequest) {
if (!firstRequest && request == null) {
return false;
}
response = requestFn.apply(request);
if (response == null) {
return false;
}
Collection results = itemsFn.apply(response);
if (results == null) {
return false;
}
currentPage = results.iterator();
return currentPage.hasNext();
}
private Iterator outerIterator() {
return new Iterator() {
@Override
public boolean hasNext() {
if (currentPage == null) {
return false;
}
if (currentPage.hasNext()) {
return true;
}
return flipNextPage(nextPageFn.apply(response), false);
}
@Override
public T next() {
return currentPage.next();
}
};
}
/**
* De-duplicate results across all pages with an ID
*
* This call is only necessary for offset/limit pagination, where additions/removals may get
* inconsistent results across multiple page calls
*
* @param idGetter reference to ID getter
* @return ID value, like 92384023984
* @param ID type, like Long
*/
public Iterable withDedupe(Function idGetter) {
all = new Dedupe<>(all, idGetter);
return this;
}
@Override
public Iterator iterator() {
return all;
}
}