Skip to content

Commit 9b848f6

Browse files
authored
Specific message for string queries that do not project __id and __cas.
com.couchbase.client.core.error.CouchbaseException: query did not project __id. Either use #{#n1ql.selectEntity} or project __id and __cas : SELECT __cas, * from `b406ab45-ef95-441f-a318-76b8e8af2d76` where iata = $1 Closes #1097. Original pull request: #1114. Co-authored-by: mikereiche <[email protected]>
1 parent 37587a1 commit 9b848f6

File tree

5 files changed

+59
-8
lines changed

5 files changed

+59
-8
lines changed

src/main/java/org/springframework/data/couchbase/core/ReactiveFindByAnalyticsOperationSupport.java

+18-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import reactor.core.publisher.Mono;
2020

2121
import org.springframework.data.couchbase.core.query.AnalyticsQuery;
22+
import org.springframework.data.couchbase.core.support.TemplateUtils;
2223

24+
import com.couchbase.client.core.error.CouchbaseException;
2325
import com.couchbase.client.java.analytics.AnalyticsOptions;
2426
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
2527
import com.couchbase.client.java.analytics.ReactiveAnalyticsResult;
@@ -92,10 +94,22 @@ public Flux<T> all() {
9294
return throwable;
9395
}
9496
}).flatMapMany(ReactiveAnalyticsResult::rowsAsObject).map(row -> {
95-
String id = row.getString("__id");
96-
long cas = row.getLong("__cas");
97-
row.removeKey("__id");
98-
row.removeKey("__cas");
97+
String id = "";
98+
long cas = 0;
99+
if (row.getString(TemplateUtils.SELECT_ID) == null) {
100+
throw new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_ID
101+
+ ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and "
102+
+ TemplateUtils.SELECT_CAS + " : " + statement);
103+
}
104+
id = row.getString(TemplateUtils.SELECT_ID);
105+
if (row.getLong(TemplateUtils.SELECT_CAS) == null) {
106+
throw new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_CAS
107+
+ ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and "
108+
+ TemplateUtils.SELECT_CAS + " : " + statement);
109+
}
110+
cas = row.getLong(TemplateUtils.SELECT_CAS);
111+
row.removeKey(TemplateUtils.SELECT_ID);
112+
row.removeKey(TemplateUtils.SELECT_CAS);
99113
return template.support().decodeEntity(id, row.toString(), cas, domainType);
100114
});
101115
});

src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.data.couchbase.core.support.TemplateUtils;
2323
import org.springframework.util.Assert;
2424

25+
import com.couchbase.client.core.error.CouchbaseException;
2526
import com.couchbase.client.java.query.QueryScanConsistency;
2627
import com.couchbase.client.java.query.ReactiveQueryResult;
2728

@@ -147,7 +148,17 @@ public Flux<T> all() {
147148
String id = "";
148149
long cas = 0;
149150
if (distinctFields == null) {
151+
if (row.getString(TemplateUtils.SELECT_ID) == null) {
152+
throw new CouchbaseException(
153+
"query did not project " + TemplateUtils.SELECT_ID + ". Either use #{#n1ql.selectEntity} or project "
154+
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement);
155+
}
150156
id = row.getString(TemplateUtils.SELECT_ID);
157+
if (row.getLong(TemplateUtils.SELECT_CAS) == null) {
158+
throw new CouchbaseException(
159+
"query did not project " + TemplateUtils.SELECT_CAS + ". Either use #{#n1ql.selectEntity} or project "
160+
+ TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement);
161+
}
151162
cas = row.getLong(TemplateUtils.SELECT_CAS);
152163
row.removeKey(TemplateUtils.SELECT_ID);
153164
row.removeKey(TemplateUtils.SELECT_CAS);

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

+8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ public interface AirportRepository extends PagingAndSortingRepository<Airport, S
5757
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
5858
List<Airport> getAllByIata(String iata);
5959

60+
@Query("SELECT __cas, * from `#{#n1ql.bucket}` where iata = $1")
61+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
62+
List<Airport> getAllByIataNoID(String iata);
63+
64+
@Query("SELECT __id, * from `#{#n1ql.bucket}` where iata = $1")
65+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
66+
List<Airport> getAllByIataNoCAS(String iata);
67+
6068
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
6169
long countByIataIn(String... iata);
6270

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.springframework.data.couchbase.domain;
22

33
public enum Iata {
4-
vie,
4+
vie, // must be lower-case to match "vie" as airport.iata is always specified in lowercase
55
xxx
66
}

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

+21-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.assertj.core.api.Assertions.assertThat;
2121
import static org.junit.jupiter.api.Assertions.assertEquals;
2222
import static org.junit.jupiter.api.Assertions.assertFalse;
23+
import static org.junit.jupiter.api.Assertions.assertNotNull;
2324
import static org.junit.jupiter.api.Assertions.assertThrows;
2425
import static org.junit.jupiter.api.Assertions.assertTrue;
2526

@@ -34,7 +35,6 @@
3435
import java.util.concurrent.Future;
3536
import java.util.stream.Collectors;
3637

37-
import com.couchbase.client.java.query.QueryScanConsistency;
3838
import org.junit.jupiter.api.BeforeEach;
3939
import org.junit.jupiter.api.Test;
4040
import org.springframework.beans.factory.annotation.Autowired;
@@ -66,7 +66,9 @@
6666
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
6767
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
6868

69+
import com.couchbase.client.core.error.CouchbaseException;
6970
import com.couchbase.client.core.error.IndexExistsException;
71+
import com.couchbase.client.java.query.QueryScanConsistency;
7072

7173
/**
7274
* Repository tests
@@ -175,11 +177,13 @@ void findByEnum() {
175177
vie = new Airport("airports::vie", "vie", "loww");
176178
vie = airportRepository.save(vie);
177179
Airport airport2 = airportRepository.findByIata(Iata.vie);
180+
assertNotNull(airport2, "should have found "+vie);
178181
assertEquals(airport2.getId(), vie.getId());
179182
} finally {
180183
airportRepository.delete(vie);
181184
}
182185
}
186+
183187
@Test
184188
public void testCas() {
185189
User user = new User("1", "Dave", "Wilson");
@@ -271,6 +275,19 @@ void threadSafeParametersTest() throws Exception {
271275
}
272276
}
273277

278+
@Test
279+
void stringQueryTest() throws Exception {
280+
Airport airport = new Airport("airports::vie", "vie", "lowx");
281+
try {
282+
airportRepository.save(airport);
283+
airportRepository.getAllByIata("vie").get(0); // gets at least one with no exception
284+
assertThrows(CouchbaseException.class, () -> airportRepository.getAllByIataNoID("vie"));
285+
assertThrows(CouchbaseException.class, () -> airportRepository.getAllByIataNoCAS("vie"));
286+
} finally {
287+
airportRepository.deleteById(airport.getId());
288+
}
289+
}
290+
274291
@Test
275292
void threadSafeStringParametersTest() throws Exception {
276293
String[] iatas = { "JFK", "IAD", "SFO", "SJC", "SEA", "LAX", "PHX" };
@@ -332,14 +349,15 @@ void deleteAllById() {
332349
void couchbaseRepositoryQuery() throws Exception {
333350
User user = new User("1", "Dave", "Wilson");
334351
userRepository.save(user);
335-
couchbaseTemplate.findByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS).matching(QueryCriteria.where("firstname").is("Dave").and("`1`").is("`1`")).all();
352+
couchbaseTemplate.findByQuery(User.class).withConsistency(QueryScanConsistency.REQUEST_PLUS)
353+
.matching(QueryCriteria.where("firstname").is("Dave").and("`1`").is("`1`")).all();
336354
String input = "findByFirstname";
337355
Method method = UserRepository.class.getMethod(input, String.class);
338356
CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method,
339357
new DefaultRepositoryMetadata(UserRepository.class), new SpelAwareProxyProjectionFactory(),
340358
couchbaseTemplate.getConverter().getMappingContext());
341359
CouchbaseRepositoryQuery query = new CouchbaseRepositoryQuery(couchbaseTemplate, queryMethod, null);
342-
List<User> users = (List<User>)query.execute(new String[] { "Dave" });
360+
List<User> users = (List<User>) query.execute(new String[] { "Dave" });
343361
assertEquals(user, users.get(0));
344362
}
345363

0 commit comments

Comments
 (0)