1
+ package com .redis .om .spring .search .stream ;
2
+
3
+ import static org .assertj .core .api .Assertions .assertThat ;
4
+ import static org .junit .jupiter .api .Assertions .*;
5
+
6
+ import java .util .Arrays ;
7
+ import java .util .List ;
8
+ import java .util .stream .Collectors ;
9
+
10
+ import org .junit .jupiter .api .AfterEach ;
11
+ import org .junit .jupiter .api .BeforeEach ;
12
+ import org .junit .jupiter .api .Test ;
13
+ import org .springframework .beans .factory .annotation .Autowired ;
14
+
15
+ import com .redis .om .spring .AbstractBaseDocumentTest ;
16
+ import com .redis .om .spring .fixtures .document .model .NumericArrayTestData ;
17
+ import com .redis .om .spring .fixtures .document .model .NumericArrayTestData$ ;
18
+ import com .redis .om .spring .fixtures .document .repository .NumericArrayTestDataRepository ;
19
+ import com .redis .om .spring .search .stream .EntityStream ;
20
+
21
+ /**
22
+ * Test class to demonstrate the issue described in GitHub issue #400:
23
+ * https://github.com/redis/redis-om-spring/issues/400
24
+ *
25
+ * The issue is that NumericField lacks methods to check if a numeric array
26
+ * contains specific numbers when using EntityStream, similar to how TagField.in() works.
27
+ *
28
+ * This test proves that the functionality is missing and shows what should work
29
+ * once the feature is implemented.
30
+ */
31
+ class NumericArraySearchTest extends AbstractBaseDocumentTest {
32
+
33
+ @ Autowired
34
+ NumericArrayTestDataRepository repository ;
35
+
36
+ @ Autowired
37
+ EntityStream entityStream ;
38
+
39
+ private NumericArrayTestData testData1 ;
40
+ private NumericArrayTestData testData2 ;
41
+ private NumericArrayTestData testData3 ;
42
+
43
+ @ BeforeEach
44
+ void loadTestData () {
45
+ testData1 = new NumericArrayTestData ();
46
+ testData1 .setName ("data1" );
47
+ testData1 .setMeasurements (Arrays .asList (1.5 , 2.5 , 3.5 ));
48
+ testData1 .setCounts (Arrays .asList (10L , 20L , 30L ));
49
+ testData1 .setRatings (Arrays .asList (1 , 2 , 3 ));
50
+ testData1 .setTags (Arrays .asList ("tag1" , "tag2" ));
51
+
52
+ testData2 = new NumericArrayTestData ();
53
+ testData2 .setName ("data2" );
54
+ testData2 .setMeasurements (Arrays .asList (2.5 , 4.5 , 6.5 ));
55
+ testData2 .setCounts (Arrays .asList (20L , 40L , 60L ));
56
+ testData2 .setRatings (Arrays .asList (2 , 4 , 6 ));
57
+ testData2 .setTags (Arrays .asList ("tag2" , "tag3" ));
58
+
59
+ testData3 = new NumericArrayTestData ();
60
+ testData3 .setName ("data3" );
61
+ testData3 .setMeasurements (Arrays .asList (3.5 , 7.5 , 9.5 ));
62
+ testData3 .setCounts (Arrays .asList (30L , 70L , 90L ));
63
+ testData3 .setRatings (Arrays .asList (3 , 7 , 9 ));
64
+ testData3 .setTags (Arrays .asList ("tag1" , "tag4" ));
65
+
66
+ repository .saveAll (Arrays .asList (testData1 , testData2 , testData3 ));
67
+ }
68
+
69
+ @ AfterEach
70
+ void cleanUp () {
71
+ repository .deleteAll ();
72
+ }
73
+
74
+ /**
75
+ * This test shows that TagField.in() works perfectly for string arrays with EntityStream.
76
+ * This is the pattern that NumericField should follow for numeric arrays.
77
+ */
78
+ @ Test
79
+ void testTagFieldInWorksWithEntityStream () {
80
+ // This demonstrates TagField.in() working with EntityStream:
81
+ List <NumericArrayTestData > results = entityStream
82
+ .of (NumericArrayTestData .class )
83
+ .filter (NumericArrayTestData$ .TAGS .in ("tag1" , "tag3" ))
84
+ .collect (Collectors .toList ());
85
+
86
+ // Verify the results - should find testData1 and testData3 (both have "tag1") and testData2 (has "tag3")
87
+ assertThat (results ).hasSize (3 );
88
+ assertThat (results ).contains (testData1 , testData2 , testData3 );
89
+ }
90
+
91
+ /**
92
+ * This test demonstrates the MISSING functionality for numeric arrays.
93
+ * This is the core issue from GitHub #400.
94
+ */
95
+ @ Test
96
+ void testNumericFieldLacksContainsFunctionalityWithEntityStream () {
97
+ // Test basic data setup first
98
+ assertThat (testData1 .getMeasurements ()).contains (2.5 );
99
+ assertThat (testData2 .getMeasurements ()).contains (2.5 );
100
+ assertThat (testData3 .getMeasurements ()).contains (7.5 );
101
+
102
+ // Should be able to find entities where measurements contains any of these values
103
+ List <NumericArrayTestData > measurementResults = entityStream
104
+ .of (NumericArrayTestData .class )
105
+ .filter (NumericArrayTestData$ .MEASUREMENTS .containsDouble (2.5 , 7.5 ))
106
+ .collect (Collectors .toList ());
107
+ assertThat (measurementResults ).hasSize (3 ); // All entities have at least one of these values
108
+
109
+ // Should be able to find entities where counts contains any of these values
110
+ List <NumericArrayTestData > countResults = entityStream
111
+ .of (NumericArrayTestData .class )
112
+ .filter (NumericArrayTestData$ .COUNTS .containsLong (20L , 70L ))
113
+ .collect (Collectors .toList ());
114
+ assertThat (countResults ).hasSize (3 ); // All entities have at least one of these values
115
+
116
+ // Should be able to find entities where ratings contains any of these values
117
+ List <NumericArrayTestData > ratingResults = entityStream
118
+ .of (NumericArrayTestData .class )
119
+ .filter (NumericArrayTestData$ .RATINGS .containsInt (2 , 7 ))
120
+ .collect (Collectors .toList ());
121
+ assertThat (ratingResults ).hasSize (3 ); // testData1 has 2, testData2 has 2, testData3 has 7
122
+ }
123
+
124
+ /**
125
+ * This test shows what currently happens when you try to use the existing in() method
126
+ * on NumericField with EntityStream - it doesn't work as expected for arrays.
127
+ */
128
+ @ Test
129
+ void testCurrentNumericFieldInMethodLimitation () {
130
+ // The current in() method on NumericField works for scalar matching, not array membership
131
+ // This is different from TagField.in() which works for array membership
132
+
133
+ // The current NumericField.in() method expects List<T> not individual values
134
+ // This shows the fundamental difference from TagField.in() which accepts varargs
135
+
136
+ // This would fail to compile: TestData$.MEASUREMENTS.in(2.5)
137
+ // because NumericField.in() expects List<Double>, not double
138
+
139
+ // NumericField.in() signature: in(List<Double> values)
140
+ // TagField.in() signature: in(String... values) or in(Object... values)
141
+
142
+ // The current NumericField.in() method would require the metamodel:
143
+ // List<NumericArrayTestData> results = entityStream
144
+ // .of(NumericArrayTestData.class)
145
+ // .filter(NumericArrayTestData$.MEASUREMENTS.in(Arrays.asList(2.5))) // Must pass as List
146
+ // .collect(Collectors.toList());
147
+
148
+ // Demonstrate the data exists but we can't query it effectively
149
+ assertThat (testData1 .getMeasurements ()).contains (2.5 );
150
+ assertThat (testData2 .getMeasurements ()).contains (2.5 );
151
+
152
+ // The issue: no easy way to find entities where numeric array contains any of multiple values
153
+
154
+ // But even if this worked, it doesn't give us "array contains any of these values" semantics
155
+ // It's checking if the field value equals the provided list, not membership
156
+ assertTrue (true , "Current NumericField.in() doesn't support array membership like TagField.in() does" );
157
+
158
+ // The key issue: NumericField.in() ≠ TagField.in() for array membership behavior
159
+ assertTrue (true , "NumericField.in() doesn't support array membership like TagField.in() does" );
160
+ }
161
+
162
+ /**
163
+ * This test demonstrates the exact scenario from GitHub issue #400.
164
+ * User wants to query: "Find all entities where numeric array contains any of these values"
165
+ */
166
+ @ Test
167
+ void testGitHubIssue400Scenario () {
168
+ // Issue #400 specifically asks for functionality like:
169
+ // field.containsLong(Long... values) similar to TagField.in()
170
+
171
+ // Verify test data setup
172
+ assertThat (testData1 .getCounts ()).contains (20L );
173
+ assertThat (testData2 .getCounts ()).contains (20L );
174
+ assertThat (testData3 .getCounts ()).contains (70L );
175
+
176
+ // This should now work with the new containsLong method:
177
+ List <NumericArrayTestData > results = entityStream
178
+ .of (NumericArrayTestData .class )
179
+ .filter (NumericArrayTestData$ .COUNTS .containsLong (20L , 70L ))
180
+ .collect (Collectors .toList ());
181
+
182
+ // Should find testData1 (has 20L), testData2 (has 20L), and testData3 (has 70L)
183
+ assertThat (results ).hasSize (3 );
184
+ assertThat (results ).contains (testData1 , testData2 , testData3 );
185
+ }
186
+
187
+ /**
188
+ * This test proves the issue exists by showing the compilation failure.
189
+ * When the feature is implemented, this test should be updated to verify the functionality works.
190
+ */
191
+ @ Test
192
+ void testCompilationFailureProvesIssueExists () {
193
+ // Verify test data has the expected values
194
+ assertThat (testData1 .getMeasurements ()).containsAnyOf (1.5 , 4.5 , 7.5 );
195
+ assertThat (testData1 .getCounts ()).containsAnyOf (10L , 40L , 70L );
196
+ assertThat (testData1 .getRatings ()).containsAnyOf (1 , 4 , 7 );
197
+
198
+ // Now these methods should work and compile successfully:
199
+
200
+ List <NumericArrayTestData > measurementResults = entityStream
201
+ .of (NumericArrayTestData .class )
202
+ .filter (NumericArrayTestData$ .MEASUREMENTS .containsDouble (1.5 , 4.5 , 7.5 ))
203
+ .collect (Collectors .toList ());
204
+
205
+ List <NumericArrayTestData > countResults = entityStream
206
+ .of (NumericArrayTestData .class )
207
+ .filter (NumericArrayTestData$ .COUNTS .containsLong (10L , 40L , 70L ))
208
+ .collect (Collectors .toList ());
209
+
210
+ List <NumericArrayTestData > ratingResults = entityStream
211
+ .of (NumericArrayTestData .class )
212
+ .filter (NumericArrayTestData$ .RATINGS .containsInt (1 , 4 , 7 ))
213
+ .collect (Collectors .toList ());
214
+
215
+ // Verify the methods work as expected
216
+ assertThat (measurementResults ).hasSize (3 ); // All entities have at least one of these measurements
217
+ assertThat (countResults ).hasSize (3 ); // All entities have at least one of these counts
218
+ assertThat (ratingResults ).hasSize (3 ); // All entities have at least one of these ratings
219
+ }
220
+ }
0 commit comments