diff --git a/spring-data-neo4j-aspects/src/main/aspect/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj b/spring-data-neo4j-aspects/src/main/aspect/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj index da1ca1f3b..bba4f515c 100644 --- a/spring-data-neo4j-aspects/src/main/aspect/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj +++ b/spring-data-neo4j-aspects/src/main/aspect/org/springframework/data/neo4j/aspects/support/node/Neo4jNodeBacking.aj @@ -159,12 +159,12 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix return this.relateTo(target, type, false); } public Relationship NodeBacked.relateTo(NodeBacked target, String type, boolean allowDuplicates) { - final RelationshipResult result = entityStateHandler().relateTo(this, target, type, allowDuplicates); + final RelationshipResult result = entityStateHandler().createRelationshipBetween(this, target, type, allowDuplicates); return result.relationship; } public Relationship NodeBacked.getRelationshipTo(NodeBacked target, String type) { - return template().getRelationshipBetween(this, target, null, type); + return template().getRelationshipBetween(this,target,type); } public Long NodeBacked.getNodeId() { diff --git a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/RelationshipEntityTest.java b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/RelationshipEntityTest.java index 6e03e987f..a8eacde11 100644 --- a/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/RelationshipEntityTest.java +++ b/spring-data-neo4j-aspects/src/test/java/org/springframework/data/neo4j/aspects/support/RelationshipEntityTest.java @@ -101,7 +101,7 @@ public class RelationshipEntityTest extends EntityTestBase { assertEquals(f, neo4jTemplate.getRelationshipBetween(p, p2, Friendship.class, "knows")); } - @Ignore("The NodeBacking.getRelationshipTo() method is broken at the moment") + //@Ignore("The NodeBacking.getRelationshipTo() method is broken at the moment") @Test @Transactional public void testGetRelationshipTo() { diff --git a/spring-data-neo4j-examples/imdb/src/main/webapp/WEB-INF/imdb-app-servlet.xml b/spring-data-neo4j-examples/imdb/src/main/webapp/WEB-INF/imdb-app-servlet.xml index 15e4c9596..64adf9620 100644 --- a/spring-data-neo4j-examples/imdb/src/main/webapp/WEB-INF/imdb-app-servlet.xml +++ b/spring-data-neo4j-examples/imdb/src/main/webapp/WEB-INF/imdb-app-servlet.xml @@ -8,13 +8,13 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd - http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd "> + http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd"> - + diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityRemover.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityRemover.java index 5dd0ba27a..ffb66798e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityRemover.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityRemover.java @@ -59,7 +59,7 @@ public class EntityRemover { graphDatabase.remove(relationship); } - public void removeRelationshipTo(Object start, Object target, String type) { + public void removeRelationshipBetween(Object start, Object target, String type) { final RelationshipResult result = entityStateHandler.removeRelationshipTo(start, target, type); if (result!=null && result.type == RelationshipResult.Type.DELETED) { relationshipTypeRepresentationStrategy.preEntityRemoval(result.relationship); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java index 91cc5f412..92e6c9dd9 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java @@ -132,17 +132,17 @@ public class EntityStateHandler { } public RelationshipResult relateTo(Object source, Object target, String type) { - return this.relateTo(source, target, type, false); + return this.createRelationshipBetween(source, target, type, false); } // todo gdc.postEntityCreation(rel), return createEntityFromState(rel) - public RelationshipResult relateTo(Object source, Object target, String type, boolean allowDuplicates) { + public RelationshipResult createRelationshipBetween(Object source, Object target, String type, boolean allowDuplicates) { if (source == null) throw new IllegalArgumentException("Source entity is null"); if (target == null) throw new IllegalArgumentException("Target entity is null"); if (type == null) throw new IllegalArgumentException("Relationshiptype is null"); if (!allowDuplicates) { - Relationship relationship = getRelationshipTo(source, target, type); + Relationship relationship = getRelationshipBetween(source, target, type); if (relationship != null) return new RelationshipResult(relationship, RelationshipResult.Type.EXISTING); } @@ -164,7 +164,7 @@ public class EntityStateHandler { } public RelationshipResult removeRelationshipTo(Object source, Object target, String relationshipType) { - final Relationship relationship = getRelationshipTo(source, target, relationshipType); + final Relationship relationship = getRelationshipBetween(source, target, relationshipType); if (relationship!=null) { relationship.delete(); return new RelationshipResult(relationship, RelationshipResult.Type.DELETED); @@ -172,7 +172,7 @@ public class EntityStateHandler { return null; } - public Relationship getRelationshipTo(Object source, Object target, String type) { + public Relationship getRelationshipBetween(Object source, Object target, String type) { if (source == null) throw new IllegalArgumentException("Source entity is null"); if (target == null) throw new IllegalArgumentException("Target entity is null"); if (type == null) throw new IllegalArgumentException("Relationshiptype is null"); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java index 22869f275..d4f46c484 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/Neo4jTemplate.java @@ -219,21 +219,19 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister { } @Override - public Result createNodes(Map firstNode, Map... otherNodes) { - Collection result = new ArrayList(otherNodes.length + 1); - result.add(createNode(firstNode)); - for (Map properties : otherNodes) { + public Result createNodes(Map... allProperties) { + Collection result = new ArrayList(allProperties.length); + for (Map properties : allProperties) { result.add(createNode(properties)); } return convert(result); } @Override - public Iterable createNodesAs(Class target, Map firstNode, Map... otherNodes) { + public Iterable createNodesAs(Class target, Map... allProperties) { final TypeRepresentationStrategy nodeTypeRepresentationStrategy = isNodeEntity(target) ? infrastructure.getTypeRepresentationStrategies().getNodeTypeRepresentationStrategy() : null; - Collection result = new ArrayList(otherNodes.length + 1); - result.add(createNode(firstNode, target, nodeTypeRepresentationStrategy)); - for (Map properties : otherNodes) { + Collection result = new ArrayList(allProperties.length); + for (Map properties : allProperties) { result.add(createNode(properties, target, nodeTypeRepresentationStrategy)); } return convert(result).to(target); @@ -279,7 +277,6 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister { return infrastructure.getEntityStateHandler().isManaged(entity); } - @Override public Object query(String statement, Map params, final TypeInformation typeInformation) { final TypeInformation actualType = typeInformation.getActualType(); final Class targetType = actualType.getType(); @@ -295,21 +292,27 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister { @Override public R getRelationshipBetween(Object start, Object end, Class relationshipEntityClass, String relationshipType) { notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType"); - final Relationship relationship = infrastructure.getEntityStateHandler().getRelationshipTo(start, end, relationshipType); + final Relationship relationship = infrastructure.getEntityStateHandler().getRelationshipBetween(start, end, relationshipType); if (relationship == null) return null; + if (Relationship.class.isAssignableFrom(relationshipEntityClass)) return (R)relationship; return infrastructure.getEntityPersister().createEntityFromState(relationship, relationshipEntityClass); } + @Override + public Relationship getRelationshipBetween(Object start, Object end, String relationshipType) { + notNull(start,"start",end,"end",relationshipType,"relationshipType"); + return infrastructure.getEntityStateHandler().getRelationshipBetween(start,end,relationshipType); + } @Override public void removeRelationshipBetween(Object start, Object end, String type) { notNull(start,"start",end,"end",type,"relationshipType"); - infrastructure.getEntityRemover().removeRelationshipTo(start, end, type); + infrastructure.getEntityRemover().removeRelationshipBetween(start, end, type); } @Override public R createRelationshipBetween(Object start, Object end, Class relationshipEntityClass, String relationshipType, boolean allowDuplicates) { notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType"); - final RelationshipResult result = infrastructure.getEntityStateHandler().relateTo(start, end, relationshipType, allowDuplicates); + final RelationshipResult result = infrastructure.getEntityStateHandler().createRelationshipBetween(start, end, relationshipType, allowDuplicates); if (result.type == RelationshipResult.Type.NEW) { // TODO postEntityCreation(result.relationship, relationshipEntityClass); @@ -360,9 +363,12 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister { } @Override + @SuppressWarnings("unchecked") public T getReferenceNode(Class target) { try { - return convert(infrastructure.getGraphDatabase().getReferenceNode(), target); + final Node node = infrastructure.getGraphDatabase().getReferenceNode(); + if (Node.class.isAssignableFrom(target)) return (T) node; + return convert(node, target); } catch (RuntimeException e) { throw translateExceptionIfPossible(e); } @@ -444,7 +450,6 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister { } - @Override @SuppressWarnings("unchecked") public Iterable traverse(Object entity, Class targetType, TraversalDescription traversalDescription) { notNull(entity,"entity",targetType,"target type",traversalDescription,"traversal description"); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java index 7c10b8623..37466b1bb 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/template/Neo4jOperations.java @@ -24,7 +24,6 @@ import org.springframework.data.neo4j.annotation.QueryType; import org.springframework.data.neo4j.conversion.Result; import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.neo4j.support.query.QueryEngine; -import org.springframework.data.util.TypeInformation; import java.util.Map; @@ -60,15 +59,34 @@ public interface Neo4jOperations { */ Node getNode(long id); - Node createNode(Map props); + /** + * Creates a node + * @param properties the properties that should be initially set on the node + */ + Node createNode(Map properties); Node createNode(); + /** + * Creates a node mapped by the given entity class + * @param target mapped entity class or Node.class + * @param properties the properties that should be initially set on the node + */ T createNodeAs(Class target, Map properties); - Result createNodes(Map firstNode, Map... otherNodes); + /** + * Creates a number of nodes in a single step + * @param allProperties + * @return the nodes as a Result, which can be converted + */ + Result createNodes(Map... allProperties); - Iterable createNodesAs(Class target, Map firstNode, Map... otherNodes); + /** + * Creates a number of nodes mapped by the given entity class + * @param target mapped entity class or Node.class + * @param allProperties properties for each of the created nodes + */ + Iterable createNodesAs(Class target, Map... allProperties); /** @@ -80,22 +98,48 @@ public interface Neo4jOperations { */ Relationship getRelationship(long id); + /** + * Creates a relationship with the given initial properties. + */ Relationship createRelationshipBetween(Node startNode, Node endNode, RelationshipType type, Map props); + /** + * Retrieves a single relationship entity between two node entities with the given relationship type projected to the provided + * relationship entity class + */ R getRelationshipBetween(Object start, Object end, Class relationshipEntityClass, String relationshipType); + /** + * Retrieves a single relationship entity between two node entities. + */ + Relationship getRelationshipBetween(Object start, Object end, String relationshipType); + + /** + * Removes the relationship of this type between the two node entities + */ void removeRelationshipBetween(Object start, Object end, String type); + /** + * Creates a single relationship entity between two node entities with the given relationship type projected to the provided + * relationship entity class. If it allowDuplicates existing relationships won't be taken into account. Returns the projected + * relationship entity. + */ R createRelationshipBetween(Object start, Object end, Class relationshipEntityClass, String relationshipType, boolean allowDuplicates); + /** + * Retrieves an existing index for the given class and/or name + * @param type entity class, might be null + * @param indexName might be null + * @return Index<Node%gt; or Index<Relationship> + */ Index getIndex(Class type, String indexName); /** * 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 + * 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 @@ -116,10 +160,15 @@ public interface Neo4jOperations { */ Result lookup(String indexName, Object query); + /** + * The query is executed on the index for this entity type returning the IndexHits wrapped in a QueryResult to be converted + * into Paths or Entities. + */ Result lookup(Class indexedType, Object query); - Object query(String statement, Map params, TypeInformation typeInformation); - + /** + * Provides a cypher or gremlin query engine set up with a default entity converter. + */ QueryEngine queryEngineFor(QueryType type); /** @@ -130,7 +179,7 @@ public interface Neo4jOperations { /** * Executes the given Gremlin statement and returns the result packaged as QueryResult as Neo4j types, not - * Gremlin types. Table rows are converted to Map. + * Gremlin types. The Neo4j-Graph is provided as variable "g". Table rows are converted to Map. */ Result execute(String statement, Map params); @@ -141,27 +190,58 @@ public interface Neo4jOperations { */ Result traverse(Node startNode, TraversalDescription traversal); + /** + * Traverses the graph starting at the given node entity with the provided traversal description. The Path's of the + * traversal will be packaged into a QueryResult which can be easily converted into Nodes, Relationships or + * Graph-Entities. + */ Result traverse(Object start, TraversalDescription traversal); - Iterable traverse(Object entity, Class targetType, TraversalDescription traversalDescription); - /** * Converts the Iterable into a QueryResult object for uniform handling. E.g. * template.convert(node.getRelationships()); */ Result convert(Iterable iterable); + /** + * Converts a single object according to the configured ResultConverter of the Neo4j-Template. + */ T convert(Object value, Class type); + /** + * Provides all instances of a given entity type using the typerepresentation strategy configured for this template. + * This method is also provided by the appropriate repository. + */ ClosableIterable findAll(Class entityClass); + /** + * Provies the instance count a given entity type using the typerepresentation strategy configured for this template. + * This method is also provided by the appropriate repository. + */ long count(Class entityClass); + /** + * Projects a node or relationship entity to a different type. This can be used to use the same, schema free data + * in different contexts. + */ T projectTo(Object entity, Class targetType); + /** + * Stores the given entity in the graph, if the entity is already attached to the graph, the node is updated, otherwise + * a new node is created. Attached relationships will be cascaded. + * This method is also provided by the appropriate repository. + */ T save(T entity); + /** + * Removes the given node or relationship entity or node or relationship from the graph, the entity is first removed + * from all indexes and then deleted. + */ void remove(Object entity); + /** + * Returns the node or relationship that backs the given entity. + */ S getPersistentState(Object entity); + }