DATAMONGO-1530 - Polishing.
Add missing transformations for ConstructorReference, OperatorNot, OpNE, OpEQ, OpGT, OpGE, OpLT, OpLE, OperatorPower, OpOr and OpAnd. This allows usage of logical operators &, || and ! as part of the expression, while ConstructorReference allows instantiating eg. arrays via an expression `new int[]{4,5,6}`. This can be useful eg. comparing arrays using $setEquals.
More complex aggregation operators like $filter can be created by defining the variable references as string inside the expression like filter(a, 'num', '$$num' > 10).
Commands like $let requires usage of InlineMap to pass in required arguments like eg. let({low:1, high:'$$low'}, gt('$$low', '$$high')).
Original Pull Request: #410
This commit is contained in:
@@ -26,24 +26,32 @@ import org.springframework.data.mongodb.core.spel.ExpressionNode;
|
||||
import org.springframework.data.mongodb.core.spel.ExpressionTransformationContextSupport;
|
||||
import org.springframework.data.mongodb.core.spel.LiteralNode;
|
||||
import org.springframework.data.mongodb.core.spel.MethodReferenceNode;
|
||||
import org.springframework.data.mongodb.core.spel.MethodReferenceNode.AggregationMethodReference;
|
||||
import org.springframework.data.mongodb.core.spel.MethodReferenceNode.AggregationMethodReference.ArgumentType;
|
||||
import org.springframework.data.mongodb.core.spel.NotOperatorNode;
|
||||
import org.springframework.data.mongodb.core.spel.OperatorNode;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelNode;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.ast.CompoundExpression;
|
||||
import org.springframework.expression.spel.ast.ConstructorReference;
|
||||
import org.springframework.expression.spel.ast.Indexer;
|
||||
import org.springframework.expression.spel.ast.InlineList;
|
||||
import org.springframework.expression.spel.ast.InlineMap;
|
||||
import org.springframework.expression.spel.ast.OperatorNot;
|
||||
import org.springframework.expression.spel.ast.PropertyOrFieldReference;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.NumberUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Renders the AST of a SpEL expression as a MongoDB Aggregation Framework projection expression.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
|
||||
@@ -65,6 +73,8 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
conversions.add(new PropertyOrFieldReferenceNodeConversion(this));
|
||||
conversions.add(new CompoundExpressionNodeConversion(this));
|
||||
conversions.add(new MethodReferenceNodeConversion(this));
|
||||
conversions.add(new NotOperatorNodeConversion(this));
|
||||
conversions.add(new ValueRetrievingNodeConversion(this));
|
||||
|
||||
this.conversions = Collections.unmodifiableList(conversions);
|
||||
}
|
||||
@@ -231,8 +241,17 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
protected Object convert(AggregationExpressionTransformationContext<OperatorNode> context) {
|
||||
|
||||
OperatorNode currentNode = context.getCurrentNode();
|
||||
|
||||
Document operationObject = createOperationObjectAndAddToPreviousArgumentsIfNecessary(context, currentNode);
|
||||
|
||||
if (currentNode.isLogicalOperator()) {
|
||||
|
||||
for (ExpressionNode expressionNode : currentNode) {
|
||||
transform(expressionNode, currentNode, operationObject, context);
|
||||
}
|
||||
|
||||
return operationObject;
|
||||
}
|
||||
|
||||
Object leftResult = transform(currentNode.getLeft(), currentNode, operationObject, context);
|
||||
|
||||
if (currentNode.isUnaryMinus()) {
|
||||
@@ -286,7 +305,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
*/
|
||||
@Override
|
||||
protected boolean supports(ExpressionNode node) {
|
||||
return node.isMathematicalOperation();
|
||||
return node.isMathematicalOperation() || node.isLogicalOperator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,13 +478,31 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
protected Object convert(AggregationExpressionTransformationContext<MethodReferenceNode> context) {
|
||||
|
||||
MethodReferenceNode node = context.getCurrentNode();
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
AggregationMethodReference methodReference = node.getMethodReference();
|
||||
|
||||
for (ExpressionNode childNode : node) {
|
||||
args.add(transform(childNode, context));
|
||||
Object args = null;
|
||||
|
||||
if (ObjectUtils.nullSafeEquals(methodReference.getArgumentType(), ArgumentType.SINGLE)) {
|
||||
args = transform(node.getChild(0), context);
|
||||
} else if (ObjectUtils.nullSafeEquals(methodReference.getArgumentType(), ArgumentType.MAP)) {
|
||||
|
||||
Document dbo = new Document();
|
||||
for (int i = 0; i < methodReference.getArgumentMap().length; i++) {
|
||||
dbo.put(methodReference.getArgumentMap()[i], transform(node.getChild(i), context));
|
||||
}
|
||||
args = dbo;
|
||||
} else {
|
||||
|
||||
List<Object> argList = new ArrayList<Object>();
|
||||
|
||||
for (ExpressionNode childNode : node) {
|
||||
argList.add(transform(childNode, context));
|
||||
}
|
||||
|
||||
args = argList;
|
||||
}
|
||||
|
||||
return context.addToPreviousOrReturn(new Document(node.getMethodName(), args));
|
||||
return context.addToPreviousOrReturn(new Document(methodReference.getMongoOperator(), args));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,4 +544,83 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
return node.isOfType(CompoundExpression.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
static class NotOperatorNodeConversion extends ExpressionNodeConversion<NotOperatorNode> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionNodeConversion}.
|
||||
*
|
||||
* @param transformer must not be {@literal null}.
|
||||
*/
|
||||
public NotOperatorNodeConversion(AggregationExpressionTransformer transformer) {
|
||||
super(transformer);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||
*/
|
||||
@Override
|
||||
protected Object convert(AggregationExpressionTransformationContext<NotOperatorNode> context) {
|
||||
|
||||
NotOperatorNode node = context.getCurrentNode();
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
|
||||
for (ExpressionNode childNode : node) {
|
||||
args.add(transform(childNode, context));
|
||||
}
|
||||
|
||||
return context.addToPreviousOrReturn(new Document(node.getMongoOperator(), args));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||
*/
|
||||
@Override
|
||||
protected boolean supports(ExpressionNode node) {
|
||||
return node.isOfType(OperatorNot.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
static class ValueRetrievingNodeConversion extends ExpressionNodeConversion<ExpressionNode> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionNodeConversion}.
|
||||
*
|
||||
* @param transformer must not be {@literal null}.
|
||||
*/
|
||||
public ValueRetrievingNodeConversion(AggregationExpressionTransformer transformer) {
|
||||
super(transformer);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.SpelNodeWrapper#convertSpelNodeToMongoObjectExpression(org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.ExpressionConversionContext)
|
||||
*/
|
||||
@Override
|
||||
protected Object convert(AggregationExpressionTransformationContext<ExpressionNode> context) {
|
||||
|
||||
Object value = context.getCurrentNode().getValue();
|
||||
return ObjectUtils.isArray(value) ? Arrays.asList(ObjectUtils.toObjectArray(value)) : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.aggregation.SpelExpressionTransformer.NodeConversion#supports(org.springframework.data.mongodb.core.spel.ExpressionNode)
|
||||
*/
|
||||
@Override
|
||||
protected boolean supports(ExpressionNode node) {
|
||||
return node.isOfType(InlineMap.class) || node.isOfType(InlineList.class)
|
||||
|| node.isOfType(ConstructorReference.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -23,12 +23,14 @@ import org.springframework.expression.spel.SpelNode;
|
||||
import org.springframework.expression.spel.ast.Literal;
|
||||
import org.springframework.expression.spel.ast.MethodReference;
|
||||
import org.springframework.expression.spel.ast.Operator;
|
||||
import org.springframework.expression.spel.ast.OperatorNot;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A value object for nodes in an expression. Allows iterating ove potentially available child {@link ExpressionNode}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
|
||||
@@ -79,6 +81,10 @@ public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
return new LiteralNode((Literal) node, state);
|
||||
}
|
||||
|
||||
if (node instanceof OperatorNot) {
|
||||
return new NotOperatorNode((OperatorNot) node, state);
|
||||
}
|
||||
|
||||
return new ExpressionNode(node, state);
|
||||
}
|
||||
|
||||
@@ -122,6 +128,16 @@ public class ExpressionNode implements Iterable<ExpressionNode> {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link ExpressionNode} is a logical conjunction operation like {@code &&, ||}.
|
||||
*
|
||||
* @return
|
||||
* @since 1.10
|
||||
*/
|
||||
public boolean isLogicalOperator() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link ExpressionNode} is a literal.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -15,7 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.spel;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.ast.BooleanLiteral;
|
||||
import org.springframework.expression.spel.ast.FloatLiteral;
|
||||
import org.springframework.expression.spel.ast.IntLiteral;
|
||||
import org.springframework.expression.spel.ast.Literal;
|
||||
@@ -26,13 +31,29 @@ import org.springframework.expression.spel.ast.StringLiteral;
|
||||
|
||||
/**
|
||||
* A node representing a literal in an expression.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class LiteralNode extends ExpressionNode {
|
||||
|
||||
private static final Set<Class<?>> SUPPORTED_LITERAL_TYPES;
|
||||
private final Literal literal;
|
||||
|
||||
static {
|
||||
|
||||
Set<Class<?>> supportedTypes = new HashSet<Class<?>>(7, 1);
|
||||
supportedTypes.add(BooleanLiteral.class);
|
||||
supportedTypes.add(FloatLiteral.class);
|
||||
supportedTypes.add(IntLiteral.class);
|
||||
supportedTypes.add(LongLiteral.class);
|
||||
supportedTypes.add(NullLiteral.class);
|
||||
supportedTypes.add(RealLiteral.class);
|
||||
supportedTypes.add(StringLiteral.class);
|
||||
|
||||
SUPPORTED_LITERAL_TYPES = Collections.unmodifiableSet(supportedTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LiteralNode} from the given {@link Literal} and {@link ExpressionState}.
|
||||
*
|
||||
@@ -66,7 +87,6 @@ public class LiteralNode extends ExpressionNode {
|
||||
*/
|
||||
@Override
|
||||
public boolean isLiteral() {
|
||||
return literal instanceof FloatLiteral || literal instanceof RealLiteral || literal instanceof IntLiteral
|
||||
|| literal instanceof LongLiteral || literal instanceof StringLiteral || literal instanceof NullLiteral;
|
||||
return SUPPORTED_LITERAL_TYPES.contains(literal.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -15,108 +15,132 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.spel;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.ast.MethodReference;
|
||||
import static org.springframework.data.mongodb.core.spel.MethodReferenceNode.AggregationMethodReference.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.ast.MethodReference;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* An {@link ExpressionNode} representing a method reference.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Sebastien Gerard
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MethodReferenceNode extends ExpressionNode {
|
||||
|
||||
private static final Map<String, String> FUNCTIONS;
|
||||
private static final Map<String, AggregationMethodReference> FUNCTIONS;
|
||||
|
||||
static {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
map.put("and", "$and"); // Returns true only when all its expressions evaluate to true.
|
||||
map.put("or", "$or"); // Returns true when any of its expressions evaluates to true.
|
||||
map.put("not", "$not"); // Returns the boolean value that is the opposite of its argument expression.
|
||||
Map<String, AggregationMethodReference> map = new HashMap<String, AggregationMethodReference>();
|
||||
|
||||
map.put("setEquals", "$setEquals"); // Returns true if the input sets have the same distinct elements.
|
||||
map.put("setIntersection", "$setIntersection"); // Returns a set with elements that appear in all of the input sets.
|
||||
map.put("setUnion", "$setUnion"); // Returns a set with elements that appear in any of the input sets.
|
||||
map.put("setDifference", "$setDifference"); // Returns a set with elements that appear in the 1st set but not in the
|
||||
// BOOLEAN OPERATORS
|
||||
map.put("and", arrayArgumentAggregationMethodReference().forOperator("$and"));
|
||||
map.put("or", arrayArgumentAggregationMethodReference().forOperator("$or"));
|
||||
map.put("not", arrayArgumentAggregationMethodReference().forOperator("$not"));
|
||||
|
||||
// SET OPERATORS
|
||||
map.put("setEquals", arrayArgumentAggregationMethodReference().forOperator("$setEquals"));
|
||||
map.put("setIntersection", arrayArgumentAggregationMethodReference().forOperator("$setIntersection"));
|
||||
map.put("setUnion", arrayArgumentAggregationMethodReference().forOperator("$setUnion"));
|
||||
map.put("setDifference", arrayArgumentAggregationMethodReference().forOperator("$setDifference"));
|
||||
// 2nd.
|
||||
map.put("setIsSubset", "$setIsSubset"); // Returns true if all elements of the 1st set appear in the 2nd set.
|
||||
map.put("anyElementTrue", "$anyElementTrue"); // Returns whether any elements of a set evaluate to true.
|
||||
map.put("allElementsTrue", "$allElementsTrue"); // Returns whether no element of a set evaluates to false.
|
||||
map.put("setIsSubset", arrayArgumentAggregationMethodReference().forOperator("$setIsSubset"));
|
||||
map.put("anyElementTrue", arrayArgumentAggregationMethodReference().forOperator("$anyElementTrue"));
|
||||
map.put("allElementsTrue", arrayArgumentAggregationMethodReference().forOperator("$allElementsTrue"));
|
||||
|
||||
map.put("cmp", "$cmp"); // Returns: 0 if the two values are equivalent, 1 if the first value is greater than the
|
||||
// second, and -1 if the first value is less than the second.
|
||||
map.put("eq", "$eq"); // Returns true if the values are equivalent.
|
||||
map.put("gt", "$gt"); // Returns true if the first value is greater than the second.
|
||||
map.put("gte", "$gte"); // Returns true if the first value is greater than or equal to the second.
|
||||
map.put("lt", "$lt"); // Returns true if the first value is less than the second.
|
||||
map.put("lte", "$lte"); // Returns true if the first value is less than or equal to the second.
|
||||
map.put("ne", "$ne"); // Returns true if the values are not equivalent.
|
||||
// COMPARISON OPERATORS
|
||||
map.put("cmp", arrayArgumentAggregationMethodReference().forOperator("$cmp"));
|
||||
map.put("eq", arrayArgumentAggregationMethodReference().forOperator("$eq"));
|
||||
map.put("gt", arrayArgumentAggregationMethodReference().forOperator("$gt"));
|
||||
map.put("gte", arrayArgumentAggregationMethodReference().forOperator("$gte"));
|
||||
map.put("lt", arrayArgumentAggregationMethodReference().forOperator("$lt"));
|
||||
map.put("lte", arrayArgumentAggregationMethodReference().forOperator("$lte"));
|
||||
map.put("ne", arrayArgumentAggregationMethodReference().forOperator("$ne"));
|
||||
|
||||
map.put("abs", "$abs"); // Returns the absolute value of a number.;
|
||||
map.put("add", "$add"); // Adds numbers to return the sum, or adds numbers and a date to return a new date.
|
||||
map.put("ceil", "$ceil"); // Returns the smallest integer greater than or equal to the specified number.
|
||||
map.put("divide", "$divide"); // Returns the result of dividing the first number by the second.
|
||||
map.put("exp", "$exp"); // Raises e to the specified exponent.
|
||||
map.put("floor", "$floor"); // Returns the largest integer less than or equal to the specified number.
|
||||
map.put("ln", "$ln"); // Calculates the natural log of a number.
|
||||
map.put("log", "$log"); // Calculates the log of a number in the specified base.
|
||||
map.put("log10", "$log10"); // Calculates the log base 10 of a number.
|
||||
map.put("mod", "$mod"); // Returns the remainder of the first number divided by the second.
|
||||
map.put("multiply", "$multiply"); // Multiplies numbers to return the product.
|
||||
map.put("pow", "$pow"); // Raises a number to the specified exponent.
|
||||
map.put("sqrt", "$sqrt"); // Calculates the square root.
|
||||
map.put("subtract", "$subtract"); // Returns the result of subtracting the second value from the first. If the
|
||||
// two values are numbers, return the difference. If the two values are dates, return the difference in
|
||||
// milliseconds.
|
||||
map.put("trunc", "$trunc"); // Truncates a number to its integer.
|
||||
// ARITHMETIC OPERATORS
|
||||
map.put("abs", singleArgumentAggregationMethodReference().forOperator("$abs"));
|
||||
map.put("add", arrayArgumentAggregationMethodReference().forOperator("$add"));
|
||||
map.put("ceil", singleArgumentAggregationMethodReference().forOperator("$ceil"));
|
||||
map.put("divide", arrayArgumentAggregationMethodReference().forOperator("$divide"));
|
||||
map.put("exp", singleArgumentAggregationMethodReference().forOperator("$exp"));
|
||||
map.put("floor", singleArgumentAggregationMethodReference().forOperator("$floor"));
|
||||
map.put("ln", singleArgumentAggregationMethodReference().forOperator("$ln"));
|
||||
map.put("log", arrayArgumentAggregationMethodReference().forOperator("$log"));
|
||||
map.put("log10", singleArgumentAggregationMethodReference().forOperator("$log10"));
|
||||
map.put("mod", arrayArgumentAggregationMethodReference().forOperator("$mod"));
|
||||
map.put("multiply", arrayArgumentAggregationMethodReference().forOperator("$multiply"));
|
||||
map.put("pow", arrayArgumentAggregationMethodReference().forOperator("$pow"));
|
||||
map.put("sqrt", singleArgumentAggregationMethodReference().forOperator("$sqrt"));
|
||||
map.put("subtract", arrayArgumentAggregationMethodReference().forOperator("$subtract"));
|
||||
map.put("trunc", singleArgumentAggregationMethodReference().forOperator("$trunc"));
|
||||
|
||||
map.put("concat", "$concat"); // Concatenates two strings.
|
||||
map.put("substr", "$substr"); // Takes a string and returns portion of that string.
|
||||
map.put("toLower", "$toLower"); // Converts a string to lowercase.
|
||||
map.put("toUpper", "$toUpper"); // Converts a string to uppercase.
|
||||
map.put("strcasecmp", "$strcasecmp"); // Compares two strings and returns an integer that reflects the comparison.
|
||||
// STRING OPERATORS
|
||||
map.put("concat", arrayArgumentAggregationMethodReference().forOperator("$concat"));
|
||||
map.put("strcasecmp", arrayArgumentAggregationMethodReference().forOperator("$strcasecmp"));
|
||||
map.put("substr", arrayArgumentAggregationMethodReference().forOperator("$substr"));
|
||||
map.put("toLower", singleArgumentAggregationMethodReference().forOperator("$toLower"));
|
||||
map.put("toUpper", singleArgumentAggregationMethodReference().forOperator("$toUpper"));
|
||||
map.put("strcasecmp", arrayArgumentAggregationMethodReference().forOperator("$strcasecmp"));
|
||||
|
||||
map.put("meta", "$meta"); // Access text search metadata.
|
||||
// TEXT SEARCH OPERATORS
|
||||
map.put("meta", singleArgumentAggregationMethodReference().forOperator("$meta"));
|
||||
|
||||
map.put("arrayElemAt", "$arrayElemAt"); // Returns the element at the specified array index.
|
||||
map.put("concatArrays", "$concatArrays"); // Concatenates arrays to return the concatenated array.
|
||||
map.put("filter", "$filter"); // Selects a subset of the array to return an array with only the elements that
|
||||
// match the filter condition.
|
||||
map.put("isArray", "$isArray"); // Determines if the operand is an array. Returns a boolean.
|
||||
map.put("size", "$size"); // Returns the number of elements in the array.
|
||||
map.put("slice", "$slice"); // Returns a subset of an array.
|
||||
// ARRAY OPERATORS
|
||||
map.put("arrayElemAt", arrayArgumentAggregationMethodReference().forOperator("$arrayElemAt"));
|
||||
map.put("concatArrays", arrayArgumentAggregationMethodReference().forOperator("$concatArrays"));
|
||||
map.put("filter", mapArgumentAggregationMethodReference().forOperator("$filter") //
|
||||
.mappingParametersTo("input", "as", "cond"));
|
||||
map.put("isArray", singleArgumentAggregationMethodReference().forOperator("$isArray"));
|
||||
map.put("size", singleArgumentAggregationMethodReference().forOperator("$size"));
|
||||
map.put("slice", arrayArgumentAggregationMethodReference().forOperator("$slice"));
|
||||
|
||||
map.put("map", "$map"); // Applies a subexpression to each element of an array and returns the array of
|
||||
// resulting values in order.
|
||||
map.put("let", "$let"); // Defines variables for use within the scope of a subexpression and returns the result
|
||||
// of the subexpression.
|
||||
// VARIABLE OPERATORS
|
||||
map.put("map", mapArgumentAggregationMethodReference().forOperator("$map") //
|
||||
.mappingParametersTo("input", "as", "in"));
|
||||
map.put("let", mapArgumentAggregationMethodReference().forOperator("$let").mappingParametersTo("vars", "in"));
|
||||
|
||||
map.put("literal", "$literal"); // Return a value without parsing.
|
||||
// LITERAL OPERATORS
|
||||
map.put("literal", singleArgumentAggregationMethodReference().forOperator("$literal"));
|
||||
|
||||
map.put("dayOfYear", "$dayOfYear"); // Converts a date to a number between 1 and 366.
|
||||
map.put("dayOfMonth", "$dayOfMonth"); // Converts a date to a number between 1 and 31.
|
||||
map.put("dayOfWeek", "$dayOfWeek"); // Converts a date to a number between 1 and 7.
|
||||
map.put("year", "$year"); // Converts a date to the full year.
|
||||
map.put("month", "$month"); // Converts a date into a number between 1 and 12.
|
||||
map.put("week", "$week"); // Converts a date into a number between 0 and 53
|
||||
map.put("hour", "$hour"); // Converts a date into a number between 0 and 23.
|
||||
map.put("minute", "$minute"); // Converts a date into a number between 0 and 59.
|
||||
map.put("second", "$second"); // Converts a date into a number between 0 and 59. May be 60 to account for leap
|
||||
// seconds.
|
||||
map.put("millisecond", "$millisecond"); // Returns the millisecond portion of a date as an integer between 0 and
|
||||
// 999.
|
||||
map.put("dateToString", "$dateToString"); // Returns the date as a formatted string.
|
||||
// DATE OPERATORS
|
||||
map.put("dayOfYear", singleArgumentAggregationMethodReference().forOperator("$dayOfYear"));
|
||||
map.put("dayOfMonth", singleArgumentAggregationMethodReference().forOperator("$dayOfMonth"));
|
||||
map.put("dayOfWeek", singleArgumentAggregationMethodReference().forOperator("$dayOfWeek"));
|
||||
map.put("year", singleArgumentAggregationMethodReference().forOperator("$year"));
|
||||
map.put("month", singleArgumentAggregationMethodReference().forOperator("$month"));
|
||||
map.put("week", singleArgumentAggregationMethodReference().forOperator("$week"));
|
||||
map.put("hour", singleArgumentAggregationMethodReference().forOperator("$hour"));
|
||||
map.put("minute", singleArgumentAggregationMethodReference().forOperator("$minute"));
|
||||
map.put("second", singleArgumentAggregationMethodReference().forOperator("$second"));
|
||||
map.put("millisecond", singleArgumentAggregationMethodReference().forOperator("$millisecond"));
|
||||
map.put("dateToString", mapArgumentAggregationMethodReference().forOperator("$dateToString") //
|
||||
.mappingParametersTo("format", "date"));
|
||||
|
||||
map.put("cond", "$cond"); // A ternary operator that evaluates one expression, and depending on the result,
|
||||
// returns the value of one of the other two expressions.
|
||||
map.put("ifNull", "$ifNull"); // Returns either the non-null result of the first expression or the result of the
|
||||
// second expression if the first expression results in a null result.
|
||||
// CONDITIONAL OPERATORS
|
||||
map.put("cond", mapArgumentAggregationMethodReference().forOperator("$cond") //
|
||||
.mappingParametersTo("if", "then", "else"));
|
||||
map.put("ifNull", arrayArgumentAggregationMethodReference().forOperator("$ifNull"));
|
||||
|
||||
// GROUP OPERATORS
|
||||
map.put("sum", arrayArgumentAggregationMethodReference().forOperator("$sum"));
|
||||
map.put("avg", arrayArgumentAggregationMethodReference().forOperator("$avg"));
|
||||
map.put("first", singleArgumentAggregationMethodReference().forOperator("$first"));
|
||||
map.put("last", singleArgumentAggregationMethodReference().forOperator("$last"));
|
||||
map.put("max", arrayArgumentAggregationMethodReference().forOperator("$max"));
|
||||
map.put("min", arrayArgumentAggregationMethodReference().forOperator("$min"));
|
||||
map.put("push", singleArgumentAggregationMethodReference().forOperator("$push"));
|
||||
map.put("addToSet", singleArgumentAggregationMethodReference().forOperator("$addToSet"));
|
||||
map.put("stdDevPop", arrayArgumentAggregationMethodReference().forOperator("$stdDevPop"));
|
||||
map.put("stdDevSamp", arrayArgumentAggregationMethodReference().forOperator("$stdDevSamp"));
|
||||
|
||||
FUNCTIONS = Collections.unmodifiableMap(map);
|
||||
}
|
||||
@@ -127,10 +151,144 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
|
||||
/**
|
||||
* Returns the name of the method.
|
||||
*
|
||||
* @Deprecated since 1.10. Please use {@link #getMethodReference()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getMethodName() {
|
||||
|
||||
AggregationMethodReference methodReference = getMethodReference();
|
||||
return methodReference != null ? methodReference.getMongoOperator() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link AggregationMethodReference}.
|
||||
*
|
||||
* @return can be {@literal null}.
|
||||
* @since 1.10
|
||||
*/
|
||||
public AggregationMethodReference getMethodReference() {
|
||||
|
||||
String name = getName();
|
||||
String methodName = name.substring(0, name.indexOf('('));
|
||||
return FUNCTIONS.get(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public static final class AggregationMethodReference {
|
||||
|
||||
private final String mongoOperator;
|
||||
private final ArgumentType argumentType;
|
||||
private final String[] argumentMap;
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationMethodReference}.
|
||||
*
|
||||
* @param mongoOperator can be {@literal null}.
|
||||
* @param argumentType can be {@literal null}.
|
||||
* @param argumentMap can be {@literal null}.
|
||||
*/
|
||||
private AggregationMethodReference(String mongoOperator, ArgumentType argumentType, String[] argumentMap) {
|
||||
|
||||
this.mongoOperator = mongoOperator;
|
||||
this.argumentType = argumentType;
|
||||
this.argumentMap = argumentMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MongoDB specific operator.
|
||||
*
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
public String getMongoOperator() {
|
||||
return this.mongoOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ArgumentType} used by the MongoDB.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public ArgumentType getArgumentType() {
|
||||
return this.argumentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property names in order order of appearance in resulting operation.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
public String[] getArgumentMap() {
|
||||
return argumentMap != null ? argumentMap : new String[] {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for a {@link ArgumentType#SINGLE} argument.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
static AggregationMethodReference singleArgumentAggregationMethodReference() {
|
||||
return new AggregationMethodReference(null, ArgumentType.SINGLE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for an {@link ArgumentType#ARRAY} argument.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
static AggregationMethodReference arrayArgumentAggregationMethodReference() {
|
||||
return new AggregationMethodReference(null, ArgumentType.ARRAY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for a {@link ArgumentType#MAP} argument.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
static AggregationMethodReference mapArgumentAggregationMethodReference() {
|
||||
return new AggregationMethodReference(null, ArgumentType.MAP, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for a given {@literal aggregationExpressionOperator} reusing
|
||||
* previously set arguments.
|
||||
*
|
||||
* @param aggregationExpressionOperator should not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
AggregationMethodReference forOperator(String aggregationExpressionOperator) {
|
||||
return new AggregationMethodReference(aggregationExpressionOperator, argumentType, argumentMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for mapping actual parameters within the AST to the given
|
||||
* {@literal aggregationExpressionProperties} reusing previously set arguments. <br />
|
||||
* <strong>NOTE:</strong> Can only be applied to {@link AggregationMethodReference} of type
|
||||
* {@link ArgumentType#MAP}.
|
||||
*
|
||||
* @param aggregationExpressionProperties should not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
AggregationMethodReference mappingParametersTo(String... aggregationExpressionProperties) {
|
||||
|
||||
Assert.isTrue(ObjectUtils.nullSafeEquals(argumentType, ArgumentType.MAP),
|
||||
"Parameter mapping can only be applied to AggregationMethodReference with MAPPED ArgumentType.");
|
||||
return new AggregationMethodReference(mongoOperator, argumentType, aggregationExpressionProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual argument type to use when mapping parameters to MongoDB specific format.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public enum ArgumentType {
|
||||
SINGLE, ARRAY, MAP
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.spel;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.SpelNode;
|
||||
import org.springframework.expression.spel.ast.OperatorNot;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
*/
|
||||
public class NotOperatorNode extends ExpressionNode {
|
||||
|
||||
private final OperatorNot operatorNode;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionNode} from the given {@link OperatorNot} and {@link ExpressionState}.
|
||||
*
|
||||
* @param node must not be {@literal null}.
|
||||
* @param state must not be {@literal null}.
|
||||
*/
|
||||
protected NotOperatorNode(OperatorNot node, ExpressionState state) {
|
||||
|
||||
super(node, state);
|
||||
this.operatorNode = node;
|
||||
}
|
||||
|
||||
public String getMongoOperator() {
|
||||
return "$not";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -17,41 +17,76 @@ package org.springframework.data.mongodb.core.spel;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
import org.springframework.expression.spel.ast.OpAnd;
|
||||
import org.springframework.expression.spel.ast.OpDivide;
|
||||
import org.springframework.expression.spel.ast.OpEQ;
|
||||
import org.springframework.expression.spel.ast.OpGE;
|
||||
import org.springframework.expression.spel.ast.OpGT;
|
||||
import org.springframework.expression.spel.ast.OpLE;
|
||||
import org.springframework.expression.spel.ast.OpLT;
|
||||
import org.springframework.expression.spel.ast.OpMinus;
|
||||
import org.springframework.expression.spel.ast.OpModulus;
|
||||
import org.springframework.expression.spel.ast.OpMultiply;
|
||||
import org.springframework.expression.spel.ast.OpNE;
|
||||
import org.springframework.expression.spel.ast.OpOr;
|
||||
import org.springframework.expression.spel.ast.OpPlus;
|
||||
import org.springframework.expression.spel.ast.Operator;
|
||||
import org.springframework.expression.spel.ast.OperatorPower;
|
||||
|
||||
/**
|
||||
* An {@link ExpressionNode} representing an operator.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class OperatorNode extends ExpressionNode {
|
||||
|
||||
private static final Map<String, String> OPERATORS;
|
||||
private static final Set<Class> SUPPORTED_MATH_OPERATORS;
|
||||
|
||||
static {
|
||||
|
||||
Map<String, String> map = new HashMap<String, String>(6);
|
||||
Map<String, String> map = new HashMap<String, String>(14, 1);
|
||||
|
||||
map.put("+", "$add");
|
||||
map.put("-", "$subtract");
|
||||
map.put("*", "$multiply");
|
||||
map.put("/", "$divide");
|
||||
map.put("%", "$mod");
|
||||
map.put("^", "$pow");
|
||||
map.put("==", "$eq");
|
||||
map.put("!=", "$ne");
|
||||
map.put(">", "$gt");
|
||||
map.put(">=", "$gte");
|
||||
map.put("<", "$lt");
|
||||
map.put("<=", "$lte");
|
||||
|
||||
map.put("and", "and");
|
||||
map.put("or", "or");
|
||||
map.put("!", "not");
|
||||
map.put("and", "$and");
|
||||
map.put("or", "$or");
|
||||
|
||||
OPERATORS = Collections.unmodifiableMap(map);
|
||||
|
||||
Set<Class> set = new HashSet<Class>(12, 1);
|
||||
set.add(OpMinus.class);
|
||||
set.add(OpPlus.class);
|
||||
set.add(OpMultiply.class);
|
||||
set.add(OpDivide.class);
|
||||
set.add(OpModulus.class);
|
||||
set.add(OperatorPower.class);
|
||||
set.add(OpNE.class);
|
||||
set.add(OpEQ.class);
|
||||
set.add(OpGT.class);
|
||||
set.add(OpGE.class);
|
||||
set.add(OpLT.class);
|
||||
set.add(OpLE.class);
|
||||
|
||||
SUPPORTED_MATH_OPERATORS = Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
private final Operator operator;
|
||||
@@ -73,8 +108,16 @@ public class OperatorNode extends ExpressionNode {
|
||||
*/
|
||||
@Override
|
||||
public boolean isMathematicalOperation() {
|
||||
return operator instanceof OpMinus || operator instanceof OpPlus || operator instanceof OpMultiply
|
||||
|| operator instanceof OpDivide || operator instanceof OpModulus;
|
||||
return SUPPORTED_MATH_OPERATORS.contains(operator.getClass());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.spel.ExpressionNode#isConjunctionOperator()
|
||||
*/
|
||||
@Override
|
||||
public boolean isLogicalOperator() {
|
||||
return operator instanceof OpOr || operator instanceof OpAnd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +135,13 @@ public class OperatorNode extends ExpressionNode {
|
||||
* @return
|
||||
*/
|
||||
public String getMongoOperator() {
|
||||
|
||||
if (!OPERATORS.containsKey(operator.getOperatorName())) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unknown operator name. Cannot translate %s into its MongoDB aggregation function representation.",
|
||||
operator.getOperatorName()));
|
||||
}
|
||||
|
||||
return OPERATORS.get(operator.getOperatorName());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.data.mongodb.core.Person;
|
||||
* @see DATAMONGO-774
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class SpelExpressionTransformerUnitTests {
|
||||
|
||||
@@ -72,7 +73,7 @@ public class SpelExpressionTransformerUnitTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void shouldThrowExceptionOnUnknownOperand() {
|
||||
transform("a ^ 1");
|
||||
transform("a++");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -202,16 +203,695 @@ public class SpelExpressionTransformerUnitTests {
|
||||
assertThat(transform("a.b + a.c"), is((Object) Document.parse("{ \"$add\" : [ \"$a.b\" , \"$a.c\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderStringFunctions() {
|
||||
public void shouldRenderMethodReferenceNodeAnd() {
|
||||
assertThat(transform("and(a, b)"), is((Object) Document.parse("{ \"$and\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
assertThat(transform("concat(a, b)"), is((Object) Document.parse("{ \"$concat\" : [ \"$a\" , \"$b\"]}")));
|
||||
assertThat(transform("substr(a, 1, 2)"), is((Object) Document.parse("{ \"$substr\" : [ \"$a\" , 1 , 2]}")));
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeOr() {
|
||||
assertThat(transform("or(a, b)"), is((Object) Document.parse("{ \"$or\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeNot() {
|
||||
assertThat(transform("not(a)"), is((Object) Document.parse("{ \"$not\" : [ \"$a\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSetEquals() {
|
||||
assertThat(transform("setEquals(a, b)"), is((Object) Document.parse("{ \"$setEquals\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSetEqualsForArrays() {
|
||||
assertThat(transform("setEquals(new int[]{1,2,3}, new int[]{4,5,6})"),
|
||||
is((Object) Document.parse("{ \"$setEquals\" : [ [ 1 , 2 , 3] , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSetEqualsMixedArrays() {
|
||||
assertThat(transform("setEquals(a, new int[]{4,5,6})"), is((Object) Document.parse("{ \"$setEquals\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSetIntersection() {
|
||||
assertThat(transform("setIntersection(a, new int[]{4,5,6})"),
|
||||
is((Object) Document.parse("{ \"$setIntersection\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSetUnion() {
|
||||
assertThat(transform("setUnion(a, new int[]{4,5,6})"), is((Object) Document.parse("{ \"$setUnion\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSeDifference() {
|
||||
assertThat(transform("setDifference(a, new int[]{4,5,6})"), is((Object) Document.parse("{ \"$setDifference\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSetIsSubset() {
|
||||
assertThat(transform("setIsSubset(a, new int[]{4,5,6})"), is((Object) Document.parse("{ \"$setIsSubset\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceAnyElementTrue() {
|
||||
assertThat(transform("anyElementTrue(a)"), is((Object) Document.parse("{ \"$anyElementTrue\" : [ \"$a\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceAllElementsTrue() {
|
||||
assertThat(transform("allElementsTrue(a, new int[]{4,5,6})"),
|
||||
is((Object) Document.parse("{ \"$allElementsTrue\" : [ \"$a\" , [ 4 , 5 , 6]]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceCmp() {
|
||||
assertThat(transform("cmp(a, 250)"), is((Object) Document.parse("{ \"$cmp\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceEq() {
|
||||
assertThat(transform("eq(a, 250)"), is((Object) Document.parse("{ \"$eq\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceGt() {
|
||||
assertThat(transform("gt(a, 250)"), is((Object) Document.parse("{ \"$gt\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceGte() {
|
||||
assertThat(transform("gte(a, 250)"), is((Object) Document.parse("{ \"$gte\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLt() {
|
||||
assertThat(transform("lt(a, 250)"), is((Object) Document.parse("{ \"$lt\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLte() {
|
||||
assertThat(transform("lte(a, 250)"), is((Object) Document.parse("{ \"$lte\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNe() {
|
||||
assertThat(transform("ne(a, 250)"), is((Object) Document.parse("{ \"$ne\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceAbs() {
|
||||
assertThat(transform("abs(1)"), is((Object) Document.parse("{ \"$abs\" : 1}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceAdd() {
|
||||
assertThat(transform("add(a, 250)"), is((Object) Document.parse("{ \"$add\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceCeil() {
|
||||
assertThat(transform("ceil(7.8)"), is((Object) Document.parse("{ \"$ceil\" : 7.8}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceDivide() {
|
||||
assertThat(transform("divide(a, 250)"), is((Object) Document.parse("{ \"$divide\" : [ \"$a\" , 250]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceExp() {
|
||||
assertThat(transform("exp(2)"), is((Object) Document.parse("{ \"$exp\" : 2}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceFloor() {
|
||||
assertThat(transform("floor(2)"), is((Object) Document.parse("{ \"$floor\" : 2}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLn() {
|
||||
assertThat(transform("ln(2)"), is((Object) Document.parse("{ \"$ln\" : 2}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLog() {
|
||||
assertThat(transform("log(100, 10)"), is((Object) Document.parse("{ \"$log\" : [ 100 , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLog10() {
|
||||
assertThat(transform("log10(100)"), is((Object) Document.parse("{ \"$log10\" : 100}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeMod() {
|
||||
assertThat(transform("mod(a, b)"), is((Object) Document.parse("{ \"$mod\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeMultiply() {
|
||||
assertThat(transform("multiply(a, b)"), is((Object) Document.parse("{ \"$multiply\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodePow() {
|
||||
assertThat(transform("pow(a, 2)"), is((Object) Document.parse("{ \"$pow\" : [ \"$a\" , 2]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSqrt() {
|
||||
assertThat(transform("sqrt(2)"), is((Object) Document.parse("{ \"$sqrt\" : 2}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSubtract() {
|
||||
assertThat(transform("subtract(a, b)"), is((Object) Document.parse("{ \"$subtract\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceTrunc() {
|
||||
assertThat(transform("trunc(2.1)"), is((Object) Document.parse("{ \"$trunc\" : 2.1}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeConcat() {
|
||||
assertThat(transform("concat(a, b, 'c')"), is((Object) Document.parse("{ \"$concat\" : [ \"$a\" , \"$b\" , \"c\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSubstrc() {
|
||||
assertThat(transform("substr(a, 0, 1)"), is((Object) Document.parse("{ \"$substr\" : [ \"$a\" , 0 , 1]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceToLower() {
|
||||
assertThat(transform("toLower(a)"), is((Object) Document.parse("{ \"$toLower\" : \"$a\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceToUpper() {
|
||||
assertThat(transform("toUpper(a)"), is((Object) Document.parse("{ \"$toUpper\" : \"$a\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeStrCaseCmp() {
|
||||
assertThat(transform("strcasecmp(a, b)"), is((Object) Document.parse("{ \"$strcasecmp\" : [ \"$a\" , \"$b\"]}")));
|
||||
assertThat(transform("toLower(a)"), is((Object) Document.parse("{ \"$toLower\" : [ \"$a\"]}")));
|
||||
assertThat(transform("toUpper(a)"), is((Object) Document.parse("{ \"$toUpper\" : [ \"$a\"]}")));
|
||||
assertThat(transform("toUpper(toLower(a))"),
|
||||
is((Object) Document.parse("{ \"$toUpper\" : [ { \"$toLower\" : [ \"$a\"]}]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceMeta() {
|
||||
assertThat(transform("meta('textScore')"), is((Object) Document.parse("{ \"$meta\" : \"textScore\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeArrayElemAt() {
|
||||
assertThat(transform("arrayElemAt(a, 10)"), is((Object) Document.parse("{ \"$arrayElemAt\" : [ \"$a\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeConcatArrays() {
|
||||
assertThat(transform("concatArrays(a, b, c)"), is((Object) Document.parse("{ \"$concatArrays\" : [ \"$a\" , \"$b\" , \"$c\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeFilter() {
|
||||
assertThat(transform("filter(a, 'num', '$$num' > 10)"),
|
||||
is((Object) Document.parse("{ \"$filter\" : { \"input\" : \"$a\" , \"as\" : \"num\" , \"cond\" : { \"$gt\" : [ \"$$num\" , 10]}}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceIsArray() {
|
||||
assertThat(transform("isArray(a)"), is((Object) Document.parse("{ \"$isArray\" : \"$a\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceIsSize() {
|
||||
assertThat(transform("size(a)"), is((Object) Document.parse("{ \"$size\" : \"$a\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSlice() {
|
||||
assertThat(transform("slice(a, 10)"), is((Object) Document.parse("{ \"$slice\" : [ \"$a\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeMap() {
|
||||
assertThat(transform("map(quizzes, 'grade', '$$grade' + 2)"), is(
|
||||
(Object) Document.parse("{ \"$map\" : { \"input\" : \"$quizzes\" , \"as\" : \"grade\" , \"in\" : { \"$add\" : [ \"$$grade\" , 2]}}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeLet() {
|
||||
assertThat(transform("let({low:1, high:'$$low'}, gt('$$low', '$$high'))"), is(
|
||||
(Object) Document.parse("{ \"$let\" : { \"vars\" : { \"low\" : 1 , \"high\" : \"$$low\"} , \"in\" : { \"$gt\" : [ \"$$low\" , \"$$high\"]}}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLiteral() {
|
||||
assertThat(transform("literal($1)"), is((Object) Document.parse("{ \"$literal\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceDayOfYear() {
|
||||
assertThat(transform("dayOfYear($1)"), is((Object) Document.parse("{ \"$dayOfYear\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceDayOfMonth() {
|
||||
assertThat(transform("dayOfMonth($1)"), is((Object) Document.parse("{ \"$dayOfMonth\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceDayOfWeek() {
|
||||
assertThat(transform("dayOfWeek($1)"), is((Object) Document.parse("{ \"$dayOfWeek\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceYear() {
|
||||
assertThat(transform("year($1)"), is((Object) Document.parse("{ \"$year\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceMonth() {
|
||||
assertThat(transform("month($1)"), is((Object) Document.parse("{ \"$month\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceWeek() {
|
||||
assertThat(transform("week($1)"), is((Object) Document.parse("{ \"$week\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceHour() {
|
||||
assertThat(transform("hour($1)"), is((Object) Document.parse("{ \"$hour\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceMinute() {
|
||||
assertThat(transform("minute($1)"), is((Object) Document.parse("{ \"$minute\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceSecond() {
|
||||
assertThat(transform("second($1)"), is((Object) Document.parse("{ \"$second\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceMillisecond() {
|
||||
assertThat(transform("millisecond($1)"), is((Object) Document.parse("{ \"$millisecond\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceDateToString() {
|
||||
assertThat(transform("dateToString('%Y-%m-%d', $date)"),
|
||||
is((Object) Document.parse("{ \"$dateToString\" : { \"format\" : \"%Y-%m-%d\" , \"date\" : \"$date\"}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceCond() {
|
||||
assertThat(transform("cond(qty > 250, 30, 20)"),
|
||||
is((Object) Document.parse("{ \"$cond\" : { \"if\" : { \"$gt\" : [ \"$qty\" , 250]} , \"then\" : 30 , \"else\" : 20}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeIfNull() {
|
||||
assertThat(transform("ifNull(a, 10)"), is((Object) Document.parse("{ \"$ifNull\" : [ \"$a\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeSum() {
|
||||
assertThat(transform("sum(a, b)"), is((Object) Document.parse("{ \"$sum\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeAvg() {
|
||||
assertThat(transform("avg(a, b)"), is((Object) Document.parse("{ \"$avg\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceFirst() {
|
||||
assertThat(transform("first($1)"), is((Object) Document.parse("{ \"$first\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceLast() {
|
||||
assertThat(transform("last($1)"), is((Object) Document.parse("{ \"$last\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeMax() {
|
||||
assertThat(transform("max(a, b)"), is((Object) Document.parse("{ \"$max\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeMin() {
|
||||
assertThat(transform("min(a, b)"), is((Object) Document.parse("{ \"$min\" : [ \"$a\" , \"$b\"]}")));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodePush() {
|
||||
assertThat(transform("push({'item':'$item', 'quantity':'$qty'})"), is((Object) Document.parse("{ \"$push\" : { \"item\" : \"$item\" , \"quantity\" : \"$qty\"}}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceAddToSet() {
|
||||
assertThat(transform("addToSet($1)"), is((Object) Document.parse("{ \"$addToSet\" : \"$1\"}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeStdDevPop() {
|
||||
assertThat(transform("stdDevPop(scores.score)"), is((Object) Document.parse("{ \"$stdDevPop\" : [ \"$scores.score\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderMethodReferenceNodeStdDevSamp() {
|
||||
assertThat(transform("stdDevSamp(age)"), is((Object) Document.parse("{ \"$stdDevSamp\" : [ \"$age\"]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeEq() {
|
||||
assertThat(transform("foo == 10"), is((Object) Document.parse("{ \"$eq\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeNe() {
|
||||
assertThat(transform("foo != 10"), is((Object) Document.parse("{ \"$ne\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeGt() {
|
||||
assertThat(transform("foo > 10"), is((Object) Document.parse("{ \"$gt\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeGte() {
|
||||
assertThat(transform("foo >= 10"), is((Object) Document.parse("{ \"$gte\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeLt() {
|
||||
assertThat(transform("foo < 10"), is((Object) Document.parse("{ \"$lt\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeLte() {
|
||||
assertThat(transform("foo <= 10"), is((Object) Document.parse("{ \"$lte\" : [ \"$foo\" , 10]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodePow() {
|
||||
assertThat(transform("foo^2"), is((Object) Document.parse("{ \"$pow\" : [ \"$foo\" , 2]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeOr() {
|
||||
assertThat(transform("true || false"), is((Object) Document.parse("{ \"$or\" : [ true , false]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderComplexOperationNodeOr() {
|
||||
assertThat(transform("1+2 || concat(a, b) || true"),
|
||||
is((Object) Document.parse("{ \"$or\" : [ { \"$add\" : [ 1 , 2]} , { \"$concat\" : [ \"$a\" , \"$b\"]} , true]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderOperationNodeAnd() {
|
||||
assertThat(transform("true && false"), is((Object) Document.parse("{ \"$and\" : [ true , false]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderComplexOperationNodeAnd() {
|
||||
assertThat(transform("1+2 && concat(a, b) && true"),
|
||||
is((Object) Document.parse("{ \"$and\" : [ { \"$add\" : [ 1 , 2]} , { \"$concat\" : [ \"$a\" , \"$b\"]} , true]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderNotCorrectly() {
|
||||
assertThat(transform("!true"), is((Object) Document.parse("{ \"$not\" : [ true]}")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-1530
|
||||
*/
|
||||
@Test
|
||||
public void shouldRenderComplexNotCorrectly() {
|
||||
assertThat(transform("!(foo > 10)"), is((Object) Document.parse("{ \"$not\" : [ { \"$gt\" : [ \"$foo\" , 10]}]}")));
|
||||
}
|
||||
|
||||
private Object transform(String expression, Object... params) {
|
||||
|
||||
@@ -1747,6 +1747,49 @@ will be translated into the following projection expression part:
|
||||
|
||||
Have a look at an example in more context in <<mongo.aggregation.examples.example5>> and <<mongo.aggregation.examples.example6>>. You can find more usage examples for supported SpEL expression constructs in `SpelExpressionTransformerUnitTests`.
|
||||
|
||||
.Supported SpEL transformations
|
||||
[cols="2"]
|
||||
|===
|
||||
| a == b
|
||||
| { $eq : [$a, $b] }
|
||||
| a != b
|
||||
| { $ne : [$a , $b] }
|
||||
| a > b
|
||||
| { $gt : [$a, $b] }
|
||||
| a >= b
|
||||
| { $gte : [$a, $b] }
|
||||
| a < b
|
||||
| { $lt : [$a, $b] }
|
||||
| a <= b
|
||||
| { $lte : [$a, $b] }
|
||||
| a + b
|
||||
| { $add : [$a, $b] }
|
||||
| a - b
|
||||
| { $subtract : [$a, $b] }
|
||||
| a * b
|
||||
| { $multiply : [$a, $b] }
|
||||
| a / b
|
||||
| { $divide : [$a, $b] }
|
||||
| a^b
|
||||
| { $pow : [$a, $b] }
|
||||
| a % b
|
||||
| { $mod : [$a, $b] }
|
||||
| a && b
|
||||
| { $and : [$a, $b] }
|
||||
| a \|\| b
|
||||
| { $or : [$a, $b] }
|
||||
| !a
|
||||
| { $not : [$a] }
|
||||
|===
|
||||
|
||||
Next to the transformations shown in <<Supported SpEL transformations>> it is possible to use standard SpEL operations like `new` to eg. create arrays and reference expressions via their name followed by the arguments to use in brackets.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
// { $setEquals : [$a, [5, 8, 13] ] }
|
||||
.andExpression("setEquals(a, new int[]{5, 8, 13})");
|
||||
----
|
||||
|
||||
[[mongo.aggregation.examples]]
|
||||
==== Aggregation Framework Examples
|
||||
|
||||
|
||||
Reference in New Issue
Block a user