=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java 2015-09-18 12:14:44 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java 2015-09-24 19:18:20 +0000 @@ -76,7 +76,8 @@ public static final String EXPRESSION_PREFIX_REGEXP = KEY_DATAELEMENT + "|" + KEY_ATTRIBUTE + "|" + KEY_PROGRAM_VARIABLE + "|" + KEY_CONSTANT; public static final String EXPRESSION_REGEXP = "(" + EXPRESSION_PREFIX_REGEXP + ")\\{([\\w\\_]+)" + SEPARATOR_ID + "?(\\w*)\\}"; - public static final String SQL_FUNC_REGEXP = "d2:(.+?)\\(([^\\),]+),?([^,\\)]+)?,?([^,\\)]+)?\\)"; + public static final String SQL_FUNC_REGEXP = "d2:(.+?)\\((.*?)\\)"; + public static final String ARGS_SPLIT = ","; public static final Pattern EXPRESSION_PATTERN = Pattern.compile( EXPRESSION_REGEXP ); public static final Pattern SQL_FUNC_PATTERN = Pattern.compile( SQL_FUNC_REGEXP ); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-09-21 11:22:28 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-09-24 19:18:20 +0000 @@ -28,6 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import static org.apache.commons.lang3.StringUtils.trim; import static org.hisp.dhis.i18n.I18nUtils.i18n; import java.util.Date; @@ -37,7 +38,6 @@ import java.util.Set; import java.util.regex.Matcher; -import org.apache.commons.lang3.StringUtils; import org.hisp.dhis.common.ValueType; import org.hisp.dhis.commons.sqlfunc.ConditionalSqlFunction; import org.hisp.dhis.commons.sqlfunc.DaysBetweenSqlFunction; @@ -67,8 +67,6 @@ import com.google.common.collect.ImmutableMap; -import static org.apache.commons.lang3.StringUtils.trim; - /** * @author Chau Thu Tran */ @@ -497,21 +495,30 @@ while ( matcher.find() ) { - String func = StringUtils.trim( matcher.group( 1 ) ); - String arg1 = getSubstitutedElementsAnalyticsSql( trim( matcher.group( 2 ) ), false ); - String arg2 = getSubstitutedElementsAnalyticsSql( trim( matcher.group( 3 ) ), false ); - String arg3 = getSubstitutedElementsAnalyticsSql( trim( matcher.group( 4 ) ), false ); - - SqlFunction function = SQL_FUNC_MAP.get( func ); - - if ( function == null ) + String func = trim( matcher.group( 1 ) ); + String arguments = trim( matcher.group( 2 ) ); + + if ( func != null && arguments != null ) { - throw new IllegalStateException( "Function not recognized: " + func ); + String[] args = arguments.split( ProgramIndicator.ARGS_SPLIT ); + + for ( int i = 0; i < args.length; i++ ) + { + String arg = getSubstitutedElementsAnalyticsSql( trim( args[i] ), false ); + args[i] = arg; + } + + SqlFunction function = SQL_FUNC_MAP.get( func ); + + if ( function == null ) + { + throw new IllegalStateException( "Function not recognized: " + func ); + } + + String result = function.evaluate( args ); + + matcher.appendReplacement( buffer, result ); } - - String result = function.evaluate( arg1, arg2, arg3 ); - - matcher.appendReplacement( buffer, result ); } return TextUtils.appendTail( matcher, buffer ); === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ConditionalSqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ConditionalSqlFunction.java 2015-09-07 10:45:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ConditionalSqlFunction.java 2015-09-24 19:18:20 +0000 @@ -39,8 +39,17 @@ public static final String KEY = "condition"; @Override - public String evaluate( String condition, String trueValue, String falseValue ) + public String evaluate( String... args ) { + if ( args == null || args.length != 3 ) + { + throw new IllegalArgumentException( "Illegal arguments, expected 3 arguments: condition, true-value, false-value" ); + } + + String condition = args[0]; + String trueValue = args[1]; + String falseValue = args[2]; + String conditional = condition.replaceAll( "^\"|^'|\"$|'$", "" ); return "case when (" + conditional + ") then " + trueValue + " else " + falseValue + " end"; === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/DaysBetweenSqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/DaysBetweenSqlFunction.java 2015-09-07 10:45:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/DaysBetweenSqlFunction.java 2015-09-24 19:18:20 +0000 @@ -37,8 +37,16 @@ public static final String KEY = "daysBetween"; @Override - public String evaluate( String startDate, String endDate, String arg3 ) - { + public String evaluate( String... args ) + { + if ( args == null || args.length != 2 ) + { + throw new IllegalArgumentException( "Illegal arguments, expected 2 arguments: start-date, end-date" ); + } + + String startDate = args[0]; + String endDate = args[1]; + return "(cast(" + endDate + " as date) - cast(" + startDate + " as date))"; } } === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/OneIfZeroOrPositiveSqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/OneIfZeroOrPositiveSqlFunction.java 2015-09-07 10:45:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/OneIfZeroOrPositiveSqlFunction.java 2015-09-24 19:18:20 +0000 @@ -40,8 +40,15 @@ public static final String KEY = "oizp"; @Override - public String evaluate( String value, String arg2, String arg3 ) + public String evaluate( String... args ) { + if ( args == null || args.length != 1 ) + { + throw new IllegalArgumentException( "Illegal arguments, expected 1 argument: value" ); + } + + String value = args[0]; + return "coalesce(case when " + value + " >= 0 then 1 else 0 end, 0)"; } } === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/SqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/SqlFunction.java 2015-08-27 22:22:39 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/SqlFunction.java 2015-09-24 19:18:20 +0000 @@ -36,11 +36,9 @@ /** * Evaluates the function using the given column name. * - * @param arg1 argument 1. - * @param arg2 argument 2. - * @param arg3 argument 3. + * @param args the arguments. * * @return the result of the evaluation. */ - String evaluate( String arg1, String arg2, String arg3 ); + String evaluate( String... args ); } === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ZeroIfNegativeSqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ZeroIfNegativeSqlFunction.java 2015-09-07 10:45:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ZeroIfNegativeSqlFunction.java 2015-09-24 19:18:20 +0000 @@ -40,8 +40,15 @@ public static final String KEY = "zing"; @Override - public String evaluate( String value, String arg2, String arg3 ) + public String evaluate( String... args ) { + if ( args == null || args.length != 1 ) + { + throw new IllegalArgumentException( "Illegal arguments, expected 1 argument: value" ); + } + + String value = args[0]; + return "coalesce(case when " + value + " < 0 then 0 else " + value + " end, 0)"; } } === modified file 'dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java 2015-08-27 22:22:39 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/util/ExpressionFunctions.java 2015-09-24 19:18:20 +0000 @@ -71,6 +71,26 @@ return ( value.doubleValue() >= 0d ) ? 1d : 0d; } + + public static Integer zpvc( Number... values ) + { + if ( values == null || values.length == 0 ) + { + throw new IllegalArgumentException( "Argument is null or empty: " + values ); + } + + int count = 0; + + for ( Number value : values ) + { + if ( value != null && value.doubleValue() >= 0d ) + { + count++; + } + } + + return count; + } /** * Functions which will return the true value if the condition is true, false === modified file 'dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ExpressionUtilsTest.java' --- dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ExpressionUtilsTest.java 2015-09-24 15:25:20 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/ExpressionUtilsTest.java 2015-09-24 19:18:20 +0000 @@ -63,8 +63,10 @@ assertEquals( 3d, ExpressionUtils.evaluateToDouble( "d2:daysBetween('2015-03-01','2015-03-04')", null ), DELTA ); assertEquals( 1d, ExpressionUtils.evaluateToDouble( "d2:oizp(d2:zing(3))", null ), DELTA ); assertEquals( 1d, ExpressionUtils.evaluateToDouble( "d2:zing(d2:oizp(3))", null ), DELTA ); + assertEquals( 2d, ExpressionUtils.evaluateToDouble( "d2:zpvc(1,3)", null ), DELTA ); + assertEquals( 3d, ExpressionUtils.evaluateToDouble( "d2:zpvc(1,-1,2,-3,0)", null ), DELTA ); } - + @Test public void testEvaluateToDoubleWithVars() {