Skip to content

Commit

Permalink
[backend/frontend] Improv code
Browse files Browse the repository at this point in the history
  • Loading branch information
RomuDeuxfois committed Aug 26, 2024
1 parent 639c3ea commit db7f69d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static <T> Specification<T> computeSearchJpa(@Nullable final String searc
List<PropertySchema> searchableProperties = getSearchableProperties(propertySchemas);
List<Predicate> predicates = searchableProperties.stream()
.map(propertySchema -> {
Expression<Object> paths = toPath(propertySchema, root);
Expression<String> paths = toPath(propertySchema, root);
return toPredicate(paths, search, cb, propertySchema.getType());
})
.toList();
Expand All @@ -44,7 +44,7 @@ public static <T> Specification<T> computeSearchJpa(@Nullable final String searc
}

private static Predicate toPredicate(
@NotNull final Expression<Object> paths,
@NotNull final Expression<String> paths,
@NotNull final String search,
@NotNull final CriteriaBuilder cb,
@NotNull final Class<?> type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import jakarta.persistence.criteria.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;

import javax.annotation.Nullable;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand All @@ -22,6 +22,7 @@
import static io.openbas.database.model.Filters.FilterMode.and;
import static io.openbas.database.model.Filters.FilterMode.or;
import static io.openbas.utils.JpaUtils.toPath;
import static io.openbas.utils.OperationUtilsJpa.*;
import static io.openbas.utils.schema.SchemaUtils.getFilterableProperties;
import static io.openbas.utils.schema.SchemaUtils.retrieveProperty;

Expand Down Expand Up @@ -69,7 +70,7 @@ public static <T> Specification<T> computeFilterGroupJpa(@Nullable final FilterG
}

@SuppressWarnings("unchecked")
private static <T> Specification<T> computeFilter(@Nullable final Filter filter) {
private static <T, U> Specification<T> computeFilter(@Nullable final Filter filter) {
if (filter == null) {
return (Specification<T>) EMPTY_SPECIFICATION;
}
Expand All @@ -79,7 +80,7 @@ private static <T> Specification<T> computeFilter(@Nullable final Filter filter)
List<PropertySchema> propertySchemas = SchemaUtils.schema(root.getJavaType());
List<PropertySchema> filterableProperties = getFilterableProperties(propertySchemas);
PropertySchema filterableProperty = retrieveProperty(filterableProperties, filterKey);
Expression<Object> paths = toPath(filterableProperty, root);
Expression<U> paths = toPath(filterableProperty, root);
// In case of join table, we will use ID so type is String
return toPredicate(
paths, filter, cb, filterableProperty.getJoinTable() != null ? String.class : filterableProperty.getType()
Expand Down Expand Up @@ -114,61 +115,50 @@ public static <T> Specification<T> computeFilterFromSpecificPath(
};
}

private static Predicate toPredicate(
@NotNull final Expression<Object> paths,
private static <U> Predicate toPredicate(
@NotNull final Expression<U> paths,
@NotNull final Filter filter,
@NotNull final CriteriaBuilder cb,
@NotNull final Class<?> type) {
BiFunction<Expression<Object>, List<String>, Predicate> operation = computeOperation(
BiFunction<Expression<U>, List<String>, Predicate> operation = computeOperation(
filter.getOperator(), cb, type
);
return operation.apply(paths, filter.getValues());
}

// -- OPERATOR --

private static BiFunction<Expression<Object>, List<String>, Predicate> computeOperation(
@NotNull final FilterOperator operator,
private static <U> BiFunction<Expression<U>, List<String>, Predicate> computeOperation(
@Nullable final FilterOperator operator,
@NotNull final CriteriaBuilder cb,
@NotNull final Class<?> type) {
if (operator == null) {
// Default case
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.equalsTexts(paths, cb, texts, type);
throw new IllegalArgumentException("Operator cannot be null");
}
if (operator.equals(FilterOperator.not_contains)) {
return (Expression<Object> paths, List<String> texts) -> {
if (CollectionUtils.isEmpty(texts)) {
return null;
}
return OperationUtilsJpa.notContainsTexts(paths, cb, texts, type);
};
return (Expression<U> paths, List<String> texts) -> notContainsTexts((Expression<String>) paths, cb, texts, type);
} else if (operator.equals(FilterOperator.contains)) {
return (Expression<Object> paths, List<String> texts) -> {
if (CollectionUtils.isEmpty(texts)) {
return null;
}
return OperationUtilsJpa.containsTexts(paths, cb, texts, type);
};
return (Expression<U> paths, List<String> texts) -> containsTexts((Expression<String>) paths, cb, texts, type);
} else if (operator.equals(FilterOperator.not_starts_with)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.notStartWithTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> notStartWithTexts((Expression<String>) paths, cb, texts);
} else if (operator.equals(FilterOperator.starts_with)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.startWithTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> startWithTexts((Expression<String>) paths, cb, texts);
} else if (operator.equals(FilterOperator.empty)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.empty(paths, cb, type);
return (Expression<U> paths, List<String> texts) -> empty((Expression<String>) paths, cb, type);
} else if (operator.equals(FilterOperator.not_empty)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.notEmpty(paths, cb, type);
return (Expression<U> paths, List<String> texts) -> notEmpty((Expression<String>) paths, cb, type);
} else if (operator.equals(FilterOperator.gt)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.greaterThanTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> greaterThanTexts((Expression<Instant>) paths, cb, texts);
} else if (operator.equals(FilterOperator.gte)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.greaterThanOrEqualTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> greaterThanOrEqualTexts((Expression<Instant>) paths, cb, texts);
} else if (operator.equals(FilterOperator.lt)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.lessThanTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> lessThanTexts((Expression<Instant>) paths, cb, texts);
} else if (operator.equals(FilterOperator.lte)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.lessThanOrEqualTexts(paths, cb, texts);
return (Expression<U> paths, List<String> texts) -> lessThanOrEqualTexts((Expression<Instant>) paths, cb, texts);
} else if (operator.equals(FilterOperator.not_eq)) {
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.notEqualsTexts(paths, cb, texts, type);
return (Expression<U> paths, List<String> texts) -> notEqualsTexts((Expression<String>) paths, cb, texts, type);
} else { // Default case -> equals
return (Expression<Object> paths, List<String> texts) -> OperationUtilsJpa.equalsTexts(paths, cb, texts, type);
return (Expression<U> paths, List<String> texts) -> equalsTexts((Expression<String>) paths, cb, texts, type);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ private JpaUtils() {

}

public static <T> Expression<Object> toPath(
public static <T, U> Expression<U> toPath(
@NotNull final PropertySchema propertySchema,
@NotNull final Root<T> root) {
// Join
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ private OperationUtilsJpa() {
// -- NOT CONTAINS --

public static Predicate notContainsTexts(
Expression<Object> paths, CriteriaBuilder cb,
Expression<String> paths, CriteriaBuilder cb,
List<String> texts, Class<?> type) {
if (isEmpty(texts)) {
return cb.conjunction();
}

Predicate[] predicates = texts.stream()
.map(text -> notContainsText(paths, cb, text, type))
.toArray(Predicate[]::new);
Expand All @@ -29,15 +33,15 @@ public static Predicate notContainsTexts(
}

public static Predicate notContainsText(
Expression<Object> paths, CriteriaBuilder cb,
Expression<String> paths, CriteriaBuilder cb,
String text, Class<?> type) {
return containsText(paths, cb, text, type).not();
}

// -- CONTAINS --

public static Predicate containsTexts(
Expression<Object> paths, CriteriaBuilder cb,
Expression<String> paths, CriteriaBuilder cb,
List<String> texts,
Class<?> type) {
if (isEmpty(texts)) {
Expand All @@ -49,30 +53,30 @@ public static Predicate containsTexts(
return cb.or(predicates);
}

public static Predicate containsText(Expression<Object> paths, CriteriaBuilder cb, String text, Class<?> type) {
public static Predicate containsText(Expression<String> paths, CriteriaBuilder cb, String text, Class<?> type) {
if (text == null) {
return cb.conjunction();
}

if (type.isAssignableFrom(Map.class) || type.getName().contains("ImmutableCollections")) {
Expression<Object> values = lower(arrayToString(avals(paths, cb), cb), cb);
return cb.like(values.as(String.class), "%" + text.toLowerCase() + "%");
Expression<String> values = lower(arrayToString(avals(paths, cb), cb), cb);
return cb.like(values, "%" + text.toLowerCase() + "%");
}
if (type.isArray()) {
return cb.like(
lower(arrayToString(paths, cb), cb).as(String.class),
lower(arrayToString(paths, cb), cb),
"%" + text.toLowerCase() + "%"
);
}
return cb.and(
cb.like(cb.lower(paths.as(String.class)), "%" + text.toLowerCase() + "%"),
cb.like(cb.lower(paths), "%" + text.toLowerCase() + "%"),
cb.isNotNull(paths)
);
}

// -- NOT EQUALS --

public static Predicate notEqualsTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts, Class<?> type) {
public static Predicate notEqualsTexts(Expression<String> paths, CriteriaBuilder cb, List<String> texts, Class<?> type) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -84,13 +88,13 @@ public static Predicate notEqualsTexts(Expression<Object> paths, CriteriaBuilder
return cb.or(predicates);
}

private static Predicate notEqualsText(Expression<Object> paths, CriteriaBuilder cb, String text, Class<?> type) {
private static Predicate notEqualsText(Expression<String> paths, CriteriaBuilder cb, String text, Class<?> type) {
return equalsText(paths, cb, text, type).not();
}

// -- EQUALS --

public static Predicate equalsTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts, Class<?> type) {
public static Predicate equalsTexts(Expression<String> paths, CriteriaBuilder cb, List<String> texts, Class<?> type) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -102,7 +106,7 @@ public static Predicate equalsTexts(Expression<Object> paths, CriteriaBuilder cb
return cb.or(predicates);
}

private static Predicate equalsText(Expression<Object> paths, CriteriaBuilder cb, String text, Class<?> type) {
private static Predicate equalsText(Expression<String> paths, CriteriaBuilder cb, String text, Class<?> type) {
if (text == null) {
return cb.conjunction();
}
Expand All @@ -114,13 +118,13 @@ private static Predicate equalsText(Expression<Object> paths, CriteriaBuilder cb
if (text.equalsIgnoreCase("true") || text.equalsIgnoreCase("false")) {
return cb.equal(paths, Boolean.valueOf(text));
} else {
return cb.equal(cb.lower(paths.as(String.class)), text.toLowerCase());
return cb.equal(cb.lower(paths), text.toLowerCase());
}
}

// -- NOT START WITH --

public static Predicate notStartWithTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate notStartWithTexts(Expression<String> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -130,13 +134,13 @@ public static Predicate notStartWithTexts(Expression<Object> paths, CriteriaBuil
return cb.or(predicates);
}

public static Predicate notStartWithText(Expression<Object> paths, CriteriaBuilder cb, String text) {
public static Predicate notStartWithText(Expression<String> paths, CriteriaBuilder cb, String text) {
return startWithText(paths, cb, text).not();
}

// -- START WITH --

public static Predicate startWithTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate startWithTexts(Expression<String> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -146,20 +150,20 @@ public static Predicate startWithTexts(Expression<Object> paths, CriteriaBuilder
return cb.or(predicates);
}

public static Predicate startWithText(Expression<Object> paths, CriteriaBuilder cb, String text) {
return cb.like(cb.lower(paths.as(String.class)), text.toLowerCase() + "%");
public static Predicate startWithText(Expression<String> paths, CriteriaBuilder cb, String text) {
return cb.like(cb.lower(paths), text.toLowerCase() + "%");
}

// -- NOT EMPTY --

public static Predicate notEmpty(Expression<Object> paths, CriteriaBuilder cb, Class<?> type) {
public static Predicate notEmpty(Expression<String> paths, CriteriaBuilder cb, Class<?> type) {
return empty(paths, cb, type).not();
}

// -- EMPTY --

public static Predicate empty(Expression<Object> paths, CriteriaBuilder cb, Class<?> type) {
Expression<Object> finalPaths;
public static Predicate empty(Expression<String> paths, CriteriaBuilder cb, Class<?> type) {
Expression<String> finalPaths;
if (type.isArray()) {
finalPaths = arrayToString(paths, cb);
} else {
Expand All @@ -174,7 +178,7 @@ public static Predicate empty(Expression<Object> paths, CriteriaBuilder cb, Clas

// -- DATE --

public static Predicate greaterThanTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate greaterThanTexts(Expression<Instant> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -186,11 +190,11 @@ public static Predicate greaterThanTexts(Expression<Object> paths, CriteriaBuild
return cb.or(predicates);
}

public static Predicate greaterThanText(Expression<Object> paths, CriteriaBuilder cb, String text) {
return cb.greaterThan(paths.as(Instant.class), Instant.parse(text));
public static Predicate greaterThanText(Expression<Instant> paths, CriteriaBuilder cb, String text) {
return cb.greaterThan(paths, Instant.parse(text));
}

public static Predicate greaterThanOrEqualTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate greaterThanOrEqualTexts(Expression<Instant> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -202,11 +206,11 @@ public static Predicate greaterThanOrEqualTexts(Expression<Object> paths, Criter
return cb.or(predicates);
}

public static Predicate greaterThanOrEqualText(Expression<Object> paths, CriteriaBuilder cb, String text) {
return cb.greaterThanOrEqualTo(paths.as(Instant.class), Instant.parse(text));
public static Predicate greaterThanOrEqualText(Expression<Instant> paths, CriteriaBuilder cb, String text) {
return cb.greaterThanOrEqualTo(paths, Instant.parse(text));
}

public static Predicate lessThanTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate lessThanTexts(Expression<Instant> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -218,11 +222,11 @@ public static Predicate lessThanTexts(Expression<Object> paths, CriteriaBuilder
return cb.or(predicates);
}

public static Predicate lessThanText(Expression<Object> paths, CriteriaBuilder cb, String text) {
return cb.lessThan(paths.as(Instant.class), Instant.parse(text));
public static Predicate lessThanText(Expression<Instant> paths, CriteriaBuilder cb, String text) {
return cb.lessThan(paths, Instant.parse(text));
}

public static Predicate lessThanOrEqualTexts(Expression<Object> paths, CriteriaBuilder cb, List<String> texts) {
public static Predicate lessThanOrEqualTexts(Expression<Instant> paths, CriteriaBuilder cb, List<String> texts) {
if (isEmpty(texts)) {
return cb.conjunction();
}
Expand All @@ -234,15 +238,15 @@ public static Predicate lessThanOrEqualTexts(Expression<Object> paths, CriteriaB
return cb.or(predicates);
}

public static Predicate lessThanOrEqualText(Expression<Object> paths, CriteriaBuilder cb, String text) {
return cb.lessThanOrEqualTo(paths.as(Instant.class), Instant.parse(text));
public static Predicate lessThanOrEqualText(Expression<Instant> paths, CriteriaBuilder cb, String text) {
return cb.lessThanOrEqualTo(paths, Instant.parse(text));
}


// -- CUSTOM FUNCTION --

private static Expression<String[]> lowerArray(Expression<?> paths, CriteriaBuilder cb) {
return stringToArray(lower(arrayToString(paths, cb), cb).as(String.class), cb);
return stringToArray(lower(arrayToString(paths, cb), cb), cb);
}

// -- BASE FUNCTION --
Expand All @@ -251,19 +255,19 @@ private static Expression<Boolean> arrayPosition(Expression<String[]> paths, Cri
return cb.function("array_position", Boolean.class, paths, text);
}

private static Expression<Object> lower(Expression<Object> paths, CriteriaBuilder cb) {
return cb.function("lower", Object.class, paths);
private static Expression<String> lower(Expression<String> paths, CriteriaBuilder cb) {
return cb.function("lower", String.class, paths);
}

private static Expression<String[]> stringToArray(Expression<String> paths, CriteriaBuilder cb) {
return cb.function("string_to_array", String[].class, paths, cb.literal(" && "));
}

private static Expression<Object> arrayToString(Expression<?> paths, CriteriaBuilder cb) {
return cb.function("array_to_string", Object.class, paths, cb.literal(" && "));
private static Expression<String> arrayToString(Expression<?> paths, CriteriaBuilder cb) {
return cb.function("array_to_string", String.class, paths, cb.literal(" && "));
}

private static Expression<String[]> avals(Expression<Object> paths, CriteriaBuilder cb) {
private static Expression<String[]> avals(Expression<String> paths, CriteriaBuilder cb) {
return cb.function("avals", String[].class, paths);
}

Expand Down

0 comments on commit db7f69d

Please sign in to comment.