GopikaReghunath commented on code in PR #2328:
URL: 
https://github.com/apache/incubator-kie-kogito-apps/pull/2328#discussion_r3503615603


##########
data-index/data-index-storage/data-index-storage-jpa-common/src/main/java/org/kie/kogito/index/jpa/storage/JPAQuery.java:
##########
@@ -156,17 +185,145 @@ protected final Predicate 
buildPredicateFunction(AttributeFilter filter, Root<E>
                 return builder
                         .lessThanOrEqualTo(getAttributePath(root, 
filter.getAttribute()), (Comparable) filter.getValue());
             case OR:
-                return builder.or(getRecursivePredicate(filter, root, 
builder).toArray(new Predicate[] {}));
+                return buildGroupedPredicate(filter, root, builder, 
criteriaQuery, false, false);
             case AND:
-                return builder.and(getRecursivePredicate(filter, root, 
builder).toArray(new Predicate[] {}));
+                return buildGroupedPredicate(filter, root, builder, 
criteriaQuery, true, false);
             case NOT:
-                return builder.not(filterPredicateFunction(root, 
builder).apply((AttributeFilter<?>) filter.getValue()));
+                AttributeFilter<?> innerFilter = (AttributeFilter<?>) 
filter.getValue();
+
+                // Handle NOT with AND/OR: Apply De Morgan's Law by negating 
and flipping the operator
+                if (innerFilter.getCondition() == FilterCondition.AND || 
innerFilter.getCondition() == FilterCondition.OR) {
+                    // NOT (A AND B) = NOT A OR NOT B, NOT (A OR B) = NOT A 
AND NOT B
+                    boolean flipToAnd = innerFilter.getCondition() == 
FilterCondition.OR;
+                    return buildGroupedPredicate(innerFilter, root, builder, 
criteriaQuery, flipToAnd, true);
+                }
+
+                if (innerFilter.getAttribute() != null && 
isCollectionAttribute(innerFilter.getAttribute()) &&
+                        (innerFilter.getCondition() == 
FilterCondition.CONTAINS ||
+                                innerFilter.getCondition() == 
FilterCondition.CONTAINS_ALL ||
+                                innerFilter.getCondition() == 
FilterCondition.CONTAINS_ANY ||
+                                innerFilter.getCondition() == 
FilterCondition.EQUAL)) {
+                    return buildCollectionPredicate(innerFilter, root, 
builder, criteriaQuery, true);
+                }
+
+                if (innerFilter.getAttribute() != null && 
isCollectionAttribute(innerFilter.getAttribute())) {
+                    return buildNegatedCollectionPredicate(innerFilter, root, 
builder, criteriaQuery);
+                }
+
+                return builder.not(filterPredicateFunction(root, builder, 
criteriaQuery).apply(innerFilter));
             default:
                 return null;
         }
 
     }
 
+    /**
+     * Builds predicates for AND/OR, grouping CONTAINS filters on same 
collection into single EXISTS.
+     * 
+     * @param isNegated if true, negates each predicate (for NOT operations 
with De Morgan's Law)
+     */
+    private Predicate buildGroupedPredicate(AttributeFilter<?> filter, Root<E> 
root,
+            CriteriaBuilder builder, CriteriaQuery<?> criteriaQuery, boolean 
isAnd, boolean isNegated) {
+
+        List<AttributeFilter<?>> nestedFilters = (List<AttributeFilter<?>>) 
filter.getValue();
+
+        java.util.Map<String, List<AttributeFilter<?>>> groups = new 
java.util.HashMap<>();
+        List<Predicate> otherPredicates = new ArrayList<>();
+
+        for (AttributeFilter<?> f : nestedFilters) {
+            if (f.getAttribute() != null && 
isCollectionAttribute(f.getAttribute()) &&
+                    (f.getCondition() == FilterCondition.CONTAINS ||
+                            f.getCondition() == FilterCondition.CONTAINS_ALL ||
+                            f.getCondition() == FilterCondition.CONTAINS_ANY ||
+                            f.getCondition() == FilterCondition.EQUAL)) {
+                String collection = f.getAttribute().split("\\.")[0];
+                groups.computeIfAbsent(collection, k -> new 
ArrayList<>()).add(f);
+            } else {
+                Predicate pred = filterPredicateFunction(root, builder, 
criteriaQuery).apply(f);
+                otherPredicates.add(isNegated ? builder.not(pred) : pred);
+            }
+        }
+
+        List<Predicate> allPredicates = new ArrayList<>(otherPredicates);
+        for (List<AttributeFilter<?>> groupFilters : groups.values()) {
+            if (groupFilters.size() == 1) {
+                
allPredicates.add(buildCollectionPredicate(groupFilters.get(0), root, builder, 
criteriaQuery, isNegated));
+            } else {
+                
allPredicates.add(buildMultiFilterCollectionPredicate(groupFilters, root, 
builder, criteriaQuery, isAnd, isNegated));
+            }
+        }
+
+        return isAnd ? builder.and(allPredicates.toArray(new Predicate[0]))
+                : builder.or(allPredicates.toArray(new Predicate[0]));
+    }
+
+    /**
+     * Builds single EXISTS with HAVING for multiple CONTAINS filters on same 
collection.
+     * Example: [{ comments.id: "A" }, { comments.status: "ACTIVE" }]
+     * → EXISTS(... HAVING SUM(id='A')>0 AND SUM(status='ACTIVE')>0)
+     * 
+     * @param isNegated if true, uses = 0 instead of > 0 and applies De 
Morgan's Law
+     */
+    private Predicate 
buildMultiFilterCollectionPredicate(List<AttributeFilter<?>> filters, Root<E> 
root,
+            CriteriaBuilder builder, CriteriaQuery<?> criteriaQuery, boolean 
combineWithAnd, boolean isNegated) {
+
+        String collectionName = filters.get(0).getAttribute().split("\\.")[0];
+
+        Subquery<Integer> subquery = criteriaQuery.subquery(Integer.class);
+        Root<E> subRoot = subquery.from(entityClass);
+        Join<?, ?> collectionJoin = subRoot.join(collectionName);
+
+        List<Predicate> havingConditions = new ArrayList<>();
+
+        for (AttributeFilter<?> filter : filters) {
+            String property = filter.getAttribute().split("\\.")[1];
+            List<Object> values = (filter.getCondition() == 
FilterCondition.CONTAINS || filter.getCondition() == FilterCondition.EQUAL)

Review Comment:
   comment addressed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to