-
Notifications
You must be signed in to change notification settings - Fork 0
Extract methodes implementing IN clause in gridsuite-computation #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
dc73e5c
Extract methodes implementing IN clause in gridsuite-computation
ipirog 260b6b8
Code indentation
ipirog c1365d0
Generalize use of IN clause
ipirog 3b08d72
Merge branch 'main' into short_circuit_results_add_global_filter
ipirog 1d7549f
It seems there are misuses of EQUALS operator with a list of paramete…
ipirog 4549d26
Fixed NOT_EQUAL implementation
ipirog 46024c2
Merge branch 'main' into short_circuit_results_add_global_filter
etiennehomer dcc7508
Merge branch 'main' into short_circuit_results_add_global_filter
ipirog b4dfbbd
Remove useless annotation @Slf4j
ipirog 6f65971
Merge branch 'main' into short_circuit_results_add_global_filter
ipirog 24dd053
Merge branch 'main' into short_circuit_results_add_global_filter
ipirog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
|
||
import com.google.common.collect.Lists; | ||
import jakarta.persistence.criteria.*; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.gridsuite.computation.dto.ResourceFilterDTO; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.springframework.data.jpa.domain.Specification; | ||
|
@@ -32,15 +33,16 @@ | |
* | ||
* @author Kevin Le Saulnier <[email protected]> | ||
*/ | ||
@Slf4j | ||
public final class SpecificationUtils { | ||
/** | ||
* Maximum values per IN clause chunk to avoid StackOverflow exceptions. | ||
* Current value (500) is a safe default but can be changed | ||
*/ | ||
public static final int MAX_IN_CLAUSE_SIZE = 500; | ||
|
||
public static final String FIELD_SEPARATOR = "."; | ||
|
||
/** | ||
Prefer less than 1000 for Oracle DB / good compromise for Postgres | ||
*/ | ||
public static final int MAX_IN_CLAUSE_SIZE = 10000; | ||
|
||
// Utility class, so no constructor | ||
private SpecificationUtils() { } | ||
|
||
|
@@ -58,6 +60,11 @@ public static <X> Specification<X> notEqual(String field, String value) { | |
return (root, cq, cb) -> cb.notEqual(getColumnPath(root, field), value); | ||
} | ||
|
||
public static <X> Specification<X> in(String field, List<String> values) { | ||
return (root, cq, cb) -> | ||
cb.upper(getColumnPath(root, field).as(String.class)).in(values); | ||
} | ||
|
||
public static <X> Specification<X> contains(String field, String value) { | ||
return (root, cq, cb) -> cb.like(cb.upper(getColumnPath(root, field).as(String.class)), "%" + EscapeCharacter.DEFAULT.escape(value).toUpperCase() + "%", EscapeCharacter.DEFAULT.getEscapeCharacter()); | ||
} | ||
|
@@ -142,15 +149,22 @@ private static <X> Specification<X> appendTextFilterToSpecification(Specificatio | |
// implicitly an IN resourceFilter type because only IN may have value lists as filter value | ||
List<String> inValues = valueList.stream() | ||
.map(Object::toString) | ||
.map(String::toUpperCase) | ||
.toList(); | ||
completedSpecification = completedSpecification.and( | ||
resourceFilter.type() == ResourceFilterDTO.Type.NOT_EQUAL ? | ||
not(generateInSpecification(resourceFilter.column(), inValues)) : | ||
generateInSpecification(resourceFilter.column(), inValues) | ||
); | ||
} else if (resourceFilter.value() == null) { | ||
// if the value is null, we build an impossible specification (trick to remove later on ?) | ||
completedSpecification = completedSpecification.and(not(completedSpecification)); | ||
} else { | ||
completedSpecification = completedSpecification.and(equals(resourceFilter.column(), resourceFilter.value().toString())); | ||
completedSpecification = completedSpecification.and( | ||
resourceFilter.type() == ResourceFilterDTO.Type.NOT_EQUAL ? | ||
notEqual(resourceFilter.column(), resourceFilter.value().toString()) : | ||
equals(resourceFilter.column(), resourceFilter.value().toString()) | ||
); | ||
} | ||
} | ||
case CONTAINS -> { | ||
|
@@ -183,32 +197,17 @@ private static <X> Specification<X> appendTextFilterToSpecification(Specificatio | |
* @return a specification for the IN clause | ||
*/ | ||
private static <X> Specification<X> generateInSpecification(String column, List<String> inPossibleValues) { | ||
|
||
if (inPossibleValues.size() > MAX_IN_CLAUSE_SIZE) { | ||
// there are too many values for only one call to anyOf() : it might cause a StackOverflow | ||
// => the specification is divided into several specifications which have an OR between them : | ||
List<List<String>> chunksOfInValues = Lists.partition(inPossibleValues, MAX_IN_CLAUSE_SIZE); | ||
Specification<X> containerSpec = null; | ||
for (List<String> chunk : chunksOfInValues) { | ||
Specification<X> multiOrEqualSpec = anyOf( | ||
chunk | ||
.stream() | ||
.map(value -> SpecificationUtils.<X>equals(column, value)) | ||
.toList() | ||
); | ||
if (containerSpec == null) { | ||
containerSpec = multiOrEqualSpec; | ||
} else { | ||
containerSpec = containerSpec.or(multiOrEqualSpec); | ||
} | ||
List<List<String>> chunksOfInValues = Lists.partition(inPossibleValues, MAX_IN_CLAUSE_SIZE); | ||
Specification<X> containerSpec = null; | ||
for (List<String> chunk : chunksOfInValues) { | ||
Specification<X> multiOrEqualSpec = Specification.anyOf(in(column, chunk)); | ||
if (containerSpec == null) { | ||
containerSpec = multiOrEqualSpec; | ||
} else { | ||
containerSpec = containerSpec.or(multiOrEqualSpec); | ||
} | ||
return containerSpec; | ||
} | ||
return anyOf(inPossibleValues | ||
.stream() | ||
.map(value -> SpecificationUtils.<X>equals(column, value)) | ||
.toList() | ||
); | ||
return containerSpec; | ||
} | ||
|
||
@NotNull | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.