fix issue with ExprEval.bestEffortOf and mixed type arrays containing ARRAY<COMPLEX<json>> and other complicated casts (#14710)

This commit is contained in:
Clint Wylie 2023-08-01 09:25:14 -07:00 committed by GitHub
parent 8a10b46dd8
commit 2e456d25ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 450 additions and 118 deletions

View File

@ -235,6 +235,9 @@ public abstract class ExprEval<T>
*/
private static Class convertType(@Nullable Class existing, Class next)
{
if (existing != null && existing.equals(Object.class)) {
return existing;
}
if (Number.class.isAssignableFrom(next) || next == String.class || next == Boolean.class) {
// coerce booleans
if (next == Boolean.class) {
@ -866,7 +869,7 @@ public abstract class ExprEval<T>
@Override
public Object[] asArray()
{
return isNumericNull() ? null : new Object[] {value.doubleValue()};
return value == null ? null : new Object[]{valueOrDefault().doubleValue()};
}
@Override
@ -888,11 +891,13 @@ public abstract class ExprEval<T>
case DOUBLE:
return ExprEval.ofDoubleArray(asArray());
case LONG:
return ExprEval.ofLongArray(value == null ? null : new Object[] {value.longValue()});
return ExprEval.ofLongArray(value == null ? null : new Object[]{value.longValue()});
case STRING:
return ExprEval.ofStringArray(value == null ? null : new Object[] {value.toString()});
return ExprEval.ofStringArray(value == null ? null : new Object[]{value.toString()});
default:
ExpressionType elementType = (ExpressionType) castTo.getElementType();
return new ArrayExprEval(castTo, new Object[]{castTo(elementType).value()});
}
break;
case COMPLEX:
if (ExpressionType.NESTED_DATA.equals(castTo)) {
return new NestedDataExprEval(value);
@ -945,7 +950,7 @@ public abstract class ExprEval<T>
@Override
public Object[] asArray()
{
return isNumericNull() ? null : new Object[] {value.longValue()};
return value == null ? null : new Object[]{valueOrDefault().longValue()};
}
@Override
@ -963,15 +968,20 @@ public abstract class ExprEval<T>
case STRING:
return ExprEval.of(asString());
case ARRAY:
if (value == null) {
return new ArrayExprEval(castTo, null);
}
switch (castTo.getElementType().getType()) {
case DOUBLE:
return ExprEval.ofDoubleArray(value == null ? null : new Object[] {value.doubleValue()});
return ExprEval.ofDoubleArray(new Object[]{value.doubleValue()});
case LONG:
return ExprEval.ofLongArray(asArray());
case STRING:
return ExprEval.ofStringArray(value == null ? null : new Object[] {value.toString()});
return ExprEval.ofStringArray(new Object[]{value.toString()});
default:
ExpressionType elementType = (ExpressionType) castTo.getElementType();
return new ArrayExprEval(castTo, new Object[]{castTo(elementType).value()});
}
break;
case COMPLEX:
if (ExpressionType.NESTED_DATA.equals(castTo)) {
return new NestedDataExprEval(value);
@ -1062,7 +1072,7 @@ public abstract class ExprEval<T>
@Override
public Object[] asArray()
{
return value == null ? null : new Object[] {value};
return value == null ? null : new Object[]{value};
}
private int computeInt()
@ -1134,18 +1144,24 @@ public abstract class ExprEval<T>
case STRING:
return this;
case ARRAY:
if (value == null) {
return new ArrayExprEval(castTo, null);
}
final Number number = computeNumber();
switch (castTo.getElementType().getType()) {
case DOUBLE:
return ExprEval.ofDoubleArray(
value == null ? null : new Object[] {number == null ? null : number.doubleValue()}
new Object[]{number == null ? null : number.doubleValue()}
);
case LONG:
return ExprEval.ofLongArray(
value == null ? null : new Object[] {number == null ? null : number.longValue()}
new Object[]{number == null ? null : number.longValue()}
);
case STRING:
return ExprEval.ofStringArray(value == null ? null : new Object[] {value});
return ExprEval.ofStringArray(new Object[]{value});
default:
ExpressionType elementType = (ExpressionType) castTo.getElementType();
return new ArrayExprEval(castTo, new Object[]{castTo(elementType).value()});
}
case COMPLEX:
if (ExpressionType.NESTED_DATA.equals(castTo)) {

View File

@ -451,10 +451,30 @@ public class EvalTest extends InitializedNullHandlingTest
).asArray()
);
Assert.assertThrows(IAE.class, () -> ExprEval.ofLong(1234L).castTo(nestedArray));
Assert.assertThrows(IAE.class, () -> ExprEval.of("hello").castTo(nestedArray));
Assert.assertThrows(IAE.class, () -> ExprEval.ofDouble(1.234).castTo(nestedArray));
Assert.assertThrows(IAE.class, () -> ExprEval.ofComplex(ExpressionType.NESTED_DATA, 1234L).castTo(nestedArray));
cast = ExprEval.ofLong(1234L).castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{1234L},
cast.asArray()
);
cast = ExprEval.of("hello").castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{"hello"},
cast.asArray()
);
cast = ExprEval.ofDouble(1.234).castTo(nestedArray);
Assert.assertEquals(nestedArray, cast.type());
Assert.assertArrayEquals(
new Object[]{1.234},
cast.asArray()
);
cast = ExprEval.ofComplex(ExpressionType.NESTED_DATA, 1234L).castTo(nestedArray);
Assert.assertArrayEquals(
new Object[]{1234L},
cast.asArray()
);
Assert.assertEquals(nestedArray, cast.type());
}
@Test
@ -1146,145 +1166,145 @@ public class EvalTest extends InitializedNullHandlingTest
Assert.assertEquals("notbase64", eval.value());
// arrays
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, ImmutableList.of(1L, 2L, 3L));
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new int[]{1, 2, 3});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, null, 3L});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, null, 3L});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, null, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
// arrays might have to fall back to using 'bestEffortOf', but will cast it to the expected output type
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {"1", "2", "3"});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new String[] {"1", "2", "3"});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new String[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {"1", "2", "wat", "3"});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{"1", "2", "wat", "3"});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, null, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new double[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {1.0, 2.0, null, 3.0});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2.0, null, 3.0});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, null, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, null, 3L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[] {1.0, 2L, "3", true, false});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L, 1L, 0L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L, 1L, 0L}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new float[] {1.0f, 2.0f, 3.0f});
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.LONG_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1L, 2L, 3L}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1L, 2L, 3L}, (Object[]) eval.value());
// etc
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Double[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new double[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new double[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {"1", "2", "3"});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {"1", "2", "wat", "3"});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{"1", "2", "wat", "3"});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, null, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, null, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {1L, 2L, 3L});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new long[] {1L, 2L, 3L});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new long[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {1L, 2L, null, 3L});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1L, 2L, null, 3L});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, null, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, null, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2L, "3", true, false});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0, 1.0, 0.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0, 1.0, 0.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Float[] {1.0f, 2.0f, 3.0f});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new Float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new float[] {1.0f, 2.0f, 3.0f});
eval = ExprEval.ofType(ExpressionType.DOUBLE_ARRAY, new float[]{1.0f, 2.0f, 3.0f});
Assert.assertEquals(ExpressionType.DOUBLE_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{1.0, 2.0, 3.0}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[] {"1", "2", "3"});
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {"1", "2", "3"}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{"1", "2", "3"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[] {1L, 2L, 3L});
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1L, 2L, 3L});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {"1", "2", "3"}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{"1", "2", "3"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[] {1.0, 2.0, 3.0});
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1.0, 2.0, 3.0});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {"1.0", "2.0", "3.0"}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{"1.0", "2.0", "3.0"}, (Object[]) eval.value());
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[] {1.0, 2L, "3", true, false});
eval = ExprEval.ofType(ExpressionType.STRING_ARRAY, new Object[]{1.0, 2L, "3", true, false});
Assert.assertEquals(ExpressionType.STRING_ARRAY, eval.type());
Assert.assertArrayEquals(new Object[] {"1.0", "2", "3", "true", "false"}, (Object[]) eval.value());
Assert.assertArrayEquals(new Object[]{"1.0", "2", "3", "true", "false"}, (Object[]) eval.value());
// nested arrays
ExpressionType nestedLongArray = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.LONG_ARRAY);
final Object[] expectedLongArray = new Object[]{
new Object[] {1L, 2L, 3L},
new Object[] {5L, null, 9L},
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[] {2L, 4L, 6L}
new Object[]{2L, 4L, 6L}
};
List<?> longArrayInputs = Arrays.asList(
new Object[]{
new Object[] {1L, 2L, 3L},
new Object[] {5L, null, 9L},
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[] {2L, 4L, 6L}
new Object[]{2L, 4L, 6L}
},
Arrays.asList(
new Object[] {1L, 2L, 3L},
new Object[] {5L, null, 9L},
new Object[]{1L, 2L, 3L},
new Object[]{5L, null, 9L},
null,
new Object[] {2L, 4L, 6L}
new Object[]{2L, 4L, 6L}
),
Arrays.asList(
Arrays.asList(1L, 2L, 3L),
@ -1312,18 +1332,18 @@ public class EvalTest extends InitializedNullHandlingTest
ExpressionType nestedDoubleArray = ExpressionTypeFactory.getInstance().ofArray(ExpressionType.DOUBLE_ARRAY);
final Object[] expectedDoubleArray = new Object[]{
new Object[] {1.1, 2.2, 3.3},
new Object[] {5.5, null, 9.9},
new Object[]{1.1, 2.2, 3.3},
new Object[]{5.5, null, 9.9},
null,
new Object[] {2.2, 4.4, 6.6}
new Object[]{2.2, 4.4, 6.6}
};
List<?> doubleArrayInputs = Arrays.asList(
new Object[]{
new Object[] {1.1, 2.2, 3.3},
new Object[] {5.5, null, 9.9},
new Object[]{1.1, 2.2, 3.3},
new Object[]{5.5, null, 9.9},
null,
new Object[] {2.2, 4.4, 6.6}
new Object[]{2.2, 4.4, 6.6}
},
new Object[]{
Arrays.asList(1.1, 2.2, 3.3),
@ -1338,10 +1358,10 @@ public class EvalTest extends InitializedNullHandlingTest
Arrays.asList(2.2, 4.4, 6.6)
),
new Object[]{
new Object[] {"1.1", "2.2", "3.3"},
new Object[]{"1.1", "2.2", "3.3"},
Arrays.asList("5.5", null, "9.9"),
null,
new String[] {"2.2", "4.4", "6.6"}
new String[]{"2.2", "4.4", "6.6"}
}
);
@ -1392,38 +1412,38 @@ public class EvalTest extends InitializedNullHandlingTest
assertBestEffortOf(1.0f, ExpressionType.DOUBLE, 1.0);
// arrays
assertBestEffortOf(new Object[] {1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new Object[] {1L, 2L, null, 3L}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, null, 3L});
assertBestEffortOf(ImmutableList.of(1L, 2L, 3L), ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new long[] {1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new Object[] {1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new Integer[] {1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new int[] {1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[] {1L, 2L, 3L});
assertBestEffortOf(new Object[]{1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[]{1L, 2L, null, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, null, 3L});
assertBestEffortOf(ImmutableList.of(1L, 2L, 3L), ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new long[]{1L, 2L, 3L}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Integer[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new int[]{1, 2, 3}, ExpressionType.LONG_ARRAY, new Object[]{1L, 2L, 3L});
assertBestEffortOf(new Object[] {1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new Object[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(
new Object[] {null, 1.0, 2.0, 3.0},
new Object[]{null, 1.0, 2.0, 3.0},
ExpressionType.DOUBLE_ARRAY,
new Object[] {null, 1.0, 2.0, 3.0}
new Object[]{null, 1.0, 2.0, 3.0}
);
assertBestEffortOf(new Double[] {1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new double[] {1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new Object[] {1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new Float[] {1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new float[] {1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0, 3.0});
assertBestEffortOf(new Double[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new double[]{1.0, 2.0, 3.0}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Object[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Float[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new float[]{1.0f, 2.0f, 3.0f}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0, 3.0});
assertBestEffortOf(new Object[] {"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[] {"1", "2", "3"});
assertBestEffortOf(new String[] {"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[] {"1", "2", "3"});
assertBestEffortOf(ImmutableList.of("1", "2", "3"), ExpressionType.STRING_ARRAY, new Object[] {"1", "2", "3"});
assertBestEffortOf(new Object[]{"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
assertBestEffortOf(new String[]{"1", "2", "3"}, ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
assertBestEffortOf(ImmutableList.of("1", "2", "3"), ExpressionType.STRING_ARRAY, new Object[]{"1", "2", "3"});
// arrays end up as the least restrictive type
assertBestEffortOf(new Object[] {1.0, 2L}, ExpressionType.DOUBLE_ARRAY, new Object[] {1.0, 2.0});
assertBestEffortOf(new Object[]{1.0, 2L}, ExpressionType.DOUBLE_ARRAY, new Object[]{1.0, 2.0});
// arrays end up as the least restrictive type
assertBestEffortOf(
new Object[] {1.0, 2L, "3", true, false},
new Object[]{1.0, 2L, "3", true, false},
ExpressionType.STRING_ARRAY,
new Object[] {"1.0", "2", "3", "true", "false"}
new Object[]{"1.0", "2", "3", "true", "false"}
);
assertBestEffortOf(

View File

@ -22,6 +22,7 @@ package org.apache.druid.math.expr;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.druid.collections.SerializablePair;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.NonnullPair;
import org.apache.druid.java.util.common.StringUtils;
@ -333,6 +334,49 @@ public class ExprEvalTest extends InitializedNullHandlingTest
coerced.rhs
);
Map<String, Object> nested1 = ImmutableMap.of("x", 1L, "y", 2L);
List<Object> mixedObject = ImmutableList.of(
"a",
1L,
3.0,
nested1
);
coerced = ExprEval.coerceListToArray(mixedObject, false);
Assert.assertEquals(
ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA),
coerced.lhs
);
Assert.assertArrayEquals(
new Object[]{
"a",
1L,
3.0,
nested1
},
coerced.rhs
);
List<Object> mixedObject2 = ImmutableList.of(
nested1,
"a",
1L,
3.0
);
coerced = ExprEval.coerceListToArray(mixedObject2, false);
Assert.assertEquals(
ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA),
coerced.lhs
);
Assert.assertArrayEquals(
new Object[]{
nested1,
"a",
1L,
3.0
},
coerced.rhs
);
List<List<String>> nestedLists = ImmutableList.of(
ImmutableList.of("a", "b", "c"),
ImmutableList.of("d", "e", "f")
@ -344,7 +388,7 @@ public class ExprEvalTest extends InitializedNullHandlingTest
coerced.rhs
);
Map<String, Object> nested1 = ImmutableMap.of("x", 1L, "y", 2L);
Map<String, Object> nested2 = ImmutableMap.of("x", 4L, "y", 5L);
List<Map<String, Object>> listUnknownComplex = ImmutableList.of(nested1, nested2);
coerced = ExprEval.coerceListToArray(listUnknownComplex, false);
@ -421,6 +465,66 @@ public class ExprEvalTest extends InitializedNullHandlingTest
coerced.rhs
);
List<Object> mixedNested2 = ImmutableList.of(
"a",
1L,
3.0,
ImmutableList.of("a", "b", "c"),
ImmutableList.of(1L, 2L, 3L),
ImmutableList.of(3.0, 4.0, 5.0),
ImmutableList.of(nested1, nested2, nested3)
);
coerced = ExprEval.coerceListToArray(mixedNested2, false);
Assert.assertEquals(
ExpressionTypeFactory.getInstance().ofArray(
ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA)
),
coerced.lhs
);
Assert.assertArrayEquals(
new Object[]{
new Object[]{"a"},
new Object[]{1L},
new Object[]{3.0},
new Object[]{"a", "b", "c"},
new Object[]{1L, 2L, 3L},
new Object[]{3.0, 4.0, 5.0},
new Object[]{nested1, nested2, nested3}
},
coerced.rhs
);
List<Object> mixedNested3 = ImmutableList.of(
"a",
1L,
3.0,
nested1,
ImmutableList.of("a", "b", "c"),
ImmutableList.of(1L, 2L, 3L),
ImmutableList.of(3.0, 4.0, 5.0),
ImmutableList.of(nested1, nested2, nested3)
);
coerced = ExprEval.coerceListToArray(mixedNested3, false);
// this one is only ARRAY<COMPLEX<json>> instead of ARRAY<ARRAY<COMPLEX<json>> because of a COMPLEX<json> element..
Assert.assertEquals(
ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA),
coerced.lhs
);
Assert.assertArrayEquals(
new Object[]{
"a",
1L,
3.0,
nested1,
new Object[]{"a", "b", "c"},
new Object[]{1L, 2L, 3L},
new Object[]{3.0, 4.0, 5.0},
new Object[]{nested1, nested2, nested3}
},
coerced.rhs
);
List<List<Object>> mixedUnknown = ImmutableList.of(
ImmutableList.of("a", "b", "c"),
ImmutableList.of(1L, 2L, 3L),
@ -435,17 +539,209 @@ public class ExprEvalTest extends InitializedNullHandlingTest
}
@Test
public void testStringArrayToNumberArray()
public void testCastString()
{
ExprEval someStringArray = ExprEval.ofStringArray(new String[]{"1", "2", "foo", null, "3.3"});
Assert.assertArrayEquals(
new Object[]{1L, 2L, null, null, 3L},
someStringArray.castTo(ExpressionType.LONG_ARRAY).asArray()
);
Assert.assertArrayEquals(
new Object[]{1.0, 2.0, null, null, 3.3},
someStringArray.castTo(ExpressionType.DOUBLE_ARRAY).asArray()
ExprEval<?> eval = ExprEval.of("hello");
ExprEval<?> cast = eval.castTo(ExpressionType.DOUBLE);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertArrayEquals(new Object[]{"hello"}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{null}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{null}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals("hello", cast.value());
cast = eval.castTo(ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA));
Assert.assertArrayEquals(new Object[]{"hello"}, (Object[]) cast.value());
eval = ExprEval.of("1234.3");
cast = eval.castTo(ExpressionType.DOUBLE);
Assert.assertEquals(1234.3, cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertEquals(1234L, cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{1234.3}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{1234L}, (Object[]) cast.value());
eval = ExprEval.ofType(ExpressionType.STRING, null);
cast = eval.castTo(ExpressionType.DOUBLE);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertNull(cast.value());
}
@Test
public void testCastDouble()
{
ExprEval<?> eval = ExprEval.of(123.4);
ExprEval<?> cast = eval.castTo(ExpressionType.STRING);
Assert.assertEquals("123.4", cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertEquals(123L, cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertArrayEquals(new Object[]{"123.4"}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{123L}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{123.4}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals(123.4, cast.value());
eval = ExprEval.ofType(ExpressionType.DOUBLE, null);
cast = eval.castTo(ExpressionType.STRING);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertNull(cast.value());
}
@Test
public void testCastLong()
{
ExprEval<?> eval = ExprEval.of(1234L);
ExprEval<?> cast = eval.castTo(ExpressionType.STRING);
Assert.assertEquals("1234", cast.value());
cast = eval.castTo(ExpressionType.DOUBLE);
Assert.assertEquals(1234.0, cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertArrayEquals(new Object[]{"1234"}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{1234L}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{1234.0}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertEquals(1234L, cast.value());
eval = ExprEval.ofType(ExpressionType.LONG, null);
cast = eval.castTo(ExpressionType.STRING);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertNull(cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertNull(cast.value());
}
@Test
public void testCastArray()
{
ExprEval<?> eval = ExprEval.ofStringArray(new String[]{"1", "2", "foo", null, "3.3"});
ExprEval<?> cast = eval.castTo(ExpressionType.LONG_ARRAY);
Assert.assertArrayEquals(new Object[]{1L, 2L, null, null, 3L}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{1.0, 2.0, null, null, 3.3}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.NESTED_DATA);
Assert.assertArrayEquals(new Object[]{"1", "2", "foo", null, "3.3"}, (Object[]) cast.value());
cast = eval.castTo(ExpressionTypeFactory.getInstance().ofArray(ExpressionType.NESTED_DATA));
Assert.assertArrayEquals(new Object[]{"1", "2", "foo", null, "3.3"}, (Object[]) cast.value());
ExprEval<?> finalEval = eval;
Throwable t = Assert.assertThrows(IAE.class, () -> finalEval.castTo(ExpressionType.LONG));
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [LONG]", t.getMessage());
t = Assert.assertThrows(IAE.class, () -> finalEval.castTo(ExpressionType.DOUBLE));
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [DOUBLE]", t.getMessage());
t = Assert.assertThrows(IAE.class, () -> finalEval.castTo(ExpressionType.STRING));
Assert.assertEquals("Invalid type, cannot cast [ARRAY<STRING>] to [STRING]", t.getMessage());
eval = ExprEval.ofType(ExpressionType.LONG_ARRAY, new Object[]{1234L});
cast = eval.castTo(ExpressionType.DOUBLE_ARRAY);
Assert.assertArrayEquals(new Object[]{1234.0}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.STRING_ARRAY);
Assert.assertArrayEquals(new Object[]{"1234"}, (Object[]) cast.value());
cast = eval.castTo(ExpressionType.STRING);
Assert.assertEquals("1234", cast.value());
cast = eval.castTo(ExpressionType.DOUBLE);
Assert.assertEquals(1234.0, cast.value());
cast = eval.castTo(ExpressionType.LONG);
Assert.assertEquals(1234L, cast.value());
}
@Test
public void testCastNestedData()
{
ExprEval<?> eval = ExprEval.ofType(ExpressionType.NESTED_DATA, ImmutableMap.of("x", 1234L, "y", 12.34));
Assert.assertEquals(
ImmutableMap.of("x", 1234L, "y", 12.34),
eval.castTo(ExpressionType.NESTED_DATA).value()
);
Throwable t = Assert.assertThrows(IAE.class, () -> eval.castTo(ExpressionType.LONG));
Assert.assertEquals("Invalid type, cannot cast [COMPLEX<json>] to [LONG]", t.getMessage());
}
@Test