Browse Source

DATAMONGO-1141 - Add support for $push $sort in Update.

Sorting update modifier added. Supports sorting arrays by document fields and element values.

Original pull request: #405.
pull/692/head
Pavel Vodrážka 9 years ago committed by Oliver Gierke
parent
commit
31d4434562
  1. 86
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java
  2. 82
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

86
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java

@ -28,6 +28,9 @@ import java.util.Set; @@ -28,6 +28,9 @@ import java.util.Set;
import org.bson.Document;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@ -42,6 +45,7 @@ import org.springframework.util.StringUtils; @@ -42,6 +45,7 @@ import org.springframework.util.StringUtils;
* @author Thomas Darimont
* @author Alexey Plotnik
* @author Mark Paluch
* @author Pavel Vodrazka
*/
public class Update {
@ -659,6 +663,58 @@ public class Update { @@ -659,6 +663,58 @@ public class Update {
}
}
/**
* Implementation of {@link Modifier} representing {@code $sort}.
*
* @author Pavel Vodrazka
* @since 1.10
*/
private static class SortModifier implements Modifier {
private final Object sort;
public SortModifier(Direction direction) {
this.sort = direction.isAscending() ? 1 : -1;
}
public SortModifier(Sort sort) {
this.sort = createDBObject(sort);
}
private Document createDBObject(Sort sort) {
Document obj = new Document();
for (Order order : sort) {
if (order.isIgnoreCase()) {
throw new IllegalArgumentException(String.format("Given sort contained an Order for %s with ignore case! "
+ "MongoDB does not support sorting ignoring case currently!", order.getProperty()));
}
obj.put(order.getProperty(), order.isAscending() ? 1 : -1);
}
return obj;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.Update.Modifier#getKey()
*/
@Override
public String getKey() {
return "$sort";
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.Update.Modifier#getValue()
*/
@Override
public Object getValue() {
return this.sort;
}
}
/**
* Builder for creating {@code $push} modifiers
*
@ -705,6 +761,36 @@ public class Update { @@ -705,6 +761,36 @@ public class Update {
return this;
}
/**
* Propagates {@code $sort} to {@code $push}. {@code $sort} requires the {@code $each} operator. Forces elements to
* be sorted by values in given {@literal direction}.
*
* @param direction must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public PushOperatorBuilder sort(Direction direction) {
Assert.notNull(direction, "Direction must not be 'null'.");
this.modifiers.addModifier(new SortModifier(direction));
return this;
}
/**
* Propagates {@code $sort} to {@code $push}. {@code $sort} requires the {@code $each} operator. Forces document
* elements to be sorted in given {@literal order}.
*
* @param order must not be {@literal null}.
* @return never {@literal null}.
* @since 1.10
*/
public PushOperatorBuilder sort(Sort order) {
Assert.notNull(order, "Order must not be 'null'.");
this.modifiers.addModifier(new SortModifier(order));
return this;
}
/**
* Forces values to be added at the given {@literal position}.
*

82
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

@ -41,6 +41,9 @@ import org.mockito.runners.MockitoJUnitRunner; @@ -41,6 +41,9 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.DocumentTestUtils;
@ -60,6 +63,7 @@ import com.mongodb.DBRef; @@ -60,6 +63,7 @@ import com.mongodb.DBRef;
* @author Christoph Strobl
* @author Thomas Darimont
* @author Mark Paluch
* @author Pavel Vodrazka
*/
@RunWith(MockitoJUnitRunner.class)
public class UpdateMapperUnitTests {
@ -398,13 +402,76 @@ public class UpdateMapperUnitTests { @@ -398,13 +402,76 @@ public class UpdateMapperUnitTests {
Document key = getAsDocument(push, "key");
assertThat(key.containsKey("$slice"), is(true));
assertThat(key.get("$slice"), is(5));
assertThat((Integer) key.get("$slice"), is(5));
assertThat(key.containsKey("$each"), is(true));
Document key2 = getAsDocument(push, "key-2");
assertThat(key2.containsKey("$slice"), is(true));
assertThat(key2.get("$slice"), is(-2));
assertThat((Integer) key2.get("$slice"), is(-2));
assertThat(key2.containsKey("$each"), is(true));
}
/**
* @see DATAMONGO-1141
*/
@Test
public void updatePushEachWithValueSortShouldRenderCorrectly() {
Update update = new Update().push("scores").sort(Direction.DESC).each(42, 23, 68);
Document mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
Document push = getAsDocument(mappedObject, "$push");
Document key = getAsDocument(push, "scores");
assertThat(key.containsKey("$sort"), is(true));
assertThat((Integer) key.get("$sort"), is(-1));
assertThat(key.containsKey("$each"), is(true));
}
/**
* @see DATAMONGO-1141
*/
@Test
public void updatePushEachWithDocumentSortShouldRenderCorrectly() {
Update update = new Update().push("names")
.sort(new Sort(new Order(Direction.ASC, "last"), new Order(Direction.ASC, "first")))
.each(Collections.emptyList());
Document mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
Document push = getAsDocument(mappedObject, "$push");
Document key = getAsDocument(push, "names");
assertThat(key.containsKey("$sort"), is(true));
assertThat((Document) key.get("$sort"), equalTo(new Document("last", 1).append("first", 1)));
assertThat(key.containsKey("$each"), is(true));
}
/**
* @see DATAMONGO-1141
*/
@Test
public void updatePushEachWithSortShouldRenderCorrectlyWhenUsingMultiplePush() {
Update update = new Update().push("authors").sort(Direction.ASC).each("Harry").push("chapters")
.sort(new Sort(Direction.ASC, "order")).each(Collections.emptyList());
Document mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
Document push = getAsDocument(mappedObject, "$push");
Document key1 = getAsDocument(push, "authors");
assertThat(key1.containsKey("$sort"), is(true));
assertThat((Integer) key1.get("$sort"), is(1));
assertThat(key1.containsKey("$each"), is(true));
Document key2 = getAsDocument(push, "chapters");
assertThat(key2.containsKey("$sort"), is(true));
assertThat((Document) key2.get("$sort"), equalTo(new Document("order", 1)));
assertThat(key2.containsKey("$each"), is(true));
}
@ -790,8 +857,7 @@ public class UpdateMapperUnitTests { @@ -790,8 +857,7 @@ public class UpdateMapperUnitTests {
@Test
public void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration() {
Map<Object, NestedDocument> map = Collections.singletonMap("jasnah",
new NestedDocument("kholin"));
Map<Object, NestedDocument> map = Collections.singletonMap("jasnah", new NestedDocument("kholin"));
Update update = new Update().set("concreteMap", map);
Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
@ -808,8 +874,8 @@ public class UpdateMapperUnitTests { @@ -808,8 +874,8 @@ public class UpdateMapperUnitTests {
@SuppressWarnings("unchecked")
public void mapsUpdateWithBothReadingAndWritingConverterRegistered() {
CustomConversions conversions = new CustomConversions(
Arrays.asList(ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
CustomConversions conversions = new CustomConversions(Arrays.asList(
ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
@ -953,8 +1019,8 @@ public class UpdateMapperUnitTests { @@ -953,8 +1019,8 @@ public class UpdateMapperUnitTests {
@SuppressWarnings("unchecked")
public void mappingShouldConsiderCustomConvertersForEnumMapKeys() {
CustomConversions conversions = new CustomConversions(
Arrays.asList(ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
CustomConversions conversions = new CustomConversions(Arrays.asList(
ClassWithEnum.AllocationToStringConverter.INSTANCE, ClassWithEnum.StringToAllocationConverter.INSTANCE));
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());

Loading…
Cancel
Save