Skip to content

Commit 0e07bc3

Browse files
authored
feature: enable repository queries on nested Set/List entity members (#159)
1 parent bd74dc3 commit 0e07bc3

File tree

7 files changed

+148
-22
lines changed

7 files changed

+148
-22
lines changed

demos/roms-documents/src/main/java/com/redis/om/documents/domain/CompanyMeta.java

+10-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.util.Set;
44

5-
import com.redis.om.spring.annotations.Document;
65
import com.redis.om.spring.annotations.Indexed;
76

87
import lombok.Data;
@@ -13,18 +12,17 @@
1312
@Data
1413
@NoArgsConstructor
1514
@RequiredArgsConstructor(staticName = "of")
16-
@Document
1715
public class CompanyMeta {
18-
19-
@Indexed
20-
@NonNull
21-
private String stringValue;
2216

23-
@Indexed
24-
@NonNull
25-
private Integer numberValue;
17+
@Indexed
18+
@NonNull
19+
private String stringValue;
2620

27-
@Indexed
28-
@NonNull
29-
private Set<String> tagValues;
21+
@Indexed
22+
@NonNull
23+
private Integer numberValue;
24+
25+
@Indexed
26+
@NonNull
27+
private Set<String> tagValues;
3028
}

redis-om-spring/src/main/java/com/redis/om/spring/repository/query/RediSearchQuery.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,14 @@ else if (Set.class.isAssignableFrom(fieldType) || List.class.isAssignableFrom(fi
303303
} else {
304304
qf.add(Pair.of(actualKey, QueryClause.get(FieldType.Geo, part.getType())));
305305
}
306-
} else { // String or Boolean
306+
} else if (CharSequence.class.isAssignableFrom(collectionType) || (collectionType == Boolean.class)) {
307307
if (isANDQuery) {
308308
qf.add(Pair.of(actualKey, QueryClause.Tag_CONTAINING_ALL));
309309
} else {
310310
qf.add(Pair.of(actualKey, QueryClause.get(FieldType.Tag, part.getType())));
311311
}
312+
} else {
313+
qf.addAll(extractQueryFields(collectionType, part, path, level + 1));
312314
}
313315
}
314316
}

redis-om-spring/src/test/java/com/redis/om/spring/RedisJSONKeyValueAdapterTest.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66

77
import java.time.LocalDate;
88
import java.util.List;
9+
import java.util.Set;
910

1011
import org.junit.jupiter.api.BeforeEach;
1112
import org.junit.jupiter.api.Test;
1213
import org.springframework.beans.factory.annotation.Autowired;
1314
import org.springframework.data.geo.Point;
1415

1516
import com.redis.om.spring.annotations.document.fixtures.Company;
17+
import com.redis.om.spring.annotations.document.fixtures.CompanyMeta;
1618
import com.redis.om.spring.annotations.document.fixtures.CompanyRepository;
1719

1820
public class RedisJSONKeyValueAdapterTest extends AbstractBaseDocumentTest {
@@ -28,10 +30,14 @@ public class RedisJSONKeyValueAdapterTest extends AbstractBaseDocumentTest {
2830
@BeforeEach
2931
void createData() {
3032
repository.deleteAll();
31-
redis = repository.save(
32-
Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]"));
33-
microsoft = repository.save(Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
34-
new Point(-122.124500, 47.640160), "[email protected]"));
33+
34+
redis = Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]");
35+
redis.setMetaList(Set.of(CompanyMeta.of("Redis", 100, Set.of("RedisTag"))));
36+
37+
microsoft = Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15), new Point(-122.124500, 47.640160), "[email protected]");
38+
microsoft.setMetaList(Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag"))));
39+
40+
repository.saveAll(List.of(redis, microsoft));
3541
}
3642

3743
@Test

redis-om-spring/src/test/java/com/redis/om/spring/annotations/document/BasicRedisDocumentMappingTest.java

+76-4
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ void cleanUp() {
4747

4848
@Test
4949
void testBasicCrudOperations() {
50-
Company redis = repository.save(
51-
Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]"));
52-
Company microsoft = repository.save(Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
53-
new Point(-122.124500, 47.640160), "[email protected]"));
50+
Company redis = Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]");
51+
redis.setMetaList(Set.of(CompanyMeta.of("Redis", 100, Set.of("RedisTag"))));
52+
53+
Company microsoft = Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
54+
new Point(-122.124500, 47.640160), "[email protected]");
55+
microsoft.setMetaList(Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag"))));
56+
57+
repository.saveAll(List.of(redis, microsoft));
5458

5559
assertEquals(2, repository.count());
5660

@@ -452,4 +456,72 @@ void testSearchContainingAllInSetOfLocations() {
452456
var docs = docWithSetsRepository.findByTheLocationsContainingAll(Set.of(point1, point2));
453457
assertThat(docs).containsOnly(doc1, doc2);
454458
}
459+
460+
@Test
461+
void testFindByTagsInNestedField() {
462+
Company redis = Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]");
463+
redis.setMetaList(Set.of(CompanyMeta.of("Redis", 100, Set.of("RedisTag", "CommonTag"))));
464+
465+
Company microsoft = Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
466+
new Point(-122.124500, 47.640160), "[email protected]");
467+
microsoft.setMetaList(Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag", "CommonTag"))));
468+
469+
repository.saveAll(List.of(redis, microsoft));
470+
471+
assertEquals(2, repository.count());
472+
473+
List<Company> shouldBeOnlyRedis = repository.findByMetaList_tagValues(Set.of("RedisTag"));
474+
List<Company> shouldBeOnlyMS = repository.findByMetaList_tagValues(Set.of("MsTag"));
475+
List<Company> shouldBeBoth = repository.findByMetaList_tagValues(Set.of("CommonTag"));
476+
477+
assertAll( //
478+
() -> assertThat(shouldBeOnlyRedis).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("RedisInc")), //
479+
() -> assertThat(shouldBeOnlyMS).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("Microsoft")), //
480+
() -> assertThat(shouldBeBoth).hasSize(2).map(Company::getName).containsExactlyInAnyOrder("RedisInc", "Microsoft") //
481+
);
482+
}
483+
484+
@Test
485+
void testFindByStringValueInNestedField() {
486+
Company redis = Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]");
487+
redis.setMetaList(Set.of(CompanyMeta.of("RD", 100, Set.of("RedisTag", "CommonTag"))));
488+
489+
Company microsoft = Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
490+
new Point(-122.124500, 47.640160), "[email protected]");
491+
microsoft.setMetaList(Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag", "CommonTag"))));
492+
493+
repository.saveAll(List.of(redis, microsoft));
494+
495+
assertEquals(2, repository.count());
496+
497+
List<Company> shouldBeOnlyRedis = repository.findByMetaList_stringValue("RD");
498+
List<Company> shouldBeOnlyMS = repository.findByMetaList_stringValue("MS");
499+
500+
assertAll( //
501+
() -> assertThat(shouldBeOnlyRedis).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("RedisInc")), //
502+
() -> assertThat(shouldBeOnlyMS).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("Microsoft")) //
503+
);
504+
}
505+
506+
@Test
507+
void testFindByNumericValueInNestedField() {
508+
Company redis = Company.of("RedisInc", 2011, LocalDate.of(2021, 5, 1), new Point(-122.066540, 37.377690), "[email protected]");
509+
redis.setMetaList(Set.of(CompanyMeta.of("RD", 100, Set.of("RedisTag", "CommonTag"))));
510+
511+
Company microsoft = Company.of("Microsoft", 1975, LocalDate.of(2022, 8, 15),
512+
new Point(-122.124500, 47.640160), "[email protected]");
513+
microsoft.setMetaList(Set.of(CompanyMeta.of("MS", 50, Set.of("MsTag", "CommonTag"))));
514+
515+
repository.saveAll(List.of(redis, microsoft));
516+
517+
assertEquals(2, repository.count());
518+
519+
List<Company> shouldBeOnlyRedis = repository.findByMetaList_numberValue(100);
520+
List<Company> shouldBeOnlyMS = repository.findByMetaList_numberValue(50);
521+
522+
assertAll( //
523+
() -> assertThat(shouldBeOnlyRedis).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("RedisInc")), //
524+
() -> assertThat(shouldBeOnlyMS).hasSize(1).allSatisfy(c -> c.getName().equalsIgnoreCase("Microsoft")) //
525+
);
526+
}
455527
}

redis-om-spring/src/test/java/com/redis/om/spring/annotations/document/fixtures/Company.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ public class Company {
4545

4646
@Indexed
4747
private Set<String> tags = new HashSet<String>();
48-
48+
4949
@NonNull
5050
@Indexed
5151
@Bloom(name = "bf_company_email", capacity = 100000, errorRate = 0.001)
5252
private String email;
53+
54+
@Indexed
55+
private Set<CompanyMeta> metaList;
5356

5457
@Indexed
5558
private boolean publiclyListed;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.redis.om.spring.annotations.document.fixtures;
2+
3+
import java.util.Set;
4+
5+
import com.redis.om.spring.annotations.Indexed;
6+
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
import lombok.NonNull;
10+
import lombok.RequiredArgsConstructor;
11+
12+
@Data
13+
@NoArgsConstructor
14+
@RequiredArgsConstructor(staticName = "of")
15+
public class CompanyMeta {
16+
17+
@Indexed
18+
@NonNull
19+
private String stringValue;
20+
21+
@Indexed
22+
@NonNull
23+
private Integer numberValue;
24+
25+
@Indexed
26+
@NonNull
27+
private Set<String> tagValues;
28+
}

redis-om-spring/src/test/java/com/redis/om/spring/annotations/document/fixtures/CompanyRepository.java

+17
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import java.util.Optional;
55
import java.util.Set;
66

7+
import org.springframework.data.geo.Distance;
8+
import org.springframework.data.geo.Point;
9+
710
import com.redis.om.spring.repository.RedisDocumentRepository;
811

912
public interface CompanyRepository extends RedisDocumentRepository<Company, String> {
@@ -20,4 +23,18 @@ public interface CompanyRepository extends RedisDocumentRepository<Company, Stri
2023
List<Company> findByPubliclyListed(boolean publiclyListed);
2124

2225
List<Company> findByTags(Set<String> tags);
26+
27+
// find one by property
28+
Optional<Company> findOneByName(String name);
29+
30+
// geospatial query
31+
Iterable<Company> findByLocationNear(Point point, Distance distance);
32+
33+
// starting with/ending with
34+
Iterable<Company> findByNameStartingWith(String prefix);
35+
36+
List<Company> findByMetaList_stringValue(String value);
37+
List<Company> findByMetaList_numberValue(Integer value);
38+
List<Company> findByMetaList_tagValues(Set<String> tags);
39+
2340
}

0 commit comments

Comments
 (0)