=== 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-04 08:57:35 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/ProgramIndicator.java 2015-09-07 10:45:45 +0000 @@ -71,9 +71,9 @@ public static final String VAR_VALUE_COUNT = "value_count"; public static final String VAR_ZERO_POS_VALUE_COUNT = "zero_pos_value_count"; - private static final String EXPRESSION_REGEXP = "(" + KEY_DATAELEMENT + "|" + KEY_ATTRIBUTE + "|" + KEY_PROGRAM_VARIABLE + "|" + KEY_CONSTANT + ")\\{(\\w+|" + + public static final String EXPRESSION_REGEXP = "(" + KEY_DATAELEMENT + "|" + KEY_ATTRIBUTE + "|" + KEY_PROGRAM_VARIABLE + "|" + KEY_CONSTANT + ")\\{(\\w+|" + VAR_INCIDENT_DATE + "|" + VAR_ENROLLMENT_DATE + "|" + VAR_CURRENT_DATE + ")" + SEPARATOR_ID + "?(\\w*)\\}"; - private static final String SQL_FUNC_REGEXP = "d2:(.+?)\\(([^,]+)\\,?([^,]*)\\,?([^,]*)\\)"; + public static final String SQL_FUNC_REGEXP = "d2:(.+?)\\(([^\\),]+),?([^,\\)]+)?,?([^,\\)]+)?\\)"; 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-04 10:49:08 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/DefaultProgramIndicatorService.java 2015-09-07 10:45:45 +0000 @@ -29,6 +29,8 @@ */ import com.google.common.collect.ImmutableMap; + +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; @@ -522,10 +524,10 @@ while ( matcher.find() ) { - String func = matcher.group( 1 ); - String arg1 = matcher.group( 2 ); - String arg2 = matcher.group( 3 ); - String arg3 = matcher.group( 4 ); + String func = StringUtils.trim( matcher.group( 1 ) ); + String arg1 = StringUtils.trim( matcher.group( 2 ) ); + String arg2 = StringUtils.trim( matcher.group( 3 ) ); + String arg3 = StringUtils.trim( matcher.group( 4 ) ); SqlFunction function = SQL_FUNC_MAP.get( func ); @@ -732,173 +734,6 @@ // ------------------------------------------------------------------------- /** - * <<<<<<< TREE - * Get indicator value for the given arguments. If programStageInstance - * argument is null, the program stage instance will be retrieved based on - * the given program instance in combination with the program stage from the indicator expression. - * - * @param indicator the indicator, must be not null. - * @param programInstance the program instance, can be null. - * @param programStageInstance the program stage instance, can be null. - */ - private Double getValue( ProgramIndicator indicator, ProgramInstance programInstance, ProgramStageInstance programStageInstance ) - { - StringBuffer buffer = new StringBuffer(); - - String expression = indicator.getExpression(); - - Matcher matcher = ProgramIndicator.EXPRESSION_PATTERN.matcher( expression ); - - int valueCount = 0; - int zeroPosValueCount = 0; - - while ( matcher.find() ) - { - String key = matcher.group( 1 ); - String uid = matcher.group( 2 ); - - if ( ProgramIndicator.KEY_DATAELEMENT.equals( key ) ) - { - String de = matcher.group( 3 ); - ProgramStage programStage = programStageService.getProgramStage( uid ); - DataElement dataElement = dataElementService.getDataElement( de ); - - if ( programStage != null && dataElement != null ) - { - ProgramStageInstance psi = programStageInstance != null ? - programStageInstance : - programStageInstanceService.getProgramStageInstance( programInstance, programStage ); - - TrackedEntityDataValue dataValue = dataValueService.getTrackedEntityDataValue( psi, dataElement ); - - if ( dataValue == null ) - { - return null; - } - - String value = dataValue.getValue(); - - if ( ValueType.DATE == dataElement.getValueType() ) - { - value = DateUtils.daysBetween( new Date(), DateUtils.getDefaultDate( value ) ) + " "; - } - - matcher.appendReplacement( buffer, value ); - - valueCount++; - zeroPosValueCount = isZeroOrPositive( value ) ? (zeroPosValueCount + 1) : zeroPosValueCount; - } - else - { - return null; - } - } - else if ( ProgramIndicator.KEY_ATTRIBUTE.equals( key ) ) - { - TrackedEntityAttribute attribute = attributeService.getTrackedEntityAttribute( uid ); - - if ( attribute != null ) - { - TrackedEntityAttributeValue attributeValue = attributeValueService.getTrackedEntityAttributeValue( - programInstance.getEntityInstance(), attribute ); - - if ( attributeValue != null ) - { - String value = attributeValue.getValue(); - - if ( ValueType.DATE == attribute.getValueType() ) - { - value = DateUtils.daysBetween( new Date(), DateUtils.getDefaultDate( value ) ) + " "; - } - - matcher.appendReplacement( buffer, value ); - - valueCount++; - zeroPosValueCount = isZeroOrPositive( value ) ? (zeroPosValueCount + 1) : zeroPosValueCount; - } - else - { - return null; - } - } - else - { - return null; - } - } - else if ( ProgramIndicator.KEY_CONSTANT.equals( key ) ) - { - Constant constant = constantService.getConstant( uid ); - - if ( constant != null ) - { - matcher.appendReplacement( buffer, String.valueOf( constant.getValue() ) ); - } - else - { - return null; - } - } - else if ( ProgramIndicator.KEY_PROGRAM_VARIABLE.equals( key ) ) - { - Date currentDate = new Date(); - Date date = null; - - if ( ProgramIndicator.VAR_ENROLLMENT_DATE.equals( uid ) ) - { - date = programInstance.getEnrollmentDate(); - } - else if ( ProgramIndicator.VAR_INCIDENT_DATE.equals( uid ) ) - { - date = programInstance.getDateOfIncident(); - } - else if ( ProgramIndicator.VAR_EXECUTION_DATE.equals( uid ) ) - { - date = programStageInstance != null ? programStageInstance.getExecutionDate() : null; - } - else if ( ProgramIndicator.VAR_CURRENT_DATE.equals( uid ) ) - { - date = currentDate; - } - - if ( date != null ) - { - matcher.appendReplacement( buffer, DateUtils.daysBetween( currentDate, date ) + "" ); - } - } - } - - expression = TextUtils.appendTail( matcher, buffer ); - - // --------------------------------------------------------------------- - // Value count variable - // --------------------------------------------------------------------- - - buffer = new StringBuffer(); - matcher = ProgramIndicator.VALUECOUNT_PATTERN.matcher( expression ); - - while ( matcher.find() ) - { - String var = matcher.group( 1 ); - - if ( ProgramIndicator.VAR_VALUE_COUNT.equals( var ) ) - { - matcher.appendReplacement( buffer, String.valueOf( valueCount ) ); - } - else if ( ProgramIndicator.VAR_ZERO_POS_VALUE_COUNT.equals( var ) ) - { - matcher.appendReplacement( buffer, String.valueOf( zeroPosValueCount ) ); - } - } - - expression = TextUtils.appendTail( matcher, buffer ); - - return MathUtils.calculateExpression( expression ); - } - - /** - * ======= - * >>>>>>> MERGE-SOURCE * Creates a SQL select clause from the given program indicator variable * based on the given expression. Wraps the count variables with * nullif to avoid potential division by zero. === modified file 'dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/program/ProgramIndicatorServiceTest.java' --- dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/program/ProgramIndicatorServiceTest.java 2015-09-06 07:15:45 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/program/ProgramIndicatorServiceTest.java 2015-09-07 10:45:45 +0000 @@ -495,7 +495,7 @@ } @Test - public void testGetAnalyticsSqlWithFunctionsA() + public void testGetAnalyticsSqlWithFunctionsZingA() { String col = COL_QUOTE + deA.getUid() + COL_QUOTE; String expected = "coalesce(case when " + col + " < 0 then 0 else " + col + " end, 0)"; @@ -503,9 +503,25 @@ assertEquals( expected, programIndicatorService.getAnalyticsSQl( expression ) ); } + + @Test + public void testGetAnalyticsSqlWithFunctionsZingB() + { + String expected = + "coalesce(case when \"EZq9VbPWgML\" < 0 then 0 else \"EZq9VbPWgML\" end, 0) + " + + "coalesce(case when \"GCyeKSqlpdk\" < 0 then 0 else \"GCyeKSqlpdk\" end, 0) + " + + "coalesce(case when \"hsCmEqBcU23\" < 0 then 0 else \"hsCmEqBcU23\" end, 0)"; + + String expression = + "d2:zing(#{OXXcwl6aPCQ.EZq9VbPWgML}) + " + + "d2:zing(#{OXXcwl6aPCQ.GCyeKSqlpdk}) + " + + "d2:zing(#{OXXcwl6aPCQ.hsCmEqBcU23})"; + + assertEquals( expected, programIndicatorService.getAnalyticsSQl( expression ) ); + } @Test - public void testGetAnalyticsSqlWithFunctionsB() + public void testGetAnalyticsSqlWithFunctionsOizp() { String col = COL_QUOTE + deA.getUid() + COL_QUOTE; String expected = "coalesce(case when " + col + " >= 0 then 1 else 0 end, 0)"; @@ -515,7 +531,7 @@ } @Test - public void testGetAnalyticsSqlWithFunctionsC() + public void testGetAnalyticsSqlWithFunctionsDaysBetween() { String col1 = COL_QUOTE + deA.getUid() + COL_QUOTE; String col2 = COL_QUOTE + deB.getUid() + COL_QUOTE; @@ -526,7 +542,7 @@ } @Test - public void testGetAnalyticsSqlWithFunctionsD() + public void testGetAnalyticsSqlWithFunctionsCondition() { String col1 = COL_QUOTE + deA.getUid() + COL_QUOTE; String expected = "case when (" + col1 + " > 3) then 10 else 5 end"; @@ -534,7 +550,23 @@ assertEquals( expected, programIndicatorService.getAnalyticsSQl( expression ) ); } - + + @Test + public void testGetAnalyticsSqlWithFunctionsComposite() + { + String expected = + "coalesce(case when \"EZq9VbPWgML\" < 0 then 0 else \"EZq9VbPWgML\" end, 0) + " + + "(cast(\"kts5J79K9gA\" as date) - cast(\"GCyeKSqlpdk\" as date)) + " + + "case when (80 > 70) then 100 else 50 end"; + + String expression = + "d2:zing(#{OXXcwl6aPCQ.EZq9VbPWgML}) + " + + "d2:daysBetween(#{OXXcwl6aPCQ.GCyeKSqlpdk},#{OXXcwl6aPCQ.kts5J79K9gA}) + " + + "d2:condition(80 > 70,100,50)"; + + assertEquals( expected, programIndicatorService.getAnalyticsSQl( expression ) ); + } + @Test( expected = IllegalStateException.class ) public void testGetAnalyticsSqlWithFunctionsInvalid() { === 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-08-27 22:22:39 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ConditionalSqlFunction.java 2015-09-07 10:45:45 +0000 @@ -39,10 +39,10 @@ public static final String KEY = "condition"; @Override - public String evaluate( String arg1, String arg2, String arg3 ) + public String evaluate( String condition, String trueValue, String falseValue ) { - String conditional = arg1.replaceAll( "^\"|^'|\"$|'$", "" ); + String conditional = condition.replaceAll( "^\"|^'|\"$|'$", "" ); - return "case when (" + conditional + ") then " + arg2 + " else " + arg3 + " end"; + 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-08-27 17:18:00 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/DaysBetweenSqlFunction.java 2015-09-07 10:45:45 +0000 @@ -37,8 +37,8 @@ public static final String KEY = "daysBetween"; @Override - public String evaluate( String arg1, String arg2, String arg3 ) + public String evaluate( String startDate, String endDate, String arg3 ) { - return "(cast(" + arg2 + " as date) - cast(" + arg1 + " as date))"; + 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-06 07:15:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/OneIfZeroOrPositiveSqlFunction.java 2015-09-07 10:45:45 +0000 @@ -40,8 +40,8 @@ public static final String KEY = "oizp"; @Override - public String evaluate( String arg1, String arg2, String arg3 ) + public String evaluate( String value, String arg2, String arg3 ) { - return "coalesce(case when " + arg1 + " >= 0 then 1 else 0 end, 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/ZeroIfNegativeSqlFunction.java' --- dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ZeroIfNegativeSqlFunction.java 2015-09-06 07:15:45 +0000 +++ dhis-2/dhis-support/dhis-support-commons/src/main/java/org/hisp/dhis/commons/sqlfunc/ZeroIfNegativeSqlFunction.java 2015-09-07 10:45:45 +0000 @@ -40,8 +40,8 @@ public static final String KEY = "zing"; @Override - public String evaluate( String arg1, String arg2, String arg3 ) + public String evaluate( String value, String arg2, String arg3 ) { - return "coalesce(case when " + arg1 + " < 0 then 0 else " + arg1 + " end, 0)"; + return "coalesce(case when " + value + " < 0 then 0 else " + value + " end, 0)"; } }