tpalfy commented on a change in pull request #4223:
URL: https://github.com/apache/nifi/pull/4223#discussion_r413232172



##########
File path: 
nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/orc/PutORCTest.java
##########
@@ -460,7 +459,7 @@ private void verifyORCUsers(final Path orcUsers, final int 
numExpectedUsers, BiF
         RecordReader recordReader = reader.rows();
 
         TypeInfo typeInfo =
-                
TypeInfoUtils.getTypeInfoFromTypeString("struct<name:string,favorite_number:int,favorite_color:string,scale:double>");
+                
TypeInfoUtils.getTypeInfoFromTypeString("struct<name:string,favorite_number:int,favorite_color:string,scale:decimal>");

Review comment:
       Something's strange. This change doesn't seem to be necessary.
   Even if left as `scale:double` all tests pass.
   Note the assertion bellow expects `double`:
   ```java
                   assertEquals(10.0 * currUser, ((DoubleWritable) 
x.get(3)).get(), Double.MIN_VALUE);
   ```

##########
File path: 
nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-processors/src/test/java/org/apache/nifi/processors/orc/PutORCTest.java
##########
@@ -285,7 +284,7 @@ public void testWriteORCWithAvroLogicalTypes() throws 
IOException, Initializatio
                     final DateFormat noTimeOfDayDateFormat = new 
SimpleDateFormat("yyyy-MM-dd");
                     
noTimeOfDayDateFormat.setTimeZone(TimeZone.getTimeZone("gmt"));
                     assertEquals(noTimeOfDayDateFormat.format(dt), 
((DateWritableV2) x.get(3)).get().toString());
-                    assertEquals(dec, ((DoubleWritable) x.get(4)).get(), 
Double.MIN_VALUE);
+                    assertEquals(dec.doubleValue(), ((HiveDecimalWritable) 
x.get(4)).doubleValue(), Double.MIN_VALUE);

Review comment:
       Can't we depend on the accuracy of `BigDecimal`?
   ```suggestion
                       assertEquals(dec, ((HiveDecimalWritable) 
x.get(4)).getHiveDecimal().bigDecimalValue());
   ```

##########
File path: 
nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
##########
@@ -1266,6 +1279,46 @@ public static boolean isBooleanTypeCompatible(final 
Object value) {
         return false;
     }
 
+    public static BigDecimal toBigDecimal(final Object value, final String 
fieldName) {
+        if (value == null) {
+            return null;
+        }
+
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        }
+
+        if (value instanceof Number) {
+            final Number number = (Number) value;
+
+            if (number instanceof Byte
+                    || number instanceof Short
+                    || number instanceof Integer
+                    || number instanceof Long) {
+                return BigDecimal.valueOf(number.longValue());
+            }
+
+            if (number instanceof BigInteger) {
+                return new BigDecimal((BigInteger) number);
+            }
+
+            if (number instanceof Float || number instanceof Double) {
+                return BigDecimal.valueOf(number.doubleValue());

Review comment:
       We should probably use
   ```java
   new BigDecimal(Float.toString((Float)number))
   ```
   and
   ```java
   new BigDecimal(Double.toString((Double)number))
   ```
   According to the javadoc for this construcor:
   
   > Note: For values other than float and double NaN and ±Infinity, this 
constructor is compatible with the values returned by Float.toString(float) and 
Double.toString(double). This is generally the preferred way to convert a float 
or double into a BigDecimal, as it doesn't suffer from the unpredictability of 
the BigDecimal(double) constructor.

##########
File path: 
nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
##########
@@ -1759,6 +1812,8 @@ public static int getSQLTypeValue(final DataType 
dataType) {
                 return Types.DOUBLE;
             case FLOAT:
                 return Types.FLOAT;
+            case BIGDECIMAL:
+                return Types.NUMERIC;

Review comment:
       Wondering if it can be used for `DECIMAL` columns as well?

##########
File path: 
nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java
##########
@@ -265,6 +268,92 @@ public void testBytesToBytes() {
         assertEquals("Conversion from byte[] to String failed at char 0", 
(Object) "Hello".getBytes(StandardCharsets.UTF_16)[0], ((Byte[]) b)[0]);
     }
 
+    @Test
+    public void testConvertToBigDecimalWhenInputIsValid() {
+        // given
+        final BigDecimal expectedValue = BigDecimal.valueOf(12L);
+
+        // when & then
+        whenExpectingValidBigDecimalConversion(expectedValue, 
BigDecimal.valueOf(12L));
+        whenExpectingValidBigDecimalConversion(expectedValue, (byte) 12);
+        whenExpectingValidBigDecimalConversion(expectedValue, (short) 12);
+        whenExpectingValidBigDecimalConversion(expectedValue, 12);
+        whenExpectingValidBigDecimalConversion(expectedValue, 12L);
+        whenExpectingValidBigDecimalConversion(expectedValue, 
BigInteger.valueOf(12L));
+        whenExpectingValidBigDecimalConversion(expectedValue, 12F);
+        whenExpectingValidBigDecimalConversion(expectedValue, 12.000F);
+        whenExpectingValidBigDecimalConversion(expectedValue, 12D);
+        whenExpectingValidBigDecimalConversion(expectedValue, 12.000D);
+        whenExpectingValidBigDecimalConversion(expectedValue, "12");
+        whenExpectingValidBigDecimalConversion(expectedValue, "12.000");
+    }
+
+    @Test
+    public void testConvertToBigDecimalWhenNullInput() {
+        assertNull(DataTypeUtils.convertType(null, 
RecordFieldType.BIGDECIMAL.getDataType(), null, StandardCharsets.UTF_8));
+    }
+
+    @Test(expected = IllegalTypeConversionException.class)
+    public void testConvertToBigDecimalWhenInputStringIsInvalid() {
+        DataTypeUtils.convertType("test", 
RecordFieldType.BIGDECIMAL.getDataType(), null, StandardCharsets.UTF_8);
+    }
+
+    @Test(expected = IllegalTypeConversionException.class)
+    public void testConvertToBigDecimalWhenUnsupportedType() {
+        DataTypeUtils.convertType(new ArrayList<Double>(), 
RecordFieldType.BIGDECIMAL.getDataType(), null, StandardCharsets.UTF_8);
+    }
+
+    @Test(expected = IllegalTypeConversionException.class)
+    public void testConvertToBigDecimalWhenUnsupportedNumberType() {
+        DataTypeUtils.convertType(new DoubleAdder(), 
RecordFieldType.BIGDECIMAL.getDataType(), null, StandardCharsets.UTF_8);
+    }
+
+    @Test
+    public void testCompatibleDataTypeBigDecimal() {
+        // given
+        final DataType dataType = RecordFieldType.BIGDECIMAL.getDataType();
+
+        // when & then
+        assertTrue(DataTypeUtils.isCompatibleDataType(new 
BigDecimal("1.2345678901234567890"), dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType(new 
BigInteger("12345678901234567890"), dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType(1234567890123456789L, 
dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType(1, dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType((byte) 1, dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType((short) 1, dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType("1.2345678901234567890", 
dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType(3.1F, dataType));
+        assertTrue(DataTypeUtils.isCompatibleDataType(3.0D, dataType));
+        assertFalse(DataTypeUtils.isCompatibleDataType("1234567XYZ", 
dataType));
+        assertFalse(DataTypeUtils.isCompatibleDataType(new Long[]{1L, 2L}, 
dataType));
+    }
+
+    @Test
+    public void testInferDataTypeWithBigDecimal() {
+        assertEquals(RecordFieldType.BIGDECIMAL.getDataType(), 
DataTypeUtils.inferDataType(BigDecimal.valueOf(12L), 
RecordFieldType.BIGDECIMAL.getDataType()));

Review comment:
       The 2nd parameter for `DataTypeUtils.inferDataType` (default return 
value) is probable better to left as `null`.

##########
File path: 
nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java
##########
@@ -265,6 +268,92 @@ public void testBytesToBytes() {
         assertEquals("Conversion from byte[] to String failed at char 0", 
(Object) "Hello".getBytes(StandardCharsets.UTF_16)[0], ((Byte[]) b)[0]);
     }
 
+    @Test

Review comment:
       Can we please add a test like this?
   ```java
       @Test
       public void 
testChooseDataTypeWhenBigDecimal_vs_FLOAT_DOUBLE_BIGDECIMAL_ThenShouldReturnBIGDECIMAL()
 {
           // GIVEN
           List<DataType> dataTypes = Arrays.asList(
               RecordFieldType.FLOAT.getDataType(),
               RecordFieldType.DOUBLE.getDataType(),
               RecordFieldType.BIGDECIMAL.getDataType()
           );
   
           Object value = new BigDecimal("1.2");
           DataType expected = RecordFieldType.BIGDECIMAL.getDataType();
   
           // WHEN
           // THEN
           testChooseDataTypeAlsoReverseTypes(value, dataTypes, expected);
       }
   ```

##########
File path: 
nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/json/WriteJsonResult.java
##########
@@ -376,6 +377,9 @@ private void writeValue(final JsonGenerator generator, 
final Object value, final
             case STRING:
                 generator.writeString(coercedValue.toString());
                 break;
+            case BIGDECIMAL:
+                generator.writeNumber((BigDecimal) coercedValue);

Review comment:
       We might want
   ```java
                   
generator.writeNumber(DataTypeUtils.toBigDecimal(coercedValue, fieldName));
   ```
   just to follow conventions. I think `coercedValue` can only be `BigDecimal` 
at this point but not sure if that is by design or because of the current 
implementation.

##########
File path: 
nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/main/java/org/apache/nifi/processors/solr/SolrUtils.java
##########
@@ -463,6 +463,8 @@ private static void writeValue(final SolrInputDocument 
inputDocument, final Obje
                     
addFieldToSolrDocument(inputDocument,fieldName,(BigInteger)coercedValue,fieldsToIndex);
                 }
                 break;
+            case BIGDECIMAL:
+                addFieldToSolrDocument(inputDocument, fieldName, coercedValue, 
fieldsToIndex);

Review comment:
       I'd use `DataTypeUtils.toBigDecimal(coercedValue, fieldName)` to be safe 
and follow conventions.

##########
File path: 
nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/test/java/org/apache/nifi/schema/validation/TestStandardSchemaValidator.java
##########
@@ -145,6 +148,9 @@ public void 
testValidateCorrectSimpleTypesStrictValidation() throws ParseExcepti
 
         valueMap.put("float_as_double", 8.0F);
 
+        valueMap.put("float_as_bigdecimal", 8.0F);

Review comment:
       Minor: we might want to add `"byte/short/int/long/bigint_as_bigdecimal"` 
as well.
   Kind of redundant with the ones below but still better to have this stay a 
simplified universal test.

##########
File path: 
nifi-nar-bundles/nifi-solr-bundle/nifi-solr-processors/src/test/java/org/apache/nifi/processors/solr/SolrUtilsTest.java
##########
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.solr;
+
+import org.apache.nifi.serialization.SimpleRecordSchema;
+import org.apache.nifi.serialization.record.MapRecord;
+import org.apache.nifi.serialization.record.Record;
+import org.apache.nifi.serialization.record.RecordField;
+import org.apache.nifi.serialization.record.RecordFieldType;
+import org.apache.solr.common.SolrInputDocument;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SolrUtilsTest {
+
+    @Mock
+    private SolrInputDocument inputDocument;
+
+    @Test
+    public void test() throws Exception {
+        // given
+        final String value = 
"12345678901234567890.123456789012345678901234567890";
+        final BigDecimal bigDecimalValue = new BigDecimal(value);
+        final List<RecordField> fields = Collections.singletonList(new 
RecordField("test", RecordFieldType.BIGDECIMAL.getDataType()));
+
+        final Map<String, Object> values = new HashMap<>();
+        values.put("test", bigDecimalValue);
+
+        final Record record = new MapRecord(new SimpleRecordSchema(fields), 
values);
+        final List<String> fieldsToIndex = 
Collections.singletonList("parent_test");
+
+        // when
+        SolrUtils.writeRecord(record, inputDocument, fieldsToIndex, "parent");
+
+        // then
+        Mockito.verify(inputDocument, 
Mockito.times(1)).addField(Mockito.eq("parent_test"), 
Mockito.eq(bigDecimalValue));

Review comment:
       Minor: could be simplified to
   ```java
           Mockito.verify(inputDocument).addField("parent_test", 
bigDecimalValue);
   ```




----------------------------------------------------------------
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.

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


Reply via email to