Compare commits
30 Commits
2.2.5.RELE
...
2.2.7.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61bbc9ab7f | ||
|
|
9e802a59c7 | ||
|
|
38e1e632a7 | ||
|
|
89cf78cc4a | ||
|
|
cecd47d679 | ||
|
|
ed35e577af | ||
|
|
f54cf40eda | ||
|
|
5314e6f8bb | ||
|
|
b7b2709177 | ||
|
|
34c47e84c0 | ||
|
|
f7d91184a0 | ||
|
|
eeddc860f7 | ||
|
|
bcefdd209b | ||
|
|
3f1fea2d19 | ||
|
|
665322a69a | ||
|
|
3e59bc3b38 | ||
|
|
1752931dde | ||
|
|
4b9bae1656 | ||
|
|
74c08fa8aa | ||
|
|
628aad8f64 | ||
|
|
39c8672e6d | ||
|
|
620991ddee | ||
|
|
ba8f28f623 | ||
|
|
6389055d3a | ||
|
|
4465ed9819 | ||
|
|
8dc97e5d01 | ||
|
|
a037c50961 | ||
|
|
28d5f02e15 | ||
|
|
e65a353fc4 | ||
|
|
42400e7836 |
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.2.5.RELEASE</version>
|
||||
<version>2.2.7.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>2.2.5.RELEASE</version>
|
||||
<version>2.2.7.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -26,7 +26,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.2.5.RELEASE</springdata.commons>
|
||||
<springdata.commons>2.2.7.RELEASE</springdata.commons>
|
||||
<mongo>3.11.2</mongo>
|
||||
<mongo.reactivestreams>1.12.0</mongo.reactivestreams>
|
||||
<jmh.version>1.19</jmh.version>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.2.5.RELEASE</version>
|
||||
<version>2.2.7.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.2.5.RELEASE</version>
|
||||
<version>2.2.7.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.2.5.RELEASE</version>
|
||||
<version>2.2.7.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -3155,12 +3155,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
@Nullable
|
||||
public T doWith(@Nullable Document object) {
|
||||
|
||||
T source = null;
|
||||
|
||||
if (null != object) {
|
||||
maybeEmitEvent(new AfterLoadEvent<>(object, type, collectionName));
|
||||
source = reader.read(type, object);
|
||||
}
|
||||
|
||||
T source = reader.read(type, object);
|
||||
|
||||
if (null != source) {
|
||||
maybeEmitEvent(new AfterConvertEvent<>(object, source, collectionName));
|
||||
}
|
||||
@@ -3200,9 +3201,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
Class<?> typeToRead = targetType.isInterface() || targetType.isAssignableFrom(entityType) ? entityType
|
||||
: targetType;
|
||||
|
||||
if (null != object) {
|
||||
maybeEmitEvent(new AfterLoadEvent<>(object, targetType, collectionName));
|
||||
}
|
||||
maybeEmitEvent(new AfterLoadEvent<>(object, targetType, collectionName));
|
||||
|
||||
Object source = reader.read(typeToRead, object);
|
||||
Object result = targetType.isInterface() ? projectionFactory.createProjection(targetType, source) : source;
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -100,14 +101,14 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected List<Object> append(Object value) {
|
||||
protected List<Object> append(Object value, Expand expandList) {
|
||||
|
||||
if (this.value instanceof List) {
|
||||
|
||||
List<Object> clone = new ArrayList<Object>((List) this.value);
|
||||
|
||||
if (value instanceof List) {
|
||||
clone.addAll((List) value);
|
||||
if (value instanceof Collection && Expand.EXPAND_VALUES.equals(expandList)) {
|
||||
clone.addAll((Collection<?>) value);
|
||||
} else {
|
||||
clone.add(value);
|
||||
}
|
||||
@@ -117,6 +118,17 @@ abstract class AbstractAggregationExpression implements AggregationExpression {
|
||||
return Arrays.asList(this.value, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a nested list of values to single entries or keep the list.
|
||||
*/
|
||||
protected enum Expand {
|
||||
EXPAND_VALUES, KEEP_SOURCE
|
||||
}
|
||||
|
||||
protected List<Object> append(Object value) {
|
||||
return append(value, Expand.EXPAND_VALUES);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected java.util.Map<String, Object> append(String key, Object value) {
|
||||
|
||||
|
||||
@@ -411,7 +411,7 @@ public class ComparisonOperators {
|
||||
public Cmp compareToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Cmp(append(value));
|
||||
return new Cmp(append(value, Expand.KEEP_SOURCE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ public class ComparisonOperators {
|
||||
public Eq equalToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Eq(append(value));
|
||||
return new Eq(append(value, Expand.KEEP_SOURCE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +873,7 @@ public class ComparisonOperators {
|
||||
public Ne notEqualToValue(Object value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Ne(append(value));
|
||||
return new Ne(append(value, Expand.KEEP_SOURCE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ import com.mongodb.DBRef;
|
||||
* @author Christoph Strobl
|
||||
* @author Jordi Llach
|
||||
* @author Mark Paluch
|
||||
* @author Heesu Jung
|
||||
*/
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||
|
||||
@@ -227,11 +228,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends Object> S read(TypeInformation<S> type, @Nullable Bson bson, ObjectPath path) {
|
||||
private <S extends Object> S read(TypeInformation<S> type, Bson bson, ObjectPath path) {
|
||||
|
||||
if (null == bson) {
|
||||
return null;
|
||||
}
|
||||
Assert.notNull(bson, "Bson must not be null!");
|
||||
|
||||
TypeInformation<? extends S> typeToUse = typeMapper.readType(bson, type);
|
||||
Class<? extends S> rawType = typeToUse.getType();
|
||||
@@ -1262,9 +1261,16 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
if (conversions.isSimpleType(obj.getClass())) {
|
||||
// Doesn't need conversion
|
||||
return getPotentiallyConvertedSimpleWrite(obj,
|
||||
typeInformation != null ? typeInformation.getType() : Object.class);
|
||||
|
||||
Class<?> conversionTargetType;
|
||||
|
||||
if (typeInformation != null && conversions.isSimpleType(typeInformation.getType())) {
|
||||
conversionTargetType = typeInformation.getType();
|
||||
} else {
|
||||
conversionTargetType = Object.class;
|
||||
}
|
||||
|
||||
return getPotentiallyConvertedSimpleWrite(obj, conversionTargetType);
|
||||
}
|
||||
|
||||
if (obj instanceof List) {
|
||||
@@ -1574,7 +1580,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
@Nullable
|
||||
private <T> T readAndConvertDBRef(@Nullable DBRef dbref, TypeInformation<?> type, ObjectPath path,
|
||||
final Class<?> rawType) {
|
||||
@Nullable Class<?> rawType) {
|
||||
|
||||
List<T> result = bulkReadAndConvertDBRefs(Collections.singletonList(dbref), type, path, rawType);
|
||||
return CollectionUtils.isEmpty(result) ? null : result.iterator().next();
|
||||
@@ -1597,7 +1603,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> List<T> bulkReadAndConvertDBRefs(List<DBRef> dbrefs, TypeInformation<?> type, ObjectPath path,
|
||||
final Class<?> rawType) {
|
||||
@Nullable Class<?> rawType) {
|
||||
|
||||
if (CollectionUtils.isEmpty(dbrefs)) {
|
||||
return Collections.emptyList();
|
||||
@@ -1612,16 +1618,19 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
for (Document document : referencedRawDocuments) {
|
||||
|
||||
T target = null;
|
||||
if (document != null) {
|
||||
maybeEmitEvent(new AfterLoadEvent<>(document, (Class<T>) rawType, collectionName));
|
||||
}
|
||||
|
||||
final T target = (T) read(type, document, path);
|
||||
targeList.add(target);
|
||||
maybeEmitEvent(
|
||||
new AfterLoadEvent<>(document, (Class<T>) (rawType != null ? rawType : Object.class), collectionName));
|
||||
target = (T) read(type, document, path);
|
||||
}
|
||||
|
||||
if (target != null) {
|
||||
maybeEmitEvent(new AfterConvertEvent<>(document, target, collectionName));
|
||||
}
|
||||
|
||||
targeList.add(target);
|
||||
}
|
||||
|
||||
return targeList;
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.bson.BsonValue;
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.domain.Example;
|
||||
@@ -175,7 +174,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
Document mappedSort = new Document();
|
||||
for(Map.Entry<String,Object> entry : BsonUtils.asMap(sortObject).entrySet()) {
|
||||
for (Map.Entry<String, Object> entry : BsonUtils.asMap(sortObject).entrySet()) {
|
||||
|
||||
Field field = createPropertyField(entity, entry.getKey(), mappingContext);
|
||||
mappedSort.put(field.getMappedKey(), entry.getValue());
|
||||
@@ -420,7 +419,7 @@ public class QueryMapper {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<? extends Object> type = value.getClass();
|
||||
Class<?> type = value.getClass();
|
||||
MongoPersistentProperty property = documentField.getProperty();
|
||||
|
||||
if (property.getActualType().isAssignableFrom(type)) {
|
||||
@@ -444,7 +443,7 @@ public class QueryMapper {
|
||||
protected Object convertSimpleOrDocument(Object source, @Nullable MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (source instanceof Example) {
|
||||
return exampleMapper.getMappedExample((Example) source, entity);
|
||||
return exampleMapper.getMappedExample((Example<?>) source, entity);
|
||||
}
|
||||
|
||||
if (source instanceof List) {
|
||||
@@ -923,6 +922,8 @@ public class QueryMapper {
|
||||
*/
|
||||
protected static class MetadataBackedField extends Field {
|
||||
|
||||
private static final Pattern POSITIONAL_PARAMETER_PATTERN = Pattern.compile("\\.\\$(\\[.*?\\])?|\\.\\d+");
|
||||
private static final Pattern DOT_POSITIONAL_PATTERN = Pattern.compile("\\.\\d+");
|
||||
private static final String INVALID_ASSOCIATION_REFERENCE = "Invalid path reference %s! Associations can only be pointed to directly or via their id property!";
|
||||
|
||||
private final MongoPersistentEntity<?> entity;
|
||||
@@ -964,7 +965,7 @@ public class QueryMapper {
|
||||
this.entity = entity;
|
||||
this.mappingContext = context;
|
||||
|
||||
this.path = getPath(name);
|
||||
this.path = getPath(removePlaceholders(POSITIONAL_PARAMETER_PATTERN, name));
|
||||
this.property = path == null ? property : path.getLeafProperty();
|
||||
this.association = findAssociation();
|
||||
}
|
||||
@@ -1072,7 +1073,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PersistentPropertyPath} for the given <code>pathExpression</code>.
|
||||
* Returns the {@link PersistentPropertyPath} for the given {@code pathExpression}.
|
||||
*
|
||||
* @param pathExpression
|
||||
* @return
|
||||
@@ -1080,8 +1081,8 @@ public class QueryMapper {
|
||||
@Nullable
|
||||
private PersistentPropertyPath<MongoPersistentProperty> getPath(String pathExpression) {
|
||||
|
||||
String rawPath = pathExpression.replaceAll("\\.\\d+", "") //
|
||||
.replaceAll(POSITIONAL_OPERATOR.pattern(), "");
|
||||
String rawPath = removePlaceholders(POSITIONAL_OPERATOR,
|
||||
removePlaceholders(DOT_POSITIONAL_PATTERN, pathExpression));
|
||||
|
||||
PropertyPath path = forName(rawPath);
|
||||
if (path == null || isPathToJavaLangClassProperty(path)) {
|
||||
@@ -1158,7 +1159,7 @@ public class QueryMapper {
|
||||
* @return
|
||||
*/
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return new PositionParameterRetainingPropertyKeyConverter(name);
|
||||
return new PositionParameterRetainingPropertyKeyConverter(name, mappingContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,7 +1170,15 @@ public class QueryMapper {
|
||||
* @since 1.7
|
||||
*/
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new AssociationConverter(getAssociation());
|
||||
return new AssociationConverter(name, getAssociation());
|
||||
}
|
||||
|
||||
protected MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
private static String removePlaceholders(Pattern pattern, String raw) {
|
||||
return pattern.matcher(raw).replaceAll("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1180,8 +1189,9 @@ public class QueryMapper {
|
||||
|
||||
private final KeyMapper keyMapper;
|
||||
|
||||
public PositionParameterRetainingPropertyKeyConverter(String rawKey) {
|
||||
this.keyMapper = new KeyMapper(rawKey);
|
||||
public PositionParameterRetainingPropertyKeyConverter(String rawKey,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> ctx) {
|
||||
this.keyMapper = new KeyMapper(rawKey, ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1223,7 +1233,8 @@ public class QueryMapper {
|
||||
|
||||
private final Iterator<String> iterator;
|
||||
|
||||
public KeyMapper(String key) {
|
||||
public KeyMapper(String key,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
this.iterator = Arrays.asList(key.split("\\.")).iterator();
|
||||
this.iterator.next();
|
||||
@@ -1243,6 +1254,7 @@ public class QueryMapper {
|
||||
while (inspect) {
|
||||
|
||||
String partial = iterator.next();
|
||||
|
||||
boolean isPositional = (isPositionalParameter(partial) && (property.isMap() || property.isCollectionLike()));
|
||||
|
||||
if (isPositional) {
|
||||
@@ -1255,7 +1267,7 @@ public class QueryMapper {
|
||||
return mappedName.toString();
|
||||
}
|
||||
|
||||
private static boolean isPositionalParameter(String partial) {
|
||||
static boolean isPositionalParameter(String partial) {
|
||||
|
||||
if ("$".equals(partial)) {
|
||||
return true;
|
||||
@@ -1283,6 +1295,7 @@ public class QueryMapper {
|
||||
*/
|
||||
protected static class AssociationConverter implements Converter<MongoPersistentProperty, String> {
|
||||
|
||||
private final String name;
|
||||
private final MongoPersistentProperty property;
|
||||
private boolean associationFound;
|
||||
|
||||
@@ -1291,10 +1304,11 @@ public class QueryMapper {
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public AssociationConverter(Association<MongoPersistentProperty> association) {
|
||||
public AssociationConverter(String name, Association<MongoPersistentProperty> association) {
|
||||
|
||||
Assert.notNull(association, "Association must not be null!");
|
||||
this.property = association.getInverse();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1312,6 +1326,12 @@ public class QueryMapper {
|
||||
associationFound = true;
|
||||
}
|
||||
|
||||
if (associationFound) {
|
||||
if (name.endsWith("$") && property.isCollectionLike()) {
|
||||
return source.getFieldName() + ".$";
|
||||
}
|
||||
}
|
||||
|
||||
return source.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class MetadataBackedUpdateField extends MetadataBackedField {
|
||||
|
||||
@@ -289,7 +290,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
public MetadataBackedUpdateField(MongoPersistentEntity<?> entity, String key,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
super(key.replaceAll("\\.\\$(\\[.*\\])?", ""), entity, mappingContext);
|
||||
super(key, entity, mappingContext);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@@ -308,7 +309,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getPropertyConverter() {
|
||||
return new PositionParameterRetainingPropertyKeyConverter(key);
|
||||
return new PositionParameterRetainingPropertyKeyConverter(key, getMappingContext());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -317,7 +318,7 @@ public class UpdateMapper extends QueryMapper {
|
||||
*/
|
||||
@Override
|
||||
protected Converter<MongoPersistentProperty, String> getAssociationConverter() {
|
||||
return new UpdateAssociationConverter(getAssociation(), key);
|
||||
return new UpdateAssociationConverter(getMappingContext(), getAssociation(), key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,10 +335,12 @@ public class UpdateMapper extends QueryMapper {
|
||||
*
|
||||
* @param association must not be {@literal null}.
|
||||
*/
|
||||
public UpdateAssociationConverter(Association<MongoPersistentProperty> association, String key) {
|
||||
public UpdateAssociationConverter(
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext,
|
||||
Association<MongoPersistentProperty> association, String key) {
|
||||
|
||||
super(association);
|
||||
this.mapper = new KeyMapper(key);
|
||||
super(key, association);
|
||||
this.mapper = new KeyMapper(key, mappingContext);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.query;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A {@link Term} defines one or multiple words {@link Type#WORD} or phrases {@link Type#PHRASE} to be used in the
|
||||
@@ -90,6 +93,47 @@ public class Term {
|
||||
return negated ? negateRaw(formatted) : formatted;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof Term)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Term term = (Term) o;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(negated, term.negated) && ObjectUtils.nullSafeEquals(type, term.type)
|
||||
&& ObjectUtils.nullSafeEquals(raw, term.raw);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += ObjectUtils.nullSafeHashCode(type);
|
||||
result += ObjectUtils.nullSafeHashCode(raw);
|
||||
result += ObjectUtils.nullSafeHashCode(negated);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFormatted();
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import org.bson.Document;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -34,7 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
public class TextCriteria implements CriteriaDefinition {
|
||||
|
||||
private final List<Term> terms;
|
||||
private @Nullable String language;
|
||||
private final @Nullable String language;
|
||||
private @Nullable Boolean caseSensitive;
|
||||
private @Nullable Boolean diacriticSensitive;
|
||||
|
||||
@@ -51,7 +52,7 @@ public class TextCriteria implements CriteriaDefinition {
|
||||
private TextCriteria(@Nullable String language) {
|
||||
|
||||
this.language = language;
|
||||
this.terms = new ArrayList<Term>();
|
||||
this.terms = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,9 +232,47 @@ public class TextCriteria implements CriteriaDefinition {
|
||||
return new Document("$text", document);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof TextCriteria)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextCriteria that = (TextCriteria) o;
|
||||
|
||||
return ObjectUtils.nullSafeEquals(terms, that.terms) && ObjectUtils.nullSafeEquals(language, that.language)
|
||||
&& ObjectUtils.nullSafeEquals(caseSensitive, that.caseSensitive)
|
||||
&& ObjectUtils.nullSafeEquals(diacriticSensitive, that.diacriticSensitive);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int result = 17;
|
||||
|
||||
result += ObjectUtils.nullSafeHashCode(terms);
|
||||
result += ObjectUtils.nullSafeHashCode(language);
|
||||
result += ObjectUtils.nullSafeHashCode(caseSensitive);
|
||||
result += ObjectUtils.nullSafeHashCode(diacriticSensitive);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String join(Iterable<Term> terms) {
|
||||
|
||||
List<String> result = new ArrayList<String>();
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for (Term term : terms) {
|
||||
if (term != null) {
|
||||
|
||||
@@ -111,7 +111,10 @@ public interface ReactiveGridFsOperations {
|
||||
* @param metadata can be {@literal null}
|
||||
* @return a {@link Mono} emitting the {@link ObjectId} of the {@link com.mongodb.client.gridfs.model.GridFSFile} just
|
||||
* created.
|
||||
* @deprecated since 2.2.6. Will be removed in 3.0. Please use {@link #store(Publisher, String, String, Object)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<ObjectId> store(AsyncInputStream content, @Nullable String filename, @Nullable String contentType,
|
||||
@Nullable Object metadata);
|
||||
|
||||
@@ -151,7 +154,10 @@ public interface ReactiveGridFsOperations {
|
||||
* @param metadata can be {@literal null}.
|
||||
* @return a {@link Mono} emitting the {@link ObjectId} of the {@link com.mongodb.client.gridfs.model.GridFSFile} just
|
||||
* created.
|
||||
* @deprecated since 2.2.6. Will be removed in 3.0. Please use {@link #store(Publisher, String, String, Document)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Mono<ObjectId> store(AsyncInputStream content, @Nullable String filename, @Nullable String contentType,
|
||||
@Nullable Document metadata);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||
@@ -71,6 +72,10 @@ public class StringBasedAggregation extends AbstractMongoQuery {
|
||||
protected Object doExecute(MongoQueryMethod method, ResultProcessor resultProcessor,
|
||||
ConvertingParameterAccessor accessor, Class<?> typeToRead) {
|
||||
|
||||
if (method.isPageQuery() || method.isSliceQuery()) {
|
||||
throw new InvalidMongoDbApiUsageException(String.format("Repository aggregation method '%s' does not support '%s' return type. Please use eg. 'List' instead.", method.getName(), method.getReturnType().getType().getSimpleName()));
|
||||
}
|
||||
|
||||
Class<?> sourceType = method.getDomainClass();
|
||||
Class<?> targetType = typeToRead;
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ class JsonScanner {
|
||||
|
||||
parenthesisCount--;
|
||||
if (parenthesisCount == 0) {
|
||||
buffer.read();
|
||||
c = buffer.read();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +333,52 @@ public class DefaultBulkOperationsUnitTests {
|
||||
.isEqualTo(new org.bson.Document("element", new Document("$gte", 100)));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2502
|
||||
public void shouldRetainNestedArrayPathWithPlaceholdersForNoMatchingPaths() {
|
||||
|
||||
ops.updateOne(new BasicQuery("{}"), new Update().set("items.$.documents.0.fileId", "new-id")).execute();
|
||||
|
||||
verify(collection).bulkWrite(captor.capture(), any());
|
||||
|
||||
UpdateOneModel<Document> updateModel = (UpdateOneModel<Document>) captor.getValue().get(0);
|
||||
assertThat(updateModel.getUpdate())
|
||||
.isEqualTo(new Document("$set", new Document("items.$.documents.0.fileId", "new-id")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2502
|
||||
public void shouldRetainNestedArrayPathWithPlaceholdersForMappedEntity() {
|
||||
|
||||
DefaultBulkOperations ops = new DefaultBulkOperations(template, "collection-1",
|
||||
new BulkOperationContext(BulkMode.ORDERED, Optional.of(mappingContext.getPersistentEntity(OrderTest.class)),
|
||||
new QueryMapper(converter), new UpdateMapper(converter), null, null));
|
||||
|
||||
ops.updateOne(new BasicQuery("{}"), Update.update("items.$.documents.0.fileId", "file-id")).execute();
|
||||
|
||||
verify(collection).bulkWrite(captor.capture(), any());
|
||||
|
||||
UpdateOneModel<Document> updateModel = (UpdateOneModel<Document>) captor.getValue().get(0);
|
||||
assertThat(updateModel.getUpdate())
|
||||
.isEqualTo(new Document("$set", new Document("items.$.documents.0.the_file_id", "file-id")));
|
||||
}
|
||||
|
||||
static class OrderTest {
|
||||
|
||||
String id;
|
||||
List<OrderTestItem> items;
|
||||
}
|
||||
|
||||
static class OrderTestItem {
|
||||
|
||||
private String cartId;
|
||||
private List<OrderTestDocument> documents;
|
||||
}
|
||||
|
||||
static class OrderTestDocument {
|
||||
|
||||
@Field("the_file_id")
|
||||
private String fileId;
|
||||
}
|
||||
|
||||
class SomeDomainType {
|
||||
|
||||
@Id String id;
|
||||
|
||||
@@ -1499,6 +1499,15 @@ public class ProjectionOperationUnitTests {
|
||||
assertThat(agg).isEqualTo(Document.parse("{ $project: { eq250: { $eq: [\"$qty\", 250]} } }"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2513
|
||||
public void shouldRenderEqAggregationExpressionWithListComparison() {
|
||||
|
||||
Document agg = project().and(ComparisonOperators.valueOf("qty").equalToValue(Arrays.asList(250))).as("eq250")
|
||||
.toDocument(Aggregation.DEFAULT_CONTEXT);
|
||||
|
||||
assertThat(agg).isEqualTo(Document.parse("{ $project: { eq250: { $eq: [\"$qty\", [250]]} } }"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1536
|
||||
public void shouldRenderGtAggregationExpression() {
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ import com.mongodb.DBRef;
|
||||
* @author Patrik Wasik
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Heesu Jung
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MappingMongoConverterUnitTests {
|
||||
@@ -2078,6 +2079,23 @@ public class MappingMongoConverterUnitTests {
|
||||
.isEqualTo(new BasicDBObject("property", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2300
|
||||
public void readAndConvertDBRefNestedByMapCorrectly() {
|
||||
|
||||
org.bson.Document cluster = new org.bson.Document("_id", 100L);
|
||||
DBRef dbRef = new DBRef("clusters", 100L);
|
||||
|
||||
org.bson.Document data = new org.bson.Document("_id", 3L);
|
||||
data.append("cluster", dbRef);
|
||||
|
||||
MappingMongoConverter spyConverter = spy(converter);
|
||||
Mockito.doReturn(cluster).when(spyConverter).readRef(dbRef);
|
||||
|
||||
Map<Object, Object> result = spyConverter.readMap(ClassTypeInformation.MAP, data, ObjectPath.ROOT);
|
||||
|
||||
assertThat(((LinkedHashMap) result.get("cluster")).get("_id")).isEqualTo(100L);
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.springframework.data.mongodb.core.mapping.TextScore;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.TextQuery;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
@@ -927,6 +928,106 @@ public class QueryMapperUnitTests {
|
||||
assertThat(target).isEqualTo(org.bson.Document.parse("{\"_id\": {\"$in\": [{\"$oid\": \"" + id + "\"}]}}"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2488
|
||||
public void mapsNestedArrayPathCorrectlyForNonMatchingPath() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("array.$[some_item].nested.$[other_item]").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(Foo.class));
|
||||
|
||||
assertThat(target).isEqualTo(new org.bson.Document("array.$[some_item].nested.$[other_item]", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2488
|
||||
public void mapsNestedArrayPathCorrectlyForObjectTargetArray() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("arrayObj.$[some_item].nested.$[other_item]").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(WithNestedArray.class));
|
||||
|
||||
assertThat(target).isEqualTo(new org.bson.Document("arrayObj.$[some_item].nested.$[other_item]", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2488
|
||||
public void mapsNestedArrayPathCorrectlyForStringTargetArray() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("arrayString.$[some_item].nested.$[other_item]").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(WithNestedArray.class));
|
||||
|
||||
assertThat(target).isEqualTo(new org.bson.Document("arrayString.$[some_item].nested.$[other_item]", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2488
|
||||
public void mapsCustomFieldNamesForNestedArrayPathCorrectly() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("arrayCustomName.$[some_item].nested.$[other_item]").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(WithNestedArray.class));
|
||||
|
||||
assertThat(target).isEqualTo(new org.bson.Document("arrayCustomName.$[some_item].nes-ted.$[other_item]", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2502
|
||||
public void shouldAllowDeeplyNestedPlaceholders() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("level0.$[some_item].arrayObj.$[other_item].nested").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(WithDeepArrayNesting.class));
|
||||
|
||||
assertThat(target).isEqualTo(new org.bson.Document("level0.$[some_item].arrayObj.$[other_item].nested", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2502
|
||||
public void shouldAllowDeeplyNestedPlaceholdersWithCustomName() {
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(
|
||||
query(where("level0.$[some_item].arrayCustomName.$[other_item].nested").is("value")).getQueryObject(),
|
||||
context.getPersistentEntity(WithDeepArrayNesting.class));
|
||||
|
||||
assertThat(target)
|
||||
.isEqualTo(new org.bson.Document("level0.$[some_item].arrayCustomName.$[other_item].nes-ted", "value"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2517
|
||||
public void shouldParseNestedKeywordWithArgumentMatchingTheSourceEntitiesConstructorCorrectly() {
|
||||
|
||||
TextQuery source = new TextQuery("test");
|
||||
|
||||
org.bson.Document target = mapper.getMappedObject(source.getQueryObject(),
|
||||
context.getPersistentEntity(WithSingleStringArgConstructor.class));
|
||||
assertThat(target).isEqualTo(org.bson.Document.parse("{\"$text\" : { \"$search\" : \"test\" }}"));
|
||||
}
|
||||
|
||||
class WithDeepArrayNesting {
|
||||
|
||||
List<WithNestedArray> level0;
|
||||
}
|
||||
|
||||
class WithNestedArray {
|
||||
|
||||
List<NestedArrayOfObj> arrayObj;
|
||||
List<NestedArrayOfString> arrayString;
|
||||
List<NestedArrayOfObjCustomFieldName> arrayCustomName;
|
||||
}
|
||||
|
||||
class NestedArrayOfObj {
|
||||
List<ArrayObj> nested;
|
||||
}
|
||||
|
||||
class NestedArrayOfObjCustomFieldName {
|
||||
|
||||
@Field("nes-ted") List<ArrayObj> nested;
|
||||
}
|
||||
|
||||
class NestedArrayOfString {
|
||||
List<String> nested;
|
||||
}
|
||||
|
||||
class ArrayObj {
|
||||
String foo;
|
||||
}
|
||||
|
||||
@Document
|
||||
public class Foo {
|
||||
@Id private ObjectId id;
|
||||
@@ -1069,4 +1170,16 @@ public class QueryMapperUnitTests {
|
||||
String id;
|
||||
@Field(targetType = FieldType.OBJECT_ID) String stringAsOid;
|
||||
}
|
||||
|
||||
@Document
|
||||
static class WithSingleStringArgConstructor {
|
||||
|
||||
String value;
|
||||
|
||||
public WithSingleStringArgConstructor() {}
|
||||
|
||||
public WithSingleStringArgConstructor(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.mongodb.core.DocumentTestUtils;
|
||||
* Unit tests for {@link TextCriteria}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Daniel Debray
|
||||
*/
|
||||
public class TextCriteriaUnitTests {
|
||||
|
||||
@@ -33,6 +34,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldNotHaveLanguageField() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage();
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ }"));
|
||||
}
|
||||
|
||||
@@ -40,6 +42,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldNotHaveLanguageForNonDefaultLanguageField() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forLanguage("spanish");
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ \"$language\" : \"spanish\" }"));
|
||||
}
|
||||
|
||||
@@ -47,6 +50,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateSearchFieldForSingleTermCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matching("cake");
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ \"$search\" : \"cake\" }"));
|
||||
}
|
||||
|
||||
@@ -54,6 +58,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateSearchFieldCorrectlyForMultipleTermsCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingAny("bake", "coffee", "cake");
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ \"$search\" : \"bake coffee cake\" }"));
|
||||
}
|
||||
|
||||
@@ -61,6 +66,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateSearchFieldForPhraseCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matchingPhrase("coffee cake");
|
||||
|
||||
assertThat(DocumentTestUtils.getAsDocument(criteria.getCriteriaObject(), "$text"))
|
||||
.isEqualTo(new Document("$search", "\"coffee cake\""));
|
||||
}
|
||||
@@ -69,6 +75,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateNotFieldCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().notMatching("cake");
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ \"$search\" : \"-cake\" }"));
|
||||
}
|
||||
|
||||
@@ -76,6 +83,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateSearchFieldCorrectlyForNotMultipleTermsCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().notMatchingAny("bake", "coffee", "cake");
|
||||
|
||||
assertThat(criteria.getCriteriaObject()).isEqualTo(searchObject("{ \"$search\" : \"-bake -coffee -cake\" }"));
|
||||
}
|
||||
|
||||
@@ -83,6 +91,7 @@ public class TextCriteriaUnitTests {
|
||||
public void shouldCreateSearchFieldForNotPhraseCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().notMatchingPhrase("coffee cake");
|
||||
|
||||
assertThat(DocumentTestUtils.getAsDocument(criteria.getCriteriaObject(), "$text"))
|
||||
.isEqualTo(new Document("$search", "-\"coffee cake\""));
|
||||
}
|
||||
@@ -91,6 +100,7 @@ public class TextCriteriaUnitTests {
|
||||
public void caseSensitiveOperatorShouldBeSetCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matching("coffee").caseSensitive(true);
|
||||
|
||||
assertThat(DocumentTestUtils.getAsDocument(criteria.getCriteriaObject(), "$text"))
|
||||
.isEqualTo(new Document("$search", "coffee").append("$caseSensitive", true));
|
||||
}
|
||||
@@ -99,10 +109,23 @@ public class TextCriteriaUnitTests {
|
||||
public void diacriticSensitiveOperatorShouldBeSetCorrectly() {
|
||||
|
||||
TextCriteria criteria = TextCriteria.forDefaultLanguage().matching("coffee").diacriticSensitive(true);
|
||||
|
||||
assertThat(DocumentTestUtils.getAsDocument(criteria.getCriteriaObject(), "$text"))
|
||||
.isEqualTo(new Document("$search", "coffee").append("$diacriticSensitive", true));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2504
|
||||
public void twoIdenticalCriteriaShouldBeEqual() {
|
||||
|
||||
TextCriteria criteriaOne = TextCriteria.forDefaultLanguage().matching("coffee");
|
||||
TextCriteria criteriaTwo = TextCriteria.forDefaultLanguage().matching("coffee");
|
||||
|
||||
assertThat(criteriaOne).isEqualTo(criteriaTwo);
|
||||
assertThat(criteriaOne).hasSameHashCodeAs(criteriaTwo);
|
||||
assertThat(criteriaOne).isNotEqualTo(criteriaTwo.diacriticSensitive(false));
|
||||
assertThat(criteriaOne.hashCode()).isNotEqualTo(criteriaTwo.diacriticSensitive(false).hashCode());
|
||||
}
|
||||
|
||||
private Document searchObject(String json) {
|
||||
return new Document("$text", Document.parse(json));
|
||||
}
|
||||
|
||||
@@ -34,8 +34,12 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||
@@ -198,6 +202,16 @@ public class StringBasedAggregationUnitTests {
|
||||
assertThat(collationOf(invocation)).isEqualTo(Collation.of("en_US"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2506
|
||||
public void aggregateRaisesErrorOnInvalidReturnType() {
|
||||
|
||||
StringBasedAggregation sba = createAggregationForMethod("invalidPageReturnType", Pageable.class);
|
||||
assertThatExceptionOfType(InvalidMongoDbApiUsageException.class) //
|
||||
.isThrownBy(() -> sba.execute(new Object[] { PageRequest.of(0, 1) })) //
|
||||
.withMessageContaining("invalidPageReturnType") //
|
||||
.withMessageContaining("Page");
|
||||
}
|
||||
|
||||
private AggregationInvocation executeAggregation(String name, Object... args) {
|
||||
|
||||
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
|
||||
@@ -276,6 +290,9 @@ public class StringBasedAggregationUnitTests {
|
||||
|
||||
@Aggregation(pipeline = RAW_GROUP_BY_LASTNAME_STRING, collation = "de_AT")
|
||||
PersonAggregate aggregateWithCollation(Collation collation);
|
||||
|
||||
@Aggregation(RAW_GROUP_BY_LASTNAME_STRING)
|
||||
Page<Person> invalidPageReturnType(Pageable page);
|
||||
}
|
||||
|
||||
static class PersonAggregate {
|
||||
|
||||
@@ -231,7 +231,7 @@ public class ParameterBindingJsonReaderUnitTests {
|
||||
public void bindMultipleUnquotedParameterInArray() {
|
||||
|
||||
Document target = parse("{ 'name' : { $in : [?0,?1] } }", "dalinar", "kohlin");
|
||||
assertThat(target).isEqualTo(new Document("name", new Document("$in",Arrays.asList("dalinar", "kohlin"))));
|
||||
assertThat(target).isEqualTo(new Document("name", new Document("$in", Arrays.asList("dalinar", "kohlin"))));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2476
|
||||
@@ -252,7 +252,16 @@ public class ParameterBindingJsonReaderUnitTests {
|
||||
public void bindQuotedMulitParameterInArray() {
|
||||
|
||||
Document target = parse("{ 'name' : { $in : ['?0,?1'] } }", "dalinar", "kohlin");
|
||||
assertThat(target).isEqualTo(new Document("name", new Document("$in", Collections.singletonList("dalinar,kohlin"))));
|
||||
assertThat(target)
|
||||
.isEqualTo(new Document("name", new Document("$in", Collections.singletonList("dalinar,kohlin"))));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2523
|
||||
public void bindSpelExpressionInArrayCorrectly/* closing bracket must not have leading whitespace! */() {
|
||||
|
||||
Document target = parse("{ $and : [?#{ [0] == null ? { '$where' : 'true' } : { 'v1' : { '$in' : {[0]} } } }]}", 1);
|
||||
|
||||
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"v1\": {\"$in\": [1]}}]}"));
|
||||
}
|
||||
|
||||
private static Document parse(String json, Object... args) {
|
||||
|
||||
@@ -416,7 +416,7 @@ The MappingMongoConverter can use metadata to drive the mapping of objects to do
|
||||
* `@TextIndexed`: Applied at the field level to mark the field to be included in the text index.
|
||||
* `@HashIndexed`: Applied at the field level for usage within a hashed index to partition data across a sharded cluster.
|
||||
* `@Language`: Applied at the field level to set the language override property for text index.
|
||||
* `@Transient`: By default all private fields are mapped to the document, this annotation excludes the field where it is applied from being stored in the database
|
||||
* `@Transient`: By default, all fields are mapped to the document. This annotation excludes the field where it is applied from being stored in the database. Transient properties cannot be used within a persistence constructor as the converter cannot materialize a value for the constructor argument.
|
||||
* `@PersistenceConstructor`: Marks a given constructor - even a package protected one - to use when instantiating the object from the database. Constructor arguments are mapped by name to the key values in the retrieved Document.
|
||||
* `@Value`: This annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments. This lets you use a Spring Expression Language statement to transform a key's value retrieved in the database before it is used to construct a domain object. In order to reference a property of a given document one has to use expressions like: `@Value("#root.myProperty")` where `root` refers to the root of the given document.
|
||||
* `@Field`: Applied at the field level it allows to describe the name and type of the field as it will be represented in the MongoDB BSON document thus allowing the name and type to be different than the fieldname of the class as well as the property type.
|
||||
|
||||
@@ -1,6 +1,66 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 2.2.7.RELEASE (2020-04-28)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2529 - EntityReader called with null argument.
|
||||
* DATAMONGO-2523 - ParameterBindingJsonReader skips too many chars.
|
||||
* DATAMONGO-2517 - Text search fails on entity with second constructor.
|
||||
* DATAMONGO-2513 - ComparisonOperators.Eq#equalToValue doesn't work well with Lists.
|
||||
* DATAMONGO-2506 - StringBasedAggregation should raise meaningful error when unsupported return type requested.
|
||||
* DATAMONGO-2504 - TextCriteria Hashcode and equals.
|
||||
* DATAMONGO-2502 - Regression in Update property mapping.
|
||||
* DATAMONGO-2500 - Release 2.2.7 (Moore SR7).
|
||||
|
||||
|
||||
Changes in version 2.1.17.RELEASE (2020-04-28)
|
||||
----------------------------------------------
|
||||
* DATAMONGO-2529 - EntityReader called with null argument.
|
||||
* DATAMONGO-2497 - Update documentation regarding @Transient properties usage in the persistence constructor.
|
||||
* DATAMONGO-2484 - Release 2.1.17 (Lovelace SR17).
|
||||
* DATAMONGO-2300 - Can't read and convert DBRef when the type is Map.
|
||||
|
||||
|
||||
Changes in version 3.0.0.RC1 (2020-03-31)
|
||||
-----------------------------------------
|
||||
* DATAMONGO-2501 - Upgrade to Querydsl 4.3.
|
||||
* DATAMONGO-2498 - Upgrade to MongoDB 4.0.1 Drivers.
|
||||
* DATAMONGO-2497 - Update documentation regarding @Transient properties usage in the persistence constructor.
|
||||
* DATAMONGO-2492 - Release 3.0 RC1 (Neumann).
|
||||
* DATAMONGO-2488 - KeyMapper.mapPropertyName does not work for nested arrays.
|
||||
* DATAMONGO-2479 - More EntityCallback specializations.
|
||||
* DATAMONGO-2477 - Disable auto-index creation by default.
|
||||
* DATAMONGO-2475 - QueryDSL: $and and $or with more than two arguments in final query document.
|
||||
* DATAMONGO-2416 - Add default methods accepting CriteriaDefinition on Fluent API.
|
||||
* DATAMONGO-2300 - Can't read and convert DBRef when the type is Map.
|
||||
* DATAMONGO-1026 - Joda, JSR-310 and ThreeTenBp converters are timezone-sensitive.
|
||||
* DATAMONGO-931 - Add support for $redact operation.
|
||||
* DATAMONGO-625 - GridFsOperations.createFile method should allow specification of _id.
|
||||
|
||||
|
||||
Changes in version 2.2.6.RELEASE (2020-03-25)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2497 - Update documentation regarding @Transient properties usage in the persistence constructor.
|
||||
* DATAMONGO-2488 - KeyMapper.mapPropertyName does not work for nested arrays.
|
||||
* DATAMONGO-2485 - Release 2.2.6 (Moore SR6).
|
||||
* DATAMONGO-2445 - Deprecate ReactiveGridFs methods using AsyncInputStream.
|
||||
* DATAMONGO-2300 - Can't read and convert DBRef when the type is Map.
|
||||
|
||||
|
||||
Changes in version 3.0.0.M4 (2020-03-11)
|
||||
----------------------------------------
|
||||
* DATAMONGO-2491 - Adapt to Mockito 3.3 changes.
|
||||
* DATAMONGO-2489 - Upgrade to MongoDB Driver 4.0.
|
||||
* DATAMONGO-2481 - Speed up build.
|
||||
* DATAMONGO-2478 - NPE when using Query annotation and with sort and pageable.
|
||||
* DATAMONGO-2476 - JsonParseException: JSON reader was expecting a value but found '}'.
|
||||
* DATAMONGO-2474 - Upgrade to MongoDB Driver 4.0.0-rc0.
|
||||
* DATAMONGO-2473 - Release 3.0 M4 (Neumann).
|
||||
* DATAMONGO-2363 - Add support for $merge aggregation stage.
|
||||
* DATAMONGO-2355 - Revise Abstract…MongoConfiguration to expose more bean detail and avoid proxying.
|
||||
* DATAMONGO-2341 - Support shard key derivation.
|
||||
|
||||
|
||||
Changes in version 2.2.5.RELEASE (2020-02-26)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2478 - NPE when using Query annotation and with sort and pageable.
|
||||
@@ -2935,3 +2995,8 @@ Repository
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 2.2.5
|
||||
Spring Data MongoDB 2.2.7
|
||||
Copyright (c) [2010-2019] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -11,3 +11,5 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user