diff --git a/.circleci/config.yml b/.circleci/config.yml index 72a0483..2438ce3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,12 +2,17 @@ version: 2.1 orbs: codecov: codecov/codecov@1.0.2 +parameters: + jdk-image: + type: string + default: cimg/openjdk:17.0 + jobs: test: environment: MAVEN_OPTS: -Xmx3200m docker: - - image: circleci/openjdk:11-jdk + - image: << pipeline.parameters.jdk-image >> working_directory: ~/project steps: - checkout diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..03b6389 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17.0 diff --git a/README.md b/README.md index 9142bad..9ad1e18 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Please note that providing such a feature on your API does not come without risk ## Getting Started -**Requirements** : JDK 8 or more. +**Requirements** : JDK 17 or more. To get a local copy up and running follow these simple steps. ### Installation @@ -91,7 +91,7 @@ Add the repo to your project inside your `pom.xml` file com.sipios spring-search - 0.2.0 + 0.3.0 ``` @@ -175,6 +175,40 @@ Request : `/cars?search=options.transmission:Auto` Request : `/cars?search=creationyear:2018 AND price<300000 AND (color:Yellow OR color:Blue) AND options.transmission:Auto` ![complex example](./docs/images/complex-example.gif) + +## Troubleshooting + +If you get the following error ⬇️ + +> No primary or default constructor found for interface org.springframework.data.jpa.domain.Specification + +You are free to opt for either of the two following solutions : +1. Add a `@Configuration` class to add our argument resolver to your project +```kotlin +// Kotlin +@Configuration +class SpringSearchResolverConf : WebMvcConfigurer { + override fun addArgumentResolvers(argumentResolvers: MutableList) { + argumentResolvers.add(SearchSpecificationResolver()) + } +} +``` +```java +// Java +@Configuration +public class SpringSearchResolverConf implements WebMvcConfigurer { + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(new SearchSpecificationResolver()); + } +} +``` + +2. Add a `@ComponentScan` annotation to your project configuration class +```java +@ComponentScan(basePackages = {"com.your-application", "com.sipios.springsearch"}) +``` + ## Roadmap diff --git a/pom.xml b/pom.xml index be0ccda..9e1929b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,22 +4,26 @@ org.springframework.boot spring-boot-starter-parent - 2.4.1 + 3.1.7 com.sipios spring-search - 0.2.5 + 0.2.6 spring-search API for generating spring boot database queries - 1.8 - 1.6.20 - 4.9 + 17 + 1.9.22 + 0.8.4 + 2.2.220 + 2.16.0 + 2.0 + 9.0.7 + 4.13.1 com.sipios.springsearch.grammar com/sipios/springsearch/grammar - 0.8.4 ${project.build.directory}/test-results @@ -32,6 +36,7 @@ com.h2database h2 + ${h2.version} test @@ -44,6 +49,18 @@ spring-boot-starter-web provided + + com.fasterxml.jackson.core + jackson-databind + ${jackson-databind.version} + provided + + + org.yaml + snakeyaml + ${snakeyaml.version} + provided + com.fasterxml.jackson.module jackson-module-kotlin @@ -52,10 +69,6 @@ org.jetbrains.kotlin kotlin-reflect - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - org.springframework.boot @@ -79,11 +92,6 @@ ${kotlin.version} test - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - ${kotlin.version} - @@ -112,10 +120,6 @@ ${project.build.directory}/generated-sources/antlr4/${grammar.directory} - - maven-compiler-plugin - 3.8.1 - org.jetbrains.kotlin kotlin-maven-plugin @@ -123,7 +127,7 @@ compile - compile + process-sources compile @@ -161,7 +165,7 @@ src/main/kotlin target/generated-sources/antlr4 - 1.8 + 17 @@ -291,6 +295,7 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 compile @@ -351,7 +356,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 3.1.0 sign-artifacts @@ -368,6 +373,18 @@ + + org.owasp + dependency-check-maven + ${dependency-check-maven.version} + + + + check + + + + diff --git a/src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt b/src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt index ced091a..8eda3ce 100644 --- a/src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt +++ b/src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt @@ -6,7 +6,7 @@ import com.sipios.springsearch.grammar.QueryParser import org.springframework.data.jpa.domain.Specification class QueryVisitorImpl(private val searchSpecAnnotation: SearchSpec) : QueryBaseVisitor>() { - private val ValueRegExp = Regex(pattern = "^(\\*?)(.+?)(\\*?)$") + private val valueRegExp = Regex(pattern = "^(\\*?)(.+?)(\\*?)$") override fun visitOpQuery(ctx: QueryParser.OpQueryContext): Specification { val left = visit(ctx.left) val right = visit(ctx.right) @@ -43,7 +43,7 @@ class QueryVisitorImpl(private val searchSpecAnnotation: SearchSpec) : QueryB .replace("\\'", "'") } - val matchResult = this.ValueRegExp.find(value!!) + val matchResult = this.valueRegExp.find(value!!) val criteria = SearchCriteria( key, op, diff --git a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt index dfaa1ee..e87ba7e 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt @@ -10,20 +10,19 @@ class SearchCriteria // Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH base // Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH based on the presence of * in the value val startsWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX) val endsWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX) - if (op === SearchOperation.EQUALS && startsWithAsterisk && endsWithAsterisk) { - op = SearchOperation.CONTAINS - } else if (op === SearchOperation.EQUALS && startsWithAsterisk) { - op = SearchOperation.ENDS_WITH - } else if (op === SearchOperation.EQUALS && endsWithAsterisk) { - op = SearchOperation.STARTS_WITH + op = when { + op === SearchOperation.EQUALS && startsWithAsterisk && endsWithAsterisk -> SearchOperation.CONTAINS + op === SearchOperation.EQUALS && startsWithAsterisk -> SearchOperation.ENDS_WITH + op === SearchOperation.EQUALS && endsWithAsterisk -> SearchOperation.STARTS_WITH + else -> op } + // Change NOT_EQUALS into DOESNT_END_WITH, DOESNT_CONTAIN, DOESNT_START_WITH based on the presence of * in the value - if (op === SearchOperation.NOT_EQUALS && startsWithAsterisk && endsWithAsterisk) { - op = SearchOperation.DOESNT_CONTAIN - } else if (op === SearchOperation.NOT_EQUALS && startsWithAsterisk) { - op = SearchOperation.DOESNT_END_WITH - } else if (op === SearchOperation.NOT_EQUALS && endsWithAsterisk) { - op = SearchOperation.DOESNT_START_WITH + op = when { + op === SearchOperation.NOT_EQUALS && startsWithAsterisk && endsWithAsterisk -> SearchOperation.DOESNT_CONTAIN + op === SearchOperation.NOT_EQUALS && startsWithAsterisk -> SearchOperation.DOESNT_END_WITH + op === SearchOperation.NOT_EQUALS && endsWithAsterisk -> SearchOperation.DOESNT_START_WITH + else -> op } } this.operation = op diff --git a/src/main/kotlin/com/sipios/springsearch/SpecificationImpl.kt b/src/main/kotlin/com/sipios/springsearch/SpecificationImpl.kt index 3c4a631..d58ca96 100644 --- a/src/main/kotlin/com/sipios/springsearch/SpecificationImpl.kt +++ b/src/main/kotlin/com/sipios/springsearch/SpecificationImpl.kt @@ -2,12 +2,12 @@ package com.sipios.springsearch import com.sipios.springsearch.anotation.SearchSpec import com.sipios.springsearch.strategies.ParsingStrategy +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.CriteriaQuery +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate +import jakarta.persistence.criteria.Root import java.util.ArrayList -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.CriteriaQuery -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate -import javax.persistence.criteria.Root import org.springframework.data.jpa.domain.Specification import org.springframework.http.HttpStatus import org.springframework.web.server.ResponseStatusException diff --git a/src/main/kotlin/com/sipios/springsearch/SpecificationsBuilder.kt b/src/main/kotlin/com/sipios/springsearch/SpecificationsBuilder.kt index c0bb5ec..aab0610 100644 --- a/src/main/kotlin/com/sipios/springsearch/SpecificationsBuilder.kt +++ b/src/main/kotlin/com/sipios/springsearch/SpecificationsBuilder.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch import com.sipios.springsearch.anotation.SearchSpec -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.CriteriaQuery -import javax.persistence.criteria.Predicate -import javax.persistence.criteria.Root +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.CriteriaQuery +import jakarta.persistence.criteria.Predicate +import jakarta.persistence.criteria.Root import org.springframework.data.jpa.domain.Specification class SpecificationsBuilder(searchSpecAnnotation: SearchSpec) { @@ -20,7 +20,7 @@ class SpecificationsBuilder(searchSpecAnnotation: SearchSpec) { /** * This function expect a search string to have been provided. - * The search string has been transformed into a Expression Queue with the format: [OR, value>100, AND, value<1000, label:*MONO*] + * The search string has been transformed into an Expression Queue with the format: [OR, value>100, AND, value<1000, label:*MONO*] * * @return A list of specification used to filter the underlying object using JPA specifications */ diff --git a/src/main/kotlin/com/sipios/springsearch/anotation/SearchSpec.kt b/src/main/kotlin/com/sipios/springsearch/anotation/SearchSpec.kt index ae51734..dd2a43d 100644 --- a/src/main/kotlin/com/sipios/springsearch/anotation/SearchSpec.kt +++ b/src/main/kotlin/com/sipios/springsearch/anotation/SearchSpec.kt @@ -14,7 +14,7 @@ annotation class SearchSpec( val searchParam: String = "search", /** - * A flag to indicate if the search needs to be case sensitive or not + * A flag to indicate if the search needs to be case-sensitive or not */ val caseSensitiveFlag: Boolean = true ) diff --git a/src/main/kotlin/com/sipios/springsearch/configuration/SearchSpecificationResolver.kt b/src/main/kotlin/com/sipios/springsearch/configuration/SearchSpecificationResolver.kt index 578cac4..6ad160d 100644 --- a/src/main/kotlin/com/sipios/springsearch/configuration/SearchSpecificationResolver.kt +++ b/src/main/kotlin/com/sipios/springsearch/configuration/SearchSpecificationResolver.kt @@ -44,7 +44,7 @@ class SearchSpecificationResolver : HandlerMethodArgumentResolver { private fun buildSpecification(specClass: Class, search: String?, searchSpecAnnotation: SearchSpec): Specification? { logger.debug("Building specification for class {}", specClass) logger.debug("Search value found is {}", search) - if (search == null || search.isEmpty()) { + if (search.isNullOrEmpty()) { return null } val specBuilder = SpecificationsBuilder(searchSpecAnnotation) diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt index 38368c9..d240e70 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt @@ -2,11 +2,11 @@ package com.sipios.springsearch.strategies import com.fasterxml.jackson.databind.util.StdDateFormat import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.text.DateFormat import java.util.Date -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class DateStrategy : ParsingStrategy { @@ -20,8 +20,8 @@ class DateStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Date) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Date) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Date) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Date) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt index 4a4452d..135dfb3 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt @@ -1,9 +1,9 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import kotlin.reflect.KClass class DoubleStrategy : ParsingStrategy { @@ -15,8 +15,8 @@ class DoubleStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Double) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Double) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Double) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Double) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt index 05f626d..c35a847 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.Duration -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class DurationStrategy : ParsingStrategy { @@ -16,8 +16,8 @@ class DurationStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Duration) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Duration) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Duration) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Duration) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt index 0041d0a..65e7525 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt @@ -1,9 +1,9 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import kotlin.reflect.KClass class FloatStrategy : ParsingStrategy { @@ -15,8 +15,8 @@ class FloatStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Float) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Float) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Float) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Float) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt index 5010a40..95aff1f 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.Instant -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class InstantStrategy : ParsingStrategy { @@ -16,8 +16,8 @@ class InstantStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Instant) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Instant) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Instant) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Instant) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt index 171f57e..fc8ceb1 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt @@ -1,9 +1,9 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import kotlin.reflect.KClass class IntStrategy : ParsingStrategy { @@ -15,8 +15,8 @@ class IntStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as Int) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as Int) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Int) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Int) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt index 0b9baea..57e8ae2 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.LocalDate -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class LocalDateStrategy : ParsingStrategy { @@ -16,8 +16,8 @@ class LocalDateStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as LocalDate) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as LocalDate) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDate) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDate) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt index 4108016..18e691f 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.LocalDateTime -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class LocalDateTimeStrategy : ParsingStrategy { @@ -16,8 +16,8 @@ class LocalDateTimeStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as LocalDateTime) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as LocalDateTime) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDateTime) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDateTime) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt index b27725c..998c8de 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.LocalTime -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass class LocalTimeStrategy : ParsingStrategy { @@ -16,8 +16,8 @@ class LocalTimeStrategy : ParsingStrategy { value: Any? ): Predicate? { return when (ops) { - SearchOperation.GREATER_THAN -> builder.greaterThan(path.get(fieldName), value as LocalTime) - SearchOperation.LESS_THAN -> builder.lessThan(path.get(fieldName), value as LocalTime) + SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalTime) + SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalTime) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/ParsingStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/ParsingStrategy.kt index 739adb9..611abff 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/ParsingStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/ParsingStrategy.kt @@ -2,6 +2,9 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation import com.sipios.springsearch.anotation.SearchSpec +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate import java.time.Duration import java.time.Instant import java.time.LocalDate @@ -9,9 +12,6 @@ import java.time.LocalDateTime import java.time.LocalTime import java.util.Date import java.util.UUID -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate import kotlin.reflect.KClass import kotlin.reflect.full.isSubclassOf @@ -47,11 +47,11 @@ interface ParsingStrategy { return when (ops) { SearchOperation.EQUALS -> builder.equal(path.get(fieldName), value) SearchOperation.NOT_EQUALS -> builder.notEqual(path.get(fieldName), value) - SearchOperation.STARTS_WITH -> builder.like(path.get(fieldName), "$value%") - SearchOperation.ENDS_WITH -> builder.like(path.get(fieldName), "%$value") + SearchOperation.STARTS_WITH -> builder.like(path[fieldName], "$value%") + SearchOperation.ENDS_WITH -> builder.like(path[fieldName], "%$value") SearchOperation.CONTAINS -> builder.like((path.get(fieldName).`as`(String::class.java)), "%$value%") - SearchOperation.DOESNT_START_WITH -> builder.notLike(path.get(fieldName), "$value%") - SearchOperation.DOESNT_END_WITH -> builder.notLike(path.get(fieldName), "%$value") + SearchOperation.DOESNT_START_WITH -> builder.notLike(path[fieldName], "$value%") + SearchOperation.DOESNT_END_WITH -> builder.notLike(path[fieldName], "%$value") SearchOperation.DOESNT_CONTAIN -> builder.notLike( (path.get(fieldName).`as`(String::class.java)), "%$value%" diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/StringStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/StringStrategy.kt index 322748a..3498959 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/StringStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/StringStrategy.kt @@ -2,11 +2,12 @@ package com.sipios.springsearch.strategies import com.sipios.springsearch.SearchOperation import com.sipios.springsearch.anotation.SearchSpec -import javax.persistence.criteria.CriteriaBuilder -import javax.persistence.criteria.Path -import javax.persistence.criteria.Predicate +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.Path +import jakarta.persistence.criteria.Predicate +import java.util.Locale -class StringStrategy(var searchSpecAnnotation: SearchSpec) : ParsingStrategy { +data class StringStrategy(var searchSpecAnnotation: SearchSpec) : ParsingStrategy { override fun buildPredicate( builder: CriteriaBuilder, path: Path<*>, @@ -15,8 +16,8 @@ class StringStrategy(var searchSpecAnnotation: SearchSpec) : ParsingStrategy { value: Any? ): Predicate? { if (!searchSpecAnnotation.caseSensitiveFlag) { - val lowerCasedValue = (value as String).toLowerCase() - val loweredFieldValue = builder.lower(path.get(fieldName)) + val lowerCasedValue = (value as String).lowercase(Locale.getDefault()) + val loweredFieldValue = builder.lower(path[fieldName]) return when (ops) { SearchOperation.STARTS_WITH -> builder.like(loweredFieldValue, "$lowerCasedValue%") SearchOperation.ENDS_WITH -> builder.like(loweredFieldValue, "%$lowerCasedValue") diff --git a/src/test/kotlin/com/sipios/springsearch/Users.kt b/src/test/kotlin/com/sipios/springsearch/Users.kt index fb6610a..73c506c 100644 --- a/src/test/kotlin/com/sipios/springsearch/Users.kt +++ b/src/test/kotlin/com/sipios/springsearch/Users.kt @@ -1,5 +1,11 @@ package com.sipios.springsearch +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Table import java.time.Duration import java.time.Instant import java.time.LocalDate @@ -7,12 +13,6 @@ import java.time.LocalDateTime import java.time.LocalTime import java.util.Date import java.util.UUID -import javax.persistence.Column -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id -import javax.persistence.Table @Entity @Table(name = "USERS")