diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java index 27ae6e820..587384cf2 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java @@ -6,36 +6,161 @@ import org.neo4j.graphdb.traversal.TraversalDescription; import java.util.Map; /** + * A template with convenience operations, exception translation and implicit transaction for modifying methods * @author mh * @since 19.02.11 */ public interface Neo4jOperations { + /** + * Executes the callback in a transactional context, throwing an exception in the callback will cause the transaction to be rolled back + * The callback is passed a GraphDatabaseService. + * @param callback for executing graph operations transactionally, not null + * @param return type + * @return whatever the callback chooses to return + * @throws org.springframework.dao.DataAccessException subclasses + */ T update(GraphCallback callback); + /** + * Executes the callback in a NON-transactional context. + * @param callback for executing graph operations NON-transactionally, not null + * @param return type + * @return whatever the callback chooses to return + * @throws org.springframework.dao.DataAccessException subclasses + */ T exec(GraphCallback callback); + /** + * Delegates to the GraphDatabaseService + * @return the reference node of the underlying graph database + */ Node getReferenceNode(); + /** + * Delegates to the GraphDatabaseService + * @param id node id + * @return the requested node of the underlying graph database + * @throws NotFoundException + */ Node getNode(long id); + /** + * Transactionally creates the node, sets the properties (if any) and indexes the given fields (if any). + * Two shortcut means of providing the properties (very short with static imports) + * template.createNode(PropertyMap._("name","value")); + * template.createNode(PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * @param props properties to be set at node creation might be null + * @param indexFields fields that are automatically indexed from the given properties for the newly created ndoe + * @return the newly created node + */ Node createNode(Map props, String... indexFields); + /** + * Delegates to the GraphDatabaseService + * @param id relationship id + * @return the requested relationship of the underlying graph database + * @throws NotFoundException + */ Relationship getRelationship(long id); + /** + * Transactionally creates the relationship, sets the properties (if any) and indexes the given fielss (if any) + * Two shortcut means of providing the properties (very short with static imports) + * template.createRelationship(from,to,TYPE, PropertyMap._("name","value")); + * template.createRelationship(from,to,TYPE, PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * @param startNode start-node of relationship + * @param endNode end-node of relationship + * @param type relationship type, might by an enum implementing RelationshipType or a DynamicRelationshipType.withName("name") + * @param props optional initial properties + * @param indexFields optional indexed fields + * @return the newly created relationship + */ Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields); + /** + * Queries the supplied index with a lucene query string or query object (if the neo4j-index provider is lucene) + * @param indexName Name of the index, will be checked against existing indexes, first relationship-indexes, then node indexes + * assumes a "node" node index for a null value + * @param pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param queryOrQueryObject a lucene query string or query object (if the neo4j-index provider is lucene) + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the query result mapping + * @see IterationController for controlling eagerness of iteration + */ Iterable query(String indexName, PathMapper pathMapper, Object queryOrQueryObject); + /** + * Queries the supplied index with a field - value combination + * @param indexName Name of the index, will be checked against existing indexes, first relationship-indexes, then node indexes + * assumes a "node" node index for a null value + * @param pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param field field to query + * @param value value to supply to index query + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the query result mapping + * @see IterationController for controlling eagerness of iteration + */ Iterable query(String indexName, PathMapper pathMapper, String field, String value); + /** + * Traverses the whole path with the given traversal descripting starting at the start node. + * @param startNode start node for the traversal + * @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param traversal a traversal description, possibly generated by the Traversal.description()... DSL + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping + */ Iterable traverseGraph(Node startNode, PathMapper pathMapper, TraversalDescription traversal); + /** + * Traverses only to the direct neighbours of the start node + * @param startNode start node for the traversal + * @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param type type of relationships to consider + * @param direction direction of relationship to consider (can be OUTGOING, INCOMING, BOTH) + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping + */ Iterable traverseNext(Node startNode, PathMapper pathMapper, RelationshipType type, Direction direction); - Iterable traverseNext(Node startNode, PathMapper pathMapper, RelationshipType... type); + /** + * Traverses only to the direct neighbours of the start node for the specified relationship types + * @param startNode start node for the traversal + * @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param types types of relationships to consider + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping + */ + Iterable traverseNext(Node startNode, PathMapper pathMapper, RelationshipType... types); + /** + * Traverses only to all direct neighbours of the start node for all relationships + * @param startNode start node for the traversal + * @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour + * @param expected type of result + * @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping + */ Iterable traverseNext(Node startNode, PathMapper pathMapper); + /** + * Indexes the given field and value for the element. + * @param indexName Name of the index, will be checked against existing indexes according to the given element + * assumes a "node" node index or "relationship" relationship index for a null value + * @param element node or relationship to index + * @param field field to index + * @param value value to index + * @param the provided element type + * @return the provided element for convenience + */ T index(String indexName, T element, String field, Object value); - T autoIndex(String indexName, T element, String... indexFields); + /** + * Auto-indexes all indexFields for the given element's properties if they exist + * @param indexName Name of the index, will be checked against existing indexes according to the given element + * assumes a "node" node index or "relationship" relationship index for a null value + * @param element node or relationship to auto-index + * @param indexProperties property names to index + * @param the provided element type + * @return the provided element for convenience + */ + T autoIndex(String indexName, T element, String... indexProperties); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java index eb5690389..8ae5dc4d0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java @@ -25,12 +25,8 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import static org.springframework.data.graph.neo4j.template.IterationController.IterationMode.EAGER_STOP_ON_NULL; - public class Neo4jTemplate implements Neo4jOperations { private final GraphDatabaseService graphDatabaseService; @@ -142,7 +138,7 @@ public class Neo4jTemplate implements Neo4jOperations { update(new GraphCallback.WithoutResult() { @Override public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception { - RelationshipIndex relationshipIndex = relationshipIndex(indexName); + RelationshipIndex relationshipIndex = relationshipIndexAllowsNull(indexName); if (relationshipIndex != null && element instanceof Relationship) { relationshipIndex.add((Relationship) element, field, value); } else if (element instanceof Node) { @@ -155,6 +151,13 @@ public class Neo4jTemplate implements Neo4jOperations { return element; } + private RelationshipIndex relationshipIndexAllowsNull(String indexName) { + if (indexName == null) { + return relationshipIndex("relationship"); + } + return relationshipIndex(indexName); + } + private RelationshipIndex relationshipIndex(String indexName) { if (indexName != null && index.existsForRelationships(indexName)) { return index.forRelationships(indexName);