diff --git a/src/main/java/org/springframework/data/gemfire/repository/query/StringBasedGemfireRepositoryQuery.java b/src/main/java/org/springframework/data/gemfire/repository/query/StringBasedGemfireRepositoryQuery.java index 3dff3708..6818818b 100644 --- a/src/main/java/org/springframework/data/gemfire/repository/query/StringBasedGemfireRepositoryQuery.java +++ b/src/main/java/org/springframework/data/gemfire/repository/query/StringBasedGemfireRepositoryQuery.java @@ -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); } diff --git a/src/test/java/org/springframework/data/gemfire/repository/sample/PersonRepository.java b/src/test/java/org/springframework/data/gemfire/repository/sample/PersonRepository.java index d7ccd565..4c7bb0bb 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/sample/PersonRepository.java +++ b/src/test/java/org/springframework/data/gemfire/repository/sample/PersonRepository.java @@ -42,4 +42,6 @@ public interface PersonRepository extends CrudRepository { Collection findByFirstnameAndLastname(String firstname, String lastname); Collection findByFirstnameOrLastname(String firstname, String lastname); + + Person findByLastname(String lastname); } diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/AbstractGemfireRepositoryFactoryIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/repository/support/AbstractGemfireRepositoryFactoryIntegrationTests.java index 4fba9928..17381dc6 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/support/AbstractGemfireRepositoryFactoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/repository/support/AbstractGemfireRepositoryFactoryIntegrationTests.java @@ -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> 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 void assertResultsFound(Iterable result, T... expected) { assertThat(result, is(notNullValue())); diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryIntegrationTests.java index 7440a9d5..2ae9edaf 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/repository/support/GemfireRepositoryFactoryIntegrationTests.java @@ -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);