Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,17 @@ public static <X> Specification<X> startsWith(String field, String value) {
return (root, cq, cb) -> cb.like(cb.upper(getColumnPath(root, field)), EscapeCharacter.DEFAULT.escape(value).toUpperCase() + "%", EscapeCharacter.DEFAULT.getEscapeCharacter());
}

/**
* Returns a specification where the field value is not equal within the given tolerance.
*/
public static <X> Specification<X> notEqual(String field, Double value, Double tolerance) {
return (root, cq, cb) -> {
Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class);
/**
* in order to be equal to doubleExpression, value has to fit :
* value - tolerance <= doubleExpression <= value + tolerance
* therefore in order to be different at least one of the opposite comparison needs to be true :
*/
return cb.or(
cb.greaterThan(doubleExpression, value + tolerance),
cb.lessThan(doubleExpression, value - tolerance)
Expand Down Expand Up @@ -137,13 +145,22 @@ private static <X> Specification<X> appendTextFilterToSpecification(Specificatio

@NotNull
private static <X> Specification<X> appendNumberFilterToSpecification(Specification<X> specification, ResourceFilterDTO resourceFilter) {
final double tolerance = 0.00001; // tolerance for comparison
String value = resourceFilter.value().toString();
return createNumberPredicate(specification, resourceFilter, value, tolerance);
return createNumberPredicate(specification, resourceFilter, value);
}

private static <X> Specification<X> createNumberPredicate(Specification<X> specification, ResourceFilterDTO resourceFilter, String value, double tolerance) {
Double valueDouble = Double.valueOf(value);
private static <X> Specification<X> createNumberPredicate(Specification<X> specification, ResourceFilterDTO resourceFilter, String filterValue) {
// the reference for the comparison is the number of digits after the decimal point in filterValue
// extra digits are ignored, but the user may add '0's after the decimal point in order to get a better precision
String[] splitValue = filterValue.split("\\.");
int numberOfDecimalAfterDot = 0;
if (splitValue.length > 1) {
numberOfDecimalAfterDot = splitValue[1].length();
}
// tolerance is multiplied by 0.5 to simulate the fact that the database value is rounded (in the front, from the user viewpoint)
// more than 13 decimal after dot will likely cause rounding errors due to double precision
final double tolerance = Math.pow(10, -numberOfDecimalAfterDot) * 0.5;
Double valueDouble = Double.valueOf(filterValue);
return switch (resourceFilter.type()) {
case NOT_EQUAL -> specification.and(notEqual(resourceFilter.column(), valueDouble, tolerance));
case LESS_THAN_OR_EQUAL ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ void findFilteredPrecontingencyLimitViolationResultsTest(List<ResourceFilterDTO>
List<PreContingencyLimitViolationResultDTO> preContingencyLimitViolation = securityAnalysisResultService.findNResult(resultEntity.getId(), filters, sort);

// assert subject ids to check parent filters
assertThat(preContingencyLimitViolation).extracting(SubjectLimitViolationEntity.Fields.subjectId).containsExactlyElementsOf(expectedResult.stream().map(PreContingencyLimitViolationResultDTO::getSubjectId).toList());
assertThat(preContingencyLimitViolation).extracting(SubjectLimitViolationEntity.Fields.subjectId)
.containsExactlyElementsOf(
expectedResult.stream().map(PreContingencyLimitViolationResultDTO::getSubjectId).toList()
);
assertSelectCount(expectedSelectCount);
}

Expand Down Expand Up @@ -110,9 +113,11 @@ private static Stream<Arguments> provideChildFilter() {

private static Stream<Arguments> provideChildFilterWithTolerance() {
return Stream.of(
Arguments.of(List.of(new ResourceFilterDTO(ResourceFilterDTO.DataType.NUMBER, ResourceFilterDTO.Type.NOT_EQUAL, "11.02425", AbstractLimitViolationEntity.Fields.value),
Arguments.of(List.of(
new ResourceFilterDTO(ResourceFilterDTO.DataType.NUMBER, ResourceFilterDTO.Type.NOT_EQUAL, "11.02425", AbstractLimitViolationEntity.Fields.value),
new ResourceFilterDTO(ResourceFilterDTO.DataType.NUMBER, ResourceFilterDTO.Type.LESS_THAN_OR_EQUAL, "10.51243", AbstractLimitViolationEntity.Fields.limit),
new ResourceFilterDTO(ResourceFilterDTO.DataType.NUMBER, ResourceFilterDTO.Type.GREATER_THAN_OR_EQUAL, "1.00001", AbstractLimitViolationEntity.Fields.limitReduction)), Sort.by(Sort.Direction.ASC, "limit"),
new ResourceFilterDTO(ResourceFilterDTO.DataType.NUMBER, ResourceFilterDTO.Type.GREATER_THAN_OR_EQUAL, "0.999999", AbstractLimitViolationEntity.Fields.limitReduction)
), Sort.by(Sort.Direction.ASC, "limit"),
getResultPreContingencyWithNestedFilter(p -> p.getLimitViolation().getLimit() <= 10.51243)
.stream().sorted(Comparator.comparing(x -> x.getLimitViolation().getLimit())).toList(), 2)
);
Expand Down
Loading