This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch merge-hibernate6 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit d68a1b859179ffd5b2f4e2804010237e336051d7 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Sep 7 13:23:53 2025 -0500 Refactoring PredicateGenerator for clarity --- .../hibernate/query/JpaCriteriaQueryCreator.java | 6 +- .../orm/hibernate/query/PredicateGenerator.java | 371 +++++++++++---------- 2 files changed, 199 insertions(+), 178 deletions(-) diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java index b2268c9b12..8b06c93a09 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/JpaCriteriaQueryCreator.java @@ -48,7 +48,7 @@ public class JpaCriteriaQueryCreator { assignGroupBy(groupProjections, root, cq, tablesByName); assignOrderBy(cq, tablesByName); - assignCriteria(cq, root,tablesByName); + assignCriteria(cq, root,tablesByName,entity); return cq; } @@ -129,10 +129,10 @@ public class JpaCriteriaQueryCreator { } } - private void assignCriteria(CriteriaQuery cq ,From root, JpaFromProvider tablesByName) { + private void assignCriteria(CriteriaQuery cq , From root, JpaFromProvider tablesByName, PersistentEntity entity) { List<Query.Criterion> criteriaList =detachedCriteria.getCriteria(); if (!criteriaList.isEmpty()) { - jakarta.persistence.criteria.Predicate[] predicates = PredicateGenerator.getPredicates(criteriaBuilder, cq, root, criteriaList, tablesByName); + jakarta.persistence.criteria.Predicate[] predicates = PredicateGenerator.getPredicates(criteriaBuilder, cq, root, criteriaList, tablesByName,entity); cq.where(criteriaBuilder.and(predicates)); } } diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java index 275254c78d..67cc104e55 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/PredicateGenerator.java @@ -35,9 +35,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @@ -50,35 +48,191 @@ public class PredicateGenerator { public static Predicate[] getPredicates(HibernateCriteriaBuilder cb, CriteriaQuery criteriaQuery, From root_, - List<Query.Criterion> criteriaList, JpaFromProvider fromsByProvider) { + List<Query.Criterion> criteriaList, JpaFromProvider fromsByProvider, PersistentEntity entity) { List<Predicate> list = criteriaList.stream(). map(criterion -> { - if (criterion instanceof Query.Disjunction) { - List<Query.Criterion> criterionList = ((Query.Disjunction) criterion).getCriteria(); - return cb.or(getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider)); - - } else if (criterion instanceof Query.Conjunction) { - List<Query.Criterion> criterionList = ((Query.Conjunction) criterion).getCriteria(); - return cb.and(getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider)); - } else if (criterion instanceof Query.Negation) { - List<Query.Criterion> criterionList = ((Query.Negation) criterion).getCriteria(); - Predicate[] predicates = getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider); - if (predicates.length != 1) { - log.error("Must have a single predicate behind a not"); - throw new RuntimeException("Must have a single predicate behind a not"); + if (criterion instanceof Query.Junction junction) { + if (junction instanceof Query.Disjunction) { + List<Query.Criterion> criterionList = junction.getCriteria(); + return cb.or(getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider, entity)); + + } else if (junction instanceof Query.Conjunction) { + List<Query.Criterion> criterionList = junction.getCriteria(); + return cb.and(getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider, entity)); + } else if (junction instanceof Query.Negation) { + List<Query.Criterion> criterionList = junction.getCriteria(); + Predicate[] predicates = getPredicates(cb, criteriaQuery, root_, criterionList, fromsByProvider, entity); + if (predicates.length != 1) { + log.error("Must have a single predicate behind a not"); + throw new RuntimeException("Must have a single predicate behind a not"); + } + return cb.not(predicates[0]); } - return cb.not(predicates[0]); } else if (criterion instanceof Query.DistinctProjection) { // this returns always true return cb.conjunction(); } else if (criterion instanceof DetachedAssociationCriteria<?> c) { - Join child = root_.join(c.getAssociationPath(), JoinType.LEFT); - List<Query.Criterion> criterionList = c.getCriteria(); - JpaFromProvider childTablesByName = (JpaFromProvider )fromsByProvider.clone(); - childTablesByName.put("root",child); - return cb.and(getPredicates(cb, criteriaQuery, child, criterionList, childTablesByName)); + Join child = root_.join(c.getAssociationPath(), JoinType.LEFT); + List<Query.Criterion> criterionList = c.getCriteria(); + JpaFromProvider childTablesByName = (JpaFromProvider) fromsByProvider.clone(); + childTablesByName.put("root", child); + return cb.and(getPredicates(cb, criteriaQuery, child, criterionList, childTablesByName, entity)); + } else if (criterion instanceof Query.PropertyCriterion) { + if (criterion instanceof Query.Equals c) { + return cb.equal(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue()); + } else if (criterion instanceof Query.NotEquals c) { + var notEqualToValue = cb.notEqual(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue()); + var isNull = cb.isNull(fromsByProvider.getFullyQualifiedPath(c.getProperty())); + return cb.or(notEqualToValue, isNull); + } else if (criterion instanceof Query.IdEquals c) { + return cb.equal(root_.get("id"), c.getValue()); + } else if (criterion instanceof Query.GreaterThan c) { + return cb.gt(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); + } else if (criterion instanceof Query.GreaterThanEquals c) { + return cb.ge(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); + } else if (criterion instanceof Query.LessThan c) { + return cb.lt(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); + } else if (criterion instanceof Query.LessThanEquals c) { + return cb.le(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); + } else if (criterion instanceof Query.SizeEquals c) { + return cb.equal(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); + } else if (criterion instanceof Query.SizeNotEquals c) { + return cb.notEqual(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); + } else if (criterion instanceof Query.SizeGreaterThan c) { + return cb.gt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeGreaterThanEquals c) { + return cb.ge(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeLessThan c) { + return cb.lt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeLessThanEquals c) { + return cb.le(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.Between c) { + if (c.getFrom() instanceof String && c.getTo() instanceof String) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (String) c.getFrom(), (String) c.getTo()); + } else if (c.getFrom() instanceof Short && c.getTo() instanceof Short) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Short) c.getFrom(), (Short) c.getTo()); + } else if (c.getFrom() instanceof Integer && c.getTo() instanceof Integer) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Integer) c.getFrom(), (Integer) c.getTo()); + } else if (c.getFrom() instanceof Long && c.getTo() instanceof Long) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Long) c.getFrom(), (Long) c.getTo()); + } else if (c.getFrom() instanceof Date && c.getTo() instanceof Date) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Date) c.getFrom(), (Date) c.getTo()); + } else if (c.getFrom() instanceof Instant && c.getTo() instanceof Instant) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Instant) c.getFrom(), (Instant) c.getTo()); + } else if (c.getFrom() instanceof LocalDate && c.getTo() instanceof LocalDate) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (LocalDate) c.getFrom(), (LocalDate) c.getTo()); + } else if (c.getFrom() instanceof LocalDateTime && c.getTo() instanceof LocalDateTime) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (LocalDateTime) c.getFrom(), (LocalDateTime) c.getTo()); + } else if (c.getFrom() instanceof OffsetDateTime && c.getTo() instanceof OffsetDateTime) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (OffsetDateTime) c.getFrom(), (OffsetDateTime) c.getTo()); + } else if (c.getFrom() instanceof ZonedDateTime && c.getTo() instanceof ZonedDateTime) { + return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (ZonedDateTime) c.getFrom(), (ZonedDateTime) c.getTo()); + } + } else if (criterion instanceof Query.ILike c) { + return cb.ilike(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue().toString()); + } else if (criterion instanceof Query.RLike c) { + return cb.like(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getPattern(), '\\'); + } else if (criterion instanceof Query.Like c) { + return cb.like(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue().toString()); + } else if (criterion instanceof Query.SizeEquals c) { + return cb.equal(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); + } else if (criterion instanceof Query.SizeGreaterThan c) { + return cb.gt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeGreaterThanEquals c) { + return cb.ge(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeLessThan c) { + return cb.lt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.SizeLessThanEquals c) { + return cb.le(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); + } else if (criterion instanceof Query.In c) { + var queryableCriteria = getQueryableCriteriaFromInCriteria(criterion); + if (Objects.nonNull(queryableCriteria)) { + + CriteriaBuilder.In value = getQueryableCriteriaValue(cb, criteriaQuery, fromsByProvider, entity, (Query.PropertyNameCriterion) criterion, queryableCriteria); + return value; + } else if (!c.getValues().isEmpty()) { + boolean areGormEntities = c.getValues().stream().allMatch(GormEntity.class::isInstance); + if (areGormEntities) { + List<GormEntity> gormEntities = new ArrayList<>(c.getValues()); + Path id = criteriaQuery.from(gormEntities.get(0).getClass()).get("id"); + Collection newValues = gormEntities.stream().map(GormEntity::ident).toList(); + return cb.in(id, newValues); + } + return cb.in(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValues()); + } + } else if (criterion instanceof Query.NotIn c) { + var queryableCriteria = getQueryableCriteriaFromInCriteria(criterion); + if (Objects.nonNull(queryableCriteria)) { + CriteriaBuilder.In value = getQueryableCriteriaValue(cb, criteriaQuery, fromsByProvider, entity, (Query.PropertyNameCriterion) criterion, queryableCriteria); + return cb.not(value); + } else if (Objects.nonNull(c.getSubquery()) + && !c.getSubquery().getProjections().isEmpty() + && c.getSubquery().getProjections().get(0) instanceof Query.PropertyProjection + ) { + Subquery subquery2 = criteriaQuery.subquery(Number.class); + Root from2 = subquery2.from(c.getValue().getPersistentEntity().getJavaClass()); + List subCriteria2 = c.getValue().getCriteria(); + Query.PropertyProjection projection = (Query.PropertyProjection) c.getSubquery().getProjections().get(0); + boolean distinct = projection instanceof Query.DistinctPropertyProjection; + JpaFromProvider newMap2 = (JpaFromProvider) fromsByProvider.clone(); + Predicate[] predicates2 = getPredicates(cb, criteriaQuery, from2, subCriteria2, newMap2, entity); + subquery2.select(from2.get(projection.getPropertyName())).distinct(distinct).where(cb.and(predicates2)); + return cb.not(cb.in(fromsByProvider.getFullyQualifiedPath(c.getProperty())).value(subquery2)); + } else if ( Objects.nonNull(c.getSubquery()) + && !c.getSubquery().getProjections().isEmpty() + && c.getSubquery().getProjections().get(0) instanceof Query.IdProjection + ) { + Subquery subquery2 = criteriaQuery.subquery(Number.class); + Root from2 = subquery2.from(c.getValue().getPersistentEntity().getJavaClass()); + List subCriteria2 = c.getValue().getCriteria(); + JpaFromProvider newMap2 = (JpaFromProvider) fromsByProvider.clone(); + Predicate[] predicates2 = getPredicates(cb, criteriaQuery, from2, subCriteria2, newMap2, entity); + subquery2.select(from2).where(cb.and(predicates2)); + return cb.not(cb.in(root_.get("id")).value(subquery2)); + } else { + return cb.not(cb.in(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue())); + } + + } else if (criterion instanceof Query.SubqueryCriterion c) { + Subquery subquery = criteriaQuery.subquery(Number.class); + Root from = subquery.from(c.getValue().getPersistentEntity().getJavaClass()); + List subCriteria = c.getValue().getCriteria(); + JpaFromProvider newMap = (JpaFromProvider) fromsByProvider.clone(); + newMap.put("root", from); + Predicate[] predicates = getPredicates(cb, criteriaQuery, from, subCriteria, newMap, entity); + if (c instanceof Query.GreaterThanEqualsAll sc) { + subquery.select(cb.max(from.get(c.getProperty()))).where(cb.and(predicates)); + return cb.greaterThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.GreaterThanAll sc) { + subquery.select(cb.max(from.get(c.getProperty()))).where(cb.and(predicates)); + return cb.greaterThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.LessThanEqualsAll sc) { + subquery.select(cb.min(from.get(c.getProperty()))).where(cb.and(predicates)); + return cb.lessThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.LessThanAll sc) { + subquery.select(cb.min(from.get(c.getProperty()))).where(cb.and(predicates)); + return cb.lessThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.EqualsAll sc) { + subquery.select(from.get(c.getProperty())).where(cb.and(predicates)); + return cb.equal(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.GreaterThanEqualsSome sc) { + subquery.select(cb.max(from.get(c.getProperty()))).where(cb.or(predicates)); + return cb.greaterThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.GreaterThanSome sc) { + subquery.select(cb.max(from.get(c.getProperty()))).where(cb.or(predicates)); + return cb.greaterThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.LessThanEqualsSome sc) { + subquery.select(cb.min(from.get(c.getProperty()))).where(cb.or(predicates)); + return cb.lessThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + } else if (c instanceof Query.LessThanSome sc) { + subquery.select(cb.min(from.get(c.getProperty()))).where(cb.or(predicates)); + return cb.lessThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); + + } + } + } else if (criterion instanceof Query.IsNull c) { return cb.isNull(fromsByProvider.getFullyQualifiedPath(c.getProperty())); } else if (criterion instanceof Query.IsNotNull c) { @@ -87,12 +241,6 @@ public class PredicateGenerator { return cb.isEmpty(fromsByProvider.getFullyQualifiedPath(c.getProperty())); } else if (criterion instanceof Query.IsNotEmpty c) { return cb.isNotEmpty(fromsByProvider.getFullyQualifiedPath(c.getProperty())); - } else if (criterion instanceof Query.Equals c) { - return cb.equal(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue()); - } else if (criterion instanceof Query.NotEquals c) { - var notEqualToValue = cb.notEqual(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue()); - var isNull = cb.isNull(fromsByProvider.getFullyQualifiedPath(c.getProperty())); - return cb.or(notEqualToValue, isNull); } else if (criterion instanceof Query.EqualsProperty c) { return cb.equal(fromsByProvider.getFullyQualifiedPath(c.getProperty()), root_.get(c.getOtherProperty())); } else if (criterion instanceof Query.NotEqualsProperty c) { @@ -105,100 +253,6 @@ public class PredicateGenerator { return cb.ge(fromsByProvider.getFullyQualifiedPath(c.getProperty()), root_.get(c.getOtherProperty())); } else if (criterion instanceof Query.GreaterThanProperty c) { return cb.gt(fromsByProvider.getFullyQualifiedPath(c.getProperty()), root_.get(c.getOtherProperty())); - } else if (criterion instanceof Query.IdEquals c) { - return cb.equal(root_.get("id"), c.getValue()); - } else if (criterion instanceof Query.GreaterThan c) { - return cb.gt(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); - } else if (criterion instanceof Query.GreaterThanEquals c) { - return cb.ge(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); - } else if (criterion instanceof Query.LessThan c) { - return cb.lt(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); - } else if (criterion instanceof Query.LessThanEquals c) { - return cb.le(fromsByProvider.getFullyQualifiedPath(c.getProperty()), getNumericValue(c)); - } else if (criterion instanceof Query.SizeEquals c) { - return cb.equal(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); - } else if (criterion instanceof Query.SizeNotEquals c) { - return cb.notEqual(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); - } else if (criterion instanceof Query.SizeGreaterThan c) { - return cb.gt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeGreaterThanEquals c) { - return cb.ge(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeLessThan c) { - return cb.lt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeLessThanEquals c) { - return cb.le(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.Between c) { - if (c.getFrom() instanceof String && c.getTo() instanceof String) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (String) c.getFrom(), (String) c.getTo()); - } else if (c.getFrom() instanceof Short && c.getTo() instanceof Short) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Short) c.getFrom(), (Short) c.getTo()); - } else if (c.getFrom() instanceof Integer && c.getTo() instanceof Integer) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Integer) c.getFrom(), (Integer) c.getTo()); - } else if (c.getFrom() instanceof Long && c.getTo() instanceof Long) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Long) c.getFrom(), (Long) c.getTo()); - } else if (c.getFrom() instanceof Date && c.getTo() instanceof Date) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Date) c.getFrom(), (Date) c.getTo()); - } else if (c.getFrom() instanceof Instant && c.getTo() instanceof Instant) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (Instant) c.getFrom(), (Instant) c.getTo()); - } else if (c.getFrom() instanceof LocalDate && c.getTo() instanceof LocalDate) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (LocalDate) c.getFrom(), (LocalDate) c.getTo()); - } else if (c.getFrom() instanceof LocalDateTime && c.getTo() instanceof LocalDateTime) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (LocalDateTime) c.getFrom(), (LocalDateTime) c.getTo()); - } else if (c.getFrom() instanceof OffsetDateTime && c.getTo() instanceof OffsetDateTime) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (OffsetDateTime) c.getFrom(), (OffsetDateTime) c.getTo()); - } else if (c.getFrom() instanceof ZonedDateTime && c.getTo() instanceof ZonedDateTime) { - return cb.between(fromsByProvider.getFullyQualifiedPath(c.getProperty()), (ZonedDateTime) c.getFrom(), (ZonedDateTime) c.getTo()); - } - } else if (criterion instanceof Query.ILike c) { - return cb.ilike(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue().toString()); - } else if (criterion instanceof Query.RLike c) { - return cb.like(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getPattern(), '\\'); - } else if (criterion instanceof Query.Like c) { - return cb.like(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue().toString()); - } else if (criterion instanceof Query.SizeEquals c) { - return cb.equal(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), c.getValue()); - } else if (criterion instanceof Query.SizeGreaterThan c) { - return cb.gt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeGreaterThanEquals c) { - return cb.ge(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeLessThan c) { - return cb.lt(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if (criterion instanceof Query.SizeLessThanEquals c) { - return cb.le(cb.size(fromsByProvider.getFullyQualifiedPath(c.getProperty())), getNumericValue(c)); - } else if(criterion instanceof Query.In || criterion instanceof Query.NotIn) { - var queryableCriteria = getQueryableCriteriaFromInCriteria(criterion); - if (Objects.nonNull(queryableCriteria)) { - - var projection = findPropertyOrIdProjection(queryableCriteria); - var subProperty = findSubproperty(projection); - var path = getPathFromInCriterion(fromsByProvider, (Query.PropertyNameCriterion) criterion); - var in = findInPredicate(cb, projection, path, subProperty); - var subquery = criteriaQuery.subquery(getJavaTypeOfInClause((SqmInListPredicate) in)); - var from = subquery.from(queryableCriteria.getPersistentEntity().getJavaClass()); - var subCriteria = queryableCriteria.getCriteria(); - var clonedProviderByName = (JpaFromProvider) fromsByProvider.clone(); - clonedProviderByName.put("root", from); - var predicates = getPredicates(cb, criteriaQuery, from, subCriteria, clonedProviderByName); - subquery.select(clonedProviderByName.getFullyQualifiedPath(subProperty)) - .distinct(true) - .where(cb.and(predicates)); - CriteriaBuilder.In value = in.value(subquery); - if (criterion instanceof Query.In) { - return value; - } - return cb.not(value); - } else if (criterion instanceof Query.In c && !c.getValues().isEmpty()) { - boolean areGormEntities = c.getValues().stream().allMatch(GormEntity.class::isInstance); - if (areGormEntities) { - List<GormEntity> gormEntities = new ArrayList<>(c.getValues()); - Path id = criteriaQuery.from(gormEntities.get(0).getClass()).get("id"); - Collection newValues = gormEntities.stream().map(GormEntity::ident).toList(); - return cb.in(id, newValues); - } - return cb.in(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValues()); - } else if (criterion instanceof Query.NotIn c) { - return cb.not(cb.in(fromsByProvider.getFullyQualifiedPath(c.getProperty()), c.getValue())); - } } else if (criterion instanceof Query.Exists c) { Subquery subquery = criteriaQuery.subquery(Integer.class); PersistentEntity childPersistentEntity = c.getSubquery().getPersistentEntity(); @@ -207,7 +261,7 @@ public class PredicateGenerator { JpaFromProvider newMap = (JpaFromProvider) fromsByProvider.clone(); newMap.put("root", subRoot); - var predicates = getPredicates(cb, criteriaQuery, subRoot, c.getSubquery().getCriteria(), newMap); + var predicates = getPredicates(cb, criteriaQuery, subRoot, c.getSubquery().getCriteria(), newMap, entity); var existsPredicate = getExistsPredicate(cb, root_, childPersistentEntity, subRoot); Predicate[] allPredicates = Stream.concat( @@ -226,7 +280,7 @@ public class PredicateGenerator { JpaFromProvider newMap = (JpaFromProvider) fromsByProvider.clone(); newMap.put("root", subRoot); - var predicates = getPredicates(cb, criteriaQuery, subRoot, c.getSubquery().getCriteria(), newMap); + var predicates = getPredicates(cb, criteriaQuery, subRoot, c.getSubquery().getCriteria(), newMap, entity); var existsPredicate = getExistsPredicate(cb, root_, childPersistentEntity, subRoot); Predicate[] allPredicates = Stream.concat( @@ -237,57 +291,6 @@ public class PredicateGenerator { subquery.select(cb.literal(1)).where(cb.and(allPredicates)); JpaPredicate exists = cb.exists(subquery); return cb.not(exists); - } else if (criterion instanceof Query.SubqueryCriterion c) { - Subquery subquery = criteriaQuery.subquery(Number.class); - Root from = subquery.from(c.getValue().getPersistentEntity().getJavaClass()); - List subCriteria = c.getValue().getCriteria(); - JpaFromProvider newMap = (JpaFromProvider) fromsByProvider.clone(); - newMap.put("root", from); - Predicate[] predicates = getPredicates(cb, criteriaQuery, from, subCriteria, newMap); - if (c instanceof Query.GreaterThanEqualsAll sc) { - subquery.select(cb.max(from.get(c.getProperty()))).where(cb.and(predicates)); - return cb.greaterThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.GreaterThanAll sc) { - subquery.select(cb.max(from.get(c.getProperty()))).where(cb.and(predicates)); - return cb.greaterThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.LessThanEqualsAll sc) { - subquery.select(cb.min(from.get(c.getProperty()))).where(cb.and(predicates)); - return cb.lessThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.LessThanAll sc) { - subquery.select(cb.min(from.get(c.getProperty()))).where(cb.and(predicates)); - return cb.lessThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.EqualsAll sc) { - subquery.select(from.get(c.getProperty())).where(cb.and(predicates)); - return cb.equal(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.GreaterThanEqualsSome sc) { - subquery.select(cb.max(from.get(c.getProperty()))).where(cb.or(predicates)); - return cb.greaterThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.GreaterThanSome sc) { - subquery.select(cb.max(from.get(c.getProperty()))).where(cb.or(predicates)); - return cb.greaterThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.LessThanEqualsSome sc) { - subquery.select(cb.min(from.get(c.getProperty()))).where(cb.or(predicates)); - return cb.lessThanOrEqualTo(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (c instanceof Query.LessThanSome sc) { - subquery.select(cb.min(from.get(c.getProperty()))).where(cb.or(predicates)); - return cb.lessThan(fromsByProvider.getFullyQualifiedPath(sc.getProperty()), subquery); - } else if (criterion instanceof Query.NotIn sc - && Objects.nonNull(sc.getSubquery()) - && !sc.getSubquery().getProjections().isEmpty() - && sc.getSubquery().getProjections().get(0) instanceof Query.PropertyProjection - ) { - Query.PropertyProjection projection = (Query.PropertyProjection) sc.getSubquery().getProjections().get(0); - boolean distinct = projection instanceof Query.DistinctPropertyProjection; - subquery.select(from.get(projection.getPropertyName())).distinct(distinct).where(cb.and(predicates)); - return cb.in(fromsByProvider.getFullyQualifiedPath(sc.getProperty())).value(subquery); - } else if (criterion instanceof Query.NotIn sc - && Objects.nonNull(sc.getSubquery()) - && !sc.getSubquery().getProjections().isEmpty() - && sc.getSubquery().getProjections().get(0) instanceof Query.IdProjection - ) { - subquery.select(from).where(cb.and(predicates)); - return cb.in(root_.get("id")).value(subquery); - } } throw new IllegalArgumentException("Unsupported criterion: " + criterion); }).filter(Objects::nonNull).toList(); @@ -297,6 +300,24 @@ public class PredicateGenerator { return list.toArray(new Predicate[0]); } + private static CriteriaBuilder.In getQueryableCriteriaValue(HibernateCriteriaBuilder cb, CriteriaQuery criteriaQuery, JpaFromProvider fromsByProvider, PersistentEntity entity, Query.PropertyNameCriterion criterion, QueryableCriteria queryableCriteria) { + var projection = findPropertyOrIdProjection(queryableCriteria); + var subProperty = findSubproperty(projection); + var path = getPathFromInCriterion(fromsByProvider, criterion); + var in = findInPredicate(cb, projection, path, subProperty); + var subquery = criteriaQuery.subquery(getJavaTypeOfInClause((SqmInListPredicate) in)); + var from = subquery.from(queryableCriteria.getPersistentEntity().getJavaClass()); + var subCriteria = queryableCriteria.getCriteria(); + var clonedProviderByName = (JpaFromProvider) fromsByProvider.clone(); + clonedProviderByName.put("root", from); + var predicates = getPredicates(cb, criteriaQuery, from, subCriteria, clonedProviderByName, entity); + subquery.select(clonedProviderByName.getFullyQualifiedPath(subProperty)) + .distinct(true) + .where(cb.and(predicates)); + CriteriaBuilder.In value = in.value(subquery); + return value; + } + private static Predicate getExistsPredicate(HibernateCriteriaBuilder cb, From root_, PersistentEntity childPersistentEntity, Root subRoot) { Association owner = childPersistentEntity .getAssociations()
