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:
Pavel Vodrážka
2016-11-02 18:13:24 +01:00
committed by Oliver Gierke
parent 40da4701de
commit 7f39c42eb7
2 changed files with 153 additions and 0 deletions

View File

@@ -27,6 +27,9 @@ import java.util.Map;
import java.util.Set;
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;
@@ -44,6 +47,7 @@ import com.mongodb.DBObject;
* @author Thomas Darimont
* @author Alexey Plotnik
* @author Mark Paluch
* @author Pavel Vodrazka
*/
public class Update {
@@ -660,6 +664,58 @@ public class Update {
return this.count;
}
}
/**
* 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 DBObject createDBObject(Sort sort) {
DBObject obj = new BasicDBObject();
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
@@ -707,6 +763,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}.
*

View File

@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.core.convert;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.collection.IsMapContaining.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -42,6 +43,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.DBObjectTestUtils;
@@ -68,6 +72,7 @@ import com.mongodb.DBRef;
* @author Christoph Strobl
* @author Thomas Darimont
* @author Mark Paluch
* @author Pavel Vodrazka
*/
@RunWith(MockitoJUnitRunner.class)
public class UpdateMapperUnitTests {
@@ -416,6 +421,68 @@ public class UpdateMapperUnitTests {
assertThat(key2.containsField("$each"), is(true));
}
/**
* @see DATAMONGO-1141
*/
@Test
public void updatePushEachWithValueSortShouldRenderCorrectly() {
Update update = new Update().push("scores").sort(Direction.DESC).each(42, 23, 68);
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
DBObject push = getAsDBObject(mappedObject, "$push");
DBObject key = getAsDBObject(push, "scores");
assertThat(key.containsField("$sort"), is(true));
assertThat((Integer) key.get("$sort"), is(-1));
assertThat(key.containsField("$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());
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
DBObject push = getAsDBObject(mappedObject, "$push");
DBObject key = getAsDBObject(push, "names");
assertThat(key.containsField("$sort"), is(true));
assertThat((DBObject) key.get("$sort"), equalTo(new BasicDBObjectBuilder().add("last", 1).add("first", 1).get()));
assertThat(key.containsField("$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());
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class));
DBObject push = getAsDBObject(mappedObject, "$push");
DBObject key1 = getAsDBObject(push, "authors");
assertThat(key1.containsField("$sort"), is(true));
assertThat((Integer) key1.get("$sort"), is(1));
assertThat(key1.containsField("$each"), is(true));
DBObject key2 = getAsDBObject(push, "chapters");
assertThat(key2.containsField("$sort"), is(true));
assertThat((DBObject) key2.get("$sort"), equalTo(new BasicDBObjectBuilder().add("order", 1).get()));
assertThat(key2.containsField("$each"), is(true));
}
/**
* @see DATAMONGO-410
*/