Skip to content

Commit 02bc0b3

Browse files
authored
Fix regression in IN operator. (#1309)
The regression occurred in changes for https://issues.couchbase.com/browse/MB-26606. Closes #1308.
1 parent 29bf1fb commit 02bc0b3

File tree

5 files changed

+76
-25
lines changed

5 files changed

+76
-25
lines changed

src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java

+16-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.LinkedList;
2525
import java.util.List;
2626

27+
import com.couchbase.client.core.error.CouchbaseException;
2728
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2829
import org.springframework.lang.Nullable;
2930
import org.springframework.util.CollectionUtils;
@@ -281,30 +282,34 @@ public QueryCriteria between(@Nullable Object o1, @Nullable Object o2) {
281282

282283
public QueryCriteria in(@Nullable Object... o) {
283284
operator = "IN";
284-
format = "%1$s in ( ";
285+
format = "%1$s in %3$s";
286+
value = new Object[1];
285287
if (o.length > 0) {
286288
if (o[0] instanceof JsonArray || o[0] instanceof List || o[0] instanceof Object[]) {
287289
if (o.length != 1) {
288290
throw new RuntimeException("IN cannot take multiple lists");
289291
}
290292
if (o[0] instanceof Object[]) {
291-
value = (Object[]) o[0];
293+
value[0] = o[0];
292294
} else if (o[0] instanceof JsonArray) {
293295
JsonArray ja = ((JsonArray) o[0]);
294-
value = ja.toList().toArray();
296+
value[0] = ja.toList().toArray();
295297
} else if (o[0] instanceof List) {
296298
List l = ((List) o[0]);
297-
value = l.toArray();
299+
value[0] = l.toArray();
298300
}
299301
} else {
300-
value = o;
301-
}
302-
for (int i = 0; i < value.length; i++) {
303-
if (i > 0)
304-
format = format + ", ";
305-
format = format + "%" + (i + 3) + "$s";
302+
// N1qlQueryCreatorTests.queryParametersArray()
303+
// Query expected = (new Query()).addCriteria(where(i("firstname")).in("Oliver", "Charles"));
304+
if (o instanceof Object[]) {
305+
value[0] = o;
306+
} else {
307+
// see QueryCriteriaTests.testNestedNotIn() - if arg to notIn is not cast to Object
308+
// notIn((Object) new String[] { "Alabama", "Florida" }));
309+
throw new CouchbaseException("unhandled parameters "+o);
310+
}
306311
}
307-
format = format + " )";
312+
308313
}
309314
return this;
310315
}

src/test/java/org/springframework/data/couchbase/core/query/QueryCriteriaTests.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ void testNestedOrCriteria() {
8484
@Test
8585
void testNestedNotIn() {
8686
QueryCriteria c = where(i("name")).is("Bubba").or(where(i("age")).gt(12).or(i("country")).is("Austria"))
87-
.and(where(i("state")).notIn(new String[] { "Alabama", "Florida" }));
87+
.and(where(i("state")).notIn((Object) new String[] { "Alabama", "Florida" }));
8888
JsonArray parameters = JsonArray.create();
89-
assertEquals("`name` = $1 or (`age` > $2 or `country` = $3) and (not( (`state` in ( $4, $5 )) ))",
89+
assertEquals("`name` = $1 or (`age` > $2 or `country` = $3) and (not( (`state` in $4) ))",
9090
c.export(new int[1], parameters, null));
9191
}
9292

@@ -225,22 +225,22 @@ void testBetween() {
225225
@Test
226226
void testIn() {
227227
String[] args = new String[] { "gump", "davis" };
228-
QueryCriteria c = where(i("name")).in((Object) args);
229-
assertEquals("`name` in ( \"gump\", \"davis\" )", c.export());
228+
QueryCriteria c = where(i("name")).in((Object) args); // the first arg is an array
229+
assertEquals("`name` in [\"gump\",\"davis\"]", c.export());
230230
JsonArray parameters = JsonArray.create();
231-
assertEquals("`name` in ( $1, $2 )", c.export(new int[1], parameters, null));
232-
assertEquals(arrayToString(args), parameters.toString());
231+
assertEquals("`name` in $1", c.export(new int[1], parameters, null));
232+
assertEquals(arrayToString(args), parameters.get(0).toString());
233233
}
234234

235235
@Test
236236
void testNotIn() {
237237
String[] args = new String[] { "gump", "davis" };
238-
QueryCriteria c = where(i("name")).notIn((Object) args);
239-
assertEquals("not( (`name` in ( \"gump\", \"davis\" )) )", c.export());
238+
QueryCriteria c = where(i("name")).notIn((Object) args); // the first arg is an array
239+
assertEquals("not( (`name` in [\"gump\",\"davis\"]) )", c.export());
240240
// this tests creating parameters from the args.
241241
JsonArray parameters = JsonArray.create();
242-
assertEquals("not( (`name` in ( $1, $2 )) )", c.export(new int[1], parameters, null));
243-
assertEquals(arrayToString(args), parameters.toString());
242+
assertEquals("not( (`name` in $1) )", c.export(new int[1], parameters, null));
243+
assertEquals(arrayToString(args), parameters.get(0).toString());
244244
}
245245

246246
@Test

src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.springframework.stereotype.Repository;
4444

4545
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
46+
import com.couchbase.client.java.json.JsonArray;
4647
import com.couchbase.client.java.query.QueryScanConsistency;
4748

4849
/**
@@ -60,6 +61,10 @@
6061
// @ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
6162
public interface AirportRepository extends CouchbaseRepository<Airport, String>, DynamicProxyable<AirportRepository> {
6263

64+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
65+
List<Airport> findByIataInAndIcaoIn(java.util.Collection<String> size, java.util.Collection<String> color,
66+
Pageable pageable);
67+
6368
@Override
6469
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
6570
List<Airport> findAll();
@@ -81,7 +86,10 @@ public interface AirportRepository extends CouchbaseRepository<Airport, String>,
8186
Airport findByIataIn(java.util.Collection<Iata> iatas);
8287

8388
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
84-
Airport findByIataIn(Iata[] iata);
89+
Airport findByIataIn(Iata... iatas);
90+
91+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
92+
Airport findByIataIn(JsonArray iatas);
8593

8694
// NOT_BOUNDED to test ScanConsistency
8795
// @ScanConsistency(query = QueryScanConsistency.NOT_BOUNDED)

src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java

+38
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.time.Duration;
3636
import java.util.ArrayList;
3737
import java.util.Arrays;
38+
import java.util.LinkedList;
3839
import java.util.List;
3940
import java.util.Locale;
4041
import java.util.Optional;
@@ -237,6 +238,30 @@ void findByInjection() {
237238

238239
}
239240

241+
@Test
242+
void issue1304CollectionParameter() {
243+
Airport vie = null;
244+
try {
245+
vie = new Airport("airports::vie", "vie", "low5");
246+
airportRepository.save(vie);
247+
java.util.Collection<String> iatas = new LinkedList<String>();
248+
iatas.add(vie.getIata());
249+
java.util.Collection<String> icaos = new LinkedList<String>();
250+
icaos.add(vie.getIcao());
251+
icaos.add("blue");
252+
PageRequest pageable = PageRequest.of( 0, 1, Sort.by("iata"));
253+
List<Airport>airports = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
254+
assertEquals(1, airports.size());
255+
256+
List<Airport>airports2 = airportRepository.findByIataInAndIcaoIn(iatas, icaos, pageable);
257+
assertEquals(1, airports2.size());
258+
259+
} finally {
260+
airportRepository.delete(vie);
261+
}
262+
263+
}
264+
240265
@Test
241266
void findBySimpleProperty() {
242267
Airport vie = null;
@@ -369,9 +394,11 @@ void findByTypeAlias() {
369394
@Test
370395
void findByEnum() {
371396
Airport vie = null;
397+
Airport zzz = null;
372398
try {
373399
vie = new Airport("airports::vie", "vie", "loww");
374400
vie = airportRepository.save(vie);
401+
zzz = airportRepository.save(vie.withId("airports::zzz").withIata("zzz"));
375402
Airport airport2 = airportRepository.findByIata(Iata.vie);
376403
assertNotNull(airport2, "should have found " + vie);
377404
assertEquals(airport2.getId(), vie.getId());
@@ -386,8 +413,19 @@ void findByEnum() {
386413
assertNotNull(airport4, "should have found " + vie);
387414
assertEquals(airport4.getId(), vie.getId());
388415

416+
Airport airport5 = airportRepository.findByIataIn(Iata.vie, Iata.xxx);
417+
assertNotNull(airport5, "should have found " + vie);
418+
assertEquals(airport5.getId(), vie.getId());
419+
420+
JsonArray iatasJson = JsonArray.ja();
421+
iatasJson.add(Iata.vie.toString());
422+
iatasJson.add(Iata.xxx.toString());
423+
Airport airport6 = airportRepository.findByIataIn(iatasJson);
424+
assertNotNull(airport6, "should have found " + vie);
425+
assertEquals(airport6.getId(), vie.getId());
389426
} finally {
390427
airportRepository.delete(vie);
428+
airportRepository.delete(zzz);
391429
}
392430
}
393431

src/test/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreatorTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void queryParametersArray() throws Exception {
109109
Query query = creator.createQuery();
110110

111111
// Query expected = (new Query()).addCriteria(where("firstname").in("Oliver", "Charles"));
112-
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
112+
assertEquals(" WHERE `firstname` in $1", query.export(new int[1]));
113113
JsonObject expectedOptions = JsonObject.create();
114114
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
115115
JsonObject actualOptions = JsonObject.create();
@@ -132,7 +132,7 @@ void queryParametersJsonArray() throws Exception {
132132
Query query = creator.createQuery();
133133

134134
Query expected = (new Query()).addCriteria(where(i("firstname")).in("Oliver", "Charles"));
135-
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
135+
assertEquals(" WHERE `firstname` in $1", query.export(new int[1]));
136136
JsonObject expectedOptions = JsonObject.create();
137137
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
138138
JsonObject actualOptions = JsonObject.create();
@@ -156,7 +156,7 @@ void queryParametersList() throws Exception {
156156

157157
Query expected = (new Query()).addCriteria(where(i("firstname")).in("Oliver", "Charles"));
158158

159-
assertEquals(" WHERE `firstname` in ( $1, $2 )", query.export(new int[1]));
159+
assertEquals(" WHERE `firstname` in $1", query.export(new int[1]));
160160
JsonObject expectedOptions = JsonObject.create();
161161
expected.buildQueryOptions(null, null).build().injectParams(expectedOptions);
162162
JsonObject actualOptions = JsonObject.create();

0 commit comments

Comments
 (0)