Skip to content

Commit

Permalink
Feat/blacklist (#83)
Browse files Browse the repository at this point in the history
* feat: is null/is not null

* fix: search null for collections

* refactor: null not case sensitive

* doc: update README.md

* refactor: throw if operand != IS | IS NOT

* refactor: throw if calling buildPredicate parent method with empty clause

* refactor: don't allow search for null collections

* refactor: don't allow search for null collections

* fix: lint

* test: add test for searching for empty non-collection fields

* refactor: avoid passing null value, check literal value instead (SearchOperation.NULL)

* feat: blacklist

* fix: add missing check for "NULL" value in strategies

* fix: missing arg in constructor

* fix: update threshold

* fix: remove unreachable code

* doc: add blacklist doc

* test: add test for UUID null

* test: canGetUsersWithUpdatedDateAtNull

* test: LocalDateTime is not null

* test: Int Boolean and Date is null

* trigger-ci

* trigger-ci

* fix: ktlint

* fix: ktlint

* fix: ktlint

* fix: test missing arguments

---------

Co-authored-by: vincentescoffier <vincent.escoffier1@gmail.com>
  • Loading branch information
reifocS and vincentescoffier authored Jun 23, 2024
1 parent 8e23f5f commit 0b8d21c
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 121 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ Request : `/cars?search=creationyear:2018 AND price<300000 AND (color:Yellow OR
15. Using the BETWEEN operator
Request : `/cars?search=creationyear BETWEEN 2017 AND 2019`

## Blocking the search on a field
```java
@GetMapping
public List<User> getUsers(@SearchSpec(blackListedFields = {"password"}) Specification<User> specs) {
return userRepository.findAll(Specification.where(specs));
}
```

<!-- TROUBLESHOOTING -->
## Troubleshooting

Expand Down
16 changes: 16 additions & 0 deletions src/main/kotlin/com/sipios/springsearch/QueryVisitorImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.sipios.springsearch.anotation.SearchSpec
import com.sipios.springsearch.grammar.QueryBaseVisitor
import com.sipios.springsearch.grammar.QueryParser
import org.springframework.data.jpa.domain.Specification
import org.springframework.http.HttpStatus
import org.springframework.web.server.ResponseStatusException

class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryBaseVisitor<Specification<T>>() {
private val valueRegExp = Regex(pattern = "^(?<prefix>\\*?)(?<value>.+?)(?<suffix>\\*?)$")
Expand Down Expand Up @@ -32,6 +34,7 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB

override fun visitIsCriteria(ctx: QueryParser.IsCriteriaContext): Specification<T> {
val key = ctx.key().text
verifyBlackList(key)
val op = if (ctx.IS() != null) {
SearchOperation.IS
} else {
Expand All @@ -42,6 +45,7 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB

override fun visitEqArrayCriteria(ctx: QueryParser.EqArrayCriteriaContext): Specification<T> {
val key = ctx.key().text
verifyBlackList(key)
val op = if (ctx.IN() != null) {
SearchOperation.IN_ARRAY
} else {
Expand All @@ -58,6 +62,7 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB

override fun visitBetweenCriteria(ctx: QueryParser.BetweenCriteriaContext): Specification<T> {
val key = ctx.key().text
verifyBlackList(key)
val leftValue = if (ctx.left.STRING() != null) {
clearString(ctx.left.text)
} else {
Expand Down Expand Up @@ -93,6 +98,7 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB
} else {
ctx.value().text
}
verifyBlackList(key)
val matchResult = this.valueRegExp.find(value)
val op = SearchOperation.getSimpleOperation(ctx.op().text) ?: throw IllegalArgumentException("Invalid operation")
val criteria = SearchCriteria(
Expand All @@ -106,6 +112,16 @@ class QueryVisitorImpl<T>(private val searchSpecAnnotation: SearchSpec) : QueryB
return SpecificationImpl(criteria, searchSpecAnnotation)
}

private fun verifyBlackList(key: String?) {
val blackList = this.searchSpecAnnotation.blackListedFields
if (blackList.contains(key)) {
throw ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Field $key is blacklisted"
)
}
}

private fun clearString(value: String) = value
.removeSurrounding("'")
.removeSurrounding("\"")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ annotation class SearchSpec(
/**
* A flag to indicate if the search needs to be case-sensitive or not
*/
val caseSensitiveFlag: Boolean = true
val caseSensitiveFlag: Boolean = true,

/**
* A list of fields that should be excluded from the search
*/
val blackListedFields: Array<String> = []
)
Loading

0 comments on commit 0b8d21c

Please sign in to comment.