Merge pull request #119 from nickithewatt/master

DATAGRAPH-345 : Add support for countBy projections on derived query
This commit is contained in:
Michael Hunger
2013-07-16 04:20:49 -07:00
6 changed files with 65 additions and 5 deletions

View File

@@ -25,13 +25,10 @@ import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.parser.Part;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static org.springframework.util.StringUtils.collectionToCommaDelimitedString;
import static org.springframework.util.StringUtils.collectionToDelimitedString;
import static org.springframework.util.StringUtils.hasText;
import static org.springframework.util.StringUtils.*;
public class CypherQuery implements CypherQueryDefinition {
private final VariableContext variableContext = new VariableContext();
@@ -42,6 +39,7 @@ public class CypherQuery implements CypherQueryDefinition {
private int index = 0;
private final Neo4jPersistentEntity<?> entity;
private final Neo4jTemplate template;
private boolean isCountQuery = false;
public CypherQuery(final Neo4jPersistentEntity<?> entity, Neo4jTemplate template) {
this.entity = entity;
@@ -176,7 +174,12 @@ public class CypherQuery implements CypherQueryDefinition {
builder.append(" WHERE ").append(whereClauses);
}
builder.append(" RETURN ").append(String.format(QueryTemplates.VARIABLE, getEntityName(entity)));
String returnEntity = String.format(QueryTemplates.VARIABLE,getEntityName(entity));
if (isCountQuery) {
builder.append(" RETURN ").append("count(").append(returnEntity).append(")");
} else {
builder.append(" RETURN ").append(returnEntity);
}
return builder.toString();
}
@@ -235,4 +238,8 @@ public class CypherQuery implements CypherQueryDefinition {
public String toString() {
return toQueryString();
}
public void setIsCountQuery(boolean isCountQuery) {
this.isCountQuery = isCountQuery;
}
}

View File

@@ -38,6 +38,11 @@ class CypherQueryBuilder {
this.query = new CypherQuery(entity, template);
}
public CypherQueryBuilder asCountQuery() {
query.setIsCountQuery(true);
return this;
}
public CypherQueryBuilder addRestriction(Part part) {
query.addPart(part, context.getPersistentPropertyPath(part.getProperty()));
return this;

View File

@@ -37,6 +37,7 @@ class CypherQueryCreator extends AbstractQueryCreator<CypherQueryDefinition, Cyp
private final MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> context;
private final Class<?> domainClass;
private final Neo4jTemplate template;
private boolean isCountProjection = false;
/**
* Creates a new {@link CypherQueryCreator} using the given {@link PartTree}, {@link org.springframework.data.neo4j.support.mapping.Neo4jMappingContext} and domain
@@ -58,6 +59,7 @@ class CypherQueryCreator extends AbstractQueryCreator<CypherQueryDefinition, Cyp
this.template = template;
this.context = context;
this.domainClass = domainClass;
this.isCountProjection = tree.isCountProjection();
}
/*
@@ -68,6 +70,9 @@ class CypherQueryCreator extends AbstractQueryCreator<CypherQueryDefinition, Cyp
protected CypherQueryBuilder create(Part part, Iterator<Object> iterator) {
CypherQueryBuilder builder = new CypherQueryBuilder(context, domainClass,template);
if (isCountProjection) {
builder = builder.asCountQuery();
}
builder.addRestriction(part);
return builder;

View File

@@ -151,6 +151,14 @@ interface RecipeRepository extends GraphRepository<Recipe> {
Set<Recipe> findByIngredientAndCookBook(Ingredient ingredient, CookBook cookBook);
Set<Recipe> findBySecrets(Ingredient ingredient);
Long countByAuthor(String author);
Long countByIngredientAndAuthor(Ingredient ingredient, String author);
Long countByIngredient(Ingredient ingredient);
Integer countByCookBookTitle(String title);
}
@RunWith(SpringJUnit4ClassRunner.class)
@@ -292,6 +300,31 @@ public class DerivedFinderTests {
assertThat(single(recipes).author, is(equalTo("Jamie")));
}
@Test
public void shouldCountCorrectlyUsingProperty() throws Exception {
Long actualCountVal = recipeRepository.countByAuthor("Hugh");
assertThat(actualCountVal, is(equalTo(3L)));
}
@Test
public void shouldCountCorrectlyUsingEntityAndProperty() throws Exception {
Long actualCountVal = recipeRepository.countByIngredientAndAuthor(oliveOil,"Hugh");
assertThat(actualCountVal, is(equalTo(1L)));
}
@Test
public void shouldCountCorrectlyUsingEntity() throws Exception {
Long actualCountVal = recipeRepository.countByIngredient(chocolate);
assertThat(actualCountVal, is(equalTo(2L)));
}
@Test
public void shouldCountCorrectlyUsingPropertyTraversal() throws Exception {
Integer actualCountVal = recipeRepository.countByCookBookTitle("Naked Chef");
assertThat(actualCountVal, is(equalTo(1)));
}
@Test
public void shouldFindUsingEntityAndPropertyTraversal() throws Exception {
Set<Recipe> recipes = recipeRepository.findByIngredientAndCookBookTitle(oliveOil, "Naked Chef");

View File

@@ -372,6 +372,14 @@ public class GraphRepositoryTests {
assertThat(findByName, hasItem(testTeam.michael));
}
@Test @Transactional
public void countByName() {
Long num = personRepository.countByName(testTeam.michael.getName());
assertEquals((Long)1L,num);
}
@Test @Transactional
public void findByPersonalityEnum() {
testTeam.michael.setPersonality(Personality.EXTROVERT);

View File

@@ -78,6 +78,8 @@ public interface PersonRepository extends GraphRepository<Person>, NamedIndexRep
Iterable<Person> findAllTeamMembersSorted(@Param("p_team") Group team, Sort sort);
Long countByName(String name);
// Derived queries
Iterable<Person> findByName(String name);