gitgabrio commented on code in PR #6299:
URL: 
https://github.com/apache/incubator-kie-drools/pull/6299#discussion_r2039513888


##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateAndTimeFunction.java:
##########
@@ -122,33 +126,33 @@ public FEELFnResult<TemporalAccessor> 
invoke(@ParameterName( "year" ) Number yea
     public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "year" ) 
Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) 
Number day,
                                                  @ParameterName( "hour" ) 
Number hour, @ParameterName( "minute" ) Number minute, @ParameterName( "second" 
) Number second,
                                                  @ParameterName( "hour offset" 
) Number hourOffset ) {
-        if ( year == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "year", "cannot be null"));
-        }
-        if ( month == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "month", "cannot be null"));
-        }
-        if ( day == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
-        }
-        if ( hour == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "hour", "cannot be null"));
-        }
-        if ( minute == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "minute", "cannot be null"));
-        }
-        if ( second == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "second", "cannot be null"));
-        }
-
         try {
+            Optional<Integer> coercedYear = coerceIntegerNumber(year);

Review Comment:
   Hi @ChinchuAjith 
   Code could be rewritten with a more idiomatic usage of Optional
   
    ```java
   try {
               int coercedYear = coerceIntegerNumber(year).orElseThrow();
               int coercedMonth = coerceIntegerNumber(month).orElseThrow();
               int coercedDay = coerceIntegerNumber(day).orElseThrow();
               int coercedHour = coerceIntegerNumber(hour).orElseThrow();
               int coercedMinute = coerceIntegerNumber(minute).orElseThrow();
               int coercedSecond = coerceIntegerNumber(second).orElseThrow();
               if (hourOffset != null) {
                   Optional<Integer> coercedHourOffset = 
coerceIntegerNumber(hourOffset);
                   return 
coercedHourOffset.<FEELFnResult<TemporalAccessor>>map(integer -> 
FEELFnResult.ofResult(
                           OffsetDateTime.of(
                                   coercedYear, coercedMonth, coercedDay,
                                   coercedHour, coercedMinute, coercedSecond,
                                   0, 
ZoneOffset.ofHours(integer)))).orElseGet(() -> FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "hour offset", "could not be coerced to 
Integer")));
               } else {
                   return FEELFnResult.ofResult(
                           LocalDateTime.of(
                                   coercedYear, coercedMonth, coercedDay,
                                   coercedHour, coercedMinute, coercedSecond)
                   );
               }
           } catch (NoSuchElementException e) { // thrown by 
Optional.orElseThrow()
               return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "coercion", "One or more input values 
could not be coerced to Integer: either null or not a valid Number."));
           } catch (DateTimeException e) {
               return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "input parameters date-parsing 
exception", e));
           }
   ```



##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java:
##########
@@ -66,12 +67,47 @@ public static BigDecimal getBigDecimalOrNull(Object value) {
         return null;
     }
 
+    /**
+     * The method handles various numeric types and converts the given object 
to an Integer
+     * Returns null If the conversion is not possible.
+     *
+     * @param value : The object to be converted.
+     * @return : An Integer representation of the value, or null if conversion 
is not possible.

Review Comment:
   Thanks @ChinchuAjith 
   IINW, this method is used only once, and inside this very class.
   Could you please:
   1. remove public accessor
   2. move it to bottom of class (readability)
   3. refactor it to return an Optional<Integer>  (let's reduce the 
proliferation of `null`s 😄  )
   4. unit test it
   5. update javadoc
   
   Thanks!



##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/NumberEvalHelper.java:
##########
@@ -66,12 +67,47 @@ public static BigDecimal getBigDecimalOrNull(Object value) {
         return null;
     }
 
+    /**
+     * The method handles various numeric types and converts the given object 
to an Integer
+     * Returns null If the conversion is not possible.
+     *
+     * @param value : The object to be converted.
+     * @return : An Integer representation of the value, or null if conversion 
is not possible.
+     */
+    public static Integer getIntegerOrNull(Object value) {
+        if ( value instanceof BigDecimal ) {
+            return ((BigDecimal) value).intValue();
+        }
+        if ( value instanceof BigInteger ) {
+            return ((BigInteger) value).intValue();
+        }
+        if ( value instanceof Number ) {
+            return ((Number) value).intValue();
+        }
+        return null;
+    }
+
     public static Object coerceNumber(Object value) {
         if ( value instanceof Number && !(value instanceof BigDecimal) ) {
             return getBigDecimalOrNull( value );
-        } else {
+        }  else {
             return value;
         }
     }
 
+    /**
+     * Converts the given object to an integer if it is an instance of Number.
+     * else it is returned unchanged.
+     *
+     * @param value : the object to be converted
+     * @return : an integer representation of the number if applicable, 
otherwise the original value
+     */
+    public static Optional<Integer> coerceIntegerNumber(Object value) {

Review Comment:
   Could you please update the javadoc ?
   Moreover, since the called method will return an Optional<Integer> by 
itself, no need to wrap it inside another Optional



##########
kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java:
##########
@@ -34,4 +36,53 @@ void getBigDecimalOrNull() {
         
assertThat(NumberEvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new 
BigDecimal("10000000000.5"));
     }
 
+    @Test

Review Comment:
   Could you please add some unit test for NumberEvalHelper.getIntegerOrNull() ?
   Thanks!



##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DateFunction.java:
##########
@@ -71,31 +75,28 @@ public FEELFnResult<TemporalAccessor> 
invoke(@ParameterName( "from" ) String val
         }
     }
 
-    public FEELFnResult<TemporalAccessor> invoke(@ParameterName( "year" ) 
Number year, @ParameterName( "month" ) Number month, @ParameterName( "day" ) 
Number day) {
-        if ( year == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "year", "cannot be null"));
-        }
-        if ( month == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "month", "cannot be null"));
-        }
-        if ( day == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "day", "cannot be null"));
-        }
-
+    public FEELFnResult<TemporalAccessor> invoke(@ParameterName("year") Number 
year, @ParameterName("month") Number month, @ParameterName("day") Number day) {
         try {
-            return FEELFnResult.ofResult( LocalDate.of( year.intValue(), 
month.intValue(), day.intValue() ) );
+            Optional<Integer> coercedYear = coerceIntegerNumber(year);

Review Comment:
   See previous comment



##########
kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java:
##########
@@ -34,4 +36,53 @@ void getBigDecimalOrNull() {
         
assertThat(NumberEvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new 
BigDecimal("10000000000.5"));
     }
 
+    @Test
+    void coerceIntegerNumber_withBigDecimal() {
+        //Verifies that BigDecimal values are truncated (not rounded) when 
coerced to integers.
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(new 
BigDecimal("99.99"));

Review Comment:
   Could you please also test, in the same method, the other "extreme" value, 
i.e. "99.00001": it also should return 99



##########
kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/NumberEvalHelperTest.java:
##########
@@ -34,4 +36,53 @@ void getBigDecimalOrNull() {
         
assertThat(NumberEvalHelper.getBigDecimalOrNull(10000000000.5D)).isEqualTo(new 
BigDecimal("10000000000.5"));
     }
 
+    @Test
+    void coerceIntegerNumber_withBigDecimal() {
+        //Verifies that BigDecimal values are truncated (not rounded) when 
coerced to integers.
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(new 
BigDecimal("99.99"));
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(99);
+    }
+
+    @Test
+    void coerceIntegerNumber_withBigInteger() {
+        Optional<Integer> result = NumberEvalHelper.coerceIntegerNumber(new 
BigInteger("1000"));
+        assertThat(result).isPresent();
+        assertThat(result.get()).isEqualTo(1000);
+    }
+
+    @Test
+    void coerceIntegerNumber_withDouble() {

Review Comment:
   Could you please also test, in the same method, "extreme" values, e.g. 
42.009 and 42.99999: both should return 42



##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/DecimalFunction.java:
##########
@@ -38,14 +40,15 @@ public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" 
) BigDecimal n, @Para
         if ( n == null ) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "n", "cannot be null"));
         }
-        if ( scale == null ) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
+        Optional<Integer> scaleObj = 
NumberEvalHelper.coerceIntegerNumber(scale);
+        if(scaleObj.isEmpty()) {
+            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be a non-null Number 
value."));
         }
+        int scaleInt = scaleObj.get();
         // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+        if (scaleInt < -6111 || scaleInt > 6176) {

Review Comment:
   See comment on CeilingFunction



##########
kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/runtime/functions/CeilingFunction.java:
##########
@@ -45,11 +47,14 @@ public FEELFnResult<BigDecimal> invoke(@ParameterName( "n" 
) BigDecimal n, @Para
         if ( scale == null ) {
             return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "cannot be null"));
         }
-        // Based on Table 76: Semantics of numeric functions, the scale is in 
range −6111 .. 6176
-        if (scale.compareTo(BigDecimal.valueOf(-6111)) < 0 || 
scale.compareTo(BigDecimal.valueOf(6176)) > 0) {
-            return FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "must be in range between -6111 
to 6176."));
+        Optional<Integer> scaleObj = 
NumberEvalHelper.coerceIntegerNumber(scale);

Review Comment:
   Hi @ChinchuAjith 
   Optional could be used in more idiomatic way to express the same behavior:
   
   ```java
   Optional<Integer> scaleObj = NumberEvalHelper.coerceIntegerNumber(scale);
   AtomicReference<FEELFnResult<BigDecimal>> toReturn = new AtomicReference<>();
   scaleObj.ifPresentOrElse(scaleInt -> {
                                        if (scaleInt < -6111 || scaleInt > 
6176) {
                                            
toReturn.set(FEELFnResult.ofError(new InvalidParametersEvent(Severity.ERROR, 
"scale", "must be in range between -6111 and 6176.")));
                                        } else {
                                            
toReturn.set(FEELFnResult.ofResult(n.setScale(scaleInt, RoundingMode.CEILING)));
                                        }
                                    },
                                    () -> toReturn.set(FEELFnResult.ofError(new 
InvalidParametersEvent(Severity.ERROR, "scale", "should be a Number type"))));
   return toReturn.get();
   ```
   
   Your choice, anyway



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to