Skip to content

Commit 45e0e1c

Browse files
author
mhewedy
committed
fix #30 set distinct if plural attributes (one-to-many and many-to-many) found on the expressions
1 parent c15d23e commit 45e0e1c

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

src/main/java/com/github/mhewedy/expressions/ExpressionsPredicateBuilder.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
import static com.github.mhewedy.expressions.Expression.*;
1919
import static java.util.Collections.singletonList;
2020
import static java.util.stream.Collectors.toList;
21+
import static javax.persistence.metamodel.Attribute.PersistentAttributeType;
2122

2223
class ExpressionsPredicateBuilder {
2324

24-
static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Expressions expressions) {
25+
static <T> Predicate getPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, Expressions expressions) {
2526

2627
Assert.notNull(expressions, "expressions must not be null!");
2728

28-
List<Predicate> predicates = getPredicates(cb,
29+
List<Predicate> predicates = getPredicates(query, cb,
2930
root,
3031
root.getModel(),
3132
expressions.getExpressions());
@@ -44,7 +45,7 @@ static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Expressions
4445
}
4546

4647
@SuppressWarnings({"rawtypes", "unchecked"})
47-
private static List<Predicate> getPredicates(CriteriaBuilder cb,
48+
private static List<Predicate> getPredicates(CriteriaQuery<?> query, CriteriaBuilder cb,
4849
Path<?> from, ManagedType<?> type,
4950
List<Expression> expressions) {
5051

@@ -60,12 +61,16 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
6061
Attribute<?, ?> attribute = getAttribute(type, field);
6162

6263
if (attribute.isAssociation()) {
64+
if (attribute instanceof PluralAttribute) {
65+
query.distinct(true);
66+
}
67+
6368
final String subField = extractSubField(singularExpression.field);
6469
if (!subField.isEmpty()) {
6570
final SingularExpression subExpression =
6671
new SingularExpression(subField, singularExpression.operator, singularExpression.value);
6772
predicates.addAll(
68-
getPredicates(cb,
73+
getPredicates(query, cb,
6974
reuseOrCreateJoin((From<?, ?>) from, attribute, field),
7075
extractSubFieldType(attribute),
7176
singletonList(subExpression)
@@ -77,7 +82,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
7782

7883
Path exprPath = from.get((SingularAttribute) attribute);
7984

80-
if (Attribute.PersistentAttributeType.EMBEDDED == attribute.getPersistentAttributeType()) {
85+
if (PersistentAttributeType.EMBEDDED == attribute.getPersistentAttributeType()) {
8186
final String subField = extractSubField(singularExpression.field);
8287
attribute = extractSubFieldType(attribute).getAttribute(subField);
8388
exprPath = exprPath.get((SingularAttribute) attribute);
@@ -114,7 +119,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
114119
predicate = cb.greaterThan(exprPath, (Comparable) attributeValue);
115120
} else {
116121
throw new IllegalArgumentException("field should be Number or Comparable: " +
117-
singularExpression);
122+
singularExpression);
118123
}
119124
break;
120125
case $gte:
@@ -124,7 +129,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
124129
predicate = cb.greaterThanOrEqualTo(exprPath, (Comparable) attributeValue);
125130
} else {
126131
throw new IllegalArgumentException("field should be Number or Comparable: " +
127-
singularExpression);
132+
singularExpression);
128133
}
129134
break;
130135
case $lt:
@@ -134,7 +139,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
134139
predicate = cb.lessThan(exprPath, (Comparable) attributeValue);
135140
} else {
136141
throw new IllegalArgumentException("field should be Number or Comparable: " +
137-
singularExpression);
142+
singularExpression);
138143
}
139144
break;
140145
case $lte:
@@ -144,7 +149,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
144149
predicate = cb.lessThanOrEqualTo(exprPath, (Comparable) attributeValue);
145150
} else {
146151
throw new IllegalArgumentException("field should be Number or Comparable: " +
147-
singularExpression);
152+
singularExpression);
148153
}
149154
break;
150155
// like
@@ -179,12 +184,16 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
179184
Attribute<?, ?> attribute = getAttribute(type, field);
180185

181186
if (attribute.isAssociation()) {
187+
if (attribute instanceof PluralAttribute) {
188+
query.distinct(true);
189+
}
190+
182191
final String subField = extractSubField(listExpression.field);
183192
if (!subField.isEmpty()) {
184193
final ListExpression subExpression =
185194
new ListExpression(subField, listExpression.operator, listExpression.values);
186195
predicates.addAll(
187-
getPredicates(cb,
196+
getPredicates(query, cb,
188197
reuseOrCreateJoin((From<?, ?>) from, attribute, field),
189198
extractSubFieldType(attribute),
190199
singletonList(subExpression)
@@ -196,7 +205,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
196205

197206
Path exprPath = from.get((SingularAttribute) attribute);
198207

199-
if (Attribute.PersistentAttributeType.EMBEDDED == attribute.getPersistentAttributeType()) {
208+
if (PersistentAttributeType.EMBEDDED == attribute.getPersistentAttributeType()) {
200209
final String subField = extractSubField(listExpression.field);
201210
attribute = extractSubFieldType(attribute).getAttribute(subField);
202211
exprPath = exprPath.get((SingularAttribute) attribute);
@@ -227,13 +236,13 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
227236

228237
} else if (expression instanceof OrExpression) {
229238
predicates.add(cb.or(
230-
getPredicates(cb, from, type,
239+
getPredicates(query, cb, from, type,
231240
((OrExpression) expression).expressions).toArray(new Predicate[0])
232241
));
233242

234243
} else if (expression instanceof AndExpression) {
235244
predicates.add(cb.and(
236-
getPredicates(cb, from, type,
245+
getPredicates(query, cb, from, type,
237246
((AndExpression) expression).expressions).toArray(new Predicate[0])
238247
));
239248
}
@@ -249,7 +258,7 @@ private static List<Predicate> getPredicates(CriteriaBuilder cb,
249258
throw new IllegalArgumentException(
250259
String.format(
251260
"Unable to locate attribute with the given name [%s] on this ManagedType [%s]," +
252-
" Are you sure this ManagedType or one of its ancestors contains such attribute?",
261+
" Are you sure this ManagedType or one of its ancestors contains such attribute?",
253262
field,
254263
type.getJavaType().getName()
255264
)

src/main/java/com/github/mhewedy/expressions/ExpressionsRepositoryImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ private static class ExpressionsSpecification<T> implements Specification<T> {
5252

5353
@Override
5454
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
55-
query.distinct(true); // to eliminate duplicate in case of one-to-many and many-to-many associations
56-
return ExpressionsPredicateBuilder.getPredicate(root, cb, expressions);
55+
return ExpressionsPredicateBuilder.getPredicate(root, query, cb, expressions);
5756
}
5857
}
5958
}

0 commit comments

Comments
 (0)