API cleanup Neo4jTemplate, Renaming EmbeddedQueryEngine to CypherQueryEngine

This commit is contained in:
Michael Hunger
2011-07-18 16:25:07 +02:00
parent 3f63270545
commit a8c223f0d1
12 changed files with 118 additions and 255 deletions

View File

@@ -26,15 +26,15 @@ import java.util.*;
* @author mh
* @since 22.06.11
*/
public class RestQueryEngine implements QueryEngine {
public class RestCypherQueryEngine implements QueryEngine {
private final RestRequest restRequest;
private final RestGraphDatabase restGraphDatabase;
private final ResultConverter resultConverter;
public RestQueryEngine(RestGraphDatabase restGraphDatabase) {
public RestCypherQueryEngine(RestGraphDatabase restGraphDatabase) {
this(restGraphDatabase,null);
}
public RestQueryEngine(RestGraphDatabase restGraphDatabase, ResultConverter resultConverter) {
public RestCypherQueryEngine(RestGraphDatabase restGraphDatabase, ResultConverter resultConverter) {
this.restGraphDatabase = restGraphDatabase;
this.resultConverter = resultConverter!=null ? resultConverter : new DefaultConverter();
this.restRequest = restGraphDatabase.getRestRequest();
@@ -65,6 +65,11 @@ public class RestQueryEngine implements QueryEngine {
return result.to(type,converter);
}
@Override
public void handle(Handler<Map<String, Object>> handler) {
result.handle(handler);
}
@Override
public Iterator<Map<String, Object>> iterator() {
return result.iterator();

View File

@@ -27,7 +27,6 @@ import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.Property;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.rest.index.RestIndexManager;
import org.springframework.data.neo4j.rest.index.RestIndexManager;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
import org.springframework.data.neo4j.support.query.QueryEngine;
@@ -106,7 +105,7 @@ public class RestGraphDatabase implements GraphDatabaseService, GraphDatabase {
@Override
public QueryEngine queryEngineFor(QueryEngine.Type type) {
return new RestQueryEngine(this, createResultConverter());
return new RestCypherQueryEngine(this, createResultConverter());
}
private ResultConverter createResultConverter() {

View File

@@ -23,4 +23,5 @@ package org.springframework.data.neo4j.conversion;
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);
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.neo4j.conversion;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IteratorWrapper;
import java.util.Iterator;
@@ -27,6 +29,8 @@ import java.util.Iterator;
public class QueryResultBuilder<T> implements QueryResult<T> {
private Iterable<T> result;
private final ResultConverter defaultConverter;
private final boolean isClosableIterable;
private boolean isClosed;
public QueryResultBuilder(Iterable<T> result) {
this(result, new DefaultConverter());
@@ -34,6 +38,7 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
public QueryResultBuilder(Iterable<T> result, final ResultConverter<T,?> defaultConverter) {
this.result = result;
this.isClosableIterable = result instanceof IndexHits || result instanceof ClosableIterable;
this.defaultConverter = defaultConverter;
}
@@ -47,17 +52,26 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
return new ConvertedResult<R>() {
@Override
public R single() {
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 resultConverter.convert(value, type);
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 resultConverter.convert(value, type);
} finally {
closeIfNeeded();
}
}
@Override
public void handle(Handler<R> handler) {
for (T value : result) {
handler.handle(resultConverter.convert(value, type));
try {
for (T value : result) {
handler.handle(resultConverter.convert(value, type));
}
} finally {
closeIfNeeded();
}
}
@@ -72,6 +86,29 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
};
}
@Override
public void handle(Handler<T> handler) {
try {
for (T value : result) {
handler.handle(value);
}
} finally {
closeIfNeeded();
}
}
private void closeIfNeeded() {
if (isClosableIterable && !isClosed) {
if (result instanceof IndexHits) {
((IndexHits) result).close();
} else if (result instanceof ClosableIterable) {
((ClosableIterable) result).close();
}
isClosed=true;
}
}
@Override
public Iterator<T> iterator() {
return result.iterator();

View File

@@ -23,7 +23,7 @@ import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.support.query.EmbeddedQueryEngine;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
@@ -95,7 +95,7 @@ public interface GraphDatabase {
*/
TraversalDescription createTraversalDescription();
QueryEngine queryEngineFor(EmbeddedQueryEngine.Type type);
QueryEngine queryEngineFor(CypherQueryEngine.Type type);
void setConversionService(ConversionService conversionService);
}

View File

@@ -26,7 +26,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.Property;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
import org.springframework.data.neo4j.support.query.EmbeddedQueryEngine;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
import java.util.Map;
@@ -126,8 +126,8 @@ public class DelegatingGraphDatabase implements GraphDatabase {
}
@Override
public QueryEngine queryEngineFor(EmbeddedQueryEngine.Type type) {
return new EmbeddedQueryEngine(delegate, createResultConverter());
public QueryEngine queryEngineFor(CypherQueryEngine.Type type) {
return new CypherQueryEngine(delegate, createResultConverter());
}
private ConversionServiceQueryResultConverter createResultConverter() {

View File

@@ -29,18 +29,18 @@ import org.springframework.data.neo4j.conversion.ResultConverter;
import java.util.Map;
public class EmbeddedQueryEngine implements QueryEngine, QueryOperations {
public class CypherQueryEngine implements QueryEngine, QueryOperations {
final ExecutionEngine executionEngine;
private ResultConverter resultConverter;
private final DefaultQueryOperations queryOperations;
public EmbeddedQueryEngine(GraphDatabaseService graphDatabaseService) {
public CypherQueryEngine(GraphDatabaseService graphDatabaseService) {
this(graphDatabaseService, new DefaultConverter());
}
public EmbeddedQueryEngine(GraphDatabaseService graphDatabaseService, ResultConverter resultConverter) {
public CypherQueryEngine(GraphDatabaseService graphDatabaseService, ResultConverter resultConverter) {
this.resultConverter = resultConverter != null ? resultConverter : new DefaultConverter();
this.executionEngine = new ExecutionEngine(graphDatabaseService);
this.queryOperations = new DefaultQueryOperations(this);

View File

@@ -31,7 +31,7 @@ public class QueryExecutor implements QueryOperations {
public QueryExecutor(GraphDatabaseContext ctx) {
EntityResultConverter converter = new EntityResultConverter(ctx);
queryEngine = new EmbeddedQueryEngine(ctx.getGraphDatabaseService(), converter);
queryEngine = new CypherQueryEngine(ctx.getGraphDatabaseService(), converter);
}
public Iterable<Map<String, Object>> queryForList(String statement) {

View File

@@ -18,10 +18,8 @@ package org.springframework.data.neo4j.template;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.helpers.collection.ClosableIterable;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.core.Property;
import org.springframework.data.neo4j.support.path.PathMapper;
import org.springframework.data.neo4j.support.query.QueryEngine;
import java.util.Map;
@@ -89,73 +87,6 @@ public interface Neo4jOperations {
*/
Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props);
/**
* Queries the supplied index with a lucene query string or query object (if the neo4j-index provider is lucene)
*
*
* @param indexName Name of the index, will be checked against existing indexes, first relationship-indexes, then node indexes
* assumes a "node" node index for a null value
* @param queryOrQueryObject a lucene query string or query object (if the neo4j-index provider is lucene)
* @param pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the query result mapping
* @see org.springframework.data.neo4j.support.path.IterationController for controlling eagerness of iteration
*/
<T> ClosableIterable<T> lookup(String indexName, Object queryOrQueryObject, PathMapper<T> pathMapper);
/**
* Queries the supplied index with a field - value combination
*
*
* @param indexName Name of the index, will be checked against existing indexes, first relationship-indexes, then node indexes
* assumes a "node" node index for a null value
* @param field field to query
* @param value value to supply to index query
* @param pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the query result mapping
* @see org.springframework.data.neo4j.support.path.IterationController for controlling eagerness of iteration
*/
<T> ClosableIterable<T> lookup(String indexName, String field, String value, PathMapper<T> pathMapper);
/**
* Traverses the whole path with the given traversal descripting starting at the start node.
*
* @param traversal a traversal description, possibly generated by the Traversal.description()... DSL
* @param startNode start node for the traversal
* @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping
*/
<T> Iterable<T> traverse(TraversalDescription traversal, Node startNode, PathMapper<T> pathMapper);
/**
* Traverses only to the direct neighbours of the start node
* @param startNode start node for the traversal
* @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @param type type of relationships to consider
* @param direction direction of relationship to consider (can be OUTGOING, INCOMING, BOTH)
* @param <T> expected type of result
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping
*/
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper, RelationshipType type, Direction direction);
/**
* Traverses only to the direct neighbours of the start node for the specified relationship types
* @param startNode start node for the traversal
* @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @param types types of relationships to consider
* @param <T> expected type of result
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping
*/
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper, RelationshipType... types);
/**
* Traverses only to all direct neighbours of the start node for all relationships
* @param startNode start node for the traversal
* @param pathMapper pathMapper a mapper that translates from the resulting paths into some domain object, might use PathMapper.WithoutResult for a callback behaviour
* @param <T> expected type of result
* @return a lazy (when mapped) or eagerly (when called back) iterable containing the results of the traversal result mapping
*/
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper);
/**
* Indexes the given field and value for the element.
* @param indexName Name of the index, will be checked against existing indexes according to the given element
@@ -168,9 +99,13 @@ public interface Neo4jOperations {
*/
<T extends PropertyContainer> T index(String indexName, T element, String field, Object value);
Iterable<Map<String, Object>> query(QueryEngine.Type engineType, String statement);
<T> QueryResult<T> convert(Iterable<T> iterable);
<T> Iterable<T> query(QueryEngine.Type engineType, String statement, Class<T> type);
QueryResult<Map<String, Object>> query(String statement);
<T> T queryForObject(QueryEngine.Type engineType, String statement, Class<T> type);
QueryResult<Path> traverse(Node startNode, TraversalDescription traversal);
<T extends PropertyContainer> QueryResult<T> lookup(String indexName, String field, Object value);
<T extends PropertyContainer> QueryResult<T> lookup(String indexName, Object valueOrQueryObject);
}

View File

@@ -30,9 +30,8 @@ import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.Property;
import org.springframework.data.neo4j.support.path.NodePath;
import org.springframework.data.neo4j.support.path.PathMapper;
import org.springframework.data.neo4j.support.path.PathMappingIterator;
import org.springframework.data.neo4j.support.path.RelationshipPath;
import org.springframework.data.neo4j.support.query.EmbeddedQueryEngine;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
@@ -167,34 +166,11 @@ public class Neo4jTemplate implements Neo4jOperations {
}
@Override
public <T> ClosableIterable<T> lookup(String indexName, Object queryOrQueryObject, final PathMapper<T> pathMapper) {
notNull(queryOrQueryObject, "queryOrQueryObject", pathMapper, "pathMapper",indexName,"indexName");
try {
Index<? extends PropertyContainer> index = graphDatabase.getIndex(indexName);
if (Relationship.class.isAssignableFrom(index.getEntityType())) {
return mapRelationships(((Index<Relationship>)index).query(queryOrQueryObject), pathMapper);
}
return mapNodes(((Index<Node>)index).query(queryOrQueryObject), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
public <T> QueryResult<T> convert(Iterable<T> iterable) {
return new QueryResultBuilder<T>(iterable);
}
@Override
public <T> ClosableIterable<T> lookup(String indexName, String field, String value, final PathMapper<T> pathMapper) {
notNull(field, "field", value, "value", pathMapper, "pathMapper", indexName, "indexName");
try {
Index<? extends PropertyContainer> index = graphDatabase.getIndex(indexName);
if (Relationship.class.isAssignableFrom(index.getEntityType())) {
return mapRelationships(((Index<Relationship>)index).get(field, value), pathMapper);
}
return mapNodes(((Index<Node>)index).get(field, value), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
private QueryEngine queryEngineFor(EmbeddedQueryEngine.Type type) {
private QueryEngine queryEngineFor(CypherQueryEngine.Type type) {
return graphDatabase.queryEngineFor(type);
}
@@ -219,62 +195,6 @@ public class Neo4jTemplate implements Neo4jOperations {
};
}
@Override
public <T> Iterable<T> traverse(TraversalDescription traversal, Node startNode, final PathMapper<T> pathMapper) {
notNull(startNode, "startNode", traversal, "traversal", pathMapper, "pathMapper");
try {
return mapPaths(traversal.traverse(startNode), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
private <T> Iterable<T> mapPaths(final Iterable<Path> paths, final PathMapper<T> pathMapper) {
return new PathMappingIterator().mapPaths(paths,pathMapper);
}
@Override
public <T> Iterable<T> traverseNext(Node startNode, final PathMapper<T> pathMapper, RelationshipType relationshipType, Direction direction) {
notNull(startNode, "startNode", relationshipType, "relationshipType", direction, "direction", pathMapper, "pathMapper");
try {
return mapRelationships(startNode.getRelationships(relationshipType, direction), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T> Iterable<T> traverseNext(Node startNode, final PathMapper<T> pathMapper, RelationshipType... relationshipTypes) {
notNull(startNode, "startNode", relationshipTypes, "relationshipType", pathMapper, "pathMapper");
try {
return mapRelationships(startNode.getRelationships(relationshipTypes), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T> Iterable<T> traverseNext(Node startNode, final PathMapper<T> pathMapper) {
notNull(startNode, "startNode", pathMapper, "pathMapper");
try {
return mapRelationships(startNode.getRelationships(), pathMapper);
} catch (RuntimeException e) {
throw translateExceptionIfPossible(e);
}
}
private <T> Iterable<T> mapRelationships(final Iterable<Relationship> relationships, final PathMapper<T> pathMapper) {
assert relationships != null;
assert pathMapper != null;
return new IterableWrapper<T, Relationship>(relationships) {
@Override
protected T underlyingObjectToObject(Relationship relationship) {
return pathMapper.mapPath(new RelationshipPath(relationship));
}
};
}
@Override
public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Property... properties) {
notNull(startNode, "startNode", endNode, "endNode", relationshipType, "relationshipType", properties, "properties");
@@ -286,19 +206,6 @@ public class Neo4jTemplate implements Neo4jOperations {
});
}
private <T extends PropertyContainer> T setProperties(T primitive, Map<String, Object> properties) {
assert primitive != null;
if (properties==null) return primitive;
for (Map.Entry<String, Object> prop : properties.entrySet()) {
if (prop.getValue()==null) {
primitive.removeProperty(prop.getKey());
} else {
primitive.setProperty(prop.getKey(), prop.getValue());
}
}
return primitive;
}
private static abstract class IndexHitsIterableWrapper<T, S extends PropertyContainer> extends IterableWrapper<T, S> implements ClosableIterable<T> {
private final IndexHits<S> indexHits;
private final PathMapper<T> pathMapper;
@@ -323,25 +230,12 @@ public class Neo4jTemplate implements Neo4jOperations {
}
@Override
public Iterable<Map<String, Object>> query(QueryEngine.Type engineType, String statement) {
return queryEngineFor(engineType).query(statement);
}
@Override
public <T> Iterable<T> query(QueryEngine.Type engineType, String statement, Class<T> type) {
return queryEngineFor(engineType).query(statement).to(type);
}
@Override
public <T> T queryForObject(QueryEngine.Type engineType, String statement, Class<T> type) {
return queryEngineFor(engineType).query(statement).to(type).single();
}
public QueryResult<Map<String, Object>> query(String statement) {
notNull(statement, "statement");
return queryEngineFor(QueryEngine.Type.Cypher).query(statement);
}
@Override
public QueryResult<Path> traverse(Node startNode, TraversalDescription traversal) {
notNull(startNode, "startNode", traversal, "traversal");
try {
@@ -351,6 +245,7 @@ public class Neo4jTemplate implements Neo4jOperations {
}
}
@Override
public <T extends PropertyContainer> QueryResult<T> lookup(String indexName, String field, Object value) {
notNull(field, "field", value, "value", indexName, "indexName");
try {
@@ -360,6 +255,7 @@ public class Neo4jTemplate implements Neo4jOperations {
throw translateExceptionIfPossible(e);
}
}
@Override
public <T extends PropertyContainer> QueryResult<T> lookup(String indexName, Object valueOrQueryObject) {
notNull(valueOrQueryObject, "valueOrQueryObject", indexName, "indexName");
try {
@@ -369,35 +265,6 @@ public class Neo4jTemplate implements Neo4jOperations {
throw translateExceptionIfPossible(e);
}
}
{
/*
final Iterable<Node> nodes = query("start n=(0) return n").to(Node.class);
final Iterable<Path> nodePaths = query("start n=(0) return n").to(Path.class);
final Iterable<Long> costs = lookup("index", "field", "value").to(Long.class, new ResultConverter<Relationship, Long>() {
@Override
public Long convert(Relationship value, Class<Long> type) {
return (Long) value.getProperty("cost");
}
});
final Iterable<Person> people = lookup("index", "field:value*").to(Person.class);
lookup("index", "field:value*").to(Node.class).handle(new Handler<Node>() {
@Override
public void handle(Node node) {
node.setProperty("count",((Integer)node.getProperty("count",0))+1);
}
});
final Iterable<Node> endNodes = traverse(start, desc).to(Node.class);
final Iterable<Relationship> lastRelationships = traverse(start, desc).to(Relationship.class);
final Iterable<Integer> pathLengths = traverse(start, desc).to(Integer.class, new ResultConverter<Path, Integer>() {
public Integer convert(Path path, Class<Integer> type) {
return path.length();
}
});
*/
}
}
/*

View File

@@ -24,13 +24,14 @@ import org.junit.Before;
import org.junit.Test;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.test.ImpermanentGraphDatabase;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.impl.transaction.SpringTransactionManager;
import org.springframework.dao.DataAccessException;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
import org.springframework.data.neo4j.support.path.PathMapper;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.jta.JtaTransactionManager;
@@ -248,40 +249,41 @@ public class Neo4jTemplateApiTest {
@Test
public void testQueryNodes() throws Exception {
assertSingleResult("node0", template.lookup("node", new TermQuery(new Term("name", "node0")), new NodeNameMapper()));
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", new NodeNameMapper()));
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")), new RelationshipNameMapper()));
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", new RelationshipNameMapper()));
assertSingleResult("rel1",template.lookup("relationship", "name", "rel1").to(String.class, new PropertyContainerNameConverter()));
}
@Test
public void testTraverse() throws Exception {
assertSingleResult("node1",template.traverse(Traversal.description().relationships(KNOWS).prune(Traversal.pruneAfterDepth(1)).filter(Traversal.returnAllButStartNode()), referenceNode, new NodeNameMapper()));
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 shouldGetDirectRelationship() throws Exception {
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper()));
assertSingleResult("rel1", template.convert(referenceNode.getRelationships()).to(String.class, new RelationshipNameConverter()));
}
@Test
public void shouldGetDirectRelationshipForType() throws Exception {
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper(), KNOWS));
assertSingleResult("rel1", template.convert(referenceNode.getRelationships(KNOWS)).to(String.class, new RelationshipNameConverter()));
}
@Test
public void shouldGetDirectRelationshipForTypeAndDirection() throws Exception {
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper(), KNOWS, Direction.OUTGOING));
assertSingleResult("rel1", template.convert(referenceNode.getRelationships(KNOWS, Direction.OUTGOING)).to(String.class, new RelationshipNameConverter()));
}
private <T> void assertSingleResult(T expected, Iterable<T> iterable) {
@@ -301,16 +303,30 @@ public class Neo4jTemplateApiTest {
assertEquals("rel2",relationship.getProperty("name","not set"));
}
private static class RelationshipNameMapper implements PathMapper<String> {
private static class PathRelationshipNameMapper implements ResultConverter<Path,String> {
@Override
public String mapPath(Path path) {
public String convert(Path path, Class<String> type) {
return (String) path.lastRelationship().getProperty("name","not set");
}
}
private static class NodeNameMapper implements PathMapper<String> {
private static class PathNodeNameMapper implements ResultConverter<Path,String> {
@Override
public String mapPath(Path path) {
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

@@ -17,12 +17,14 @@
package org.springframework.data.neo4j.template;
import org.junit.Test;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Traversal;
import org.springframework.data.neo4j.support.path.PathMapper;
import org.springframework.data.neo4j.conversion.Handler;
import org.springframework.data.neo4j.conversion.QueryResult;
import org.springframework.data.neo4j.core.GraphDatabase;
import java.util.HashSet;
import java.util.Set;
@@ -49,13 +51,14 @@ public class NeoTraversalTest extends NeoApiTest {
});
final Set<String> resultSet = new HashSet<String>();
template.traverse(Traversal.description().relationships(HAS).filter(returnAllButStartNode()).prune(Traversal.pruneAfterDepth(2)), template.getReferenceNode(), new PathMapper.WithoutResult() {
final TraversalDescription description = Traversal.description().relationships(HAS).filter(returnAllButStartNode()).prune(Traversal.pruneAfterDepth(2));
final QueryResult<Path> queryResult = template.traverse(template.getReferenceNode(), description);
queryResult.handle(new Handler<Path>() {
@Override
public void eachPath(Path path) {
String nodeName = (String) path.endNode().getProperty("name", "");
resultSet.add(nodeName);
}
});
public void handle(Path value) {
final String name = (String) value.endNode().getProperty("name", "");
resultSet.add(name);
}});
assertEquals("all members", new HashSet<String>(asList("grandpa", "grandma", "daughter", "son", "man", "wife", "family")), resultSet);
}