Skip to content

Commit 6d2d6f8

Browse files
author
gustavnavar
committed
Add support for "duplicated" filters
1 parent 96bc08d commit 6d2d6f8

30 files changed

Lines changed: 493 additions & 120 deletions

gridcore/src/main/java/me/agno/gridcore/filtering/DefaultColumnFilter.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package me.agno.gridcore.filtering;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67
import me.agno.gridcore.filtering.types.FilterTypeResolver;
78
import me.agno.gridcore.filtering.types.IFilterType;
9+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
810

911
import java.util.List;
1012

@@ -19,12 +21,13 @@ public DefaultColumnFilter(String expression, Class<TData> targetType) {
1921
this.targetType = targetType;
2022
}
2123

22-
public Predicate applyFilter(CriteriaBuilder cb, Root<T> root, List<ColumnFilterValue> values) {
23-
return applyFilter(cb, root, values, null);
24+
public Predicate applyFilter(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
25+
SqmQuerySpec source, List<ColumnFilterValue> values) {
26+
return applyFilter(cb, cq, root, source, values,null);
2427
}
2528

26-
public Predicate applyFilter(CriteriaBuilder cb, Root<T> root, List<ColumnFilterValue> values,
27-
String removeDiacritics) {
29+
public Predicate applyFilter(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
30+
SqmQuerySpec source, List<ColumnFilterValue> values, String removeDiacritics) {
2831
if (values == null && values.stream().noneMatch(ColumnFilterValue::isNotNull))
2932
throw new IllegalArgumentException ("values");
3033

@@ -41,11 +44,12 @@ public Predicate applyFilter(CriteriaBuilder cb, Root<T> root, List<ColumnFilter
4144

4245
var filterValues = values.stream().filter(r -> r.isNotNull() && r.getFilterType() != GridFilterType.CONDITION).toList();
4346

44-
return GetFilterExpression(cb, root, filterValues, condition, removeDiacritics);
47+
return GetFilterExpression(cb, cq, root, source, filterValues, condition, removeDiacritics);
4548
}
4649

47-
private Predicate GetFilterExpression(CriteriaBuilder cb, Root<T> root, List<ColumnFilterValue> values,
48-
GridFilterCondition condition, String removeDiacritics) {
50+
private Predicate GetFilterExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
51+
SqmQuerySpec source, List<ColumnFilterValue> values, GridFilterCondition condition,
52+
String removeDiacritics) {
4953

5054
Predicate mainPredicate = null;
5155

@@ -54,7 +58,7 @@ private Predicate GetFilterExpression(CriteriaBuilder cb, Root<T> root, List<Col
5458
if (value.isNull())
5559
continue;
5660

57-
Predicate predicate = GetExpression(cb, root, value, removeDiacritics);
61+
Predicate predicate = GetExpression(cb, cq, root, source, value, removeDiacritics);
5862
if (predicate != null) {
5963
if (mainPredicate == null)
6064
mainPredicate = predicate;
@@ -71,10 +75,11 @@ else if (condition.equals(GridFilterCondition.OR)) {
7175
return mainPredicate;
7276
}
7377

74-
private Predicate GetExpression(CriteriaBuilder cb, Root<T> root, ColumnFilterValue value, String removeDiacritics)
78+
private Predicate GetExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
79+
SqmQuerySpec source, ColumnFilterValue value, String removeDiacritics)
7580
{
7681
IFilterType<T, TData> filterType = this.typeResolver.GetFilterType(this.targetType);
77-
return filterType.getFilterExpression(cb, root, this.expression, value.getFilterValue(),
82+
return filterType.getFilterExpression(cb, cq, root, source, this.expression, value.getFilterValue(),
7883
value.getFilterType(), removeDiacritics);
7984
}
8085
}

gridcore/src/main/java/me/agno/gridcore/filtering/FilterProcessor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import lombok.Setter;
55
import me.agno.gridcore.IGrid;
66
import me.agno.gridcore.columns.IGridColumn;
7+
import org.hibernate.query.sqm.tree.SqmCopyContext;
8+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
9+
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
710

811
import java.util.ArrayList;
912
import java.util.List;
@@ -34,6 +37,10 @@ public Predicate process(Predicate predicate) {
3437
if (this.process != null)
3538
return this.process.apply(predicate);
3639

40+
var gridQuery = (SqmSelectStatement) grid.getCriteriaQuery();
41+
var gridQuerySpec = gridQuery.getQuerySpec();
42+
SqmQuerySpec source = gridQuerySpec.copy(SqmCopyContext.simpleContext());
43+
3744
for (IGridColumn<T> gridColumn : this.grid.getColumns().values()) {
3845
if (gridColumn == null) continue;
3946
if (gridColumn.getFilter() == null) continue;
@@ -47,8 +54,8 @@ public Predicate process(Predicate predicate) {
4754
options = this.settings.getFilteredColumns().getByColumn(gridColumn);
4855
}
4956

50-
var newPredicate = gridColumn.getFilter().applyFilter(this.grid.getCriteriaBuilder(), this.grid.getRoot(),
51-
options, this.grid.getRemoveDiacritics());
57+
var newPredicate = gridColumn.getFilter().applyFilter(this.grid.getCriteriaBuilder(), this.grid.getCriteriaQuery(),
58+
this.grid.getRoot(), source, options, this.grid.getRemoveDiacritics());
5259

5360
if(predicate == null)
5461
predicate = newPredicate;

gridcore/src/main/java/me/agno/gridcore/filtering/GridFilterType.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ public enum GridFilterType {
1616
CONDITION,
1717
NOT_EQUALS,
1818
IS_NULL,
19-
IS_NOT_NULL;
19+
IS_NOT_NULL,
20+
IS_DUPLICATED,
21+
IS_NOT_DUPLICATED;
2022

2123
@Override public String toString() {
2224
return switch (this) {
@@ -33,6 +35,8 @@ public enum GridFilterType {
3335
case NOT_EQUALS -> "10";
3436
case IS_NULL -> "11";
3537
case IS_NOT_NULL -> "12";
38+
case IS_DUPLICATED -> "13";
39+
case IS_NOT_DUPLICATED -> "14";
3640
default -> null;
3741
};
3842
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package me.agno.gridcore.filtering;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67

8+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
9+
710
import java.util.List;
811

912
public interface IColumnFilter<T> {
1013

11-
Predicate applyFilter(CriteriaBuilder cb, Root<T> root, List<ColumnFilterValue> values);
14+
Predicate applyFilter(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root, SqmQuerySpec source,
15+
List<ColumnFilterValue> values);
1216

13-
Predicate applyFilter(CriteriaBuilder cb, Root<T> root, List<ColumnFilterValue> values, String removeDiacritics);
17+
Predicate applyFilter(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root, SqmQuerySpec source,
18+
List<ColumnFilterValue> values, String removeDiacritics);
1419
}

gridcore/src/main/java/me/agno/gridcore/filtering/types/BigDecimalFilterType.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package me.agno.gridcore.filtering.types;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67
import lombok.Getter;
78
import me.agno.gridcore.filtering.GridFilterType;
9+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
810

911
import java.math.BigDecimal;
1012

@@ -15,23 +17,31 @@ public class BigDecimalFilterType<T> extends FilterTypeBase<T, BigDecimal> {
1517

1618
public GridFilterType getValidType(GridFilterType type) {
1719
return switch (type) {
18-
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS -> type;
20+
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS,
21+
IS_DUPLICATED, IS_NOT_DUPLICATED -> type;
1922
default -> GridFilterType.EQUALS;
2023
};
2124
}
2225

2326
public BigDecimal getTypedValue(String value) {
24-
return new BigDecimal(value);
27+
try {
28+
return new BigDecimal(value);
29+
}
30+
catch (Exception e) {
31+
return null;
32+
}
2533
}
2634

27-
public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String expression, String value, GridFilterType filterType,
28-
String removeDiacritics) {
35+
public Predicate getFilterExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
36+
SqmQuerySpec source, String expression, String value,
37+
GridFilterType filterType, String removeDiacritics) {
2938

3039
//base implementation of building filter expressions
3140
filterType = getValidType(filterType);
3241

3342
BigDecimal typedValue = getTypedValue(value);
34-
if (typedValue == null)
43+
if (typedValue == null &&
44+
filterType != GridFilterType.IS_DUPLICATED && filterType != GridFilterType.IS_NOT_DUPLICATED)
3545
return null; //incorrent filter value;
3646

3747
var path = getPath(root, expression);
@@ -43,6 +53,9 @@ public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String ex
4353
case LESS_THAN_OR_EQUALS -> cb.le(path, typedValue);
4454
case GREATER_THAN -> cb.gt(path, typedValue);
4555
case GREATER_THAN_OR_EQUALS -> cb.ge(path, typedValue);
56+
case IS_DUPLICATED -> isDuplicated(cb, cq, root, source, this.targetType, expression);
57+
case IS_NOT_DUPLICATED -> isNotDuplicated(cb, cq, root, source,this.targetType,
58+
expression);
4659
default -> throw new IllegalArgumentException();
4760
};
4861
}

gridcore/src/main/java/me/agno/gridcore/filtering/types/BigIntegerFilterType.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package me.agno.gridcore.filtering.types;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67
import lombok.Getter;
78
import me.agno.gridcore.filtering.GridFilterType;
9+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
810

911
import java.math.BigInteger;
1012

@@ -15,23 +17,31 @@ public class BigIntegerFilterType<T> extends FilterTypeBase<T, BigInteger> {
1517

1618
public GridFilterType getValidType(GridFilterType type) {
1719
return switch (type) {
18-
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS -> type;
20+
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS,
21+
IS_DUPLICATED, IS_NOT_DUPLICATED -> type;
1922
default -> GridFilterType.EQUALS;
2023
};
2124
}
2225

2326
public BigInteger getTypedValue(String value) {
24-
return new BigInteger(value);
27+
try {
28+
return new BigInteger(value);
29+
}
30+
catch (Exception e) {
31+
return null;
32+
}
2533
}
2634

27-
public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String expression, String value, GridFilterType filterType,
28-
String removeDiacritics) {
35+
public Predicate getFilterExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
36+
SqmQuerySpec source, String expression, String value,
37+
GridFilterType filterType, String removeDiacritics) {
2938

3039
//base implementation of building filter expressions
3140
filterType = getValidType(filterType);
3241

3342
BigInteger typedValue = this.getTypedValue(value);
34-
if (typedValue == null)
43+
if (typedValue == null &&
44+
filterType != GridFilterType.IS_DUPLICATED && filterType != GridFilterType.IS_NOT_DUPLICATED)
3545
return null; //incorrent filter value;
3646

3747
var path = getPath(root, expression);
@@ -43,6 +53,9 @@ public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String ex
4353
case LESS_THAN_OR_EQUALS -> cb.le(path, typedValue);
4454
case GREATER_THAN -> cb.gt(path, typedValue);
4555
case GREATER_THAN_OR_EQUALS -> cb.ge(path, typedValue);
56+
case IS_DUPLICATED -> isDuplicated(cb, cq, root, source,this.targetType, expression);
57+
case IS_NOT_DUPLICATED -> isNotDuplicated(cb, cq, root, source,this.targetType,
58+
expression);
4659
default -> throw new IllegalArgumentException();
4760
};
4861
}

gridcore/src/main/java/me/agno/gridcore/filtering/types/BooleanFilterType.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package me.agno.gridcore.filtering.types;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67
import lombok.Getter;
78
import me.agno.gridcore.filtering.GridFilterType;
9+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
810

911
import java.util.Objects;
1012

@@ -23,7 +25,8 @@ public Boolean getTypedValue(String value) {
2325
return "true".equalsIgnoreCase(value);
2426
}
2527

26-
public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String expression, String value,
28+
public Predicate getFilterExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
29+
SqmQuerySpec source, String expression, String value,
2730
GridFilterType filterType, String removeDiacritics) {
2831

2932
//base implementation of building filter expressions

gridcore/src/main/java/me/agno/gridcore/filtering/types/ByteFilterType.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package me.agno.gridcore.filtering.types;
22

33
import jakarta.persistence.criteria.CriteriaBuilder;
4+
import jakarta.persistence.criteria.CriteriaQuery;
45
import jakarta.persistence.criteria.Predicate;
56
import jakarta.persistence.criteria.Root;
67
import lombok.Getter;
78
import me.agno.gridcore.filtering.GridFilterType;
9+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
810

911
import java.nio.charset.StandardCharsets;
1012

@@ -15,23 +17,31 @@ public final class ByteFilterType<T> extends FilterTypeBase<T, Byte> {
1517

1618
public GridFilterType getValidType(GridFilterType type) {
1719
return switch (type) {
18-
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS -> type;
20+
case EQUALS, NOT_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, LESS_THAN, LESS_THAN_OR_EQUALS,
21+
IS_DUPLICATED, IS_NOT_DUPLICATED -> type;
1922
default -> GridFilterType.EQUALS;
2023
};
2124
}
2225

2326
public Byte getTypedValue(String value) {
24-
return value.getBytes(StandardCharsets.UTF_8)[0];
27+
try {
28+
return value.getBytes(StandardCharsets.UTF_8)[0];
29+
}
30+
catch (Exception e) {
31+
return null;
32+
}
2533
}
2634

27-
public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String expression, String value, GridFilterType filterType,
28-
String removeDiacritics) {
35+
public Predicate getFilterExpression(CriteriaBuilder cb, CriteriaQuery<T> cq, Root<T> root,
36+
SqmQuerySpec source, String expression, String value,
37+
GridFilterType filterType, String removeDiacritics) {
2938

3039
//base implementation of building filter expressions
3140
filterType = this.getValidType(filterType);
3241

3342
Byte typedValue = this.getTypedValue(value);
34-
if (typedValue == null)
43+
if (typedValue == null &&
44+
filterType != GridFilterType.IS_DUPLICATED && filterType != GridFilterType.IS_NOT_DUPLICATED)
3545
return null; //incorrent filter value;
3646

3747
var path = getPath(root, expression);
@@ -43,6 +53,9 @@ public Predicate getFilterExpression(CriteriaBuilder cb, Root<T> root, String ex
4353
case LESS_THAN_OR_EQUALS -> cb.le(path, typedValue);
4454
case GREATER_THAN -> cb.gt(path, typedValue);
4555
case GREATER_THAN_OR_EQUALS -> cb.ge(path, typedValue);
56+
case IS_DUPLICATED -> isDuplicated(cb, cq, root, source, this.targetType, expression);
57+
case IS_NOT_DUPLICATED -> isNotDuplicated(cb, cq, root, source,this.targetType,
58+
expression);
4659
default -> throw new IllegalArgumentException();
4760
};
4861
}

0 commit comments

Comments
 (0)