DATAMONGO-1738 - Move repository query execution to fluent operations API.
We now use the fluent FindOperations API in AbstractMongoQuery and MongoQueryExecution instead of the MongoOperations. This allows us to eagerly resolve some general execution coordinates (which collection to query etc.) and thus simplify the eventual execution. Got rid of a couple of very simple QueryExecution implementations that can be replace by a simple lambda. Removed the need to read into a partially filled domain object and then map to the projection DTO as we can now tell the operations to read into the DTO directly. Adapted unit tests. Original pull request: #484.
This commit is contained in:
committed by
Mark Paluch
parent
e1f19f69bd
commit
dd8fc1a591
@@ -15,25 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.repository.query;
|
package org.springframework.data.mongodb.repository.query;
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithProjection;
|
||||||
import org.springframework.data.convert.EntityInstantiators;
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithQuery;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.CollectionExecution;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.CountExecution;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.DeleteExecution;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ExistsExecution;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagedExecution;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagingGeoNearExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.PagingGeoNearExecution;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ResultProcessingConverter;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.ResultProcessingExecution;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SingleEntityExecution;
|
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SlicedExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.SlicedExecution;
|
||||||
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.StreamExecution;
|
import org.springframework.data.mongodb.repository.query.MongoQueryExecution.StreamExecution;
|
||||||
import org.springframework.data.repository.query.ParameterAccessor;
|
import org.springframework.data.repository.query.ParameterAccessor;
|
||||||
import org.springframework.data.repository.query.RepositoryQuery;
|
import org.springframework.data.repository.query.RepositoryQuery;
|
||||||
import org.springframework.data.repository.query.ResultProcessor;
|
import org.springframework.data.repository.query.ResultProcessor;
|
||||||
|
import org.springframework.data.repository.query.ReturnedType;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +43,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
|||||||
|
|
||||||
private final MongoQueryMethod method;
|
private final MongoQueryMethod method;
|
||||||
private final MongoOperations operations;
|
private final MongoOperations operations;
|
||||||
private final EntityInstantiators instantiators;
|
private final FindOperationWithProjection<?> findOperationWithProjection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link AbstractMongoQuery} from the given {@link MongoQueryMethod} and {@link MongoOperations}.
|
* Creates a new {@link AbstractMongoQuery} from the given {@link MongoQueryMethod} and {@link MongoOperations}.
|
||||||
@@ -63,7 +58,12 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
|||||||
|
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.instantiators = new EntityInstantiators();
|
|
||||||
|
ReturnedType returnedType = method.getResultProcessor().getReturnedType();
|
||||||
|
|
||||||
|
this.findOperationWithProjection = operations//
|
||||||
|
.query(returnedType.getDomainType())//
|
||||||
|
.inCollection(method.getEntityInformation().getCollectionName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -86,52 +86,36 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
|||||||
applyQueryMetaAttributesWhenPresent(query);
|
applyQueryMetaAttributesWhenPresent(query);
|
||||||
|
|
||||||
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor);
|
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(accessor);
|
||||||
String collection = method.getEntityInformation().getCollectionName();
|
ReturnedType returnedType = processor.getReturnedType();
|
||||||
|
FindOperationWithQuery<?> find = findOperationWithProjection.as(returnedType.getTypeToRead());
|
||||||
|
|
||||||
MongoQueryExecution execution = getExecution(query, accessor,
|
MongoQueryExecution execution = getExecution(accessor, find);
|
||||||
new ResultProcessingConverter(processor, operations, instantiators));
|
|
||||||
|
|
||||||
return execution.execute(query, processor.getReturnedType().getDomainType(), collection);
|
return processor.processResult(execution.execute(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private MongoQueryExecution getExecution(MongoParameterAccessor accessor, FindOperationWithQuery<?> operation) {
|
||||||
* Returns the execution instance to use.
|
|
||||||
*
|
|
||||||
* @param query must not be {@literal null}.
|
|
||||||
* @param parameters must not be {@literal null}.
|
|
||||||
* @param accessor must not be {@literal null}.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private MongoQueryExecution getExecution(Query query, MongoParameterAccessor accessor,
|
|
||||||
Converter<Object, Object> resultProcessing) {
|
|
||||||
|
|
||||||
if (method.isStreamQuery()) {
|
|
||||||
return new StreamExecution(operations, resultProcessing);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ResultProcessingExecution(getExecutionToWrap(query, accessor), resultProcessing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MongoQueryExecution getExecutionToWrap(Query query, MongoParameterAccessor accessor) {
|
|
||||||
|
|
||||||
if (isDeleteQuery()) {
|
if (isDeleteQuery()) {
|
||||||
return new DeleteExecution(operations, method);
|
return new DeleteExecution(operations, method);
|
||||||
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
|
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
|
||||||
return new PagingGeoNearExecution(operations, accessor, method.getReturnType(), this);
|
return new PagingGeoNearExecution(operations, method, accessor, this);
|
||||||
} else if (method.isGeoNearQuery()) {
|
} else if (method.isGeoNearQuery()) {
|
||||||
return new GeoNearExecution(operations, accessor, method.getReturnType());
|
return new GeoNearExecution(operations, method, accessor);
|
||||||
} else if (method.isSliceQuery()) {
|
} else if (method.isSliceQuery()) {
|
||||||
return new SlicedExecution(operations, accessor.getPageable());
|
return new SlicedExecution(operation, accessor.getPageable());
|
||||||
|
} else if (method.isStreamQuery()) {
|
||||||
|
return new StreamExecution(operation);
|
||||||
} else if (method.isCollectionQuery()) {
|
} else if (method.isCollectionQuery()) {
|
||||||
return new CollectionExecution(operations, accessor.getPageable());
|
return q -> operation.matching(q.with(accessor.getPageable())).all();
|
||||||
} else if (method.isPageQuery()) {
|
} else if (method.isPageQuery()) {
|
||||||
return new PagedExecution(operations, accessor.getPageable());
|
return new PagedExecution(operation, accessor.getPageable());
|
||||||
} else if (isCountQuery()) {
|
} else if (isCountQuery()) {
|
||||||
return new CountExecution(operations);
|
return q -> operation.matching(q).count();
|
||||||
} else if (isExistsQuery()) {
|
} else if (isExistsQuery()) {
|
||||||
return new ExistsExecution(operations);
|
return q -> operation.matching(q).exists();
|
||||||
} else {
|
} else {
|
||||||
return new SingleEntityExecution(operations);
|
return q -> operation.matching(q).oneValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,7 @@ import lombok.NonNull;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
|
||||||
import org.springframework.data.convert.EntityInstantiators;
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Range;
|
import org.springframework.data.domain.Range;
|
||||||
@@ -34,16 +30,16 @@ import org.springframework.data.geo.GeoPage;
|
|||||||
import org.springframework.data.geo.GeoResult;
|
import org.springframework.data.geo.GeoResult;
|
||||||
import org.springframework.data.geo.GeoResults;
|
import org.springframework.data.geo.GeoResults;
|
||||||
import org.springframework.data.geo.Point;
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithQuery;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFindOperation;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.repository.query.ResultProcessor;
|
|
||||||
import org.springframework.data.repository.query.ReturnedType;
|
|
||||||
import org.springframework.data.repository.support.PageableExecutionUtils;
|
import org.springframework.data.repository.support.PageableExecutionUtils;
|
||||||
import org.springframework.data.util.CloseableIterator;
|
import org.springframework.data.util.CloseableIterator;
|
||||||
import org.springframework.data.util.StreamUtils;
|
import org.springframework.data.util.StreamUtils;
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import com.mongodb.client.result.DeleteResult;
|
import com.mongodb.client.result.DeleteResult;
|
||||||
|
|
||||||
@@ -58,7 +54,7 @@ import com.mongodb.client.result.DeleteResult;
|
|||||||
*/
|
*/
|
||||||
interface MongoQueryExecution {
|
interface MongoQueryExecution {
|
||||||
|
|
||||||
Object execute(Query query, Class<?> type, String collection);
|
Object execute(Query query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link MongoQueryExecution} for collection returning queries.
|
* {@link MongoQueryExecution} for collection returning queries.
|
||||||
@@ -68,16 +64,16 @@ interface MongoQueryExecution {
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
final class CollectionExecution implements MongoQueryExecution {
|
final class CollectionExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final @NonNull MongoOperations operations;
|
private final @NonNull ExecutableFindOperation.FindOperationWithQuery<?> find;
|
||||||
private final Pageable pageable;
|
private final @NonNull Pageable pageable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
return operations.find(query.with(pageable), type, collection);
|
return find.matching(query.with(pageable)).all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,24 +85,24 @@ interface MongoQueryExecution {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
final class SlicedExecution implements MongoQueryExecution {
|
static final class SlicedExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final @NonNull MongoOperations operations;
|
private final @NonNull FindOperationWithQuery<?> find;
|
||||||
private final @NonNull Pageable pageable;
|
private final @NonNull Pageable pageable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
int pageSize = pageable.getPageSize();
|
int pageSize = pageable.getPageSize();
|
||||||
|
|
||||||
// Apply Pageable but tweak limit to peek into next page
|
// Apply Pageable but tweak limit to peek into next page
|
||||||
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
|
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
|
||||||
List result = operations.find(modifiedQuery, type, collection);
|
List result = find.matching(modifiedQuery).all();
|
||||||
|
|
||||||
boolean hasNext = result.size() > pageSize;
|
boolean hasNext = result.size() > pageSize;
|
||||||
|
|
||||||
@@ -121,19 +117,21 @@ interface MongoQueryExecution {
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
final class PagedExecution implements MongoQueryExecution {
|
static final class PagedExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final @NonNull MongoOperations operations;
|
private final @NonNull FindOperationWithQuery<?> operation;
|
||||||
private final @NonNull Pageable pageable;
|
private final @NonNull Pageable pageable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(final Query query, final Class<?> type, final String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
final int overallLimit = query.getLimit();
|
int overallLimit = query.getLimit();
|
||||||
|
|
||||||
|
TerminatingFindOperation<?> matching = operation.matching(query);
|
||||||
|
|
||||||
// Apply raw pagination
|
// Apply raw pagination
|
||||||
query.with(pageable);
|
query.with(pageable);
|
||||||
@@ -143,35 +141,14 @@ interface MongoQueryExecution {
|
|||||||
query.limit((int) (overallLimit - pageable.getOffset()));
|
query.limit((int) (overallLimit - pageable.getOffset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return PageableExecutionUtils.getPage(operations.find(query, type, collection), pageable, () -> {
|
return PageableExecutionUtils.getPage(matching.all(), pageable, () -> {
|
||||||
|
|
||||||
long count = operations.count(query, type, collection);
|
long count = matching.count();
|
||||||
return overallLimit != 0 ? Math.min(count, overallLimit) : count;
|
return overallLimit != 0 ? Math.min(count, overallLimit) : count;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link MongoQueryExecution} to return a single entity.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
final class SingleEntityExecution implements MongoQueryExecution {
|
|
||||||
|
|
||||||
private final MongoOperations operations;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
|
||||||
return operations.findOne(query, type, collection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link MongoQueryExecution} to perform a count projection.
|
* {@link MongoQueryExecution} to perform a count projection.
|
||||||
*
|
*
|
||||||
@@ -182,36 +159,15 @@ interface MongoQueryExecution {
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
static final class CountExecution implements MongoQueryExecution {
|
static final class CountExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final MongoOperations operations;
|
private final @NonNull FindOperationWithQuery<?> operation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
return operations.count(query, type, collection);
|
return operation.count();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link MongoQueryExecution} to perform an exists projection.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 1.10
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
static final class ExistsExecution implements MongoQueryExecution {
|
|
||||||
|
|
||||||
private final MongoOperations operations;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
|
||||||
return operations.exists(query, type, collection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,25 +177,28 @@ interface MongoQueryExecution {
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class GeoNearExecution implements MongoQueryExecution {
|
static class GeoNearExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final MongoOperations operations;
|
private final MongoOperations operations;
|
||||||
|
private final MongoQueryMethod method;
|
||||||
private final MongoParameterAccessor accessor;
|
private final MongoParameterAccessor accessor;
|
||||||
private final TypeInformation<?> returnType;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
GeoResults<?> results = doExecuteQuery(query, type, collection);
|
GeoResults<?> results = doExecuteQuery(query);
|
||||||
return isListOfGeoResult() ? results.getContent() : results;
|
return isListOfGeoResult(method.getReturnType()) ? results.getContent() : results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected GeoResults<Object> doExecuteQuery(Query query, Class<?> type, String collection) {
|
protected GeoResults<Object> doExecuteQuery(Query query) {
|
||||||
|
|
||||||
|
Class<?> type = method.getReturnedObjectType();
|
||||||
|
String collection = method.getEntityInformation().getCollectionName();
|
||||||
|
|
||||||
Point nearLocation = accessor.getGeoNearLocation();
|
Point nearLocation = accessor.getGeoNearLocation();
|
||||||
NearQuery nearQuery = NearQuery.near(nearLocation);
|
NearQuery nearQuery = NearQuery.near(nearLocation);
|
||||||
@@ -261,7 +220,7 @@ interface MongoQueryExecution {
|
|||||||
return (GeoResults<Object>) operations.geoNear(nearQuery, type, collection);
|
return (GeoResults<Object>) operations.geoNear(nearQuery, type, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isListOfGeoResult() {
|
private static boolean isListOfGeoResult(TypeInformation<?> returnType) {
|
||||||
|
|
||||||
if (!returnType.getType().equals(List.class)) {
|
if (!returnType.getType().equals(List.class)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -278,20 +237,22 @@ interface MongoQueryExecution {
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
final class PagingGeoNearExecution extends GeoNearExecution {
|
static final class PagingGeoNearExecution extends GeoNearExecution {
|
||||||
|
|
||||||
private final MongoOperations operations;
|
private final MongoOperations operations;
|
||||||
|
private final MongoQueryMethod method;
|
||||||
private final MongoParameterAccessor accessor;
|
private final MongoParameterAccessor accessor;
|
||||||
private final AbstractMongoQuery mongoQuery;
|
private final AbstractMongoQuery mongoQuery;
|
||||||
|
|
||||||
public PagingGeoNearExecution(MongoOperations operations, MongoParameterAccessor accessor,
|
public PagingGeoNearExecution(MongoOperations operations, MongoQueryMethod method, MongoParameterAccessor accessor,
|
||||||
TypeInformation<?> returnType, AbstractMongoQuery query) {
|
AbstractMongoQuery query) {
|
||||||
|
|
||||||
super(operations, accessor, returnType);
|
super(operations, method, accessor);
|
||||||
|
|
||||||
this.accessor = accessor;
|
this.accessor = accessor;
|
||||||
this.operations = operations;
|
this.operations = operations;
|
||||||
this.mongoQuery = query;
|
this.mongoQuery = query;
|
||||||
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -299,19 +260,20 @@ interface MongoQueryExecution {
|
|||||||
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution.GeoNearExecution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(Query query, Class<?> type, final String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
GeoResults<Object> geoResults = doExecuteQuery(query, type, collection);
|
String collectionName = method.getEntityInformation().getCollectionName();
|
||||||
|
|
||||||
|
GeoResults<Object> geoResults = doExecuteQuery(query);
|
||||||
|
|
||||||
Page<GeoResult<Object>> page = PageableExecutionUtils.getPage(geoResults.getContent(), accessor.getPageable(),
|
Page<GeoResult<Object>> page = PageableExecutionUtils.getPage(geoResults.getContent(), accessor.getPageable(),
|
||||||
() -> {
|
() -> {
|
||||||
|
|
||||||
ConvertingParameterAccessor parameterAccessor = new ConvertingParameterAccessor(operations.getConverter(),
|
|
||||||
accessor);
|
|
||||||
Query countQuery = mongoQuery
|
Query countQuery = mongoQuery
|
||||||
.applyQueryMetaAttributesWhenPresent(mongoQuery.createCountQuery(parameterAccessor));
|
.createCountQuery(new ConvertingParameterAccessor(operations.getConverter(), accessor));
|
||||||
|
countQuery = mongoQuery.applyQueryMetaAttributesWhenPresent(countQuery);
|
||||||
|
|
||||||
return operations.count(countQuery, collection);
|
return operations.count(countQuery, collectionName);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -326,23 +288,26 @@ interface MongoQueryExecution {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
final class DeleteExecution implements MongoQueryExecution {
|
static final class DeleteExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final MongoOperations operations;
|
private final MongoOperations operations;
|
||||||
private final MongoQueryMethod method;
|
private final MongoQueryMethod method;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
|
String collectionName = method.getEntityInformation().getCollectionName();
|
||||||
|
Class<?> type = method.getEntityInformation().getJavaType();
|
||||||
|
|
||||||
if (method.isCollectionQuery()) {
|
if (method.isCollectionQuery()) {
|
||||||
return operations.findAllAndRemove(query, type, collection);
|
return operations.findAllAndRemove(query, type, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteResult writeResult = operations.remove(query, type, collection);
|
DeleteResult writeResult = operations.remove(query, type, collectionName);
|
||||||
return writeResult != null ? writeResult.getDeletedCount() : 0L;
|
return writeResult != null ? writeResult.getDeletedCount() : 0L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,82 +317,21 @@ interface MongoQueryExecution {
|
|||||||
* @since 1.7
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
final class StreamExecution implements MongoQueryExecution {
|
static final class StreamExecution implements MongoQueryExecution {
|
||||||
|
|
||||||
private final @NonNull MongoOperations operations;
|
private final @NonNull FindOperationWithQuery<?> operation;
|
||||||
private final @NonNull Converter<Object, Object> resultProcessing;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
* @see org.springframework.data.mongodb.repository.query.MongoQueryExecution#execute(org.springframework.data.mongodb.core.query.Query)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
public Object execute(Query query) {
|
||||||
|
|
||||||
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) operations.stream(query, type))
|
TerminatingFindOperation<?> matching = operation.matching(query);
|
||||||
.map(new Function<Object, Object>() {
|
|
||||||
|
|
||||||
@Override
|
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) matching.stream());
|
||||||
public Object apply(Object t) {
|
|
||||||
return resultProcessing.convert(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link MongoQueryExecution} that wraps the results of the given delegate with the given result processing.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @since 1.9
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
final class ResultProcessingExecution implements MongoQueryExecution {
|
|
||||||
|
|
||||||
private final @NonNull MongoQueryExecution delegate;
|
|
||||||
private final @NonNull Converter<Object, Object> converter;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object execute(Query query, Class<?> type, String collection) {
|
|
||||||
return converter.convert(delegate.execute(query, type, collection));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Converter} to post-process all source objects using the given {@link ResultProcessor}.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @since 1.9
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
final class ResultProcessingConverter implements Converter<Object, Object> {
|
|
||||||
|
|
||||||
private final @NonNull ResultProcessor processor;
|
|
||||||
private final @NonNull MongoOperations operations;
|
|
||||||
private final @NonNull EntityInstantiators instantiators;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object convert(Object source) {
|
|
||||||
|
|
||||||
ReturnedType returnedType = processor.getReturnedType();
|
|
||||||
|
|
||||||
if (ClassUtils.isPrimitiveOrWrapper(returnedType.getReturnedType())) {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
Converter<Object, Object> converter = new DtoInstantiatingConverter(returnedType.getReturnedType(),
|
|
||||||
operations.getConverter().getMappingContext(), instantiators);
|
|
||||||
|
|
||||||
return processor.processResult(source, converter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ package org.springframework.data.mongodb.repository.query;
|
|||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -24,12 +26,10 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.hamcrest.core.Is;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Matchers;
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
@@ -39,6 +39,9 @@ import org.springframework.data.domain.Pageable;
|
|||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperation;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithProjection;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithQuery;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.Person;
|
import org.springframework.data.mongodb.core.Person;
|
||||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
@@ -69,6 +72,9 @@ import com.mongodb.client.result.DeleteResult;
|
|||||||
public class AbstractMongoQueryUnitTests {
|
public class AbstractMongoQueryUnitTests {
|
||||||
|
|
||||||
@Mock MongoOperations mongoOperationsMock;
|
@Mock MongoOperations mongoOperationsMock;
|
||||||
|
@Mock FindOperation<?> findOperationMock;
|
||||||
|
@Mock FindOperationWithProjection<?> withProjectionMock;
|
||||||
|
@Mock FindOperationWithQuery<?> withQueryMock;
|
||||||
@Mock BasicMongoPersistentEntity<?> persitentEntityMock;
|
@Mock BasicMongoPersistentEntity<?> persitentEntityMock;
|
||||||
@Mock MongoMappingContext mappingContextMock;
|
@Mock MongoMappingContext mappingContextMock;
|
||||||
@Mock WriteResult writeResultMock;
|
@Mock WriteResult writeResultMock;
|
||||||
@@ -87,26 +93,27 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
converter.afterPropertiesSet();
|
converter.afterPropertiesSet();
|
||||||
|
|
||||||
doReturn(converter).when(mongoOperationsMock).getConverter();
|
doReturn(converter).when(mongoOperationsMock).getConverter();
|
||||||
|
doReturn(findOperationMock).when(mongoOperationsMock).query(any());
|
||||||
|
doReturn(withProjectionMock).when(findOperationMock).inCollection(any());
|
||||||
|
doReturn(withQueryMock).when(withProjectionMock).as(any());
|
||||||
|
doReturn(withQueryMock).when(withQueryMock).matching(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Test // DATAMONGO-566
|
@Test // DATAMONGO-566
|
||||||
public void testDeleteExecutionCallsRemoveCorreclty() {
|
public void testDeleteExecutionCallsRemoveCorreclty() {
|
||||||
|
|
||||||
createQueryForMethod("deletePersonByLastname", String.class).setDeleteQuery(true).execute(new Object[] { "booh" });
|
createQueryForMethod("deletePersonByLastname", String.class).setDeleteQuery(true).execute(new Object[] { "booh" });
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(1)).remove(Matchers.any(Query.class), eq(Person.class), eq("persons"));
|
verify(mongoOperationsMock, times(1)).remove(any(), eq(Person.class), eq("persons"));
|
||||||
verify(mongoOperationsMock, times(0)).find(Matchers.any(Query.class), Matchers.any(Class.class),
|
verify(mongoOperationsMock, times(0)).find(any(), any(), any());
|
||||||
Matchers.anyString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Test // DATAMONGO-566, DATAMONGO-1040
|
@Test // DATAMONGO-566, DATAMONGO-1040
|
||||||
public void testDeleteExecutionLoadsListOfRemovedDocumentsWhenReturnTypeIsCollectionLike() {
|
public void testDeleteExecutionLoadsListOfRemovedDocumentsWhenReturnTypeIsCollectionLike() {
|
||||||
|
|
||||||
createQueryForMethod("deleteByLastname", String.class).setDeleteQuery(true).execute(new Object[] { "booh" });
|
createQueryForMethod("deleteByLastname", String.class).setDeleteQuery(true).execute(new Object[] { "booh" });
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(1)).findAllAndRemove(Mockito.any(Query.class), eq(Person.class), eq("persons"));
|
verify(mongoOperationsMock, times(1)).findAllAndRemove(any(), eq(Person.class), eq("persons"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-566
|
@Test // DATAMONGO-566
|
||||||
@@ -115,21 +122,20 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
MongoQueryFake query = createQueryForMethod("deletePersonByLastname", String.class);
|
MongoQueryFake query = createQueryForMethod("deletePersonByLastname", String.class);
|
||||||
query.setDeleteQuery(true);
|
query.setDeleteQuery(true);
|
||||||
|
|
||||||
assertThat(query.execute(new Object[] { "fake" }), Is.<Object> is(0L));
|
assertThat(query.execute(new Object[] { "fake" }), is(0L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-566, DATAMONGO-978
|
@Test // DATAMONGO-566, DATAMONGO-978
|
||||||
public void testDeleteExecutionReturnsNrDocumentsDeletedFromWriteResult() {
|
public void testDeleteExecutionReturnsNrDocumentsDeletedFromWriteResult() {
|
||||||
|
|
||||||
when(deleteResultMock.getDeletedCount()).thenReturn(100L);
|
when(deleteResultMock.getDeletedCount()).thenReturn(100L);
|
||||||
when(mongoOperationsMock.remove(Matchers.any(Query.class), eq(Person.class), eq("persons")))
|
when(mongoOperationsMock.remove(any(), eq(Person.class), eq("persons"))).thenReturn(deleteResultMock);
|
||||||
.thenReturn(deleteResultMock);
|
|
||||||
|
|
||||||
MongoQueryFake query = createQueryForMethod("deletePersonByLastname", String.class);
|
MongoQueryFake query = createQueryForMethod("deletePersonByLastname", String.class);
|
||||||
query.setDeleteQuery(true);
|
query.setDeleteQuery(true);
|
||||||
|
|
||||||
assertThat(query.execute(new Object[] { "fake" }), is((Object) 100L));
|
assertThat(query.execute(new Object[] { "fake" }), is((Object) 100L));
|
||||||
verify(mongoOperationsMock, times(1)).remove(Matchers.any(Query.class), eq(Person.class), eq("persons"));
|
verify(mongoOperationsMock, times(1)).remove(any(), eq(Person.class), eq("persons"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-957
|
@Test // DATAMONGO-957
|
||||||
@@ -140,7 +146,9 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(1)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock).as(Person.class);
|
||||||
|
verify(withQueryMock).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getValue().getMeta().getComment(), nullValue());
|
assertThat(captor.getValue().getMeta().getComment(), nullValue());
|
||||||
}
|
}
|
||||||
@@ -153,7 +161,10 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(this.mongoOperationsMock, times(1)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock).as(Person.class);
|
||||||
|
verify(withQueryMock).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +176,10 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(1)).count(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock).as(Person.class);
|
||||||
|
verify(withQueryMock).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +191,10 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(this.mongoOperationsMock, times(1)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock).as(Person.class);
|
||||||
|
verify(withQueryMock).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +210,9 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(2)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock, times(2)).as(Person.class);
|
||||||
|
verify(withQueryMock, times(2)).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getAllValues().get(0).getSkip(), is(0L));
|
assertThat(captor.getAllValues().get(0).getSkip(), is(0L));
|
||||||
assertThat(captor.getAllValues().get(1).getSkip(), is(10L));
|
assertThat(captor.getAllValues().get(1).getSkip(), is(10L));
|
||||||
@@ -211,7 +230,9 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(2)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock, times(2)).as(Person.class);
|
||||||
|
verify(withQueryMock, times(2)).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
assertThat(captor.getAllValues().get(0).getLimit(), is(11));
|
assertThat(captor.getAllValues().get(0).getLimit(), is(11));
|
||||||
assertThat(captor.getAllValues().get(1).getLimit(), is(11));
|
assertThat(captor.getAllValues().get(1).getLimit(), is(11));
|
||||||
@@ -229,7 +250,9 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||||
|
|
||||||
verify(mongoOperationsMock, times(2)).find(captor.capture(), eq(Person.class), eq("persons"));
|
verify(withProjectionMock, times(2)).as(Person.class);
|
||||||
|
verify(withQueryMock, times(2)).matching(captor.capture());
|
||||||
|
verify(findOperationMock).inCollection("persons");
|
||||||
|
|
||||||
Document expectedSortObject = new Document().append("bar", -1);
|
Document expectedSortObject = new Document().append("bar", -1);
|
||||||
assertThat(captor.getAllValues().get(0).getSortObject(), is(expectedSortObject));
|
assertThat(captor.getAllValues().get(0).getSortObject(), is(expectedSortObject));
|
||||||
@@ -240,8 +263,8 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
public void doesNotTryToPostProcessQueryResultIntoWrapperType() {
|
public void doesNotTryToPostProcessQueryResultIntoWrapperType() {
|
||||||
|
|
||||||
Person reference = new Person();
|
Person reference = new Person();
|
||||||
when(mongoOperationsMock.findOne(Mockito.any(Query.class), eq(Person.class), eq("persons"))).//
|
|
||||||
thenReturn(reference);
|
doReturn(reference).when(withQueryMock).oneValue();
|
||||||
|
|
||||||
AbstractMongoQuery query = createQueryForMethod("findByLastname", String.class);
|
AbstractMongoQuery query = createQueryForMethod("findByLastname", String.class);
|
||||||
|
|
||||||
@@ -269,7 +292,6 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
private static class MongoQueryFake extends AbstractMongoQuery {
|
private static class MongoQueryFake extends AbstractMongoQuery {
|
||||||
|
|
||||||
private boolean isCountQuery;
|
private boolean isCountQuery;
|
||||||
private boolean isExistsQuery;
|
|
||||||
private boolean isDeleteQuery;
|
private boolean isDeleteQuery;
|
||||||
|
|
||||||
public MongoQueryFake(MongoQueryMethod method, MongoOperations operations) {
|
public MongoQueryFake(MongoQueryMethod method, MongoOperations operations) {
|
||||||
@@ -310,7 +332,7 @@ public class AbstractMongoQueryUnitTests {
|
|||||||
|
|
||||||
List<Person> findByFirstname(String firstname);
|
List<Person> findByFirstname(String firstname);
|
||||||
|
|
||||||
@Meta(comment = "comment", flags = {org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT})
|
@Meta(comment = "comment", flags = { org.springframework.data.mongodb.core.query.Meta.CursorOption.NO_TIMEOUT })
|
||||||
Page<Person> findByFirstname(String firstnanme, Pageable pageable);
|
Page<Person> findByFirstname(String firstnanme, Pageable pageable);
|
||||||
|
|
||||||
@Meta(comment = "comment")
|
@Meta(comment = "comment")
|
||||||
|
|||||||
@@ -15,8 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.repository.query;
|
package org.springframework.data.mongodb.repository.query;
|
||||||
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -36,6 +35,9 @@ import org.springframework.data.geo.GeoResult;
|
|||||||
import org.springframework.data.geo.GeoResults;
|
import org.springframework.data.geo.GeoResults;
|
||||||
import org.springframework.data.geo.Metrics;
|
import org.springframework.data.geo.Metrics;
|
||||||
import org.springframework.data.geo.Point;
|
import org.springframework.data.geo.Point;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperation;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperationWithQuery;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFindOperation;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
@@ -50,7 +52,6 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
|||||||
import org.springframework.data.repository.Repository;
|
import org.springframework.data.repository.Repository;
|
||||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,6 +65,8 @@ import org.springframework.util.ReflectionUtils;
|
|||||||
public class MongoQueryExecutionUnitTests {
|
public class MongoQueryExecutionUnitTests {
|
||||||
|
|
||||||
@Mock MongoOperations mongoOperationsMock;
|
@Mock MongoOperations mongoOperationsMock;
|
||||||
|
@Mock FindOperation<?> findOperationMock;
|
||||||
|
@Mock FindOperationWithQuery<?> operationMock;
|
||||||
@Mock DbRefResolver dbRefResolver;
|
@Mock DbRefResolver dbRefResolver;
|
||||||
|
|
||||||
Point POINT = new Point(10, 20);
|
Point POINT = new Point(10, 20);
|
||||||
@@ -79,46 +82,54 @@ public class MongoQueryExecutionUnitTests {
|
|||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, context);
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, context);
|
||||||
|
|
||||||
when(mongoOperationsMock.getConverter()).thenReturn(converter);
|
when(mongoOperationsMock.getConverter()).thenReturn(converter);
|
||||||
|
when(mongoOperationsMock.query(any(Class.class))).thenReturn(findOperationMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-1464
|
@Test // DATAMONGO-1464
|
||||||
public void pagedExecutionShouldNotGenerateCountQueryIfQueryReportedNoResults() {
|
public void pagedExecutionShouldNotGenerateCountQueryIfQueryReportedNoResults() {
|
||||||
|
|
||||||
when(mongoOperationsMock.find(any(Query.class), eq(Person.class), eq("person")))
|
TerminatingFindOperation<Object> terminating = mock(TerminatingFindOperation.class);
|
||||||
.thenReturn(Collections.<Person> emptyList());
|
|
||||||
|
|
||||||
PagedExecution execution = new PagedExecution(mongoOperationsMock, PageRequest.of(0, 10));
|
doReturn(terminating).when(operationMock).matching(any(Query.class));
|
||||||
execution.execute(new Query(), Person.class, "person");
|
doReturn(Collections.emptyList()).when(terminating).all();
|
||||||
|
|
||||||
verify(mongoOperationsMock).find(any(Query.class), eq(Person.class), eq("person"));
|
PagedExecution execution = new PagedExecution(operationMock, PageRequest.of(0, 10));
|
||||||
verify(mongoOperationsMock, never()).count(any(Query.class), eq(Person.class), eq("person"));
|
execution.execute(new Query());
|
||||||
|
|
||||||
|
verify(terminating).all();
|
||||||
|
verify(terminating, never()).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-1464
|
@Test // DATAMONGO-1464
|
||||||
public void pagedExecutionShouldUseCountFromResultWithOffsetAndResultsWithinPageSize() {
|
public void pagedExecutionShouldUseCountFromResultWithOffsetAndResultsWithinPageSize() {
|
||||||
|
|
||||||
when(mongoOperationsMock.find(any(Query.class), eq(Person.class), eq("person")))
|
TerminatingFindOperation<Object> terminating = mock(TerminatingFindOperation.class);
|
||||||
.thenReturn(Arrays.asList(new Person(), new Person(), new Person(), new Person()));
|
|
||||||
|
|
||||||
PagedExecution execution = new PagedExecution(mongoOperationsMock, PageRequest.of(0, 10));
|
doReturn(terminating).when(operationMock).matching(any(Query.class));
|
||||||
execution.execute(new Query(), Person.class, "person");
|
doReturn(Arrays.asList(new Person(), new Person(), new Person(), new Person())).when(terminating).all();
|
||||||
|
|
||||||
verify(mongoOperationsMock).find(any(Query.class), eq(Person.class), eq("person"));
|
PagedExecution execution = new PagedExecution(operationMock, PageRequest.of(0, 10));
|
||||||
verify(mongoOperationsMock, never()).count(any(Query.class), eq(Person.class), eq("person"));
|
execution.execute(new Query());
|
||||||
|
|
||||||
|
verify(terminating).all();
|
||||||
|
verify(terminating, never()).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-1464
|
@Test // DATAMONGO-1464
|
||||||
public void pagedExecutionRetrievesObjectsForPageableOutOfRange() throws Exception {
|
public void pagedExecutionRetrievesObjectsForPageableOutOfRange() throws Exception {
|
||||||
|
|
||||||
when(mongoOperationsMock.find(any(Query.class), eq(Person.class), eq("person")))
|
TerminatingFindOperation<Object> terminating = mock(TerminatingFindOperation.class);
|
||||||
.thenReturn(Collections.<Person> emptyList());
|
|
||||||
|
|
||||||
PagedExecution execution = new PagedExecution(mongoOperationsMock, PageRequest.of(2, 10));
|
doReturn(terminating).when(operationMock).matching(any(Query.class));
|
||||||
execution.execute(new Query(), Person.class, "person");
|
doReturn(Collections.emptyList()).when(terminating).all();
|
||||||
|
|
||||||
verify(mongoOperationsMock).find(any(Query.class), eq(Person.class), eq("person"));
|
PagedExecution execution = new PagedExecution(operationMock, PageRequest.of(2, 10));
|
||||||
verify(mongoOperationsMock).count(any(Query.class), eq(Person.class), eq("person"));
|
execution.execute(new Query());
|
||||||
|
|
||||||
|
verify(terminating).all();
|
||||||
|
verify(terminating).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMONGO-1464
|
@Test // DATAMONGO-1464
|
||||||
@@ -133,9 +144,8 @@ public class MongoQueryExecutionUnitTests {
|
|||||||
when(mongoOperationsMock.geoNear(any(NearQuery.class), eq(Person.class), eq("person")))
|
when(mongoOperationsMock.geoNear(any(NearQuery.class), eq(Person.class), eq("person")))
|
||||||
.thenReturn(new GeoResults<Person>(Arrays.asList(result, result, result, result)));
|
.thenReturn(new GeoResults<Person>(Arrays.asList(result, result, result, result)));
|
||||||
|
|
||||||
PagingGeoNearExecution execution = new PagingGeoNearExecution(mongoOperationsMock, accessor,
|
PagingGeoNearExecution execution = new PagingGeoNearExecution(mongoOperationsMock, queryMethod, accessor, query);
|
||||||
ClassTypeInformation.fromReturnTypeOf(method), query);
|
execution.execute(new Query());
|
||||||
execution.execute(new Query(), Person.class, "person");
|
|
||||||
|
|
||||||
verify(mongoOperationsMock).geoNear(any(NearQuery.class), eq(Person.class), eq("person"));
|
verify(mongoOperationsMock).geoNear(any(NearQuery.class), eq(Person.class), eq("person"));
|
||||||
verify(mongoOperationsMock, never()).count(any(Query.class), eq("person"));
|
verify(mongoOperationsMock, never()).count(any(Query.class), eq("person"));
|
||||||
@@ -152,9 +162,8 @@ public class MongoQueryExecutionUnitTests {
|
|||||||
when(mongoOperationsMock.geoNear(any(NearQuery.class), eq(Person.class), eq("person")))
|
when(mongoOperationsMock.geoNear(any(NearQuery.class), eq(Person.class), eq("person")))
|
||||||
.thenReturn(new GeoResults<Person>(Collections.<GeoResult<Person>> emptyList()));
|
.thenReturn(new GeoResults<Person>(Collections.<GeoResult<Person>> emptyList()));
|
||||||
|
|
||||||
PagingGeoNearExecution execution = new PagingGeoNearExecution(mongoOperationsMock, accessor,
|
PagingGeoNearExecution execution = new PagingGeoNearExecution(mongoOperationsMock, queryMethod, accessor, query);
|
||||||
ClassTypeInformation.fromReturnTypeOf(method), query);
|
execution.execute(new Query());
|
||||||
execution.execute(new Query(), Person.class, "person");
|
|
||||||
|
|
||||||
verify(mongoOperationsMock).geoNear(any(NearQuery.class), eq(Person.class), eq("person"));
|
verify(mongoOperationsMock).geoNear(any(NearQuery.class), eq(Person.class), eq("person"));
|
||||||
verify(mongoOperationsMock).count(any(Query.class), eq("person"));
|
verify(mongoOperationsMock).count(any(Query.class), eq("person"));
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.query;
|
|||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.springframework.data.mongodb.core.query.IsTextQuery.*;
|
import static org.springframework.data.mongodb.core.query.IsTextQuery.*;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.mongodb.MongoDbFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperation;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||||
@@ -63,6 +65,7 @@ import com.mongodb.util.JSONParseException;
|
|||||||
public class PartTreeMongoQueryUnitTests {
|
public class PartTreeMongoQueryUnitTests {
|
||||||
|
|
||||||
@Mock MongoOperations mongoOperationsMock;
|
@Mock MongoOperations mongoOperationsMock;
|
||||||
|
@Mock FindOperation<?> findOperationMock;
|
||||||
|
|
||||||
MongoMappingContext mappingContext;
|
MongoMappingContext mappingContext;
|
||||||
|
|
||||||
@@ -75,7 +78,8 @@ public class PartTreeMongoQueryUnitTests {
|
|||||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mock(MongoDbFactory.class));
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mock(MongoDbFactory.class));
|
||||||
MongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
|
MongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
|
||||||
|
|
||||||
when(mongoOperationsMock.getConverter()).thenReturn(converter);
|
doReturn(converter).when(mongoOperationsMock).getConverter();
|
||||||
|
doReturn(findOperationMock).when(mongoOperationsMock).query(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAMOGO-952
|
@Test // DATAMOGO-952
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.query;
|
|||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -36,6 +37,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||||
|
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindOperation;
|
||||||
import org.springframework.data.mongodb.core.MongoOperations;
|
import org.springframework.data.mongodb.core.MongoOperations;
|
||||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
|
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
|
||||||
@@ -67,6 +69,7 @@ public class StringBasedMongoQueryUnitTests {
|
|||||||
SpelExpressionParser PARSER = new SpelExpressionParser();
|
SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||||
|
|
||||||
@Mock MongoOperations operations;
|
@Mock MongoOperations operations;
|
||||||
|
@Mock FindOperation<Object> findOperation;
|
||||||
@Mock DbRefResolver factory;
|
@Mock DbRefResolver factory;
|
||||||
|
|
||||||
MongoConverter converter;
|
MongoConverter converter;
|
||||||
@@ -75,6 +78,8 @@ public class StringBasedMongoQueryUnitTests {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
|
||||||
this.converter = new MappingMongoConverter(factory, new MongoMappingContext());
|
this.converter = new MappingMongoConverter(factory, new MongoMappingContext());
|
||||||
|
|
||||||
|
doReturn(findOperation).when(operations).query(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user