Compare commits
13 Commits
2.0.8.RELE
...
2.0.9.RELE
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8f093269d | ||
|
|
172db96fea | ||
|
|
c8381c734b | ||
|
|
bf82964474 | ||
|
|
2d0495874f | ||
|
|
82c91cbb71 | ||
|
|
4d309bd7f0 | ||
|
|
6f011b0fa1 | ||
|
|
1a3b9e3c42 | ||
|
|
5a37468103 | ||
|
|
d4b0963550 | ||
|
|
468c497525 | ||
|
|
4562f39d7a |
6
pom.xml
6
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.8.RELEASE</version>
|
||||
<version>2.0.9.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.0.8.RELEASE</version>
|
||||
<version>2.0.9.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
@@ -27,7 +27,7 @@
|
||||
<properties>
|
||||
<project.type>multi</project.type>
|
||||
<dist.id>spring-data-mongodb</dist.id>
|
||||
<springdata.commons>2.0.8.RELEASE</springdata.commons>
|
||||
<springdata.commons>2.0.9.RELEASE</springdata.commons>
|
||||
<mongo>3.5.0</mongo>
|
||||
<mongo.reactivestreams>1.6.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.0.8.RELEASE</version>
|
||||
<version>2.0.9.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.8.RELEASE</version>
|
||||
<version>2.0.9.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<version>2.0.8.RELEASE</version>
|
||||
<version>2.0.9.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- reactive -->
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||
<version>2.0.8.RELEASE</version>
|
||||
<version>2.0.9.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.0.8.RELEASE</version>
|
||||
<version>2.0.9.RELEASE</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ import com.mongodb.MongoCredential;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Stephen Tyler Conrad
|
||||
* @author Mark Paluch
|
||||
* @since 1.7
|
||||
*/
|
||||
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
||||
@@ -164,7 +166,7 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
||||
private static Properties extractOptions(String text) {
|
||||
|
||||
int optionsSeparationIndex = text.lastIndexOf(OPTIONS_DELIMITER);
|
||||
int dbSeparationIndex = text.lastIndexOf(OPTIONS_DELIMITER);
|
||||
int dbSeparationIndex = text.lastIndexOf(DATABASE_DELIMITER);
|
||||
|
||||
if (optionsSeparationIndex == -1 || dbSeparationIndex > optionsSeparationIndex) {
|
||||
return new Properties();
|
||||
@@ -173,7 +175,13 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
||||
Properties properties = new Properties();
|
||||
|
||||
for (String option : text.substring(optionsSeparationIndex + 1).split(OPTION_VALUE_DELIMITER)) {
|
||||
|
||||
String[] optionArgs = option.split("=");
|
||||
|
||||
if (optionArgs.length == 1) {
|
||||
throw new IllegalArgumentException(String.format("Query parameter '%s' has no value!", optionArgs[0]));
|
||||
}
|
||||
|
||||
properties.put(optionArgs[0], optionArgs[1]);
|
||||
}
|
||||
|
||||
|
||||
@@ -980,13 +980,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
items.add(read(componentType, (BasicDBObject) element, path));
|
||||
} else {
|
||||
|
||||
if (element instanceof Collection) {
|
||||
if (!Object.class.equals(rawComponentType) && element instanceof Collection) {
|
||||
if (!rawComponentType.isArray() && !ClassUtils.isAssignable(Iterable.class, rawComponentType)) {
|
||||
throw new MappingException(
|
||||
String.format(INCOMPATIBLE_TYPES, element, element.getClass(), rawComponentType, path));
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof List) {
|
||||
items.add(readCollectionOrArray(componentType, (Collection<Object>) element, path));
|
||||
} else {
|
||||
|
||||
@@ -44,13 +44,14 @@ import com.mongodb.client.gridfs.model.GridFSUploadOptions;
|
||||
|
||||
/**
|
||||
* {@link GridFsOperations} implementation to store content into MongoDB GridFS.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Philipp Schneider
|
||||
* @author Thomas Darimont
|
||||
* @author Martin Baumgartner
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Niklas Helge Hanft
|
||||
*/
|
||||
public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver {
|
||||
|
||||
@@ -62,7 +63,7 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
|
||||
/**
|
||||
* Creates a new {@link GridFsTemplate} using the given {@link MongoDbFactory} and {@link MongoConverter}.
|
||||
*
|
||||
*
|
||||
* @param dbFactory must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
@@ -72,7 +73,7 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
|
||||
/**
|
||||
* Creates a new {@link GridFsTemplate} using the given {@link MongoDbFactory} and {@link MongoConverter}.
|
||||
*
|
||||
*
|
||||
* @param dbFactory must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param bucket
|
||||
@@ -228,7 +229,7 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
public GridFsResource getResource(String location) {
|
||||
|
||||
GridFSFile file = findOne(query(whereFilename().is(location)));
|
||||
return file != null ? new GridFsResource(file, getGridFs().openDownloadStream(location)) : null;
|
||||
return file != null ? new GridFsResource(file, getGridFs().openDownloadStream(file.getObjectId())) : null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -246,13 +247,13 @@ public class GridFsTemplate implements GridFsOperations, ResourcePatternResolver
|
||||
if (path.isPattern()) {
|
||||
|
||||
GridFSFindIterable files = find(query(whereFilename().regex(path.toRegex())));
|
||||
List<GridFsResource> resources = new ArrayList<GridFsResource>();
|
||||
List<GridFsResource> resources = new ArrayList<>();
|
||||
|
||||
for (GridFSFile file : files) {
|
||||
resources.add(new GridFsResource(file, getGridFs().openDownloadStream(file.getFilename())));
|
||||
resources.add(new GridFsResource(file, getGridFs().openDownloadStream(file.getObjectId())));
|
||||
}
|
||||
|
||||
return resources.toArray(new GridFsResource[resources.size()]);
|
||||
return resources.toArray(new GridFsResource[0]);
|
||||
}
|
||||
|
||||
return new GridFsResource[] { getResource(locationPattern) };
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.data.mongodb.repository.query.ReactiveMongoQueryExecu
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.repository.query.ReturnedType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -150,6 +149,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
|
||||
return (q, t, c) -> operation.matching(q.with(accessor.getPageable())).all();
|
||||
} else if (isCountQuery()) {
|
||||
return (q, t, c) -> operation.matching(q).count();
|
||||
} else if (isExistsQuery()) {
|
||||
return (q, t, c) -> operation.matching(q).exists();
|
||||
} else {
|
||||
return (q, t, c) -> {
|
||||
|
||||
@@ -204,6 +205,14 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
|
||||
*/
|
||||
protected abstract boolean isCountQuery();
|
||||
|
||||
/**
|
||||
* Returns whether the query should get an exists projection applied.
|
||||
*
|
||||
* @return
|
||||
* @since 2.0.9
|
||||
*/
|
||||
protected abstract boolean isExistsQuery();
|
||||
|
||||
/**
|
||||
* Return weather the query should delete matching documents.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* Utility class containing methods to interact with boolean values.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0.9
|
||||
*/
|
||||
@UtilityClass
|
||||
class BooleanUtil {
|
||||
|
||||
/**
|
||||
* Count the number of {@literal true} values.
|
||||
*
|
||||
* @param values
|
||||
* @return the number of values that are {@literal true}.
|
||||
*/
|
||||
static int countBooleanTrueValues(boolean... values) {
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (boolean value : values) {
|
||||
|
||||
if (value) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,19 @@
|
||||
package org.springframework.data.mongodb.repository.query;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -206,6 +209,7 @@ class ExpressionEvaluatingParameterBinder {
|
||||
* @param binding must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private String getParameterValueForBinding(MongoParameterAccessor accessor, MongoParameters parameters,
|
||||
ParameterBinding binding) {
|
||||
|
||||
@@ -222,43 +226,7 @@ class ExpressionEvaluatingParameterBinder {
|
||||
return binding.isExpression() ? JSON.serialize(value) : QuotedString.unquote(JSON.serialize(value));
|
||||
}
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
|
||||
if (binding.isQuoted()) {
|
||||
return DatatypeConverter.printBase64Binary((byte[]) value);
|
||||
}
|
||||
|
||||
return encode(new Binary((byte[]) value), BinaryCodec::new);
|
||||
}
|
||||
|
||||
if (value instanceof UUID) {
|
||||
|
||||
if (binding.isQuoted()) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
return encode((UUID) value, UuidCodec::new);
|
||||
}
|
||||
|
||||
return JSON.serialize(value);
|
||||
}
|
||||
|
||||
private <T> String encode(T value, Supplier<Codec<T>> defaultCodec) {
|
||||
|
||||
Codec<T> codec;
|
||||
|
||||
try {
|
||||
codec = codecRegistry.get((Class<T>) value.getClass());
|
||||
} catch (CodecConfigurationException exception) {
|
||||
codec = defaultCodec.get();
|
||||
}
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
codec.encode(new JsonWriter(writer), value, null);
|
||||
writer.flush();
|
||||
|
||||
return writer.toString();
|
||||
return EncodableValue.create(value).encode(codecRegistry, binding.isQuoted());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,4 +448,230 @@ class ExpressionEvaluatingParameterBinder {
|
||||
return quoted.substring(1, quoted.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Value object encapsulating a bindable value, that can be encoded to be represented as JSON (BSON).
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
abstract static class EncodableValue {
|
||||
|
||||
/**
|
||||
* Obtain a {@link EncodableValue} given {@code value}.
|
||||
*
|
||||
* @param value the value to encode, may be {@literal null}.
|
||||
* @return the {@link EncodableValue} for {@code value}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static EncodableValue create(@Nullable Object value) {
|
||||
|
||||
if (value instanceof byte[]) {
|
||||
return new BinaryValue((byte[]) value);
|
||||
}
|
||||
|
||||
if (value instanceof UUID) {
|
||||
return new UuidValue((UUID) value);
|
||||
}
|
||||
|
||||
if (value instanceof Collection) {
|
||||
|
||||
Collection<?> collection = (Collection<?>) value;
|
||||
Class<?> commonElement = CollectionUtils.findCommonElementType(collection);
|
||||
|
||||
if (commonElement != null) {
|
||||
|
||||
if (UUID.class.isAssignableFrom(commonElement)) {
|
||||
return new UuidCollection((Collection<UUID>) value);
|
||||
}
|
||||
|
||||
if (byte[].class.isAssignableFrom(commonElement)) {
|
||||
return new BinaryCollectionValue((Collection<byte[]>) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ObjectValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the encapsulated value.
|
||||
*
|
||||
* @param provider
|
||||
* @param quoted
|
||||
* @return
|
||||
*/
|
||||
public abstract String encode(CodecRegistry codecRegistry, boolean quoted);
|
||||
|
||||
/**
|
||||
* Encode a {@code value} to JSON.
|
||||
*
|
||||
* @param provider
|
||||
* @param value
|
||||
* @param defaultCodec
|
||||
* @param <V>
|
||||
* @return
|
||||
*/
|
||||
protected <V> String encode(CodecRegistry codecRegistry, V value, Supplier<Codec<V>> defaultCodec) {
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
doEncode(codecRegistry, writer, value, defaultCodec);
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a {@link Collection} to JSON and potentially apply a {@link Function mapping function} before encoding.
|
||||
*
|
||||
* @param provider
|
||||
* @param value
|
||||
* @param mappingFunction
|
||||
* @param defaultCodec
|
||||
* @param <I> Input value type.
|
||||
* @param <V> Target type.
|
||||
* @return
|
||||
*/
|
||||
protected <I, V> String encodeCollection(CodecRegistry codecRegistry, Iterable<I> value,
|
||||
Function<I, V> mappingFunction, Supplier<Codec<V>> defaultCodec) {
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
writer.append("[");
|
||||
value.forEach(it -> {
|
||||
|
||||
if (writer.getBuffer().length() > 1) {
|
||||
writer.append(", ");
|
||||
}
|
||||
|
||||
doEncode(codecRegistry, writer, mappingFunction.apply(it), defaultCodec);
|
||||
});
|
||||
|
||||
writer.append("]");
|
||||
writer.flush();
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V> void doEncode(CodecRegistry codecRegistry, StringWriter writer, V value,
|
||||
Supplier<Codec<V>> defaultCodec) {
|
||||
|
||||
Codec<V> codec = getCodec(codecRegistry, (Class<V>) value.getClass(), defaultCodec);
|
||||
|
||||
JsonWriter jsonWriter = new JsonWriter(writer);
|
||||
codec.encode(jsonWriter, value, null);
|
||||
jsonWriter.flush();
|
||||
}
|
||||
|
||||
private <T> Codec<T> getCodec(CodecRegistry codecRegistry, Class<T> type, Supplier<Codec<T>> defaultCodec) {
|
||||
|
||||
try {
|
||||
return codecRegistry.get(type);
|
||||
} catch (CodecConfigurationException exception) {
|
||||
return defaultCodec.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EncodableValue} for {@code byte[]} to render to {@literal $binary}.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class BinaryValue extends EncodableValue {
|
||||
|
||||
private final byte[] value;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.ExpressionEvaluatingParameterBinder.EncodableValue#encode(org.bson.codecs.configuration.CodecRegistry, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String encode(CodecRegistry codecRegistry, boolean quoted) {
|
||||
|
||||
if (quoted) {
|
||||
return DatatypeConverter.printBase64Binary(this.value);
|
||||
}
|
||||
|
||||
return encode(codecRegistry, new Binary(this.value), BinaryCodec::new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EncodableValue} for {@link Collection} containing only {@code byte[]} items to render to a BSON list
|
||||
* containing {@literal $binary}.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class BinaryCollectionValue extends EncodableValue {
|
||||
|
||||
private final Collection<byte[]> value;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.ExpressionEvaluatingParameterBinder.EncodableValue#encode(org.bson.codecs.configuration.CodecRegistry, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String encode(CodecRegistry codecRegistry, boolean quoted) {
|
||||
return encodeCollection(codecRegistry, this.value, Binary::new, BinaryCodec::new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EncodableValue} for {@link UUID} to render to {@literal $binary}.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class UuidValue extends EncodableValue {
|
||||
|
||||
private final UUID value;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.ExpressionEvaluatingParameterBinder.EncodableValue#encode(org.bson.codecs.configuration.CodecRegistry, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String encode(CodecRegistry codecRegistry, boolean quoted) {
|
||||
|
||||
if (quoted) {
|
||||
return this.value.toString();
|
||||
}
|
||||
|
||||
return encode(codecRegistry, this.value, UuidCodec::new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EncodableValue} for {@link Collection} containing only {@link UUID} items to render to a BSON list
|
||||
* containing {@literal $binary}.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class UuidCollection extends EncodableValue {
|
||||
|
||||
private final Collection<UUID> value;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.ExpressionEvaluatingParameterBinder.EncodableValue#encode(org.bson.codecs.configuration.CodecRegistry, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String encode(CodecRegistry codecRegistry, boolean quoted) {
|
||||
return encodeCollection(codecRegistry, this.value, Function.identity(), UuidCodec::new);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback-{@link EncodableValue} for {@link Object}-typed values.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
static class ObjectValue extends EncodableValue {
|
||||
|
||||
private final @Nullable Object value;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.ExpressionEvaluatingParameterBinder.EncodableValue#encode(org.bson.codecs.configuration.CodecRegistry, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String encode(CodecRegistry codecRegistry, boolean quoted) {
|
||||
return JSON.serialize(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,15 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
|
||||
return tree.isCountProjection();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isExistsQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return tree.isExistsProjection();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isDeleteQuery()
|
||||
|
||||
@@ -40,13 +40,14 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
|
||||
|
||||
private static final String COUND_AND_DELETE = "Manually defined query for %s cannot be both a count and delete query at the same time!";
|
||||
private static final String COUNT_EXISTS_AND_DELETE = "Manually defined query for %s cannot be a count and exists or delete query at the same time!";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReactiveStringBasedMongoQuery.class);
|
||||
private static final ParameterBindingParser BINDING_PARSER = ParameterBindingParser.INSTANCE;
|
||||
|
||||
private final String query;
|
||||
private final String fieldSpec;
|
||||
private final boolean isCountQuery;
|
||||
private final boolean isExistsQuery;
|
||||
private final boolean isDeleteQuery;
|
||||
private final List<ParameterBinding> queryParameterBindings;
|
||||
private final List<ParameterBinding> fieldSpecParameterBindings;
|
||||
@@ -92,11 +93,23 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
|
||||
this.fieldSpec = BINDING_PARSER.parseAndCollectParameterBindingsFromQueryIntoBindings(
|
||||
method.getFieldSpecification(), this.fieldSpecParameterBindings);
|
||||
|
||||
this.isCountQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().count() : false;
|
||||
this.isDeleteQuery = method.hasAnnotatedQuery() ? method.getQueryAnnotation().delete() : false;
|
||||
if (method.hasAnnotatedQuery()) {
|
||||
|
||||
if (isCountQuery && isDeleteQuery) {
|
||||
throw new IllegalArgumentException(String.format(COUND_AND_DELETE, method));
|
||||
org.springframework.data.mongodb.repository.Query queryAnnotation = method.getQueryAnnotation();
|
||||
|
||||
this.isCountQuery = queryAnnotation.count();
|
||||
this.isExistsQuery = queryAnnotation.exists();
|
||||
this.isDeleteQuery = queryAnnotation.delete();
|
||||
|
||||
if (hasAmbiguousProjectionFlags(this.isCountQuery, this.isExistsQuery, this.isDeleteQuery)) {
|
||||
throw new IllegalArgumentException(String.format(COUNT_EXISTS_AND_DELETE, method));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.isCountQuery = false;
|
||||
this.isExistsQuery = false;
|
||||
this.isDeleteQuery = false;
|
||||
}
|
||||
|
||||
this.parameterBinder = new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider);
|
||||
@@ -132,6 +145,15 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
|
||||
return isCountQuery;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isExistsQuery()
|
||||
*/
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return isExistsQuery;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractReactiveMongoQuery#isDeleteQuery()
|
||||
@@ -150,4 +172,9 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
|
||||
boolean isDeleteQuery) {
|
||||
return BooleanUtil.countBooleanTrueValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -169,11 +169,6 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
return this.isDeleteQuery;
|
||||
}
|
||||
|
||||
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
|
||||
boolean isDeleteQuery) {
|
||||
return countBooleanValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery#isLimiting()
|
||||
@@ -183,18 +178,9 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int countBooleanValues(boolean... values) {
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (boolean value : values) {
|
||||
|
||||
if (value) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
private static boolean hasAmbiguousProjectionFlags(boolean isCountQuery, boolean isExistsQuery,
|
||||
boolean isDeleteQuery) {
|
||||
return BooleanUtil.countBooleanTrueValues(isCountQuery, isExistsQuery, isDeleteQuery) > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.config;
|
||||
|
||||
import static org.hamcrest.collection.IsIterableContainingInOrder.*;
|
||||
import static org.hamcrest.core.IsNull.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
@@ -34,6 +32,7 @@ import com.mongodb.MongoCredential;
|
||||
* Unit tests for {@link MongoCredentialPropertyEditor}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Stephen Tyler Conrad
|
||||
*/
|
||||
public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
@@ -54,6 +53,10 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
static final String USER_4_ENCODED_PWD;
|
||||
static final String USER_4_DB = "targaryen";
|
||||
|
||||
static final String USER_5_NAME = "lyanna";
|
||||
static final String USER_5_PWD = "random?password";
|
||||
static final String USER_5_DB = "mormont";
|
||||
|
||||
static final String USER_1_AUTH_STRING = USER_1_NAME + ":" + USER_1_PWD + "@" + USER_1_DB;
|
||||
static final String USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM = USER_1_AUTH_STRING + "?uri.authMechanism=PLAIN";
|
||||
|
||||
@@ -66,6 +69,10 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
static final String USER_4_AUTH_STRING;
|
||||
|
||||
static final String USER_5_AUTH_STRING = USER_5_NAME + ":" + USER_5_PWD + "@" + USER_5_DB;
|
||||
static final String USER_5_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM = USER_5_AUTH_STRING + "?uri.authMechanism=PLAIN";
|
||||
static final String USER_5_AUTH_STRING_WITH_QUERY_ARGS = USER_5_AUTH_STRING + "?uri.authMechanism=PLAIN&foo=&bar";
|
||||
|
||||
static final MongoCredential USER_1_CREDENTIALS = MongoCredential.createCredential(USER_1_NAME, USER_1_DB,
|
||||
USER_1_PWD.toCharArray());
|
||||
static final MongoCredential USER_1_CREDENTIALS_PLAIN_AUTH = MongoCredential.createPlainCredential(USER_1_NAME,
|
||||
@@ -81,6 +88,11 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
static final MongoCredential USER_4_CREDENTIALS = MongoCredential.createCredential(USER_4_PLAIN_NAME, USER_4_DB,
|
||||
USER_4_PLAIN_PWD.toCharArray());
|
||||
|
||||
static final MongoCredential USER_5_CREDENTIALS = MongoCredential.createCredential(USER_5_NAME, USER_5_DB,
|
||||
USER_5_PWD.toCharArray());
|
||||
static final MongoCredential USER_5_CREDENTIALS_PLAIN_AUTH = MongoCredential.createPlainCredential(USER_5_NAME,
|
||||
USER_5_DB, USER_5_PWD.toCharArray());
|
||||
|
||||
MongoCredentialPropertyEditor editor;
|
||||
|
||||
static {
|
||||
@@ -108,7 +120,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText(null);
|
||||
|
||||
assertThat(editor.getValue(), nullValue());
|
||||
assertThat(getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1158
|
||||
@@ -116,7 +128,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText(" ");
|
||||
|
||||
assertThat(editor.getValue(), nullValue());
|
||||
assertThat(getValue()).isNull();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1158
|
||||
@@ -135,7 +147,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText(USER_1_AUTH_STRING);
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1158
|
||||
@@ -144,7 +156,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText(USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM);
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS_PLAIN_AUTH));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS_PLAIN_AUTH);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1158
|
||||
@@ -154,38 +166,37 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
editor
|
||||
.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList(USER_1_AUTH_STRING, USER_2_AUTH_STRING)));
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1158
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleUserNamePasswordStringWithDatabaseAndAuthOptions() {
|
||||
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList(
|
||||
USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM, USER_2_AUTH_STRING_WITH_MONGODB_CR_AUTH_MECHANISM)));
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays
|
||||
.asList(USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM, USER_2_AUTH_STRING_WITH_MONGODB_CR_AUTH_MECHANISM)));
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(),
|
||||
contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS_CR_AUTH));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS_CR_AUTH);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1158
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleUserNamePasswordStringWithDatabaseAndMixedOptions() {
|
||||
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList(
|
||||
USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM, USER_2_AUTH_STRING)));
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(
|
||||
Arrays.asList(USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM, USER_2_AUTH_STRING)));
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1257
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleQuotedUserNamePasswordStringWithDatabaseAndNoOptions() {
|
||||
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList("'" + USER_1_AUTH_STRING + "'", "'"
|
||||
+ USER_2_AUTH_STRING + "'")));
|
||||
editor.setAsText(StringUtils.collectionToCommaDelimitedString(
|
||||
Arrays.asList("'" + USER_1_AUTH_STRING + "'", "'" + USER_2_AUTH_STRING + "'")));
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1257
|
||||
@@ -194,7 +205,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText("'" + USER_1_AUTH_STRING + "'");
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_1_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1257
|
||||
@@ -203,7 +214,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText(USER_3_AUTH_STRING_WITH_X509_AUTH_MECHANISM);
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_3_CREDENTIALS_X509_AUTH));
|
||||
assertThat(getValue()).contains(USER_3_CREDENTIALS_X509_AUTH);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1257
|
||||
@@ -212,7 +223,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText("tyrion?uri.authMechanism=MONGODB-X509");
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(MongoCredential.createMongoX509Credential("tyrion")));
|
||||
assertThat(getValue()). contains(MongoCredential.createMongoX509Credential("tyrion"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1257
|
||||
@@ -220,7 +231,7 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText("tyrion?uri.authMechanism=MONGODB-CR");
|
||||
|
||||
editor.getValue();
|
||||
getValue();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAMONGO-1257
|
||||
@@ -228,15 +239,44 @@ public class MongoCredentialPropertyEditorUnitTests {
|
||||
|
||||
editor.setAsText("tyrion@?uri.authMechanism=MONGODB-CR");
|
||||
|
||||
editor.getValue();
|
||||
getValue();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1317
|
||||
@SuppressWarnings("unchecked")
|
||||
public void encodedUserNameAndPasswrodShouldBeDecoded() throws UnsupportedEncodingException {
|
||||
public void encodedUserNameAndPasswordShouldBeDecoded() {
|
||||
|
||||
editor.setAsText(USER_4_AUTH_STRING);
|
||||
|
||||
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_4_CREDENTIALS));
|
||||
assertThat(getValue()).contains(USER_4_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2016
|
||||
@SuppressWarnings("unchecked")
|
||||
public void passwordWithQuestionMarkShouldNotBeInterpretedAsOptionString() {
|
||||
|
||||
editor.setAsText(USER_5_AUTH_STRING);
|
||||
|
||||
assertThat(getValue()).contains(USER_5_CREDENTIALS);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2016
|
||||
@SuppressWarnings("unchecked")
|
||||
public void passwordWithQuestionMarkShouldNotBreakParsingOfOptionString() {
|
||||
|
||||
editor.setAsText(USER_5_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM);
|
||||
|
||||
assertThat(getValue()).contains(USER_5_CREDENTIALS_PLAIN_AUTH);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class) // DATAMONGO-2016
|
||||
@SuppressWarnings("unchecked")
|
||||
public void failsGracefullyOnEmptyQueryArgument() {
|
||||
editor.setAsText(USER_5_AUTH_STRING_WITH_QUERY_ARGS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<MongoCredential> getValue() {
|
||||
return (List<MongoCredential>) editor.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1886,6 +1886,15 @@ public class MappingMongoConverterUnitTests {
|
||||
assertThat(result.nestedFloats).isEqualTo(new float[][][] { { { 1.0f, 2.0f } } });
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2011
|
||||
public void readsNestedListsToObjectCorrectly() {
|
||||
|
||||
List<String> values = Arrays.asList("ONE", "TWO");
|
||||
org.bson.Document source = new org.bson.Document("value", Collections.singletonList(values));
|
||||
|
||||
assertThat(converter.read(Attribute.class, source).value).isInstanceOf(List.class);
|
||||
}
|
||||
|
||||
static class GenericType<T> {
|
||||
T content;
|
||||
}
|
||||
|
||||
@@ -313,6 +313,11 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
|
||||
StepVerifier.create(repository.findFirstByLastname(dave.getLastname())).expectNextCount(1).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2030
|
||||
public void shouldReturnExistsBy() {
|
||||
StepVerifier.create(repository.existsByLastname(dave.getLastname())).expectNext(true).verifyComplete();
|
||||
}
|
||||
|
||||
interface ReactivePersonRepository extends ReactiveMongoRepository<Person, String> {
|
||||
|
||||
Flux<Person> findByLastname(String lastname);
|
||||
@@ -340,6 +345,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
|
||||
|
||||
Flux<Person> findPersonByLocationNear(Point point, Distance maxDistance);
|
||||
|
||||
Mono<Boolean> existsByLastname(String lastname);
|
||||
|
||||
Mono<Person> findFirstByLastname(String lastname);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,14 @@ public class ReactiveStringBasedMongoQueryUnitTests {
|
||||
createQueryForMethod("invalidMethod", String.class);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2030
|
||||
public void shouldSupportExistsProjection() throws Exception {
|
||||
|
||||
ReactiveStringBasedMongoQuery mongoQuery = createQueryForMethod("existsByLastname", String.class);
|
||||
|
||||
assertThat(mongoQuery.isExistsQuery(), is(true));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1444
|
||||
public void shouldSupportFindByParameterizedCriteriaAndFields() throws Exception {
|
||||
|
||||
@@ -260,5 +268,8 @@ public class ReactiveStringBasedMongoQueryUnitTests {
|
||||
|
||||
@Query("{'id':?#{ [0] ? { $exists :true} : [1] }, 'foo':42, 'bar': ?#{ [0] ? { $exists :false} : [1] }}")
|
||||
Flux<Person> findByQueryWithExpressionAndMultipleNestedObjects(boolean param0, String param1, String param2);
|
||||
|
||||
@Query(value = "{ 'lastname' : ?0 }", exists = true)
|
||||
Mono<Boolean> existsByLastname(String lastname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -322,6 +323,21 @@ public class StringBasedMongoQueryUnitTests {
|
||||
assertThat(query.getQueryObject().toJson(), is(reference.getQueryObject().toJson()));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2029
|
||||
public void shouldSupportNonQuotedBinaryCollectionDataReplacement() {
|
||||
|
||||
byte[] binaryData = "Matthews".getBytes(StandardCharsets.UTF_8);
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
(Object) Arrays.asList(binaryData));
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameAsBinaryIn", List.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery("{'lastname' : { $in: [{'$binary' : '"
|
||||
+ DatatypeConverter.printBase64Binary(binaryData) + "', '$type' : '" + BSON.B_GENERAL + "'}] }}");
|
||||
|
||||
assertThat(query.getQueryObject().toJson(), is(reference.getQueryObject().toJson()));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1911
|
||||
public void shouldSupportNonQuotedUUIDReplacement() {
|
||||
|
||||
@@ -336,6 +352,23 @@ public class StringBasedMongoQueryUnitTests {
|
||||
assertThat(query.getQueryObject().toJson(), is(reference.getQueryObject().toJson()));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2029
|
||||
public void shouldSupportNonQuotedUUIDCollectionReplacement() {
|
||||
|
||||
UUID uuid1 = UUID.fromString("864de43b-e3ea-f1e4-3663-fb8240b659b9");
|
||||
UUID uuid2 = UUID.fromString("864de43b-cafe-f1e4-3663-fb8240b659b9");
|
||||
|
||||
ConvertingParameterAccessor accessor = StubParameterAccessor.getAccessor(converter,
|
||||
(Object) Arrays.asList(uuid1, uuid2));
|
||||
StringBasedMongoQuery mongoQuery = createQueryForMethod("findByLastnameAsUUIDIn", List.class);
|
||||
|
||||
org.springframework.data.mongodb.core.query.Query query = mongoQuery.createQuery(accessor);
|
||||
org.springframework.data.mongodb.core.query.Query reference = new BasicQuery(
|
||||
"{'lastname' : { $in: [{ $binary : \"5PHq4zvkTYa5WbZAgvtjNg==\", $type : \"03\" }, { $binary : \"5PH+yjvkTYa5WbZAgvtjNg==\", $type : \"03\" }]}}");
|
||||
|
||||
assertThat(query.getQueryObject().toJson(), is(reference.getQueryObject().toJson()));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1911
|
||||
public void shouldSupportQuotedUUIDReplacement() {
|
||||
|
||||
@@ -580,9 +613,15 @@ public class StringBasedMongoQueryUnitTests {
|
||||
@Query("{ 'lastname' : ?0 }")
|
||||
Person findByLastnameAsBinary(byte[] lastname);
|
||||
|
||||
@Query("{ 'lastname' : { $in: ?0} }")
|
||||
Person findByLastnameAsBinaryIn(List<byte[]> lastname);
|
||||
|
||||
@Query("{ 'lastname' : ?0 }")
|
||||
Person findByLastnameAsUUID(UUID lastname);
|
||||
|
||||
@Query("{ 'lastname' : { $in : ?0} }")
|
||||
Person findByLastnameAsUUIDIn(List<UUID> lastname);
|
||||
|
||||
@Query("{ 'lastname' : '?0' }")
|
||||
Person findByLastnameAsStringUUID(UUID lastname);
|
||||
|
||||
|
||||
@@ -1,6 +1,55 @@
|
||||
Spring Data MongoDB Changelog
|
||||
=============================
|
||||
|
||||
Changes in version 2.0.9.RELEASE (2018-07-26)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2030 - Reactive repositories don't handle existsByProperty properly.
|
||||
* DATAMONGO-2029 - String query methods do not convert List<UUID> and List<byte[]> to their correct representation.
|
||||
* DATAMONGO-2016 - MongoCredentialPropertyEditor throws ArrayIndexOutOfBoundsException when password contains a questionmark.
|
||||
* DATAMONGO-2011 - Getting exception in MappingMongoConverter while trying to map array of arrays into Object.
|
||||
* DATAMONGO-2007 - Release 2.0.9 (Kay SR9).
|
||||
|
||||
|
||||
Changes in version 2.1.0.RC1 (2018-07-26)
|
||||
-----------------------------------------
|
||||
* DATAMONGO-2030 - Reactive repositories don't handle existsByProperty properly.
|
||||
* DATAMONGO-2029 - String query methods do not convert List<UUID> and List<byte[]> to their correct representation.
|
||||
* DATAMONGO-2028 - EntityOperations does not apply conversion to Mongo types.
|
||||
* DATAMONGO-2026 - Final id field causes UnsupportedOperationException when reading object.
|
||||
* DATAMONGO-2021 - Use correct document identifier on GridFsOperations getResource method.
|
||||
* DATAMONGO-2016 - MongoCredentialPropertyEditor throws ArrayIndexOutOfBoundsException when password contains a questionmark.
|
||||
* DATAMONGO-2012 - Upgrade to MongoDB java driver 3.8 and reactive streams 1.9.
|
||||
* DATAMONGO-2011 - Getting exception in MappingMongoConverter while trying to map array of arrays into Object.
|
||||
* DATAMONGO-2010 - SpringDataMongodbSerializer does not convert 'in' predicate for nested String id properties mapping to ObjectId.
|
||||
* DATAMONGO-2005 - Switch reactive transactions API over to Flux.usingWhen.
|
||||
* DATAMONGO-2004 - Lazily resolve DBRefs during constructor creation of the enclosing entity.
|
||||
* DATAMONGO-2003 - MongoQueryCreator will not create query correctly when passing Pattern Object with options.
|
||||
* DATAMONGO-2002 - Criteria instances using different regex Patterns are considered equal.
|
||||
* DATAMONGO-2001 - Count within session should return only the total count of documents visible to the specific session.
|
||||
* DATAMONGO-1998 - SpringDataMongodbSerializer cannot convert query on nested id.
|
||||
* DATAMONGO-1996 - ChangeStreamEvent Aggregator filter doesn't work for nested fields.
|
||||
* DATAMONGO-1993 - Change default fullDocumentLookup in ReactiveMongoTemplate.changeStream.
|
||||
* DATAMONGO-1992 - Add support for immutable objects.
|
||||
* DATAMONGO-1990 - Adapt build to changes in is-new-handling.
|
||||
* DATAMONGO-1988 - String ID not working for embeded objects.
|
||||
* DATAMONGO-1987 - Upgarde test infrastructure to MongoDB 4.0-rc0.
|
||||
* DATAMONGO-1986 - Aggregation MatchOperation fails to convert query.
|
||||
* DATAMONGO-1983 - Reference documentation does not include Transaction and sessions.
|
||||
* DATAMONGO-1982 - Release 2.1 RC1 (Lovelace).
|
||||
* DATAMONGO-1979 - Adding Support For Sorting in @Query Annotation and Creating an alias for value.
|
||||
* DATAMONGO-1919 - Decouple reactive mongo bits from blocking MongoClient.
|
||||
* DATAMONGO-1848 - Migrate to Document API-based Querydsl implementation.
|
||||
* DATAMONGO-1842 - Optimistic locking allows ReactiveMongoTemplate to modify immutable objects.
|
||||
* DATAMONGO-1827 - Allow document replacements via MongoCollection.findOneAndReplace(…).
|
||||
* DATAMONGO-1810 - Querydsl predicate using IN operator fails for DBRef.
|
||||
* DATAMONGO-1434 - Convert Exceptions into Spring Exception hierarchy when going through Querydsl.
|
||||
* DATAMONGO-1311 - Add an option to specify the cursor.batchSize() for repository methods returning streams.
|
||||
* DATAMONGO-1185 - Provide lifecycle events when using QueryDSL.
|
||||
* DATAMONGO-700 - Events not triggered during Querydsl repository usage.
|
||||
* DATAMONGO-595 - Expose new QueryDSL elemMatch feature.
|
||||
* DATAMONGO-362 - QueryDSL does not work with DBRef.
|
||||
|
||||
|
||||
Changes in version 2.0.8.RELEASE (2018-06-13)
|
||||
---------------------------------------------
|
||||
* DATAMONGO-2003 - MongoQueryCreator will not create query correctly when passing Pattern Object with options.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data MongoDB 2.0.8
|
||||
Spring Data MongoDB 2.0.9
|
||||
Copyright (c) [2010-2015] 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