DATAMONGO-2287 - Polishing.

Add new factory method for ArrayOperators that deals with a collection of values.

Original pull request: #760.
This commit is contained in:
Christoph Strobl
2019-06-27 10:22:31 +02:00
committed by Mark Paluch
parent a3ef9b5856
commit 8b406b23ff
2 changed files with 265 additions and 24 deletions

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -58,13 +59,25 @@ public class ArrayOperators {
return new ArrayOperatorFactory(expression);
}
/**
* Take the given {@link Collection values} {@link AggregationExpression}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link ArrayOperatorFactory}.
* @since 2.2
*/
public static ArrayOperatorFactory arrayOf(Collection<?> values) {
return new ArrayOperatorFactory(values);
}
/**
* @author Christoph Strobl
*/
public static class ArrayOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
private final @Nullable String fieldReference;
private final @Nullable AggregationExpression expression;
private final @Nullable Collection values;
/**
* Creates new {@link ArrayOperatorFactory} for given {@literal fieldReference}.
@@ -76,6 +89,7 @@ public class ArrayOperators {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
this.values = null;
}
/**
@@ -88,6 +102,21 @@ public class ArrayOperators {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
this.values = null;
}
/**
* Creates new {@link ArrayOperatorFactory} for given values.
*
* @param values must not be {@literal null}.
* @since 2.2
*/
public ArrayOperatorFactory(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
this.fieldReference = null;
this.expression = null;
this.values = values;
}
/**
@@ -128,7 +157,12 @@ public class ArrayOperators {
}
private ArrayElemAt createArrayElemAt() {
return usesFieldRef() ? ArrayElemAt.arrayOf(fieldReference) : ArrayElemAt.arrayOf(expression);
if (usesFieldRef()) {
return ArrayElemAt.arrayOf(fieldReference);
}
return usesExpression() ? ArrayElemAt.arrayOf(expression) : ArrayElemAt.arrayOf(values);
}
/**
@@ -158,7 +192,12 @@ public class ArrayOperators {
}
private ConcatArrays createConcatArrays() {
return usesFieldRef() ? ConcatArrays.arrayOf(fieldReference) : ConcatArrays.arrayOf(expression);
if (usesFieldRef()) {
return ConcatArrays.arrayOf(fieldReference);
}
return usesExpression() ? ConcatArrays.arrayOf(expression) : ConcatArrays.arrayOf(values);
}
/**
@@ -168,7 +207,13 @@ public class ArrayOperators {
* @return
*/
public AsBuilder filter() {
return Filter.filter(fieldReference);
if (usesFieldRef()) {
return Filter.filter(fieldReference);
}
Assert.state(values != null, "Values must not be null!");
return Filter.filter(new ArrayList<>(values));
}
/**
@@ -177,6 +222,9 @@ public class ArrayOperators {
* @return
*/
public IsArray isArray() {
Assert.state(values == null, "Does it make sense to call isArray on an array? Maybe just skip it?");
return usesFieldRef() ? IsArray.isArray(fieldReference) : IsArray.isArray(expression);
}
@@ -186,7 +234,12 @@ public class ArrayOperators {
* @return
*/
public Size length() {
return usesFieldRef() ? Size.lengthOfArray(fieldReference) : Size.lengthOfArray(expression);
if (usesFieldRef()) {
return Size.lengthOfArray(fieldReference);
}
return usesExpression() ? Size.lengthOfArray(expression) : Size.lengthOfArray(values);
}
/**
@@ -195,7 +248,12 @@ public class ArrayOperators {
* @return
*/
public Slice slice() {
return usesFieldRef() ? Slice.sliceArrayOf(fieldReference) : Slice.sliceArrayOf(expression);
if (usesFieldRef()) {
return Slice.sliceArrayOf(fieldReference);
}
return usesExpression() ? Slice.sliceArrayOf(expression) : Slice.sliceArrayOf(values);
}
/**
@@ -206,8 +264,13 @@ public class ArrayOperators {
* @return
*/
public IndexOfArray indexOf(Object value) {
return usesFieldRef() ? IndexOfArray.arrayOf(fieldReference).indexOf(value)
: IndexOfArray.arrayOf(expression).indexOf(value);
if (usesFieldRef()) {
return IndexOfArray.arrayOf(fieldReference).indexOf(value);
}
return usesExpression() ? IndexOfArray.arrayOf(expression).indexOf(value)
: IndexOfArray.arrayOf(values).indexOf(value);
}
/**
@@ -216,7 +279,13 @@ public class ArrayOperators {
* @return
*/
public ReverseArray reverse() {
return usesFieldRef() ? ReverseArray.reverseArrayOf(fieldReference) : ReverseArray.reverseArrayOf(expression);
if (usesFieldRef()) {
return ReverseArray.reverseArrayOf(fieldReference);
}
return usesExpression() ? ReverseArray.reverseArrayOf(expression)
: ReverseArray.reverseArrayOf(Collections.singletonList(values));
}
/**
@@ -254,7 +323,12 @@ public class ArrayOperators {
* @return
*/
public Zip zipWith(Object... arrays) {
return (usesFieldRef() ? Zip.arrayOf(fieldReference) : Zip.arrayOf(expression)).zip(arrays);
if (usesFieldRef()) {
return Zip.arrayOf(fieldReference).zip(arrays);
}
return (usesExpression() ? Zip.arrayOf(expression) : Zip.arrayOf(values)).zip(arrays);
}
/**
@@ -265,7 +339,12 @@ public class ArrayOperators {
* @return
*/
public In containsValue(Object value) {
return (usesFieldRef() ? In.arrayOf(fieldReference) : In.arrayOf(expression)).containsValue(value);
if (usesFieldRef()) {
return In.arrayOf(fieldReference).containsValue(value);
}
return (usesExpression() ? In.arrayOf(expression) : In.arrayOf(values)).containsValue(value);
}
/**
@@ -277,8 +356,11 @@ public class ArrayOperators {
*/
public ArrayToObject toObject() {
return usesFieldRef() ? ArrayToObject.arrayValueOfToObject(fieldReference)
: ArrayToObject.arrayValueOfToObject(expression);
if (usesFieldRef()) {
return ArrayToObject.arrayValueOfToObject(fieldReference);
}
return usesExpression() ? ArrayToObject.arrayValueOfToObject(expression) : ArrayToObject.arrayToObject(values);
}
/**
@@ -295,9 +377,20 @@ public class ArrayOperators {
Reduce startingWith(Object initialValue);
}
/**
* @return {@literal true} if {@link #fieldReference} is not {@literal null}.
*/
private boolean usesFieldRef() {
return fieldReference != null;
}
/**
* @return {@literal true} if {@link #expression} is not {@literal null}.
* @since 2.2
*/
private boolean usesExpression() {
return expression != null;
}
}
/**
@@ -340,6 +433,19 @@ public class ArrayOperators {
return new ArrayElemAt(Collections.singletonList(expression));
}
/**
* Creates new {@link ArrayElemAt}.
*
* @param values The array members. Must not be {@literal null}.
* @return new instance of {@link ArrayElemAt}.
* @since 2.2
*/
public static ArrayElemAt arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
return new ArrayElemAt(Collections.singletonList(values));
}
public ArrayElemAt elementAt(int index) {
return new ArrayElemAt(append(index));
}
@@ -397,6 +503,19 @@ public class ArrayOperators {
return new ConcatArrays(Collections.singletonList(expression));
}
/**
* Creates new {@link ConcatArrays}.
*
* @param values The array members. Must not be {@literal null}.
* @return new instance of {@link ConcatArrays}.
* @since 2.2
*/
public static ConcatArrays arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
return new ConcatArrays(Collections.singletonList(values));
}
public ConcatArrays concat(String arrayFieldReference) {
Assert.notNull(arrayFieldReference, "ArrayFieldReference must not be null!");
@@ -741,6 +860,19 @@ public class ArrayOperators {
Assert.notNull(expression, "Expression must not be null!");
return new Size(expression);
}
/**
* Creates new {@link Size}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link Size}.
* @since 2.2
*/
public static Size lengthOfArray(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
return new Size(Collections.singletonList(values));
}
}
/**
@@ -783,6 +915,19 @@ public class ArrayOperators {
return new Slice(Collections.singletonList(expression));
}
/**
* Creates new {@link Slice}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link Slice}.
* @since 2.2
*/
public static Slice sliceArrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
return new Slice(Collections.singletonList(values));
}
public Slice itemCount(int nrElements) {
return new Slice(append(nrElements));
}
@@ -853,6 +998,19 @@ public class ArrayOperators {
return new IndexOfArrayBuilder(expression);
}
/**
* Start creating new {@link IndexOfArray}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link IndexOfArray}.
* @since 2.2
*/
public static IndexOfArrayBuilder arrayOf(Collection<?> values) {
Assert.notNull(values, "Values must not be null!");
return new IndexOfArrayBuilder(values);
}
public IndexOfArray within(Range<Long> range) {
return new IndexOfArray(append(AggregationUtils.toRangeValues(range)));
}
@@ -1007,6 +1165,17 @@ public class ArrayOperators {
public static ReverseArray reverseArrayOf(AggregationExpression expression) {
return new ReverseArray(expression);
}
/**
* Creates new {@link ReverseArray}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link ReverseArray}.
* @since 2.2
*/
public static ReverseArray reverseArrayOf(Collection<?> values) {
return new ReverseArray(values);
}
}
/**
@@ -1359,6 +1528,19 @@ public class ArrayOperators {
return new ZipBuilder(expression);
}
/**
* Start creating new {@link Zip}.
*
* @param values must not be {@literal null}.
* @return new instance of {@link Zip}.
* @since 2.2
*/
public static ZipBuilder arrayOf(Collection<?> values) {
Assert.notNull(values, "Expression must not be null!");
return new ZipBuilder(values);
}
/**
* Create new {@link Zip} and set the {@code useLongestLength} property to {@literal true}.
*
@@ -1483,7 +1665,7 @@ public class ArrayOperators {
* @param expression must not be {@literal null}.
* @return
*/
public static InBuilder arrayOf(final AggregationExpression expression) {
public static InBuilder arrayOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
@@ -1501,13 +1683,13 @@ public class ArrayOperators {
/**
* Support for Aggregation In Search an Element in List of Objects to Filter Start creating {@link In}.
*
* @author Shashank Sharma
* @param elementList must not be {@literal null}.
* @return
* @param values must not be {@literal null}.
* @return new instance of {@link InBuilder}.
* @since 2.2
*/
public static InBuilder arrayOf(final List<Object> elementList) {
public static InBuilder arrayOf(Collection<?> values) {
Assert.notNull(elementList, "Elements must not be null!");
Assert.notNull(values, "Values must not be null!");
return new InBuilder() {
@@ -1515,7 +1697,7 @@ public class ArrayOperators {
public In containsValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new In(Arrays.asList(value, elementList));
return new In(Arrays.asList(value, values));
}
};
}

View File

@@ -34,6 +34,8 @@ import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToO
*/
public class ArrayOperatorsUnitTests {
static final List<Object> VALUE_LIST = Arrays.asList(1, "2", new Document("_id", 3));
static final String VALUE_LIST_STRING = "[1, \"2\", { \"_id\" : 3 }]";
static final String EXPRESSION_STRING = "{ \"$stablemaster\" : \"burrich\" }";
static final Document EXPRESSION_DOC = Document.parse(EXPRESSION_STRING);
static final AggregationExpression EXPRESSION = context -> EXPRESSION_DOC;
@@ -64,10 +66,67 @@ public class ArrayOperatorsUnitTests {
}
@Test // DATAMONGO-2287
public void inArrayAggregationWithArgumentList() {
public void arrayElementAtWithValueList() {
assertThat(ArrayOperators.In.arrayOf(Arrays.asList("Shashank", "Sharma")).containsValue("$userName")
assertThat(ArrayOperators.arrayOf(VALUE_LIST).elementAt(1).toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $arrayElemAt: [ " + VALUE_LIST_STRING + ", 1] } "));
}
@Test // DATAMONGO-2287
public void concatWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).concat("field").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $concatArrays: [ " + VALUE_LIST_STRING + ", \"$field\"] } "));
}
@Test // DATAMONGO-2287
public void filterWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).filter().as("var").by(new Document())
.toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ \"$in\" : [\"$userName\", [\"Shashank\", \"Sharma\"]] }"));
.isEqualTo(Document
.parse("{ $filter: { \"input\" : " + VALUE_LIST_STRING + ", \"as\" : \"var\", \"cond\" : {} } } "));
}
@Test // DATAMONGO-2287
public void lengthWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).length().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $size: [ " + VALUE_LIST_STRING + "] } "));
}
@Test // DATAMONGO-2287
public void sliceWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).slice().itemCount(3).toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $slice: [ " + VALUE_LIST_STRING + ", 3] } "));
}
@Test // DATAMONGO-2287
public void indexOfWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).indexOf("s1p").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $indexOfArray: [ " + VALUE_LIST_STRING + ", \"s1p\"] } "));
}
@Test // DATAMONGO-2287
public void reverseWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).reverse().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $reverseArray: [ " + VALUE_LIST_STRING + "] } "));
}
@Test // DATAMONGO-2287
public void zipWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).zipWith("field").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ $zip: { \"inputs\": [" + VALUE_LIST_STRING + ", \"$field\"]} } "));
}
@Test // DATAMONGO-2287
public void inWithValueList() {
assertThat(ArrayOperators.arrayOf(VALUE_LIST).containsValue("$userName").toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo(Document.parse("{ \"$in\" : [\"$userName\", " + VALUE_LIST_STRING + "] }"));
}
}