new logic join
This commit is contained in:
parent
9d90770bd9
commit
5534b18573
9
pom.xml
9
pom.xml
@ -6,12 +6,12 @@
|
||||
<parent>
|
||||
<groupId>org.sadtech.haiti</groupId>
|
||||
<artifactId>haiti</artifactId>
|
||||
<version>0.0.1-RELEASE</version>
|
||||
<version>0.0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.sadtech.haiti.filter</groupId>
|
||||
<artifactId>haiti-filter-criteria</artifactId>
|
||||
<version>0.0.2-RELEASE</version>
|
||||
<version>0.0.3-SNAPSHOT</version>
|
||||
|
||||
<name>Haiti Filter Criteria</name>
|
||||
<description>Fast creation of filtering requests using the Criteria Api wrapper.</description>
|
||||
@ -82,6 +82,11 @@
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>javax.persistence-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>5.4.29.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
@ -1,9 +1,13 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* // TODO: 09.11.2020 Добавить описание.
|
||||
*
|
||||
@ -11,9 +15,20 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class Container<T> {
|
||||
|
||||
private String joinTable;
|
||||
private final String uuid = UUID.randomUUID().toString();
|
||||
|
||||
private List<JoinTable> joinTables;
|
||||
private Specification<T> specification;
|
||||
|
||||
private Container(List<JoinTable> joinTables) {
|
||||
this.joinTables = joinTables;
|
||||
}
|
||||
|
||||
public static <T> Container<T> of(List<JoinTable> joinTables) {
|
||||
return new Container<>(joinTables);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.sadtech.haiti.filter.FilterQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -14,8 +15,8 @@ import java.util.stream.Collectors;
|
||||
public class CriteriaQuery<T> implements FilterQuery {
|
||||
|
||||
private static final CriteriaQuery<?> EMPTY = new CriteriaQuery<>(new ArrayList<>());
|
||||
private final List<Container<T>> specifications;
|
||||
private String joinTable;
|
||||
private final List<Container<T>> containers;
|
||||
private List<JoinTable> joinTables = new ArrayList<>();
|
||||
private final SimpleCriteriaQuery<T> simpleCriteriaQuery = new SimpleCriteriaQuery();
|
||||
|
||||
public static <T> FilterQuery create() {
|
||||
@ -28,15 +29,38 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
*
|
||||
* @param fieldName Имя поля сущности, которое отвечает за название таблицы.
|
||||
*/
|
||||
public CriteriaQuery<T> join(@NonNull String fieldName) {
|
||||
joinTable = fieldName;
|
||||
public CriteriaQuery<T> join(@NonNull String... fieldName) {
|
||||
joinTables = Arrays.stream(fieldName)
|
||||
.map(JoinTable::of)
|
||||
.collect(Collectors.toList());
|
||||
return this;
|
||||
}
|
||||
|
||||
public CriteriaQuery<T> join(@NonNull JoinTable... joinTables) {
|
||||
this.joinTables = Arrays.stream(joinTables).collect(Collectors.toList());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y extends Comparable<? super Y>> FilterQuery between(@NonNull String field, Y from, Y to) {
|
||||
if (from != null && to != null) {
|
||||
specifications.add(simpleCriteriaQuery.between(joinTable, field, from, to));
|
||||
containers.add(simpleCriteriaQuery.between(joinTables, field, from, to));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y extends Comparable<? super Y>> FilterQuery greaterThan(@NonNull String field, Y value) {
|
||||
if (value != null) {
|
||||
containers.add(simpleCriteriaQuery.greaterThan(joinTables, field, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y extends Comparable<? super Y>> FilterQuery lessThan(@NonNull String field, Y value) {
|
||||
if (value != null) {
|
||||
containers.add(simpleCriteriaQuery.lessThan(joinTables, field, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -44,7 +68,7 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
@Override
|
||||
public FilterQuery matchPhrase(@NonNull String field, Object value) {
|
||||
if (value != null) {
|
||||
specifications.add(simpleCriteriaQuery.matchPhrase(joinTable, field, value));
|
||||
containers.add(simpleCriteriaQuery.matchPhrase(joinTables, field, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -52,9 +76,20 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
@Override
|
||||
public <U> FilterQuery matchPhrase(@NonNull String field, Set<U> values) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
specifications.addAll(
|
||||
containers.addAll(
|
||||
values.stream()
|
||||
.map(value -> simpleCriteriaQuery.matchPhrase(joinTable, field, value))
|
||||
.map(value -> simpleCriteriaQuery.matchPhrase(joinTables, field, value))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <U extends List<U>> CriteriaQuery<T> collectionElementsIn(List<U> values) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
containers.addAll(
|
||||
values.stream()
|
||||
.map(value -> simpleCriteriaQuery.collectionElements(joinTables, value))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
@ -64,17 +99,17 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
@Override
|
||||
public FilterQuery exists(String field) {
|
||||
if (field != null) {
|
||||
specifications.add(simpleCriteriaQuery.exists(joinTable, field));
|
||||
containers.add(simpleCriteriaQuery.exists(joinTables, field));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterQuery like(@NonNull String field, String value, boolean ignoreCase) {
|
||||
specifications.add(
|
||||
containers.add(
|
||||
ignoreCase
|
||||
? simpleCriteriaQuery.likeIgnoreCase(joinTable, field, value)
|
||||
: simpleCriteriaQuery.like(joinTable, field, value)
|
||||
? simpleCriteriaQuery.likeIgnoreCase(joinTables, field, value)
|
||||
: simpleCriteriaQuery.like(joinTables, field, value)
|
||||
);
|
||||
return this;
|
||||
}
|
||||
@ -82,8 +117,8 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
@Override
|
||||
public FilterQuery checkBoolInt(@NonNull String field, Boolean flag) {
|
||||
if (flag != null) {
|
||||
specifications.add(
|
||||
simpleCriteriaQuery.between(joinTable, field, 0, Integer.MAX_VALUE)
|
||||
containers.add(
|
||||
simpleCriteriaQuery.between(joinTables, field, 0, Integer.MAX_VALUE)
|
||||
);
|
||||
}
|
||||
return this;
|
||||
@ -91,7 +126,7 @@ public class CriteriaQuery<T> implements FilterQuery {
|
||||
|
||||
@Override
|
||||
public <Q> Q build() {
|
||||
return (Q) specifications.stream()
|
||||
return (Q) containers.stream()
|
||||
.map(Container::getSpecification)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* // TODO: 15.04.2021 Добавить описание.
|
||||
*
|
||||
* @author upagge 15.04.2021
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class JoinTable {
|
||||
|
||||
private final String tableName;
|
||||
private final JoinTypeOperation joinTypeOperation;
|
||||
|
||||
public static JoinTable of(@NonNull String tableName) {
|
||||
return new JoinTable(tableName, JoinTypeOperation.LEFT);
|
||||
}
|
||||
|
||||
public static JoinTable of(@NonNull String tableName, JoinTypeOperation joinType) {
|
||||
return new JoinTable(tableName, joinType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import javax.persistence.criteria.JoinType;
|
||||
|
||||
/**
|
||||
* // TODO: 15.04.2021 Добавить описание.
|
||||
*
|
||||
* @author upagge 15.04.2021
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum JoinTypeOperation {
|
||||
|
||||
LEFT(JoinType.LEFT),
|
||||
INNER(JoinType.INNER);
|
||||
|
||||
private final JoinType criteriaType;
|
||||
|
||||
}
|
@ -1,63 +1,114 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.NonNull;
|
||||
import org.hibernate.query.criteria.internal.path.PluralAttributeJoinSupport;
|
||||
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SimpleCriteriaQuery<T> {
|
||||
|
||||
private final Map<String, Join> joinMap = new HashMap<>();
|
||||
private From<Object, Object> lastJoin;
|
||||
private final Set<String> unique = new HashSet<>();
|
||||
private final Map<String, From<Object, Object>> joinMap = new HashMap<>();
|
||||
|
||||
public Container<T> matchPhrase(String joinTable, @NonNull String field, @NonNull Object value) {
|
||||
final Container<T> container = getContainer(joinTable);
|
||||
container.setSpecification((root, query, cb) -> cb.equal(getPath(root, joinTable, field), value));
|
||||
public Container<T> matchPhrase(List<JoinTable> joinTables, @NonNull String field, @NonNull Object value) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification((root, query, cb) -> cb.equal(getPath(root, container).get(field), value));
|
||||
return container;
|
||||
}
|
||||
|
||||
public Container<T> exists(String joinTable, @NonNull String field) {
|
||||
final Container<T> container = getContainer(joinTable);
|
||||
container.setSpecification((root, query, cb) -> cb.isNotNull(getPath(root, joinTable, field)));
|
||||
public <U> Container<T> collectionElements(List<JoinTable> joinTables, List<U> values) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification(
|
||||
(root, query, builder) -> {
|
||||
Predicate where = builder.conjunction();
|
||||
return builder.and(where, getPath(root, container).in(values));
|
||||
}
|
||||
);
|
||||
return container;
|
||||
}
|
||||
|
||||
public Container<T> likeIgnoreCase(String joinTable, @NonNull String field, String value) {
|
||||
final Container<T> container = getContainer(joinTable);
|
||||
container.setSpecification((root, query, cb) -> cb.like(cb.lower(getPath(root, joinTable, field)), value));
|
||||
public Container<T> exists(List<JoinTable> joinTables, @NonNull String field) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification((root, query, cb) -> cb.isNotNull(getPath(root, container).get(field)));
|
||||
return container;
|
||||
}
|
||||
|
||||
public Container<T> like(String joinTable, @NonNull String field, String value) {
|
||||
final Container<T> container = getContainer(joinTable);
|
||||
container.setSpecification((root, query, cb) -> cb.like(getPath(root, joinTable, field), value));
|
||||
public Container<T> likeIgnoreCase(List<JoinTable> joinTables, @NonNull String field, String value) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification((root, query, cb) -> cb.like(cb.lower(getPath(root, container).get(field)), value));
|
||||
return container;
|
||||
}
|
||||
|
||||
public <Y extends Comparable<? super Y>> Container<T> between(String joinTable, @NonNull String field, Y from, Y to) {
|
||||
final Container<T> container = getContainer(joinTable);
|
||||
container.setSpecification((root, query, cb) -> cb.between(getPath(root, joinTable, field), from, to));
|
||||
public Container<T> like(List<JoinTable> joinTables, @NonNull String field, String value) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification((root, query, cb) -> cb.like(getPath(root, container).get(field), value));
|
||||
return container;
|
||||
}
|
||||
|
||||
private Container<T> getContainer(String joinTableName) {
|
||||
final Container<T> container = new Container<>();
|
||||
container.setJoinTable(joinTableName);
|
||||
public <Y extends Comparable<? super Y>> Container<T> between(List<JoinTable> joinTables, @NonNull String field, Y from, Y to) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification((root, query, cb) -> cb.between(getPath(root, container).get(field), from, to));
|
||||
return container;
|
||||
}
|
||||
|
||||
private <Z> Expression<Z> getPath(Root<T> root, String joinTable, String field) {
|
||||
if (joinTable != null) {
|
||||
Join join = joinMap.get(joinTable);
|
||||
if (join == null) {
|
||||
join = root.join(joinTable);
|
||||
joinMap.put(joinTable, join);
|
||||
public <Y extends Comparable<? super Y>> Container<T> greaterThan(List<JoinTable> joinTables, @NonNull String field, Y value) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification(((root, query, cb) -> cb.greaterThan(getPath(root, container).get(field), value)));
|
||||
return container;
|
||||
}
|
||||
|
||||
public <Y extends Comparable<? super Y>> Container<T> lessThan(List<JoinTable> joinTables, @NonNull String field, Y value) {
|
||||
final Container<T> container = Container.of(joinTables);
|
||||
container.setSpecification(((root, query, cb) -> cb.lessThan(getPath(root, container).get(field), value)));
|
||||
return container;
|
||||
}
|
||||
|
||||
private From<Object, Object> getPath(Root root, Container<T> container) {
|
||||
final List<JoinTable> joinTables = container.getJoinTables();
|
||||
final String uuid = container.getUuid();
|
||||
From<Object, Object> join = root;
|
||||
if (!joinTables.isEmpty()) {
|
||||
check(uuid);
|
||||
for (JoinTable table : joinTables) {
|
||||
final String tableName = table.getTableName();
|
||||
final JoinType criteriaType = table.getJoinTypeOperation().getCriteriaType();
|
||||
if (joinMap.containsKey(tableName)) {
|
||||
join = joinMap.get(tableName);
|
||||
} else {
|
||||
final Set<String> attributes = ((Root<Object>) root).getModel().getAttributes().stream()
|
||||
.map(Attribute::getName)
|
||||
.collect(Collectors.toSet());
|
||||
if (attributes.contains(tableName)) {
|
||||
join = root.join(tableName, criteriaType);
|
||||
} else {
|
||||
join = lastJoin.join(tableName, criteriaType);
|
||||
}
|
||||
if (join instanceof PluralAttributeJoinSupport && !((PluralAttributeJoinSupport) join).isBasicCollection()) {
|
||||
lastJoin = join;
|
||||
}
|
||||
joinMap.put(tableName, join);
|
||||
}
|
||||
}
|
||||
return join.get(field);
|
||||
}
|
||||
return root.get(field);
|
||||
return join;
|
||||
}
|
||||
|
||||
private void check(String uuid) {
|
||||
if (unique.contains(uuid)) {
|
||||
joinMap.clear();
|
||||
}
|
||||
unique.add(uuid);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user