InitCommit
This commit is contained in:
commit
94a7a72166
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
*.class
|
||||
*.log
|
||||
*.ctxt
|
||||
.mtj.tmp/
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
hs_err_pid*
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
.idea/**/contentModel.xml
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
cmake-build-*/
|
||||
.idea/**/mongoSettings.xml
|
||||
*.iws
|
||||
out/
|
||||
.idea_modules/
|
||||
atlassian-ide-plugin.xml
|
||||
.idea/replstate.xml
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
.idea/httpRequests
|
||||
.idea/caches/build_file_checksums.ser
|
29
LICENSE.md
Normal file
29
LICENSE.md
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020, Struchkov Mark
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
47
pom.xml
Normal file
47
pom.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.sadtech.haiti</groupId>
|
||||
<artifactId>haiti</artifactId>
|
||||
<version>0.0.1-RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>criteria-filter</artifactId>
|
||||
<version>0.0.1-RELEASE</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.sadtech.haiti</groupId>
|
||||
<artifactId>haiti-filter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>javax.persistence-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>uPagge</id>
|
||||
<name>Struchkov Mark</name>
|
||||
<email>upagge@ya.ru</email>
|
||||
<organization>SADTECH</organization>
|
||||
<url>https://uPagge.sadtech.org</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
</project>
|
@ -0,0 +1,19 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* // TODO: 09.11.2020 Добавить описание.
|
||||
*
|
||||
* @author upagge 09.11.2020
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class Container<T> {
|
||||
|
||||
private String joinTable;
|
||||
private Specification<T> specification;
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.sadtech.haiti.filter.Filter;
|
||||
import org.sadtech.haiti.filter.FilterQuery;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CriteriaFilter<T> implements Filter {
|
||||
|
||||
private final List<Specification<T>> andSpecifications = new ArrayList<>();
|
||||
private final List<Specification<T>> orSpecifications = new ArrayList<>();
|
||||
private final List<Specification<T>> notSpecifications = new ArrayList<>();
|
||||
|
||||
public static <T> Filter create() {
|
||||
return new CriteriaFilter<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter and(FilterQuery filterQuery) {
|
||||
andSpecifications.addAll(getSpecification(filterQuery));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter or(FilterQuery filterQuery) {
|
||||
orSpecifications.addAll(getSpecification(filterQuery));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter not(FilterQuery filterQuery) {
|
||||
notSpecifications.addAll(
|
||||
getSpecification(filterQuery).stream()
|
||||
.map(Specification::not)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<Specification<T>> getSpecification(FilterQuery filterQuery) {
|
||||
CriteriaQuery<T> criteriaQuery = (CriteriaQuery<T>) filterQuery;
|
||||
return criteriaQuery.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<T> build() {
|
||||
return generateSpecification(
|
||||
generateQueryAnd(andSpecifications),
|
||||
generateQueryAnd(notSpecifications),
|
||||
generateQueryOr(orSpecifications)
|
||||
);
|
||||
}
|
||||
|
||||
private Specification<T> generateQueryOr(List<Specification<T>> orSpecifications) {
|
||||
Specification<T> queryOr = null;
|
||||
if (!orSpecifications.isEmpty()) {
|
||||
queryOr = orSpecifications.get(0);
|
||||
if (orSpecifications.size() > 1) {
|
||||
for (int i = 1; i < orSpecifications.size(); i++) {
|
||||
queryOr = queryOr.or(orSpecifications.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return queryOr;
|
||||
}
|
||||
|
||||
private Specification<T> generateQueryAnd(List<Specification<T>> andSpecifications) {
|
||||
Specification<T> queryAnd = null;
|
||||
if (!andSpecifications.isEmpty()) {
|
||||
queryAnd = andSpecifications.get(0);
|
||||
if (andSpecifications.size() > 1) {
|
||||
for (int i = 1; i < andSpecifications.size(); i++) {
|
||||
queryAnd = queryAnd.and(andSpecifications.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return queryAnd;
|
||||
}
|
||||
|
||||
private Specification<T> generateSpecification(Specification<T>... specifications) {
|
||||
final List<Specification<T>> specificationList = Arrays.stream(specifications)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (!specificationList.isEmpty()) {
|
||||
Specification<T> query = Specification.where(specificationList.get(0));
|
||||
for (int i = 1; i < specificationList.size(); i++) {
|
||||
query = query.and(specificationList.get(i));
|
||||
}
|
||||
return query;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.sadtech.haiti.filter.FilterQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
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 SimpleCriteriaQuery<T> simpleCriteriaQuery = new SimpleCriteriaQuery();
|
||||
|
||||
public static <T> FilterQuery create() {
|
||||
return new CriteriaQuery<T>(new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Используется для присоединения таблицы, все последующие операции {@link CriteriaQuery} будут выполняться для
|
||||
* этого Join
|
||||
*
|
||||
* @param fieldName Имя поля сущности, которое отвечает за название таблицы.
|
||||
*/
|
||||
public CriteriaQuery<T> join(@NonNull String fieldName) {
|
||||
joinTable = fieldName;
|
||||
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));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterQuery matchPhrase(@NonNull String field, Object value) {
|
||||
if (value != null) {
|
||||
specifications.add(simpleCriteriaQuery.matchPhrase(joinTable, field, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> FilterQuery matchPhrase(@NonNull String field, Set<U> values) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
specifications.addAll(
|
||||
values.stream()
|
||||
.map(value -> simpleCriteriaQuery.matchPhrase(joinTable, field, value))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterQuery exists(String field) {
|
||||
if (field != null) {
|
||||
specifications.add(simpleCriteriaQuery.exists(joinTable, field));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterQuery like(@NonNull String field, String value, boolean ignoreCase) {
|
||||
specifications.add(
|
||||
ignoreCase
|
||||
? simpleCriteriaQuery.likeIgnoreCase(joinTable, field, value)
|
||||
: simpleCriteriaQuery.like(joinTable, field, value)
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterQuery checkBoolInt(@NonNull String field, Boolean flag) {
|
||||
if (flag != null) {
|
||||
specifications.add(
|
||||
simpleCriteriaQuery.between(joinTable, field, 0, Integer.MAX_VALUE)
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Q> Q build() {
|
||||
return (Q) specifications;
|
||||
}
|
||||
|
||||
public static <E> CriteriaQuery<E> empty() {
|
||||
final CriteriaQuery empty = EMPTY;
|
||||
return empty;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package org.sadtech.haiti.filter.criteria;
|
||||
|
||||
import lombok.NonNull;
|
||||
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleCriteriaQuery<T> {
|
||||
|
||||
private final Map<String, Join> 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));
|
||||
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)));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
return container;
|
||||
}
|
||||
|
||||
private Container<T> getContainer(String joinTableName) {
|
||||
final Container<T> container = new Container<>();
|
||||
container.setJoinTable(joinTableName);
|
||||
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);
|
||||
}
|
||||
return join.get(field);
|
||||
}
|
||||
return root.get(field);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user