private void addCriteriaCall()

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)));
    }