From f6ebe2a9868d9c2c47bbd1fb71c958923dc7579c Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:40:50 +0100 Subject: [PATCH 01/12] update grammar --- src/main/antlr4/Query.g4 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/antlr4/Query.g4 b/src/main/antlr4/Query.g4 index 2a2a373..36a722c 100644 --- a/src/main/antlr4/Query.g4 +++ b/src/main/antlr4/Query.g4 @@ -33,7 +33,9 @@ value op : EQ | GT + | GTE | LT + | LTE | NOT_EQ ; @@ -137,11 +139,17 @@ GT : '>' ; +GTE + : '>=' + ; LT : '<' ; +LTE + : '<=' + ; EQ : ':' From 2ae2e01d0ffecb6d14c21cb4e1044df104e94c36 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:41:00 +0100 Subject: [PATCH 02/12] add tests --- .../SpringSearchApplicationTest.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 66eb2e6..453bc73 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -1015,4 +1015,42 @@ class SpringSearchApplicationTest { Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals(user2UUID, robotUsers[0].uuid) } + + @Test + fun canGetUsersWithNumberOfChildrenLessOrEqualSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber<=2").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(1, users.size) + Assertions.assertEquals("john", users[0].userFirstName) + } + + @Test + fun canGetUsersWithNumberOfChildrenGreaterOrEqualSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber>=3").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + } + + @Test + fun canGetUsersWithNumberOfChildrenLessSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber<3").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(1, users.size) + Assertions.assertEquals("john", users[0].userFirstName) + } } From 54d3772f94ec65ec7c367f34236aa9d223999661 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:41:44 +0100 Subject: [PATCH 03/12] add gte and lte operations and change from chat to string --- .../com/sipios/springsearch/SearchCriteria.kt | 2 +- .../com/sipios/springsearch/SearchOperation.kt | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt index e87ba7e..adcc69c 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt @@ -5,7 +5,7 @@ class SearchCriteria // Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH base var operation: SearchOperation? init { - var op = SearchOperation.getSimpleOperation(operation[0]) + var op = SearchOperation.getSimpleOperation(operation) if (op != null) { // 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) diff --git a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt index d6a1a04..333f5c5 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch enum class SearchOperation { - EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN; + EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN, GREATER_THAN_EQUALS, LESS_THAN_EQUALS; companion object { - val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~") + val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">=", "<=") val ZERO_OR_MORE_REGEX = "*" val OR_OPERATOR = "OR" val AND_OPERATOR = "AND" @@ -17,12 +17,14 @@ enum class SearchOperation { * @param input operation as string * @return The matching operation */ - fun getSimpleOperation(input: Char): SearchOperation? { + fun getSimpleOperation(input: String): SearchOperation? { return when (input) { - ':' -> EQUALS - '!' -> NOT_EQUALS - '>' -> GREATER_THAN - '<' -> LESS_THAN + ":" -> EQUALS + "!" -> NOT_EQUALS + ">" -> GREATER_THAN + "<" -> LESS_THAN + ">=" -> GREATER_THAN_EQUALS + "<=" -> LESS_THAN_EQUALS else -> null } } From 2ddcc64dee1f96c99c12ccd264b7e633f9032298 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 11:03:00 +0100 Subject: [PATCH 04/12] update strategies and add tests --- .../springsearch/strategies/DateStrategy.kt | 2 + .../springsearch/strategies/DoubleStrategy.kt | 2 + .../strategies/DurationStrategy.kt | 2 + .../springsearch/strategies/FloatStrategy.kt | 2 + .../strategies/InstantStrategy.kt | 2 + .../springsearch/strategies/IntStrategy.kt | 2 + .../strategies/LocalDateStrategy.kt | 2 + .../strategies/LocalDateTimeStrategy.kt | 2 + .../strategies/LocalTimeStrategy.kt | 2 + .../SpringSearchApplicationTest.kt | 138 ++++++++++++++++-- 10 files changed, 147 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt index d240e70..61f5c69 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt @@ -22,6 +22,8 @@ class DateStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Date) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Date) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Date) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 135dfb3..7b1ccc0 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt @@ -17,6 +17,8 @@ class DoubleStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Double) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Double) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Double) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 c35a847..a722fe2 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt @@ -18,6 +18,8 @@ class DurationStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Duration) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Duration) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Duration) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 65e7525..ea1d1e6 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt @@ -17,6 +17,8 @@ class FloatStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Float) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Float) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Float) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 95aff1f..66294cd 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt @@ -18,6 +18,8 @@ class InstantStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Instant) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Instant) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Instant) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 fc8ceb1..21f3863 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt @@ -17,6 +17,8 @@ class IntStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Int) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Int) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Int) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 57e8ae2..2b435f6 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt @@ -18,6 +18,8 @@ class LocalDateStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDate) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDate) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalDate) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 18e691f..763dae5 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt @@ -18,6 +18,8 @@ class LocalDateTimeStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDateTime) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDateTime) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalDateTime) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 998c8de..7682689 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt @@ -18,6 +18,8 @@ class LocalTimeStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalTime) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalTime) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalTime) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(path[fieldName], value as LocalTime) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 453bc73..4123a0c 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -592,6 +592,44 @@ class SpringSearchApplicationTest { Assertions.assertEquals(0, specificationUsers.size) } + @Test + fun canGetUsersAfterEqualDate() { + val sdf = StdDateFormat() + userRepository.save(Users(createdAt = sdf.parse("2019-01-01"))) + userRepository.save(Users(createdAt = sdf.parse("2019-01-03"))) + + var specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt>='2019-01-01'").build() + var specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(2, specificationUsers.size) + + specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt>='2019-01-04'").build() + specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(0, specificationUsers.size) + } + + @Test + fun canGetUsersEarlierEqualDate() { + val sdf = StdDateFormat() + userRepository.save(Users(createdAt = sdf.parse("2019-01-01"))) + userRepository.save(Users(createdAt = sdf.parse("2019-01-03"))) + + var specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt<='2019-01-01'").build() + var specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(1, specificationUsers.size) + + specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt<='2019-01-03'").build() + specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(2, specificationUsers.size) + } + @Test fun canGetUsersAtPreciseDate() { val sdf = StdDateFormat() @@ -742,7 +780,7 @@ class SpringSearchApplicationTest { } @Test - fun canGetUsersWithUpdatedInstantAtGreaterSearch() { + fun canGetUsersWithUpdateInstantAtGreaterSearch() { userRepository.save( Users( userFirstName = "HamidReza", @@ -760,10 +798,10 @@ class SpringSearchApplicationTest { } @Test - fun canGetUsersWithUpdatedInstantAtLessSearch() { + fun canGetUsersWithUpdateInstantAtGreaterThanEqualSearch() { userRepository.save( Users( - userFirstName = "HamidReza", + userFirstName = "john", updatedInstantAt = Instant.parse("2020-01-10T10:15:30Z") ) ) @@ -771,17 +809,17 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt<'2020-01-11T10:17:30Z'").build() + ).withSearch("updatedInstantAt>='2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) - Assertions.assertEquals("HamidReza", robotUsers[0].userFirstName) + Assertions.assertEquals("robot", robotUsers[0].userFirstName) } @Test - fun canGetUsersWithUpdatedInstantAtEqualSearch() { + fun canGetUsersWithUpdateInstantAtLessThanEqualSearch() { userRepository.save( Users( - userFirstName = "HamidReza", + userFirstName = "john", updatedInstantAt = Instant.parse("2020-01-10T10:15:30Z") ) ) @@ -789,10 +827,10 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt:'2020-01-10T10:15:30Z'").build() + ).withSearch("updatedInstantAt<='2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) - Assertions.assertEquals("HamidReza", robotUsers[0].userFirstName) + Assertions.assertEquals("john", robotUsers[0].userFirstName) } @Test @@ -834,6 +872,32 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedAt = LocalDateTime.parse("2020-01-10T10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedAt = LocalDateTime.parse("2020-01-11T10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedAt>='2020-01-11T10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + + @Test + fun canGetUsersWithUpdatedAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedAt = LocalDateTime.parse("2020-01-10T10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedAt = LocalDateTime.parse("2020-01-11T10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedAt<='2020-01-11T10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + @Test fun canGetUsersWithUpdatedDateAtGreaterSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedDateAt = LocalDate.parse("2020-01-10"))) @@ -886,6 +950,34 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedDateAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedDateAt = LocalDate.parse("2020-01-10"))) + userRepository.save(Users(userFirstName = "robot", updatedDateAt = LocalDate.parse("2020-01-11"))) + userRepository.save(Users(userFirstName = "robot2", updatedDateAt = LocalDate.parse("2020-01-12"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedDateAt<='2020-01-11'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + + @Test + fun canGetUsersWithUpdatedDateAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedDateAt = LocalDate.parse("2020-01-10"))) + userRepository.save(Users(userFirstName = "robot", updatedDateAt = LocalDate.parse("2020-01-11"))) + userRepository.save(Users(userFirstName = "robot2", updatedDateAt = LocalDate.parse("2020-01-12"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedDateAt>='2020-01-11'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + @Test fun canGetUsersWithUpdatedTimeAtGreaterSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedTimeAt = LocalTime.parse("10:15:30"))) @@ -925,6 +1017,34 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedTimeAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedTimeAt = LocalTime.parse("10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedTimeAt = LocalTime.parse("10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedTimeAt = LocalTime.parse("10:25:30"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedTimeAt<='10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + + @Test + fun canGetUsersWithUpdatedTimeAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedTimeAt = LocalTime.parse("10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedTimeAt = LocalTime.parse("10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedTimeAt = LocalTime.parse("10:25:30"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedTimeAt>='10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + @Test fun canGetUsersWithUpdatedTimeAtNotEqualSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedTimeAt = LocalTime.parse("10:15:30"))) From d713cda0cd983a16368928646e14cf3bd34ba0a3 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 11:28:18 +0100 Subject: [PATCH 05/12] update documentation --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3143ca7..745f8ab 100644 --- a/README.md +++ b/README.md @@ -134,10 +134,14 @@ Request : `/cars?search=color!Red` 3. Using the greater than operator `>` Request : `/cars?search=creationyear>2017` +> Note: You can use the `>=` operator as well. + ![greater than operator example](./docs/images/greater-than-example.gif) 4. Using the less than operator `<` -Request : `/cars?search=price<100000` +Request : `/cars?search=price<100000` +> Note: You can use the `<=` operator as well. + ![less than operator example](./docs/images/less-than-example.gif) 5. Using the starts with operator `*` From a5fd95947d3ca3d1e3ac8ded8d0686b88a645e33 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 16:12:38 +0100 Subject: [PATCH 06/12] change from = to : --- README.md | 4 +-- src/main/antlr4/Query.g4 | 4 +-- .../sipios/springsearch/SearchOperation.kt | 6 ++-- .../SpringSearchApplicationTest.kt | 28 +++++++++---------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 745f8ab..97c9161 100644 --- a/README.md +++ b/README.md @@ -134,13 +134,13 @@ Request : `/cars?search=color!Red` 3. Using the greater than operator `>` Request : `/cars?search=creationyear>2017` -> Note: You can use the `>=` operator as well. +> Note: You can use the `>:` operator as well. ![greater than operator example](./docs/images/greater-than-example.gif) 4. Using the less than operator `<` Request : `/cars?search=price<100000` -> Note: You can use the `<=` operator as well. +> Note: You can use the `<:` operator as well. ![less than operator example](./docs/images/less-than-example.gif) diff --git a/src/main/antlr4/Query.g4 b/src/main/antlr4/Query.g4 index 36a722c..0bf8374 100644 --- a/src/main/antlr4/Query.g4 +++ b/src/main/antlr4/Query.g4 @@ -140,7 +140,7 @@ GT ; GTE - : '>=' + : '>:' ; LT @@ -148,7 +148,7 @@ LT ; LTE - : '<=' + : '<:' ; EQ diff --git a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt index 333f5c5..f8f024a 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt @@ -4,7 +4,7 @@ enum class SearchOperation { EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN, GREATER_THAN_EQUALS, LESS_THAN_EQUALS; companion object { - val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">=", "<=") + val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">:", "<:") val ZERO_OR_MORE_REGEX = "*" val OR_OPERATOR = "OR" val AND_OPERATOR = "AND" @@ -23,8 +23,8 @@ enum class SearchOperation { "!" -> NOT_EQUALS ">" -> GREATER_THAN "<" -> LESS_THAN - ">=" -> GREATER_THAN_EQUALS - "<=" -> LESS_THAN_EQUALS + ">:" -> GREATER_THAN_EQUALS + "<:" -> LESS_THAN_EQUALS else -> null } } diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 4123a0c..492531b 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -600,13 +600,13 @@ class SpringSearchApplicationTest { var specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt>='2019-01-01'").build() + ).withSearch("createdAt>:'2019-01-01'").build() var specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(2, specificationUsers.size) specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt>='2019-01-04'").build() + ).withSearch("createdAt>:'2019-01-04'").build() specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(0, specificationUsers.size) } @@ -619,13 +619,13 @@ class SpringSearchApplicationTest { var specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt<='2019-01-01'").build() + ).withSearch("createdAt<:'2019-01-01'").build() var specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(1, specificationUsers.size) specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt<='2019-01-03'").build() + ).withSearch("createdAt<:'2019-01-03'").build() specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(2, specificationUsers.size) } @@ -809,7 +809,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt>='2020-01-11T09:20:30Z'").build() + ).withSearch("updatedInstantAt>:'2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals("robot", robotUsers[0].userFirstName) @@ -827,7 +827,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt<='2020-01-11T09:20:30Z'").build() + ).withSearch("updatedInstantAt<:'2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals("john", robotUsers[0].userFirstName) @@ -879,7 +879,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedAt>='2020-01-11T10:20:30'").build() + ).withSearch("updatedAt>:'2020-01-11T10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -892,7 +892,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedAt<='2020-01-11T10:20:30'").build() + ).withSearch("updatedAt<:'2020-01-11T10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -958,7 +958,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedDateAt<='2020-01-11'").build() + ).withSearch("updatedDateAt<:'2020-01-11'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -972,7 +972,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedDateAt>='2020-01-11'").build() + ).withSearch("updatedDateAt>:'2020-01-11'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -1025,7 +1025,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedTimeAt<='10:20:30'").build() + ).withSearch("updatedTimeAt<:'10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -1039,7 +1039,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedTimeAt>='10:20:30'").build() + ).withSearch("updatedTimeAt>:'10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -1143,7 +1143,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("userChildrenNumber<=2").build() + ).withSearch("userChildrenNumber<:2").build() val users = userRepository.findAll(specification) Assertions.assertEquals(1, users.size) Assertions.assertEquals("john", users[0].userFirstName) @@ -1156,7 +1156,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("userChildrenNumber>=3").build() + ).withSearch("userChildrenNumber>:3").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) } From 4a3e821cd360957f06719226c2dfba5581499fae Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:40:50 +0100 Subject: [PATCH 07/12] feat: update grammar --- src/main/antlr4/Query.g4 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/antlr4/Query.g4 b/src/main/antlr4/Query.g4 index 2a2a373..36a722c 100644 --- a/src/main/antlr4/Query.g4 +++ b/src/main/antlr4/Query.g4 @@ -33,7 +33,9 @@ value op : EQ | GT + | GTE | LT + | LTE | NOT_EQ ; @@ -137,11 +139,17 @@ GT : '>' ; +GTE + : '>=' + ; LT : '<' ; +LTE + : '<=' + ; EQ : ':' From b6e1e085f5c799f0533f1cc724c1099420b43ddb Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:41:00 +0100 Subject: [PATCH 08/12] test: add tests --- .../SpringSearchApplicationTest.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 66eb2e6..453bc73 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -1015,4 +1015,42 @@ class SpringSearchApplicationTest { Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals(user2UUID, robotUsers[0].uuid) } + + @Test + fun canGetUsersWithNumberOfChildrenLessOrEqualSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber<=2").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(1, users.size) + Assertions.assertEquals("john", users[0].userFirstName) + } + + @Test + fun canGetUsersWithNumberOfChildrenGreaterOrEqualSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber>=3").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + } + + @Test + fun canGetUsersWithNumberOfChildrenLessSearch() { + userRepository.save(Users(userFirstName = "john", userChildrenNumber = 2)) + userRepository.save(Users(userFirstName = "jane", userChildrenNumber = 3)) + userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("userChildrenNumber<3").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(1, users.size) + Assertions.assertEquals("john", users[0].userFirstName) + } } From ddb389d765a1bf1f1845e3897203ff3093b7f15d Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 10:41:44 +0100 Subject: [PATCH 09/12] feat: add gte and lte operations and change from chat to string --- .../com/sipios/springsearch/SearchCriteria.kt | 2 +- .../com/sipios/springsearch/SearchOperation.kt | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt index e87ba7e..adcc69c 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchCriteria.kt @@ -5,7 +5,7 @@ class SearchCriteria // Change EQUALS into ENDS_WITH, CONTAINS, STARTS_WITH base var operation: SearchOperation? init { - var op = SearchOperation.getSimpleOperation(operation[0]) + var op = SearchOperation.getSimpleOperation(operation) if (op != null) { // 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) diff --git a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt index d6a1a04..333f5c5 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt @@ -1,10 +1,10 @@ package com.sipios.springsearch enum class SearchOperation { - EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN; + EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN, GREATER_THAN_EQUALS, LESS_THAN_EQUALS; companion object { - val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~") + val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">=", "<=") val ZERO_OR_MORE_REGEX = "*" val OR_OPERATOR = "OR" val AND_OPERATOR = "AND" @@ -17,12 +17,14 @@ enum class SearchOperation { * @param input operation as string * @return The matching operation */ - fun getSimpleOperation(input: Char): SearchOperation? { + fun getSimpleOperation(input: String): SearchOperation? { return when (input) { - ':' -> EQUALS - '!' -> NOT_EQUALS - '>' -> GREATER_THAN - '<' -> LESS_THAN + ":" -> EQUALS + "!" -> NOT_EQUALS + ">" -> GREATER_THAN + "<" -> LESS_THAN + ">=" -> GREATER_THAN_EQUALS + "<=" -> LESS_THAN_EQUALS else -> null } } From 8750f62108735f81639a42a4a85114df0660dfe2 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 11:03:00 +0100 Subject: [PATCH 10/12] feat: update strategies and add tests --- .../springsearch/strategies/DateStrategy.kt | 2 + .../springsearch/strategies/DoubleStrategy.kt | 2 + .../strategies/DurationStrategy.kt | 2 + .../springsearch/strategies/FloatStrategy.kt | 2 + .../strategies/InstantStrategy.kt | 2 + .../springsearch/strategies/IntStrategy.kt | 2 + .../strategies/LocalDateStrategy.kt | 2 + .../strategies/LocalDateTimeStrategy.kt | 2 + .../strategies/LocalTimeStrategy.kt | 2 + .../SpringSearchApplicationTest.kt | 138 ++++++++++++++++-- 10 files changed, 147 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt index d240e70..61f5c69 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DateStrategy.kt @@ -22,6 +22,8 @@ class DateStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Date) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Date) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Date) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 135dfb3..7b1ccc0 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DoubleStrategy.kt @@ -17,6 +17,8 @@ class DoubleStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Double) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Double) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Double) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 c35a847..a722fe2 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/DurationStrategy.kt @@ -18,6 +18,8 @@ class DurationStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Duration) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Duration) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Duration) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 65e7525..ea1d1e6 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/FloatStrategy.kt @@ -17,6 +17,8 @@ class FloatStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Float) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Float) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Float) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 95aff1f..66294cd 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/InstantStrategy.kt @@ -18,6 +18,8 @@ class InstantStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Instant) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Instant) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Instant) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 fc8ceb1..21f3863 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/IntStrategy.kt @@ -17,6 +17,8 @@ class IntStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as Int) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as Int) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as Int) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 57e8ae2..2b435f6 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateStrategy.kt @@ -18,6 +18,8 @@ class LocalDateStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDate) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDate) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalDate) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 18e691f..763dae5 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalDateTimeStrategy.kt @@ -18,6 +18,8 @@ class LocalDateTimeStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalDateTime) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalDateTime) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalDateTime) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(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 998c8de..7682689 100644 --- a/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt +++ b/src/main/kotlin/com/sipios/springsearch/strategies/LocalTimeStrategy.kt @@ -18,6 +18,8 @@ class LocalTimeStrategy : ParsingStrategy { return when (ops) { SearchOperation.GREATER_THAN -> builder.greaterThan(path[fieldName], value as LocalTime) SearchOperation.LESS_THAN -> builder.lessThan(path[fieldName], value as LocalTime) + SearchOperation.GREATER_THAN_EQUALS -> builder.greaterThanOrEqualTo(path[fieldName], value as LocalTime) + SearchOperation.LESS_THAN_EQUALS -> builder.lessThanOrEqualTo(path[fieldName], value as LocalTime) else -> super.buildPredicate(builder, path, fieldName, ops, value) } } diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 453bc73..4123a0c 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -592,6 +592,44 @@ class SpringSearchApplicationTest { Assertions.assertEquals(0, specificationUsers.size) } + @Test + fun canGetUsersAfterEqualDate() { + val sdf = StdDateFormat() + userRepository.save(Users(createdAt = sdf.parse("2019-01-01"))) + userRepository.save(Users(createdAt = sdf.parse("2019-01-03"))) + + var specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt>='2019-01-01'").build() + var specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(2, specificationUsers.size) + + specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt>='2019-01-04'").build() + specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(0, specificationUsers.size) + } + + @Test + fun canGetUsersEarlierEqualDate() { + val sdf = StdDateFormat() + userRepository.save(Users(createdAt = sdf.parse("2019-01-01"))) + userRepository.save(Users(createdAt = sdf.parse("2019-01-03"))) + + var specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt<='2019-01-01'").build() + var specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(1, specificationUsers.size) + + specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", true) + ).withSearch("createdAt<='2019-01-03'").build() + specificationUsers = userRepository.findAll(specification) + Assertions.assertEquals(2, specificationUsers.size) + } + @Test fun canGetUsersAtPreciseDate() { val sdf = StdDateFormat() @@ -742,7 +780,7 @@ class SpringSearchApplicationTest { } @Test - fun canGetUsersWithUpdatedInstantAtGreaterSearch() { + fun canGetUsersWithUpdateInstantAtGreaterSearch() { userRepository.save( Users( userFirstName = "HamidReza", @@ -760,10 +798,10 @@ class SpringSearchApplicationTest { } @Test - fun canGetUsersWithUpdatedInstantAtLessSearch() { + fun canGetUsersWithUpdateInstantAtGreaterThanEqualSearch() { userRepository.save( Users( - userFirstName = "HamidReza", + userFirstName = "john", updatedInstantAt = Instant.parse("2020-01-10T10:15:30Z") ) ) @@ -771,17 +809,17 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt<'2020-01-11T10:17:30Z'").build() + ).withSearch("updatedInstantAt>='2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) - Assertions.assertEquals("HamidReza", robotUsers[0].userFirstName) + Assertions.assertEquals("robot", robotUsers[0].userFirstName) } @Test - fun canGetUsersWithUpdatedInstantAtEqualSearch() { + fun canGetUsersWithUpdateInstantAtLessThanEqualSearch() { userRepository.save( Users( - userFirstName = "HamidReza", + userFirstName = "john", updatedInstantAt = Instant.parse("2020-01-10T10:15:30Z") ) ) @@ -789,10 +827,10 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt:'2020-01-10T10:15:30Z'").build() + ).withSearch("updatedInstantAt<='2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) - Assertions.assertEquals("HamidReza", robotUsers[0].userFirstName) + Assertions.assertEquals("john", robotUsers[0].userFirstName) } @Test @@ -834,6 +872,32 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedAt = LocalDateTime.parse("2020-01-10T10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedAt = LocalDateTime.parse("2020-01-11T10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedAt>='2020-01-11T10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + + @Test + fun canGetUsersWithUpdatedAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedAt = LocalDateTime.parse("2020-01-10T10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedAt = LocalDateTime.parse("2020-01-11T10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedAt<='2020-01-11T10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + @Test fun canGetUsersWithUpdatedDateAtGreaterSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedDateAt = LocalDate.parse("2020-01-10"))) @@ -886,6 +950,34 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedDateAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedDateAt = LocalDate.parse("2020-01-10"))) + userRepository.save(Users(userFirstName = "robot", updatedDateAt = LocalDate.parse("2020-01-11"))) + userRepository.save(Users(userFirstName = "robot2", updatedDateAt = LocalDate.parse("2020-01-12"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedDateAt<='2020-01-11'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + + @Test + fun canGetUsersWithUpdatedDateAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedDateAt = LocalDate.parse("2020-01-10"))) + userRepository.save(Users(userFirstName = "robot", updatedDateAt = LocalDate.parse("2020-01-11"))) + userRepository.save(Users(userFirstName = "robot2", updatedDateAt = LocalDate.parse("2020-01-12"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedDateAt>='2020-01-11'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + @Test fun canGetUsersWithUpdatedTimeAtGreaterSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedTimeAt = LocalTime.parse("10:15:30"))) @@ -925,6 +1017,34 @@ class SpringSearchApplicationTest { Assertions.assertEquals("HamidReza", hamidrezaUsers[0].userFirstName) } + @Test + fun canGetUsersWithUpdatedTimeAtLessThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedTimeAt = LocalTime.parse("10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedTimeAt = LocalTime.parse("10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedTimeAt = LocalTime.parse("10:25:30"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedTimeAt<='10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) + } + + @Test + fun canGetUsersWithUpdatedTimeAtGreaterThanEqualSearch() { + userRepository.save(Users(userFirstName = "john", updatedTimeAt = LocalTime.parse("10:15:30"))) + userRepository.save(Users(userFirstName = "robot", updatedTimeAt = LocalTime.parse("10:20:30"))) + userRepository.save(Users(userFirstName = "robot2", updatedTimeAt = LocalTime.parse("10:25:30"))) + + val specification = SpecificationsBuilder( + SearchSpec::class.constructors.first().call("", false) + ).withSearch("updatedTimeAt>='10:20:30'").build() + val users = userRepository.findAll(specification) + Assertions.assertEquals(2, users.size) + Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) + } + @Test fun canGetUsersWithUpdatedTimeAtNotEqualSearch() { userRepository.save(Users(userFirstName = "HamidReza", updatedTimeAt = LocalTime.parse("10:15:30"))) From c58f5ed243a10b66ceb462eb334d71513b16bcd6 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 11:28:18 +0100 Subject: [PATCH 11/12] doc: update documentation --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3143ca7..745f8ab 100644 --- a/README.md +++ b/README.md @@ -134,10 +134,14 @@ Request : `/cars?search=color!Red` 3. Using the greater than operator `>` Request : `/cars?search=creationyear>2017` +> Note: You can use the `>=` operator as well. + ![greater than operator example](./docs/images/greater-than-example.gif) 4. Using the less than operator `<` -Request : `/cars?search=price<100000` +Request : `/cars?search=price<100000` +> Note: You can use the `<=` operator as well. + ![less than operator example](./docs/images/less-than-example.gif) 5. Using the starts with operator `*` From 64a183b448a11a70c7c40017905c591453807657 Mon Sep 17 00:00:00 2001 From: vincentescoffier Date: Thu, 4 Jan 2024 16:12:38 +0100 Subject: [PATCH 12/12] refactor: change from = to : --- README.md | 4 +-- src/main/antlr4/Query.g4 | 4 +-- .../sipios/springsearch/SearchOperation.kt | 6 ++-- .../SpringSearchApplicationTest.kt | 28 +++++++++---------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 745f8ab..97c9161 100644 --- a/README.md +++ b/README.md @@ -134,13 +134,13 @@ Request : `/cars?search=color!Red` 3. Using the greater than operator `>` Request : `/cars?search=creationyear>2017` -> Note: You can use the `>=` operator as well. +> Note: You can use the `>:` operator as well. ![greater than operator example](./docs/images/greater-than-example.gif) 4. Using the less than operator `<` Request : `/cars?search=price<100000` -> Note: You can use the `<=` operator as well. +> Note: You can use the `<:` operator as well. ![less than operator example](./docs/images/less-than-example.gif) diff --git a/src/main/antlr4/Query.g4 b/src/main/antlr4/Query.g4 index 36a722c..0bf8374 100644 --- a/src/main/antlr4/Query.g4 +++ b/src/main/antlr4/Query.g4 @@ -140,7 +140,7 @@ GT ; GTE - : '>=' + : '>:' ; LT @@ -148,7 +148,7 @@ LT ; LTE - : '<=' + : '<:' ; EQ diff --git a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt index 333f5c5..f8f024a 100644 --- a/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt +++ b/src/main/kotlin/com/sipios/springsearch/SearchOperation.kt @@ -4,7 +4,7 @@ enum class SearchOperation { EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, STARTS_WITH, ENDS_WITH, CONTAINS, DOESNT_START_WITH, DOESNT_END_WITH, DOESNT_CONTAIN, GREATER_THAN_EQUALS, LESS_THAN_EQUALS; companion object { - val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">=", "<=") + val SIMPLE_OPERATION_SET = arrayOf(":", "!", ">", "<", "~", ">:", "<:") val ZERO_OR_MORE_REGEX = "*" val OR_OPERATOR = "OR" val AND_OPERATOR = "AND" @@ -23,8 +23,8 @@ enum class SearchOperation { "!" -> NOT_EQUALS ">" -> GREATER_THAN "<" -> LESS_THAN - ">=" -> GREATER_THAN_EQUALS - "<=" -> LESS_THAN_EQUALS + ">:" -> GREATER_THAN_EQUALS + "<:" -> LESS_THAN_EQUALS else -> null } } diff --git a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt index 4123a0c..492531b 100644 --- a/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt +++ b/src/test/kotlin/com/sipios/springsearch/SpringSearchApplicationTest.kt @@ -600,13 +600,13 @@ class SpringSearchApplicationTest { var specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt>='2019-01-01'").build() + ).withSearch("createdAt>:'2019-01-01'").build() var specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(2, specificationUsers.size) specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt>='2019-01-04'").build() + ).withSearch("createdAt>:'2019-01-04'").build() specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(0, specificationUsers.size) } @@ -619,13 +619,13 @@ class SpringSearchApplicationTest { var specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt<='2019-01-01'").build() + ).withSearch("createdAt<:'2019-01-01'").build() var specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(1, specificationUsers.size) specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", true) - ).withSearch("createdAt<='2019-01-03'").build() + ).withSearch("createdAt<:'2019-01-03'").build() specificationUsers = userRepository.findAll(specification) Assertions.assertEquals(2, specificationUsers.size) } @@ -809,7 +809,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt>='2020-01-11T09:20:30Z'").build() + ).withSearch("updatedInstantAt>:'2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals("robot", robotUsers[0].userFirstName) @@ -827,7 +827,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedInstantAt<='2020-01-11T09:20:30Z'").build() + ).withSearch("updatedInstantAt<:'2020-01-11T09:20:30Z'").build() val robotUsers = userRepository.findAll(specification) Assertions.assertEquals(1, robotUsers.size) Assertions.assertEquals("john", robotUsers[0].userFirstName) @@ -879,7 +879,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedAt>='2020-01-11T10:20:30'").build() + ).withSearch("updatedAt>:'2020-01-11T10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -892,7 +892,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "robot2", updatedAt = LocalDateTime.parse("2020-01-12T10:20:30"))) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedAt<='2020-01-11T10:20:30'").build() + ).withSearch("updatedAt<:'2020-01-11T10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -958,7 +958,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedDateAt<='2020-01-11'").build() + ).withSearch("updatedDateAt<:'2020-01-11'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -972,7 +972,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedDateAt>='2020-01-11'").build() + ).withSearch("updatedDateAt>:'2020-01-11'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -1025,7 +1025,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedTimeAt<='10:20:30'").build() + ).withSearch("updatedTimeAt<:'10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "robot2" }) @@ -1039,7 +1039,7 @@ class SpringSearchApplicationTest { val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("updatedTimeAt>='10:20:30'").build() + ).withSearch("updatedTimeAt>:'10:20:30'").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) Assertions.assertFalse(users.any { user -> user.userFirstName == "john" }) @@ -1143,7 +1143,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("userChildrenNumber<=2").build() + ).withSearch("userChildrenNumber<:2").build() val users = userRepository.findAll(specification) Assertions.assertEquals(1, users.size) Assertions.assertEquals("john", users[0].userFirstName) @@ -1156,7 +1156,7 @@ class SpringSearchApplicationTest { userRepository.save(Users(userFirstName = "joe", userChildrenNumber = 4)) val specification = SpecificationsBuilder( SearchSpec::class.constructors.first().call("", false) - ).withSearch("userChildrenNumber>=3").build() + ).withSearch("userChildrenNumber>:3").build() val users = userRepository.findAll(specification) Assertions.assertEquals(2, users.size) }