diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java index 1c072980a..c8d5352d9 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/NodeBacked.java @@ -20,6 +20,7 @@ import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.traversal.TraversalDescription; import org.springframework.data.graph.neo4j.fieldaccess.EntityState; +import org.springframework.data.graph.neo4j.support.EntityPath; /** * Interface introduced to objects annotated with @NodeEntity by the {@link org.springframework.data.graph.neo4j.support.node.Neo4jNodeBacking} aspect. @@ -92,6 +93,15 @@ public interface NodeBacked extends GraphBacked { */ Iterable findAllByTraversal(final Class targetType, TraversalDescription traversalDescription); + /** + * Perform a traversal from this entity's underlying node with the given traversal description. The found paths + * are used to create the wrapping entity paths. + * + * @param traversalDescription traversal description used + * @return Lazy {@link java.lang.Iterable} over the traversal result paths, wrapped as entity paths @{link EntityPath} + * entity instances + */ + Iterable> findAllPathsByTraversal(TraversalDescription traversalDescription); /** * Removes the all relationships of the given type between this entity's underlying node and the target diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java index 5763965b9..addbcda7e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/RelationshipBacked.java @@ -25,7 +25,7 @@ import org.neo4j.graphdb.Relationship; public interface RelationshipBacked extends GraphBacked{ /** - * @return relationship id if there is an underlying relationship + * @return the id of the underlying relationship or null if there is none */ Long getRelationshipId(); @@ -40,8 +40,4 @@ public interface RelationshipBacked extends GraphBacked{ R projectTo(Class targetType); - /** - * @return the id of the underlying relationship or null if there is none - */ - Long getRelationshipId(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/EntityPathPathIterableWrapper.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/EntityPathPathIterableWrapper.java new file mode 100644 index 000000000..ebc622614 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/EntityPathPathIterableWrapper.java @@ -0,0 +1,40 @@ +/** + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.graph.neo4j.support.node; + +import org.neo4j.graphdb.Path; +import org.neo4j.helpers.collection.IterableWrapper; +import org.springframework.data.graph.core.NodeBacked; +import org.springframework.data.graph.neo4j.support.EntityPath; +import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; + +/** +* @author mh +* @since 04.04.11 +*/ +public class EntityPathPathIterableWrapper extends IterableWrapper, Path> { + private final GraphDatabaseContext graphDatabaseContext; + + public EntityPathPathIterableWrapper(Iterable paths, GraphDatabaseContext graphDatabaseContext) { + super(paths); + this.graphDatabaseContext = graphDatabaseContext; + } + + protected EntityPath underlyingObjectToObject(Path path) { + return new EntityPath(graphDatabaseContext,path); + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj index baf4278be..8106e0df2 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jNodeBacking.aj @@ -27,13 +27,14 @@ import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.RelationshipBacked; import org.springframework.data.graph.neo4j.fieldaccess.*; +import org.springframework.data.graph.neo4j.support.EntityPath; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import java.lang.reflect.Field; import org.springframework.data.graph.annotation.*; import javax.persistence.Transient; import javax.persistence.Entity; -import org.springframework.beans.factory.annotation.Configurable; + +import java.lang.reflect.Field; import static org.springframework.data.graph.neo4j.fieldaccess.DoReturn.unwrap; @@ -173,6 +174,12 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext); } + public Iterable> NodeBacked.findAllPathsByTraversal(TraversalDescription traversalDescription) { + if (!hasPersistentState()) throw new IllegalStateException("No node attached to " + this); + final Traverser traverser = traversalDescription.traverse(this.getPersistentState()); + return new EntityPathPathIterableWrapper(traverser, Neo4jNodeBacking.aspectOf().graphDatabaseContext); + } + public R NodeBacked.relateTo(N target, Class relationshipClass, String relationshipType) { if (target==null) throw new IllegalArgumentException("Target entity is null"); if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null"); @@ -264,4 +271,5 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields people = (Iterable) group.findAllByTraversal(Person.class, traversalDescription); final HashSet found = new HashSet(); for (Person person : people) { @@ -77,6 +79,21 @@ public class TraversalTest { } assertEquals(Collections.singleton(p),found); } + @Test + @Transactional + public void testTraverseFromGroupToPeoplePaths() { + Person p = persistedPerson("Michael", 35); + Group group = new Group().persist(); + group.setName("dev"); + group.addPerson(p); + final TraversalDescription traversalDescription = Traversal.description().relationships(DynamicRelationshipType.withName("persons"), Direction.OUTGOING).evaluator(Evaluators.excludeStartPosition()); + Iterable> paths = group.findAllPathsByTraversal(traversalDescription); + for (EntityPath path : paths) { + assertEquals(group, path.startEntity()); + assertEquals(p, path.endEntity()); + assertEquals(1,path.length()); + } + } @Test @Transactional diff --git a/src/docbkx/reference/programming-model/introducedmethods.xml b/src/docbkx/reference/programming-model/introducedmethods.xml index 8b9aa2ee3..cbf92f091 100644 --- a/src/docbkx/reference/programming-model/introducedmethods.xml +++ b/src/docbkx/reference/programming-model/introducedmethods.xml @@ -75,11 +75,19 @@ - traversing, starting at the current node + traversing, starting at the current node, returns end-nodes of traversal converted to provided type nodeEntity.findAllByTraversal(targetType, traversalDescription) + + traversing, starting at the current node, returns EntityPath's of the traversal result + bound to the provided start and end-node-entity types + + + Iterable<EntityPath> findAllPathsByTraversal(traversalDescription) + +