Skip to content

Commit 1716229

Browse files
raphaeldeliobsbodden
authored andcommitted
feat: adding complementing filtering methods for numbers and other tag methods
1 parent 59ab590 commit 1716229

File tree

3 files changed

+183
-6
lines changed

3 files changed

+183
-6
lines changed

redis-om-spring/src/main/java/com/redis/om/spring/metamodel/indexed/NumericField.java

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.redis.om.spring.metamodel.indexed;
22

3+
import java.util.ArrayList;
34
import java.util.Arrays;
5+
import java.util.Collection;
46
import java.util.List;
57
import java.util.function.Consumer;
68

@@ -137,7 +139,7 @@ public BetweenPredicate<E, T> between(T min, T max) {
137139

138140
/**
139141
* Creates an in predicate for this numeric field to match any of the specified values.
140-
*
142+
*
141143
* @param values the values to match against
142144
* @return an InPredicate that matches entities where this field equals any of the specified values
143145
*/
@@ -148,6 +150,22 @@ public BetweenPredicate<E, T> between(T min, T max) {
148150
return new InPredicate<>(searchFieldAccessor, Arrays.asList(values));
149151
}
150152

153+
/**
154+
* Creates an in predicate for this numeric field to match any of the specified values from a collection.
155+
* <p>
156+
* This is useful when you already have your values in a Collection (List, Set, etc.) and want to
157+
* avoid converting to an array.
158+
*
159+
* @param values the collection of values to match against
160+
* @return an InPredicate that matches entities where this field equals any of the specified values
161+
*/
162+
@SuppressWarnings(
163+
"unchecked"
164+
)
165+
public InPredicate<E, ?> in(Collection<T> values) {
166+
return new InPredicate<>(searchFieldAccessor, new ArrayList<>(values));
167+
}
168+
151169
/**
152170
* Creates an increment action for this numeric field.
153171
*
@@ -172,7 +190,7 @@ public Consumer<E> decrBy(Long value) {
172190
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
173191
* Double values.
174192
* This method is similar to TagField.in() but for numeric arrays.
175-
*
193+
*
176194
* @param values the Double values to check for membership in the array
177195
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
178196
*/
@@ -183,11 +201,28 @@ public Consumer<E> decrBy(Long value) {
183201
return new InPredicate<>(searchFieldAccessor, Arrays.asList(values));
184202
}
185203

204+
/**
205+
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
206+
* Double values from a collection.
207+
* <p>
208+
* This is useful when you already have your Double values in a Collection (List, Set, etc.) and want to
209+
* avoid converting to an array.
210+
*
211+
* @param values the collection of Double values to check for membership in the array
212+
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
213+
*/
214+
@SuppressWarnings(
215+
"unchecked"
216+
)
217+
public InPredicate<E, ?> containsDouble(Collection<Double> values) {
218+
return new InPredicate<>(searchFieldAccessor, new ArrayList<>(values));
219+
}
220+
186221
/**
187222
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
188223
* Long values.
189224
* This method is similar to TagField.in() but for numeric arrays.
190-
*
225+
*
191226
* @param values the Long values to check for membership in the array
192227
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
193228
*/
@@ -198,11 +233,28 @@ public Consumer<E> decrBy(Long value) {
198233
return new InPredicate<>(searchFieldAccessor, Arrays.asList(values));
199234
}
200235

236+
/**
237+
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
238+
* Long values from a collection.
239+
* <p>
240+
* This is useful when you already have your Long values in a Collection (List, Set, etc.) and want to
241+
* avoid converting to an array.
242+
*
243+
* @param values the collection of Long values to check for membership in the array
244+
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
245+
*/
246+
@SuppressWarnings(
247+
"unchecked"
248+
)
249+
public InPredicate<E, ?> containsLong(Collection<Long> values) {
250+
return new InPredicate<>(searchFieldAccessor, new ArrayList<>(values));
251+
}
252+
201253
/**
202254
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
203255
* Integer values.
204256
* This method is similar to TagField.in() but for numeric arrays.
205-
*
257+
*
206258
* @param values the Integer values to check for membership in the array
207259
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
208260
*/
@@ -213,4 +265,21 @@ public Consumer<E> decrBy(Long value) {
213265
return new InPredicate<>(searchFieldAccessor, Arrays.asList(values));
214266
}
215267

268+
/**
269+
* Creates an array membership predicate for this numeric field to check if the array contains any of the specified
270+
* Integer values from a collection.
271+
* <p>
272+
* This is useful when you already have your Integer values in a Collection (List, Set, etc.) and want to
273+
* avoid converting to an array.
274+
*
275+
* @param values the collection of Integer values to check for membership in the array
276+
* @return an InPredicate that matches entities where this numeric array field contains any of the specified values
277+
*/
278+
@SuppressWarnings(
279+
"unchecked"
280+
)
281+
public InPredicate<E, ?> containsInt(Collection<Integer> values) {
282+
return new InPredicate<>(searchFieldAccessor, new ArrayList<>(values));
283+
}
284+
216285
}

redis-om-spring/src/main/java/com/redis/om/spring/metamodel/indexed/TagField.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.redis.om.spring.metamodel.indexed;
22

3+
import java.util.ArrayList;
34
import java.util.Arrays;
45
import java.util.Collection;
5-
import java.util.List;
66
import java.util.Set;
77
import java.util.function.Consumer;
88
import java.util.function.ToLongFunction;
@@ -117,6 +117,20 @@ public NotEqualPredicate<E, T> notEq(Object... values) {
117117
return new NotEqualPredicate<>(searchFieldAccessor, Arrays.stream(values).map(Object::toString).toList());
118118
}
119119

120+
/**
121+
* Creates a not-equal predicate for a collection of string values.
122+
* <p>
123+
* This predicate matches entities where the tag field does not contain any of the specified values.
124+
* This is useful for excluding entities tagged with any of several tags when the values are already
125+
* in a Collection (List, Set, etc.).
126+
*
127+
* @param values the collection of tag values to exclude from results
128+
* @return a not-equal predicate for query building
129+
*/
130+
public NotEqualPredicate<E, T> notEq(Collection<String> values) {
131+
return new NotEqualPredicate<>(searchFieldAccessor, new ArrayList<>(values));
132+
}
133+
120134
/**
121135
* Creates an IN predicate for multiple string values.
122136
* <p>
@@ -154,7 +168,7 @@ public NotEqualPredicate<E, T> notEq(Object... values) {
154168
* @return an IN predicate for query building
155169
*/
156170
public InPredicate<E, ?> in(Collection<String> values) {
157-
return new InPredicate<>(searchFieldAccessor, List.copyOf(values));
171+
return new InPredicate<>(searchFieldAccessor, new ArrayList<>(values));
158172
}
159173

160174
/**
@@ -183,6 +197,20 @@ public NotEqualPredicate<E, T> notEq(Object... values) {
183197
return new ContainsAllPredicate<>(searchFieldAccessor, Arrays.stream(values).map(Object::toString).toList());
184198
}
185199

200+
/**
201+
* Creates a contains-all predicate for a collection of string values.
202+
* <p>
203+
* This predicate matches entities where the tag field contains all of the specified values.
204+
* This is useful for finding entities that have been tagged with a specific combination of tags
205+
* when the values are already in a Collection (List, Set, etc.).
206+
*
207+
* @param values the collection of tag values that must all be present
208+
* @return a contains-all predicate for query building
209+
*/
210+
public ContainsAllPredicate<E, ?> containsAll(Collection<String> values) {
211+
return new ContainsAllPredicate<>(searchFieldAccessor, new ArrayList<>(values));
212+
}
213+
186214
/**
187215
* Creates a contains-none predicate for a single value.
188216
* <p>

tests/src/test/java/com/redis/om/spring/search/stream/EntityStreamDocsTest.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,20 @@ void testFindByThreeNumericPropertiesOrList() {
255255
assertThat(names).contains("RedisInc", "Microsoft", "Tesla");
256256
}
257257

258+
@Test
259+
void testFindByIntegerNumericPropertyInWithCollection() {
260+
// Test passing a Collection directly to the in() method for Integer fields
261+
List<Integer> yearsToSearch = List.of(2011, 1975, 2003);
262+
263+
List<String> names = entityStream //
264+
.of(Company.class) //
265+
.filter(Company$.YEAR_FOUNDED.in(yearsToSearch)) //
266+
.map(Company$.NAME) //
267+
.collect(Collectors.toList());
268+
269+
assertThat(names).contains("RedisInc", "Microsoft", "Tesla");
270+
}
271+
258272
@Test
259273
void testFindByTwoPropertiesAndedNotEquals() {
260274
SearchStream<Company> stream = entityStream.of(Company.class);
@@ -786,6 +800,42 @@ void testFindByRolesInWithList() {
786800
assertTrue(names.contains("Suze Shardlow"));
787801
}
788802

803+
@Test
804+
void testFindByRolesInWithSet() {
805+
// Test passing a Set directly to the in() method
806+
Set<String> rolesToSearch = Set.of("educator", "devrel");
807+
808+
List<String> names = entityStream //
809+
.of(User.class) //
810+
.filter(User$.ROLES.in(rolesToSearch)) //
811+
.map(User$.NAME) //
812+
.collect(Collectors.toList());
813+
814+
assertEquals(4, names.size());
815+
816+
assertTrue(names.contains("Steve Lorello"));
817+
assertTrue(names.contains("Nava Levy"));
818+
assertTrue(names.contains("Savannah Norem"));
819+
assertTrue(names.contains("Suze Shardlow"));
820+
}
821+
822+
@Test
823+
void testFindByRolesNotEqWithCollection() {
824+
// Test passing a Collection to the notEq() method
825+
List<String> rolesToExclude = List.of("guru");
826+
827+
List<String> names = entityStream //
828+
.of(User.class) //
829+
.filter(User$.ROLES.notEq(rolesToExclude)) //
830+
.map(User$.NAME) //
831+
.collect(Collectors.toList());
832+
833+
assertEquals(2, names.size());
834+
835+
assertTrue(names.contains("Savannah Norem"));
836+
assertTrue(names.contains("Suze Shardlow"));
837+
}
838+
789839
@Test
790840
void testFindByTagsContainingAll() {
791841
List<String> names = entityStream //
@@ -799,6 +849,22 @@ void testFindByTagsContainingAll() {
799849
assertTrue(names.contains("RedisInc"));
800850
}
801851

852+
@Test
853+
void testFindByTagsContainingAllWithCollection() {
854+
// Test passing a Collection to the containsAll() method
855+
List<String> requiredTags = List.of("fast", "scalable", "reliable");
856+
857+
List<String> names = entityStream //
858+
.of(Company.class) //
859+
.filter(Company$.TAGS.containsAll(requiredTags)) //
860+
.map(Company$.NAME) //
861+
.collect(Collectors.toList());
862+
863+
assertEquals(1, names.size());
864+
865+
assertTrue(names.contains("RedisInc"));
866+
}
867+
802868
@Test
803869
void testFindByTagsEquals() {
804870
Set<String> tags = Set.of("fast", "scalable", "reliable", "database", "nosql");
@@ -1332,6 +1398,20 @@ void testFindByDoubleNumericPropertyIn() {
13321398
assertThat(names).containsExactly("Nava Levy", "Savannah Norem");
13331399
}
13341400

1401+
@Test
1402+
void testFindByDoubleNumericPropertyInWithCollection() {
1403+
// Test passing a Collection directly to the in() method
1404+
List<Double> winningsToSearch = List.of(1234.5678, 999.99);
1405+
1406+
List<String> names = entityStream //
1407+
.of(User.class) //
1408+
.filter(User$.LOTTERY_WINNINGS.in(winningsToSearch)) //
1409+
.map(User$.NAME) //
1410+
.collect(Collectors.toList());
1411+
1412+
assertThat(names).containsExactly("Nava Levy", "Savannah Norem");
1413+
}
1414+
13351415
@Test
13361416
void testFindByDoubleNumericPropertyBetween() {
13371417
SearchStream<User> stream = entityStream.of(User.class);

0 commit comments

Comments
 (0)