Skip to content

Commit e399e26

Browse files
DATAMONGO-941 - Add support for $min to Update.
Added new methods to Update. Added bunch of unit tests (some failing) - have to get them running.
1 parent 0036fd6 commit e399e26

File tree

5 files changed

+341
-1
lines changed

5 files changed

+341
-1
lines changed

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.Collection;
2222
import java.util.Collections;
23+
import java.util.Date;
2324
import java.util.HashSet;
2425
import java.util.LinkedHashMap;
2526
import java.util.List;
@@ -336,6 +337,38 @@ public BitwiseOperatorBuilder bitwise(String key) {
336337
return new BitwiseOperatorBuilder(this, key);
337338
}
338339

340+
/**
341+
* Update given key to value if the given value is less than the current value of the field.
342+
*
343+
* @see http://docs.mongodb.org/manual/reference/operator/update/min/
344+
* @param key must not be {@literal null}.
345+
* @param value must not be {@literal null}.
346+
* @return
347+
* @since 1.7
348+
*/
349+
public Update min(String key, Number value) {
350+
351+
Assert.notNull(value, "Value for min operation must not be 'null'.");
352+
addMultiFieldOperation("$min", key, value);
353+
return this;
354+
}
355+
356+
/**
357+
* Update given key to value if the given date is before than the current date value of the field.
358+
*
359+
* @see http://docs.mongodb.org/manual/reference/operator/update/min/
360+
* @param key must not be {@literal null}.
361+
* @param value must not be {@literal null}.
362+
* @return
363+
* @since 1.7
364+
*/
365+
public Update min(String key, Date value) {
366+
367+
Assert.notNull(value, "Value for min operation must not be 'null'.");
368+
addMultiFieldOperation("$min", key, value);
369+
return this;
370+
}
371+
339372
public DBObject getUpdateObject() {
340373

341374
DBObject dbo = new BasicDBObject();

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/DBObjectTestUtils.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,70 @@
1818
import static org.hamcrest.Matchers.*;
1919
import static org.junit.Assert.*;
2020

21+
import java.util.Arrays;
22+
import java.util.Iterator;
23+
import java.util.NoSuchElementException;
24+
2125
import com.mongodb.BasicDBList;
2226
import com.mongodb.DBObject;
2327

2428
/**
2529
* Helper classes to ease assertions on {@link DBObject}s.
2630
*
2731
* @author Oliver Gierke
32+
* @autor Christoph Strobl
2833
*/
2934
public abstract class DBObjectTestUtils {
3035

3136
private DBObjectTestUtils() {
3237

3338
}
3439

40+
/**
41+
* Extracts value for a given path within the dbo. Indexes in arrays can be addressed via {@code []}.
42+
*
43+
* @param source
44+
* @param path
45+
* @return
46+
*/
47+
@SuppressWarnings("unchecked")
48+
public static <T> T getValue(DBObject source, String path) {
49+
50+
String[] fragments = path.split("\\.");
51+
if (fragments.length == 1) {
52+
return (T) source.get(path);
53+
}
54+
55+
Iterator<String> it = Arrays.asList(fragments).iterator();
56+
57+
DBObject dbo = source;
58+
while (it.hasNext()) {
59+
60+
String key = it.next();
61+
62+
if (key.startsWith("[")) {
63+
String indexNumber = key.substring(1, key.indexOf("]"));
64+
dbo = getAsDBObject((BasicDBList) dbo, Integer.parseInt(indexNumber));
65+
} else {
66+
67+
if (!it.hasNext()) {
68+
return (T) dbo.get(key);
69+
}
70+
71+
Object value = dbo.get(key);
72+
if (value instanceof DBObject) {
73+
dbo = (DBObject) value;
74+
} else {
75+
if (it.next().startsWith("$")) {
76+
return (T) value;
77+
}
78+
}
79+
}
80+
}
81+
82+
throw new NoSuchElementException(String.format("Unable to find '%s' in %s.", path, source));
83+
}
84+
3585
/**
3686
* Expects the field with the given key to be not {@literal null} and a {@link DBObject} in turn and returns it.
3787
*

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@
2323
import static org.springframework.data.mongodb.core.query.Query.*;
2424
import static org.springframework.data.mongodb.core.query.Update.*;
2525

26+
import java.math.BigDecimal;
2627
import java.math.BigInteger;
2728
import java.util.ArrayList;
2829
import java.util.Arrays;
30+
import java.util.Calendar;
2931
import java.util.Collections;
3032
import java.util.Date;
3133
import java.util.HashMap;
3234
import java.util.HashSet;
3335
import java.util.List;
36+
import java.util.Locale;
3437
import java.util.Map;
3538

3639
import org.bson.types.ObjectId;
@@ -2751,6 +2754,65 @@ public void insertsAndRemovesBasicDbObjectCorrectly() {
27512754
assertThat(template.findAll(DBObject.class, "collection"), hasSize(0));
27522755
}
27532756

2757+
/**
2758+
* @see DATAMONGO-941
2759+
*/
2760+
@Test
2761+
public void updatesDateValueCorrectlyWhenUsingMinOperator() {
2762+
2763+
Calendar cal = Calendar.getInstance(Locale.US);
2764+
cal.set(2013, 10, 13, 0, 0, 0);
2765+
2766+
TypeWithDate twd = new TypeWithDate();
2767+
twd.date = new Date();
2768+
template.save(twd);
2769+
template.updateFirst(query(where("id").is(twd.id)), new Update().min("date", cal.getTime()), TypeWithDate.class);
2770+
2771+
TypeWithDate loaded = template.find(query(where("id").is(twd.id)), TypeWithDate.class).get(0);
2772+
assertThat(loaded.date, equalTo(cal.getTime()));
2773+
}
2774+
2775+
/**
2776+
* @see DATAMONGO-941
2777+
*/
2778+
@Test
2779+
public void updatesNumericValueCorrectlyWhenUsingMinOperator() {
2780+
2781+
TypeWithNumbers twn = new TypeWithNumbers();
2782+
twn.byteVal = 100;
2783+
twn.doubleVal = 200D;
2784+
twn.floatVal = 300F;
2785+
twn.intVal = 400;
2786+
twn.longVal = 500L;
2787+
2788+
// Note that $min operator is not supported for BigInteger and BigDecimal types.
2789+
// twn.bigIntegerVal = new BigInteger("600");
2790+
// twn.bigDeciamVal = new BigDecimal("700.0");
2791+
2792+
template.save(twn);
2793+
2794+
byte byteVal = 90;
2795+
Update update = new Update()//
2796+
.min("byteVal", byteVal) //
2797+
.min("doubleVal", 190D) //
2798+
.min("floatVal", 290F) //
2799+
.min("intVal", 390) //
2800+
.min("longVal", 490) //
2801+
// Not supported
2802+
// .min("bigIntegerVal", new BigInteger("590")) //
2803+
// .min("bigDeciamVal", new BigDecimal("690")) //
2804+
;
2805+
2806+
template.updateFirst(query(where("id").is(twn.id)), update, TypeWithNumbers.class);
2807+
2808+
TypeWithNumbers loaded = template.find(query(where("id").is(twn.id)), TypeWithNumbers.class).get(0);
2809+
assertThat(loaded.byteVal, equalTo(byteVal));
2810+
assertThat(loaded.doubleVal, equalTo(190D));
2811+
assertThat(loaded.floatVal, equalTo(290F));
2812+
assertThat(loaded.intVal, equalTo(390));
2813+
assertThat(loaded.longVal, equalTo(490L));
2814+
}
2815+
27542816
static class DoucmentWithNamedIdField {
27552817

27562818
@Id String someIdKey;
@@ -3018,4 +3080,16 @@ static class SomeMessage {
30183080
@org.springframework.data.mongodb.core.mapping.DBRef SomeContent dbrefContent;
30193081
SomeContent normalContent;
30203082
}
3083+
3084+
static class TypeWithNumbers {
3085+
3086+
@Id String id;
3087+
Integer intVal;
3088+
Float floatVal;
3089+
Long longVal;
3090+
Double doubleVal;
3091+
BigDecimal bigDeciamVal;
3092+
BigInteger bigIntegerVal;
3093+
Byte byteVal;
3094+
}
30213095
}

0 commit comments

Comments
 (0)