#599 - ElasticSearch - add query join support for find, findList, findPagedList, findEach, findEachWhile

This commit is contained in:
Robin Bygrave
2016-03-14 17:40:26 +13:00
parent fa451078b7
commit b99f002968
27 changed files with 276 additions and 87 deletions
@@ -1,5 +1,6 @@
package com.avaje.ebean;
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -48,12 +49,12 @@ public interface DocumentStore {
* If the document is not found null is returned.
*/
@Nullable
<T> T find(Class<T> beanType, Object id);
<T> T find(DocQueryRequest<T> request);
/**
* Execute the query against the document store returning the list.
* Execute the find list query. This request is prepared to execute secondary queries.
*/
<T> List<T> findList(Query<T> query);
<T> List<T> findList(DocQueryRequest<T> request);
/**
* Execute the query against the document store returning the paged list.
@@ -61,7 +62,7 @@ public interface DocumentStore {
* The query should have <code>firstRow</code> or <code>maxRows</code> set prior to calling this method.
* </p>
*/
<T> PagedList<T> findPagedList(Query<T> query);
<T> PagedList<T> findPagedList(DocQueryRequest<T> request);
/**
* Execute the query against the document store with the expectation of a large set of results
@@ -70,7 +71,7 @@ public interface DocumentStore {
* For example, with the ElasticSearch doc store this uses SCROLL.
* </p>
*/
<T> void findEach(Query<T> query, QueryEachConsumer<T> consumer);
<T> void findEach(DocQueryRequest<T> query, QueryEachConsumer<T> consumer);
/**
* Execute the query against the document store with the expectation of a large set of results
@@ -82,7 +83,7 @@ public interface DocumentStore {
* For example, with the ElasticSearch doc store this uses SCROLL.
* </p>
*/
<T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer);
<T> void findEachWhile(DocQueryRequest<T> query, QueryEachWhileConsumer<T> consumer);
/**
* Process the queue entries sending updates to the document store or queuing them for later processing.
@@ -31,6 +31,11 @@ public interface BeanCollection<E> extends Serializable {
ALL
}
/**
* Load bean from another collection.
*/
void loadFrom(BeanCollection<?> other);
/**
* Add a bean to the list/set with modifyListen notification.
*/
@@ -1,5 +1,6 @@
package com.avaje.ebean.common;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
@@ -64,6 +65,15 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
list.add((E) bean);
}
@Override
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
if (list == null) {
list = new ArrayList<E>();
}
list.addAll((Collection<? extends E>) other.getActualDetails());
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
@@ -1,5 +1,6 @@
package com.avaje.ebean.common;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
@@ -51,6 +52,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
return !touched && (map == null || map.isEmpty());
}
@Override
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
BeanMap<K,E> otherMap = (BeanMap<K,E>)other;
internalPutNull();
map.putAll(otherMap.getActualMap());
}
public void internalPutNull() {
if (map == null) {
map = new LinkedHashMap<K, E>();
@@ -1,5 +1,6 @@
package com.avaje.ebean.common;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebean.bean.BeanCollectionAdd;
import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
@@ -57,6 +58,15 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
set.add((E) bean);
}
@Override
@SuppressWarnings("unchecked")
public void loadFrom(BeanCollection<?> other) {
if (set == null) {
set = new LinkedHashSet<E>();
}
set.addAll((Collection<? extends E>) other.getActualDetails());
}
@Override
public void internalAddWithCheck(Object bean) {
if (set == null || !set.contains(bean)) {
@@ -20,7 +20,7 @@ public interface JsonBeanReader<T> {
/**
* Create a new reader taking the context from the existing one but using a new JsonParser.
*/
JsonBeanReader<T> forJson(JsonParser moreJson);
JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext);
/**
* Add a bean explicitly to the persistence context.
@@ -23,6 +23,8 @@ public class JsonReadOptions {
protected PersistenceContext persistenceContext;
protected Object loadContext;
/**
* Default constructor.
*/
@@ -100,4 +102,19 @@ public class JsonReadOptions {
public PersistenceContext getPersistenceContext() {
return persistenceContext;
}
/**
* Return the load context to use.
*/
public Object getLoadContext() {
return loadContext;
}
/**
* Set the load context to use.
*/
public void setLoadContext(Object loadContext) {
this.loadContext = loadContext;
}
}
@@ -16,38 +16,40 @@ public interface LoadContext {
*/
int getSecondaryQueriesMinBatchSize(int defaultQueryBatch);
/**
* Execute any secondary (+query) queries if there are any defined.
* @param parentRequest the originating query request
*/
void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
/**
* Execute any secondary (+query) queries if there are any defined.
*
* @param parentRequest the originating query request
* @param forEach set true when using findEach iteration
*/
void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, boolean forEach);
/**
* Return the node for a given path which is used by AutoTune profiling.
*/
ObjectGraphNode getObjectGraphNode(String path);
* Return the node for a given path which is used by AutoTune profiling.
*/
ObjectGraphNode getObjectGraphNode(String path);
/**
* Return the persistence context used by this query and future lazy loading.
*/
PersistenceContext getPersistenceContext();
/**
* Return the persistence context used by this query and future lazy loading.
*/
PersistenceContext getPersistenceContext();
/**
* Set the persistence context used by this query and future lazy loading.
* <p>
* Used by query iterator when processing large result sets.
* </p>
*/
void resetPersistenceContext(PersistenceContext persistenceContext);
/**
* Set the persistence context used by this query and future lazy loading.
* <p>
* Used by query iterator when processing large result sets.
* </p>
*/
void resetPersistenceContext(PersistenceContext persistenceContext);
/**
* Register a Bean for lazy loading.
*/
void register(String path, EntityBeanIntercept ebi);
/**
* Register a Bean for lazy loading.
*/
void register(String path, EntityBeanIntercept ebi);
/**
* Register a collection for lazy loading.
*/
void register(String path, BeanCollection<?> bc);
/**
* Register a collection for lazy loading.
*/
void register(String path, BeanCollection<?> bc);
}
@@ -14,5 +14,5 @@ public interface LoadSecondaryQuery {
/**
* Execute the secondary query with a given batch size.
*/
void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach);
}
@@ -1124,7 +1124,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
SpiOrmQueryRequest<T> request = createQueryRequest(spiQuery, t);
if (request.isUseDocStore()) {
return docStore().find(query.getBeanType(), query.getId());
return docStore().find(request);
}
try {
request.initTransIfRequired();
@@ -1329,7 +1329,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
if (spiQuery.isUseDocStore()) {
return docStore().findPagedList(query);
return docStore().findPagedList(createQueryRequest(Type.LIST, query, transaction));
}
return new LimitOffsetPagedList<T>(this, spiQuery);
@@ -1340,7 +1340,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
if (request.isUseDocStore()) {
docStore().findEach(query, consumer);
docStore().findEach(request, consumer);
return;
}
@@ -1353,7 +1353,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
if (request.isUseDocStore()) {
docStore().findEachWhile(query, consumer);
docStore().findEachWhile(request, consumer);
return;
}
@@ -1398,7 +1398,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return (List<T>) result;
}
if (request.isUseDocStore()) {
return docStore().findList(query);
return docStore().findList(request);
}
try {
@@ -12,6 +12,7 @@ import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.event.BeanFindController;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebeaninternal.api.BeanIdList;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.HashQuery;
@@ -59,6 +60,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
private PersistenceContext persistenceContext;
private JsonReadOptions jsonRead;
private HashQuery cacheKey;
private CQueryPlanKey queryPlanKey;
@@ -94,8 +97,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
return ebeanServer.getDatabasePlatform().getLikeClause();
}
public void executeSecondaryQueries() {
loadContext.executeSecondaryQueries(this);
public void executeSecondaryQueries(boolean forEach) {
// disable lazy loading leaves loadContext null
if (loadContext != null) {
loadContext.executeSecondaryQueries(this, forEach);
}
}
/**
@@ -152,7 +158,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public void prepareQuery() {
adapterPreQuery();
this.secondaryQueries = query.convertJoins();
this.queryPlanKey = query.prepare(this);
}
@@ -213,9 +218,27 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
createdTransaction = true;
}
}
// initialise the persistenceContext and loadContext
this.persistenceContext = getPersistenceContext(query, transaction);
this.loadContext = new DLoadContext(this, secondaryQueries);
persistenceContext = getPersistenceContext(query, transaction);
loadContext = new DLoadContext(this, secondaryQueries);
}
/**
* Return the JsonReadOptions taking into account lazy loading and persistence context.
*/
public JsonReadOptions createJsonReadOptions() {
persistenceContext = getPersistenceContext(query, transaction);
if (query.getPersistenceContext() == null) {
query.setPersistenceContext(persistenceContext);
}
jsonRead = new JsonReadOptions();
jsonRead.setPersistenceContext(persistenceContext);
if (!query.isDisableLazyLoading()) {
loadContext = new DLoadContext(this, secondaryQueries);
jsonRead.setLoadContext(loadContext);
}
return jsonRead;
}
/**
@@ -224,6 +247,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public void flushPersistenceContextOnIterate() {
persistenceContext = new DefaultPersistenceContext();
loadContext.resetPersistenceContext(persistenceContext);
if (jsonRead != null) {
jsonRead.setPersistenceContext(persistenceContext);
jsonRead.setLoadContext(loadContext);
}
}
/**
@@ -239,7 +266,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
// determine the scope (from the query and then server)
PersistenceContextScope scope = ebeanServer.getPersistenceContextScope(query);
return (scope == PersistenceContextScope.QUERY) ? new DefaultPersistenceContext() : t.getPersistenceContext();
return (scope == PersistenceContextScope.QUERY || t == null) ? new DefaultPersistenceContext() : t.getPersistenceContext();
}
/**
@@ -7,6 +7,7 @@ import com.avaje.ebean.Version;
import com.avaje.ebean.bean.BeanCollection;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
import java.util.List;
import java.util.Map;
@@ -15,7 +16,7 @@ import java.util.Set;
/**
* Defines the ORM query request api.
*/
public interface SpiOrmQueryRequest<T> {
public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
/**
* Return the query.
@@ -107,6 +107,28 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
private final ConcurrentHashMap<String, ElComparator<T>> comparatorCache = new ConcurrentHashMap<String, ElComparator<T>>();
public void merge(EntityBean bean, EntityBean existing) {
EntityBeanIntercept fromEbi = bean._ebean_getIntercept();
EntityBeanIntercept toEbi = existing._ebean_getIntercept();
int propertyLength = toEbi.getPropertyLength();
String[] names = getProperties();
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i) ) {
BeanProperty property = getBeanProperty(names[i]);
if (!toEbi.isLoadedProperty(i)) {
Object val = property.getValue(bean);
property.setValue(existing, val);
} else if (property.isMany()) {
property.merge(bean, existing);
}
}
}
}
public enum EntityType {
ORM, EMBEDDED, SQL
}
@@ -1329,4 +1329,7 @@ public class BeanProperty implements ElPropertyValue, Property {
return DocPropertyType.STRING == type && (id || discriminator);
}
public void merge(EntityBean bean, EntityBean existing) {
// do nothing unless Many property
}
}
@@ -201,6 +201,27 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
// by default not including "Many" properties in document store
}
/**
* Copy collection value if existing is empty.
*/
@Override
public void merge(EntityBean bean, EntityBean existing) {
Object existingCollection = getVal(existing);
if (existingCollection instanceof BeanCollection<?>) {
BeanCollection<?> toBC = (BeanCollection<?>)existingCollection;
if (!toBC.isPopulated()) {
Object fromCollection = getVal(bean);
if (fromCollection instanceof BeanCollection<?>) {
BeanCollection<?> fromBC = (BeanCollection<?>)fromCollection;
if (fromBC.isPopulated()) {
toBC.loadFrom(fromBC);
}
}
}
}
}
/**
* Add the bean to the appropriate collection on the parent bean.
*/
@@ -70,13 +70,12 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
return buffer;
}
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest) {
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
}
synchronized (this) {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
@@ -87,8 +86,12 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
break;
}
}
// this is only run once - secondary query is a one shot deal
this.bufferList = null;
if (forEach) {
clear();
} else {
// this is only run once - secondary query is a one shot deal
this.bufferList = null;
}
}
}
}
@@ -182,12 +182,12 @@ public class DLoadContext implements LoadContext {
/**
* Execute all the secondary queries.
*/
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest) {
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, boolean forEach) {
if (secQuery != null) {
for (int i = 0; i < secQuery.size(); i++) {
LoadSecondaryQuery load = getLoadSecondaryQuery(secQuery.get(i).getPath());
load.loadSecondaryQuery(parentRequest);
load.loadSecondaryQuery(parentRequest, forEach);
}
}
}
@@ -21,6 +21,8 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
protected final BeanPropertyAssocMany<?> property;
private final boolean docStoreMapped;
private List<LoadBuffer> bufferList;
private LoadBuffer currentBuffer;
@@ -31,6 +33,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
this.property = property;
this.docStoreMapped = property.getTargetDescriptor().isDocStoreMapped();
// bufferList only required when using query joins (queryFetch)
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadManyContext.LoadBuffer>();
this.currentBuffer = createBuffer(firstBatchSize);
@@ -56,7 +59,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
public void configureQuery(SpiQuery<?> query) {
parent.propagateQueryState(query, desc.isDocStoreMapped());
parent.propagateQueryState(query, docStoreMapped);
query.setParentNode(objectGraphNode);
if (queryProps != null) {
queryProps.configureBeanQuery(query);
@@ -85,7 +88,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
bc.setLoader(currentBuffer);
}
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest) {
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
@@ -103,8 +106,12 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
}
}
// this is only run once - secondary query is a one shot deal
this.bufferList = null;
if (forEach) {
clear();
} else {
// this is only run once - secondary query is a one shot deal
this.bufferList = null;
}
}
}
}
@@ -131,7 +138,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
@Override
public boolean isUseDocStore() {
return context.parent.useDocStore;
return context.parent.useDocStore && context.docStoreMapped;
}
public int getBatchSize() {
@@ -316,7 +316,7 @@ public class CQueryEngine {
cquery.auditFindMany();
}
request.executeSecondaryQueries();
request.executeSecondaryQueries(false);
return beanCollection;
@@ -365,7 +365,7 @@ public class CQueryEngine {
cquery.auditFind(bean);
}
request.executeSecondaryQueries();
request.executeSecondaryQueries(false);
return (T) bean;
@@ -42,8 +42,7 @@ class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
moreToLoad = false;
}
}
// execute secondary queries
request.executeSecondaryQueries();
request.executeSecondaryQueries(true);
}
return !buffer.isEmpty();
@@ -462,10 +462,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public SpiQuerySecondary convertJoins() {
createExtraJoinsToSupportManyWhereClause();
if (!useDocStore) {
createExtraJoinsToSupportManyWhereClause();
}
markQueryJoins();
return new OrmQuerySecondary(removeQueryJoins(), removeLazyJoins());
}
@@ -845,7 +845,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
public CQueryPlanKey prepare(BeanQueryRequest<?> request) {
prepareExpressions(request);
queryPlanKey = createQueryPlanKey();
return queryPlanKey;
}
@@ -45,7 +45,7 @@ public class DJsonBeanReader<T> implements JsonBeanReader<T> {
}
@Override
public JsonBeanReader<T> forJson(JsonParser moreJson) {
return new DJsonBeanReader(desc, readJson.forJson(moreJson));
public JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext) {
return new DJsonBeanReader(desc, readJson.forJson(moreJson, resetContext));
}
}
@@ -63,21 +63,31 @@ public class ReadJson {
/**
* Construct when transferring load context, persistence context, object mapper etc to a new ReadJson instance.
*/
private ReadJson(JsonParser moreJson, ReadJson source) {
private ReadJson(JsonParser moreJson, ReadJson source, boolean resetContext) {
this.parser = moreJson;
this.rootDesc = source.rootDesc;
this.pathStack = source.pathStack;
this.visitorMap = source.visitorMap;
this.objectMapper = source.objectMapper;
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
if (resetContext) {
this.persistenceContext = new DefaultPersistenceContext();
this.loadContext = source.loadContext;
if (loadContext != null) {
loadContext.resetPersistenceContext(persistenceContext);
}
} else {
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
}
private LoadContext initLoadContext(BeanDescriptor<?> desc, JsonReadOptions readOptions) {
if (readOptions != null && readOptions.isEnableLazyLoading()) {
if (readOptions == null) return null;
if (readOptions.isEnableLazyLoading() && readOptions.getLoadContext() == null) {
return new DLoadContext(desc, persistenceContext);
} else {
return (LoadContext) readOptions.getLoadContext();
}
return null;
}
private PersistenceContext initPersistenceContext(JsonReadOptions readOptions) {
@@ -97,8 +107,8 @@ public class ReadJson {
/**
* Return a new instance of ReadJson using the existing context but with a new JsonParser.
*/
public ReadJson forJson(JsonParser moreJson) {
return new ReadJson(moreJson, this);
public ReadJson forJson(JsonParser moreJson, boolean resetContext) {
return new ReadJson(moreJson, this, resetContext);
}
/**
@@ -120,8 +130,11 @@ public class ReadJson {
return null;
}
Object contextBean = beanDesc.contextPutIfAbsent(persistenceContext, id, bean);
if (contextBean == null) {
Object existing = beanDesc.contextPutIfAbsent(persistenceContext, id, bean);
if (existing != null) {
beanDesc.merge(bean, (EntityBean)existing);
} else {
if (loadContext != null) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
if (ebi.isPartial()) {
@@ -134,7 +147,7 @@ public class ReadJson {
}
return null;
}
return contextBean;
return existing;
}
/**
@@ -0,0 +1,26 @@
package com.avaje.ebeanservice.docstore.api;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebeaninternal.api.SpiQuery;
/**
* A Query request for the document store.
*/
public interface DocQueryRequest<T> {
/**
* Return the query for this request.
*/
SpiQuery<T> getQuery();
/**
* Create JsonReadOptions taking into account persistence context and lazy loading support.
*/
JsonReadOptions createJsonReadOptions();
/**
* Execute secondary queries.
*/
void executeSecondaryQueries(boolean forEach);
}
@@ -6,7 +6,7 @@ import com.avaje.ebean.PagedList;
import com.avaje.ebean.Query;
import com.avaje.ebean.QueryEachConsumer;
import com.avaje.ebean.QueryEachWhileConsumer;
import org.jetbrains.annotations.Nullable;
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
import java.io.IOException;
import java.util.List;
@@ -60,29 +60,28 @@ public class NoneDocStore implements DocumentStore {
throw implementationNotInClassPath();
}
@Nullable
@Override
public <T> T find(Class<T> beanType, Object id) {
public <T> T find(DocQueryRequest<T> request) {
throw implementationNotInClassPath();
}
@Override
public <T> PagedList<T> findPagedList(Query<T> query) {
public <T> PagedList<T> findPagedList(DocQueryRequest<T> request) {
throw implementationNotInClassPath();
}
@Override
public <T> List<T> findList(Query<T> query) {
public <T> List<T> findList(DocQueryRequest<T> request) {
throw implementationNotInClassPath();
}
@Override
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer) {
public <T> void findEach(DocQueryRequest<T> query, QueryEachConsumer<T> consumer) {
throw implementationNotInClassPath();
}
@Override
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer) {
public <T> void findEachWhile(DocQueryRequest<T> query, QueryEachWhileConsumer<T> consumer) {
throw implementationNotInClassPath();
}