Last active
October 6, 2024 21:54
-
-
Save josergdev/c327bb9569a6c891e7d4e21c01a2f719 to your computer and use it in GitHub Desktop.
Revisions
-
josergdev revised this gist
Oct 6, 2024 . 2 changed files with 112 additions and 50 deletions.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 charactersOriginal file line number Diff line number Diff line change @@ -1,50 +0,0 @@ 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,112 @@ package dev.joserg.jpa; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; import lombok.extern.slf4j.Slf4j; @Slf4j public class CriteriaBuilderTupleIn { private final CriteriaBuilder criteriaBuilder; public CriteriaBuilderTupleIn(CriteriaBuilder criteriaBuilder) { this.criteriaBuilder = criteriaBuilder; } public <T> Predicate tupleIn(final List<T> tupables, final Function<T, In> tupleizer) { return this.tupleIn(tupables.stream().map(tupable -> InTupable.of(tupable, tupleizer)).toList()); } public Predicate tupleIn(final List<? extends InTupable> inTupables) { final var tuples = inTupables.stream().map(InTupable::inTupleize).toList(); return tuples.stream().findFirst() .map(tuple -> this.tupleIn(tuple.getExpressions(), tuples.stream().map(In::getValues).toList())) .orElseGet(this.criteriaBuilder::disjunction); } public Predicate tupleIn(final List<? extends Expression<?>> tupleExpression, final List<List<Object>> tupleValues) { final var leftIn = this.criteriaBuilder.function("", Object.class, tupleExpression.toArray(Expression[]::new)); final var rightIn = tupleValues.stream() .map(tupleValue -> { if (tupleExpression.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } final var values = tupleValue.stream().map(this.criteriaBuilder::literal).toArray(Expression[]::new); return this.criteriaBuilder.function("", Object.class, values); }) .toArray(Expression[]::new); try { return leftIn.in(rightIn); } catch (final Exception e) { log.warn("Build predicate with multiple columns IN clause failed. Using simulated feature"); return this.simulatedTupleIn(tupleExpression, tupleValues); } } public <T> Predicate simulatedTupleIn(final List<T> tupables, final Function<T, In> tupleizer) { return this.simulatedTupleIn(tupables.stream().map(tupable -> InTupable.of(tupable, tupleizer)).toList()); } public Predicate simulatedTupleIn(final List<? extends InTupable> inTupables) { final var tuples = inTupables.stream().map(InTupable::inTupleize).toList(); return tuples.stream().findFirst() .map(tuple -> this.tupleIn(tuple.getExpressions(), tuples.stream().map(In::getValues).toList())) .orElseGet(this.criteriaBuilder::disjunction); } public Predicate simulatedTupleIn(final List<? extends Expression<?>> tupleExpression, final List<List<Object>> tupleValues) { var outerPredicate = this.criteriaBuilder.disjunction(); for (final var tupleValue : tupleValues) { if (tupleExpression.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } var innerPredicate = this.criteriaBuilder.conjunction(); for (int i = 0; i < tupleExpression.size(); i++) { final var equalPredicate = this.criteriaBuilder.equal(tupleExpression.get(i), tupleValue.get(i)); innerPredicate = this.criteriaBuilder.and(innerPredicate, equalPredicate); } outerPredicate = this.criteriaBuilder.or(outerPredicate, innerPredicate); } return outerPredicate; } public interface InTupable { static <T> InTupable of(final T tupable, final Function<T, In> tupleizer) { return () -> tupleizer.apply(tupable); } In inTupleize(); } public static class In { private final List<Expression<?>> expressions; private final List<Object> values; public In() { this.expressions = new ArrayList<>(); this.values = new ArrayList<>(); } public <T> In element(Expression<T> expression, T value) { this.expressions.add(expression); this.values.add(value); return this; } public List<Expression<?>> getExpressions() { return this.expressions; } public List<Object> getValues() { return this.values; } } } -
josergdev revised this gist
Oct 6, 2024 . 1 changed file with 9 additions and 9 deletions.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 charactersOriginal file line number Diff line number Diff line change @@ -13,12 +13,11 @@ public class CriteriaBuilderExtension { public CriteriaBuilderExtension(CriteriaBuilder criteriaBuilder) { this.criteriaBuilder = criteriaBuilder; } public Predicate tupleIn(final List<? extends Expression<?>> tupleExpression, final List<List<Object>> tupleValues) { final var leftIn = this.criteriaBuilder.function("", Object.class, tupleExpression.toArray(new Expression[0])); final var rightIn = tupleValues.stream() .map(tupleValue -> { if (tupleExpression.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } final var values = tupleValue.stream().map(this.criteriaBuilder::literal).toList(); @@ -28,19 +27,20 @@ public Predicate tuplesIn(final List<? extends Expression<?>> tuplePath, final L try { return leftIn.in(rightIn); } catch (final Exception e) { log.warn("Build predicate with multiple columns IN clause failed. Using simulated feature"); return this.simulatedTupleIn(tupleExpression, tupleValues); } } public Predicate simulatedTupleIn(final List<? extends Expression<?>> tupleExpression, final List<List<Object>> tupleValues) { var outerPredicate = this.criteriaBuilder.disjunction(); for (final var tupleValue : tupleValues) { if (tupleExpression.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } var innerPredicate = this.criteriaBuilder.conjunction(); for (int i = 0; i < tupleExpression.size(); i++) { final var equalPredicate = this.criteriaBuilder.equal(tupleExpression.get(i), tupleValue.get(i)); innerPredicate = this.criteriaBuilder.and(innerPredicate, equalPredicate); } outerPredicate = this.criteriaBuilder.or(outerPredicate, innerPredicate); -
josergdev revised this gist
Oct 6, 2024 . 1 changed file with 10 additions and 10 deletions.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 charactersOriginal file line number Diff line number Diff line change @@ -15,17 +15,17 @@ public CriteriaBuilderExtension(CriteriaBuilder criteriaBuilder) { } public Predicate tuplesIn(final List<? extends Expression<?>> tuplePath, final List<List<Object>> tupleValues) { final var leftIn = this.criteriaBuilder.function("", Object.class, tuplePath.toArray(new Expression[0])); final var rightIn = tupleValues.stream() .map(tupleValue -> { if (tuplePath.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } final var values = tupleValue.stream().map(this.criteriaBuilder::literal).toList(); return this.criteriaBuilder.function("", Object.class, values.toArray(new Expression[0])); }) .toArray(); try { return leftIn.in(rightIn); } catch (final Exception e) { return this.simulatedTuplesIn(tuplePath, tupleValues); -
josergdev revised this gist
Oct 6, 2024 . 1 changed file with 20 additions and 10 deletions.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 charactersOriginal file line number Diff line number Diff line change @@ -14,20 +14,30 @@ public CriteriaBuilderExtension(CriteriaBuilder criteriaBuilder) { this.criteriaBuilder = criteriaBuilder; } public Predicate tuplesIn(final List<? extends Expression<?>> tuplePath, final List<List<Object>> tupleValues) { try { final var leftIn = this.criteriaBuilder.function("", Object.class, tuplePath.toArray(new Expression[0])); final var rightIn = tupleValues.stream() .map(tupleValue -> { if (tuplePath.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } final var values = tupleValue.stream().map(this.criteriaBuilder::literal).toList(); return this.criteriaBuilder.function("", Object.class, values.toArray(new Expression[0])); }) .toArray(); return leftIn.in(rightIn); } catch (final Exception e) { return this.simulatedTuplesIn(tuplePath, tupleValues); } } public Predicate simulatedTuplesIn(final List<? extends Expression<?>> tuplePath, final List<List<Object>> tupleValues) { var outerPredicate = this.criteriaBuilder.disjunction(); for (final var tupleValue : tupleValues) { if (tuplePath.size() != tupleValue.size()) { throw new IllegalArgumentException("Tuple expression and tuple value must have the same size"); } var innerPredicate = this.criteriaBuilder.conjunction(); for (int i = 0; i < tuplePath.size(); i++) { final var equalPredicate = this.criteriaBuilder.equal(tuplePath.get(i), tupleValue.get(i)); -
josergdev revised this gist
Oct 6, 2024 . 1 changed file with 13 additions and 0 deletions.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 charactersOriginal file line number Diff line number Diff line change @@ -24,4 +24,17 @@ public Predicate tuplesIn(final List<? extends Expression<Object>> tuplePath, fi .toArray(); return leftIn.in(rightIn); } public Predicate simulatedTuplesIn(final List<? extends Expression<Object>> tuplePath, final List<List<Object>> tupleValues) { var outerPredicate = this.criteriaBuilder.disjunction(); for (final var tupleValue : tupleValues) { var innerPredicate = this.criteriaBuilder.conjunction(); for (int i = 0; i < tuplePath.size(); i++) { final var equalPredicate = this.criteriaBuilder.equal(tuplePath.get(i), tupleValue.get(i)); innerPredicate = this.criteriaBuilder.and(innerPredicate, equalPredicate); } outerPredicate = this.criteriaBuilder.or(outerPredicate, innerPredicate); } return outerPredicate; } } -
josergdev created this gist
Oct 6, 2024 .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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,27 @@ package dev.joserg.jpa; import java.util.List; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; public class CriteriaBuilderExtension { private final CriteriaBuilder criteriaBuilder; public CriteriaBuilderExtension(CriteriaBuilder criteriaBuilder) { this.criteriaBuilder = criteriaBuilder; } public Predicate tuplesIn(final List<? extends Expression<Object>> tuplePath, final List<List<Object>> tupleValues) { final var leftIn = this.criteriaBuilder.function("", Object.class, tuplePath.toArray(new Expression[0])); final var rightIn = tupleValues.stream() .map(tupleValue -> { final var values = tupleValue.stream().map(this.criteriaBuilder::literal).toList(); return this.criteriaBuilder.function("", Object.class, values.toArray(new Expression[0])); }) .toArray(); return leftIn.in(rightIn); } }