SGF-113 - Added support to return single entities from query methods.
If a query method returns a single entity it is now correctly unwrapped from the result collection returned by the query. No entities being found will result in null returned, more than one entity being found results in an IncorrectResultSizeDataAccessException to align with the other repository implementations.
This commit is contained in:
@@ -19,6 +19,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -34,6 +35,8 @@ import com.gemstone.gemfire.cache.query.internal.ResultsBag;
|
||||
*/
|
||||
public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
|
||||
private static final String INVALID_EXECUTION = "Paging and modifying queries are not supported!";
|
||||
|
||||
private final QueryString query;
|
||||
private final GemfireQueryMethod method;
|
||||
private final GemfireTemplate template;
|
||||
@@ -67,6 +70,10 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
this.query = new QueryString(StringUtils.hasText(query) ? query : method.getAnnotatedQuery());
|
||||
this.method = method;
|
||||
this.template = template;
|
||||
|
||||
if (method.isPageQuery() || method.isModifyingQuery()) {
|
||||
throw new IllegalStateException(INVALID_EXECUTION);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -83,7 +90,24 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
while (indexes.hasNext()) {
|
||||
query = query.bindIn(toCollection(accessor.getBindableValue(indexes.next() - 1)));
|
||||
}
|
||||
return toCollection(template.find(query.toString(), parameters));
|
||||
|
||||
Collection<?> result = toCollection(template.find(query.toString(), parameters));
|
||||
|
||||
if (method.isCollectionQuery()) {
|
||||
return result;
|
||||
} else if (method.isQueryForEntity()) {
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
} else if (result.size() == 1) {
|
||||
return result.iterator().next();
|
||||
} else {
|
||||
throw new IncorrectResultSizeDataAccessException(1, result.size());
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException(INVALID_EXECUTION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,15 +118,15 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
|
||||
* @return
|
||||
*/
|
||||
private Collection<?> toCollection(Object source) {
|
||||
|
||||
if (source instanceof ResultsBag) {
|
||||
ResultsBag bag = (ResultsBag)source;
|
||||
ResultsBag bag = (ResultsBag) source;
|
||||
return bag.asList();
|
||||
}
|
||||
|
||||
|
||||
if (source instanceof Collection) {
|
||||
return (Collection<?>) source;
|
||||
}
|
||||
|
||||
|
||||
return source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singleton(source);
|
||||
}
|
||||
|
||||
@@ -42,4 +42,6 @@ public interface PersonRepository extends CrudRepository<Person, Long> {
|
||||
Collection<Person> findByFirstnameAndLastname(String firstname, String lastname);
|
||||
|
||||
Collection<Person> findByFirstnameOrLastname(String firstname, String lastname);
|
||||
|
||||
Person findByLastname(String lastname);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
|
||||
import org.springframework.data.gemfire.mapping.Regions;
|
||||
@@ -46,7 +47,7 @@ public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
|
||||
@Autowired
|
||||
List<Region<?, ?>> regions;
|
||||
|
||||
Person dave, carter, boyd, stefan, leroi, jeff;
|
||||
Person dave, carter, boyd, stefan, leroi, jeff, oliverAugust;
|
||||
PersonRepository repository;
|
||||
|
||||
@Before
|
||||
@@ -58,6 +59,7 @@ public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
|
||||
stefan = new Person(4L, "Stefan", "Lessard");
|
||||
leroi = new Person(5L, "Leroi", "Moore");
|
||||
jeff = new Person(6L, "Jeff", "Coffin");
|
||||
oliverAugust = new Person(7L, "Oliver August", "Matthews");
|
||||
|
||||
GemfireMappingContext context = new GemfireMappingContext();
|
||||
|
||||
@@ -70,6 +72,7 @@ public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
|
||||
template.put(stefan.id, stefan);
|
||||
template.put(leroi.id, leroi);
|
||||
template.put(jeff.id, jeff);
|
||||
template.put(oliverAugust.id, oliverAugust);
|
||||
|
||||
repository = getRepository(regions);
|
||||
}
|
||||
@@ -105,7 +108,7 @@ public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void executesDerivedQueryWithOrCorrectly() {
|
||||
assertResultsFound(repository.findByFirstnameOrLastname("Carter", "Matthews"), carter, dave);
|
||||
assertResultsFound(repository.findByFirstnameOrLastname("Carter", "Matthews"), carter, dave, oliverAugust);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,6 +122,37 @@ public abstract class AbstractGemfireRepositoryFactoryIntegrationTests {
|
||||
assertResultsFound(repository.findAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-113
|
||||
*/
|
||||
@Test
|
||||
public void findsPersonByLastname() {
|
||||
assertThat(repository.findByLastname("Beauford"), is(carter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-113
|
||||
*/
|
||||
@Test
|
||||
public void returnsNullForEmptyResultForSingleEntityQuery() {
|
||||
assertThat(repository.findByLastname("Foo"), is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SGF-113
|
||||
*/
|
||||
@Test
|
||||
public void throwsExceptionForMoreThanOneResultForSingleEntityQuery() {
|
||||
|
||||
try {
|
||||
repository.findByLastname("Matthews");
|
||||
fail("Exception expected!");
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
assertThat(e.getExpectedSize(), is(1));
|
||||
assertThat(e.getActualSize(), is(2));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void assertResultsFound(Iterable<T> result, T... expected) {
|
||||
|
||||
assertThat(result, is(notNullValue()));
|
||||
|
||||
@@ -38,7 +38,7 @@ public class GemfireRepositoryFactoryIntegrationTests extends AbstractGemfireRep
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void throwsExceptionIfReferencedRegionIsNotConfigured() {
|
||||
|
||||
GemfireRepositoryFactory factory = new GemfireRepositoryFactory((Iterable) Collections.emptySet(), null);
|
||||
|
||||
Reference in New Issue
Block a user