Check for _ID and _CAS as well as __id and __cas being projected from query and analytics. (#1390)

Closes #1389.
This commit is contained in:
Michael Reiche
2022-04-14 07:52:25 -07:00
committed by Michael Reiche
parent baf198c868
commit 9fe8472b37
5 changed files with 62 additions and 8 deletions

View File

@@ -118,19 +118,27 @@ public class ReactiveFindByAnalyticsOperationSupport implements ReactiveFindByAn
}
}).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);

View File

@@ -90,7 +90,7 @@ public class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
public FindByQueryWithQuery<T> 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 class ReactiveFindByQueryOperationSupport implements ReactiveFindByQueryO
}
}).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);
}

View File

@@ -32,6 +32,8 @@ import org.springframework.data.couchbase.repository.query.CountFragment;
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();

View File

@@ -33,6 +33,9 @@ public interface AirlineRepository extends PagingAndSortingRepository<Airline, S
QuerydslPredicateExecutor<Airline>, DynamicProxyable<AirlineRepository> {
@Query("#{#n1ql.selectEntity} where #{#n1ql.filter} and (name = $1)")
List<User> getByName(@Param("airline_name") String airlineName);
List<Airline> 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<Airline> getByName_3x(@Param("airline_name") String airlineName);
}

View File

@@ -116,6 +116,39 @@ class StringN1qlQueryCreatorTests extends ClusterAwareIntegrationTests {
}
}
@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<Airline> 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);
}