|
7 | 7 |
|
8 | 8 | package org.gridsuite.shortcircuit.server.repositories.specifications;
|
9 | 9 |
|
| 10 | +import jakarta.persistence.criteria.Expression; |
10 | 11 | import jakarta.persistence.criteria.Path;
|
11 | 12 | import jakarta.persistence.criteria.Root;
|
12 | 13 | import org.gridsuite.shortcircuit.server.dto.ResourceFilter;
|
@@ -45,16 +46,55 @@ public static <X> Specification<X> startsWith(String field, String value) {
|
45 | 46 | return (root, cq, cb) -> cb.like(cb.upper(getColumnPath(root, field)), EscapeCharacter.DEFAULT.escape(value).toUpperCase() + "%", EscapeCharacter.DEFAULT.getEscapeCharacter());
|
46 | 47 | }
|
47 | 48 |
|
48 |
| - public static <X> Specification<X> notEqual(String field, Double value) { |
49 |
| - return (root, cq, cb) -> cb.notEqual(getColumnPath(root, field), value); |
| 49 | + /** |
| 50 | + * Returns a specification where the field value is not equal within the given tolerance. |
| 51 | + * |
| 52 | + * @param <X> Entity type. |
| 53 | + * @param field Field name. |
| 54 | + * @param value Comparison value. |
| 55 | + * @param tolerance Tolerance range. |
| 56 | + * @return Specification of non-equality with tolerance. |
| 57 | + */ |
| 58 | + public static <X> Specification<X> notEqual(String field, Double value, Double tolerance) { |
| 59 | + return (root, cq, cb) -> { |
| 60 | + Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class); |
| 61 | + return cb.or( |
| 62 | + cb.greaterThan(doubleExpression, value + tolerance), |
| 63 | + cb.lessThan(doubleExpression, value - tolerance) |
| 64 | + ); |
| 65 | + }; |
50 | 66 | }
|
51 | 67 |
|
52 |
| - public static <X> Specification<X> lessThanOrEqual(String field, Double value) { |
53 |
| - return (root, cq, cb) -> cb.lessThanOrEqualTo(getColumnPath(root, field), value); |
| 68 | + /** |
| 69 | + * Returns a specification where the field value is less than or equal to the value plus tolerance. |
| 70 | + * |
| 71 | + * @param <X> Entity type. |
| 72 | + * @param field Field name. |
| 73 | + * @param value Comparison value. |
| 74 | + * @param tolerance Tolerance range. |
| 75 | + * @return Specification of less than or equal with tolerance. |
| 76 | + */ |
| 77 | + public static <X> Specification<X> lessThanOrEqual(String field, Double value, Double tolerance) { |
| 78 | + return (root, cq, cb) -> { |
| 79 | + Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class); |
| 80 | + return cb.lessThanOrEqualTo(doubleExpression, value + tolerance); |
| 81 | + }; |
54 | 82 | }
|
55 | 83 |
|
56 |
| - public static <X> Specification<X> greaterThanOrEqual(String field, Double value) { |
57 |
| - return (root, cq, cb) -> cb.greaterThanOrEqualTo(getColumnPath(root, field), value); |
| 84 | + /** |
| 85 | + * Returns a specification where the field value is greater than or equal to the value minus tolerance. |
| 86 | + * |
| 87 | + * @param <X> Entity type. |
| 88 | + * @param field Field name. |
| 89 | + * @param value Comparison value. |
| 90 | + * @param tolerance Tolerance range. |
| 91 | + * @return Specification of greater than or equal with tolerance. |
| 92 | + */ |
| 93 | + public static <X> Specification<X> greaterThanOrEqual(String field, Double value, Double tolerance) { |
| 94 | + return (root, cq, cb) -> { |
| 95 | + Expression<Double> doubleExpression = getColumnPath(root, field).as(Double.class); |
| 96 | + return cb.greaterThanOrEqualTo(doubleExpression, value - tolerance); |
| 97 | + }; |
58 | 98 | }
|
59 | 99 |
|
60 | 100 | public static <X> Specification<X> isNotEmpty(String field) {
|
@@ -116,21 +156,23 @@ private static <X> Specification<X> appendTextFilterToSpecification(Specificatio
|
116 | 156 |
|
117 | 157 | @NotNull
|
118 | 158 | private static <X> Specification<X> appendNumberFilterToSpecification(Specification<X> specification, ResourceFilter resourceFilter) {
|
119 |
| - Specification<X> completedSpecification = specification; |
120 |
| - |
121 |
| - // We need to cast it as String before and use .valueOf to be able to works with integers |
122 |
| - Double value = Double.valueOf(resourceFilter.value().toString()); |
| 159 | + final double tolerence = 0.00001; // tolerance for comparison |
| 160 | + String value = resourceFilter.value().toString(); |
| 161 | + return createNumberPredicate(specification, resourceFilter, value, tolerence); |
| 162 | + } |
123 | 163 |
|
| 164 | + private static <X> Specification<X> createNumberPredicate(Specification<X> specification, ResourceFilter resourceFilter, String value, double tolerance) { |
| 165 | + Specification<X> completedSpecification = specification; |
| 166 | + Double valueDouble = Double.valueOf(value); |
124 | 167 | switch (resourceFilter.type()) {
|
125 | 168 | case NOT_EQUAL ->
|
126 |
| - completedSpecification = completedSpecification.and(notEqual(resourceFilter.column(), value)); |
| 169 | + completedSpecification = specification.and(notEqual(resourceFilter.column(), valueDouble, tolerance)); |
127 | 170 | case LESS_THAN_OR_EQUAL ->
|
128 |
| - completedSpecification = completedSpecification.and(lessThanOrEqual(resourceFilter.column(), value)); |
| 171 | + completedSpecification = specification.and(lessThanOrEqual(resourceFilter.column(), valueDouble, tolerance)); |
129 | 172 | case GREATER_THAN_OR_EQUAL ->
|
130 |
| - completedSpecification = completedSpecification.and(greaterThanOrEqual(resourceFilter.column(), value)); |
| 173 | + completedSpecification = specification.and(greaterThanOrEqual(resourceFilter.column(), valueDouble, tolerance)); |
131 | 174 | default -> throwBadFilterTypeException(resourceFilter.type(), resourceFilter.dataType());
|
132 | 175 | }
|
133 |
| - |
134 | 176 | return completedSpecification;
|
135 | 177 | }
|
136 | 178 |
|
@@ -159,7 +201,7 @@ private static <X, Y> Path<Y> getColumnPath(Root<X> root, String dotSeparatedFie
|
159 | 201 | }
|
160 | 202 |
|
161 | 203 | // will be overloaded by Spring as InvalidDataAccessApiUsageException
|
162 |
| - private static void throwBadFilterTypeException(ResourceFilter.Type filterType, ResourceFilter.DataType dataType) { |
| 204 | + private static void throwBadFilterTypeException(ResourceFilter.Type filterType, ResourceFilter.DataType dataType) throws IllegalArgumentException { |
163 | 205 | throw new IllegalArgumentException("The filter type " + filterType + " is not supported with the data type " + dataType);
|
164 | 206 | }
|
165 | 207 | }
|
0 commit comments