DATACOUCH-246 - Projections support for query derivation.

Used the result processor projecting information to just fetch the selected fields and again to post process results to projection object/interfaces.

Added test for projection using DTO.

Original pull request: #122.
This commit is contained in:
Subhashni Balakrishnan
2016-09-23 15:39:59 -07:00
committed by Oliver Gierke
parent c8324caf7f
commit ce356f827f
12 changed files with 310 additions and 35 deletions

View File

@@ -24,6 +24,7 @@ import com.couchbase.client.java.repository.annotation.Field;
* Test class for persisting and loading from {@link CouchbaseTemplate}.
*
* @author Michael Nitschinger
* @author Subhashni Balakrishnan
*/
public class Beer {
@@ -35,13 +36,19 @@ public class Beer {
@Field("is_active")
private boolean active = true;
public Beer(String id) {
@Field("desc")
private String description;
public Beer(String id, String name, Boolean active, String description) {
this.id = id;
this.name = name;
this.active = active;
this.description = description;
}
@Override
public String toString() {
return "Beer [id=" + id + ", name=" + name + ", active=" + active + "]";
return "Beer [id=" + id + ", name=" + name + ", active=" + active + ", description=" + description + "]";
}
public Beer setName(String name) {
@@ -62,6 +69,15 @@ public class Beer {
return active;
}
public Beer setDescription(String description) {
this.description = description;
return this;
}
public String getDescription() {
return description;
}
public String getId() {
return id;
}

View File

@@ -0,0 +1,34 @@
package org.springframework.data.couchbase.core;
import com.couchbase.client.java.repository.annotation.Field;
/**
* Test DTO for projecting from {@link CouchbaseTemplate}.
*
* @author Subhashni Balakrishnan
*/
public class BeerDTO{
private String name;
@Field("desc")
private String description;
public BeerDTO(String name, String description) {
this.name = name;
this.description = description;
}
public BeerDTO setName(String name) {
this.name = name;
return this;
}
public String getName() { return name; }
public BeerDTO setDescription(String description) {
this.description = description;
return this;
}
public String getDescription() { return description; }
}

View File

@@ -0,0 +1,10 @@
package org.springframework.data.couchbase.core;
/**
* Test interface for projecting data from {@link CouchbaseTemplate}.
*
* @author Subhashni Balakrishnan
*/
public interface BeerProjection {
String getDescription();
}

View File

@@ -6,10 +6,16 @@ import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
import org.springframework.data.couchbase.core.BeerDTO;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.mapping.*;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.Beer;
import org.springframework.data.couchbase.core.BeerProjection;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
@@ -18,10 +24,10 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.EntityMetadata;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -30,6 +36,7 @@ import org.springframework.data.repository.query.ParameterAccessor;
import com.couchbase.client.java.CouchbaseBucket;
import com.couchbase.client.java.query.Statement;
import org.springframework.data.repository.query.ResultProcessor;
public class PartTreeN1qBasedQueryTest {
@@ -117,12 +124,79 @@ public class PartTreeN1qBasedQueryTest {
}
@Test
public void testProjectionInterface() throws Exception {
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
CouchbaseBucket couchbaseBucket = mock(CouchbaseBucket.class);
CouchbaseConverter couchbaseConverter = mock(CouchbaseConverter.class);
EntityMetadata entityInformation = mock(EntityMetadata.class);
ParameterAccessor accessor = mock(ParameterAccessor.class);
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
factory.createProjection(BeerProjection.class);
MappingContext mappingContext = new CouchbaseMappingContext();
RepositoryMetadata metadata = new DefaultRepositoryMetadata(TestRepository.class);
Method method = TestRepository.class.getMethod("findAllProjectedBy");
CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext);
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor);
when(entityInformation.getJavaType()).thenReturn(Beer.class);
when(couchbaseOperations.getCouchbaseBucket()).thenReturn(couchbaseBucket);
when(couchbaseBucket.name()).thenReturn("B");
when(couchbaseOperations.getConverter()).thenReturn(couchbaseConverter);
when(couchbaseOperations.getConverter().getMappingContext()).thenReturn(mappingContext);
when(couchbaseConverter.getTypeKey()).thenReturn("_class");
when(couchbaseConverter.convertForWriteIfNeeded(eq("value"))).thenReturn("value");
PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
Statement statement = query.getStatement(accessor, null, processor.getReturnedType());
assertEquals("SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS, `B`.`desc` FROM `B` WHERE "
+ "`_class` = \"org.springframework.data.couchbase.core.Beer\"", statement.toString());
}
@Test
public void testProjectionDTO() throws Exception {
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
CouchbaseBucket couchbaseBucket = mock(CouchbaseBucket.class);
CouchbaseConverter couchbaseConverter = mock(CouchbaseConverter.class);
EntityMetadata entityInformation = mock(EntityMetadata.class);
ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
ParameterAccessor accessor = mock(ParameterAccessor.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(TestRepository.class);
Method method = TestRepository.class.getMethod("findAllDtoedBy");
MappingContext mappingContext = new CouchbaseMappingContext();
CouchbaseQueryMethod queryMethod = new CouchbaseQueryMethod(method, metadata, factory, mappingContext);
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor);
when(entityInformation.getJavaType()).thenReturn(Beer.class);
when(couchbaseOperations.getCouchbaseBucket()).thenReturn(couchbaseBucket);
when(couchbaseBucket.name()).thenReturn("B");
when(couchbaseOperations.getConverter()).thenReturn(couchbaseConverter);
when(couchbaseOperations.getConverter().getMappingContext()).thenReturn(mappingContext);
when(couchbaseConverter.getTypeKey()).thenReturn("_class");
PartTreeN1qlBasedQuery query = new PartTreeN1qlBasedQuery(queryMethod, couchbaseOperations);
Statement statement = query.getStatement(accessor, null, processor.getReturnedType());
assertEquals("SELECT META(`B`).id AS _ID, META(`B`).cas AS _CAS, `B`.`name`, `B`.`desc` FROM `B` "
+ "WHERE `_class` = \"org.springframework.data.couchbase.core.Beer\"", statement.toString());
}
public static interface TestRepository extends CrudRepository<Beer, String> {
Page<Beer> findByNameOrderByName(String name, Pageable pageRequest);
Page<Beer> findByName(String name, Pageable pageRequest);
}
Collection<BeerProjection> findAllProjectedBy();
}
List<BeerDTO> findAllDtoedBy();
}
}