From 0cd2a6899b3a6027d94e650828e3fad207395de9 Mon Sep 17 00:00:00 2001 From: Harshad Kadam Date: Mon, 21 Aug 2023 17:31:42 +0530 Subject: [PATCH] FIlter fixes - datatype matching --- .../constants/OperationPredicates.java | 119 +++++++++--------- .../core/filters/services/QueryService.java | 3 + .../jarc/core/QueryServiceTests.java | 91 +++++++++++--- .../jarc/core/test/models/User.java | 5 +- 4 files changed, 139 insertions(+), 79 deletions(-) diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/constants/OperationPredicates.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/constants/OperationPredicates.java index acb94137..be60f0fe 100644 --- a/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/constants/OperationPredicates.java +++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/constants/OperationPredicates.java @@ -2,102 +2,77 @@ import static java.util.Map.entry; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.sourcefuse.jarc.core.filters.interfaces.TriFunction; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; import java.util.List; import java.util.Map; +import java.util.Set; public final class OperationPredicates { - private static Map, Object, Predicate>> operatorMap = + private static ObjectMapper objectMapper = new ObjectMapper() + .registerModule(new JavaTimeModule()); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static Map, Object, Predicate>> operatorMap = Map.ofEntries( entry("eq", CriteriaBuilder::equal), entry("neq", CriteriaBuilder::notEqual), entry( "in", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> + (CriteriaBuilder cb, Expression path, Object value) -> path.in((List) value) ), entry( "nin", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.not(path.in((List) value)) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.not(path.in((List) value)) ), entry( "like", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.like(path, String.valueOf(value)) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.like(path.as(String.class), String.valueOf(value)) ), entry( "nlike", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.notLike(path, String.valueOf(value)) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.notLike(path.as(String.class), String.valueOf(value)) ), entry( "gt", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.greaterThan( - path.as(Double.class), - Double.valueOf(value.toString()) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.greaterThan( + (Expression) path, + (Comparable) value ) ), entry( "gte", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.greaterThanOrEqualTo( - path.as(Double.class), - Double.valueOf(value.toString()) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.greaterThanOrEqualTo( + (Expression) path, + (Comparable) value ) ), entry( "lt", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.lessThan( - path.as(Double.class), - Double.valueOf(value.toString()) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.lessThan( + (Expression) path, + (Comparable) value ) ), entry( "lte", - ( - CriteriaBuilder criteriaBuilder, - Expression path, - Object value - ) -> - criteriaBuilder.lessThanOrEqualTo( - path.as(Double.class), - Double.valueOf(value.toString()) + (CriteriaBuilder cb, Expression path, Object value) -> + cb.lessThanOrEqualTo( + (Expression) path, + (Comparable) value ) ) ); @@ -110,20 +85,42 @@ private OperationPredicates() { } public static Predicate getPredicate( - CriteriaBuilder criteriaBuilder, + CriteriaBuilder cb, String operator, - Expression fieldPath, + Expression fieldPath, Object value ) { return operatorMap .getOrDefault( operator, - (CriteriaBuilder builder, Expression path, Object val) -> { + (CriteriaBuilder builder, Expression path, Object val) -> { throw new IllegalArgumentException( "Unsupported operator: " + operator ); } ) - .apply(criteriaBuilder, fieldPath, value); + .apply(cb, fieldPath, castValueToDataType(cb, fieldPath, value)); + } + + private static Object castValueToDataType( + CriteriaBuilder cb, + Expression path, + Object value + ) { + Class dataType = path.getJavaType(); + + if (value instanceof List listVal) { + return listVal + .stream() + .map(ele -> objectMapper.convertValue(ele, dataType)) + .toList(); + } else if (value instanceof Set setVal) { + return setVal + .stream() + .map(ele -> objectMapper.convertValue(ele, dataType)) + .toList(); + } else { + return objectMapper.convertValue(value, dataType); + } } } diff --git a/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/services/QueryService.java b/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/services/QueryService.java index d9905fc2..af9c39cf 100644 --- a/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/services/QueryService.java +++ b/libs/core/src/main/java/com/sourcefuse/jarc/core/filters/services/QueryService.java @@ -102,6 +102,9 @@ private List buildPredicates( From from, CriteriaQuery criteriaQuery ) { + if (filter == null) { + return new ArrayList<>(); + } // Apply WHERE clause List predicates = new ArrayList<>(); diff --git a/libs/core/src/test/java/com/sourcefuse/jarc/core/QueryServiceTests.java b/libs/core/src/test/java/com/sourcefuse/jarc/core/QueryServiceTests.java index 4294f101..9cb65e14 100644 --- a/libs/core/src/test/java/com/sourcefuse/jarc/core/QueryServiceTests.java +++ b/libs/core/src/test/java/com/sourcefuse/jarc/core/QueryServiceTests.java @@ -16,6 +16,7 @@ import com.sourcefuse.jarc.core.test.repositories.UserRepository; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -140,7 +141,7 @@ void testFilter_ForGreaterThanOperator() { @Test void testFilter_ForGreaterThanOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> this.filterWithOperatorAndAge("gt", "24s") ); } @@ -155,7 +156,7 @@ void testFilter_ForGreaterThanOrEqulsToOperator() { @Test void testFilter_ForGreaterThanOrEqulsToOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> this.filterWithOperatorAndAge("gte", "24s") ); } @@ -170,7 +171,7 @@ void testFilter_ForLessThanOperator() { @Test void testFilter_ForLessThanOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> this.filterWithOperatorAndAge("lt", "24s") ); } @@ -185,7 +186,7 @@ void testFilter_ForLessThanOrEqualsToOperator() { @Test void testFilter_ForLessThanOrEqualsToOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> this.filterWithOperatorAndAge("lte", "24s") ); } @@ -383,7 +384,7 @@ void testFilterWithJson_ForGreaterThanOperator() { @Test void testFilterWithJson_ForGreaterThanOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> filterService.executeQuery( "{\"where\":{\"age\":{\"gt\":\"24s\"}}}", @@ -405,7 +406,7 @@ void testFilterWithJson_ForGreaterThanOrEqulsToOperator() { @Test void testFilterWithJson_ForGreaterThanOrEqulsToOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> filterService.executeQuery( "{\"where\":{\"age\":{\"gte\":\"20s\"}}}", @@ -427,7 +428,7 @@ void testFilterWithJson_ForLessThanOperator() { @Test void testFilterWithJson_ForLessThanOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> filterService.executeQuery( "{\"where\":{\"age\":{\"lt\":\"24s\"}}}", @@ -436,6 +437,42 @@ void testFilterWithJson_ForLessThanOperatorWithString() { ); } + @Test + void testFilterWithJson_ForGreaterThanOperatorWithLocalDateTime() { + List users = filterService.executeQuery( + "{\"where\":{\"createdOn\":{\"gt\":\"" + + LocalDateTime.now().toString() + + "\"}}}", + User.class + ); + + assertThat(users).hasSize(0); + } + + @Test + void testFilterWithJson_ForLessThanOperatorWithLocalDateTime() { + List users = filterService.executeQuery( + "{\"where\":{\"createdOn\":{\"lt\":\"" + + LocalDateTime.now().toString() + + "\"}}}", + User.class + ); + + assertThat(users).hasSize(3).contains(user1, user2, user3); + } + + @Test + void testFilterWithJson_ForInOperatorWithLocalDateTime() { + List users = filterService.executeQuery( + "{\"where\":{\"createdOn\":{\"in\":[\"" + + user1.getCreatedOn().toString() + + "\"]}}}", + User.class + ); + + assertThat(users).hasSize(1).contains(user1); + } + @Test void testFilterWithJson_ForLessThanOrEqualsToOperator() { List users = filterService.executeQuery( @@ -449,7 +486,7 @@ void testFilterWithJson_ForLessThanOrEqualsToOperator() { @Test void testFilterWithJson_ForLessThanOrEqualsToOperatorWithString() { assertThrows( - NumberFormatException.class, + IllegalArgumentException.class, () -> filterService.executeQuery( "{\"where\":{\"age\":{\"lte\":\"24s\"}}}", @@ -497,9 +534,9 @@ void testFilterWithJson_FieldSelectionTest() { void testFilterWithJson_ForInOerator() { List roles = filterService.executeQuery( "{\"where\":{\"id\":{\"in\": [\"" + - tempRole.getId() + + tempRole.getId().toString() + "\", \"" + - adminRole.getId() + + adminRole.getId().toString() + "\"]}}}", Role.class ); @@ -511,9 +548,9 @@ void testFilterWithJson_ForInOerator() { void testFilterWithJson_ForNotInOerator() { List roles = filterService.executeQuery( "{\"where\":{\"id\":{\"nin\": [\"" + - tempRole.getId() + + tempRole.getId().toString() + "\", \"" + - adminRole.getId() + + adminRole.getId().toString() + "\"]}}}", Role.class ); @@ -603,6 +640,18 @@ void testSpecificationFilterWithJson_ForEqualsOperator() { assertThat(userRole.getId()).isEqualTo(roles.get(0).getId()); } + @Test + void testSpecificationFilterWithJson_ForEqualsOperatorWithUUID() { + Specification specs = filterService.getSpecifications( + "{\"where\":{\"id\":{\"eq\":\"" + userRole.getId().toString() + "\"}}}" + ); + List roles = this.roleRepository.findAll(specs); + + assertThat(roles).hasSize(1); + + assertThat(userRole.getId()).isEqualTo(roles.get(0).getId()); + } + @Test void testSpecificationFilterWithJson_ForNotEqualsOperator() { Specification specs = filterService.getSpecifications( @@ -613,6 +662,16 @@ void testSpecificationFilterWithJson_ForNotEqualsOperator() { assertThat(roles).hasSize(2).contains(adminRole, tempRole); } + @Test + void testSpecificationFilterWithJson_ForNotEqualsOperatorWithUUID() { + Specification specs = filterService.getSpecifications( + "{\"where\":{\"id\":{\"neq\":\"" + userRole.getId().toString() + "\"}}}" + ); + List roles = this.roleRepository.findAll(specs); + + assertThat(roles).hasSize(2).contains(adminRole, tempRole); + } + @Test void testSpecificationFilterWithJson_ForGreaterThanOperator() { Specification specs = filterService.getSpecifications( @@ -689,9 +748,9 @@ void testSpecificationFilterWithJson_ForNotLikeOperator() { void testSpecificationFilterWithJson_ForInOerator() { Specification specs = filterService.getSpecifications( "{\"where\":{\"id\":{\"in\": [\"" + - tempRole.getId() + + tempRole.getId().toString() + "\", \"" + - adminRole.getId() + + adminRole.getId().toString() + "\"]}}}" ); List roles = this.roleRepository.findAll(specs); @@ -703,9 +762,9 @@ void testSpecificationFilterWithJson_ForInOerator() { void testSpecificationFilterWithJson_ForNotInOerator() { Specification specs = filterService.getSpecifications( "{\"where\":{\"id\":{\"nin\": [\"" + - tempRole.getId() + + tempRole.getId().toString() + "\", \"" + - adminRole.getId() + + adminRole.getId().toString() + "\"]}}}" ); List roles = this.roleRepository.findAll(specs); diff --git a/libs/core/src/test/java/com/sourcefuse/jarc/core/test/models/User.java b/libs/core/src/test/java/com/sourcefuse/jarc/core/test/models/User.java index 662c37db..e0ddc4cc 100644 --- a/libs/core/src/test/java/com/sourcefuse/jarc/core/test/models/User.java +++ b/libs/core/src/test/java/com/sourcefuse/jarc/core/test/models/User.java @@ -1,6 +1,7 @@ package com.sourcefuse.jarc.core.test.models; -import com.sourcefuse.jarc.core.models.base.SoftDeleteEntity; +import com.sourcefuse.jarc.core.models.base.UserModifiableEntity; + import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -18,7 +19,7 @@ @Setter @Entity @Table(name = "users", schema = "main") -public class User extends SoftDeleteEntity { +public class User extends UserModifiableEntity { @Id @GeneratedValue(strategy = GenerationType.UUID)