Collection support for predicates on meta fields. (#1338)

When a derived query is being created and there is a predicate on
a meta-field ( meta().id, cas, expiry), translate that field
(i.e. id -> meta().id) *without* the bucket or collection name,
as it might apply to a collelction which we do not know yet
(for instance, if there is a withCollection() specified)..
This is fine, because in a derived query, meta() without the
bucket or collection name is unambigous.
This commit is contained in:
Michael Reiche
2022-02-14 09:09:09 -08:00
committed by Michael Reiche
parent 9048c7ca82
commit 6ebb0dd20e
4 changed files with 36 additions and 11 deletions

View File

@@ -76,7 +76,7 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
protected QueryCriteria create(final Part part, final Iterator<Object> iterator) { protected QueryCriteria create(final Part part, final Iterator<Object> iterator) {
PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty()); PersistentPropertyPath<CouchbasePersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
CouchbasePersistentProperty property = path.getLeafProperty(); CouchbasePersistentProperty property = path.getLeafProperty();
return from(part, property, where(addMetaIfRequired(bucketName, path, property, entity)), iterator); return from(part, property, where(addMetaIfRequired(null, path, property, entity)), iterator);
} }
@Override @Override
@@ -187,17 +187,28 @@ public class N1qlQueryCreator extends AbstractQueryCreator<Query, QueryCriteria>
} }
} }
/**
* Translate meta-fields to META(bucketName).id, cas, expiry.<br>
* If bucketName is null, META().id etc, <br>
* If not a meta-field, just create the corresponding path
*
* @param bucketName
* @param persistentPropertyPath
* @param property
* @param entity
* @return N1QLExpression
*/
public static N1QLExpression addMetaIfRequired(String bucketName, public static N1QLExpression addMetaIfRequired(String bucketName,
final PersistentPropertyPath<CouchbasePersistentProperty> persistentPropertyPath, final PersistentPropertyPath<CouchbasePersistentProperty> persistentPropertyPath,
final CouchbasePersistentProperty property, final PersistentEntity entity) { final CouchbasePersistentProperty property, final PersistentEntity entity) {
if (entity != null && property == entity.getIdProperty()) { if (entity != null && property == entity.getIdProperty()) {
return path(meta(i(bucketName)), i(META_ID_PROPERTY)); return path(meta(bucketName != null ? i(bucketName) : x("")), i(META_ID_PROPERTY));
} }
if (property == entity.getVersionProperty()) { if (property == entity.getVersionProperty()) {
return path(meta(i(bucketName)), i(META_CAS_PROPERTY)); return path(meta(bucketName != null ? i(bucketName) : x("")), i(META_CAS_PROPERTY));
} }
if (property.isExpirationProperty()) { if (property.isExpirationProperty()) {
return path(meta(i(bucketName)), i(META_EXPIRATION_PROPERTY)); return path(meta(bucketName != null ? i(bucketName) : x("")), i(META_EXPIRATION_PROPERTY));
} }
return x(persistentPropertyPath.toDotPath(cvtr)); return x(persistentPropertyPath.toDotPath(cvtr));
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors * Copyright 2012-2022 the original author or authors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -40,10 +40,13 @@ public interface UserColRepository extends CouchbaseRepository<UserCol, String>,
// CouchbaseRepositoryQueryCollectionIntegrationTests.testScopeCollectionAnnotationSwap() relies on this // CouchbaseRepositoryQueryCollectionIntegrationTests.testScopeCollectionAnnotationSwap() relies on this
// being commented out. // being commented out.
//<S extends UserCol> S save(S var1); // <S extends UserCol> S save(S var1);
List<UserCol> findByFirstname(String firstname); List<UserCol> findByFirstname(String firstname);
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
UserCol getById(String id);
List<UserCol> findByFirstnameIn(String... firstnames); List<UserCol> findByFirstnameIn(String... firstnames);
List<UserCol> findByFirstnameIn(JsonArray firstnames); List<UserCol> findByFirstnameIn(JsonArray firstnames);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2021 the original author or authors. * Copyright 2017-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -91,6 +91,16 @@ public class CouchbaseRepositoryQueryCollectionIntegrationTests extends Collecti
super.afterEach(); super.afterEach();
} }
@Test
void findByKey() {
UserCol userCol = new UserCol("101", "userColFirst", "userColLast");
userColRepository.save(userCol);
UserCol found = userColRepository.getById(userCol.getId());
System.err.println("found: " + found);
assertEquals(userCol, found);
userColRepository.delete(found);
}
@Test @Test
public void myTest() { public void myTest() {

View File

@@ -189,8 +189,8 @@ class N1qlQueryCreatorTests {
converter, bucketName); converter, bucketName);
Query query = creator.createQuery(); Query query = creator.createQuery();
assertEquals(query.export(), assertEquals(" WHERE " + where(x("META().`id`")).isNotNull().and(i("firstname")).is("Oliver").export(),
" WHERE " + where(x("META(`" + bucketName + "`).`id`")).isNotNull().and(i("firstname")).is("Oliver").export()); query.export());
} }
@Test // https://github.com/spring-projects/spring-data-couchbase/issues/1072 @Test // https://github.com/spring-projects/spring-data-couchbase/issues/1072
@@ -204,8 +204,9 @@ class N1qlQueryCreatorTests {
getAccessor(getParameters(method), 1611287177404088320L, "Oliver"), queryMethod, converter, bucketName); getAccessor(getParameters(method), 1611287177404088320L, "Oliver"), queryMethod, converter, bucketName);
Query query = creator.createQuery(); Query query = creator.createQuery();
assertEquals(query.export(), " WHERE " + where(x("META(`" + bucketName + "`).`cas`")).is(1611287177404088320L) assertEquals(
.and(i("firstname")).is("Oliver").export()); " WHERE " + where(x("META().`cas`")).is(1611287177404088320L).and(i("firstname")).is("Oliver").export(),
query.export());
} }
private ParameterAccessor getAccessor(Parameters<?, ?> params, Object... values) { private ParameterAccessor getAccessor(Parameters<?, ?> params, Object... values) {