added tests for cypher-integration, removed circular dependency check

This commit is contained in:
Michael Hunger
2011-06-13 11:37:52 +02:00
parent 2f0bfcaa8c
commit b627f762d6
21 changed files with 349 additions and 85 deletions

View File

@@ -7,7 +7,6 @@ Changes in version 1.1.0.M1 (2011-06-13)
* updated dependency to AspectJ 1.6.12.M1 (also available with STS 2.7.0.M2)
* fixed errors in the REST binding (multiple property setting, index operations)
* added sample build scripts for gradle and ant/ivy
* cleanup of refrenced nodes/rels after transaction rollback
* added support for the Neo4j query language "Cypher" in entity annotations, introduced methods and repositories
* added support for self-relationships
* elementClass annotation attribute is now optional

View File

@@ -16,9 +16,6 @@
package org.springframework.data.graph.annotation;
import org.springframework.data.graph.core.FieldTraversalDescriptionBuilder;
import org.springframework.data.graph.core.NodeBacked;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,7 +33,7 @@ import java.lang.annotation.Target;
* @since 15.09.2010
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface GraphQuery {
/**
* @return Query to be executed %d will be replaced by the node-id of the current entity other placeholders by the given params

View File

@@ -69,10 +69,6 @@ public abstract class AbstractNodeRelationshipFieldAccessor<ENTITY extends Graph
}
}
protected void checkNoCircularReference(Node node, Set<STATE> targetNodes) {
if (targetNodes.contains(node)) throw new InvalidDataAccessApiUsageException("Cannot create a circular reference to "+ targetNodes);
}
protected Set<STATE> checkTargetIsSetOfNodebacked(Object newVal) {
if (!(newVal instanceof Set)) {
throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass());

View File

@@ -48,12 +48,13 @@ public class NodeDelegatingFieldAccessorFactory extends DelegatingFieldAccessorF
return Arrays.<FieldAccessorFactory<?>>asList(
new IdFieldAccessorFactory(),
new TransientFieldAccessorFactory(),
new TraversalFieldAccessorFactory(),
new QueryFieldAccessorFactory(),
new PropertyFieldAccessorFactory(graphDatabaseContext.getConversionService()),
new ConvertingNodePropertyFieldAccessorFactory(graphDatabaseContext.getConversionService()),
new SingleRelationshipFieldAccessorFactory(graphDatabaseContext),
new OneToNRelationshipFieldAccessorFactory(graphDatabaseContext),
new ReadOnlyOneToNRelationshipFieldAccessorFactory(graphDatabaseContext),
new TraversalFieldAccessorFactory(),
new OneToNRelationshipEntityFieldAccessorFactory(graphDatabaseContext)
);
}

View File

@@ -18,7 +18,7 @@ package org.springframework.data.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.data.graph.annotation.RelatedTo;
import org.springframework.data.graph.core.NodeBacked;
import org.springframework.data.graph.neo4j.support.GraphDatabaseContext;
@@ -39,14 +39,15 @@ public abstract class NodeRelationshipFieldAccessorFactory implements FieldAcces
this.graphDatabaseContext = graphDatabaseContext;
}
protected Class<? extends NodeBacked> targetFrom(Field field) {
@SuppressWarnings({"unchecked"})
protected Class<? extends NodeBacked> targetFrom(Field field, RelatedTo relatedTo) {
if (relatedTo!=null && relatedTo.elementClass()!=NodeBacked.class) return relatedTo.elementClass();
if (Iterable.class.isAssignableFrom(field.getType())) {
return (Class<? extends NodeBacked>) GenericCollectionTypeResolver.getCollectionFieldType(field);
}
return (Class<? extends NodeBacked>) field.getType();
}
protected Class<? extends NodeBacked> targetFrom(RelatedTo relAnnotation) {
return (Class<? extends NodeBacked>) relAnnotation.elementClass();
}
protected Direction dirFrom(RelatedTo relAnnotation) {
return relAnnotation.direction().toNeo4jDir();
}
@@ -69,11 +70,6 @@ public abstract class NodeRelationshipFieldAccessorFactory implements FieldAcces
protected boolean hasValidRelationshipAnnotation(Field field) {
final RelatedTo relAnnotation = getRelationshipAnnotation(field);
if (relAnnotation == null) return false;
boolean hasElementClass = !relAnnotation.elementClass().equals(NodeBacked.class);
if (!hasElementClass) throw new InvalidDataAccessApiUsageException(String.format(
"Missing mandatory attribute @RelatedTo.elementClass for one-to-N relationship field %s in class: %s",
field.getName(), field.getDeclaringClass().getName()));
return true;
return (relAnnotation != null);
}
}

View File

@@ -44,7 +44,7 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel
@Override
public FieldAccessor<NodeBacked> forField(final Field field) {
final RelatedTo relAnnotation = getRelationshipAnnotation(field);
return new OneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext,field);
return new OneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field);
}
public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
@@ -60,7 +60,6 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel
return null;
}
final Set<Node> targetNodes = checkTargetIsSetOfNodebacked(newVal);
checkNoCircularReference(node, targetNodes);
removeMissingRelationships(node, targetNodes);
createAddedRelationships(node, targetNodes);
return createManagedSet(entity, (Set<NodeBacked>) newVal);

View File

@@ -76,16 +76,16 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory<NodeBacke
@Override
public Object getValue(final NodeBacked nodeBacked) {
final String queryString = String.format(this.query, createPlaceholderParams(nodeBacked));
final String queryString = String.format(this.query, (Object[])createPlaceholderParams(nodeBacked));
return doReturn(executeQuery(nodeBacked, queryString));
}
private Object executeQuery(NodeBacked nodeBacked, String queryString) {
if (iterableResult) {
if (target.equals(Object.class)) return nodeBacked.findAllByQuery(queryString);
nodeBacked.findAllByQuery(queryString, this.target);
return nodeBacked.findAllByQuery(queryString, this.target);
}
return nodeBacked.findByQuery(query,this.target);
return nodeBacked.findByQuery(queryString,this.target);
}
private Object[] createPlaceholderParams(NodeBacked nodeBacked) {

View File

@@ -39,7 +39,7 @@ public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends NodeRelation
@Override
public FieldAccessor<NodeBacked> forField(final Field field) {
final RelatedTo relAnnotation = getRelationshipAnnotation(field);
return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext,field);
return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field);
}
public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor {

View File

@@ -44,8 +44,8 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel
public FieldAccessor<NodeBacked> forField(final Field field) {
final RelatedTo relAnnotation = getRelationshipAnnotation(field);
if (relAnnotation == null)
return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field), graphDatabaseContext, field);
return new SingleRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext,field);
return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field, relAnnotation), graphDatabaseContext, field);
return new SingleRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field, relAnnotation), graphDatabaseContext,field);
}
public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
@@ -61,7 +61,6 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel
return null;
}
final Set<Node> target=checkTargetIsSetOfNodebacked(Collections.singleton(newVal));
checkNoCircularReference(node,target);
removeMissingRelationships(node, target);
createAddedRelationships(node,target);
return newVal;

View File

@@ -136,6 +136,8 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
return Arrays.<FieldAccessorFactory<?>>asList(
//new IdFieldAccessorFactory(),
//new TransientFieldAccessorFactory(),
new TraversalFieldAccessorFactory(),
new QueryFieldAccessorFactory(),
newPropertyFieldAccessorFactory(),
newConvertingNodePropertyFieldAccessorFactory(),
new SingleRelationshipFieldAccessorFactory(getGraphDatabaseContext()) {
@@ -146,7 +148,6 @@ public class PartialNodeEntityState<ENTITY extends NodeBacked> extends DefaultEn
},
new OneToNRelationshipFieldAccessorFactory(getGraphDatabaseContext()),
new ReadOnlyOneToNRelationshipFieldAccessorFactory(getGraphDatabaseContext()),
new TraversalFieldAccessorFactory(),
new OneToNRelationshipEntityFieldAccessorFactory(getGraphDatabaseContext())
);
}

View File

@@ -29,6 +29,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.graph.core.TypeRepresentationStrategy;
import org.springframework.data.graph.neo4j.support.GraphDatabaseContext;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -105,7 +106,8 @@ public class QueryExecutor {
return new IterableWrapper<Map<String, Object>, Map<String, Object>>(result) {
@Override
protected Map<String, Object> underlyingObjectToObject(Map<String, Object> row) {
for (Map.Entry<String, Object> entry : row.entrySet()) {
Map<String,Object> newRow=new HashMap<String,Object>(row); // todo performance
for (Map.Entry<String, Object> entry : newRow.entrySet()) {
Object value = convertValue(entry.getValue());
if (value != entry.getValue()) {
entry.setValue(value);

View File

@@ -43,7 +43,7 @@ public class Group {
public final static String OTHER_NAME_INDEX="other_name";
public static final String SEARCH_GROUPS_INDEX = "search-groups";
@RelatedTo(direction = Direction.OUTGOING, elementClass = Person.class)
@RelatedTo(direction = Direction.OUTGOING)
private Collection<Person> persons;
@RelatedTo(type = "persons", elementClass = Person.class)

View File

@@ -16,10 +16,7 @@
package org.springframework.data.graph.neo4j;
import org.springframework.data.graph.annotation.GraphId;
import org.springframework.data.graph.annotation.NodeEntity;
import org.springframework.data.graph.annotation.RelatedTo;
import org.springframework.data.graph.annotation.RelatedToVia;
import org.springframework.data.graph.annotation.*;
import org.springframework.data.graph.core.Direction;
import org.springframework.data.graph.neo4j.annotation.Indexed;
@@ -27,9 +24,10 @@ import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.Map;
@NodeEntity(useShortNames = false)
@NodeEntity
public class Person {
public static final String NAME_INDEX = "name_index";
@@ -69,6 +67,34 @@ public class Person {
@RelatedToVia(type = "knows", elementClass = Friendship.class)
private Iterable<Friendship> friendships;
@GraphQuery(value = "start person=(%d) match (person)<-[:boss]-(boss) return boss")
private Person bossByQuery;
@GraphQuery(value = "start person=(%d) match (person)<-[:boss]-(boss) return boss.%s",params = "name")
private String bossName;
@GraphQuery(value = "start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
private Iterable<Person> otherTeamMembers;
@GraphQuery(value = "start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
private Iterable<Map<String,Object>> otherTeamMemberData;
public String getBossName() {
return bossName;
}
public Iterable<Person> getOtherTeamMembers() {
return otherTeamMembers;
}
public Iterable<Map<String, Object>> getOtherTeamMemberData() {
return otherTeamMemberData;
}
public Person getBossByQuery() {
return bossByQuery;
}
public Person() {
}

View File

@@ -96,7 +96,7 @@ public class IndexTest {
Person me = persistedPerson(NAME_VALUE, 35);
Person spouse = persistedPerson(NAME_VALUE3, 36);
me.setSpouse(spouse);
final Person foundMe = this.personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE);
final Person foundMe = this.personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE);
assertEquals(spouse, foundMe.getSpouse());
}
@@ -242,14 +242,14 @@ public class IndexTest {
@Transactional
public void testFindAllPersonByIndexOnAnnotatedField() {
Person person = persistedPerson(NAME_VALUE, 35);
final Person found = personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE);
final Person found = personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE);
assertEquals(person, found);
}
@Test
public void findsPersonByIndexOnAnnotatedIntFieldInSeparateTransactions() {
Person person = persistedPerson(NAME_VALUE, 35);
final Person found = personFinder.findByPropertyValue("Person.age", 35);
final Person found = personFinder.findByPropertyValue("age", 35);
assertEquals("person found inside range", person, found);
}
@@ -257,7 +257,7 @@ public class IndexTest {
@Transactional
public void testRangeQueryPersonByIndexOnAnnotatedField() {
Person person = persistedPerson(NAME_VALUE, 35);
final Person found = personFinder.findAllByRange("Person.age", 10, 40).iterator().next();
final Person found = personFinder.findAllByRange("age", 10, 40).iterator().next();
assertEquals("person found inside range", person, found);
}
@@ -265,7 +265,7 @@ public class IndexTest {
@Transactional
public void testOutsideRangeQueryPersonByIndexOnAnnotatedField() {
Person person = persistedPerson(NAME_VALUE, 35);
Iterable<Person> emptyResult = personFinder.findAllByRange("Person.age", 0, 34);
Iterable<Person> emptyResult = personFinder.findAllByRange("age", 0, 34);
assertFalse("nothing found outside range", emptyResult.iterator().hasNext());
}
@@ -275,7 +275,7 @@ public class IndexTest {
public void testFindAllPersonByIndexOnAnnotatedFieldWithAtIndexed() {
Person person = persistedPerson(NAME_VALUE, 35);
person.setNickname("Mike");
final Person found = personFinder.findByPropertyValue( "Person.nickname", "Mike");
final Person found = personFinder.findByPropertyValue( "nickname", "Mike");
assertEquals(person, found);
}
@@ -293,11 +293,11 @@ public class IndexTest {
@Transactional
public void testNodeCanbBeIndexedTwice() {
final Person p = persistedPerson(NAME_VALUE2, 30);
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE2));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE2));
p.setName(NAME_VALUE);
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE));
p.setName(NAME_VALUE2);
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE2));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE2));
}
@Test
public void testNodeCanbBeIndexedTwiceInDifferentTransactions() {
@@ -310,7 +310,7 @@ public class IndexTest {
} finally {
tx.finish();
}
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE2));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE2));
try {
tx = graphDatabaseContext.beginTx();
p.setName(NAME_VALUE);
@@ -318,7 +318,7 @@ public class IndexTest {
} finally {
tx.finish();
}
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE));
try {
tx = graphDatabaseContext.beginTx();
p.setName(NAME_VALUE2);
@@ -326,7 +326,7 @@ public class IndexTest {
} finally {
tx.finish();
}
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "Person.name", NAME_VALUE2));
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE2));
}
@Test

View File

@@ -69,7 +69,7 @@ public class ModificationOutsideOfTransactionTest
assertEquals(36, p.getAge());
assertFalse(hasPersistentState(p));
p.persist();
assertEquals(36, nodeFor(p).getProperty("Person.age"));
assertEquals(36, nodeFor(p).getProperty("age"));
}
@Test
@@ -160,7 +160,7 @@ public class ModificationOutsideOfTransactionTest
Person p = persistedPerson( "Michael", 35 );
p.setAge( 25 );
assertEquals(25, p.getAge());
assertEquals( 35, nodeFor( p ).getProperty("Person.age") );
assertEquals( 35, nodeFor( p ).getProperty("age") );
}
@Ignore
@@ -200,7 +200,7 @@ public class ModificationOutsideOfTransactionTest
p.setSpouse( spouse );
assertEquals( spouse, p.getSpouse() );
assertThat( nodeFor( p ), hasNoRelationship( "Person.spouse",spouse.getPersistentState() ) );
assertThat( nodeFor( p ), hasNoRelationship( "spouse",spouse.getPersistentState() ) );
Person spouse2 = persistedPerson( "Rana", 5 );
@@ -218,7 +218,7 @@ public class ModificationOutsideOfTransactionTest
p.persist();
assertEquals( spouse, p.getSpouse() );
assertThat( nodeFor( p ), hasRelationship( "Person.spouse" ) );
assertThat( nodeFor( p ), hasRelationship( "spouse" ) );
Person spouse2 = persistedPerson( "Rana", 5 );

View File

@@ -0,0 +1,80 @@
/**
* 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;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.graph.neo4j.Person;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Map;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.internal.matchers.IsCollectionContaining.hasItems;
/**
* @author mh
* @since 13.06.11
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml"})
@Transactional
public class NodeEntityQueryTest {
@Autowired
GraphDatabaseContext graphDatabaseContext;
private TestTeam testTeam;
private Person michael;
@Before
public void setUp() throws Exception {
testTeam = new TestTeam(graphDatabaseContext);
testTeam.createSDGTeam();
michael = testTeam.michael;
}
@Test
@Transactional
public void testQueryVariableRelationshipSingleResult() throws Exception {
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(michael.getOtherTeamMemberData());
assertThat(result,hasItems(testTeam.simpleRowFor(testTeam.emil, "member"), testTeam.simpleRowFor(testTeam.david, "member")));
}
@Test
public void testQueryVariableRelationshipIterableResult() throws Exception {
final Collection<Person> result = IteratorUtil.asCollection(michael.getOtherTeamMembers());
assertThat(result,hasItems(testTeam.david,testTeam.emil));
}
@Test
public void testQueryVariableSingleResultPerson() throws Exception {
assertEquals(testTeam.emil,michael.getBossByQuery());
}
@Test
public void testQueryVariableStringResult() throws Exception {
assertEquals(testTeam.emil.getName(),michael.getBossName());
}
}

View File

@@ -65,7 +65,7 @@ public class NodeEntityRelationshipTest {
Person p = persistedPerson("Michael", 35);
Person spouse = persistedPerson("Tina", 36);
p.setSpouse(spouse);
Node spouseNode=p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), Direction.OUTGOING).getEndNode();
Node spouseNode=p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("spouse"), Direction.OUTGOING).getEndNode();
assertEquals(spouse.getPersistentState(), spouseNode);
assertEquals(spouse, p.getSpouse());
}
@@ -76,7 +76,7 @@ public class NodeEntityRelationshipTest {
Person p = persistedPerson("Michael", 35);
Person mother = persistedPerson("Gabi", 60);
p.setMother(mother);
Node motherNode = p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("Person.mother"), Direction.OUTGOING).getEndNode();
Node motherNode = p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("mother"), Direction.OUTGOING).getEndNode();
assertEquals(mother.getPersistentState(), motherNode);
assertEquals(mother, p.getMother());
}
@@ -88,7 +88,7 @@ public class NodeEntityRelationshipTest {
Person spouse = persistedPerson("Tina", 36);
p.setSpouse(spouse);
p.setSpouse(null);
Assert.assertNull(p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), Direction.OUTGOING));
Assert.assertNull(p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("spouse"), Direction.OUTGOING));
Assert.assertNull(p.getSpouse());
}
@@ -100,7 +100,7 @@ public class NodeEntityRelationshipTest {
Person friend = persistedPerson("Helga", 34);
p.setSpouse(spouse);
p.setSpouse(friend);
assertEquals(friend.getPersistentState(), p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), Direction.OUTGOING).getEndNode());
assertEquals(friend.getPersistentState(), p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("spouse"), Direction.OUTGOING).getEndNode());
assertEquals(friend, p.getSpouse());
}
@@ -114,11 +114,12 @@ public class NodeEntityRelationshipTest {
assertEquals(boss, p.getBoss());
}
@Test(expected = InvalidDataAccessApiUsageException.class)
@Transactional
public void testCircularRelationship() {
public void testAllowsCircularRelationship() {
Person p = persistedPerson("Michael", 35);
p.setSpouse(p);
p.setBoss(p);
assertEquals("created self-referencing relationship",p,p.getBoss());
}
@Test
@Transactional

View File

@@ -64,11 +64,11 @@ import static org.springframework.data.graph.neo4j.Person.persistedPerson;
@Transactional
public void testUserConstructor() {
Person p = persistedPerson("Rod", 39);
assertEquals(p.getName(), p.getPersistentState().getProperty("Person.name"));
assertEquals(p.getAge(), p.getPersistentState().getProperty("Person.age"));
assertEquals(p.getName(), p.getPersistentState().getProperty("name"));
assertEquals(p.getAge(), p.getPersistentState().getProperty("age"));
Person found = graphDatabaseContext.createEntityFromState(graphDatabaseContext.getNodeById(p.getNodeId()), Person.class);
assertEquals("Rod", found.getPersistentState().getProperty("Person.name"));
assertEquals(39, found.getPersistentState().getProperty("Person.age"));
assertEquals("Rod", found.getPersistentState().getProperty("name"));
assertEquals(39, found.getPersistentState().getProperty("age"));
}
@Test
@@ -82,8 +82,8 @@ import static org.springframework.data.graph.neo4j.Person.persistedPerson;
p.setName( name );
p.setAge( age );
p.setHeight( height );
assertEquals( name, p.getPersistentState().getProperty( "Person.name" ) );
assertEquals( age, p.getPersistentState().getProperty("Person.age"));
assertEquals( name, p.getPersistentState().getProperty( "name" ) );
assertEquals( age, p.getPersistentState().getProperty("age"));
assertEquals((Short)height, p.getHeight());
}
@@ -93,7 +93,7 @@ import static org.springframework.data.graph.neo4j.Person.persistedPerson;
Person p = persistedPerson("Foo", 2);
p.setHeight((short)182);
assertEquals((Short)(short)182, p.getHeight());
assertEquals((short)182, p.getPersistentState().getProperty("Person.height"));
assertEquals((short)182, p.getPersistentState().getProperty("height"));
}
@Test
@Transactional

View File

@@ -18,6 +18,7 @@ package org.springframework.data.graph.neo4j.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.NotFoundException;
@@ -59,14 +60,14 @@ public class PropertyTest {
public void testSetPropertyEnum() {
Person p = persistedPerson("Michael", 35);
p.setPersonality(Personality.EXTROVERT);
assertEquals("Wrong enum serialization.", "EXTROVERT", p.getPersistentState().getProperty("Person.personality"));
assertEquals("Wrong enum serialization.", "EXTROVERT", p.getPersistentState().getProperty("personality"));
}
@Test
@Transactional
public void testGetPropertyEnum() {
Person p = persistedPerson("Michael", 35);
p.getPersistentState().setProperty("Person.personality", "EXTROVERT");
p.getPersistentState().setProperty("personality", "EXTROVERT");
assertEquals("Did not deserialize property value properly.", Personality.EXTROVERT, p.getPersonality());
}
@@ -75,7 +76,7 @@ public class PropertyTest {
public void testSetTransientPropertyFieldNotManaged() {
Person p = persistedPerson("Michael", 35);
p.setThought("food");
p.getPersistentState().getProperty("Person.thought");
p.getPersistentState().getProperty("thought");
}
@Test
@@ -83,7 +84,7 @@ public class PropertyTest {
public void testGetTransientPropertyFieldNotManaged() {
Person p = persistedPerson("Michael", 35);
p.setThought("food");
p.getPersistentState().setProperty("Person.thought", "sleep");
p.getPersistentState().setProperty("thought", "sleep");
assertEquals("Should not have read transient value from graph.", "food", p.getThought());
}
@Test
@@ -143,16 +144,4 @@ public class PropertyTest {
Friendship f = p.knows(p2);
assertEquals("Wrong ID.", (Long)f.getPersistentState().getId(), f.getRelationshipId());
}
@Test(expected = InvalidDataAccessApiUsageException.class)
@Transactional
public void testFailFastOnMisconfiguredOneToNProperty() {
new InvalidOneToNEntity();
}
@Test(expected = InvalidDataAccessApiUsageException.class)
@Transactional
public void testFailFastOnMisconfiguredReadOnlyOneToNProperty() {
new InvalidReadOnlyOneToNEntity();
}
}

View File

@@ -0,0 +1,58 @@
/**
* 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;
import org.neo4j.helpers.collection.MapUtil;
import org.springframework.data.graph.neo4j.Group;
import org.springframework.data.graph.neo4j.Person;
import org.springframework.data.graph.neo4j.Personality;
import java.util.Map;
/**
* @author mh
* @since 13.06.11
*/
public class TestTeam {
private final GraphDatabaseContext graphDatabaseContext;
public Person michael;
public Person emil;
public Person david;
public Group sdg;
public TestTeam(GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
public void createSDGTeam() {
michael = Person.persistedPerson("Michael", 36);
emil = Person.persistedPerson("Emil", 30);
michael.setBoss(emil);
michael.setPersonality(Personality.EXTROVERT);
david = Person.persistedPerson("David", 25);
david.setBoss(emil);
sdg = new Group().persist();
sdg.setName("SDG");
sdg.addPerson(michael);
sdg.addPerson(emil);
sdg.addPerson(david);
}
public Map<String, Object> simpleRowFor(final Person person, String prefix) {
return MapUtil.map(prefix+".name", person.getName(), prefix+".age", person.getAge());
}
}

View File

@@ -0,0 +1,120 @@
/**
* 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.query;
import org.junit.Before;
import org.junit.Test;
import org.junit.internal.matchers.IsCollectionContaining;
import org.junit.runner.RunWith;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.graph.neo4j.Group;
import org.springframework.data.graph.neo4j.Person;
import org.springframework.data.graph.neo4j.Personality;
import org.springframework.data.graph.neo4j.support.GraphDatabaseContext;
import org.springframework.data.graph.neo4j.support.TestTeam;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Map;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author mh
* @since 13.06.11
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml"})
@Transactional
public class QueryExecutorTest {
@Autowired
GraphDatabaseContext graphDatabaseContext;
private QueryExecutor queryExecutor;
private TestTeam testTeam;
private Person michael;
@Before
public void setUp() throws Exception {
testTeam = new TestTeam(graphDatabaseContext);
testTeam.createSDGTeam();
queryExecutor = new QueryExecutor(graphDatabaseContext);
michael = testTeam.michael;
}
@Test
@Transactional
public void testQueryList() throws Exception {
final String queryString = String.format("start person=(%d,%d) return person.name, person.age", michael.getNodeId(), testTeam.david.getNodeId());
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryExecutor.query(queryString));
assertEquals(asList(testTeam.simpleRowFor(michael,"person"),testTeam.simpleRowFor(testTeam.david,"person")),result);
}
@Test
public void testQueryListOfTypePerson() throws Exception {
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:boss]- (boss) return boss", michael.getName());
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
assertEquals(asList(testTeam.emil),result);
}
@Test
public void testQueryOtherTeamMembers() throws Exception {
final String queryString = String.format("start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member", michael.getNodeId());
System.out.println("testTeam = " + testTeam.sdg.getPersons());
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
assertThat(result, IsCollectionContaining.hasItems(testTeam.david, testTeam.emil));
}
@Test
public void testQueryAllTeamMembersByTeam() throws Exception {
final String queryString = String.format("start team=(Group,name,\"%s\") match (team)-[:persons]->(member) return member", testTeam.sdg.getName());
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
assertThat(result, IsCollectionContaining.hasItems(testTeam.david,testTeam.michael));
}
@Test
public void testQueryForObjectAsGroup() throws Exception {
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team", michael.getName());
final Group result = queryExecutor.queryForObject(queryString, Group.class);
assertEquals(testTeam.sdg,result);
}
@Test
public void testQueryForObjectAsString() throws Exception {
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team.name", michael.getName());
final String result = queryExecutor.queryForObject(queryString, String.class);
assertEquals(testTeam.sdg.getName(),result);
}
@Test
public void testQueryForObjectAsEnum() throws Exception {
final String queryString = String.format("start person=(name_index,name,\"%s\") return person.personality", michael.getName());
final Personality result = queryExecutor.queryForObject(queryString, Personality.class);
assertEquals(michael.getPersonality(),result);
}
}