applied davids patch

This commit is contained in:
Michael Hunger
2010-08-09 23:53:18 +02:00
3 changed files with 125 additions and 52 deletions

View File

@@ -1,7 +1,9 @@
package org.springframework.persistence.graph.neo4j;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.FieldSignature;
import org.neo4j.graphdb.Direction;
@@ -118,7 +120,7 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
if (me == null) {
throw new IllegalStateException("Entity must have a backing Node");
}
org.neo4j.graphdb.Relationship singleRelationship = getRelationship(me, f);
org.neo4j.graphdb.Relationship singleRelationship = getRelationship(me, RelationshipInfo.forField(f));
// TODO is this correct
// [mh] i assume only for null
@@ -137,15 +139,8 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
}
private org.neo4j.graphdb.Relationship getRelationship(Node me, Field field) {
Relationship r = field.getAnnotation(Relationship.class);
if (r == null) {
RelationshipType type=DynamicRelationshipType.withName(getNeo4jPropertyName(field));
return me.getSingleRelationship(type, Direction.OUTGOING);
}
RelationshipType type = DynamicRelationshipType.withName(r.type());
org.neo4j.graphdb.Relationship singleRelationship = me.getSingleRelationship(type, r.direction().toNeo4jDir());
return singleRelationship;
private org.neo4j.graphdb.Relationship getRelationship(Node me, RelationshipInfo relInfo) {
return me.getSingleRelationship(relInfo.getType(), relInfo.getDirection());
}
@@ -162,10 +157,9 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
RelationshipInfo relInfo = RelationshipInfo.forField(f);
graphEntityFieldSet(entity, (NodeBacked) newVal, relInfo);
org.neo4j.graphdb.Relationship relationship=getRelationship(entity.getUnderlyingNode(), f);
if (relationship!=null) relationship.delete();
addRelationship(entity, newVal, f);
log.info("SET " + f + " -> Neo4J relationship with value=[" + newVal + "]");
return null;
}
@@ -175,29 +169,20 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
}
}
private void addRelationship(NodeBacked entity, Object newVal, Field f) {
Relationship r = f.getAnnotation(Relationship.class);
if (r == null) {
addRelationship(entity, (NodeBacked) newVal, getNeo4jPropertyName(f),Direction.OUTGOING);
} else {
addRelationship(entity, (NodeBacked) newVal, r.type(), r.direction().toNeo4jDir());
}
}
// todo what happens to the previous value, remove relationships?
private void addRelationship(NodeBacked entity, NodeBacked newVal, String relationshipName, Direction direction) {
RelationshipType type = DynamicRelationshipType.withName(relationshipName);
private void graphEntityFieldSet(NodeBacked entity, NodeBacked newVal, RelationshipInfo relationshipInfo) {
Node me = entity.getUnderlyingNode();
for ( org.neo4j.graphdb.Relationship relationship : me.getRelationships(relationshipInfo.getType(), relationshipInfo.getDirection()) ) {
relationship.delete();
}
if (newVal == null) {
return;
}
Node targetNode = newVal.getUnderlyingNode();
switch(direction) {
case OUTGOING : me.createRelationshipTo(targetNode, type); break;
case INCOMING : targetNode.createRelationshipTo(me, type); break;
case BOTH :
me.createRelationshipTo(targetNode, type);
targetNode.createRelationshipTo(me, type);
break;
switch(relationshipInfo.getDirection()) {
case OUTGOING : me.createRelationshipTo(targetNode, relationshipInfo.getType()); break;
case INCOMING : targetNode.createRelationshipTo(me, relationshipInfo.getType()); break;
default : throw new IllegalArgumentException("invalid direction "+relationshipInfo.getDirection());
}
}
@@ -206,9 +191,31 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
return NodeBacked.class.isAssignableFrom(f.getType());
}
private String getNeo4jPropertyName(Field field) {
private static String getNeo4jPropertyName(Field field) {
return String.format("%s.%s",field.getDeclaringClass().getSimpleName(),field.getName());
}
public static class RelationshipInfo {
private final Direction direction;
private final RelationshipType type;
public RelationshipInfo(String typeName, Direction direction) {
this.type = DynamicRelationshipType.withName(typeName);
this.direction=direction;
}
public static RelationshipInfo forField(Field field) {
final Relationship relationshipAnnotation = field.getAnnotation(Relationship.class);
if (relationshipAnnotation!=null) return new RelationshipInfo(relationshipAnnotation.type(),relationshipAnnotation.direction().toNeo4jDir());
return new RelationshipInfo(getNeo4jPropertyName(field),Direction.OUTGOING);
}
public RelationshipType getType() {
return type;
}
public Direction getDirection() {
return direction;
}
}
}

View File

@@ -18,8 +18,14 @@ public class Person {
Person spouse;
@Relationship(type="mother",direction=Direction.BOTH)
@Relationship(type="mother", direction=Direction.OUTGOING)
Person mother;
@Relationship(type="boss", direction=Direction.INCOMING)
Person boss;
@Relationship(type="friend", direction=Direction.BOTH)
Person friend;
// @Property(serialize=SerializationPolicy.STRING, index=true, queryable=true, removeOnReset=true)
// Date birthday;
@@ -61,18 +67,31 @@ public class Person {
return spouse;
}
public void setSpouse(Person spouse) {
this.spouse = spouse;
}
public Person getMother() {
return mother;
}
public void setMother(Person mother) {
this.mother = mother;
}
public Person getBoss() {
return boss;
}
public void setBoss(Person boss) {
this.boss = boss;
}
public Person getFriend() {
return friend;
}
public void setFriend(Person friend) {
this.friend = friend;
}
}

View File

@@ -5,6 +5,7 @@ import junit.framework.Assert;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
@@ -19,12 +20,16 @@ import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class Neo4jGraphPersistenceTest {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private EntityInstantiator<NodeBacked,Node> nodeInstantiator;
@@ -43,44 +48,86 @@ public class Neo4jGraphPersistenceTest {
@Transactional
@Rollback(false)
public void testUserConstructor() {
int age = 39;
Person p = new Person("Rod", age);
Person p = new Person("Rod", 39);
Assert.assertEquals(p.getName(), p.getUnderlyingNode().getProperty("Person.name"));
Assert.assertEquals(p.getAge(), p.getUnderlyingNode().getProperty("Person.age"));
insertedId = p.getId();
}
@Test
@Transactional
public void testSetProperties() {
Person p = new Person("Foo", 2);
p.setName("Michael");
p.setAge(35);
Assert.assertEquals("Michael", p.getUnderlyingNode().getProperty("Person.name"));
Assert.assertEquals(35, p.getUnderlyingNode().getProperty("Person.age"));
}
@Test
@Transactional
public void testCreateRelationshipWithoutAnnotationOnSet() {
Person p = new Person("Michael", 35);
Person spouse=new Person("Tina",36);
Person spouse = new Person("Tina",36);
p.setSpouse(spouse);
Assert.assertEquals("Tina", p.getSpouse().getUnderlyingNode().getProperty("Person.name"));
Node spouseNode=p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), org.neo4j.graphdb.Direction.OUTGOING).getEndNode();
Assert.assertEquals(spouse.getUnderlyingNode(), spouseNode);
Assert.assertEquals(spouse, p.getSpouse());
}
@Test
@Ignore
@Transactional
public void testCreateRelationshipWithAnnotationOnSet() {
Person p = new Person("Michael", 35);
Person mother=new Person("Gabi",60);
Person mother = new Person("Gabi",60);
p.setMother(mother);
Assert.assertEquals("Gabi", p.getMother().getUnderlyingNode().getProperty("Person.name"));
Node motherNode=p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("mother"), org.neo4j.graphdb.Direction.BOTH).getEndNode();
Node motherNode = p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("mother"), org.neo4j.graphdb.Direction.OUTGOING).getEndNode();
Assert.assertEquals(mother.getUnderlyingNode(), motherNode);
Assert.assertEquals(mother, p.getMother());
}
@Test
@Transactional
public void testDeleteRelationship() {
Person p = new Person("Michael", 35);
Person spouse = new Person("Tina", 36);
p.setSpouse(spouse);
p.setSpouse(null);
Assert.assertNull(p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), org.neo4j.graphdb.Direction.OUTGOING));
Assert.assertNull(p.getSpouse());
}
// TODO test delete relationship
// TODO test delete previous relationship
// TODO test incoming relationship
// TODO test bidirectional relationship
// TODO test remove property (set to null)
@Test
@Transactional
public void testDeletePreviousRelationshipOnNewRelationship() {
Person p = new Person("Michael", 35);
Person spouse = new Person("Tina", 36);
Person friend = new Person("Helga", 34);
p.setSpouse(spouse);
p.setSpouse(friend);
Assert.assertEquals(friend.getUnderlyingNode(), p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), org.neo4j.graphdb.Direction.OUTGOING).getEndNode());
Assert.assertEquals(friend, p.getSpouse());
}
@Test
@Transactional
public void testCreateIncomingRelationshipWithAnnotationOnSet() {
Person p = new Person("David", 25);
Person boss = new Person("Emil", 32);
p.setBoss(boss);
Assert.assertEquals(boss.getUnderlyingNode(), p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("boss"), org.neo4j.graphdb.Direction.INCOMING).getStartNode());
Assert.assertEquals(boss, p.getBoss());
}
@Ignore
@Test
@Transactional
public void testBidirectionalRelationshipWithAnnotationOnSet() {
Person p = new Person("Michael", 35);
Person friend = new Person("David", 25);
p.setFriend(friend);
}
@Test
@Transactional
public void testInstantiatedFinder() {