DATAGRAPH-685 - LoadByProperty depth support in Neo4jOperations.

This commit is contained in:
Luanne Misquitta
2015-11-13 17:35:32 +05:30
parent 5bcedea378
commit bbe042c53b
5 changed files with 198 additions and 5 deletions

View File

@@ -95,6 +95,23 @@ public interface Neo4jOperations {
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves the entity of the specified type that contains a property matching the given name with the given value.
* This method assumes that the requested property/value combination will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The instance of T corresponding to the entity that matches the given property, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given value.
*
@@ -106,6 +123,19 @@ public interface Neo4jOperations {
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue);
/**
* Retrieves all the entities of the specified type that contain a property matching the given name with the given value.
*
* @param type The type of entity to load
* @param propertyName The name of the property on the entity against which to match the given value
* @param propertyValue The value of the named property against which to match entities
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all the entities that match the given property or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperty(Class<T> type, String propertyName, Object propertyValue, int depth);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and value.
* This method assumes that the requested property/value combinations will be unique for all entities of this type in
@@ -120,6 +150,22 @@ public interface Neo4jOperations {
*/
<T> T loadByProperties(Class<T> type, Filters parameters);
/**
* Retrieves the entity of the specified type that contains properties matching the ones supplied with given name and value.
* This method assumes that the requested property/value combinations will be unique for all entities of this type in
* the database and will throw an exception unless exactly one result is found. If several entities are expected to
* be returned then use {@link #loadAllByProperty(Class, String, Object)} instead.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return The instance of T corresponding to the entity that matches the given properties, never <code>null</code>
* @throws NotFoundException if there are no matching entities
* @throws IllegalStateException if there's more than one matching entity
*/
<T> T loadByProperties(Class<T> type, Filters parameters, int depth);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given name and value.
*
@@ -130,6 +176,18 @@ public interface Neo4jOperations {
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters);
/**
* Retrieves all the entities of the specified type that contain a properties matching the ones supplied with given name and value.
*
* @param type The type of entity to load
* @param parameters The parameters to filter by
* @param depth The maximum number of relationships away from each loaded object to follow when loading related entities.
* A value of 0 just loads the object's properties and no related entities. A value of -1 implies no depth limit.
* @return A {@link Collection} containing all the entities that match the given properties or an empty {@link Collection} if
* there aren't any matches, never <code>null</code>
*/
<T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters, int depth);
/**
* Saves the specified entity in the graph database. If the entity is currently transient then the persistent version of
* the entity will be returned, containing its new graph ID.

View File

@@ -138,8 +138,13 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationEventPublisher
@Override
public <T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue) {
return loadByProperty(type, propertyName, propertyValue, 1);
}
@Override
public <T> T loadByProperty(Class<T> type, String propertyName, Object propertyValue, int depth) {
try {
return getSingle(loadAllByProperty(type, propertyName, propertyValue));
return getSingle(loadAllByProperty(type, propertyName, propertyValue, depth));
} catch (Exception e) {
throw Neo4jOgmExceptionTranslator.translateExceptionIfPossible(e);
}
@@ -164,8 +169,13 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationEventPublisher
@Override
public <T> T loadByProperties(Class<T> type, Filters parameters) {
return loadByProperties(type, parameters, 1);
}
@Override
public <T> T loadByProperties(Class<T> type, Filters parameters, int depth) {
try {
return getSingle(loadAllByProperties(type, parameters));
return getSingle(loadAllByProperties(type, parameters, depth));
} catch (Exception e) {
throw Neo4jOgmExceptionTranslator.translateExceptionIfPossible(e);
}
@@ -173,8 +183,13 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationEventPublisher
@Override
public <T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters) {
return loadAllByProperties(type, parameters, 1);
}
@Override
public <T> Collection<T> loadAllByProperties(Class<T> type, Filters parameters, int depth) {
try {
return session.loadAll(type, parameters);
return session.loadAll(type, parameters, depth);
} catch (Exception e) {
throw Neo4jOgmExceptionTranslator.translateExceptionIfPossible(e);
}

View File

@@ -72,4 +72,8 @@ public class User extends Person{
public Set<Rating> getRatings() {
return ratings;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
}

View File

@@ -27,9 +27,11 @@ import org.junit.Test;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.*;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.cypher.BooleanOperator;
import org.neo4j.ogm.cypher.ComparisonOperator;
import org.neo4j.ogm.cypher.Filter;
import org.neo4j.ogm.cypher.Filters;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.Utils;
import org.neo4j.ogm.session.result.QueryStatistics;
@@ -48,11 +50,13 @@ public class Neo4jTemplateTest {
public static Neo4jIntegrationTestRule neo4jRule = new Neo4jIntegrationTestRule();
private Neo4jOperations template;
private Session session;
@Before
public void setUpOgmSession() {
SessionFactory sessionFactory = new SessionFactory("org.springframework.data.neo4j.examples.movies.domain");
this.template = new Neo4jTemplate(sessionFactory.openSession(neo4jRule.url()));
session = sessionFactory.openSession(neo4jRule.url());
this.template = new Neo4jTemplate(session);
addArbitraryDataToDatabase();
}
@@ -164,6 +168,113 @@ public class Neo4jTemplateTest {
assertEquals("Horror", loadedGenre.getName());
}
/**
* @see DATAGRAPH-685
*/
@Test
public void shouldRetrieveEntitiesByMatchingPropertyAndDepth() {
User user = new User("Harmanpreet Singh");
TempMovie bollywood = new TempMovie("Desi Boyz");
TempMovie hollywood = new TempMovie("Mission Impossible");
template.save(user.rate(bollywood, 1, "Bakwaas"));
template.save(user.rate(hollywood, 4, "Pretty good"));
session.clear();
User u = template.loadByProperty(User.class, "name", "Harmanpreet Singh",0);
assertEquals(0,u.getRatings().size());
u = template.loadByProperty(User.class, "name", "Harmanpreet Singh",2);
assertEquals(2,u.getRatings().size());
assertNotNull(u.getRatings().iterator().next().getMovie().getRatings());
}
/**
* @see DATAGRAPH-685
*/
@Test
public void shouldRetrieveAllEntitiesByMatchingPropertyAndDepth() {
User user = new User("Harmanpreet Singh");
TempMovie bollywood = new TempMovie("Desi Boyz");
TempMovie hollywood = new TempMovie("Desi Boyz");
template.save(user.rate(bollywood, 1, "Bakwaas"));
template.save(user.rate(hollywood, 4, "Pretty good"));
session.clear();
Collection<TempMovie> m = template.loadAllByProperty(TempMovie.class, "name", "Desi Boyz",0);
assertEquals(2,m.size());
assertEquals(0, m.iterator().next().getRatings().size());
m = template.loadAllByProperty(TempMovie.class, "name", "Desi Boyz",1);
assertEquals(2,m.size());
assertEquals(1, m.iterator().next().getRatings().size());
}
/**
* @see DATAGRAPH-685
*/
@Test
public void shouldRetrieveEntitiesByMatchingPropertiesAndDepth() {
User user = new User("Harmanpreet Singh");
user.setMiddleName("A");
User user2 = new User("Harmanpreet Singh");
user2.setMiddleName("B");
TempMovie bollywood = new TempMovie("Desi Boyz");
TempMovie hollywood = new TempMovie("Mission Impossible");
template.save(user.rate(bollywood, 1, "Bakwaas"));
template.save(user.rate(hollywood, 4, "Pretty good"));
template.save(user2);
session.clear();
Filter nameFilter = new Filter("name","Harmanpreet Singh");
Filter middleNameFilter = new Filter("middleName","A");
middleNameFilter.setBooleanOperator(BooleanOperator.AND);
Filters filters = new Filters();
filters.add(nameFilter, middleNameFilter);
User u = template.loadByProperties(User.class,filters,0);
assertEquals(0,u.getRatings().size());
u = template.loadByProperties(User.class, filters,2);
assertEquals(2,u.getRatings().size());
assertNotNull(u.getRatings().iterator().next().getMovie().getRatings());
}
/**
* @see DATAGRAPH-685
*/
@Test
public void shouldRetrieveAllEntitiesByMatchingPropertiesAndDepth() {
User user = new User("Harmanpreet Singh");
user.setMiddleName("A");
User user2 = new User("Harmanpreet Singh");
user2.setMiddleName("A");
TempMovie bollywood = new TempMovie("Desi Boyz");
TempMovie hollywood = new TempMovie("Mission Impossible");
template.save(user.rate(bollywood, 1, "Bakwaas"));
template.save(user.rate(hollywood, 4, "Pretty good"));
template.save(user2);
session.clear();
Filter nameFilter = new Filter("name","Harmanpreet Singh");
Filter middleNameFilter = new Filter("middleName","A");
middleNameFilter.setBooleanOperator(BooleanOperator.AND);
Filters filters = new Filters();
filters.add(nameFilter, middleNameFilter);
Collection<User> u = template.loadAllByProperties(User.class,filters,0);
assertEquals(2,u.size());
assertEquals(0,u.iterator().next().getRatings().size());
u = template.loadAllByProperties(User.class, filters,2);
assertEquals(2,u.size());
assertNotNull(u.iterator().next().getRatings().iterator().next().getMovie().getRatings());
}
@Test
public void shouldExecuteArbitraryUpdateQuery() {
assertTrue("There shouldn't be any genres in the database", this.template.loadAll(Genre.class).isEmpty());

View File

@@ -59,6 +59,11 @@ The named or indexed parameter `{param}` will be substituted by the actual metho
Node and Relationship-Entities are handled directly and converted into their respective ids, Iterables thereof as well.
All other parameters types are provided directly (i.e. Strings, Longs, etc).
[NOTE]
====
In the current version, custom queries do not support paging, sorting or a custom depth.
====
=== Query results
Typical results for queries are `Iterable<Type>`, `Iterable<Map<String,Object>>` or simply `Type`.
@@ -140,7 +145,7 @@ public interface PersonRepository extends GraphRepository<Person> {
[NOTE]
====
In the current version, derived finders and custom queries do not support paging, sorting or a custom depth.
In the current version, derived finders do not support paging, sorting or a custom depth.
====