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.
This commit is contained in:
committed by
Oliver Gierke
parent
f5a339bfe4
commit
31d4434562
@@ -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;
|
||||
* @author Thomas Darimont
|
||||
* @author Alexey Plotnik
|
||||
* @author Mark Paluch
|
||||
* @author Pavel Vodrazka
|
||||
*/
|
||||
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 {
|
||||
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}.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
* @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 {
|
||||
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 {
|
||||
@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 {
|
||||
@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 {
|
||||
@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());
|
||||
|
||||
Reference in New Issue
Block a user