diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java index 5865df61a4..9711d36db0 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java @@ -163,7 +163,8 @@ public Update push(String key, Object value) { /** * Update using {@code $push} modifier.
- * Allows creation of {@code $push} command for single or multiple (using {@code $each}) values. + * Allows creation of {@code $push} command for single or multiple (using {@code $each}) values as well as using + * {@code $position}. * * @see http://docs.mongodb.org/manual/reference/operator/update/push/ * @see http://docs.mongodb.org/manual/reference/operator/update/each/ @@ -577,6 +578,31 @@ public boolean equals(Object that) { } } + /** + * {@link Modifier} implementation used to propagate {@code $position}. + * + * @author Christoph Strobl + * @since 1.7 + */ + private static class PositionModifier implements Modifier { + + private final int position; + + public PositionModifier(int position) { + this.position = position; + } + + @Override + public String getKey() { + return "$position"; + } + + @Override + public Object getValue() { + return position; + } + } + /** * Builder for creating {@code $push} modifiers * @@ -605,6 +631,42 @@ public Update each(Object... values) { return Update.this.push(key, this.modifiers); } + /** + * Forces values to be added at the given {@literal position}. + * + * @param position needs to be greater than or equal to zero. + * @return + * @since 1.7 + */ + public PushOperatorBuilder atPosition(int position) { + + if (position < 0) { + throw new IllegalArgumentException("Position must be greater than or equal to zero."); + } + + this.modifiers.addModifier(new PositionModifier(position)); + + return this; + } + + /** + * Forces values to be added at given {@literal position}. + * + * @param position can be {@literal null} which will be appended at the last position. + * @return + * @since 1.7 + */ + public PushOperatorBuilder atPosition(Position position) { + + if (position == null || Position.LAST.equals(position)) { + return this; + } + + this.modifiers.addModifier(new PositionModifier(0)); + + return this; + } + /** * Propagates {@link #value(Object)} to {@code $push} * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java index 94af26d3d0..ffe1262050 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java @@ -44,6 +44,7 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.data.mongodb.core.query.Update.Position; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; @@ -293,6 +294,76 @@ public void testUpdateShouldAllowMultiplePushEachForDifferentFields() { assertThat(getAsDBObject(push, "type").containsField("$each"), is(true)); } + /** + * @see DATAMONGO-943 + */ + @Test + public void updatePushEachAtPositionWorksCorrectlyWhenGivenPositiveIndexParameter() { + + Update update = new Update().push("key").atPosition(2).each(Arrays.asList("Arya", "Arry", "Weasel")); + + DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class)); + + DBObject push = getAsDBObject(mappedObject, "$push"); + DBObject key = getAsDBObject(push, "key"); + + assertThat(key.containsField("$position"), is(true)); + assertThat((Integer) key.get("$position"), is(2)); + assertThat(getAsDBObject(push, "key").containsField("$each"), is(true)); + } + + /** + * @see DATAMONGO-943 + */ + @Test + public void updatePushEachAtPositionWorksCorrectlyWhenGivenPositionFirst() { + + Update update = new Update().push("key").atPosition(Position.FIRST).each(Arrays.asList("Arya", "Arry", "Weasel")); + + DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class)); + + DBObject push = getAsDBObject(mappedObject, "$push"); + DBObject key = getAsDBObject(push, "key"); + + assertThat(key.containsField("$position"), is(true)); + assertThat((Integer) key.get("$position"), is(0)); + assertThat(getAsDBObject(push, "key").containsField("$each"), is(true)); + } + + /** + * @see DATAMONGO-943 + */ + @Test + public void updatePushEachAtPositionWorksCorrectlyWhenGivenPositionLast() { + + Update update = new Update().push("key").atPosition(Position.LAST).each(Arrays.asList("Arya", "Arry", "Weasel")); + + DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class)); + + DBObject push = getAsDBObject(mappedObject, "$push"); + DBObject key = getAsDBObject(push, "key"); + + assertThat(key.containsField("$position"), is(false)); + assertThat(getAsDBObject(push, "key").containsField("$each"), is(true)); + } + + /** + * @see DATAMONGO-943 + */ + @Test + public void updatePushEachAtPositionWorksCorrectlyWhenGivenPositionNull() { + + Update update = new Update().push("key").atPosition(null).each(Arrays.asList("Arya", "Arry", "Weasel")); + + DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(), context.getPersistentEntity(Object.class)); + + DBObject push = getAsDBObject(mappedObject, "$push"); + DBObject key = getAsDBObject(push, "key"); + + assertThat(key.containsField("$position"), is(false)); + assertThat(getAsDBObject(push, "key").containsField("$each"), is(true)); + } + /** * @see DATAMONGO-410 */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java index 57bc186e01..9f7429dfa8 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java @@ -476,4 +476,12 @@ public void getUpdateObjectShouldReturnCorrectRepresentationForBitwiseXor() { assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$bit", new BasicDBObject("key", new BasicDBObject("xor", 10L))).get())); } + + /** + * @see DATAMONGO-943 + */ + @Test(expected = IllegalArgumentException.class) + public void pushShouldThrowExceptionWhenGivenNegativePosition() { + new Update().push("foo").atPosition(-1).each("booh"); + } }