public static Boolean compare(Object left, Object right, BiPredicate<Comparable, Comparable> op) {
        if ( left == null || right == null ) {
            return null;
        }
        if (left instanceof ChronoPeriod && right instanceof ChronoPeriod) {
            // periods have special compare semantics in FEEL as it ignores "days". Only months and years are compared
            Long l = ComparablePeriod.toTotalMonths((ChronoPeriod) left);
            Long r = ComparablePeriod.toTotalMonths((ChronoPeriod) right);
            return op.test( l, r );
        }
        if (left instanceof TemporalAccessor && right instanceof TemporalAccessor) {
            // Handle specific cases when both time / datetime
            TemporalAccessor l = (TemporalAccessor) left;
            TemporalAccessor r = (TemporalAccessor) right;
            if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.TIME) {
                return op.test(valuet(l), valuet(r));
            } else if (BuiltInType.determineTypeFromInstance(left) == BuiltInType.DATE_TIME && BuiltInType.determineTypeFromInstance(right) == BuiltInType.DATE_TIME) {
                return op.test(valuedt(l, r.query(TemporalQueries.zone())), valuedt(r, l.query(TemporalQueries.zone())));
            }
        }
        if (left instanceof Number && right instanceof Number) {
            // Handle specific cases when both are Number, converting both to BigDecimal
            BigDecimal l = getBigDecimalOrNull(left);
            BigDecimal r = getBigDecimalOrNull(right);
            return op.test(l, r);
        }
        // last fallback:
        if ((left instanceof String && right instanceof String) ||
                (left instanceof Boolean && right instanceof Boolean) ||
                (left instanceof Comparable && left.getClass().isAssignableFrom(right.getClass()))) {
            Comparable<?> l = (Comparable<?>) left;
            Comparable<?> r = (Comparable<?>) right;
            return op.test(l, r);
        }
        return null;
    }
@Test
    void numericValuesComparative() {
        assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(1.0, 2.0, (l, r) -> l.compareTo(r) < 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(1, 2, (l, r) -> l.compareTo(r) > 0)).isFalse();
        assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2, (l, r) -> l.compareTo(r) > 0)).isFalse();
        assertThat(BooleanEvalHelper.compare(1, BigDecimal.valueOf(2), (l, r) -> l.compareTo(r) < 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 2.3,  (l, r) -> l.compareTo(r) == 0)).isFalse();
        assertThat(BooleanEvalHelper.compare(1.2, BigDecimal.valueOf(1.2),  (l, r) -> l.compareTo(r) == 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(BigDecimal.valueOf(1), 0L,  (l, r) -> l.compareTo(r) > 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(10L, BigDecimal.valueOf(2),  (l, r) -> l.compareTo(r) < 0)).isFalse();
        assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), BigInteger.valueOf(2), (l, r) -> l.compareTo(r) == 0)).isFalse();
        assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2,  (l, r) -> l.compareTo(r) < 0)).isTrue();
        assertThat(BooleanEvalHelper.compare(BigInteger.valueOf(1), 2.3,  (l, r) -> l.compareTo(r) == 0)).isFalse();
    }