From 7c431d640ffd5239491bc3222bb9efedc1b77258 Mon Sep 17 00:00:00 2001 From: Michael Reiche <48999328+mikereiche@users.noreply.github.com> Date: Mon, 12 Oct 2020 13:22:19 -0700 Subject: [PATCH] DATACOUCH-583 - Nested properties in queries not working. (#270) The complete property path was being quoted instead of the individual components. ie. `address.street` instead of `address`.`street` Also fixed another issue - changed the maybeQuote() method for property names to correctly look for back-tics instead of double quotes and changed the name accordingly. Co-authored-by: mikereiche --- .../couchbase/core/query/QueryCriteria.java | 6 +++--- .../repository/query/N1qlQueryCreator.java | 7 ++++++- .../couchbase/domain/PersonRepository.java | 6 +++++- ...chbaseRepositoryQueryIntegrationTests.java | 21 +++++++++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java b/src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java index 022a6fa3..df4f6d3a 100644 --- a/src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java +++ b/src/main/java/org/springframework/data/couchbase/core/query/QueryCriteria.java @@ -343,7 +343,7 @@ public class QueryCriteria implements QueryCriteriaDefinition { */ private StringBuilder exportSingle(StringBuilder sb, int[] paramIndexPtr, JsonValue parameters, CouchbaseConverter converter) { - String fieldName = maybeQuote(key); + String fieldName = maybeBackTic(key); int valueLen = value == null ? 0 : value.length; Object[] v = new Object[valueLen + 2]; v[0] = fieldName; @@ -445,8 +445,8 @@ public class QueryCriteria implements QueryCriteriaDefinition { posValues.add(ja); } - private String maybeQuote(String value) { - if (value == null || (value.startsWith("\"") && value.endsWith("\""))) { + private String maybeBackTic(String value) { + if (value == null || (value.startsWith("`") && value.endsWith("`"))) { return value; } else { return "`" + value + "`"; diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java index 44ba7774..a10ac154 100644 --- a/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java +++ b/src/main/java/org/springframework/data/couchbase/repository/query/N1qlQueryCreator.java @@ -19,6 +19,7 @@ import static org.springframework.data.couchbase.core.query.QueryCriteria.*; import java.util.Iterator; +import org.springframework.core.convert.converter.Converter; import org.springframework.data.couchbase.core.convert.CouchbaseConverter; import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty; import org.springframework.data.couchbase.core.query.Query; @@ -56,9 +57,13 @@ public class N1qlQueryCreator extends AbstractQueryCreator protected QueryCriteria create(final Part part, final Iterator iterator) { PersistentPropertyPath path = context.getPersistentPropertyPath(part.getProperty()); CouchbasePersistentProperty property = path.getLeafProperty(); - return from(part, property, where(path.toDotPath()), iterator); + return from(part, property, where(path.toDotPath(cvtr)), iterator); } + static Converter cvtr = ( + source) -> new StringBuilder(source.getName().length() + 2).append('`').append(source.getName()).append('`') + .toString(); + @Override protected QueryCriteria and(final Part part, final QueryCriteria base, final Iterator iterator) { if (base == null) { diff --git a/src/test/java/org/springframework/data/couchbase/domain/PersonRepository.java b/src/test/java/org/springframework/data/couchbase/domain/PersonRepository.java index a621c7fc..b5dafc15 100644 --- a/src/test/java/org/springframework/data/couchbase/domain/PersonRepository.java +++ b/src/test/java/org/springframework/data/couchbase/domain/PersonRepository.java @@ -15,7 +15,9 @@ */ package org.springframework.data.couchbase.domain; +import com.couchbase.client.java.query.QueryScanConsistency; import org.springframework.data.couchbase.repository.Query; +import org.springframework.data.couchbase.repository.ScanConsistency; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; @@ -105,4 +107,6 @@ public interface PersonRepository extends CrudRepository { void deleteAll(); -} \ No newline at end of file + @ScanConsistency(query=QueryScanConsistency.REQUEST_PLUS) + List findByAddressStreet(String street); +} diff --git a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java index 5e0fa218..2debef14 100644 --- a/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java @@ -33,8 +33,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.data.couchbase.CouchbaseClientFactory; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; +import org.springframework.data.couchbase.domain.Address; import org.springframework.data.couchbase.domain.Airport; import org.springframework.data.couchbase.domain.AirportRepository; +import org.springframework.data.couchbase.domain.Person; +import org.springframework.data.couchbase.domain.PersonRepository; import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; import org.springframework.data.couchbase.util.Capabilities; import org.springframework.data.couchbase.util.ClusterAwareIntegrationTests; @@ -82,6 +85,24 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr } } + @Autowired PersonRepository personRepository; + + @Test + void nestedFind() { + Person person = null; + try { + person = new Person(1, "first", "last"); + Address address = new Address(); + address.setStreet("Maple"); + person.setAddress(address); + personRepository.save(person); + List persons = personRepository.findByAddressStreet("Maple"); + assertEquals(1, persons.size()); + } finally { + personRepository.deleteById(person.getId().toString()); + } + } + // "1\" or name=name or name=\"1") @Test void findByInjection() {