diff --git a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByAnalyticsOperationSupport.java b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByAnalyticsOperationSupport.java index b46a81f53..b8481dcee 100644 --- a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByAnalyticsOperationSupport.java +++ b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByAnalyticsOperationSupport.java @@ -118,19 +118,27 @@ public Flux all() { } }).flatMapMany(ReactiveAnalyticsResult::rowsAsObject).flatMap(row -> { String id = ""; - long cas = 0; - if (row.getString(TemplateUtils.SELECT_ID) == null) { + Long cas = Long.valueOf(0); + if (row.getString(TemplateUtils.SELECT_ID) == null && row.getString(TemplateUtils.SELECT_ID_3x) == null) { return Flux.error(new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_ID + ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement)); } id = row.getString(TemplateUtils.SELECT_ID); - if (row.getLong(TemplateUtils.SELECT_CAS) == null) { + if (id == null) { + id = row.getString(TemplateUtils.SELECT_ID_3x); + row.removeKey(TemplateUtils.SELECT_ID_3x); + } + if (row.getLong(TemplateUtils.SELECT_CAS) == null && row.getLong(TemplateUtils.SELECT_CAS_3x) == null) { return Flux.error(new CouchbaseException("analytics query did not project " + TemplateUtils.SELECT_CAS + ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement)); } cas = row.getLong(TemplateUtils.SELECT_CAS); + if (cas == null) { + cas = row.getLong(TemplateUtils.SELECT_CAS_3x); + row.removeKey(TemplateUtils.SELECT_CAS_3x); + } row.removeKey(TemplateUtils.SELECT_ID); row.removeKey(TemplateUtils.SELECT_CAS); return support.decodeEntity(id, row.toString(), cas, returnType, null, null); diff --git a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java index cfa3e0f34..03ae5f0d6 100644 --- a/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java +++ b/src/main/java/org/springframework/data/couchbase/core/ReactiveFindByQueryOperationSupport.java @@ -90,7 +90,7 @@ static class ReactiveFindByQuerySupport implements ReactiveFindByQuery { public FindByQueryWithQuery matching(Query query) { QueryScanConsistency scanCons; if (query.getScanConsistency() != null) { // redundant, since buildQueryOptions() will use - // query.getScanConsistency() + // query.getScanConsistency() scanCons = query.getScanConsistency(); } else { scanCons = scanConsistency; @@ -185,20 +185,28 @@ public Flux all() { } }).flatMapMany(ReactiveQueryResult::rowsAsObject).flatMap(row -> { String id = ""; - long cas = 0; + Long cas = Long.valueOf(0); if (!query.isDistinct() && distinctFields == null) { - if (row.getString(TemplateUtils.SELECT_ID) == null) { + if (row.getString(TemplateUtils.SELECT_ID) == null && row.getString(TemplateUtils.SELECT_ID_3x) == null) { return Flux.error(new CouchbaseException( "query did not project " + TemplateUtils.SELECT_ID + ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement)); } id = row.getString(TemplateUtils.SELECT_ID); - if (row.getLong(TemplateUtils.SELECT_CAS) == null) { + if (id == null) { + id = row.getString(TemplateUtils.SELECT_ID_3x); + row.removeKey(TemplateUtils.SELECT_ID_3x); + } + if (row.getLong(TemplateUtils.SELECT_CAS) == null && row.getLong(TemplateUtils.SELECT_CAS_3x) == null) { return Flux.error(new CouchbaseException( "query did not project " + TemplateUtils.SELECT_CAS + ". Either use #{#n1ql.selectEntity} or project " + TemplateUtils.SELECT_ID + " and " + TemplateUtils.SELECT_CAS + " : " + statement)); } cas = row.getLong(TemplateUtils.SELECT_CAS); + if (cas == null) { + cas = row.getLong(TemplateUtils.SELECT_CAS_3x); + row.removeKey(TemplateUtils.SELECT_CAS_3x); + } row.removeKey(TemplateUtils.SELECT_ID); row.removeKey(TemplateUtils.SELECT_CAS); } diff --git a/src/main/java/org/springframework/data/couchbase/core/support/TemplateUtils.java b/src/main/java/org/springframework/data/couchbase/core/support/TemplateUtils.java index 2d92763d1..65cc4986a 100644 --- a/src/main/java/org/springframework/data/couchbase/core/support/TemplateUtils.java +++ b/src/main/java/org/springframework/data/couchbase/core/support/TemplateUtils.java @@ -32,6 +32,8 @@ public class TemplateUtils { public static final String SELECT_ID = "__id"; public static final String SELECT_CAS = "__cas"; + public static final String SELECT_ID_3x = "_ID"; + public static final String SELECT_CAS_3x = "_CAS"; public static final String SELECT_COUNT = CountFragment.COUNT_ALIAS; private static PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator(); diff --git a/src/test/java/org/springframework/data/couchbase/domain/AirlineRepository.java b/src/test/java/org/springframework/data/couchbase/domain/AirlineRepository.java index 04706eb35..ffbf244e9 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/AirlineRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/AirlineRepository.java @@ -34,6 +34,9 @@ public interface AirlineRepository extends CouchbaseRepository, QuerydslPredicateExecutor, DynamicProxyable { @Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and (name = $1)") - List getByName(@Param("airline_name") String airlineName); + List getByName(@Param("airline_name") String airlineName); + + @Query("select meta().id as _ID, meta().cas as _CAS, #{#n1ql.bucket}.* from #{#n1ql.bucket} where #{#n1ql.filter} and (name = $1)") + List getByName_3x(@Param("airline_name") String airlineName); } diff --git a/src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java b/src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java index b22d31267..b14b712d8 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreatorTests.java @@ -116,6 +116,39 @@ queryMethod, converter, config().bucketname(), new SpelExpressionParser(), } } + @Test + @IgnoreWhen(missesCapabilities = Capabilities.QUERY, clusterTypes = ClusterType.MOCKED) + void findUsingStringNq1l_3x_projection_id_cas() throws Exception { + Airline airline = new Airline(UUID.randomUUID().toString(), "Continental", "USA"); + try { + Airline modified = couchbaseTemplate.upsertById(Airline.class).one(airline); + + String input = "getByName_3x"; + Method method = AirlineRepository.class.getMethod(input, String.class); + + CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, + new DefaultRepositoryMetadata(AirlineRepository.class), new SpelAwareProxyProjectionFactory(), + converter.getMappingContext()); + + StringN1qlQueryCreator creator = new StringN1qlQueryCreator(getAccessor(getParameters(method), "Continental"), + queryMethod, converter, config().bucketname(), new SpelExpressionParser(), + QueryMethodEvaluationContextProvider.DEFAULT, namedQueries); + + Query query = creator.createQuery(); + + ExecutableFindByQuery q = (ExecutableFindByQuery) couchbaseTemplate.findByQuery(Airline.class) + .withConsistency(QueryScanConsistency.REQUEST_PLUS).matching(query); + + Optional al = q.one(); + assertEquals(airline.toString(), al.get().toString()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + couchbaseTemplate.removeById().one(airline.getId()); + } + } + private ParameterAccessor getAccessor(Parameters params, Object... values) { return new ParametersParameterAccessor(params, values); }