in grails-datamapping-core/src/main/groovy/org/grails/datastore/gorm/query/transform/DetachedCriteriaTransformer.java [1068:1244]
private void addCriteriaCall(BlockStatement newCode, String operator, Expression leftExpression, Expression rightExpression, String propertyName, List<String> propertyNames, boolean addAll, String methodToCall, VariableScope variableScope) {
if (rightExpression instanceof VariableExpression) {
String rightPropertyName = rightExpression.getText();
if (!variableScope.isReferencedLocalVariable(rightPropertyName)) {
if ((propertyNames.contains(rightPropertyName) || addAll) && PROPERTY_COMPARISON_OPERATOR_TO_CRITERIA_METHOD_MAP.containsKey(operator)) {
methodToCall = PROPERTY_COMPARISON_OPERATOR_TO_CRITERIA_METHOD_MAP.get(operator);
rightExpression = new ConstantExpression(rightPropertyName);
}
}
} else if (rightExpression instanceof MethodCallExpression) {
// potential aggregation
MethodCallExpression aggregateMethodCall = (MethodCallExpression) rightExpression;
Expression methodTarget = aggregateMethodCall.getObjectExpression();
String methodName = aggregateMethodCall.getMethodAsString();
String aggregateFunctionName = AGGREGATE_FUNCTIONS.get(methodName);
if ("of".equals(methodName) && aggregateMethodCall.getObjectExpression() instanceof MethodCallExpression) {
ArgumentListExpression arguments = (ArgumentListExpression) aggregateMethodCall.getArguments();
if (arguments.getExpressions().size() == 1 && arguments.getExpression(0) instanceof ClosureExpression) {
ClosureExpression ce = (ClosureExpression) arguments.getExpression(0);
transformClosureExpression(this.currentClassNode, ce);
aggregateMethodCall = (MethodCallExpression) aggregateMethodCall.getObjectExpression();
aggregateFunctionName = AGGREGATE_FUNCTIONS.get(aggregateMethodCall.getMethodAsString());
ArgumentListExpression aggregateMethodCallArguments = (ArgumentListExpression) aggregateMethodCall.getArguments();
if (aggregateFunctionName != null && aggregateMethodCallArguments.getExpressions().size() == 1) {
Expression expression = aggregateMethodCallArguments.getExpression(0);
String aggregatePropertyName = null;
if (expression instanceof VariableExpression || expression instanceof ConstantExpression) {
aggregatePropertyName = expression.getText();
}
boolean validProperty = aggregatePropertyName != null && propertyNames.contains(aggregatePropertyName);
if (validProperty) {
BlockStatement bs = (BlockStatement) ce.getCode();
addProjectionToCurrentBody(bs, aggregateFunctionName, aggregatePropertyName, variableScope);
rightExpression = new MethodCallExpression(new ConstructorCallExpression(getParameterizedDetachedCriteriaClassNode(null), new ArgumentListExpression(new ClassExpression(this.currentClassNode))), "build", new ArgumentListExpression(ce));
}
}
}
} else if (aggregateFunctionName != null) {
if((methodTarget instanceof VariableExpression) &&
((VariableExpression)methodTarget).isThisExpression()) {
Expression arguments = aggregateMethodCall.getArguments();
if (arguments instanceof ArgumentListExpression) {
ArgumentListExpression argList = (ArgumentListExpression) arguments;
List<Expression> expressions = argList.getExpressions();
int argCount = expressions.size();
if (argCount == 1) {
Expression expression = expressions.get(0);
String aggregatePropertyName;
if (expression instanceof VariableExpression || expression instanceof ConstantExpression) {
aggregatePropertyName = expression.getText();
} else {
sourceUnit.getErrorCollector().addError(new LocatedMessage("Cannot use aggregate function " + aggregateFunctionName + " on expressions \"" + expression.getText() + "\".", Token.newString(propertyName, aggregateMethodCall.getLineNumber(), aggregateMethodCall.getColumnNumber()), sourceUnit));
return;
}
boolean validProperty = aggregatePropertyName != null && propertyNames.contains(aggregatePropertyName);
if (validProperty) {
ClosureAndArguments closureAndArguments = new ClosureAndArguments(variableScope);
BlockStatement currentBody = closureAndArguments.getCurrentBody();
addProjectionToCurrentBody(currentBody, aggregateFunctionName, aggregatePropertyName, variableScope);
rightExpression = closureAndArguments.getClosureExpression();
if ("property".equals(aggregateFunctionName) && METHOD_TO_SUBQUERY_MAP.containsKey(methodToCall)) {
methodToCall = methodToCall + "All";
}
} else {
sourceUnit.getErrorCollector().addError(new LocatedMessage("Cannot use aggregate function " + aggregateFunctionName + " on property \"" + aggregatePropertyName + "\" - no such property on class " + this.currentClassNode.getName() + " exists.", Token.newString(propertyName, aggregateMethodCall.getLineNumber(), aggregateMethodCall.getColumnNumber()), sourceUnit));
}
}
}
}
} else if (isFunctionCall(aggregateMethodCall)) {
// TODO: Allow function calls on right hand arguments
ArgumentListExpression existingArgs = (ArgumentListExpression) aggregateMethodCall.getArguments();
Expression propertyNameExpression = existingArgs.getExpression(0);
sourceUnit.getErrorCollector().addError(new LocatedMessage("Function call " + aggregateFunctionName + " not allowed on property \"" + propertyNameExpression.getText() + "\". Function calls can currently only be used on the left-hand side of expressions", Token.newString(propertyName, aggregateMethodCall.getLineNumber(), aggregateMethodCall.getColumnNumber()), sourceUnit));
return;
//
// ArgumentListExpression newArgs = new ArgumentListExpression();
// ArgumentListExpression constructorArgs = new ArgumentListExpression();
// constructorArgs.addExpression(new ConstantExpression(methodName));
// ClassNode criterionClassNode = OPERATOR_TO_PROPERTY_CRITERION_METHOD_MAP.get(operator);
// if (criterionClassNode != null) {
// ArgumentListExpression criterionConstructorArguments = new ArgumentListExpression();
// if (!(propertyNameExpression instanceof ConstantExpression)) {
// propertyNameExpression = new ConstantExpression(propertyNameExpression.getText());
// }
// criterionConstructorArguments.addExpression(new ConstantExpression(propertyName));
// criterionConstructorArguments.addExpression(propertyNameExpression);
//
// constructorArgs.addExpression(new ConstructorCallExpression(criterionClassNode, criterionConstructorArguments));
// constructorArgs.addExpression(new ConstantExpression(true));
// ConstructorCallExpression constructorCallExpression = new ConstructorCallExpression(FUNCTION_CALL_CRITERION, constructorArgs);
// newArgs.addExpression(constructorCallExpression );
//
// newCode.addStatement(new ExpressionStatement(new MethodCallExpression(THIS_EXPRESSION, "add", newArgs)));
// }
// else {
// sourceUnit.getErrorCollector().addError(new LocatedMessage("Function call "+aggregateFunctionName+" not allowed on property \""+propertyNameExpression.getText()+"\".", Token.newString(propertyName,aggregateMethodCall.getLineNumber(), aggregateMethodCall.getColumnNumber()), sourceUnit));
// }
// return;
}
} else {
if ("like".equals(methodToCall) && rightExpression instanceof BitwiseNegationExpression) {
methodToCall = "rlike";
BitwiseNegationExpression bne = (BitwiseNegationExpression) rightExpression;
rightExpression = bne.getExpression();
} else if ("inList".equals(methodToCall) && rightExpression instanceof RangeExpression) {
methodToCall = "between";
RangeExpression re = (RangeExpression) rightExpression;
ArgumentListExpression betweenArgs = new ArgumentListExpression();
betweenArgs.addExpression(new ConstantExpression(propertyName))
.addExpression(re.getFrom())
.addExpression(re.getTo());
rightExpression = betweenArgs;
}
}
ArgumentListExpression arguments;
if (rightExpression instanceof ArgumentListExpression) {
arguments = (ArgumentListExpression) rightExpression;
} else if (rightExpression instanceof ConstantExpression) {
ConstantExpression constant = (ConstantExpression) rightExpression;
if (constant.getValue() == null) {
boolean singleArg = false;
if (operator.equals(EQUALS_OPERATOR)) {
singleArg = true;
methodToCall = IS_NULL_CRITERION;
} else if (operator.equals("!=")) {
singleArg = true;
methodToCall = "isNotNull";
}
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(propertyName));
if (!singleArg) {
arguments.addExpression(rightExpression);
}
} else {
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(propertyName))
.addExpression(rightExpression);
}
} else if(rightExpression instanceof PropertyExpression) {
PropertyExpression pe = (PropertyExpression) rightExpression;
String property = pe.getObjectExpression().getText();
if((leftExpression instanceof PropertyExpression ) && aliases.containsKey(property)) {
aliasExpressions.add(pe);
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(((PropertyExpression)leftExpression).getPropertyAsString()));
arguments.addExpression(new ConstantExpression(pe.getText()));
methodToCall = PROPERTY_COMPARISON_OPERATOR_TO_CRITERIA_METHOD_MAP.get(operator);
}
else if((leftExpression instanceof VariableExpression) && aliases.containsKey(property)) {
aliasExpressions.add(pe);
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(((VariableExpression)leftExpression).getName()));
arguments.addExpression(new ConstantExpression(pe.getText()));
methodToCall = PROPERTY_COMPARISON_OPERATOR_TO_CRITERIA_METHOD_MAP.get(operator);
}
else {
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(propertyName))
.addExpression(rightExpression);
}
} else {
arguments = new ArgumentListExpression();
arguments.addExpression(new ConstantExpression(propertyName))
.addExpression(rightExpression);
}
newCode.addStatement(new ExpressionStatement(new MethodCallExpression(new VariableExpression("this"), methodToCall, arguments)));
}