Browse Source

DATAMONGO-1564 - Split up AggregationExpressions.

Refactored to multiple smaller Aggregation Operator classes reflecting the grouping (array operators, string operators,…) predefined by MongoDB.

Original pull request: #429.
pull/692/head
Christoph Strobl 9 years ago committed by Mark Paluch
parent
commit
2c29f204c3
  1. 149
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AbstractAggregationExpression.java
  2. 641
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AccumulatorOperators.java
  3. 8655
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpressions.java
  4. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRenderer.java
  5. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationSpELExpression.java
  6. 1421
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java
  7. 1515
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
  8. 353
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/BooleanOperators.java
  9. 879
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java
  10. 973
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ConditionalOperators.java
  11. 67
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DataTypeOperators.java
  12. 838
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java
  13. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java
  14. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java
  15. 96
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/LiteralOperators.java
  16. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/NestedDelegatingExpressionAggregationOperationContext.java
  17. 50
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java
  18. 666
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperators.java
  19. 1089
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java
  20. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContext.java
  21. 389
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/VariableOperators.java
  22. 16
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java
  23. 11
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java
  24. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/BucketOperationUnitTests.java
  25. 5
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/CondExpressionUnitTests.java
  26. 2
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java
  27. 5
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GraphLookupOperationUnitTests.java
  28. 35
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java
  29. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java
  30. 1
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContextUnitTests.java

149
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AbstractAggregationExpression.java

@ -0,0 +1,149 @@ @@ -0,0 +1,149 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import org.bson.Document;
import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
* @since 1.10
*/
abstract class AbstractAggregationExpression implements AggregationExpression {
private final Object value;
protected AbstractAggregationExpression(Object value) {
this.value = value;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
return toDocument(this.value, context);
}
public Document toDocument(Object value, AggregationOperationContext context) {
Object valueToUse;
if (value instanceof List) {
List<Object> arguments = (List<Object>) value;
List<Object> args = new ArrayList<Object>(arguments.size());
for (Object val : arguments) {
args.add(unpack(val, context));
}
valueToUse = args;
} else if (value instanceof java.util.Map) {
Document dbo = new Document();
for (java.util.Map.Entry<String, Object> entry : ((java.util.Map<String, Object>) value).entrySet()) {
dbo.put(entry.getKey(), unpack(entry.getValue(), context));
}
valueToUse = dbo;
} else {
valueToUse = unpack(value, context);
}
return new Document(getMongoMethod(), valueToUse);
}
protected static List<Field> asFields(String... fieldRefs) {
if (ObjectUtils.isEmpty(fieldRefs)) {
return Collections.emptyList();
}
return Fields.fields(fieldRefs).asList();
}
private Object unpack(Object value, AggregationOperationContext context) {
if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDocument(context);
}
if (value instanceof Field) {
return context.getReference((Field) value).toString();
}
if (value instanceof List) {
List<Object> sourceList = (List<Object>) value;
List<Object> mappedList = new ArrayList<Object>(sourceList.size());
for (Object item : sourceList) {
mappedList.add(unpack(item, context));
}
return mappedList;
}
return value;
}
protected List<Object> append(Object value) {
if (this.value instanceof List) {
List<Object> clone = new ArrayList<Object>((List) this.value);
if (value instanceof List) {
for (Object val : (List) value) {
clone.add(val);
}
} else {
clone.add(value);
}
return clone;
}
return Arrays.asList(this.value, value);
}
protected java.util.Map<String, Object> append(String key, Object value) {
if (!(this.value instanceof java.util.Map)) {
throw new IllegalArgumentException("o_O");
}
java.util.Map<String, Object> clone = new LinkedHashMap<String, Object>(
(java.util.Map<String, Object>) this.value);
clone.put(key, value);
return clone;
}
protected List<Object> values() {
if (value instanceof List) {
return new ArrayList<Object>((List) value);
}
if (value instanceof java.util.Map) {
return new ArrayList<Object>(((java.util.Map) value).values());
}
return new ArrayList<Object>(Arrays.asList(value));
}
protected abstract String getMongoMethod();
}

641
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AccumulatorOperators.java

@ -0,0 +1,641 @@ @@ -0,0 +1,641 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.util.Assert;
/**
* Gateway to {@literal accumulator} aggregation operations.
*
* @author Christoph Strobl
* @since 1.10
* @soundtrack Rage Against The Machine - Killing In The Name
*/
public class AccumulatorOperators {
/**
* Take the numeric value referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static AccumulatorOperatorFactory valueOf(String fieldReference) {
return new AccumulatorOperatorFactory(fieldReference);
}
/**
* Take the numeric value referenced resulting from given {@link AggregationExpression}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static AccumulatorOperatorFactory valueOf(AggregationExpression expression) {
return new AccumulatorOperatorFactory(expression);
}
/**
* @author Christoph Strobl
*/
public static class AccumulatorOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link AccumulatorOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public AccumulatorOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link ArrayOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public AccumulatorOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and calculates and
* returns the sum.
*
* @return
*/
public Sum sum() {
return usesFieldRef() ? Sum.sumOf(fieldReference) : Sum.sumOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and returns the
* average value.
*
* @return
*/
public Avg avg() {
return usesFieldRef() ? Avg.avgOf(fieldReference) : Avg.avgOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and returns the
* maximum value.
*
* @return
*/
public Max max() {
return usesFieldRef() ? Max.maxOf(fieldReference) : Max.maxOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and returns the
* minimum value.
*
* @return
*/
public Min min() {
return usesFieldRef() ? Min.minOf(fieldReference) : Min.minOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and calculates the
* population standard deviation of the input values.
*
* @return
*/
public StdDevPop stdDevPop() {
return usesFieldRef() ? StdDevPop.stdDevPopOf(fieldReference) : StdDevPop.stdDevPopOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes the associated numeric value expression and calculates the
* sample standard deviation of the input values.
*
* @return
*/
public StdDevSamp stdDevSamp() {
return usesFieldRef() ? StdDevSamp.stdDevSampOf(fieldReference) : StdDevSamp.stdDevSampOf(expression);
}
private boolean usesFieldRef() {
return fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $sum}.
*
* @author Christoph Strobl
*/
public static class Sum extends AbstractAggregationExpression {
private Sum(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$sum";
}
/**
* Creates new {@link Sum}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Sum sumOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Sum(asFields(fieldReference));
}
/**
* Creates new {@link Sum}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Sum sumOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Sum(Collections.singletonList(expression));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Sum and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Sum(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public Sum and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Sum(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
/**
* {@link AggregationExpression} for {@code $avg}.
*
* @author Christoph Strobl
*/
public static class Avg extends AbstractAggregationExpression {
private Avg(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$avg";
}
/**
* Creates new {@link Avg}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Avg avgOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Avg(asFields(fieldReference));
}
/**
* Creates new {@link Avg}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Avg avgOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Avg(Collections.singletonList(expression));
}
/**
* Creates new {@link Avg} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Avg and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Avg(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Avg} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public Avg and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Avg(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
/**
* {@link AggregationExpression} for {@code $max}.
*
* @author Christoph Strobl
*/
public static class Max extends AbstractAggregationExpression {
private Max(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$max";
}
/**
* Creates new {@link Max}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Max maxOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Max(asFields(fieldReference));
}
/**
* Creates new {@link Max}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Max maxOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Max(Collections.singletonList(expression));
}
/**
* Creates new {@link Max} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Max and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Max(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Max} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public Max and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Max(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
/**
* {@link AggregationExpression} for {@code $min}.
*
* @author Christoph Strobl
*/
public static class Min extends AbstractAggregationExpression {
private Min(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$min";
}
/**
* Creates new {@link Min}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Min minOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Min(asFields(fieldReference));
}
/**
* Creates new {@link Min}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Min minOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Min(Collections.singletonList(expression));
}
/**
* Creates new {@link Min} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Min and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Min(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Min} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public Min and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Min(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
/**
* {@link AggregationExpression} for {@code $stdDevPop}.
*
* @author Christoph Strobl
*/
public static class StdDevPop extends AbstractAggregationExpression {
private StdDevPop(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$stdDevPop";
}
/**
* Creates new {@link StdDevPop}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static StdDevPop stdDevPopOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new StdDevPop(asFields(fieldReference));
}
/**
* Creates new {@link StdDevPop} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public static StdDevPop stdDevPopOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new StdDevPop(Collections.singletonList(expression));
}
/**
* Creates new {@link StdDevPop} with all previously added arguments appending the given one. <br/>
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public StdDevPop and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new StdDevPop(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public StdDevPop and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new StdDevPop(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
/**
* {@link AggregationExpression} for {@code $stdDevSamp}.
*
* @author Christoph Strobl
*/
public static class StdDevSamp extends AbstractAggregationExpression {
private StdDevSamp(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$stdDevSamp";
}
/**
* Creates new {@link StdDevSamp}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static StdDevSamp stdDevSampOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new StdDevSamp(asFields(fieldReference));
}
/**
* Creates new {@link StdDevSamp}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static StdDevSamp stdDevSampOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new StdDevSamp(Collections.singletonList(expression));
}
/**
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public StdDevSamp and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new StdDevSamp(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link StdDevSamp} with all previously added arguments appending the given one. <br />
* <strong>NOTE:</strong> Only possible in {@code $project} stage.
*
* @param expression must not be {@literal null}.
* @return
*/
public StdDevSamp and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new StdDevSamp(append(expression));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.AbstractAggregationExpression#toDocument(java.lang.Object, org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(Object value, AggregationOperationContext context) {
if (value instanceof List) {
if (((List) value).size() == 1) {
return super.toDocument(((List<Object>) value).iterator().next(), context);
}
}
return super.toDocument(value, context);
}
}
}

8655
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpressions.java

File diff suppressed because it is too large Load Diff

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRenderer.java

@ -26,7 +26,7 @@ import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField @@ -26,7 +26,7 @@ import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
/**
* Rendering support for {@link AggregationOperation} into a {@link List} of {@link com.mongodb.Document}.
* Rendering support for {@link AggregationOperation} into a {@link List} of {@link org.bson.Document}.
*
* @author Mark Paluch
* @author Christoph Strobl

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationSpELExpression.java

@ -64,7 +64,7 @@ public class AggregationSpELExpression implements AggregationExpression { @@ -64,7 +64,7 @@ public class AggregationSpELExpression implements AggregationExpression {
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDbObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {

1421
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java

File diff suppressed because it is too large Load Diff

1515
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java

File diff suppressed because it is too large Load Diff

353
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/BooleanOperators.java

@ -0,0 +1,353 @@ @@ -0,0 +1,353 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.util.Assert;
/**
* Gateway to {@literal boolean expressions} that evaluate their argument expressions as booleans and return a boolean
* as the result.
*
* @author Christoph Strobl
* @since 1.10
*/
public class BooleanOperators {
/**
* Take the array referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static BooleanOperatorFactory valueOf(String fieldReference) {
return new BooleanOperatorFactory(fieldReference);
}
/**
* Take the value resulting of the given {@link AggregationExpression}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static BooleanOperatorFactory valueOf(AggregationExpression fieldReference) {
return new BooleanOperatorFactory(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that evaluates the boolean value of the referenced field and returns the
* opposite boolean value.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Not not(String fieldReference) {
return Not.not(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that evaluates the boolean value of {@link AggregationExpression} result
* and returns the opposite boolean value.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Not not(AggregationExpression expression) {
return Not.not(expression);
}
/**
* @author Christoph Strobl
*/
public static class BooleanOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link BooleanOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public BooleanOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link BooleanOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public BooleanOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpressions} that evaluates one or more expressions and returns {@literal true} if
* all of the expressions are {@literal true}.
*
* @param expression must not be {@literal null}.
* @return
*/
public And and(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return createAnd().andExpression(expression);
}
/**
* Creates new {@link AggregationExpressions} that evaluates one or more expressions and returns {@literal true} if
* all of the expressions are {@literal true}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public And and(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return createAnd().andField(fieldReference);
}
private And createAnd() {
return usesFieldRef() ? And.and(Fields.field(fieldReference)) : And.and(expression);
}
/**
* Creates new {@link AggregationExpressions} that evaluates one or more expressions and returns {@literal true} if
* any of the expressions are {@literal true}.
*
* @param expression must not be {@literal null}.
* @return
*/
public Or or(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return createOr().orExpression(expression);
}
/**
* Creates new {@link AggregationExpressions} that evaluates one or more expressions and returns {@literal true} if
* any of the expressions are {@literal true}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Or or(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return createOr().orField(fieldReference);
}
private Or createOr() {
return usesFieldRef() ? Or.or(Fields.field(fieldReference)) : Or.or(expression);
}
/**
* Creates new {@link AggregationExpression} that evaluates a boolean and returns the opposite boolean value.
*
* @return
*/
public Not not() {
return usesFieldRef() ? Not.not(fieldReference) : Not.not(expression);
}
private boolean usesFieldRef() {
return this.fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $and}.
*
* @author Christoph Strobl
*/
public static class And extends AbstractAggregationExpression {
private And(List<?> values) {
super(values);
}
@Override
protected String getMongoMethod() {
return "$and";
}
/**
* Creates new {@link And} that evaluates one or more expressions and returns {@literal true} if all of the
* expressions are {@literal true}.
*
* @param expressions
* @return
*/
public static And and(Object... expressions) {
return new And(Arrays.asList(expressions));
}
/**
* Creates new {@link And} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public And andExpression(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new And(append(expression));
}
/**
* Creates new {@link And} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public And andField(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new And(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link And} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public And andValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new And(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $or}.
*
* @author Christoph Strobl
*/
public static class Or extends AbstractAggregationExpression {
private Or(List<?> values) {
super(values);
}
@Override
protected String getMongoMethod() {
return "$or";
}
/**
* Creates new {@link Or} that evaluates one or more expressions and returns {@literal true} if any of the
* expressions are {@literal true}.
*
* @param expressions must not be {@literal null}.
* @return
*/
public static Or or(Object... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new Or(Arrays.asList(expressions));
}
/**
* Creates new {@link Or} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Or orExpression(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Or(append(expression));
}
/**
* Creates new {@link Or} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Or orField(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Or(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Or} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Or orValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Or(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $not}.
*
* @author Christoph Strobl
*/
public static class Not extends AbstractAggregationExpression {
private Not(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$not";
}
/**
* Creates new {@link Not} that evaluates the boolean value of the referenced field and returns the opposite boolean
* value.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Not not(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Not(asFields(fieldReference));
}
/**
* Creates new {@link Not} that evaluates the resulting boolean value of the given {@link AggregationExpression} and
* returns the opposite boolean value.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Not not(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Not(Collections.singletonList(expression));
}
}
}

879
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ComparisonOperators.java

@ -0,0 +1,879 @@ @@ -0,0 +1,879 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.Collections;
import java.util.List;
import org.springframework.util.Assert;
/**
* Gateway to {@literal comparison expressions}.
*
* @author Christoph Strobl
* @since 1.10
*/
public class ComparisonOperators {
/**
* Take the field referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static ComparisonOperatorFactory valueOf(String fieldReference) {
return new ComparisonOperatorFactory(fieldReference);
}
/**
* Take the value resulting from the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static ComparisonOperatorFactory valueOf(AggregationExpression expression) {
return new ComparisonOperatorFactory(expression);
}
public static class ComparisonOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link ComparisonOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public ComparisonOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link ComparisonOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public ComparisonOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpressions} that compares two values.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Cmp compareTo(String fieldReference) {
return createCmp().compareTo(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values.
*
* @param expression must not be {@literal null}.
* @return
*/
public Cmp compareTo(AggregationExpression expression) {
return createCmp().compareTo(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values.
*
* @param value must not be {@literal null}.
* @return
*/
public Cmp compareToValue(Object value) {
return createCmp().compareToValue(value);
}
private Cmp createCmp() {
return usesFieldRef() ? Cmp.valueOf(fieldReference) : Cmp.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is equal to the value of the referenced field.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Eq equalTo(String fieldReference) {
return createEq().equalTo(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is equal to the expression result.
*
* @param expression must not be {@literal null}.
* @return
*/
public Eq equalTo(AggregationExpression expression) {
return createEq().equalTo(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is equal to the given value.
*
* @param value must not be {@literal null}.
* @return
*/
public Eq equalToValue(Object value) {
return createEq().equalToValue(value);
}
private Eq createEq() {
return usesFieldRef() ? Eq.valueOf(fieldReference) : Eq.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than the value of the referenced field.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Gt greaterThan(String fieldReference) {
return createGt().greaterThan(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than the expression result.
*
* @param expression must not be {@literal null}.
* @return
*/
public Gt greaterThan(AggregationExpression expression) {
return createGt().greaterThan(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than the given value.
*
* @param value must not be {@literal null}.
* @return
*/
public Gt greaterThanValue(Object value) {
return createGt().greaterThanValue(value);
}
private Gt createGt() {
return usesFieldRef() ? Gt.valueOf(fieldReference) : Gt.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than or equivalent to the value of the referenced field.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualTo(String fieldReference) {
return createGte().greaterThanEqualTo(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than or equivalent to the expression result.
*
* @param expression must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualTo(AggregationExpression expression) {
return createGte().greaterThanEqualTo(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is greater than or equivalent to the given value.
*
* @param value must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualToValue(Object value) {
return createGte().greaterThanEqualToValue(value);
}
private Gte createGte() {
return usesFieldRef() ? Gte.valueOf(fieldReference) : Gte.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than the value of the referenced field.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Lt lessThan(String fieldReference) {
return createLt().lessThan(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than the expression result.
*
* @param expression must not be {@literal null}.
* @return
*/
public Lt lessThan(AggregationExpression expression) {
return createLt().lessThan(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than to the given value.
*
* @param value must not be {@literal null}.
* @return
*/
public Lt lessThanValue(Object value) {
return createLt().lessThanValue(value);
}
private Lt createLt() {
return usesFieldRef() ? Lt.valueOf(fieldReference) : Lt.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than or equivalent to the value of the referenced field.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Lte lessThanEqualTo(String fieldReference) {
return createLte().lessThanEqualTo(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than or equivalent to the expression result.
*
* @param expression must not be {@literal null}.
* @return
*/
public Lte lessThanEqualTo(AggregationExpression expression) {
return createLte().lessThanEqualTo(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the first
* value is less than or equivalent to the given value.
*
* @param value
* @return
*/
public Lte lessThanEqualToValue(Object value) {
return createLte().lessThanEqualToValue(value);
}
private Lte createLte() {
return usesFieldRef() ? Lte.valueOf(fieldReference) : Lte.valueOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the values
* are not equivalent.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Ne notEqualTo(String fieldReference) {
return createNe().notEqualTo(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the values
* are not equivalent.
*
* @param expression must not be {@literal null}.
* @return
*/
public Ne notEqualTo(AggregationExpression expression) {
return createNe().notEqualTo(expression);
}
/**
* Creates new {@link AggregationExpressions} that compares two values and returns {@literal true} when the values
* are not equivalent.
*
* @param value must not be {@literal null}.
* @return
*/
public Ne notEqualToValue(Object value) {
return createNe().notEqualToValue(value);
}
private Ne createNe() {
return usesFieldRef() ? Ne.valueOf(fieldReference) : Ne.valueOf(expression);
}
private boolean usesFieldRef() {
return fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $cmp}.
*
* @author Christoph Strobl
*/
public static class Cmp extends AbstractAggregationExpression {
private Cmp(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$cmp";
}
/**
* Creates new {@link Cmp}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Cmp valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Cmp(asFields(fieldReference));
}
/**
* Creates new {@link Cmp}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Cmp valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Cmp(Collections.singletonList(expression));
}
/**
* Creates new {@link Cmp} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Cmp compareTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Cmp(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Cmp} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Cmp compareTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Cmp(append(expression));
}
/**
* Creates new {@link Cmp} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Cmp compareToValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Cmp(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $eq}.
*
* @author Christoph Strobl
*/
public static class Eq extends AbstractAggregationExpression {
private Eq(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$eq";
}
/**
* Creates new {@link Eq}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Eq valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Eq(asFields(fieldReference));
}
/**
* Creates new {@link Eq}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Eq valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Eq(Collections.singletonList(expression));
}
/**
* Creates new {@link Eq} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Eq equalTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Eq(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Eq} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Eq equalTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Eq(append(expression));
}
/**
* Creates new {@link Eq} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Eq equalToValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Eq(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $gt}.
*
* @author Christoph Strobl
*/
public static class Gt extends AbstractAggregationExpression {
private Gt(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$gt";
}
/**
* Creates new {@link Gt}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Gt valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Gt(asFields(fieldReference));
}
/**
* Creates new {@link Gt}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Gt valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Gt(Collections.singletonList(expression));
}
/**
* Creates new {@link Gt} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Gt greaterThan(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Gt(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Gt} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Gt greaterThan(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Gt(append(expression));
}
/**
* Creates new {@link Gt} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Gt greaterThanValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Gt(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $lt}.
*
* @author Christoph Strobl
*/
public static class Lt extends AbstractAggregationExpression {
private Lt(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$lt";
}
/**
* Creates new {@link Lt}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Lt valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Lt(asFields(fieldReference));
}
/**
* Creates new {@link Lt}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Lt valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Lt(Collections.singletonList(expression));
}
/**
* Creates new {@link Lt} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Lt lessThan(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Lt(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Lt} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Lt lessThan(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Lt(append(expression));
}
/**
* Creates new {@link Lt} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Lt lessThanValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Lt(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $gte}.
*
* @author Christoph Strobl
*/
public static class Gte extends AbstractAggregationExpression {
private Gte(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$gte";
}
/**
* Creates new {@link Gte}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Gte valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Gte(asFields(fieldReference));
}
/**
* Creates new {@link Gte}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Gte valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Gte(Collections.singletonList(expression));
}
/**
* Creates new {@link Gte} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Gte(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Gte} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Gte(append(expression));
}
/**
* Creates new {@link Gte} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Gte greaterThanEqualToValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Gte(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $lte}.
*
* @author Christoph Strobl
*/
public static class Lte extends AbstractAggregationExpression {
private Lte(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$lte";
}
/**
* Creates new {@link Lte}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Lte valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Lte(asFields(fieldReference));
}
/**
* Creates new {@link Lte}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Lte valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Lte(Collections.singletonList(expression));
}
/**
* Creates new {@link Lte} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Lte lessThanEqualTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Lte(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Lte} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Lte lessThanEqualTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Lte(append(expression));
}
/**
* Creates new {@link Lte} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Lte lessThanEqualToValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Lte(append(value));
}
}
/**
* {@link AggregationExpression} for {@code $ne}.
*
* @author Christoph Strobl
*/
public static class Ne extends AbstractAggregationExpression {
private Ne(List<?> value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$ne";
}
/**
* Creates new {@link Ne}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Ne valueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Ne(asFields(fieldReference));
}
/**
* Creates new {@link Ne}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Ne valueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Ne(Collections.singletonList(expression));
}
/**
* Creates new {@link Ne} with all previously added arguments appending the given one.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public Ne notEqualTo(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Ne(append(Fields.field(fieldReference)));
}
/**
* Creates new {@link Ne} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public Ne notEqualTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Ne(append(expression));
}
/**
* Creates new {@link Eq} with all previously added arguments appending the given one.
*
* @param value must not be {@literal null}.
* @return
*/
public Ne notEqualToValue(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Ne(append(value));
}
}
}

973
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ConditionalOperators.java

@ -0,0 +1,973 @@ @@ -0,0 +1,973 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.OtherwiseBuilder;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.ThenBuilder;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch.CaseOperator;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Gateway to {@literal conditional expressions} that evaluate their argument expressions as booleans to a value.
*
* @author Mark Paluch
*/
public class ConditionalOperators {
/**
* Take the field referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static ConditionalOperatorFactory when(String fieldReference) {
return new ConditionalOperatorFactory(fieldReference);
}
/**
* Take the value resulting from the given {@literal expression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static ConditionalOperatorFactory when(AggregationExpression expression) {
return new ConditionalOperatorFactory(expression);
}
/**
* Take the value resulting from the given {@literal criteriaDefinition}.
*
* @param criteriaDefinition must not be {@literal null}.
* @return
*/
public static ConditionalOperatorFactory when(CriteriaDefinition criteriaDefinition) {
return new ConditionalOperatorFactory(criteriaDefinition);
}
/**
* Creates new {@link AggregationExpressions} that evaluates an expression and returns the value of the expression if
* the expression evaluates to a non-null value. If the expression evaluates to a {@literal null} value, including
* instances of undefined values or missing fields, returns the value of the replacement expression.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static IfNull.ThenBuilder ifNull(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return IfNull.ifNull(fieldReference);
}
/**
* Creates new {@link AggregationExpressions} that evaluates an expression and returns the value of the expression if
* the expression evaluates to a non-null value. If the expression evaluates to a {@literal null} value, including
* instances of undefined values or missing fields, returns the value of the replacement expression.
*
* @param expression must not be {@literal null}.
* @return
*/
public static IfNull.ThenBuilder ifNull(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return IfNull.ifNull(expression);
}
/**
* Creates new {@link AggregationExpression} that evaluates a series of {@link CaseOperator} expressions. When it
* finds an expression which evaluates to {@literal true}, {@code $switch} executes a specified expression and breaks
* out of the control flow.
*
* @param conditions must not be {@literal null}.
* @return
*/
public static Switch switchCases(CaseOperator... conditions) {
return Switch.switchCases(conditions);
}
/**
* Creates new {@link AggregationExpression} that evaluates a series of {@link CaseOperator} expressions. When it
* finds an expression which evaluates to {@literal true}, {@code $switch} executes a specified expression and breaks
* out of the control flow.
*
* @param conditions must not be {@literal null}.
* @return
*/
public static Switch switchCases(List<CaseOperator> conditions) {
return Switch.switchCases(conditions);
}
public static class ConditionalOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
private final CriteriaDefinition criteriaDefinition;
/**
* Creates new {@link ConditionalOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public ConditionalOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
this.criteriaDefinition = null;
}
/**
* Creates new {@link ConditionalOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public ConditionalOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
this.criteriaDefinition = null;
}
/**
* Creates new {@link ConditionalOperatorFactory} for given {@link CriteriaDefinition}.
*
* @param criteriaDefinition must not be {@literal null}.
*/
public ConditionalOperatorFactory(CriteriaDefinition criteriaDefinition) {
Assert.notNull(criteriaDefinition, "CriteriaDefinition must not be null!");
this.fieldReference = null;
this.expression = null;
this.criteriaDefinition = criteriaDefinition;
}
/**
* Creates new {@link AggregationExpression} that evaluates a boolean expression to return one of the two specified
* return expressions.
*
* @param value must not be {@literal null}.
* @return
*/
public OtherwiseBuilder then(Object value) {
Assert.notNull(value, "Value must not be null!");
return createThenBuilder().then(value);
}
/**
* Creates new {@link AggregationExpressions} that evaluates a boolean expression to return one of the two specified
* return expressions.
*
* @param expression must not be {@literal null}.
* @return
*/
public OtherwiseBuilder thenValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return createThenBuilder().then(expression);
}
/**
* Creates new {@link AggregationExpressions} that evaluates a boolean expression to return one of the two specified
* return expressions.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public OtherwiseBuilder thenValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return createThenBuilder().then(fieldReference);
}
private ThenBuilder createThenBuilder() {
if (usesFieldRef()) {
return Cond.newBuilder().when(fieldReference);
}
return usesCriteriaDefinition() ? Cond.newBuilder().when(criteriaDefinition) : Cond.newBuilder().when(expression);
}
private boolean usesFieldRef() {
return this.fieldReference != null;
}
private boolean usesCriteriaDefinition() {
return this.criteriaDefinition != null;
}
}
/**
* Encapsulates the aggregation framework {@code $ifNull} operator. Replacement values can be either {@link Field
* field references}, {@link AggregationExpression expressions}, values of simple MongoDB types or values that can be
* converted to a simple MongoDB type.
*
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/ifNull/
* @author Mark Paluch
*/
public static class IfNull implements AggregationExpression {
private final Object condition;
private final Object value;
private IfNull(Object condition, Object value) {
this.condition = condition;
this.value = value;
}
/**
* Creates new {@link IfNull}.
*
* @param fieldReference the field to check for a {@literal null} value, field reference must not be {@literal null}
* .
* @return
*/
public static ThenBuilder ifNull(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new IfNullOperatorBuilder().ifNull(fieldReference);
}
/**
* Creates new {@link IfNull}.
*
* @param expression the expression to check for a {@literal null} value, field reference must not be
* {@literal null}.
* @return
*/
public static ThenBuilder ifNull(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new IfNullOperatorBuilder().ifNull(expression);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
List<Object> list = new ArrayList<Object>();
if (condition instanceof Field) {
list.add(context.getReference((Field) condition).toString());
} else if (condition instanceof AggregationExpression) {
list.add(((AggregationExpression) condition).toDocument(context));
} else {
list.add(condition);
}
list.add(resolve(value, context));
return new Document("$ifNull", list);
}
private Object resolve(Object value, AggregationOperationContext context) {
if (value instanceof Field) {
return context.getReference((Field) value).toString();
} else if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDocument(context);
} else if (value instanceof Document) {
return value;
}
return context.getMappedObject(new Document("$set", value)).get("$set");
}
/**
* @author Mark Paluch
*/
public static interface IfNullBuilder {
/**
* @param fieldReference the field to check for a {@literal null} value, field reference must not be
* {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder ifNull(String fieldReference);
/**
* @param expression the expression to check for a {@literal null} value, field name must not be {@literal null}
* or empty.
* @return the {@link ThenBuilder}
*/
ThenBuilder ifNull(AggregationExpression expression);
}
/**
* @author Mark Paluch
*/
public static interface ThenBuilder {
/**
* @param value the value to be used if the {@code $ifNull} condition evaluates {@literal true}. Can be a
* {@link Document}, a value that is supported by MongoDB or a value that can be converted to a MongoDB
* representation but must not be {@literal null}.
* @return
*/
IfNull then(Object value);
/**
* @param fieldReference the field holding the replacement value, must not be {@literal null}.
* @return
*/
IfNull thenValueOf(String fieldReference);
/**
* @param expression the expression yielding to the replacement value, must not be {@literal null}.
* @return
*/
public IfNull thenValueOf(AggregationExpression expression);
}
/**
* Builder for fluent {@link IfNullOperator} creation.
*
* @author Mark Paluch
*/
static final class IfNullOperatorBuilder implements IfNullBuilder, ThenBuilder {
private Object condition;
private IfNullOperatorBuilder() {}
/**
* Creates a new builder for {@link IfNullOperator}.
*
* @return never {@literal null}.
*/
public static IfNullOperatorBuilder newBuilder() {
return new IfNullOperatorBuilder();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull.IfNullBuilder#ifNull(java.lang.String)
*/
public ThenBuilder ifNull(String fieldReference) {
Assert.hasText(fieldReference, "FieldReference name must not be null or empty!");
this.condition = Fields.field(fieldReference);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull.IfNullBuilder#ifNull(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
*/
@Override
public ThenBuilder ifNull(AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression name must not be null or empty!");
this.condition = expression;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull.ThenBuilder#then(java.lang.Object)
*/
public IfNull then(Object value) {
return new IfNull(condition, value);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull.ThenBuilder#thenValueOf(java.lang.String)
*/
public IfNull thenValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new IfNull(condition, Fields.field(fieldReference));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull.ThenBuilder#thenValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
*/
public IfNull thenValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new IfNull(condition, expression);
}
}
}
/**
* {@link AggregationExpression} for {@code $switch}.
*
* @author Christoph Strobl
*/
public static class Switch extends AbstractAggregationExpression {
private Switch(java.util.Map<String, Object> values) {
super(values);
}
@Override
protected String getMongoMethod() {
return "$switch";
}
/**
* Creates new {@link Switch}.
*
* @param conditions must not be {@literal null}.
*/
public static Switch switchCases(CaseOperator... conditions) {
Assert.notNull(conditions, "Conditions must not be null!");
return switchCases(Arrays.asList(conditions));
}
/**
* Creates new {@link Switch}.
*
* @param conditions must not be {@literal null}.
*/
public static Switch switchCases(List<CaseOperator> conditions) {
Assert.notNull(conditions, "Conditions must not be null!");
return new Switch(Collections.<String, Object> singletonMap("branches", new ArrayList<CaseOperator>(conditions)));
}
public Switch defaultTo(Object value) {
return new Switch(append("default", value));
}
/**
* Encapsulates the aggregation framework case document inside a {@code $switch}-operation.
*/
public static class CaseOperator implements AggregationExpression {
private final AggregationExpression when;
private final Object then;
private CaseOperator(AggregationExpression when, Object then) {
this.when = when;
this.then = then;
}
public static ThenBuilder when(final AggregationExpression condition) {
Assert.notNull(condition, "Condition must not be null!");
return new ThenBuilder() {
@Override
public CaseOperator then(Object value) {
Assert.notNull(value, "Value must not be null!");
return new CaseOperator(condition, value);
}
};
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
Document dbo = new Document("case", when.toDocument(context));
if (then instanceof AggregationExpression) {
dbo.put("then", ((AggregationExpression) then).toDocument(context));
} else if (then instanceof Field) {
dbo.put("then", context.getReference((Field) then).toString());
} else {
dbo.put("then", then);
}
return dbo;
}
/**
* @author Christoph Strobl
*/
public interface ThenBuilder {
/**
* Set the then {@literal value}.
*
* @param value must not be {@literal null}.
* @return
*/
CaseOperator then(Object value);
}
}
}
/**
* Encapsulates the aggregation framework {@code $cond} operator. A {@link Cond} allows nested conditions
* {@code if-then[if-then-else]-else} using {@link Field}, {@link CriteriaDefinition}, {@link AggregationExpression}
* or a {@link Document custom} condition. Replacement values can be either {@link Field field references},
* {@link AggregationExpression expressions}, values of simple MongoDB types or values that can be converted to a
* simple MongoDB type.
*
* @see http://docs.mongodb.com/manual/reference/operator/aggregation/cond/
* @author Mark Paluch
* @author Christoph Strobl
*/
public static class Cond implements AggregationExpression {
private final Object condition;
private final Object thenValue;
private final Object otherwiseValue;
/**
* Creates a new {@link Cond} for a given {@link Field} and {@code then}/{@code otherwise} values.
*
* @param condition must not be {@literal null}.
* @param thenValue must not be {@literal null}.
* @param otherwiseValue must not be {@literal null}.
*/
private Cond(Field condition, Object thenValue, Object otherwiseValue) {
this((Object) condition, thenValue, otherwiseValue);
}
/**
* Creates a new {@link Cond} for a given {@link CriteriaDefinition} and {@code then}/{@code otherwise} values.
*
* @param condition must not be {@literal null}.
* @param thenValue must not be {@literal null}.
* @param otherwiseValue must not be {@literal null}.
*/
private Cond(CriteriaDefinition condition, Object thenValue, Object otherwiseValue) {
this((Object) condition, thenValue, otherwiseValue);
}
private Cond(Object condition, Object thenValue, Object otherwiseValue) {
Assert.notNull(condition, "Condition must not be null!");
Assert.notNull(thenValue, "Then value must not be null!");
Assert.notNull(otherwiseValue, "Otherwise value must not be null!");
assertNotBuilder(condition, "Condition");
assertNotBuilder(thenValue, "Then value");
assertNotBuilder(otherwiseValue, "Otherwise value");
this.condition = condition;
this.thenValue = thenValue;
this.otherwiseValue = otherwiseValue;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(AggregationOperationContext context) {
Document condObject = new Document();
condObject.append("if", resolveCriteria(context, condition));
condObject.append("then", resolveValue(context, thenValue));
condObject.append("else", resolveValue(context, otherwiseValue));
return new Document("$cond", condObject);
}
private Object resolveValue(AggregationOperationContext context, Object value) {
if (value instanceof Document || value instanceof Field) {
return resolve(context, value);
}
if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDocument(context);
}
return context.getMappedObject(new Document("$set", value)).get("$set");
}
private Object resolveCriteria(AggregationOperationContext context, Object value) {
if (value instanceof Document || value instanceof Field) {
return resolve(context, value);
}
if (value instanceof AggregationExpression) {
return ((AggregationExpression) value).toDocument(context);
}
if (value instanceof CriteriaDefinition) {
Document mappedObject = context.getMappedObject(((CriteriaDefinition) value).getCriteriaObject());
List<Object> clauses = new ArrayList<Object>();
clauses.addAll(getClauses(context, mappedObject));
return clauses.size() == 1 ? clauses.get(0) : clauses;
}
throw new InvalidDataAccessApiUsageException(
String.format("Invalid value in condition. Supported: Document, Field references, Criteria, got: %s", value));
}
private List<Object> getClauses(AggregationOperationContext context, Document mappedObject) {
List<Object> clauses = new ArrayList<Object>();
for (String key : mappedObject.keySet()) {
Object predicate = mappedObject.get(key);
clauses.addAll(getClauses(context, key, predicate));
}
return clauses;
}
private List<Object> getClauses(AggregationOperationContext context, String key, Object predicate) {
List<Object> clauses = new ArrayList<Object>();
if (predicate instanceof List) {
List<Object> args = new ArrayList<Object>();
for (Object clause : (List<?>) predicate) {
if (clause instanceof Document) {
args.addAll(getClauses(context, (Document) clause));
}
}
clauses.add(new Document(key, args));
} else if (predicate instanceof Document) {
Document nested = (Document) predicate;
for (String s : nested.keySet()) {
if (!isKeyword(s)) {
continue;
}
List<Object> args = new ArrayList<Object>();
args.add("$" + key);
args.add(nested.get(s));
clauses.add(new Document(s, args));
}
} else if (!isKeyword(key)) {
List<Object> args = new ArrayList<Object>();
args.add("$" + key);
args.add(predicate);
clauses.add(new Document("$eq", args));
}
return clauses;
}
/**
* Returns whether the given {@link String} is a MongoDB keyword.
*
* @param candidate
* @return
*/
private boolean isKeyword(String candidate) {
return candidate.startsWith("$");
}
private Object resolve(AggregationOperationContext context, Object value) {
if (value instanceof Document) {
return context.getMappedObject((Document) value);
}
return context.getReference((Field) value).toString();
}
private void assertNotBuilder(Object toCheck, String name) {
Assert.isTrue(!ClassUtils.isAssignableValue(ConditionalExpressionBuilder.class, toCheck),
String.format("%s must not be of type %s", name, ConditionalExpressionBuilder.class.getSimpleName()));
}
/**
* Get a builder that allows fluent creation of {@link Cond}.
*
* @return never {@literal null}.
*/
public static WhenBuilder newBuilder() {
return ConditionalExpressionBuilder.newBuilder();
}
/**
* Start creating new {@link Cond} by providing the boolean expression used in {@code if}.
*
* @param booleanExpression must not be {@literal null}.
* @return never {@literal null}.
*/
public static ThenBuilder when(Document booleanExpression) {
return ConditionalExpressionBuilder.newBuilder().when(booleanExpression);
}
/**
* Start creating new {@link Cond} by providing the {@link AggregationExpression} used in {@code if}.
*
* @param expression expression that yields in a boolean result, must not be {@literal null}.
* @return never {@literal null}.
*/
public static ThenBuilder when(AggregationExpression expression) {
return ConditionalExpressionBuilder.newBuilder().when(expression);
}
/**
* Start creating new {@link Cond} by providing the field reference used in {@code if}.
*
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
* @return never {@literal null}.
*/
public static ThenBuilder when(String booleanField) {
return ConditionalExpressionBuilder.newBuilder().when(booleanField);
}
/**
* Start creating new {@link Cond} by providing the {@link CriteriaDefinition} used in {@code if}.
*
* @param criteria criteria to evaluate, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
public static ThenBuilder when(CriteriaDefinition criteria) {
return ConditionalExpressionBuilder.newBuilder().when(criteria);
}
/**
* @author Mark Paluch
*/
public static interface WhenBuilder {
/**
* @param booleanExpression expression that yields in a boolean result, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(Document booleanExpression);
/**
* @param expression expression that yields in a boolean result, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(AggregationExpression expression);
/**
* @param booleanField name of a field holding a boolean value, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(String booleanField);
/**
* @param criteria criteria to evaluate, must not be {@literal null}.
* @return the {@link ThenBuilder}
*/
ThenBuilder when(CriteriaDefinition criteria);
}
/**
* @author Mark Paluch
*/
public static interface ThenBuilder {
/**
* @param value the value to be used if the condition evaluates {@literal true}. Can be a {@link Document}, a
* value that is supported by MongoDB or a value that can be converted to a MongoDB representation but
* must not be {@literal null}.
* @return the {@link OtherwiseBuilder}
*/
OtherwiseBuilder then(Object value);
/**
* @param fieldReference must not be {@literal null}.
* @return the {@link OtherwiseBuilder}
*/
OtherwiseBuilder thenValueOf(String fieldReference);
/**
* @param expression must not be {@literal null}.
* @return the {@link OtherwiseBuilder}
*/
OtherwiseBuilder thenValueOf(AggregationExpression expression);
}
/**
* @author Mark Paluch
*/
public static interface OtherwiseBuilder {
/**
* @param value the value to be used if the condition evaluates {@literal false}. Can be a {@link Document}, a
* value that is supported by MongoDB or a value that can be converted to a MongoDB representation but
* must not be {@literal null}.
* @return the {@link Cond}
*/
Cond otherwise(Object value);
/**
* @param fieldReference must not be {@literal null}.
* @return the {@link Cond}
*/
Cond otherwiseValueOf(String fieldReference);
/**
* @param expression must not be {@literal null}.
* @return the {@link Cond}
*/
Cond otherwiseValueOf(AggregationExpression expression);
}
/**
* Builder for fluent {@link Cond} creation.
*
* @author Mark Paluch
*/
static class ConditionalExpressionBuilder implements WhenBuilder, ThenBuilder, OtherwiseBuilder {
private Object condition;
private Object thenValue;
private ConditionalExpressionBuilder() {}
/**
* Creates a new builder for {@link Cond}.
*
* @return never {@literal null}.
*/
public static ConditionalExpressionBuilder newBuilder() {
return new ConditionalExpressionBuilder();
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.WhenBuilder#when(org.bson.Document)
*/
@Override
public ConditionalExpressionBuilder when(Document booleanExpression) {
Assert.notNull(booleanExpression, "'Boolean expression' must not be null!");
this.condition = booleanExpression;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.WhenBuilder#when(org.springframework.data.mongodb.core.query.CriteriaDefinition)
*/
@Override
public ThenBuilder when(CriteriaDefinition criteria) {
Assert.notNull(criteria, "Criteria must not be null!");
this.condition = criteria;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.WhenBuilder#when(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
*/
@Override
public ThenBuilder when(AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression field must not be null!");
this.condition = expression;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.WhenBuilder#when(java.lang.String)
*/
@Override
public ThenBuilder when(String booleanField) {
Assert.hasText(booleanField, "Boolean field name must not be null or empty!");
this.condition = Fields.field(booleanField);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.ThenBuilder#then(java.lang.Object)
*/
@Override
public OtherwiseBuilder then(Object thenValue) {
Assert.notNull(thenValue, "Then-value must not be null!");
this.thenValue = thenValue;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.ThenBuilder#thenValueOf(java.lang.String)
*/
@Override
public OtherwiseBuilder thenValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.thenValue = Fields.field(fieldReference);
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.ThenBuilder#thenValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
*/
@Override
public OtherwiseBuilder thenValueOf(AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression must not be null!");
this.thenValue = expression;
return this;
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.OtherwiseBuilder#otherwise(java.lang.Object)
*/
@Override
public Cond otherwise(Object otherwiseValue) {
Assert.notNull(otherwiseValue, "Value must not be null!");
return new Cond(condition, thenValue, otherwiseValue);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.OtherwiseBuilder#otherwiseValueOf(java.lang.String)
*/
@Override
public Cond otherwiseValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Cond(condition, thenValue, Fields.field(fieldReference));
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.OtherwiseBuilder#otherwiseValueOf(org.springframework.data.mongodb.core.aggregation.AggregationExpression)
*/
@Override
public Cond otherwiseValueOf(AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression must not be null!");
return new Cond(condition, thenValue, expression);
}
}
}
}

67
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DataTypeOperators.java

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import org.springframework.util.Assert;
/**
* Gateway to {@literal data type} expressions.
*
* @author Christoph Strobl
* @since 1.10
* @soundtrack Clawfinger - Catch Me
*/
public class DataTypeOperators {
/**
* Return the BSON data type of the given {@literal field}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Type typeOf(String fieldReference) {
return Type.typeOf(fieldReference);
}
/**
* {@link AggregationExpression} for {@code $type}.
*
* @author Christoph Strobl
*/
public static class Type extends AbstractAggregationExpression {
private Type(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$type";
}
/**
* Creates new {@link Type}.
*
* @param field must not be {@literal null}.
* @return
*/
public static Type typeOf(String field) {
Assert.notNull(field, "Field must not be null!");
return new Type(Fields.field(field));
}
}
}

838
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java

@ -0,0 +1,838 @@ @@ -0,0 +1,838 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.LinkedHashMap;
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators.ArithmeticOperatorFactory;
import org.springframework.util.Assert;
/**
* Gateway to {@literal Date} aggregation operations.
*
* @author Christoph Strobl
* @since 1.10
*/
public class DateOperators {
/**
* Take the date referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static DateOperatorFactory dateOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new DateOperatorFactory(fieldReference);
}
/**
* Take the date resulting from the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static DateOperatorFactory dateOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new DateOperatorFactory(expression);
}
/**
* @author Christoph Strobl
*/
public static class DateOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link ArithmeticOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public DateOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link ArithmeticOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public DateOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpressions} that returns the day of the year for a date as a number between 1 and
* 366.
*
* @return
*/
public DayOfYear dayOfYear() {
return usesFieldRef() ? DayOfYear.dayOfYear(fieldReference) : DayOfYear.dayOfYear(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the day of the month for a date as a number between 1 and
* 31.
*
* @return
*/
public DayOfMonth dayOfMonth() {
return usesFieldRef() ? DayOfMonth.dayOfMonth(fieldReference) : DayOfMonth.dayOfMonth(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the day of the week for a date as a number between 1
* (Sunday) and 7 (Saturday).
*
* @return
*/
public DayOfWeek dayOfWeek() {
return usesFieldRef() ? DayOfWeek.dayOfWeek(fieldReference) : DayOfWeek.dayOfWeek(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the year portion of a date.
*
* @return
*/
public Year year() {
return usesFieldRef() ? Year.yearOf(fieldReference) : Year.yearOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the month of a date as a number between 1 and 12.
*
* @return
*/
public Month month() {
return usesFieldRef() ? Month.monthOf(fieldReference) : Month.monthOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the week of the year for a date as a number between 0 and
* 53.
*
* @return
*/
public Week week() {
return usesFieldRef() ? Week.weekOf(fieldReference) : Week.weekOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the hour portion of a date as a number between 0 and 23.
*
* @return
*/
public Hour hour() {
return usesFieldRef() ? Hour.hourOf(fieldReference) : Hour.hourOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the minute portion of a date as a number between 0 and
* 59.
*
* @return
*/
public Minute minute() {
return usesFieldRef() ? Minute.minuteOf(fieldReference) : Minute.minuteOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the second portion of a date as a number between 0 and
* 59, but can be 60 to account for leap seconds.
*
* @return
*/
public Second second() {
return usesFieldRef() ? Second.secondOf(fieldReference) : Second.secondOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the millisecond portion of a date as an integer between 0
* and 999.
*
* @return
*/
public Millisecond millisecond() {
return usesFieldRef() ? Millisecond.millisecondOf(fieldReference) : Millisecond.millisecondOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that converts a date object to a string according to a user-specified
* {@literal format}.
*
* @param format must not be {@literal null}.
* @return
*/
public DateToString toString(String format) {
return (usesFieldRef() ? DateToString.dateOf(fieldReference) : DateToString.dateOf(expression)).toString(format);
}
/**
* Creates new {@link AggregationExpressions} that returns the weekday number in ISO 8601 format, ranging from 1
* (for Monday) to 7 (for Sunday).
*
* @return
*/
public IsoDayOfWeek isoDayOfWeek() {
return usesFieldRef() ? IsoDayOfWeek.isoDayOfWeek(fieldReference) : IsoDayOfWeek.isoDayOfWeek(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the week number in ISO 8601 format, ranging from 1 to 53.
*
* @return
*/
public IsoWeek isoWeek() {
return usesFieldRef() ? IsoWeek.isoWeekOf(fieldReference) : IsoWeek.isoWeekOf(expression);
}
/**
* Creates new {@link AggregationExpressions} that returns the year number in ISO 8601 format.
*
* @return
*/
public IsoWeekYear isoWeekYear() {
return usesFieldRef() ? IsoWeekYear.isoWeekYearOf(fieldReference) : IsoWeekYear.isoWeekYearOf(expression);
}
private boolean usesFieldRef() {
return fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $dayOfYear}.
*
* @author Christoph Strobl
*/
public static class DayOfYear extends AbstractAggregationExpression {
private DayOfYear(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$dayOfYear";
}
/**
* Creates new {@link DayOfYear}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static DayOfYear dayOfYear(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new DayOfYear(Fields.field(fieldReference));
}
/**
* Creates new {@link DayOfYear}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static DayOfYear dayOfYear(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new DayOfYear(expression);
}
}
/**
* {@link AggregationExpression} for {@code $dayOfMonth}.
*
* @author Christoph Strobl
*/
public static class DayOfMonth extends AbstractAggregationExpression {
private DayOfMonth(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$dayOfMonth";
}
/**
* Creates new {@link DayOfMonth}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static DayOfMonth dayOfMonth(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new DayOfMonth(Fields.field(fieldReference));
}
/**
* Creates new {@link DayOfMonth}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static DayOfMonth dayOfMonth(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new DayOfMonth(expression);
}
}
/**
* {@link AggregationExpression} for {@code $dayOfWeek}.
*
* @author Christoph Strobl
*/
public static class DayOfWeek extends AbstractAggregationExpression {
private DayOfWeek(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$dayOfWeek";
}
/**
* Creates new {@link DayOfWeek}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static DayOfWeek dayOfWeek(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new DayOfWeek(Fields.field(fieldReference));
}
/**
* Creates new {@link DayOfWeek}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static DayOfWeek dayOfWeek(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new DayOfWeek(expression);
}
}
/**
* {@link AggregationExpression} for {@code $year}.
*
* @author Christoph Strobl
*/
public static class Year extends AbstractAggregationExpression {
private Year(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$year";
}
/**
* Creates new {@link Year}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Year yearOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Year(Fields.field(fieldReference));
}
/**
* Creates new {@link Year}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Year yearOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Year(expression);
}
}
/**
* {@link AggregationExpression} for {@code $month}.
*
* @author Christoph Strobl
*/
public static class Month extends AbstractAggregationExpression {
private Month(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$month";
}
/**
* Creates new {@link Month}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Month monthOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Month(Fields.field(fieldReference));
}
/**
* Creates new {@link Month}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Month monthOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Month(expression);
}
}
/**
* {@link AggregationExpression} for {@code $week}.
*
* @author Christoph Strobl
*/
public static class Week extends AbstractAggregationExpression {
private Week(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$week";
}
/**
* Creates new {@link Week}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Week weekOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Week(Fields.field(fieldReference));
}
/**
* Creates new {@link Week}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Week weekOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Week(expression);
}
}
/**
* {@link AggregationExpression} for {@code $hour}.
*
* @author Christoph Strobl
*/
public static class Hour extends AbstractAggregationExpression {
private Hour(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$hour";
}
/**
* Creates new {@link Hour}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Hour hourOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Hour(Fields.field(fieldReference));
}
/**
* Creates new {@link Hour}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Hour hourOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Hour(expression);
}
}
/**
* {@link AggregationExpression} for {@code $minute}.
*
* @author Christoph Strobl
*/
public static class Minute extends AbstractAggregationExpression {
private Minute(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$minute";
}
/**
* Creates new {@link Minute}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Minute minuteOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Minute(Fields.field(fieldReference));
}
/**
* Creates new {@link Minute}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Minute minuteOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Minute(expression);
}
}
/**
* {@link AggregationExpression} for {@code $second}.
*
* @author Christoph Strobl
*/
public static class Second extends AbstractAggregationExpression {
private Second(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$second";
}
/**
* Creates new {@link Second}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Second secondOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Second(Fields.field(fieldReference));
}
/**
* Creates new {@link Second}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Second secondOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Second(expression);
}
}
/**
* {@link AggregationExpression} for {@code $millisecond}.
*
* @author Christoph Strobl
*/
public static class Millisecond extends AbstractAggregationExpression {
private Millisecond(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$millisecond";
}
/**
* Creates new {@link Millisecond}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Millisecond millisecondOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new Millisecond(Fields.field(fieldReference));
}
/**
* Creates new {@link Millisecond}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Millisecond millisecondOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Millisecond(expression);
}
}
/**
* {@link AggregationExpression} for {@code $dateToString}.
*
* @author Christoph Strobl
*/
public static class DateToString extends AbstractAggregationExpression {
private DateToString(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$dateToString";
}
/**
* Creates new {@link FormatBuilder} allowing to define the date format to apply.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static FormatBuilder dateOf(final String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new FormatBuilder() {
@Override
public DateToString toString(String format) {
Assert.notNull(format, "Format must not be null!");
return new DateToString(argumentMap(Fields.field(fieldReference), format));
}
};
}
/**
* Creates new {@link FormatBuilder} allowing to define the date format to apply.
*
* @param expression must not be {@literal null}.
* @return
*/
public static FormatBuilder dateOf(final AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new FormatBuilder() {
@Override
public DateToString toString(String format) {
Assert.notNull(format, "Format must not be null!");
return new DateToString(argumentMap(expression, format));
}
};
}
private static java.util.Map<String, Object> argumentMap(Object date, String format) {
java.util.Map<String, Object> args = new LinkedHashMap<String, Object>(2);
args.put("format", format);
args.put("date", date);
return args;
}
public interface FormatBuilder {
/**
* Creates new {@link DateToString} with all previously added arguments appending the given one.
*
* @param format must not be {@literal null}.
* @return
*/
DateToString toString(String format);
}
}
/**
* {@link AggregationExpression} for {@code $isoDayOfWeek}.
*
* @author Christoph Strobl
*/
public static class IsoDayOfWeek extends AbstractAggregationExpression {
private IsoDayOfWeek(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$isoDayOfWeek";
}
/**
* Creates new {@link IsoDayOfWeek}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static IsoDayOfWeek isoDayOfWeek(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new IsoDayOfWeek(Fields.field(fieldReference));
}
/**
* Creates new {@link IsoDayOfWeek}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static IsoDayOfWeek isoDayOfWeek(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new IsoDayOfWeek(expression);
}
}
/**
* {@link AggregationExpression} for {@code $isoWeek}.
*
* @author Christoph Strobl
*/
public static class IsoWeek extends AbstractAggregationExpression {
private IsoWeek(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$isoWeek";
}
/**
* Creates new {@link IsoWeek}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static IsoWeek isoWeekOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new IsoWeek(Fields.field(fieldReference));
}
/**
* Creates new {@link IsoWeek}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static IsoWeek isoWeekOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new IsoWeek(expression);
}
}
/**
* {@link AggregationExpression} for {@code $isoWeekYear}.
*
* @author Christoph Strobl
*/
public static class IsoWeekYear extends AbstractAggregationExpression {
private IsoWeekYear(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$isoWeekYear";
}
/**
* Creates new {@link IsoWeekYear}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static IsoWeekYear isoWeekYearOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new IsoWeekYear(Fields.field(fieldReference));
}
/**
* Creates new {@link Millisecond}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static IsoWeekYear isoWeekYearOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new IsoWeekYear(expression);
}
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java

@ -55,7 +55,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -55,7 +55,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
*/
@Override
public Document getMappedObject(Document document) {

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/GroupOperation.java

@ -27,9 +27,6 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldRefe @@ -27,9 +27,6 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldRefe
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $group}-operation.
* <p>

96
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/LiteralOperators.java

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import org.springframework.util.Assert;
/**
* Gateway to {@literal literal} aggregation operations.
*
* @author Christoph Strobl
* @since 1.10
*/
public class LiteralOperators {
/**
* Take the value referenced by given {@literal value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static LiteralOperatorFactory valueOf(Object value) {
Assert.notNull(value, "Value must not be null!");
return new LiteralOperatorFactory(value);
}
/**
* @author Christoph Strobl
*/
public static class LiteralOperatorFactory {
private final Object value;
/**
* Creates new {@link LiteralOperatorFactory} for given {@literal value}.
*
* @param value must not be {@literal null}.
*/
public LiteralOperatorFactory(Object value) {
Assert.notNull(value, "Value must not be null!");
this.value = value;
}
/**
* Creates new {@link AggregationExpressions} that returns the associated value without parsing.
*
* @return
*/
public Literal asLiteral() {
return Literal.asLiteral(value);
}
}
/**
* {@link AggregationExpression} for {@code $literal}.
*
* @author Christoph Strobl
*/
public static class Literal extends AbstractAggregationExpression {
private Literal(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$literal";
}
/**
* Creates new {@link Literal}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Literal asLiteral(Object value) {
Assert.notNull(value, "Value must not be null!");
return new Literal(value);
}
}
}

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/NestedDelegatingExpressionAggregationOperationContext.java

@ -20,8 +20,6 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldRefe @@ -20,8 +20,6 @@ import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldRefe
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExpressionFieldReference;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* {@link AggregationOperationContext} that delegates {@link FieldReference} resolution and mapping to a parent one, but
* assures {@link FieldReference} get converted into {@link ExpressionFieldReference} using {@code $$} to ref an inner

50
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperation.java

@ -22,9 +22,9 @@ import java.util.Collections; @@ -22,9 +22,9 @@ import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.IfNull;
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.IfNull;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder.FieldProjection;
@ -788,7 +788,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -788,7 +788,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder filter(String as, AggregationExpression condition) {
return this.operation.and(AggregationExpressions.Filter.filter(name).as(as).by(condition));
return this.operation.and(ArrayOperators.Filter.filter(name).as(as).by(condition));
}
// SET OPERATORS
@ -893,7 +893,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -893,7 +893,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder absoluteValue() {
return this.operation.and(AggregationExpressions.Abs.absoluteValueOf(name));
return this.operation.and(ArithmeticOperators.Abs.absoluteValueOf(name));
}
/**
@ -904,7 +904,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -904,7 +904,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder ceil() {
return this.operation.and(AggregationExpressions.Ceil.ceilValueOf(name));
return this.operation.and(ArithmeticOperators.Ceil.ceilValueOf(name));
}
/**
@ -915,7 +915,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -915,7 +915,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder exp() {
return this.operation.and(AggregationExpressions.Exp.expValueOf(name));
return this.operation.and(ArithmeticOperators.Exp.expValueOf(name));
}
/**
@ -926,7 +926,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -926,7 +926,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder floor() {
return this.operation.and(AggregationExpressions.Floor.floorValueOf(name));
return this.operation.and(ArithmeticOperators.Floor.floorValueOf(name));
}
/**
@ -937,7 +937,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -937,7 +937,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder ln() {
return this.operation.and(AggregationExpressions.Ln.lnValueOf(name));
return this.operation.and(ArithmeticOperators.Ln.lnValueOf(name));
}
/**
@ -949,7 +949,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -949,7 +949,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder log(String baseFieldRef) {
return this.operation.and(AggregationExpressions.Log.valueOf(name).log(baseFieldRef));
return this.operation.and(ArithmeticOperators.Log.valueOf(name).log(baseFieldRef));
}
/**
@ -961,7 +961,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -961,7 +961,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder log(Number base) {
return this.operation.and(AggregationExpressions.Log.valueOf(name).log(base));
return this.operation.and(ArithmeticOperators.Log.valueOf(name).log(base));
}
/**
@ -973,7 +973,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -973,7 +973,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder log(AggregationExpression base) {
return this.operation.and(AggregationExpressions.Log.valueOf(name).log(base));
return this.operation.and(ArithmeticOperators.Log.valueOf(name).log(base));
}
/**
@ -984,7 +984,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -984,7 +984,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder log10() {
return this.operation.and(AggregationExpressions.Log10.log10ValueOf(name));
return this.operation.and(ArithmeticOperators.Log10.log10ValueOf(name));
}
/**
@ -996,7 +996,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -996,7 +996,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder pow(String exponentFieldRef) {
return this.operation.and(AggregationExpressions.Pow.valueOf(name).pow(exponentFieldRef));
return this.operation.and(ArithmeticOperators.Pow.valueOf(name).pow(exponentFieldRef));
}
/**
@ -1008,7 +1008,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1008,7 +1008,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder pow(Number exponent) {
return this.operation.and(AggregationExpressions.Pow.valueOf(name).pow(exponent));
return this.operation.and(ArithmeticOperators.Pow.valueOf(name).pow(exponent));
}
/**
@ -1020,7 +1020,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1020,7 +1020,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder pow(AggregationExpression exponentExpression) {
return this.operation.and(AggregationExpressions.Pow.valueOf(name).pow(exponentExpression));
return this.operation.and(ArithmeticOperators.Pow.valueOf(name).pow(exponentExpression));
}
/**
@ -1031,7 +1031,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1031,7 +1031,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder sqrt() {
return this.operation.and(AggregationExpressions.Sqrt.sqrtOf(name));
return this.operation.and(ArithmeticOperators.Sqrt.sqrtOf(name));
}
/**
@ -1041,7 +1041,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1041,7 +1041,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder trunc() {
return this.operation.and(AggregationExpressions.Trunc.truncValueOf(name));
return this.operation.and(ArithmeticOperators.Trunc.truncValueOf(name));
}
/**
@ -1088,7 +1088,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1088,7 +1088,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder toLower() {
return this.operation.and(AggregationExpressions.ToLower.lowerValueOf(name));
return this.operation.and(StringOperators.ToLower.lowerValueOf(name));
}
/**
@ -1099,7 +1099,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1099,7 +1099,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder toUpper() {
return this.operation.and(AggregationExpressions.ToUpper.upperValueOf(name));
return this.operation.and(StringOperators.ToUpper.upperValueOf(name));
}
/**
@ -1170,7 +1170,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1170,7 +1170,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder isArray() {
return this.operation.and(AggregationExpressions.IsArray.isArray(name));
return this.operation.and(ArrayOperators.IsArray.isArray(name));
}
/**
@ -1180,7 +1180,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1180,7 +1180,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder asLiteral() {
return this.operation.and(AggregationExpressions.Literal.asLiteral(name));
return this.operation.and(LiteralOperators.Literal.asLiteral(name));
}
/**
@ -1192,7 +1192,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1192,7 +1192,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder dateAsFormattedString(String format) {
return this.operation.and(AggregationExpressions.DateToString.dateOf(name).toString(format));
return this.operation.and(DateOperators.DateToString.dateOf(name).toString(format));
}
/**
@ -1207,7 +1207,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1207,7 +1207,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
*/
public ProjectionOperationBuilder let(AggregationExpression valueExpression, String variableName,
AggregationExpression in) {
return this.operation.and(AggregationExpressions.Let.define(ExpressionVariable.newVariable(variableName).forExpression(valueExpression)).andApply(in));
return this.operation.and(VariableOperators.Let.define(ExpressionVariable.newVariable(variableName).forExpression(valueExpression)).andApply(in));
}
/**
@ -1220,7 +1220,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation { @@ -1220,7 +1220,7 @@ public class ProjectionOperation implements FieldsExposingAggregationOperation {
* @since 1.10
*/
public ProjectionOperationBuilder let(Collection<ExpressionVariable> variables, AggregationExpression in) {
return this.operation.and(AggregationExpressions.Let.define(variables).andApply(in));
return this.operation.and(VariableOperators.Let.define(variables).andApply(in));
}
/*

666
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SetOperators.java

@ -0,0 +1,666 @@ @@ -0,0 +1,666 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.Sum;
import org.springframework.util.Assert;
/**
* Gateway to {@literal Set expressions} which perform {@literal set} operation on arrays, treating arrays as sets.
*
* @author Christoph Strobl
* @since 1.10
*/
public class SetOperators {
/**
* Take the array referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static SetOperatorFactory arrayAsSet(String fieldReference) {
return new SetOperatorFactory(fieldReference);
}
/**
* Take the array resulting from the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetOperatorFactory arrayAsSet(AggregationExpression expression) {
return new SetOperatorFactory(expression);
}
/**
* @author Christoph Strobl
*/
public static class SetOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link SetOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public SetOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link SetOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public SetOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpressions} that compares the previously mentioned field to one or more arrays and
* returns {@literal true} if they have the same distinct elements and {@literal false} otherwise.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(String... arrayReferences) {
return createSetEquals().isEqualTo(arrayReferences);
}
/**
* Creates new {@link AggregationExpressions} that compares the previously mentioned field to one or more arrays and
* returns {@literal true} if they have the same distinct elements and {@literal false} otherwise.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(AggregationExpression... expressions) {
return createSetEquals().isEqualTo(expressions);
}
private SetEquals createSetEquals() {
return usesFieldRef() ? SetEquals.arrayAsSet(fieldReference) : SetEquals.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in every of those.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetIntersection intersects(String... arrayReferences) {
return createSetIntersection().intersects(arrayReferences);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in every of those.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetIntersection intersects(AggregationExpression... expressions) {
return createSetIntersection().intersects(expressions);
}
private SetIntersection createSetIntersection() {
return usesFieldRef() ? SetIntersection.arrayAsSet(fieldReference) : SetIntersection.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in any of those.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetUnion union(String... arrayReferences) {
return createSetUnion().union(arrayReferences);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in any of those.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetUnion union(AggregationExpression... expressions) {
return createSetUnion().union(expressions);
}
private SetUnion createSetUnion() {
return usesFieldRef() ? SetUnion.arrayAsSet(fieldReference) : SetUnion.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and returns an
* array containing the elements that do not exist in the given {@literal arrayReference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(String arrayReference) {
return createSetDifference().differenceTo(arrayReference);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and returns an
* array containing the elements that do not exist in the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(AggregationExpression expression) {
return createSetDifference().differenceTo(expression);
}
private SetDifference createSetDifference() {
return usesFieldRef() ? SetDifference.arrayAsSet(fieldReference) : SetDifference.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and returns
* {@literal true} if it is a subset of the given {@literal arrayReference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(String arrayReference) {
return createSetIsSubset().isSubsetOf(arrayReference);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and returns
* {@literal true} if it is a subset of the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(AggregationExpression expression) {
return createSetIsSubset().isSubsetOf(expression);
}
private SetIsSubset createSetIsSubset() {
return usesFieldRef() ? SetIsSubset.arrayAsSet(fieldReference) : SetIsSubset.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that takes array of the previously mentioned field and returns
* {@literal true} if any of the elements are {@literal true} and {@literal false} otherwise.
*
* @return
*/
public AnyElementTrue anyElementTrue() {
return usesFieldRef() ? AnyElementTrue.arrayAsSet(fieldReference) : AnyElementTrue.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpressions} that tkes array of the previously mentioned field and returns
* {@literal true} if no elements is {@literal false}.
*
* @return
*/
public AllElementsTrue allElementsTrue() {
return usesFieldRef() ? AllElementsTrue.arrayAsSet(fieldReference) : AllElementsTrue.arrayAsSet(expression);
}
private boolean usesFieldRef() {
return this.fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $setEquals}.
*
* @author Christoph Strobl
*/
public static class SetEquals extends AbstractAggregationExpression {
private SetEquals(List<?> arrays) {
super(arrays);
}
@Override
protected String getMongoMethod() {
return "$setEquals";
}
/**
* Create new {@link SetEquals}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetEquals arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetEquals(asFields(arrayReference));
}
/**
* Create new {@link SetEquals}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetEquals arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetEquals(Collections.singletonList(expression));
}
/**
* Creates new {@link java.util.Set} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetEquals(append(Fields.fields(arrayReferences).asList()));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetEquals(append(Arrays.asList(expressions)));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one.
*
* @param array must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(Object[] array) {
Assert.notNull(array, "Array must not be null!");
return new SetEquals(append(array));
}
}
/**
* {@link AggregationExpression} for {@code $setIntersection}.
*
* @author Christoph Strobl
*/
public static class SetIntersection extends AbstractAggregationExpression {
private SetIntersection(List<?> arrays) {
super(arrays);
}
@Override
protected String getMongoMethod() {
return "$setIntersection";
}
/**
* Creates new {@link SetIntersection}
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetIntersection arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIntersection(asFields(arrayReference));
}
/**
* Creates new {@link SetIntersection}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetIntersection arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIntersection(Collections.singletonList(expression));
}
/**
* Creates new {@link SetIntersection} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetIntersection intersects(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetIntersection(append(asFields(arrayReferences)));
}
/**
* Creates new {@link SetIntersection} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetIntersection intersects(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetIntersection(append(Arrays.asList(expressions)));
}
}
/**
* {@link AggregationExpression} for {@code $setUnion}.
*
* @author Christoph Strobl
*/
public static class SetUnion extends AbstractAggregationExpression {
private SetUnion(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setUnion";
}
/**
* Creates new {@link SetUnion}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetUnion arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetUnion(asFields(arrayReference));
}
/**
* Creates new {@link SetUnion}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetUnion arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetUnion(Collections.singletonList(expression));
}
/**
* Creates new {@link SetUnion} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetUnion union(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetUnion(append(asFields(arrayReferences)));
}
/**
* Creates new {@link SetUnion} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetUnion union(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetUnion(append(Arrays.asList(expressions)));
}
}
/**
* {@link AggregationExpression} for {@code $setDifference}.
*
* @author Christoph Strobl
*/
public static class SetDifference extends AbstractAggregationExpression {
private SetDifference(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setDifference";
}
/**
* Creates new {@link SetDifference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetDifference arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetDifference(asFields(arrayReference));
}
/**
* Creates new {@link SetDifference}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetDifference arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetDifference(Collections.singletonList(expression));
}
/**
* Creates new {@link SetDifference} with all previously added arguments appending the given one.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetDifference(append(Fields.field(arrayReference)));
}
/**
* Creates new {@link SetDifference} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetDifference(append(expression));
}
}
/**
* {@link AggregationExpression} for {@code $setIsSubset}.
*
* @author Christoph Strobl
*/
public static class SetIsSubset extends AbstractAggregationExpression {
private SetIsSubset(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setIsSubset";
}
/**
* Creates new {@link SetIsSubset}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetIsSubset arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIsSubset(asFields(arrayReference));
}
/**
* Creates new {@link SetIsSubset}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetIsSubset arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIsSubset(Collections.singletonList(expression));
}
/**
* Creates new {@link SetIsSubset} with all previously added arguments appending the given one.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIsSubset(append(Fields.field(arrayReference)));
}
/**
* Creates new {@link SetIsSubset} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIsSubset(append(expression));
}
}
/**
* {@link AggregationExpression} for {@code $anyElementTrue}.
*
* @author Christoph Strobl
*/
public static class AnyElementTrue extends AbstractAggregationExpression {
private AnyElementTrue(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$anyElementTrue";
}
/**
* Creates new {@link AnyElementTrue}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static AnyElementTrue arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new AnyElementTrue(asFields(arrayReference));
}
/**
* Creates new {@link AnyElementTrue}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static AnyElementTrue arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new AnyElementTrue(Collections.singletonList(expression));
}
public AnyElementTrue anyElementTrue() {
return this;
}
}
/**
* {@link AggregationExpression} for {@code $allElementsTrue}.
*
* @author Christoph Strobl
*/
public static class AllElementsTrue extends AbstractAggregationExpression {
private AllElementsTrue(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$allElementsTrue";
}
/**
* Creates new {@link AllElementsTrue}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static AllElementsTrue arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new AllElementsTrue(asFields(arrayReference));
}
/**
* Creates new {@link AllElementsTrue}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static AllElementsTrue arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new AllElementsTrue(Collections.singletonList(expression));
}
public AllElementsTrue allElementsTrue() {
return this;
}
}
}

1089
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/StringOperators.java

File diff suppressed because it is too large Load Diff

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContext.java

@ -65,7 +65,7 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio @@ -65,7 +65,7 @@ public class TypeBasedAggregationOperationContext implements AggregationOperatio
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(com.mongodb.Document)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperationContext#getMappedObject(org.bson.Document)
*/
@Override
public Document getMappedObject(Document document) {

389
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/VariableOperators.java

@ -0,0 +1,389 @@ @@ -0,0 +1,389 @@
/*
* Copyright 2016. the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
import org.springframework.util.Assert;
/**
* Gateway to {@literal variable} aggregation operations.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.10
*/
public class VariableOperators {
/**
* Starts building new {@link Map} that applies an {@link AggregationExpression} to each item of a referenced array
* and returns an array with the applied results.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static Map.AsBuilder mapItemsOf(String fieldReference) {
return Map.itemsOf(fieldReference);
}
/**
* Starts building new {@link Map} that applies an {@link AggregationExpression} to each item of a referenced array
* and returns an array with the applied results.
*
* @param expression must not be {@literal null}.
* @return
*/
public static Map.AsBuilder mapItemsOf(AggregationExpression expression) {
return Map.itemsOf(expression);
}
/**
* Start creating new {@link Let} that allows definition of {@link ExpressionVariable} that can be used within a
* nested {@link AggregationExpression}.
*
* @param variables must not be {@literal null}.
* @return
*/
public static Let.LetBuilder define(ExpressionVariable... variables) {
return Let.define(variables);
}
/**
* Start creating new {@link Let} that allows definition of {@link ExpressionVariable} that can be used within a
* nested {@link AggregationExpression}.
*
* @param variables must not be {@literal null}.
* @return
*/
public static Let.LetBuilder define(Collection<ExpressionVariable> variables) {
return Let.define(variables);
}
/**
* {@link AggregationExpression} for {@code $map}.
*/
public static class Map implements AggregationExpression {
private Object sourceArray;
private String itemVariableName;
private AggregationExpression functionToApply;
private Map(Object sourceArray, String itemVariableName, AggregationExpression functionToApply) {
Assert.notNull(sourceArray, "SourceArray must not be null!");
Assert.notNull(itemVariableName, "ItemVariableName must not be null!");
Assert.notNull(functionToApply, "FunctionToApply must not be null!");
this.sourceArray = sourceArray;
this.itemVariableName = itemVariableName;
this.functionToApply = functionToApply;
}
/**
* Starts building new {@link Map} that applies an {@link AggregationExpression} to each item of a referenced array
* and returns an array with the applied results.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static AsBuilder itemsOf(final String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
return new AsBuilder() {
@Override
public FunctionBuilder as(final String variableName) {
Assert.notNull(variableName, "VariableName must not be null!");
return new FunctionBuilder() {
@Override
public Map andApply(final AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression must not be null!");
return new Map(Fields.field(fieldReference), variableName, expression);
}
};
}
};
};
/**
* Starts building new {@link Map} that applies an {@link AggregationExpression} to each item of a referenced array
* and returns an array with the applied results.
*
* @param source must not be {@literal null}.
* @return
*/
public static AsBuilder itemsOf(final AggregationExpression source) {
Assert.notNull(source, "AggregationExpression must not be null!");
return new AsBuilder() {
@Override
public FunctionBuilder as(final String variableName) {
Assert.notNull(variableName, "VariableName must not be null!");
return new FunctionBuilder() {
@Override
public Map andApply(final AggregationExpression expression) {
Assert.notNull(expression, "AggregationExpression must not be null!");
return new Map(source, variableName, expression);
}
};
}
};
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(final AggregationOperationContext context) {
return toMap(ExposedFields.synthetic(Fields.fields(itemVariableName)), context);
}
private Document toMap(ExposedFields exposedFields, AggregationOperationContext context) {
Document map = new Document();
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
Document input;
if (sourceArray instanceof Field) {
input = new Document("input", context.getReference((Field) sourceArray).toString());
} else {
input = new Document("input", ((AggregationExpression) sourceArray).toDocument(context));
}
map.putAll(context.getMappedObject(input));
map.put("as", itemVariableName);
map.put("in",
functionToApply.toDocument(new NestedDelegatingExpressionAggregationOperationContext(operationContext)));
return new Document("$map", map);
}
public interface AsBuilder {
/**
* Define the {@literal variableName} for addressing items within the array.
*
* @param variableName must not be {@literal null}.
* @return
*/
FunctionBuilder as(String variableName);
}
public interface FunctionBuilder {
/**
* Creates new {@link Map} that applies the given {@link AggregationExpression} to each item of the referenced
* array and returns an array with the applied results.
*
* @param expression must not be {@literal null}.
* @return
*/
Map andApply(AggregationExpression expression);
}
}
/**
* {@link AggregationExpression} for {@code $let} that binds {@link AggregationExpression} to variables for use in the
* specified {@code in} expression, and returns the result of the expression.
*
* @author Christoph Strobl
* @since 1.10
*/
public static class Let implements AggregationExpression {
private final List<ExpressionVariable> vars;
private final AggregationExpression expression;
private Let(List<ExpressionVariable> vars, AggregationExpression expression) {
this.vars = vars;
this.expression = expression;
}
/**
* Start creating new {@link Let} by defining the variables for {@code $vars}.
*
* @param variables must not be {@literal null}.
* @return
*/
public static LetBuilder define(final Collection<ExpressionVariable> variables) {
Assert.notNull(variables, "Variables must not be null!");
return new LetBuilder() {
@Override
public Let andApply(final AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Let(new ArrayList<ExpressionVariable>(variables), expression);
}
};
}
/**
* Start creating new {@link Let} by defining the variables for {@code $vars}.
*
* @param variables must not be {@literal null}.
* @return
*/
public static LetBuilder define(final ExpressionVariable... variables) {
Assert.notNull(variables, "Variables must not be null!");
return new LetBuilder() {
@Override
public Let andApply(final AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new Let(Arrays.asList(variables), expression);
}
};
}
public interface LetBuilder {
/**
* Define the {@link AggregationExpression} to evaluate.
*
* @param expression must not be {@literal null}.
* @return
*/
Let andApply(AggregationExpression expression);
}
/* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationExpression#toDocument(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public Document toDocument(final AggregationOperationContext context) {
return toLet(ExposedFields.synthetic(Fields.fields(getVariableNames())), context);
}
private String[] getVariableNames() {
String[] varNames = new String[this.vars.size()];
for (int i = 0; i < this.vars.size(); i++) {
varNames[i] = this.vars.get(i).variableName;
}
return varNames;
}
private Document toLet(ExposedFields exposedFields, AggregationOperationContext context) {
Document letExpression = new Document();
Document mappedVars = new Document();
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
for (ExpressionVariable var : this.vars) {
mappedVars.putAll(getMappedVariable(var, context));
}
letExpression.put("vars", mappedVars);
letExpression.put("in", getMappedIn(operationContext));
return new Document("$let", letExpression);
}
private Document getMappedVariable(ExpressionVariable var, AggregationOperationContext context) {
return new Document(var.variableName, var.expression instanceof AggregationExpression
? ((AggregationExpression) var.expression).toDocument(context) : var.expression);
}
private Object getMappedIn(AggregationOperationContext context) {
return expression.toDocument(new NestedDelegatingExpressionAggregationOperationContext(context));
}
/**
* @author Christoph Strobl
*/
public static class ExpressionVariable {
private final String variableName;
private final Object expression;
/**
* Creates new {@link ExpressionVariable}.
*
* @param variableName can be {@literal null}.
* @param expression can be {@literal null}.
*/
private ExpressionVariable(String variableName, Object expression) {
this.variableName = variableName;
this.expression = expression;
}
/**
* Create a new {@link ExpressionVariable} with given name.
*
* @param variableName must not be {@literal null}.
* @return never {@literal null}.
*/
public static ExpressionVariable newVariable(String variableName) {
Assert.notNull(variableName, "VariableName must not be null!");
return new ExpressionVariable(variableName, null);
}
/**
* Create a new {@link ExpressionVariable} with current name and given {@literal expression}.
*
* @param expression must not be {@literal null}.
* @return never {@literal null}.
*/
public ExpressionVariable forExpression(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new ExpressionVariable(variableName, expression);
}
/**
* Create a new {@link ExpressionVariable} with current name and given {@literal expressionObject}.
*
* @param expressionObject must not be {@literal null}.
* @return never {@literal null}.
*/
public ExpressionVariable forExpression(Document expressionObject) {
Assert.notNull(expressionObject, "Expression must not be null!");
return new ExpressionVariable(variableName, expressionObject);
}
}
}
}

16
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java

@ -58,11 +58,7 @@ import org.springframework.data.mapping.model.MappingException; @@ -58,11 +58,7 @@ import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.core.CollectionCallback;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.Venue;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Multiply;
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.AggregationTests.CarDescriptor.Entry;
import org.springframework.data.mongodb.core.aggregation.BucketAutoOperation.Granularities;
import org.springframework.data.mongodb.core.index.GeospatialIndex;
@ -529,7 +525,7 @@ public class AggregationTests { @@ -529,7 +525,7 @@ public class AggregationTests {
TypedAggregation<InventoryItem> aggregation = newAggregation(InventoryItem.class, //
project("item") //
.and("discount")//
.applyCondition(Cond.newBuilder().when(Criteria.where("qty").gte(250)) //
.applyCondition(ConditionalOperators.Cond.newBuilder().when(Criteria.where("qty").gte(250)) //
.then(30) //
.otherwise(20)));
@ -1616,11 +1612,11 @@ public class AggregationTests { @@ -1616,11 +1612,11 @@ public class AggregationTests {
ExpressionVariable total = ExpressionVariable.newVariable("total")
.forExpression(AggregationFunctionExpressions.ADD.of(Fields.field("price"), Fields.field("tax")));
ExpressionVariable discounted = ExpressionVariable.newVariable("discounted")
.forExpression(Cond.when("applyDiscount").then(0.9D).otherwise(1.0D));
.forExpression(ConditionalOperators.Cond.when("applyDiscount").then(0.9D).otherwise(1.0D));
TypedAggregation<Sales2> agg = Aggregation.newAggregation(Sales2.class,
Aggregation.project()
.and(Let.define(total, discounted).andApply(
.and(VariableOperators.Let.define(total, discounted).andApply(
AggregationFunctionExpressions.MULTIPLY.of(Fields.field("total"), Fields.field("discounted"))))
.as("finalTotal"));
@ -1720,7 +1716,7 @@ public class AggregationTests { @@ -1720,7 +1716,7 @@ public class AggregationTests {
mongoTemplate.insert(Arrays.asList(a1, a2, a3, a4), Art.class);
TypedAggregation<Art> aggregation = newAggregation(Art.class, //
bucketAuto(Multiply.valueOf("price").multiplyBy(10), 3) //
bucketAuto(ArithmeticOperators.Multiply.valueOf("price").multiplyBy(10), 3) //
.withGranularity(Granularities.E12) //
.andOutputCount().as("count") //
.andOutput("title").push().as("titles") //
@ -1756,7 +1752,7 @@ public class AggregationTests { @@ -1756,7 +1752,7 @@ public class AggregationTests {
mongoTemplate.insert(Arrays.asList(a1, a2, a3, a4), Art.class);
BucketAutoOperation bucketPrice = bucketAuto(Multiply.valueOf("price").multiplyBy(10), 3) //
BucketAutoOperation bucketPrice = bucketAuto(ArithmeticOperators.Multiply.valueOf("price").multiplyBy(10), 3) //
.withGranularity(Granularities.E12) //
.andOutputCount().as("count") //
.andOutput("title").push().as("titles") //

11
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationUnitTests.java

@ -31,8 +31,7 @@ import org.junit.Rule; @@ -31,8 +31,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond;
import org.springframework.data.mongodb.core.query.Criteria;
/**
@ -423,7 +422,7 @@ public class AggregationUnitTests { @@ -423,7 +422,7 @@ public class AggregationUnitTests {
public void shouldRenderProjectionConditionalExpressionCorrectly() {
Document agg = Aggregation.newAggregation(//
project().and(Cond.newBuilder() //
project().and(ConditionalOperators.Cond.newBuilder() //
.when("isYellow") //
.then("bright") //
.otherwise("dark")).as("color"))
@ -446,7 +445,7 @@ public class AggregationUnitTests { @@ -446,7 +445,7 @@ public class AggregationUnitTests {
Document agg = Aggregation.newAggregation(//
project().and("color")
.applyCondition(Cond.newBuilder() //
.applyCondition(ConditionalOperators.Cond.newBuilder() //
.when("isYellow") //
.then("bright") //
.otherwise("dark")))
@ -470,7 +469,7 @@ public class AggregationUnitTests { @@ -470,7 +469,7 @@ public class AggregationUnitTests {
Document agg = Aggregation
.newAggregation(project()//
.and("color")//
.applyCondition(Cond.newBuilder().when(Criteria.where("key").gt(5)) //
.applyCondition(ConditionalOperators.Cond.newBuilder().when(Criteria.where("key").gt(5)) //
.then("bright").otherwise("dark"))) //
.toDocument("foo", Aggregation.DEFAULT_CONTEXT);
@ -518,7 +517,7 @@ public class AggregationUnitTests { @@ -518,7 +517,7 @@ public class AggregationUnitTests {
.newAggregation(//
project().and("color").as("chroma"),
project().and("luminosity") //
.applyCondition(Cond.newBuilder()
.applyCondition(ConditionalOperators.Cond.newBuilder()
.when(Criteria.where("chroma") //
.is(100)) //
.then("bright").otherwise("dark"))) //

1
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/BucketOperationUnitTests.java

@ -21,7 +21,6 @@ import static org.junit.Assert.*; @@ -21,7 +21,6 @@ import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import org.junit.Test;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ArithmeticOperators;
import org.bson.Document;

5
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/CondExpressionUnitTests.java

@ -16,15 +16,14 @@ @@ -16,15 +16,14 @@
package org.springframework.data.mongodb.core.aggregation;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond.*;
import static org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond.*;
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
import java.util.Arrays;
import org.bson.Document;
import org.junit.Test;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Cond;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Cond;
import org.springframework.data.mongodb.core.query.Criteria;
/**

2
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/FilterExpressionUnitTests.java

@ -17,7 +17,7 @@ package org.springframework.data.mongodb.core.aggregation; @@ -17,7 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
import static org.hamcrest.core.Is.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Filter.*;
import static org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.*;
import java.util.Arrays;
import java.util.List;

5
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/GraphLookupOperationUnitTests.java

@ -22,7 +22,6 @@ import static org.springframework.data.mongodb.test.util.IsBsonObject.*; @@ -22,7 +22,6 @@ import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
import org.bson.Document;
import org.junit.Test;
import org.springframework.data.mongodb.core.Person;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Literal;
import org.springframework.data.mongodb.core.query.Criteria;
import com.mongodb.BasicDBObject;
@ -112,7 +111,7 @@ public class GraphLookupOperationUnitTests { @@ -112,7 +111,7 @@ public class GraphLookupOperationUnitTests {
GraphLookupOperation graphLookupOperation = GraphLookupOperation.builder() //
.from("employees") //
.startWith("reportsTo", Literal.asLiteral("$boss")) //
.startWith("reportsTo", LiteralOperators.Literal.asLiteral("$boss")) //
.connectFrom("reportsTo") //
.connectTo("name") //
.as("reportingHierarchy");
@ -146,7 +145,7 @@ public class GraphLookupOperationUnitTests { @@ -146,7 +145,7 @@ public class GraphLookupOperationUnitTests {
GraphLookupOperation graphLookupOperation = GraphLookupOperation.builder() //
.from("employees") //
.startWith(Literal.asLiteral("hello")) //
.startWith(LiteralOperators.Literal.asLiteral("hello")) //
.connectFrom("reportsTo") //
.connectTo("name") //
.as("reportingHierarchy");

35
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ProjectionOperationUnitTests.java

@ -19,9 +19,9 @@ import static org.hamcrest.Matchers.*; @@ -19,9 +19,9 @@ import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable.*;
import static org.springframework.data.mongodb.core.aggregation.AggregationFunctionExpressions.*;
import static org.springframework.data.mongodb.core.aggregation.Fields.*;
import static org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable.*;
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
import java.util.Arrays;
@ -32,12 +32,11 @@ import org.hamcrest.Matchers; @@ -32,12 +32,11 @@ import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.data.domain.Range;
import org.springframework.data.mongodb.core.DocumentTestUtils;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Let.ExpressionVariable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Reduce.PropertyExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Reduce.Variable;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.Switch.CaseOperator;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Reduce.PropertyExpression;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Reduce.Variable;
import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch.CaseOperator;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation.ProjectionOperationBuilder;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.*;
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable;
/**
* Unit tests for {@link ProjectionOperation}.
@ -1759,7 +1758,8 @@ public class ProjectionOperationUnitTests { @@ -1759,7 +1758,8 @@ public class ProjectionOperationUnitTests {
.define(
newVariable("total")
.forExpression(AggregationFunctionExpressions.ADD.of(Fields.field("price"), Fields.field("tax"))),
newVariable("discounted").forExpression(Cond.when("applyDiscount").then(0.9D).otherwise(1.0D)))
newVariable("discounted")
.forExpression(ConditionalOperators.Cond.when("applyDiscount").then(0.9D).otherwise(1.0D)))
.andApply(AggregationFunctionExpressions.MULTIPLY.of(Fields.field("total"), Fields.field("discounted")))) //
.as("finalTotal").toDocument(Aggregation.DEFAULT_CONTEXT);
@ -1783,7 +1783,7 @@ public class ProjectionOperationUnitTests { @@ -1783,7 +1783,7 @@ public class ProjectionOperationUnitTests {
.forExpression(AggregationFunctionExpressions.ADD.of(Fields.field("price"), Fields.field("tax")));
ExpressionVariable var2 = newVariable("discounted")
.forExpression(Cond.when("applyDiscount").then(0.9D).otherwise(1.0D));
.forExpression(ConditionalOperators.Cond.when("applyDiscount").then(0.9D).otherwise(1.0D));
Document agg = Aggregation.project().and("foo")
.let(Arrays.asList(var1, var2),
@ -1919,8 +1919,8 @@ public class ProjectionOperationUnitTests { @@ -1919,8 +1919,8 @@ public class ProjectionOperationUnitTests {
@Test
public void shouldRenderRangeCorrectly() {
Document agg = project().and(RangeOperator.rangeStartingAt(0L).to("distance").withStepSize(25L)).as("rest_stops")
.toDocument(Aggregation.DEFAULT_CONTEXT);
Document agg = project().and(ArrayOperators.RangeOperator.rangeStartingAt(0L).to("distance").withStepSize(25L))
.as("rest_stops").toDocument(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, isBsonObject().containing("$project.rest_stops.$range.[0]", 0L)
.containing("$project.rest_stops.$range.[1]", "$distance").containing("$project.rest_stops.$range.[2]", 25L));
@ -2068,11 +2068,16 @@ public class ProjectionOperationUnitTests { @@ -2068,11 +2068,16 @@ public class ProjectionOperationUnitTests {
" }\n" + //
"}";
CaseOperator cond1 = CaseOperator.when(Gte.valueOf(Avg.avgOf("scores")).greaterThanEqualToValue(90))
CaseOperator cond1 = CaseOperator
.when(ComparisonOperators.Gte.valueOf(AccumulatorOperators.Avg.avgOf("scores")).greaterThanEqualToValue(90))
.then("Doing great!");
CaseOperator cond2 = CaseOperator.when(And.and(Gte.valueOf(Avg.avgOf("scores")).greaterThanEqualToValue(80),
Lt.valueOf(Avg.avgOf("scores")).lessThanValue(90))).then("Doing pretty well.");
CaseOperator cond3 = CaseOperator.when(Lt.valueOf(Avg.avgOf("scores")).lessThanValue(80))
CaseOperator cond2 = CaseOperator
.when(BooleanOperators.And.and(
ComparisonOperators.Gte.valueOf(AccumulatorOperators.Avg.avgOf("scores")).greaterThanEqualToValue(80),
ComparisonOperators.Lt.valueOf(AccumulatorOperators.Avg.avgOf("scores")).lessThanValue(90)))
.then("Doing pretty well.");
CaseOperator cond3 = CaseOperator
.when(ComparisonOperators.Lt.valueOf(AccumulatorOperators.Avg.avgOf("scores")).lessThanValue(80))
.then("Needs improvement.");
Document agg = project().and(ConditionalOperators.switchCases(cond1, cond2, cond3).defaultTo("No scores found."))
@ -2087,7 +2092,7 @@ public class ProjectionOperationUnitTests { @@ -2087,7 +2092,7 @@ public class ProjectionOperationUnitTests {
@Test
public void shouldTypeCorrectly() {
Document agg = project().and(Type.typeOf("a")).as("a").toDocument(Aggregation.DEFAULT_CONTEXT);
Document agg = project().and(DataTypeOperators.Type.typeOf("a")).as("a").toDocument(Aggregation.DEFAULT_CONTEXT);
assertThat(agg, Matchers.is(Document.parse("{ $project : { a: { $type: \"$a\" } } }")));
}

1
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ReplaceRootOperationUnitTests.java

@ -20,7 +20,6 @@ import static org.junit.Assert.*; @@ -20,7 +20,6 @@ import static org.junit.Assert.*;
import org.bson.Document;
import org.junit.Test;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.VariableOperators;
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperation;
/**

1
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/TypeBasedAggregationOperationContextUnitTests.java

@ -37,7 +37,6 @@ import org.springframework.data.annotation.Id; @@ -37,7 +37,6 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mongodb.core.aggregation.AggregationExpressions.ConditionalOperators;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.DirectFieldReference;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;

Loading…
Cancel
Save