started merging GraphDatabaseContext and Neo4jTemplate, unifying methods and conversion approach.

Renamed QueryResult to Result, ConvertedResult to EndResult
More advanced index-check handling in GDC.IndexProvider
Removed DirectGraphDatabaseRepositoryFactory in favor of gdc.repositoryFor()
This commit is contained in:
Michael Hunger
2011-10-16 17:23:46 +02:00
parent 98944fb069
commit 2ae9abee7d
51 changed files with 1068 additions and 415 deletions

View File

@@ -16,13 +16,9 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Developer;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@@ -35,11 +31,6 @@ import static org.junit.Assert.assertNull;
public class AttachEntityTest extends EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@Test
@Transactional
public void entityShouldHaveNoNode() {

View File

@@ -24,7 +24,6 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.aspects.FriendshipRepository;
import org.springframework.data.neo4j.aspects.GroupRepository;
import org.springframework.data.neo4j.aspects.PersonRepository;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.transaction.BeforeTransaction;
@@ -45,8 +44,6 @@ public class EntityTestBase {
@Autowired protected GraphDatabaseService graphDatabaseService;
@Autowired protected DirectGraphRepositoryFactory graphRepositoryFactory;
@Autowired protected PersonRepository personRepository;
@Autowired protected GroupRepository groupRepository;
@Autowired protected FriendshipRepository friendshipRepository;

View File

@@ -39,7 +39,6 @@ import static org.neo4j.helpers.collection.IteratorUtil.asCollection;
import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = {"classpath:repository-namespace-config-context.xml"})
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/aspects/support/Neo4jGraphPersistenceTest-context.xml"})
public class FinderTest extends EntityTestBase {

View File

@@ -16,10 +16,7 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
@@ -28,17 +25,15 @@ import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.aspects.*;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.aspects.Friendship;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.aspects.SubGroup;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
@@ -57,28 +52,6 @@ public class IndexTest extends EntityTestBase {
private static final String NAME_VALUE = "aName";
private static final String NAME_VALUE2 = "aSecondName";
private static final String NAME_VALUE3 = "aThirdName";
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
protected GraphRepository<Group> groupFinder;
protected GraphRepository<Person> personFinder;
@Autowired protected PersonRepository personRepository;
@Autowired protected GroupRepository groupRepository;
@Before
public void setUp() throws Exception {
groupFinder = graphRepositoryFactory.createGraphRepository(Group.class);
personFinder = graphRepositoryFactory.createGraphRepository(Person.class);
}
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Test
@Transactional
@@ -87,7 +60,7 @@ public class IndexTest extends EntityTestBase {
Person p2 = persistedPerson(NAME_VALUE2, 25);
Friendship friendship = p.knows(p2);
friendship.setYears(1);
GraphRepository<Friendship> friendshipFinder = graphRepositoryFactory.createGraphRepository(Friendship.class);
GraphRepository<Friendship> friendshipFinder = graphDatabaseContext.repositoryFor(Friendship.class);
assertEquals(friendship, friendshipFinder.findByPropertyValue("Friendship.years", 1));
}
@@ -114,7 +87,7 @@ public class IndexTest extends EntityTestBase {
} finally {
tx.finish();
}
final Group found = groupFinder.findByPropertyValue( NAME, NAME_VALUE);
final Group found = this.groupRepository.findByPropertyValue(NAME, NAME_VALUE);
assertNull("Group.name removed from index", found);
}
@@ -131,7 +104,7 @@ public class IndexTest extends EntityTestBase {
} finally {
tx.finish();
}
final Group found = groupFinder.findByPropertyValue( NAME, NAME_VALUE);
final Group found = this.groupRepository.findByPropertyValue(NAME, NAME_VALUE);
assertNull("Group.name removed from index", found);
}
@@ -144,7 +117,7 @@ public class IndexTest extends EntityTestBase {
public void testFindGroupByIndex() {
Group group = persist(new Group());
group.setName(NAME_VALUE);
final Group found = groupFinder.findByPropertyValue(NAME, NAME_VALUE);
final Group found = this.groupRepository.findByPropertyValue(NAME, NAME_VALUE);
assertEquals(group, found);
}
@@ -164,7 +137,7 @@ public class IndexTest extends EntityTestBase {
public void testFindGroupByAlternativeFieldNameIndex() {
Group group = persist(new Group());
group.setOtherName(NAME_VALUE);
final Group found = groupFinder.findByPropertyValue(Group.OTHER_NAME_INDEX, NAME_VALUE);
final Group found = this.groupRepository.findByPropertyValue(Group.OTHER_NAME_INDEX, NAME_VALUE);
assertEquals(group, found);
}
@@ -177,18 +150,10 @@ public class IndexTest extends EntityTestBase {
@Indexed(fulltext = true, indexName = "InvalidIndexed")
String fullTextDefaultIndexName;
public String getFulltextNoIndexName() {
return fulltextNoIndexName;
}
public void setFulltextNoIndexName(String fulltextNoIndexName) {
this.fulltextNoIndexName = fulltextNoIndexName;
}
public String getFullTextDefaultIndexName() {
return fullTextDefaultIndexName;
}
public void setFullTextDefaultIndexName(String fullTextDefaultIndexName) {
this.fullTextDefaultIndexName = fullTextDefaultIndexName;
}
@@ -215,7 +180,7 @@ public class IndexTest extends EntityTestBase {
public void testDontFindGroupByNonIndexedFieldWithAnnotation() {
Group group = persist(new Group());
group.setUnindexedName("value-unindexedName");
final Group found = groupFinder.findByPropertyValue("unindexedName", "value-unindexedName");
final Group found = this.groupRepository.findByPropertyValue("unindexedName", "value-unindexedName");
assertNull(found);
}
@@ -224,7 +189,7 @@ public class IndexTest extends EntityTestBase {
public void testDontFindGroupByNonIndexedField() {
Group group = persist(new Group());
group.setUnindexedName2("value-unindexedName2");
final Group found = groupFinder.findByPropertyValue( "unindexedName2", "value-unindexedName2");
final Group found = this.groupRepository.findByPropertyValue("unindexedName2", "value-unindexedName2");
assertNull(found);
}
@@ -235,7 +200,7 @@ public class IndexTest extends EntityTestBase {
group.setName(NAME_VALUE);
Group group2 = persist(new Group());
group2.setName(NAME_VALUE);
final Iterable<Group> found = groupFinder.findAllByPropertyValue(NAME, NAME_VALUE);
final Iterable<Group> found = this.groupRepository.findAllByPropertyValue(NAME, NAME_VALUE);
final Collection<Group> result = IteratorUtil.addToCollection(found.iterator(), new HashSet<Group>());
assertEquals(new HashSet<Group>(Arrays.asList(group, group2)), result);
}
@@ -261,7 +226,7 @@ public class IndexTest extends EntityTestBase {
@Test
public void findsPersonByIndexOnAnnotatedIntFieldInSeparateTransactions() {
Person person = persistedPerson(NAME_VALUE, 35);
final Person found = personFinder.findByPropertyValue("age", 35);
final Person found = this.personRepository.findByPropertyValue("age", 35);
assertEquals("person found inside range", person, found);
}
@@ -269,15 +234,15 @@ public class IndexTest extends EntityTestBase {
@Transactional
public void testRangeQueryPersonByIndexOnAnnotatedField() {
Person person = persistedPerson(NAME_VALUE, 35);
final Person found = personFinder.findAllByRange("age", 10, 40).iterator().next();
final Person found = this.personRepository.findAllByRange("age", 10, 40).iterator().next();
assertEquals("person found inside range", person, found);
}
@Test
@Transactional
public void testOutsideRangeQueryPersonByIndexOnAnnotatedField() {
Person person = persistedPerson(NAME_VALUE, 35);
Iterable<Person> emptyResult = personFinder.findAllByRange("age", 0, 34);
persistedPerson(NAME_VALUE, 35);
Iterable<Person> emptyResult = this.personRepository.findAllByRange("age", 0, 34);
assertFalse("nothing found outside range", emptyResult.iterator().hasNext());
}
@@ -287,7 +252,7 @@ public class IndexTest extends EntityTestBase {
public void testFindAllPersonByIndexOnAnnotatedFieldWithAtIndexed() {
Person person = persistedPerson(NAME_VALUE, 35);
person.setNickname("Mike");
final Person found = personFinder.findByPropertyValue( "nickname", "Mike");
final Person found = this.personRepository.findByPropertyValue("nickname", "Mike");
assertEquals(person, found);
}
@@ -320,7 +285,7 @@ public class IndexTest extends EntityTestBase {
p = persistedPerson(NAME_VALUE2, 30);
tx.success();
} finally {
tx.finish();
if (tx != null) tx.finish();
}
Assert.assertEquals(p, personRepository.findByPropertyValue(NAME_INDEX, "name", NAME_VALUE2));
try {

View File

@@ -16,22 +16,16 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotInTransactionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Friendship;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -48,17 +42,9 @@ import static org.springframework.data.neo4j.aspects.support.HasRelationshipMatc
@ContextConfiguration( locations = {"classpath:org/springframework/data/neo4j/aspects/support/Neo4jGraphPersistenceTest-context.xml"} )
public class ModificationOutsideOfTransactionTest extends EntityTestBase {
protected final Log log = LogFactory.getLog( getClass() );
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@Before
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
public void cleanUp() {
manualCleanDb();
}
@Test
@@ -248,7 +234,7 @@ public class ModificationOutsideOfTransactionTest extends EntityTestBase {
@Test
public void testFindOutsideTransaction()
{
final GraphRepository<Person> finder = graphRepositoryFactory.createGraphRepository(Person.class);
final GraphRepository<Person> finder = graphDatabaseContext.repositoryFor(Person.class);
assertEquals( false, finder.findAll().iterator().hasNext() );
}

View File

@@ -16,23 +16,16 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
@@ -45,20 +38,7 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
"classpath:org/springframework/data/neo4j/aspects/support/PersonDirectCreator-context.xml" })
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
public class NodeEntityInstantiationTest extends EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
public class NodeEntityInstantiationTest extends EntityTestBase {
@Test
@Transactional
@@ -72,7 +52,7 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
Person person2 = graphDatabaseContext.createEntityFromState(node,Person.class);
assertEquals("Rod", person2.getName());
GraphRepository<Person> finder = graphRepositoryFactory.createGraphRepository(Person.class);
GraphRepository<Person> finder = graphDatabaseContext.repositoryFor(Person.class);
Person found = finder.findOne(nodeId);
assertEquals("Rod", found.getName());
}

View File

@@ -16,8 +16,6 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,17 +24,12 @@ import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.neo4j.aspects.Friendship;
import org.springframework.data.neo4j.aspects.Group;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
@@ -50,19 +43,6 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
public class NodeEntityRelationshipTest extends EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Test
@Transactional
public void testCreateRelationshipWithoutAnnotationOnSet() {

View File

@@ -16,22 +16,15 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.NotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Friendship;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.aspects.Personality;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@@ -44,18 +37,6 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
public class PropertyTest extends EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Test
@Transactional
public void testSetPropertyEnum() {

View File

@@ -16,22 +16,17 @@
package org.springframework.data.neo4j.aspects.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.Friendship;
import org.springframework.data.neo4j.aspects.FriendshipRepository;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.assertEquals;
@@ -43,23 +38,6 @@ import static org.springframework.data.neo4j.aspects.Person.persistedPerson;
public class RelationshipEntityTest extends EntityTestBase {
protected final Log log = LogFactory.getLog(getClass());
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private GraphDatabaseService graphDatabaseService;
@Autowired
private FriendshipRepository friendshipRepository;
@Autowired
private DirectGraphRepositoryFactory graphRepositoryFactory;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(graphDatabaseContext);
}
@Test
@Transactional
public void testRelationshipCreate() {

View File

@@ -69,7 +69,7 @@ public class TraversalTest extends EntityTestBase {
group.setName("dev");
group.addPerson(p);
final TraversalDescription traversalDescription = Traversal.description().relationships(DynamicRelationshipType.withName("persons"), Direction.OUTGOING).evaluator(Evaluators.excludeStartPosition());
Iterable<EntityPath<Group,Person>> paths = graphDatabaseContext.<EntityPath<Group,Person>>findAllByTraversal(group, EntityPath.class, traversalDescription);
Iterable<EntityPath<Group,Person>> paths = (Iterable<EntityPath<Group, Person>>) graphDatabaseContext.<EntityPath<Group,Person>>findAllByTraversal(group, EntityPath.class, traversalDescription);
for (EntityPath<Group, Person> path : paths) {
assertEquals(group, path.startEntity());
assertEquals(p, path.endEntity());
@@ -107,7 +107,7 @@ public class TraversalTest extends EntityTestBase {
@Test
@Transactional
public void testTraverseFromGroupToPeopleWithFinder() {
final GraphRepository<Person> finder = graphRepositoryFactory.createGraphRepository(Person.class);
final GraphRepository<Person> finder = graphDatabaseContext.repositoryFor(Person.class);
Person p = persistedPerson("Michael", 35);
Group group = persist(new Group());
group.setName("dev");

View File

@@ -28,7 +28,7 @@ import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.aspects.Personality;
import org.springframework.data.neo4j.aspects.support.EntityTestBase;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
@@ -87,7 +87,7 @@ public class QueryEngineTest extends EntityTestBase {
@Test
public void testQueryListOfTypeNode() throws Exception {
final String queryString = "start person=node:name_index(name={name}) match (person) <-[:boss]- (boss) return boss";
final QueryResult<Map<String,Object>> queryResult = queryEngine.query(queryString, michaelsName());
final Result<Map<String,Object>> queryResult = queryEngine.query(queryString, michaelsName());
final Collection<Node> result = IteratorUtil.asCollection(queryResult.to(Node.class));
assertEquals(asList(getNodeState(testTeam.emil)),result);

View File

@@ -172,7 +172,7 @@ public class SubReferenceNodeTypeRepresentationStrategyTest extends EntityTestBa
public void testInstantiateConcreteClassWithFinder() {
log.debug("testInstantiateConcreteClassWithFinder");
Volvo v = persist(new Volvo());
GraphRepository<Car> finder = graphRepositoryFactory.createGraphRepository(Car.class);
GraphRepository<Car> finder = graphDatabaseContext.repositoryFor(Car.class);
assertEquals("Wrong concrete class.", Volvo.class, finder.findAll().iterator().next().getClass());
}
@@ -184,16 +184,16 @@ public class SubReferenceNodeTypeRepresentationStrategyTest extends EntityTestBa
log.warn("Created volvo");
persist(new Toyota());
log.warn("Created volvo");
assertEquals("Wrong count for Volvo.", 1L, graphRepositoryFactory.createGraphRepository(Volvo.class).count());
assertEquals("Wrong count for Toyota.", 1L, graphRepositoryFactory.createGraphRepository(Toyota.class).count());
assertEquals("Wrong count for Car.", 2L, graphRepositoryFactory.createGraphRepository(Car.class).count());
assertEquals("Wrong count for Volvo.", 1L, graphDatabaseContext.repositoryFor(Volvo.class).count());
assertEquals("Wrong count for Toyota.", 1L, graphDatabaseContext.repositoryFor(Toyota.class).count());
assertEquals("Wrong count for Car.", 2L, graphDatabaseContext.repositoryFor(Car.class).count());
}
@Test
@Transactional
public void testCountClasses() {
persistedPerson("Michael", 36);
persistedPerson("David", 25);
assertEquals("Wrong Person instance count.", 2L, graphRepositoryFactory.createGraphRepository(Person.class).count());
assertEquals("Wrong Person instance count.", 2L, graphDatabaseContext.repositoryFor(Person.class).count());
}

View File

@@ -93,10 +93,6 @@
<property name="mappingContext" ref="mappingContext"/>
</bean>
<bean id="graphRepositoryFactory" class="org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory">
<constructor-arg ref="graphDatabaseContext" />
</bean>
<!--bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">

View File

@@ -22,7 +22,6 @@ import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.transaction.PlatformTransactionManager;
@@ -37,8 +36,6 @@ public class DataGraphNamespaceHandlerCrossStoreTest {
@Autowired
GraphDatabaseService graphDatabaseService;
@Autowired
DirectGraphRepositoryFactory graphRepositoryFactory;
@Autowired
GraphDatabaseContext graphDatabaseContext;
@Autowired
PlatformTransactionManager transactionManager;
@@ -56,7 +53,6 @@ public class DataGraphNamespaceHandlerCrossStoreTest {
Assert.assertNotNull("graphDatabaseContext", graphDatabaseContext);
EmbeddedGraphDatabase graphDatabaseService = (EmbeddedGraphDatabase) graphDatabaseContext.getGraphDatabaseService();
Assert.assertEquals("store-dir", "target/config-test", graphDatabaseService.getStoreDir());
Assert.assertNotNull("graphRepositoryFactory", config.graphRepositoryFactory);
Assert.assertNotNull("graphDatabaseService", config.graphDatabaseService);
Assert.assertNotNull("transactionManager", config.transactionManager);
config.graphDatabaseService.shutdown();

View File

@@ -146,10 +146,6 @@
</bean>
<bean id="graphRepositoryFactory" class="org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory">
<constructor-arg ref="graphDatabaseContext" />
</bean>
<bean id="transactionManager" class="org.springframework.data.neo4j.transaction.ChainedTransactionManager" >
<constructor-arg>
<list>

View File

@@ -16,13 +16,14 @@
package org.springframework.data.neo4j.rest;
import org.neo4j.rest.graphdb.util.ConvertedResult;
import org.springframework.data.neo4j.conversion.EndResult;
import java.util.Iterator;
class SpringConvertedResult<R> implements org.springframework.data.neo4j.conversion.ConvertedResult<R> {
class SpringEndResult<R> implements EndResult<R> {
private final ConvertedResult<R> result;
public SpringConvertedResult(ConvertedResult<R> result) {
public SpringEndResult(ConvertedResult<R> result) {
this.result = result;
}

View File

@@ -31,8 +31,8 @@ public class SpringRestCypherQueryEngine implements QueryEngine<Map<String,Objec
}
@Override
public SpringRestQueryResult<Map<String,Object>> query(String statement, Map<String, Object> params) {
return new SpringRestQueryResult<Map<String, Object>>(restCypherQueryEngine.query(statement, params));
public SpringRestResult<Map<String,Object>> query(String statement, Map<String, Object> params) {
return new SpringRestResult<Map<String, Object>>(restCypherQueryEngine.query(statement, params));
}
}

View File

@@ -27,6 +27,7 @@ import org.neo4j.rest.graphdb.query.RestCypherQueryEngine;
import org.neo4j.rest.graphdb.query.RestGremlinQueryEngine;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
@@ -77,13 +78,19 @@ public class SpringRestGraphDatabase extends org.neo4j.rest.graphdb.RestGraphDat
return super.getRestAPI().createTraversalDescription();
}
@SuppressWarnings("unchecked")
@Override
public <T> QueryEngine<T> queryEngineFor(QueryType type, final ResultConverter resultConverter) {
switch (type) {
case Cypher: return (QueryEngine<T>)new SpringRestCypherQueryEngine(new RestCypherQueryEngine(getRestAPI(), new SpringResultConverter(resultConverter)));
case Gremlin: return (QueryEngine<T>)new SpringRestGremlinQueryEngine(new RestGremlinQueryEngine(getRestAPI(),new SpringResultConverter(resultConverter)));
}
throw new IllegalArgumentException("Unknown Query Engine Type "+type);
}
@Override
public <T> QueryEngine<T> queryEngineFor(QueryType type) {
switch (type) {
case Cypher: return (QueryEngine<T>)new SpringRestCypherQueryEngine(new RestCypherQueryEngine(super.getRestAPI()));
case Gremlin: return (QueryEngine<T>)new SpringRestGremlinQueryEngine(new RestGremlinQueryEngine(super.getRestAPI()));
}
throw new IllegalArgumentException("Unknown Query Engine Type "+type);
return queryEngineFor(type,createResultConverter());
}
@Override
@@ -92,8 +99,20 @@ public class SpringRestGraphDatabase extends org.neo4j.rest.graphdb.RestGraphDat
}
private ResultConverter createResultConverter() {
if (conversionService==null) return null;
if (conversionService==null) return new DefaultConverter();
return new ConversionServiceQueryResultConverter(conversionService);
}
private static class SpringResultConverter implements org.neo4j.rest.graphdb.util.ResultConverter {
private final ResultConverter resultConverter;
public SpringResultConverter(ResultConverter resultConverter) {
this.resultConverter = resultConverter;
}
@Override
public Object convert(Object value, Class target) {
return resultConverter.convert(value,target);
}
}
}

View File

@@ -31,8 +31,8 @@ public class SpringRestGremlinQueryEngine implements QueryEngine<Object> {
}
@Override
public SpringRestQueryResult<Object> query(String statement, Map<String, Object> params) {
return new SpringRestQueryResult<Object>(restGremlinQueryEngine.query(statement, params));
public SpringRestResult<Object> query(String statement, Map<String, Object> params) {
return new SpringRestResult<Object>(restGremlinQueryEngine.query(statement, params));
}
}

View File

@@ -17,30 +17,36 @@ package org.springframework.data.neo4j.rest;
import org.neo4j.rest.graphdb.util.ConvertedResult;
import org.neo4j.rest.graphdb.util.ResultConverter;
import org.springframework.data.neo4j.conversion.EndResult;
import org.springframework.data.neo4j.conversion.Result;
import java.util.Iterator;
class SpringRestQueryResult<T> implements org.springframework.data.neo4j.conversion.QueryResult<T> {
class SpringRestResult<T> implements Result<T> {
org.neo4j.rest.graphdb.util.QueryResult<T> queryResult;
@Override
public <R> org.springframework.data.neo4j.conversion.ConvertedResult<R> to(final Class<R> type) {
return new SpringConvertedResult<R>(queryResult.to(type));
SpringRestResult(org.neo4j.rest.graphdb.util.QueryResult<T> queryResult) {
this.queryResult = queryResult;
}
public <R> org.springframework.data.neo4j.conversion.ConvertedResult<R> to(Class<R> type, final org.springframework.data.neo4j.conversion.ResultConverter<T, R> trResultConverter) {
@Override
public <R> EndResult<R> to(final Class<R> type) {
return new SpringEndResult<R>(queryResult.to(type));
}
public <R> EndResult<R> to(Class<R> type, final org.springframework.data.neo4j.conversion.ResultConverter<T, R> converter) {
ConvertedResult<R> result = queryResult.to(type, new ResultConverter<T, R>() {
@Override
public R convert(T value, Class<R> type) {
return trResultConverter.convert(value,type);
return converter.convert(value,type);
}
});
return new SpringConvertedResult<R>(result);
return new SpringEndResult<R>(result);
}
public void handle(org.springframework.data.neo4j.conversion.Handler<T> tHandler) {
queryResult.handle(new SpringHandler<T>(tHandler));
public void handle(org.springframework.data.neo4j.conversion.Handler<T> handler) {
queryResult.handle(new SpringHandler<T>(handler));
}
@Override
@@ -48,11 +54,11 @@ class SpringRestQueryResult<T> implements org.springframework.data.neo4j.convers
return queryResult.iterator();
}
SpringRestQueryResult(org.neo4j.rest.graphdb.util.QueryResult<T> queryResult) {
this.queryResult = queryResult;
@SuppressWarnings("unchecked")
@Override
public T single() {
return (T) to(Object.class).single();
}
org.neo4j.rest.graphdb.util.QueryResult<T> queryResult;
}

View File

@@ -52,7 +52,6 @@ public class RestFinderTest extends FinderTest {
@AfterClass
public static void shutdownDb() {
RestTestBase.shutdownDb();
}
}

View File

@@ -37,7 +37,6 @@ import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryB
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory;
import org.springframework.data.neo4j.mapping.*;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
import org.springframework.data.neo4j.support.EntityInstantiator;
import org.springframework.data.neo4j.support.EntityStateHandler;
@@ -97,6 +96,9 @@ public abstract class Neo4jConfiguration {
gdc.setRelationshipTypeRepresentationStrategy(relationshipTypeRepresentationStrategy());
gdc.setRelationshipEntityInstantiator(graphRelationshipInstantiator());
gdc.setTransactionManager(neo4jTransactionManager());
gdc.setGraphDatabase(graphDatabase());
if (validator!=null) {
gdc.setValidator(validator);
}
@@ -161,12 +163,6 @@ public abstract class Neo4jConfiguration {
return new NodeEntityInstantiator(entityStateHandler());
}
@Bean
public DirectGraphRepositoryFactory directGraphRepositoryFactory() throws Exception {
return new DirectGraphRepositoryFactory(graphDatabaseContext());
}
@Bean
public Neo4jMappingContext mappingContext() {
return new Neo4jMappingContext();

View File

@@ -20,7 +20,7 @@ package org.springframework.data.neo4j.conversion;
* @author mh
* @since 28.06.11
*/
public interface ConvertedResult<R> extends Iterable<R> {
public interface EndResult<R> extends Iterable<R> {
R single();
void handle(Handler<R> handler);
}

View File

@@ -26,7 +26,7 @@ import java.util.Iterator;
* @author mh
* @since 28.06.11
*/
public class QueryResultBuilder<T> implements QueryResult<T> {
public class QueryResultBuilder<T> implements Result<T> {
private Iterable<T> result;
private final ResultConverter defaultConverter;
private final boolean isClosableIterable;
@@ -45,13 +45,27 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
@SuppressWarnings("unchecked")
@Override
public <R> ConvertedResult<R> to(Class<R> type) {
public <R> EndResult<R> to(Class<R> type) {
return this.to(type, defaultConverter);
}
@Override
public <R> ConvertedResult<R> to(final Class<R> type, final ResultConverter<T, R> resultConverter) {
return new ConvertedResult<R>() {
public T single() {
try {
final Iterator<T> it = result.iterator();
if (!it.hasNext()) throw new IllegalStateException("Expected at least one result, got none.");
final T value = it.next();
if (it.hasNext())
throw new IllegalStateException("Expected at least one result, got more than one.");
return value;
} finally {
closeIfNeeded();
}
}
@Override
public <R> EndResult<R> to(final Class<R> type, final ResultConverter<T, R> resultConverter) {
return new EndResult<R>() {
@Override
public R single() {
try {

View File

@@ -20,8 +20,7 @@ package org.springframework.data.neo4j.conversion;
* @author mh
* @since 28.06.11
*/
public interface QueryResult<T> extends Iterable<T> {
<R> ConvertedResult<R> to(Class<R> type);
<R> ConvertedResult<R> to(Class<R> type, ResultConverter<T, R> resultConverter);
void handle(Handler<T> handler);
public interface Result<T> extends Iterable<T>, EndResult<T> {
<R> EndResult<R> to(Class<R> type);
<R> EndResult<R> to(Class<R> type, ResultConverter<T, R> resultConverter);
}

View File

@@ -0,0 +1,68 @@
/**
* 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.neo4j.conversion;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IterableWrapper;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.path.EntityPathPathIterableWrapper;
/**
* @author mh
* @since 16.10.11
*/ // todo integrate in result conversion handling
public class TraverserConverter<T> {
private final GraphDatabaseContext ctx;
public TraverserConverter(GraphDatabaseContext ctx) {
this.ctx = ctx;
}
@SuppressWarnings("unchecked")
public Iterable<T> convert(Traverser traverser, Class<T> targetType) {
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
if (EntityPath.class.isAssignableFrom(targetType)) return new EntityPathPathIterableWrapper(traverser, ctx);
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
return (Iterable<T>) convertToGraphEntity(traverser, targetType);
}
private Iterable<?> convertToGraphEntity(Traverser traverser, final Class<?> targetType) {
if (ctx.isNodeEntity(targetType)) {
return new IterableWrapper<Object, Node>(traverser.nodes()) {
@Override
protected Object underlyingObjectToObject(Node node) {
return ctx.createEntityFromState(node, targetType);
}
};
}
if (ctx.isRelationshipEntity(targetType)) {
return new IterableWrapper<Object, Relationship>(traverser.relationships()) {
@Override
protected Object underlyingObjectToObject(Relationship relationship) {
return ctx.createEntityFromState(relationship, targetType);
}
};
}
throw new IllegalStateException("Can't determine valid type for traversal target " + targetType);
}
}

View File

@@ -24,6 +24,7 @@ import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.support.query.QueryEngine;
import java.util.Map;
@@ -102,4 +103,6 @@ public interface GraphDatabase {
<T> QueryEngine<T> queryEngineFor(QueryType type);
void setConversionService(ConversionService conversionService);
<T> QueryEngine<T> queryEngineFor(QueryType type, ResultConverter resultConverter);
}

View File

@@ -93,7 +93,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory {
}
private Object executeQuery(Object entity, String queryString, Map<String, Object> params) {
return graphDatabaseContext.executeQuery(queryString,params,property);
return graphDatabaseContext.query(queryString, params, property.getTypeInformation());
}
private Map<String, Object> createPlaceholderParams(Object entity) {

View File

@@ -53,7 +53,8 @@ public class Neo4jEntityPersister implements Neo4jEntityConverter<Object,Node> {
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
return createEntityFromState(state,null);
}
static class StackedEntityCache {
private long depth;
private final Map<PropertyContainer,Object> objects =new HashMap<PropertyContainer, Object>();

View File

@@ -1,41 +0,0 @@
/**
* 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.neo4j.repository;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
/**
* Simple Factory for {@link NodeGraphRepository} instances.
*/
public class DirectGraphRepositoryFactory {
private final GraphDatabaseContext graphDatabaseContext;
public DirectGraphRepositoryFactory(final GraphDatabaseContext graphDatabaseContext) {
this.graphDatabaseContext = graphDatabaseContext;
}
@SuppressWarnings({"unchecked"})
public <T> GraphRepository<T> createGraphRepository(Class<T> clazz) {
if (graphDatabaseContext.isNodeEntity(clazz)) return new NodeGraphRepository(clazz, graphDatabaseContext);
if (graphDatabaseContext.isRelationshipEntity(clazz)) return new RelationshipGraphRepository(clazz, graphDatabaseContext);
throw new IllegalArgumentException("Can't create graph repository for non graph entity of type "+clazz);
}
}

View File

@@ -16,13 +16,6 @@
package org.springframework.data.neo4j.repository;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
@@ -44,13 +37,16 @@ import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.*;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author mh
* @since 28.03.11

View File

@@ -24,11 +24,14 @@ import org.neo4j.index.impl.lucene.LuceneIndexImplementation;
import org.neo4j.kernel.Traversal;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.GremlinQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.util.ClassUtils;
import java.util.Map;
@@ -40,10 +43,15 @@ public class DelegatingGraphDatabase implements GraphDatabase {
protected GraphDatabaseService delegate;
private ConversionService conversionService;
private ResultConverter resultConverter;
public DelegatingGraphDatabase(final GraphDatabaseService delegate) {
this.delegate = delegate;
}
public DelegatingGraphDatabase(final GraphDatabaseService delegate, ResultConverter resultConverter) {
this.delegate = delegate;
this.resultConverter = resultConverter;
}
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
@@ -117,7 +125,7 @@ public class DelegatingGraphDatabase implements GraphDatabase {
Map<String, String> existingConfig = delegate.index().getConfiguration(index);
Map<String, String> config = indexConfigFor(fullText);
if (config.equals(existingConfig)) return index;
throw new IllegalArgumentException("Setup for index "+indexName+" does not match "+(fullText ? "fulltext":"exact"));
throw new IllegalArgumentException("Setup for index name '"+indexName+"' does not match "+(fullText ? "fulltext":"exact"));
}
private Map<String, String> indexConfigFor(boolean fullText) {
@@ -129,18 +137,36 @@ public class DelegatingGraphDatabase implements GraphDatabase {
return Traversal.description();
}
@SuppressWarnings("unchecked")
// todo create query engines only once
public <T> QueryEngine<T> queryEngineFor(QueryType type) {
return queryEngineFor(type,createResultConverter());
}
@SuppressWarnings("unchecked")
public <T> QueryEngine<T> queryEngineFor(QueryType type,ResultConverter resultConverter) {
switch (type) {
case Cypher: return (QueryEngine<T>)new CypherQueryEngine(delegate, createResultConverter());
case Gremlin: return (QueryEngine<T>) new GremlinQueryEngine(delegate);
case Cypher: {
if (!ClassUtils.isPresent("org.neo4j.cypher.javacompat.ExecutionEngine", getClass().getClassLoader())) {
return new FailingQueryEngine<T>("Cypher");
}
return (QueryEngine<T>)new CypherQueryEngine(delegate, resultConverter);
}
case Gremlin: {
if (!ClassUtils.isPresent("com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph", getClass().getClassLoader())) {
return new FailingQueryEngine<T>("Gremlin");
}
return (QueryEngine<T>) new GremlinQueryEngine(delegate,resultConverter);
}
}
throw new IllegalArgumentException("Unknown Query Engine Type "+type);
}
private ConversionServiceQueryResultConverter createResultConverter() {
if (conversionService == null) return null;
return new ConversionServiceQueryResultConverter(conversionService);
private ResultConverter createResultConverter() {
if (resultConverter!=null) return resultConverter;
if (conversionService != null) {
this.resultConverter = new ConversionServiceQueryResultConverter(conversionService);
}
return null;
}
public void shutdown() {
@@ -151,4 +177,17 @@ public class DelegatingGraphDatabase implements GraphDatabase {
public Node getReferenceNode() {
return delegate.getReferenceNode();
}
private static class FailingQueryEngine<T> implements QueryEngine<T> {
private String dependency;
private FailingQueryEngine(final String dependency) {
this.dependency = dependency;
}
@Override
public Result<T> query(String statement, Map<String, Object> params) {
throw new IllegalStateException(dependency + " is not available, please add it to your dependencies to execute: " +statement);
}
}
}

View File

@@ -206,4 +206,9 @@ public class EntityStateHandler {
}
public Node getNodeState(Object entity) {
final PropertyContainer result = getPersistentState(entity);
if (result==null || result instanceof Node) return (Node) result;
throw new IllegalArgumentException("State of "+entity+" is no Node but "+result);
}
}

View File

@@ -24,31 +24,54 @@ import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.index.impl.lucene.LuceneIndexImplementation;
import org.neo4j.kernel.AbstractGraphDatabase;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.neo4j.annotation.Indexed;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.conversion.TraverserConverter;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
import org.springframework.data.neo4j.core.UncategorizedGraphStoreException;
import org.springframework.data.neo4j.fieldaccess.GraphBackedEntityIterableWrapper;
import org.springframework.data.neo4j.mapping.Neo4jEntityPersister;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntityImpl;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.NodeGraphRepository;
import org.springframework.data.neo4j.repository.RelationshipGraphRepository;
import org.springframework.data.neo4j.support.conversion.EntityResultConverter;
import org.springframework.data.neo4j.support.node.EntityStateFactory;
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
import org.springframework.data.neo4j.support.path.EntityPathPathIterableWrapper;
import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
import org.springframework.data.neo4j.template.GraphCallback;
import org.springframework.data.neo4j.template.Neo4jExceptionTranslator;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.util.TypeInformation;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;
import javax.annotation.PostConstruct;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
@@ -60,7 +83,7 @@ import java.util.Map;
* @author Michael Hunger
* @since 13.09.2010
*/
public class GraphDatabaseContext {
public class GraphDatabaseContext implements Neo4jOperations {
private static final Log log = LogFactory.getLog(GraphDatabaseContext.class);
@@ -81,13 +104,44 @@ public class GraphDatabaseContext {
private TypeRepresentationStrategies typeRepresentationStrategies;
private EntityInstantiator<Relationship> relationshipEntityInstantiator;
private EntityInstantiator<Node> nodeEntityInstantiator;
private PlatformTransactionManager transactionManager;
private GraphDatabase graphDatabase;
private ResultConverter resultConverter;
private IndexProvider indexProvider;
public void setRelationshipEntityInstantiator(EntityInstantiator<Relationship> relationshipEntityInstantiator) {
this.relationshipEntityInstantiator = relationshipEntityInstantiator;
/**
* default constructor for dependency injection, TODO provide dependencies at creation time
*/
public GraphDatabaseContext() {
}
public void setNodeEntityInstantiator(EntityInstantiator<Node> nodeEntityInstantiator) {
this.nodeEntityInstantiator = nodeEntityInstantiator;
/**
* @param graphDatabase the neo4j graph database
* @param transactionManager if passed in, will be used to create implicit transactions whenever needed
*/
public GraphDatabaseContext(final GraphDatabase graphDatabase, PlatformTransactionManager transactionManager) {
notNull(graphDatabase, "graphDatabase");
this.transactionManager = transactionManager;
this.graphDatabase = graphDatabase;
}
public GraphDatabaseContext(final GraphDatabase graphDatabase) {
notNull(graphDatabase, "graphDatabase");
transactionManager = null;
this.graphDatabase = graphDatabase;
}
@SuppressWarnings({"unchecked"})
public <T> GraphRepository<T> repositoryFor(Class<T> clazz) {
if (isNodeEntity(clazz)) return new NodeGraphRepository(clazz, this);
if (isRelationshipEntity(clazz)) return new RelationshipGraphRepository(clazz, this);
throw new IllegalArgumentException("Can't create graph repository for non graph entity of type "+clazz);
}
public GraphDatabase getGraphDatabase() {
return graphDatabase;
}
static class IndexProvider {
@@ -109,30 +163,80 @@ public class GraphDatabaseContext {
@SuppressWarnings("unchecked")
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName, Boolean fullText) {
if (indexName == null) indexName = Indexed.Name.get(type);
if (fullText == null) {
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName);
if (mappingContext.isRelationshipEntity(type))
return (Index<S>) getIndexManager().forRelationships(indexName);
throw new IllegalArgumentException("Wrong index type supplied: " + type + " expected Node- or Relationship-Entity");
if (type==null) {
notNull(indexName,"indexName");
return getIndex(indexName);
}
Map<String, String> config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG;
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName, config);
if (mappingContext.isRelationshipEntity(type))
return (Index<S>) getIndexManager().forRelationships(indexName, config);
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
if (indexName == null) indexName = Indexed.Name.get(type);
final boolean useExistingIndex = fullText == null;
if (useExistingIndex) {
if (persistentEntity.isNodeEntity()) return (Index<S>) getIndexManager().forNodes(indexName);
if (persistentEntity.isRelationshipEntity()) return (Index<S>) getIndexManager().forRelationships(indexName);
throw new IllegalArgumentException("Wrong index type supplied: " + type + " expected Node- or Relationship-Entity");
}
if (persistentEntity.isNodeEntity()) return (Index<S>) createIndex(Node.class, indexName, fullText);
if (persistentEntity.isRelationshipEntity()) return (Index<S>) createIndex(Relationship.class, indexName, fullText);
throw new IllegalArgumentException("Wrong index type supplied: " + type + " expected Node- or Relationship-Entity");
}
public IndexManager getIndexManager() {
return indexManager;
}
@SuppressWarnings("unchecked")
public <T extends PropertyContainer> Index<T> getIndex(String indexName) {
if (indexManager.existsForNodes(indexName)) return (Index<T>) indexManager.forNodes(indexName);
if (indexManager.existsForRelationships(indexName)) return (Index<T>) indexManager.forRelationships(indexName);
throw new IllegalArgumentException("Index "+indexName+" does not exist.");
}
public boolean isNode(Class<? extends PropertyContainer> type) {
if (type.equals(Node.class)) return true;
if (type.equals(Relationship.class)) return false;
throw new IllegalArgumentException("Unknown Graph Primitive, neither Node nor Relationship"+type);
}
// TODO handle existing indexes
@SuppressWarnings("unchecked")
public <T extends PropertyContainer> Index<T> createIndex(Class<T> type, String indexName, boolean fullText) {
if (isNode(type)) {
if (indexManager.existsForNodes(indexName))
return (Index<T>) checkAndGetExistingIndex(indexName, fullText, indexManager.forNodes(indexName));
return (Index<T>) indexManager.forNodes(indexName, indexConfigFor(fullText));
} else {
if (indexManager.existsForRelationships(indexName))
return (Index<T>) checkAndGetExistingIndex(indexName, fullText, indexManager.forRelationships(indexName));
return (Index<T>) indexManager.forRelationships(indexName, indexConfigFor(fullText));
}
}
private <T extends PropertyContainer> Index<T> checkAndGetExistingIndex(final String indexName, boolean fullText, final Index<T> index) {
Map<String, String> existingConfig = indexManager.getConfiguration(index);
Map<String, String> config = indexConfigFor(fullText);
if (configCheck(config, existingConfig, "provider") && configCheck(config, existingConfig, "type")) return index;
throw new IllegalArgumentException("Setup for index "+indexName+" does not match. Existing: "+existingConfig+" required "+config);
}
private boolean configCheck(Map<String, String> config, Map<String, String> existingConfig, String setting) {
return ObjectUtils.nullSafeEquals(config.get(setting), existingConfig.get(setting));
}
private Map<String, String> indexConfigFor(boolean fullText) {
return fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG;
}
}
IndexProvider indexProvider;
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type) {
return indexProvider.getIndex(type, null);
}
public <S extends PropertyContainer> Index<S> getIndex(String name) {
return indexProvider.getIndex(null, name);
}
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName) {
return indexProvider.getIndex(type, indexName, null);
@@ -160,39 +264,6 @@ public class GraphDatabaseContext {
}
@SuppressWarnings("unchecked")
public <T> Iterable<T> findAllByTraversal(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
final PropertyContainer state = entityPersister.getPersistentState(entity);
if (state == null) throw new IllegalStateException("No node attached to " + this);
final Traverser traverser = traversalDescription.traverse((Node) state);
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
if (EntityPath.class.isAssignableFrom(targetType)) return new EntityPathPathIterableWrapper(traverser,this);
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
return (Iterable<T>) convertToGraphEntity(traverser, targetType);
}
private Iterable<?> convertToGraphEntity(Traverser traverser, final Class<?> targetType) {
if (isNodeEntity(targetType)) {
return new IterableWrapper<Object, Node>(traverser.nodes()) {
@Override
protected Object underlyingObjectToObject(Node node) {
return createEntityFromState(node, targetType);
}
};
}
if (isRelationshipEntity(targetType)) {
return new IterableWrapper<Object, Relationship>(traverser.relationships()) {
@Override
protected Object underlyingObjectToObject(Relationship relationship) {
return createEntityFromState(relationship, targetType);
}
};
}
throw new IllegalStateException("Can't determine valid type for traversal target " + targetType);
}
public <T> ClosableIterable<T> findAll(final Class<T> entityClass) {
return typeRepresentationStrategies.findAll(entityClass);
}
@@ -231,6 +302,14 @@ public class GraphDatabaseContext {
}
public void remove(Object entity) {
if (entity instanceof Node) {
((Node)entity).delete();
return;
}
if (entity instanceof Relationship) {
((Relationship)entity).delete();
return;
}
final Class<?> type = entity.getClass();
if (isNodeEntity(type)) {
entityRemover.removeNodeEntity(entity);
@@ -253,10 +332,45 @@ public class GraphDatabaseContext {
/**
* Delegates to {@link GraphDatabaseService}
*/
@Override
public Node createNode() {
return graphDatabaseService.createNode();
}
@Override
public Node createNode(final Map<String,Object> properties) {
return graphDatabase.createNode(properties);
}
public <T> T createNode(Class<T> target, Map<String,Object> properties) {
final Node node = createNode(properties);
if (isNodeEntity(target)) {
typeRepresentationStrategies.postEntityCreation(node,target);
}
return convert(node, target);
}
public Result<Node> createNodes(Map<String,Object>...allNodes) {
Collection<Node> result=new ArrayList<Node>(allNodes.length);
for (Map<String, Object> properties : allNodes) {
result.add(createNode(properties));
}
return convert(result);
}
public <T> Iterable<T> createNodes(Class<T> target, Map<String,Object>...allNodes) {
final TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy = isNodeEntity(target) ? typeRepresentationStrategies.getNodeTypeRepresentationStrategy() : null;
Collection<Node> result=new ArrayList<Node>(allNodes.length);
for (Map<String, Object> properties : allNodes) {
final Node node = createNode(properties);
if (nodeTypeRepresentationStrategy!=null) {
nodeTypeRepresentationStrategy.postEntityCreation(node,target);
}
result.add(node);
}
return convert(result).to(target);
}
/**
* Delegates to {@link GraphDatabaseService}
*/
@@ -267,15 +381,8 @@ public class GraphDatabaseContext {
/**
* Delegates to {@link GraphDatabaseService}
*/
public Node getReferenceNode() {
return graphDatabaseService.getReferenceNode();
}
/**
* Delegates to {@link GraphDatabaseService}
*/
public Iterable<? extends Node> getAllNodes() {
return graphDatabaseService.getAllNodes();
public Result<Node> getAllNodes() {
return convert(graphDatabaseService.getAllNodes());
}
/**
@@ -294,6 +401,10 @@ public class GraphDatabaseContext {
@PostConstruct
public void postConstruct() {
this.resultConverter = new EntityResultConverter<Object, Object>(this);
if (this.graphDatabase==null) {
this.graphDatabase=new DelegatingGraphDatabase(graphDatabaseService,resultConverter);
}
this.typeRepresentationStrategies = new TypeRepresentationStrategies(mappingContext, nodeTypeRepresentationStrategy, relationshipTypeRepresentationStrategy);
this.cypherQueryExecutor = new CypherQueryExecutor(this);
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, graphDatabaseService);
@@ -328,19 +439,19 @@ public class GraphDatabaseContext {
return entityStateHandler.isManaged(entity);
}
public Object executeQuery(String queryString, Map<String, Object> params, Neo4jPersistentProperty property) {
final TypeInformation<?> typeInformation = property.getTypeInformation();
public Object query(String statement, Map<String, Object> params, final TypeInformation<?> typeInformation) {
final TypeInformation<?> actualType = typeInformation.getActualType();
final Class<?> targetType = actualType.getType();
if (actualType.isMap()) {
return cypherQueryExecutor.queryForList(queryString, params);
return cypherQueryExecutor.queryForList(statement, params);
}
if (typeInformation.isCollectionLike()) {
return cypherQueryExecutor.query(queryString, targetType, params);
return cypherQueryExecutor.query(statement, targetType, params);
}
return cypherQueryExecutor.queryForObject(queryString, targetType, params);
return cypherQueryExecutor.queryForObject(statement, targetType, params);
}
// todo have an result converter that is able to handle iterable input and output types
@SuppressWarnings("unchecked")
public <T> Iterable<T> convertResultsTo(Traverser traverser, Class<T> targetType) {
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
@@ -376,6 +487,211 @@ public class GraphDatabaseContext {
return createEntityFromState(result.relationship, relationshipClass);
}
@Override
public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Map<String,Object> properties) {
notNull(startNode, "startNode", endNode, "endNode", relationshipType, "relationshipType", properties, "properties");
return exec(new GraphCallback<Relationship>() {
@Override
public Relationship doWithGraph(GraphDatabase graph) throws Exception {
return graph.createRelationship(startNode, endNode, relationshipType, properties);
}
});
}
private final Neo4jExceptionTranslator exceptionTranslator = new Neo4jExceptionTranslator();
private static void notNull(Object... pairs) {
assert pairs.length % 2 == 0 : "wrong number of pairs to check";
for (int i = 0; i < pairs.length; i += 2) {
if (pairs[i] == null) {
throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + pairs[i + 1] + " is required; it must not be null");
}
}
}
public DataAccessException translateExceptionIfPossible(Exception ex) {
if (ex instanceof RuntimeException) {
return exceptionTranslator.translateExceptionIfPossible((RuntimeException) ex);
}
return new UncategorizedGraphStoreException("Error executing callback",ex);
}
private <T> T doExecute(final GraphCallback<T> callback) {
notNull(callback, "callback");
try {
return callback.doWithGraph(graphDatabase);
} catch (Exception e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T> T exec(final GraphCallback<T> callback) {
if (transactionManager == null) return doExecute(callback);
TransactionTemplate template = new TransactionTemplate(transactionManager);
return template.execute(new TransactionCallback<T>() {
public T doInTransaction(TransactionStatus status) {
return doExecute(callback);
}
});
}
@Override
public Node getReferenceNode() {
try {
return graphDatabase.getReferenceNode();
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public Node getNode(long id) {
if (id < 0) throw new InvalidDataAccessApiUsageException("id is negative");
try {
return graphDatabase.getNodeById(id);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public Relationship getRelationship(long id) {
if (id < 0) throw new InvalidDataAccessApiUsageException("id is negative");
try {
return graphDatabase.getRelationshipById(id);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T extends PropertyContainer> T index(final String indexName, final T element, final String field, final Object value) {
notNull(element, "element", field, "field", value, "value",indexName,"indexName");
exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
if (element instanceof Relationship) {
Index<Relationship> relationshipIndex = graphDatabase.createIndex(Relationship.class, indexName, false);
relationshipIndex.add((Relationship) element, field, value);
} else if (element instanceof Node) {
graphDatabase.createIndex(Node.class, indexName, false).add((Node) element, field, value);
} else {
throw new IllegalArgumentException("Provided element is neither node nor relationship " + element);
}
}
});
return element;
}
@Override
@SuppressWarnings("unchecked")
public <T> Result<T> convert(Iterable<T> iterable) {
return new QueryResultBuilder<T>(iterable, (ResultConverter<T,?>) resultConverter);
}
@Override
@SuppressWarnings("unchecked")
public <T> T convert(Object value, Class<T> type) {
return (T) resultConverter.convert(value,type);
}
public QueryEngine queryEngineFor(QueryType type) {
return graphDatabase.queryEngineFor(type,resultConverter);
}
@SuppressWarnings("unchecked")
public Result<Map<String, Object>> query(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Cypher).query(statement, params);
}
@SuppressWarnings("unchecked")
@Override
public Result<Object> execute(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Gremlin).query(statement, params);
}
@Override
public Result<Path> traverse(Object start, TraversalDescription traversal) {
return traverse((Node)getPersistentState(start),traversal);
}
// TODO result handling !!
@SuppressWarnings("unchecked")
public <T> Iterable<T> findAllByTraversal(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
final PropertyContainer state = entityPersister.getPersistentState(entity);
if (state instanceof Node) {
final Traverser traverser = traversalDescription.traverse((Node) state);
return new TraverserConverter<T>(this).convert(traverser, (Class<T>) targetType);
}
throw new IllegalStateException("No node attached to " + entity);
}
@Override
public Result<Path> traverse(Node startNode, TraversalDescription traversal) {
notNull(startNode, "startNode", traversal, "traversal");
try {
return this.convert(traversal.traverse(startNode));
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T extends PropertyContainer> Result<T> lookup(String indexName, String field, Object value) {
notNull(field, "field", value, "value", indexName, "indexName");
try {
Index<T> index = getIndex(null, indexName);
return convert(index.get(field, value));
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T extends PropertyContainer> Result<T> lookup(final Class<?> indexedType, final Object query) {
notNull(query, "valueOrQueryObject", indexedType, "indexedType");
try {
Index<T> index = getIndex(indexedType);
return convert(index.query(query));
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T extends PropertyContainer> Result<T> lookup(String indexName, Object query) {
notNull(query, "valueOrQueryObject", indexName, "indexName");
try {
Index<T> index = getIndex(null, indexName);
return convert(index.query(query));
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void setRelationshipEntityInstantiator(EntityInstantiator<Relationship> relationshipEntityInstantiator) {
this.relationshipEntityInstantiator = relationshipEntityInstantiator;
}
public void setNodeEntityInstantiator(EntityInstantiator<Node> nodeEntityInstantiator) {
this.nodeEntityInstantiator = nodeEntityInstantiator;
}
public void setEntityStateHandler(EntityStateHandler entityStateHandler) {
this.entityStateHandler = entityStateHandler;
@@ -437,5 +753,9 @@ public class GraphDatabaseContext {
public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) {
this.graphDatabaseService = graphDatabaseService;
}
public void setGraphDatabase(GraphDatabase graphDatabase) {
this.graphDatabase = graphDatabase;
}
}

View File

@@ -108,4 +108,12 @@ public class TypeRepresentationStrategies implements TypeRepresentationStrategy<
public <U> U projectEntity(PropertyContainer state, Class<U> type) {
return getTypeRepresentationStrategy(state).projectEntity(state, type);
}
public TypeRepresentationStrategy<Node> getNodeTypeRepresentationStrategy() {
return nodeTypeRepresentationStrategy;
}
public TypeRepresentationStrategy<Relationship> getRelationshipTypeRepresentationStrategy() {
return relationshipTypeRepresentationStrategy;
}
}

View File

@@ -17,10 +17,8 @@
package org.springframework.data.neo4j.support.conversion;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.core.EntityPath;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.path.ConvertingEntityPath;
@@ -41,10 +39,10 @@ public class EntityResultConverter<T,R> extends DefaultConverter<T,R> {
@Override
protected Object doConvert(Object value, Class<?> sourceType, Class targetType) {
if (ctx.isNodeEntity(targetType)) {
return ctx.createEntityFromState(toNode(value,sourceType),targetType);
return ctx.projectTo(toNode(value,sourceType),targetType);
}
if (ctx.isRelationshipEntity(targetType)) {
return ctx.createEntityFromState(toRelationship(value,sourceType),targetType);
return ctx.projectTo(toRelationship(value,sourceType),targetType);
}
if (EntityPath.class.isAssignableFrom(targetType)) {
return new ConvertingEntityPath(ctx,toPath(value,sourceType));

View File

@@ -38,24 +38,24 @@ public class ConvertingEntityPath<S,E> implements EntityPath<S,E> {
@Override
public <T> T startEntity(Class<T>... types) {
return createNodeEntityFromFirstParameterOrStoredType(startNode(), types);
return projectEntityToFirstParameterOrCreateFromStoredType(startNode(), types);
}
private <T> T createNodeEntityFromFirstParameterOrStoredType(Node node, Class<T>...types) {
private <T> T projectEntityToFirstParameterOrCreateFromStoredType(Node node, Class<T>... types) {
if (node==null) return null;
if (types==null || types.length==0) return graphDatabaseContext.createEntityFromStoredType(node);
return graphDatabaseContext.createEntityFromState(node,types[0]);
return graphDatabaseContext.projectTo(node, types[0]);
}
@Override
public <T> T endEntity(Class<T>... types) {
return createNodeEntityFromFirstParameterOrStoredType(endNode(),types);
return projectEntityToFirstParameterOrCreateFromStoredType(endNode(), types);
}
@Override
public <T> T lastRelationshipEntity(Class<T>... types) {
Relationship relationship = lastRelationship();
if (relationship==null) return null;
return graphDatabaseContext.createEntityFromState(relationship, getFirstOrDefault((Class<T>) DefaultRelationshipBacked.class, types));
return graphDatabaseContext.projectTo(relationship, getFirstOrDefault((Class<T>) DefaultRelationshipBacked.class, types));
}
private static <T> T getFirstOrDefault(final T defaultValue, T... values) {
@@ -78,7 +78,7 @@ public class ConvertingEntityPath<S,E> implements EntityPath<S,E> {
return new IterableWrapper<T,Relationship>(relationships()) {
@Override
protected T underlyingObjectToObject(Relationship relationship) {
return graphDatabaseContext.createEntityFromState(relationship, getFirstOrDefault((Class<T>)DefaultRelationshipBacked.class, relationships));
return graphDatabaseContext.projectTo(relationship, getFirstOrDefault((Class<T>) DefaultRelationshipBacked.class, relationships));
}
};
}
@@ -88,7 +88,7 @@ public class ConvertingEntityPath<S,E> implements EntityPath<S,E> {
return new IterableWrapper<T,PropertyContainer>(delegate) {
@Override
protected T underlyingObjectToObject(PropertyContainer element) {
return graphDatabaseContext.createEntityFromState(element, getFirstOrDefault((Class<T>)DefaultRelationshipBacked.class, relationships));
return graphDatabaseContext.projectTo(element, getFirstOrDefault((Class<T>) DefaultRelationshipBacked.class, relationships));
}
};
}

View File

@@ -23,7 +23,7 @@ import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.ResultConverter;
@@ -47,7 +47,7 @@ public class CypherQueryEngine implements QueryEngine<Map<String,Object>> {
@SuppressWarnings("unchecked")
@Override
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
public Result<Map<String, Object>> query(String statement, Map<String, Object> params) {
try {
ExecutionResult result = parseAndExecuteQuery(statement,params);
return new QueryResultBuilder<Map<String,Object>>(result,resultConverter);

View File

@@ -16,9 +16,9 @@
package org.springframework.data.neo4j.support.query;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.conversion.EntityResultConverter;
import org.springframework.util.ClassUtils;
import java.util.Map;
@@ -32,13 +32,12 @@ public class CypherQueryExecutor implements QueryOperations<Map<String,Object>>
private final QueryEngine<Map<String,Object>> queryEngine;
public CypherQueryExecutor(GraphDatabaseContext ctx) {
EntityResultConverter converter = new EntityResultConverter(ctx);
if (ClassUtils.isPresent("org.neo4j.cypher.javacompat.ExecutionEngine",getClass().getClassLoader())) {
queryEngine = new CypherQueryEngine(ctx.getGraphDatabaseService(), converter);
queryEngine = ctx.queryEngineFor(QueryType.Cypher);
} else {
queryEngine = new QueryEngine<Map<String, Object>>() {
@Override
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
public Result<Map<String, Object>> query(String statement, Map<String, Object> params) {
throw new IllegalStateException("Cypher is not available, please add it to your dependencies to execute: "+statement);
}
};

View File

@@ -19,7 +19,7 @@ package org.springframework.data.neo4j.support.query;
import org.neo4j.graphdb.GraphDatabaseService;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.ResultConverter;
@@ -42,7 +42,7 @@ public class GremlinQueryEngine implements QueryEngine<Object> {
@SuppressWarnings("unchecked")
@Override
public QueryResult<Object> query(String statement, Map<String, Object> params) {
public Result<Object> query(String statement, Map<String, Object> params) {
try {
Iterable<Object> result = gremlinExecutor.query(statement, params);
return new QueryResultBuilder<Object>(result,resultConverter);

View File

@@ -16,7 +16,7 @@
package org.springframework.data.neo4j.support.query;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import java.util.Map;
@@ -25,6 +25,6 @@ import java.util.Map;
* @since 22.06.11
*/
public interface QueryEngine<T> {
QueryResult<T> query(String statement, Map<String, Object> params);
Result<T> query(String statement, Map<String, Object> params);
}

View File

@@ -18,7 +18,7 @@ package org.springframework.data.neo4j.template;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import java.util.Map;
@@ -102,36 +102,45 @@ public interface Neo4jOperations {
* Converts the Iterable into a QueryResult object for uniform handling. E.g.
* template.convert(node.getRelationships());
*/
<T> QueryResult<T> convert(Iterable<T> iterable);
<T> Result<T> convert(Iterable<T> iterable);
/**
* Runs the given cypher statement and packages the result in a QueryResult, simple conversions via the
* registered converter-factories are already executed via this method.
*/
QueryResult<Map<String, Object>> query(String statement,Map<String,Object> params);
Result<Map<String, Object>> query(String statement,Map<String,Object> params);
/**
* Executes the given Gremlin statement and returns the result packaged as QueryResult as Neo4j types, not
* Gremlin types. Table rows are converted to Map<String,Object>.
*/
QueryResult<Object> execute(String statement, Map<String,Object> params);
Result<Object> execute(String statement, Map<String,Object> params);
/**
* Traverses the graph starting at the given node 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.
*/
QueryResult<Path> traverse(Node startNode, TraversalDescription traversal);
Result<Path> traverse(Node startNode, TraversalDescription traversal);
/**
* The value is looked up in the Neo4j index returning the IndexHits wrapped in a QueryResult to be converted
* into Paths or Entities.
*/
<T extends PropertyContainer> QueryResult<T> lookup(String indexName, String field, Object value);
<T extends PropertyContainer> Result<T> lookup(String indexName, String field, Object value);
/**
* The query is executed on the index returning the IndexHits wrapped in a QueryResult to be converted
* into Paths or Entities.
*/
<T extends PropertyContainer> QueryResult<T> lookup(String indexName, Object query);
<T extends PropertyContainer> Result<T> lookup(String indexName, Object query);
Result<Path> traverse(Object start, TraversalDescription traversal);
<T extends PropertyContainer> Result<T> lookup(Class<?> indexedType, Object query);
Node createNode();
@SuppressWarnings("unchecked")
<T> T convert(Object value, Class<T> type);
}

View File

@@ -22,7 +22,7 @@ import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.query.QueryEngine;
@@ -154,7 +154,7 @@ public class Neo4jTemplate implements Neo4jOperations {
}
@Override
public <T> QueryResult<T> convert(Iterable<T> iterable) {
public <T> Result<T> convert(Iterable<T> iterable) {
return new QueryResultBuilder<T>(iterable);
}
@@ -174,20 +174,20 @@ public class Neo4jTemplate implements Neo4jOperations {
}
@SuppressWarnings("unchecked")
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
public Result<Map<String, Object>> query(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Cypher).query(statement, params);
}
@SuppressWarnings("unchecked")
@Override
public QueryResult<Object> execute(String statement, Map<String, Object> params) {
public Result<Object> execute(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Gremlin).query(statement, params);
}
@Override
public QueryResult<Path> traverse(Node startNode, TraversalDescription traversal) {
public Result<Path> traverse(Node startNode, TraversalDescription traversal) {
notNull(startNode, "startNode", traversal, "traversal");
try {
return new QueryResultBuilder<Path>(traversal.traverse(startNode));
@@ -197,7 +197,7 @@ public class Neo4jTemplate implements Neo4jOperations {
}
@Override
public <T extends PropertyContainer> QueryResult<T> lookup(String indexName, String field, Object value) {
public <T extends PropertyContainer> Result<T> lookup(String indexName, String field, Object value) {
notNull(field, "field", value, "value", indexName, "indexName");
try {
Index<T> index = graphDatabase.getIndex(indexName);
@@ -207,7 +207,7 @@ public class Neo4jTemplate implements Neo4jOperations {
}
}
@Override
public <T extends PropertyContainer> QueryResult<T> lookup(String indexName, Object query) {
public <T extends PropertyContainer> Result<T> lookup(String indexName, Object query) {
notNull(query, "valueOrQueryObject", indexName, "indexName");
try {
Index<T> index = graphDatabase.getIndex(indexName);
@@ -216,6 +216,26 @@ public class Neo4jTemplate implements Neo4jOperations {
throw translateExceptionIfPossible(e);
}
}
@Override
public Result<Path> traverse(Object start, TraversalDescription traversal) {
return null;
}
@Override
public <T extends PropertyContainer> Result<T> lookup(Class<?> indexedType, Object query) {
return null;
}
@Override
public Node createNode() {
return null;
}
@Override
public <T> T convert(Object value, Class<T> type) {
return null;
}
}
/*

View File

@@ -23,7 +23,6 @@ import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.neo4j.model.PersonRepository;
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.transaction.PlatformTransactionManager;
@@ -38,8 +37,6 @@ public class DataGraphNamespaceHandlerTest {
@Autowired
GraphDatabaseService graphDatabaseService;
@Autowired
DirectGraphRepositoryFactory graphRepositoryFactory;
@Autowired
GraphDatabaseContext graphDatabaseContext;
@Autowired
PlatformTransactionManager transactionManager;
@@ -69,7 +66,6 @@ public class DataGraphNamespaceHandlerTest {
Assert.assertNotNull("graphDatabaseContext", graphDatabaseContext);
EmbeddedGraphDatabase graphDatabaseService = (EmbeddedGraphDatabase) graphDatabaseContext.getGraphDatabaseService();
Assert.assertEquals("store-dir", "target/config-test", graphDatabaseService.getStoreDir());
Assert.assertNotNull("graphRepositoryFactory",config.graphRepositoryFactory);
Assert.assertNotNull("graphDatabaseService",config.graphDatabaseService);
Assert.assertNotNull("transactionManager",config.transactionManager);
config.graphDatabaseService.shutdown();

View File

@@ -0,0 +1,353 @@
/**
* 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.neo4j.template;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.model.Person;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.node.Neo4jHelper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Iterator;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*;
import static org.neo4j.helpers.collection.MapUtil.map;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:template-config-context.xml"})
public class GraphDatabaseContextTemplateTest {
private static final DynamicRelationshipType KNOWS = DynamicRelationshipType.withName("knows");
private static final DynamicRelationshipType HAS = DynamicRelationshipType.withName("has");
@Autowired
GraphDatabaseContext template;
protected GraphDatabase graphDatabase;
protected Node referenceNode;
protected Relationship relationship1;
protected Node node1;
@Autowired
PlatformTransactionManager transactionManager;
@BeforeTransaction
public void cleanDb() {
Neo4jHelper.cleanDb(template);
}
@Before
public void setUp() throws Exception {
Neo4jHelper.cleanDb(template);
graphDatabase = template.getGraphDatabase();
referenceNode = graphDatabase.getReferenceNode();
createData();
}
private void createData() {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
referenceNode.setProperty("name", "node0");
graphDatabase.createIndex(Node.class, "node", false).add(referenceNode, "name", "node0");
node1 = graphDatabase.createNode(map("name", "node1"));
relationship1 = referenceNode.createRelationshipTo(node1, KNOWS);
relationship1.setProperty("name", "rel1");
graphDatabase.createIndex(Relationship.class, "relationship", false).add(relationship1, "name", "rel1");
}
});
}
@Test
public void shouldExecuteCallbackInTransaction() throws Exception {
Node refNode = template.exec(new GraphCallback<Node>() {
@Override
public Node doWithGraph(GraphDatabase graph) throws Exception {
Node referenceNode = graph.getReferenceNode();
referenceNode.setProperty("test", "testDoInTransaction");
return referenceNode;
}
});
assertEquals("same reference node", referenceNode, refNode);
assertTestPropertySet(referenceNode, "testDoInTransaction");
}
@Test
public void shouldRollbackTransactionOnException() {
try {
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
graph.getReferenceNode().setProperty("test", "shouldRollbackTransactionOnException");
throw new RuntimeException("please rollback");
}
});
} catch (RuntimeException re) {
System.out.println(re.getMessage());
}
Assert.assertThat((String) graphDatabase.getReferenceNode().getProperty("test", "not set"), not("shouldRollbackTransactionOnException"));
}
@Test
public void shouldRollbackViaStatus() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
graph.getReferenceNode().setProperty("test", "shouldRollbackTransactionOnException");
status.setRollbackOnly();
}
});
}
});
Assert.assertThat((String) graphDatabase.getReferenceNode().getProperty("test", "not set"), not("shouldRollbackTransactionOnException"));
}
@Test(expected = RuntimeException.class)
public void shouldNotConvertUserRuntimeExceptionToDataAccessException() {
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
throw new RuntimeException();
}
});
}
@Test(expected = DataAccessException.class)
public void shouldConvertMissingTransactionExceptionToDataAccessException() {
Neo4jTemplate template = new Neo4jTemplate(graphDatabase, null);
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
graph.createNode(null);
}
});
}
@Test(expected = DataAccessException.class)
public void shouldConvertNotFoundExceptionToDataAccessException() {
Neo4jTemplate template = new Neo4jTemplate(graphDatabase, transactionManager);
template.exec(new GraphCallback.WithoutResult() {
@Override
public void doWithGraphWithoutResult(GraphDatabase graph) throws Exception {
graph.getNodeById(Long.MAX_VALUE);
}
});
}
@Test(expected = DataAccessException.class)
public void shouldConvertTemplateNotFoundExceptionToDataAccessException() {
template.getNode(Long.MAX_VALUE);
}
@Test
public void shouldExecuteCallback() throws Exception {
Long refNodeId = template.exec(new GraphCallback<Long>() {
@Override
public Long doWithGraph(GraphDatabase graph) throws Exception {
return graph.getReferenceNode().getId();
}
});
assertEquals(referenceNode.getId(), (long) refNodeId);
}
@Test
public void testGetReferenceNode() throws Exception {
assertEquals(referenceNode, template.getReferenceNode());
}
@Test
@Transactional
public void testCreateNode() throws Exception {
Node node = template.createNode(null);
assertNotNull("created node", node);
}
@Test
@Transactional
public void testCreateEntityWithProperties() throws Exception {
Person person = template.createNode(Person.class, map("name", "name"));
assertNotNull("created node", person);
assertEquals("property created", "name", person.getName());
}
@Test
@Transactional
public void testCreateNodeTypeWithProperties() throws Exception {
Node person = template.createNode(Node.class, map("name", "name"));
assertNotNull("created node", person);
assertEquals("property created", "name", person.getProperty("name"));
}
@Test
@Transactional
public void testCreateNodeWithProperties() throws Exception {
Node node = template.createNode(map("test", "testCreateNodeWithProperties"));
assertTestPropertySet(node, "testCreateNodeWithProperties");
}
private void assertTestPropertySet(Node node, String testName) {
assertEquals(testName, node.getProperty("test", "not set"));
}
@Test
public void testGetNode() throws Exception {
Node lookedUpNode = template.getNode(referenceNode.getId());
assertEquals(referenceNode, lookedUpNode);
}
@Test
public void testGetRelationship() throws Exception {
Relationship lookedUpRelationship = template.getRelationship(relationship1.getId());
assertThat(lookedUpRelationship, is(relationship1));
}
@Test
public void testIndexRelationship() throws Exception {
Index<Relationship> index = graphDatabase.getIndex("relationship");
Relationship lookedUpRelationship = index.get("name", "rel1").getSingle();
assertThat("same relationship from index", lookedUpRelationship, is(relationship1));
}
@Test
public void testIndexNode() throws Exception {
template.index("node", node1, "name", "node1");
Index<Node> index = graphDatabase.getIndex("node");
Node lookedUpNode = index.get("name", "node1").getSingle();
assertThat("same node from index", lookedUpNode, is(node1));
}
@Test
public void testQueryNodes() throws Exception {
assertSingleResult("node0", template.lookup("node", new TermQuery(new Term("name", "node0"))).to(String.class, new PropertyContainerNameConverter()));
}
@Test
public void testRetrieveNodes() throws Exception {
assertSingleResult("node0", template.lookup("node", "name", "node0").to(String.class, new PropertyContainerNameConverter()));
}
@Test
public void testQueryRelationships() throws Exception {
assertSingleResult("rel1", template.lookup("relationship", new TermQuery(new Term("name", "rel1"))).to(String.class, new PropertyContainerNameConverter()));
}
@Test
public void testRetrieveRelationships() throws Exception {
assertSingleResult("rel1", template.lookup("relationship", "name", "rel1").to(String.class, new PropertyContainerNameConverter()));
}
@SuppressWarnings("deprecation")
@Test
public void testTraverse() throws Exception {
final TraversalDescription description = Traversal.description().relationships(KNOWS).prune(Traversal.pruneAfterDepth(1)).filter(Traversal.returnAllButStartNode());
assertSingleResult("node1", template.traverse(referenceNode, description).to(String.class, new PathNodeNameMapper()));
}
@Test
public void shouldFindNextNodeViaCypher() throws Exception {
assertSingleResult(node1, template.query("start n=node(0) match n-->m return m", null).to(Node.class));
}
@Test
public void shouldFindNextNodeViaGremlin() throws Exception {
assertSingleResult(node1, template.execute("g.v(0).out", null).to(Node.class));
}
@Test
public void shouldGetDirectRelationship() throws Exception {
assertSingleResult("rel1", template.convert(referenceNode.getRelationships()).to(String.class, new RelationshipNameConverter()));
}
@Test
public void shouldGetDirectRelationshipForType() throws Exception {
assertSingleResult("rel1", template.convert(referenceNode.getRelationships(KNOWS)).to(String.class, new RelationshipNameConverter()));
}
@Test
public void shouldGetDirectRelationshipForTypeAndDirection() throws Exception {
assertSingleResult("rel1", template.convert(referenceNode.getRelationships(KNOWS, Direction.OUTGOING)).to(String.class, new RelationshipNameConverter()));
}
private <T> void assertSingleResult(T expected, Iterable<T> iterable) {
Iterator<T> result = iterable.iterator();
assertEquals(expected, result.next());
assertEquals(false, result.hasNext());
}
@Test
public void shouldCreateRelationshipWithProperty() throws Exception {
Relationship relationship = template.createRelationship(referenceNode, node1, HAS, map("name", "rel2"));
assertNotNull(relationship);
assertEquals(referenceNode, relationship.getStartNode());
assertEquals(node1, relationship.getEndNode());
assertEquals(HAS.name(), relationship.getType().name());
assertEquals("rel2", relationship.getProperty("name", "not set"));
}
private static class PathRelationshipNameMapper implements ResultConverter<Path, String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.lastRelationship().getProperty("name", "not set");
}
}
private static class PathNodeNameMapper implements ResultConverter<Path, String> {
@Override
public String convert(Path path, Class<String> type) {
return (String) path.endNode().getProperty("name", "not set");
}
}
private static class RelationshipNameConverter implements ResultConverter<Relationship, String> {
@Override
public String convert(Relationship value, Class<String> type) {
return (String) value.getProperty("name");
}
}
private static class PropertyContainerNameConverter implements ResultConverter<PropertyContainer, String> {
@Override
public String convert(PropertyContainer value, Class<String> type) {
return (String) value.getProperty("name");
}
}
}

View File

@@ -23,7 +23,7 @@ import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.springframework.data.neo4j.conversion.Handler;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.core.GraphDatabase;
import java.util.HashSet;
@@ -52,7 +52,7 @@ public class NeoTraversalTest extends NeoApiTest {
final Set<String> resultSet = new HashSet<String>();
@SuppressWarnings("deprecation") final TraversalDescription description = Traversal.description().relationships(HAS).filter(returnAllButStartNode()).prune(Traversal.pruneAfterDepth(2));
final QueryResult<Path> queryResult = template.traverse(template.getReferenceNode(), description);
final Result<Path> queryResult = template.traverse(template.getReferenceNode(), description);
queryResult.handle(new Handler<Path>() {
@Override
public void handle(Path value) {

View File

@@ -12,4 +12,5 @@
<neo4j:config graphDatabaseService="graphDatabaseService"/>
<neo4j:repositories base-package="org.springframework.data.neo4j.model"/>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"/>
<tx:annotation-driven/>
</beans>

View File

@@ -49,7 +49,7 @@
public HelloWorldInitializer() {
super(new String[]{"spring/helloWorldServer-Context.xml"},
Pair.of("worldRepository", WorldRepository.class),
Pair.of("graphRepositoryFactory", GraphRepositoryFactory.class));
Pair.of("template", Neo4jTemplate.class));
}
}
]]></programlisting>

View File

@@ -45,8 +45,7 @@ class Person {
@Indexed int age;
}
GraphRepository<Person> graphRepository = graphRepositoryFactory
.createGraphRepository(Person.class);
GraphRepository<Person> graphRepository = template.repositoryFor(Person.class);
// Exact match, in named index
Person mark = graphRepository.findByPropertyValue("people", "name", "mark");
@@ -84,8 +83,8 @@ class Person {
@Indexed(indexName = "people-search", fulltext=true) String name;
}
GraphRepository<Person> graphRepository = graphRepositoryFactory
.createGraphRepository(Person.class);
GraphRepository<Person> graphRepository =
template.repositoryFor(Person.class);
Person mark = graphRepository.findAllByQuery("people-search", "name", "ma*");
]]></programlisting>

View File

@@ -201,8 +201,8 @@
</para>
<example>
<title>Using GraphRepositories</title>
<programlisting language="java"><![CDATA[GraphRepository<Person> graphRepository = graphRepositoryFactory
.createGraphRepository(Person.class);
<programlisting language="java"><![CDATA[GraphRepository<Person> graphRepository = template
.repositoryFor(Person.class);
Person michael = graphRepository.save(new Person("Michael", 36));

View File

@@ -18,13 +18,13 @@
int year;
}
@Autowired DirectGraphRepositoryFactory graphRepositoryFactory;
@Autowired Neo4jTemplate template;
@Test public void persistedMovieShouldBeRetrievableFromGraphDb() {
int id = 1;
Movie forrestGump = new Movie(id, "Forrest Gump", 1994).persist();
GraphRepository<Movie> movieRepository =
graphRepositoryFactory.createGraphRepository(Movie.class);
template.repositoryFor(Movie.class);
Movie retrievedMovie = movieRepository.findByPropertyValue("id", id);
assertEqual("retrieved movie matches persisted one", forrestGump, retrievedMovie);
assertEqual("retrieved movie title matches", "Forrest Gump", retrievedMovie.getTitle());