Compare commits
19 Commits
3.1.4
...
1.6.1.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eae463622c | ||
|
|
6ba8144bca | ||
|
|
9d1c1a9fc5 | ||
|
|
f552ca8073 | ||
|
|
d7bd82c643 | ||
|
|
078cca83e3 | ||
|
|
93ae6815bd | ||
|
|
13dcb8cda1 | ||
|
|
a4497bcf8a | ||
|
|
6a82c47a4d | ||
|
|
8f8f5b7ce4 | ||
|
|
c683813a7a | ||
|
|
dbe983c3cb | ||
|
|
8e11fe84df | ||
|
|
9eb2856840 | ||
|
|
828b379f1f | ||
|
|
161fd8c09d | ||
|
|
dc037dfef6 | ||
|
|
c41653f9da |
8
pom.xml
8
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Data MongoDB</name>
|
||||
@@ -15,7 +15,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>1.5.0.RELEASE</version>
|
||||
<version>1.5.1.RELEASE</version>
|
||||
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>1.9.0.RELEASE</springdata.commons>
|
||||
<springdata.commons>1.9.1.RELEASE</springdata.commons>
|
||||
<mongo>2.12.3</mongo>
|
||||
<mongo.osgi>2.12.3</mongo.osgi>
|
||||
</properties>
|
||||
@@ -116,7 +116,7 @@
|
||||
<id>mongo-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</repositories>
|
||||
|
||||
</profile>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>1.6.0.RELEASE</version>
|
||||
<version>1.6.1.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
static class LazyLoadingInterceptor implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor,
|
||||
Serializable {
|
||||
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD;
|
||||
private static final Method INITIALIZE_METHOD, TO_DBREF_METHOD, FINALIZE_METHOD;
|
||||
|
||||
private final DbRefResolverCallback callback;
|
||||
private final MongoPersistentProperty property;
|
||||
@@ -192,6 +192,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
try {
|
||||
INITIALIZE_METHOD = LazyLoadingProxy.class.getMethod("getTarget");
|
||||
TO_DBREF_METHOD = LazyLoadingProxy.class.getMethod("toDBRef");
|
||||
FINALIZE_METHOD = Object.class.getDeclaredMethod("finalize");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -255,6 +256,11 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
if (ReflectionUtils.isHashCodeMethod(method)) {
|
||||
return proxyHashCode(proxy);
|
||||
}
|
||||
|
||||
// DATAMONGO-1076 - finalize methods should not trigger proxy initialization
|
||||
if (FINALIZE_METHOD.equals(method)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Object target = ensureResolved();
|
||||
|
||||
@@ -284,7 +284,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||
|
||||
final MongoPersistentProperty property = association.getInverse();
|
||||
Object value = dbo.get(property.getName());
|
||||
Object value = dbo.get(property.getFieldName());
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
|
||||
@@ -334,7 +334,8 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> entity = documentField.getPropertyEntity();
|
||||
return entity.hasIdProperty() && entity.getIdProperty().getActualType().isAssignableFrom(type);
|
||||
return entity.hasIdProperty()
|
||||
&& (type.equals(DBRef.class) || entity.getIdProperty().getActualType().isAssignableFrom(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,10 +383,16 @@ public class QueryMapper {
|
||||
*/
|
||||
protected Object convertAssociation(Object source, MongoPersistentProperty property) {
|
||||
|
||||
if (property == null || source == null || source instanceof DBRef || source instanceof DBObject) {
|
||||
if (property == null || source == null || source instanceof DBObject) {
|
||||
return source;
|
||||
}
|
||||
|
||||
if (source instanceof DBRef) {
|
||||
|
||||
DBRef ref = (DBRef) source;
|
||||
return new DBRef(ref.getDB(), ref.getRef(), convertId(ref.getId()));
|
||||
}
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
BasicDBList result = new BasicDBList();
|
||||
for (Object element : (Iterable<?>) source) {
|
||||
@@ -785,7 +792,7 @@ public class QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
public String getMappedKey() {
|
||||
return path == null ? name : path.toDotPath(getPropertyConverter());
|
||||
return path == null ? name : path.toDotPath(isAssociation() ? getAssociationConverter() : getPropertyConverter());
|
||||
}
|
||||
|
||||
protected PersistentPropertyPath<MongoPersistentProperty> getPath() {
|
||||
@@ -837,5 +844,56 @@ public class QueryMapper {
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return PropertyToFieldNameConverter.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Converter} to use for creating the mapped key of an association. Default implementation is
|
||||
* {@link AssociationConverter}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.7
|
||||
*/
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new AssociationConverter(getAssociation());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converter to skip all properties after an association property was rendered.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
protected static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final MongoPersistentProperty property;
|
||||
private boolean associationFound;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
this.property = association.getInverse();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
|
||||
if (associationFound) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (property.equals(source)) {
|
||||
associationFound = true;
|
||||
}
|
||||
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,47 +194,48 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return isAssociation() ? new AssociationConverter(getAssociation()) : new UpdatePropertyConverter(key);
|
||||
return new UpdatePropertyConverter(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getAssociationConverter()
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new UpdateAssociationConverter(getAssociation(), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converter to skip all properties after an association property was rendered.
|
||||
* Special mapper handling positional parameter {@literal $} within property names.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.7
|
||||
*/
|
||||
private static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||
private static class UpdateKeyMapper {
|
||||
|
||||
private final MongoPersistentProperty property;
|
||||
private boolean associationFound;
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
protected UpdateKeyMapper(String rawKey) {
|
||||
|
||||
Assert.hasText(rawKey, "Key must not be null or empty!");
|
||||
|
||||
this.iterator = Arrays.asList(rawKey.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
* Maps the property name while retaining potential positional operator {@literal $}.
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||
protected String mapPropertyName(MongoPersistentProperty property) {
|
||||
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
this.property = association.getInverse();
|
||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
|
||||
if (associationFound) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (property.equals(source)) {
|
||||
associationFound = true;
|
||||
}
|
||||
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,10 +243,11 @@ public class UpdateMapper extends QueryMapper {
|
||||
* contained in the source update key.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class UpdatePropertyConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final Iterator<String> iterator;
|
||||
private final UpdateKeyMapper mapper;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UpdatePropertyConverter} with the given update key.
|
||||
@@ -256,8 +258,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
|
||||
Assert.hasText(updateKey, "Update key must not be null or empty!");
|
||||
|
||||
this.iterator = Arrays.asList(updateKey.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
this.mapper = new UpdateKeyMapper(updateKey);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -266,9 +267,37 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty property) {
|
||||
return mapper.mapPropertyName(property);
|
||||
}
|
||||
}
|
||||
|
||||
String mappedName = PropertyToFieldNameConverter.INSTANCE.convert(property);
|
||||
return iterator.hasNext() && iterator.next().equals("$") ? String.format("%s.$", mappedName) : mappedName;
|
||||
/**
|
||||
* {@link Converter} retaining positional parameter {@literal $} for {@link Association}s.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
protected static class UpdateAssociationConverter extends AssociationConverter {
|
||||
|
||||
private final UpdateKeyMapper mapper;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AssociationConverter} for the given {@link Association}.
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
|
||||
|
||||
super(association);
|
||||
this.mapper = new UpdateKeyMapper(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String convert(MongoPersistentProperty source) {
|
||||
return super.convert(source) == null ? null : mapper.mapPropertyName(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
}
|
||||
|
||||
private void appendTextIndexInformation(final String dotPath,
|
||||
final TextIndexDefinitionBuilder indexDefinitionBuilder, MongoPersistentEntity<?> entity,
|
||||
final TextIndexDefinitionBuilder indexDefinitionBuilder, final MongoPersistentEntity<?> entity,
|
||||
final TextIndexIncludeOptions includeOptions, final CycleGuard guard) {
|
||||
|
||||
entity.doWithProperties(new PropertyHandler<MongoPersistentProperty>() {
|
||||
@@ -230,7 +230,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
|
||||
guard.protect(persistentProperty, dotPath);
|
||||
|
||||
if (persistentProperty.isLanguageProperty()) {
|
||||
if (persistentProperty.isExplicitLanguageProperty() && !StringUtils.hasText(dotPath)) {
|
||||
indexDefinitionBuilder.withLanguageOverride(persistentProperty.getFieldName());
|
||||
}
|
||||
|
||||
@@ -257,6 +257,10 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
|
||||
mappingContext.getPersistentEntity(persistentProperty.getActualType()), optionsForNestedType, guard);
|
||||
} catch (CyclicPropertyReferenceException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
} catch (InvalidDataAccessApiUsageException e) {
|
||||
LOGGER.warn(
|
||||
String.format("Potentially invald index structure discovered. Breaking operation for %s.",
|
||||
entity.getName()), e);
|
||||
}
|
||||
} else if (includeOptions.isForce() || indexed != null) {
|
||||
indexDefinitionBuilder.onField(propertyDotPath, weight);
|
||||
|
||||
@@ -284,7 +284,7 @@ public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, Mong
|
||||
|
||||
private void potentiallyAssertLanguageType(MongoPersistentProperty persistentProperty) {
|
||||
|
||||
if (persistentProperty.isLanguageProperty()) {
|
||||
if (persistentProperty.isExplicitLanguageProperty()) {
|
||||
assertPropertyType(persistentProperty, String.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,9 +190,18 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
|
||||
*/
|
||||
@Override
|
||||
public boolean isLanguageProperty() {
|
||||
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isAnnotationPresent(Language.class);
|
||||
return getFieldName().equals(LANGUAGE_FIELD_NAME) || isExplicitLanguageProperty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isExplicitLanguageProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isExplicitLanguageProperty() {
|
||||
return isAnnotationPresent(Language.class);
|
||||
};
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isTextScoreProperty()
|
||||
|
||||
@@ -61,14 +61,22 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
|
||||
boolean isExplicitIdProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property indicates the documents language either by having a {@link #getFieldName()} equal to
|
||||
* {@literal language} or being annotated with {@link Language}.
|
||||
* Returns true whether the property indicates the documents language either by having a {@link #getFieldName()} equal
|
||||
* to {@literal language} or being annotated with {@link Language}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6
|
||||
*/
|
||||
boolean isLanguageProperty();
|
||||
|
||||
/**
|
||||
* Returns true when property being annotated with {@link Language}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.6.1
|
||||
*/
|
||||
boolean isExplicitLanguageProperty();
|
||||
|
||||
/**
|
||||
* Returns whether the property holds the documents score calculated by text search. <br/>
|
||||
* It's marked with {@link TextScore}.
|
||||
|
||||
@@ -31,7 +31,9 @@ import org.springframework.data.geo.Shape;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
import org.springframework.data.mongodb.core.geo.Sphere;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -515,8 +517,11 @@ public class Criteria implements CriteriaDefinition {
|
||||
* @see org.springframework.data.mongodb.core.query.CriteriaDefinition#getCriteriaObject()
|
||||
*/
|
||||
public DBObject getCriteriaObject() {
|
||||
|
||||
if (this.criteriaChain.size() == 1) {
|
||||
return criteriaChain.get(0).getSingleCriteriaObject();
|
||||
} else if (CollectionUtils.isEmpty(this.criteriaChain) && !CollectionUtils.isEmpty(this.criteria)) {
|
||||
return getSingleCriteriaObject();
|
||||
} else {
|
||||
DBObject criteriaObject = new BasicDBObject();
|
||||
for (Criteria c : this.criteriaChain) {
|
||||
@@ -550,6 +555,13 @@ public class Criteria implements CriteriaDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(this.key)) {
|
||||
if (not) {
|
||||
return new BasicDBObject("$not", dbo);
|
||||
}
|
||||
return dbo;
|
||||
}
|
||||
|
||||
DBObject queryCriteria = new BasicDBObject();
|
||||
|
||||
if (!NOT_SET.equals(isValue)) {
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.List;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
@@ -88,39 +87,25 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
|
||||
applyQueryMetaAttributesWhenPresent(query);
|
||||
|
||||
Object result = null;
|
||||
|
||||
if (isDeleteQuery()) {
|
||||
result = new DeleteExecution().execute(query);
|
||||
return new DeleteExecution().execute(query);
|
||||
} else if (method.isGeoNearQuery() && method.isPageQuery()) {
|
||||
|
||||
MongoParameterAccessor countAccessor = new MongoParametersParameterAccessor(method, parameters);
|
||||
Query countQuery = createCountQuery(new ConvertingParameterAccessor(operations.getConverter(), countAccessor));
|
||||
|
||||
result = new GeoNearExecution(accessor).execute(query, countQuery);
|
||||
return new GeoNearExecution(accessor).execute(query, countQuery);
|
||||
} else if (method.isGeoNearQuery()) {
|
||||
result = new GeoNearExecution(accessor).execute(query);
|
||||
return new GeoNearExecution(accessor).execute(query);
|
||||
} else if (method.isSliceQuery()) {
|
||||
result = new SlicedExecution(accessor.getPageable()).execute(query);
|
||||
return new SlicedExecution(accessor.getPageable()).execute(query);
|
||||
} else if (method.isCollectionQuery()) {
|
||||
result = new CollectionExecution(accessor.getPageable()).execute(query);
|
||||
return new CollectionExecution(accessor.getPageable()).execute(query);
|
||||
} else if (method.isPageQuery()) {
|
||||
result = new PagedExecution(accessor.getPageable()).execute(query);
|
||||
return new PagedExecution(accessor.getPageable()).execute(query);
|
||||
} else {
|
||||
result = new SingleEntityExecution(isCountQuery()).execute(query);
|
||||
return new SingleEntityExecution(isCountQuery()).execute(query);
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Class<?> expectedReturnType = method.getReturnType().getType();
|
||||
|
||||
if (expectedReturnType.isAssignableFrom(result.getClass())) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return CONVERSION_SERVICE.convert(result, expectedReturnType);
|
||||
}
|
||||
|
||||
private Query applyQueryMetaAttributesWhenPresent(Query query) {
|
||||
@@ -211,6 +196,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
* {@link Execution} for {@link Slice} query methods.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.5
|
||||
*/
|
||||
|
||||
@@ -232,9 +218,11 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
|
||||
|
||||
MongoEntityMetadata<?> metadata = method.getEntityInformation();
|
||||
int pageSize = pageable.getPageSize();
|
||||
Pageable slicePageable = new PageRequest(pageable.getPageNumber(), pageSize + 1, pageable.getSort());
|
||||
|
||||
List result = operations.find(query.with(slicePageable), metadata.getJavaType(), metadata.getCollectionName());
|
||||
// Apply Pageable but tweak limit to peek into next page
|
||||
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
|
||||
|
||||
List result = operations.find(modifiedQuery, metadata.getJavaType(), metadata.getCollectionName());
|
||||
|
||||
boolean hasNext = result.size() > pageSize;
|
||||
|
||||
|
||||
@@ -102,9 +102,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
MongoPersistentProperty property = path.getLeafProperty();
|
||||
Criteria criteria = from(part, property,
|
||||
where(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
|
||||
(PotentiallyConvertingIterator) iterator);
|
||||
Criteria criteria = from(part, property, where(path.toDotPath()), (PotentiallyConvertingIterator) iterator);
|
||||
|
||||
return criteria;
|
||||
}
|
||||
@@ -123,9 +121,7 @@ class MongoQueryCreator extends AbstractQueryCreator<Query, Criteria> {
|
||||
PersistentPropertyPath<MongoPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
|
||||
MongoPersistentProperty property = path.getLeafProperty();
|
||||
|
||||
return from(part, property,
|
||||
base.and(path.toDotPath(MongoPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
|
||||
(PotentiallyConvertingIterator) iterator);
|
||||
return from(part, property, base.and(path.toDotPath()), (PotentiallyConvertingIterator) iterator);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
import com.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
@@ -199,6 +200,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
* {@link Collections#emptyList()}.
|
||||
*
|
||||
* @param input
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public List<ParameterBinding> parseParameterBindingsFrom(String input) {
|
||||
@@ -229,14 +231,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
if (value instanceof String) {
|
||||
|
||||
String string = ((String) value).trim();
|
||||
|
||||
Matcher valueMatcher = PARSEABLE_BINDING_PATTERN.matcher(string);
|
||||
while (valueMatcher.find()) {
|
||||
int paramIndex = Integer.parseInt(valueMatcher.group(PARAMETER_INDEX_GROUP));
|
||||
boolean quoted = (string.startsWith("'") && string.endsWith("'"))
|
||||
|| (string.startsWith("\"") && string.endsWith("\""));
|
||||
bindings.add(new ParameterBinding(paramIndex, quoted));
|
||||
}
|
||||
potentiallyAddBinding(string, bindings);
|
||||
|
||||
} else if (value instanceof Pattern) {
|
||||
|
||||
@@ -255,15 +250,37 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
bindings.add(new ParameterBinding(paramIndex, quoted));
|
||||
}
|
||||
|
||||
} else if (value instanceof DBRef) {
|
||||
|
||||
DBRef dbref = (DBRef) value;
|
||||
|
||||
potentiallyAddBinding(dbref.getRef(), bindings);
|
||||
potentiallyAddBinding(dbref.getId().toString(), bindings);
|
||||
|
||||
} else if (value instanceof DBObject) {
|
||||
|
||||
DBObject dbo = (DBObject) value;
|
||||
|
||||
for (String field : dbo.keySet()) {
|
||||
collectParameterReferencesIntoBindings(bindings, field);
|
||||
collectParameterReferencesIntoBindings(bindings, dbo.get(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void potentiallyAddBinding(String source, List<ParameterBinding> bindings) {
|
||||
|
||||
Matcher valueMatcher = PARSEABLE_BINDING_PATTERN.matcher(source);
|
||||
|
||||
while (valueMatcher.find()) {
|
||||
|
||||
int paramIndex = Integer.parseInt(valueMatcher.group(PARAMETER_INDEX_GROUP));
|
||||
boolean quoted = (source.startsWith("'") && source.endsWith("'"))
|
||||
|| (source.startsWith("\"") && source.endsWith("\""));
|
||||
|
||||
bindings.add(new ParameterBinding(paramIndex, quoted));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -41,7 +44,17 @@ import com.mysema.query.types.PathType;
|
||||
*/
|
||||
class SpringDataMongodbSerializer extends MongodbSerializer {
|
||||
|
||||
private final String ID_KEY = "_id";
|
||||
private static final String ID_KEY = "_id";
|
||||
private static final Set<PathType> PATH_TYPES;
|
||||
|
||||
static {
|
||||
|
||||
Set<PathType> pathTypes = new HashSet<PathType>();
|
||||
pathTypes.add(PathType.VARIABLE);
|
||||
pathTypes.add(PathType.PROPERTY);
|
||||
|
||||
PATH_TYPES = Collections.unmodifiableSet(pathTypes);
|
||||
}
|
||||
|
||||
private final MongoConverter converter;
|
||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||
@@ -138,7 +151,7 @@ class SpringDataMongodbSerializer extends MongodbSerializer {
|
||||
|
||||
Path<?> parent = path.getMetadata().getParent();
|
||||
|
||||
if (parent == null) {
|
||||
if (parent == null || !PATH_TYPES.contains(path.getMetadata().getPathType())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -49,11 +50,17 @@ public class ServerAddressPropertyEditorUnitTests {
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-454
|
||||
* @see DATAMONGO-1062
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsAddressConfigWithoutASingleParsableServerAddress() {
|
||||
public void rejectsAddressConfigWithoutASingleParsableAndResolvableServerAddress() {
|
||||
|
||||
editor.setAsText("foo, bar");
|
||||
String unknownHost1 = "gugu.nonexistant.example.org";
|
||||
String unknownHost2 = "gaga.nonexistant.example.org";
|
||||
|
||||
assertUnresolveableHostnames(unknownHost1, unknownHost2);
|
||||
|
||||
editor.setAsText(unknownHost1 + "," + unknownHost2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,4 +200,16 @@ public class ServerAddressPropertyEditorUnitTests {
|
||||
assertThat(addresses, hasItem(new ServerAddress(InetAddress.getByName(hostAddress), port)));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertUnresolveableHostnames(String... hostnames) {
|
||||
|
||||
for (String hostname : hostnames) {
|
||||
try {
|
||||
InetAddress.getByName(hostname);
|
||||
Assert.fail("Supposedly unresolveable hostname '" + hostname + "' can be resolved.");
|
||||
} catch (UnknownHostException expected) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2791,6 +2791,7 @@ public class MongoTemplateTests {
|
||||
|
||||
@Id public String id;
|
||||
|
||||
@Field("db_ref_list")/** @see DATAMONGO-1058 */
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef//
|
||||
public List<Sample> dbRefAnnotatedList;
|
||||
|
||||
|
||||
@@ -541,6 +541,26 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
assertProxyIsResolved(proxy, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1076
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotTriggerResolvingOfLazyLoadedProxyWhenFinalizeMethodIsInvoked() throws Exception {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(WithObjectMethodOverrideLazyDbRefs.class);
|
||||
MongoPersistentProperty property = entity.getPersistentProperty("dbRefToConcreteTypeWithPropertyAccess");
|
||||
|
||||
String idValue = new ObjectId().toString();
|
||||
DBRef dbRef = converter.toDBRef(new LazyDbRefTargetPropertyAccess(idValue), property);
|
||||
|
||||
WithObjectMethodOverrideLazyDbRefs result = converter.read(WithObjectMethodOverrideLazyDbRefs.class,
|
||||
new BasicDBObject("dbRefToPlainObject", dbRef));
|
||||
|
||||
ReflectionTestUtils.invokeMethod(result.dbRefToPlainObject, "finalize");
|
||||
|
||||
assertProxyIsResolved(result.dbRefToPlainObject, false);
|
||||
}
|
||||
|
||||
private Object transport(Object result) {
|
||||
return SerializationUtils.deserialize(SerializationUtils.serialize(result));
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -1853,6 +1854,21 @@ public class MappingMongoConverterUnitTests {
|
||||
converter.read(Item.class, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1058
|
||||
*/
|
||||
@Test
|
||||
public void readShouldRespectExplicitFieldNameForDbRef() {
|
||||
|
||||
BasicDBObject source = new BasicDBObject();
|
||||
source.append("explict-name-for-db-ref", new DBRef(mock(DB.class), "foo", "1"));
|
||||
|
||||
converter.read(ClassWithExplicitlyNamedDBRefProperty.class, source);
|
||||
|
||||
verify(resolver, times(1)).resolveDbRef(Mockito.any(MongoPersistentProperty.class), Mockito.any(DBRef.class),
|
||||
Mockito.any(DbRefResolverCallback.class), Mockito.any(DbRefProxyHandler.class));
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
@@ -2102,4 +2118,16 @@ public class MappingMongoConverterUnitTests {
|
||||
|
||||
@TextScore Float score;
|
||||
}
|
||||
|
||||
class ClassWithExplicitlyNamedDBRefProperty {
|
||||
|
||||
@Field("explict-name-for-db-ref")//
|
||||
@org.springframework.data.mongodb.core.mapping.DBRef//
|
||||
ClassWithIntId dbRefProperty;
|
||||
|
||||
public ClassWithIntId getDbRefProperty() {
|
||||
return dbRefProperty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,6 +658,22 @@ public class QueryMapperUnitTests {
|
||||
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("_id", 1).get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1070
|
||||
*/
|
||||
@Test
|
||||
public void mapsIdReferenceToDBRefCorrectly() {
|
||||
|
||||
ObjectId id = new ObjectId();
|
||||
|
||||
DBObject query = new BasicDBObject("reference.id", new com.mongodb.DBRef(null, "reference", id.toString()));
|
||||
DBObject result = mapper.getMappedObject(query, context.getPersistentEntity(WithDBRef.class));
|
||||
|
||||
assertThat(result.containsField("reference"), is(true));
|
||||
com.mongodb.DBRef reference = getTypedValue(result, "reference", com.mongodb.DBRef.class);
|
||||
assertThat(reference.getId(), is(instanceOf(ObjectId.class)));
|
||||
}
|
||||
|
||||
@Document
|
||||
public class Foo {
|
||||
@Id private ObjectId id;
|
||||
|
||||
@@ -508,6 +508,23 @@ public class UpdateMapperUnitTests {
|
||||
assertThat(list, equalTo(new BasicDBObjectBuilder().add("_id", "1").get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1077
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotRemovePositionalParameter() {
|
||||
|
||||
Update update = new Update();
|
||||
update.unset("dbRefAnnotatedList.$");
|
||||
|
||||
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
|
||||
context.getPersistentEntity(DocumentWithDBRefCollection.class));
|
||||
|
||||
DBObject $unset = DBObjectTestUtils.getAsDBObject(mappedUpdate, "$unset");
|
||||
|
||||
assertThat($unset, equalTo(new BasicDBObjectBuilder().add("dbRefAnnotatedList.$", 1).get()));
|
||||
}
|
||||
|
||||
@org.springframework.data.mongodb.core.mapping.Document(collection = "DocumentWithReferenceToInterface")
|
||||
static interface DocumentWithReferenceToInterface {
|
||||
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.index;
|
||||
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.*;
|
||||
import static org.hamcrest.collection.IsEmptyCollection.*;
|
||||
import static org.hamcrest.core.IsEqual.*;
|
||||
import static org.hamcrest.core.IsInstanceOf.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@@ -26,8 +23,6 @@ import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.collection.IsEmptyCollection;
|
||||
import org.hamcrest.core.IsEqual;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
@@ -461,7 +456,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
indexDefinitions.get(0));
|
||||
|
||||
DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights");
|
||||
assertThat(weights.get("nested.foo"), IsEqual.<Object> equalTo(5F));
|
||||
assertThat(weights.get("nested.foo"), is((Object) 5F));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,8 +471,8 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
"textIndexOnNestedWithMostSpecificValueRoot", indexDefinitions.get(0));
|
||||
|
||||
DBObject weights = DBObjectTestUtils.getAsDBObject(indexDefinitions.get(0).getIndexOptions(), "weights");
|
||||
assertThat(weights.get("nested.foo"), IsEqual.<Object> equalTo(5F));
|
||||
assertThat(weights.get("nested.bar"), IsEqual.<Object> equalTo(10F));
|
||||
assertThat(weights.get("nested.foo"), is((Object) 5F));
|
||||
assertThat(weights.get("nested.bar"), is((Object) 10F));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,17 +482,57 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
public void shouldSetDefaultLanguageCorrectly() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithDefaultLanguage.class);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), IsEqual.<Object> equalTo("spanish"));
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("default_language"), is((Object) "spanish"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-937
|
||||
* @see DATAMONGO-937, DATAMONGO-1049
|
||||
*/
|
||||
@Test
|
||||
public void shouldResolveTextIndexLanguageOverrideCorrectly() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElementRoot.class);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), IsEqual.<Object> equalTo("lang"));
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverride.class);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1049
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreTextIndexLanguageOverrideOnNestedElements() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithLanguageOverrideOnNestedElement.class);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1049
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotCreateIndexDefinitionWhenOnlyLanguageButNoTextIndexPresent() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguage.class);
|
||||
assertThat(indexDefinitions, is(empty()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1049
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotCreateIndexDefinitionWhenOnlyAnnotatedLanguageButNoTextIndexPresent() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated.class);
|
||||
assertThat(indexDefinitions, is(empty()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1049
|
||||
*/
|
||||
@Test
|
||||
public void shouldPreferExplicitlyAnnotatedLanguageProperty() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithOverlappingLanguageProps.class);
|
||||
assertThat(indexDefinitions.get(0).getIndexOptions().get("language_override"), is((Object) "lang"));
|
||||
}
|
||||
|
||||
@Document
|
||||
@@ -527,14 +562,12 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
static class TextIndexOnNested {
|
||||
|
||||
String foo;
|
||||
|
||||
}
|
||||
|
||||
@Document
|
||||
static class TextIndexOnNestedWithWeightRoot {
|
||||
|
||||
@TextIndexed(weight = 5) TextIndexOnNested nested;
|
||||
|
||||
}
|
||||
|
||||
@Document
|
||||
@@ -554,18 +587,39 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithLanguageOverrideOnNestedElementRoot {
|
||||
static class DocumentWithLanguageOverrideOnNestedElement {
|
||||
|
||||
DocumentWithLanguageOverrideOnNestedElement nested;
|
||||
DocumentWithLanguageOverride nested;
|
||||
}
|
||||
|
||||
static class DocumentWithLanguageOverrideOnNestedElement {
|
||||
@Document
|
||||
static class DocumentWithLanguageOverride {
|
||||
|
||||
@TextIndexed String foo;
|
||||
|
||||
@Language String lang;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguage {
|
||||
|
||||
String language;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithNoTextIndexPropertyButReservedFieldLanguageAnnotated {
|
||||
|
||||
@Field("language") String lang;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class DocumentWithOverlappingLanguageProps {
|
||||
|
||||
@TextIndexed String foo;
|
||||
String language;
|
||||
@Language String lang;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MixedIndexResolutionTests {
|
||||
@@ -670,7 +724,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
public void shouldDetectSelfCycleViaCollectionTypeCorrectly() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(SelfCyclingViaCollectionType.class);
|
||||
assertThat(indexDefinitions, IsEmptyCollection.empty());
|
||||
assertThat(indexDefinitions, empty());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -680,7 +734,7 @@ public class MongoPersistentEntityIndexResolverUnitTests {
|
||||
public void shouldNotDetectCycleWhenTypeIsUsedMoreThanOnce() {
|
||||
|
||||
List<IndexDefinitionHolder> indexDefinitions = prepareMappingContextAndResolveIndexForType(MultipleObjectsOfSameType.class);
|
||||
assertThat(indexDefinitions, IsEmptyCollection.empty());
|
||||
assertThat(indexDefinitions, empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.mapping.model.MappingException;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
|
||||
/**
|
||||
@@ -36,6 +37,7 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
public class BasicMongoPersistentEntityUnitTests {
|
||||
|
||||
@Mock ApplicationContext context;
|
||||
@Mock MongoPersistentProperty propertyMock;
|
||||
|
||||
@Test
|
||||
public void subclassInheritsAtDocumentAnnotation() {
|
||||
@@ -80,6 +82,61 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
assertThat(entity.getLanguage(), is("spanish"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1053
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test(expected = MappingException.class)
|
||||
public void verifyShouldThrowExceptionForInvalidTypeOfExplicitLanguageProperty() {
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
|
||||
when(propertyMock.isExplicitLanguageProperty()).thenReturn(true);
|
||||
when(propertyMock.getActualType()).thenReturn((Class) Number.class);
|
||||
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
entity.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1053
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void verifyShouldPassForStringAsExplicitLanguageProperty() {
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
when(propertyMock.isExplicitLanguageProperty()).thenReturn(true);
|
||||
when(propertyMock.getActualType()).thenReturn((Class) String.class);
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
entity.verify();
|
||||
|
||||
verify(propertyMock, times(1)).isExplicitLanguageProperty();
|
||||
verify(propertyMock, times(1)).getActualType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1053
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void verifyShouldIgnoreNonExplicitLanguageProperty() {
|
||||
|
||||
BasicMongoPersistentEntity<AnyDocument> entity = new BasicMongoPersistentEntity<AnyDocument>(
|
||||
ClassTypeInformation.from(AnyDocument.class));
|
||||
when(propertyMock.isExplicitLanguageProperty()).thenReturn(false);
|
||||
when(propertyMock.getActualType()).thenReturn((Class) Number.class);
|
||||
entity.addPersistentProperty(propertyMock);
|
||||
|
||||
entity.verify();
|
||||
|
||||
verify(propertyMock, times(1)).isExplicitLanguageProperty();
|
||||
verify(propertyMock, never()).getActualType();
|
||||
}
|
||||
|
||||
@Document(collection = "contacts")
|
||||
class Contact {
|
||||
|
||||
@@ -111,4 +168,8 @@ public class BasicMongoPersistentEntityUnitTests {
|
||||
static class DocumentWithLanguage {
|
||||
|
||||
}
|
||||
|
||||
static class AnyDocument {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
* Copyright 2010-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,12 +22,14 @@ import org.junit.Test;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class CriteriaTests {
|
||||
|
||||
@Test
|
||||
@@ -72,50 +74,94 @@ public class CriteriaTests {
|
||||
assertThat(left, is(not(right)));
|
||||
assertThat(right, is(not(left)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test
|
||||
public void shouldNegateFollowingSimpleExpression() {
|
||||
|
||||
Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
|
||||
DBObject co = c.getCriteriaObject();
|
||||
|
||||
assertThat(co, is(notNullValue()));
|
||||
assertThat(co.toString(), is("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateAndOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.andOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateOrOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.orOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionWhenTryingToNegateNorOperation() {
|
||||
|
||||
new Criteria() //
|
||||
.not() //
|
||||
.norOperator(Criteria.where("delete").is(true).and("_id").is(42)); //
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-507
|
||||
*/
|
||||
@Test
|
||||
public void shouldNegateFollowingSimpleExpression() {
|
||||
|
||||
Criteria c = Criteria.where("age").not().gt(18).and("status").is("student");
|
||||
DBObject co = c.getCriteriaObject();
|
||||
|
||||
assertThat(co, is(notNullValue()));
|
||||
assertThat(co.toString(), is("{ \"age\" : { \"$not\" : { \"$gt\" : 18}} , \"status\" : \"student\"}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1068
|
||||
*/
|
||||
@Test
|
||||
public void getCriteriaObjectShouldReturnEmptyDBOWhenNoCriteriaSpecified() {
|
||||
|
||||
DBObject dbo = new Criteria().getCriteriaObject();
|
||||
|
||||
assertThat(dbo, equalTo(new BasicDBObjectBuilder().get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1068
|
||||
*/
|
||||
@Test
|
||||
public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresent() {
|
||||
|
||||
DBObject dbo = new Criteria().lt("foo").getCriteriaObject();
|
||||
|
||||
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("$lt", "foo").get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1068
|
||||
*/
|
||||
@Test
|
||||
public void getCriteriaObjectShouldUseCritieraValuesWhenNoKeyIsPresentButMultipleCriteriasPresent() {
|
||||
|
||||
DBObject dbo = new Criteria().lt("foo").gt("bar").getCriteriaObject();
|
||||
|
||||
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("$lt", "foo").add("$gt", "bar").get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1068
|
||||
*/
|
||||
@Test
|
||||
public void getCriteriaObjectShouldRespectNotWhenNoKeyPresent() {
|
||||
|
||||
DBObject dbo = new Criteria().lt("foo").not().getCriteriaObject();
|
||||
|
||||
assertThat(dbo, equalTo(new BasicDBObjectBuilder().add("$not", new BasicDBObject("$lt", "foo")).get()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static java.util.Arrays.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -1023,6 +1024,40 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result.firstname, is("Carter"));
|
||||
assertThat(result.lastname, is("Beauford"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1057
|
||||
*/
|
||||
@Test
|
||||
public void sliceShouldTraverseElementsWithoutSkippingOnes() {
|
||||
|
||||
repository.deleteAll();
|
||||
|
||||
List<Person> persons = new ArrayList<Person>(100);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
// format firstname to assert sorting retains proper order
|
||||
persons.add(new Person(String.format("%03d", i), "ln" + 1, 100));
|
||||
}
|
||||
|
||||
repository.save(persons);
|
||||
|
||||
Slice<Person> slice = repository.findByAgeGreaterThan(50, new PageRequest(0, 20, Direction.ASC, "firstname"));
|
||||
assertThat(slice, contains(persons.subList(0, 20).toArray()));
|
||||
|
||||
slice = repository.findByAgeGreaterThan(50, slice.nextPageable());
|
||||
assertThat(slice, contains(persons.subList(20, 40).toArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1072
|
||||
*/
|
||||
@Test
|
||||
public void shouldBindPlaceholdersUsedAsKeysCorrectly() {
|
||||
|
||||
List<Person> persons = repository.findByKeyValue("firstname", alicia.getFirstname());
|
||||
|
||||
assertThat(persons, hasSize(1));
|
||||
assertThat(persons, hasItem(alicia));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ public class Person extends Contact {
|
||||
@SuppressWarnings("unused") private Sex sex;
|
||||
Date createdAt;
|
||||
|
||||
List<String> skills;
|
||||
|
||||
@GeoSpatialIndexed private Point location;
|
||||
|
||||
private Address address;
|
||||
@@ -271,6 +273,14 @@ public class Person extends Contact {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public void setSkills(List<String> skills) {
|
||||
this.skills = skills;
|
||||
}
|
||||
|
||||
public List<String> getSkills() {
|
||||
return skills;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -317,4 +317,7 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
|
||||
* @see DATAMONGO-1030
|
||||
*/
|
||||
PersonSummary findSummaryByLastname(String lastname);
|
||||
|
||||
@Query("{ ?0 : ?1 }")
|
||||
List<Person> findByKeyValue(String key, String value);
|
||||
}
|
||||
|
||||
@@ -17,12 +17,14 @@ package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.hamcrest.core.Is;
|
||||
@@ -32,10 +34,13 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Matchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
@@ -50,6 +55,8 @@ import org.springframework.data.mongodb.repository.Meta;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.WriteResult;
|
||||
|
||||
/**
|
||||
@@ -211,6 +218,88 @@ public class AbstractMongoQueryUnitTests {
|
||||
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1057
|
||||
*/
|
||||
@Test
|
||||
public void slicedExecutionShouldRetainNrOfElementsToSkip() {
|
||||
|
||||
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
|
||||
Pageable page1 = new PageRequest(0, 10);
|
||||
Pageable page2 = page1.next();
|
||||
|
||||
query.execute(new Object[] { "fake", page1 });
|
||||
query.execute(new Object[] { "fake", page2 });
|
||||
|
||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||
|
||||
verify(this.mongoOperationsMock, times(2))
|
||||
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
|
||||
|
||||
assertThat(captor.getAllValues().get(0).getSkip(), is(0));
|
||||
assertThat(captor.getAllValues().get(1).getSkip(), is(10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1057
|
||||
*/
|
||||
@Test
|
||||
public void slicedExecutionShouldIncrementLimitByOne() {
|
||||
|
||||
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
|
||||
Pageable page1 = new PageRequest(0, 10);
|
||||
Pageable page2 = page1.next();
|
||||
|
||||
query.execute(new Object[] { "fake", page1 });
|
||||
query.execute(new Object[] { "fake", page2 });
|
||||
|
||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||
|
||||
verify(this.mongoOperationsMock, times(2))
|
||||
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
|
||||
|
||||
assertThat(captor.getAllValues().get(0).getLimit(), is(11));
|
||||
assertThat(captor.getAllValues().get(1).getLimit(), is(11));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1057
|
||||
*/
|
||||
@Test
|
||||
public void slicedExecutionShouldRetainSort() {
|
||||
|
||||
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
|
||||
Pageable page1 = new PageRequest(0, 10, Sort.Direction.DESC, "bar");
|
||||
Pageable page2 = page1.next();
|
||||
|
||||
query.execute(new Object[] { "fake", page1 });
|
||||
query.execute(new Object[] { "fake", page2 });
|
||||
|
||||
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
|
||||
|
||||
verify(this.mongoOperationsMock, times(2))
|
||||
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
|
||||
|
||||
DBObject expectedSortObject = new BasicDBObjectBuilder().add("bar", -1).get();
|
||||
assertThat(captor.getAllValues().get(0).getSortObject(), is(expectedSortObject));
|
||||
assertThat(captor.getAllValues().get(1).getSortObject(), is(expectedSortObject));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1080
|
||||
*/
|
||||
@Test
|
||||
public void doesNotTryToPostProcessQueryResultIntoWrapperType() {
|
||||
|
||||
Person reference = new Person();
|
||||
when(mongoOperationsMock.findOne(Mockito.any(Query.class), eq(Person.class), eq("persons"))).//
|
||||
thenReturn(reference);
|
||||
|
||||
AbstractMongoQuery query = createQueryForMethod("findByLastname", String.class);
|
||||
|
||||
assertThat(query.execute(new Object[] { "lastname" }), is((Object) reference));
|
||||
}
|
||||
|
||||
private MongoQueryFake createQueryForMethod(String methodName, Class<?>... paramTypes) {
|
||||
|
||||
try {
|
||||
@@ -272,5 +361,9 @@ public class AbstractMongoQueryUnitTests {
|
||||
@org.springframework.data.mongodb.repository.Query("{}")
|
||||
Page<Person> findByAnnotatedQuery(String firstnanme, Pageable pageable);
|
||||
|
||||
/** @see DATAMONGO-1057 */
|
||||
Slice<Person> findByLastname(String lastname, Pageable page);
|
||||
|
||||
Optional<Person> findByLastname(String lastname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,19 +167,6 @@ public class MongoQueryCreatorUnitTests {
|
||||
assertThat(creator.createQuery(), is(reference));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-291
|
||||
*/
|
||||
@Test
|
||||
public void honoursMappingInformationForPropertyPaths() {
|
||||
|
||||
PartTree partTree = new PartTree("findByUsername", User.class);
|
||||
|
||||
MongoQueryCreator creator = new MongoQueryCreator(partTree, getAccessor(converter, "Oliver"), context);
|
||||
Query reference = query(where("foo").is("Oliver"));
|
||||
assertThat(creator.createQuery(), is(reference));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-338
|
||||
*/
|
||||
@@ -268,7 +255,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "Matt"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("foo").regex("^Matt"))));
|
||||
assertThat(query, is(query(where("username").regex("^Matt"))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,7 +268,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "ews"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("foo").regex("ews$"))));
|
||||
assertThat(query, is(query(where("username").regex("ews$"))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,7 +281,7 @@ public class MongoQueryCreatorUnitTests {
|
||||
MongoQueryCreator creator = new MongoQueryCreator(tree, getAccessor(converter, "thew"), context);
|
||||
Query query = creator.createQuery();
|
||||
|
||||
assertThat(query, is(query(where("foo").regex(".*thew.*"))));
|
||||
assertThat(query, is(query(where("username").regex(".*thew.*"))));
|
||||
}
|
||||
|
||||
private void assertBindsDistanceToQuery(Point point, Distance distance, Query reference) throws Exception {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mongodb.core.DBObjectTestUtils;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
|
||||
@@ -42,7 +43,9 @@ import org.springframework.data.mongodb.repository.Query;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.BasicDBObjectBuilder;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link StringBasedMongoQuery}.
|
||||
@@ -255,6 +258,37 @@ public class StringBasedMongoQueryUnitTests {
|
||||
assertThat(query.getQueryObject(), is(reference.getQueryObject()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1070
|
||||
*/
|
||||
@Test
|
||||
public void parsesDbRefDeclarationsCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("methodWithManuallyDefinedDbRef", String.class);
|
||||
ConvertingParameterAccessor parameterAccessor = StubParameterAccessor.getAccessor(converter, "myid");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(parameterAccessor);
|
||||
|
||||
DBRef dbRef = DBObjectTestUtils.getTypedValue(query.getQueryObject(), "reference", DBRef.class);
|
||||
assertThat(dbRef.getId(), is((Object) "myid"));
|
||||
assertThat(dbRef.getRef(), is("reference"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1072
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseJsonKeyReplacementCorrectly() throws Exception {
|
||||
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("methodWithPlaceholderInKeyOfJsonStructure", String.class,
|
||||
String.class);
|
||||
ConvertingParameterAccessor parameterAccessor = StubParameterAccessor.getAccessor(converter, "key", "value");
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(parameterAccessor);
|
||||
|
||||
assertThat(query.getQueryObject(), is(new BasicDBObjectBuilder().add("key", "value").get()));
|
||||
}
|
||||
|
||||
private StringBasedMongoQuery createQueryForMethod(String name, Class<?>... parameters) throws Exception {
|
||||
|
||||
Method method = SampleRepository.class.getMethod(name, parameters);
|
||||
@@ -291,7 +325,14 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Query("{'title': { $regex : '^?0', $options : 'i'}}")
|
||||
List<DBObject> findByTitleBeginsWithExplicitQuoting(String title);
|
||||
|
||||
@Query(value = "{$where: 'return this.date.getUTCMonth() == ?2 && this.date.getUTCDay() == ?3;'}")
|
||||
@Query("{$where: 'return this.date.getUTCMonth() == ?2 && this.date.getUTCDay() == ?3;'}")
|
||||
List<DBObject> findByQueryWithParametersInExpression(int param1, int param2, int param3, int param4);
|
||||
|
||||
@Query("{ 'reference' : { $ref : 'reference', $id : ?0 }}")
|
||||
Object methodWithManuallyDefinedDbRef(String id);
|
||||
|
||||
@Query("{ ?0 : ?1}")
|
||||
Object methodWithPlaceholderInKeyOfJsonStructure(String keyReplacement, String valueReplacement);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.data.mongodb.repository.support;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -40,8 +42,7 @@ import com.mysema.query.mongodb.MongodbQuery;
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class QuerydslRepositorySupportUnitTests {
|
||||
|
||||
@Autowired
|
||||
MongoOperations operations;
|
||||
@Autowired MongoOperations operations;
|
||||
Person person;
|
||||
|
||||
@Before
|
||||
@@ -54,9 +55,26 @@ public class QuerydslRepositorySupportUnitTests {
|
||||
@Test
|
||||
public void providesMongoQuery() {
|
||||
QPerson p = QPerson.person;
|
||||
QuerydslRepositorySupport support = new QuerydslRepositorySupport(operations) {
|
||||
};
|
||||
QuerydslRepositorySupport support = new QuerydslRepositorySupport(operations) {};
|
||||
MongodbQuery<Person> query = support.from(p).where(p.lastname.eq("Matthews"));
|
||||
assertThat(query.uniqueResult(), is(person));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1063
|
||||
*/
|
||||
@Test
|
||||
public void shouldAllowAny() {
|
||||
|
||||
person.setSkills(Arrays.asList("vocalist", "songwriter", "guitarist"));
|
||||
|
||||
operations.save(person);
|
||||
|
||||
QPerson p = QPerson.person;
|
||||
QuerydslRepositorySupport support = new QuerydslRepositorySupport(operations) {};
|
||||
|
||||
MongodbQuery<Person> query = support.from(p).where(p.skills.any().in("guitarist"));
|
||||
|
||||
assertThat(query.uniqueResult(), is(person));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 1.6.1.RELEASE (2014-10-30)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-1080 - AbstractMongoQuery must not eagerly post-process results.
|
||||
* DATAMONGO-1079 - Release 1.6.1.
|
||||
* DATAMONGO-1077 - Update removes positional operator $ in key when used on DBRef property.
|
||||
* DATAMONGO-1076 - Finalizer hit db on lazy dbrefs.
|
||||
* DATAMONGO-1072 - Query placeholders in keys no longer correctly substituted.
|
||||
* DATAMONGO-1070 - Query annotation with $oid leads to a parse error.
|
||||
* DATAMONGO-1068 - elemMatch of Class Criteria fails to build special cirteria.
|
||||
* DATAMONGO-1063 - IllegalStateException using any().in().
|
||||
* DATAMONGO-1062 - Fix failing test in ServerAddressPropertyEditorUnitTests.
|
||||
* DATAMONGO-1058 - Using @Field("foo") with @Dbref breaking behavior.
|
||||
* DATAMONGO-1057 - AbstractMongoQuery.SlicedExecution#execute() skips every nth element.
|
||||
* DATAMONGO-1053 - In 1.6, any field in a mapped object named "language" will fail to map if it is a type other than String.
|
||||
* DATAMONGO-1049 - Reserved field name 'language' causes trouble.
|
||||
|
||||
|
||||
Changes in version 1.6.0.RELEASE (2014-09-05)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-1046 - Release 1.6 GA.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 1.6 GA
|
||||
Spring Data MongoDB 1.6.1
|
||||
Copyright (c) [2010-2014] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
Reference in New Issue
Block a user