Neo4jOperations cleanup

This commit is contained in:
Michael Hunger
2011-10-17 14:17:57 +02:00
parent 807d60108e
commit 2344576c20
9 changed files with 144 additions and 85 deletions

View File

@@ -53,7 +53,7 @@ public class TraversalTest extends EntityTestBase {
group.setName("dev");
group.addPerson(p);
final TraversalDescription traversalDescription = Traversal.description().relationships(DynamicRelationshipType.withName("persons")).evaluator(Evaluators.excludeStartPosition());
Iterable<Person> people = neo4jTemplate.<Person>findAllByTraversal(group,Person.class, traversalDescription);
Iterable<Person> people = neo4jTemplate.<Person>traverse(group, Person.class, traversalDescription);
final HashSet<Person> found = new HashSet<Person>();
for (Person person : people) {
found.add(person);
@@ -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 = (Iterable<EntityPath<Group, Person>>) neo4jTemplate.<EntityPath<Group,Person>>findAllByTraversal(group, EntityPath.class, traversalDescription);
Iterable<EntityPath<Group,Person>> paths = (Iterable<EntityPath<Group, Person>>) neo4jTemplate.<EntityPath<Group,Person>>traverse(group, EntityPath.class, traversalDescription);
for (EntityPath<Group, Person> path : paths) {
assertEquals(group, path.startEntity());
assertEquals(p, path.endEntity());

View File

@@ -104,7 +104,7 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory {
@Override
public Object getValue(final Object entity) {
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(entity, property,params);
return doReturn(template.findAllByTraversal(entity,target, traversalDescription));
return doReturn(template.traverse(entity, target, traversalDescription));
}

View File

@@ -231,13 +231,13 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
}
@Override
public boolean isEntity() {
return super.isEntity() && (isRelationshipEntity() || isNodeEntity());
return super.isEntity() && (hasRelationshipEntityType() || hasNodeEntityType());
}
private boolean isRelationshipEntity() {
private boolean hasRelationshipEntityType() {
return getType().isAnnotationPresent(RelationshipEntity.class);
}
private boolean isNodeEntity() {
private boolean hasNodeEntityType() {
return getType().isAnnotationPresent(NodeEntity.class);
}
}

View File

@@ -34,7 +34,7 @@ public class NodeGraphRepository<T> extends AbstractGraphRepository<Node, T> imp
@Override
public <N> Iterable<T> findAllByTraversal(final N start, final TraversalDescription traversalDescription) {
return template.findAllByTraversal(start, clazz, traversalDescription);
return template.traverse(start, clazz, traversalDescription);
}
@SuppressWarnings("unchecked")

View File

@@ -213,4 +213,8 @@ public class MappingInfrastructure {
public CypherQueryExecutor getCypherQueryExecutor() {
return cypherQueryExecutor;
}
public Neo4jMappingContext getMappingContext() {
return mappingContext;
}
}

View File

@@ -25,9 +25,7 @@ import org.neo4j.helpers.collection.ClosableIterable;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
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;
@@ -99,8 +97,10 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
}
@Override
@SuppressWarnings({"unchecked"})
public <T> GraphRepository<T> repositoryFor(Class<T> clazz) {
notNull(clazz,"entity type");
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);
@@ -108,13 +108,16 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type) {
notNull(type, "entity type");
return infrastructure.getIndexProvider().getIndex(type, null);
}
public <S extends PropertyContainer> Index<S> getIndex(String name) {
notNull(name, "index name");
return infrastructure.getIndexProvider().getIndex(null, name);
}
@Override
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName) {
return infrastructure.getIndexProvider().getIndex(type, indexName, null);
}
@@ -132,33 +135,44 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
}
@Override
public <T> ClosableIterable<T> findAll(final Class<T> entityClass) {
notNull(entityClass,"entity type");
return infrastructure.getTypeRepresentationStrategies().findAll(entityClass);
}
@Override
public <T> long count(final Class<T> entityClass) {
notNull(entityClass,"entity type");
return infrastructure.getTypeRepresentationStrategies().count(entityClass);
}
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
notNull(state,"node or relationship");
return infrastructure.getEntityPersister().createEntityFromStoredType(state);
}
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
notNull(state,"node or relationship",type,"entity class");
return infrastructure.getEntityPersister().createEntityFromState(state, type);
}
@Override
public <S extends PropertyContainer, T> T projectTo(Object entity, Class<T> targetType) {
notNull(entity,"entity",targetType,"new entity class");
return infrastructure.getEntityPersister().projectTo(entity, targetType);
}
@Override
@SuppressWarnings("unchecked")
public <S extends PropertyContainer> S getPersistentState(Object entity) {
notNull(entity,"entity");
return infrastructure.getEntityPersister().getPersistentState(entity);
}
@SuppressWarnings("unchecked")
public <S extends PropertyContainer, T> T setPersistentState(T entity, S state) {
notNull(entity,"entity",state,"node or relationship");
infrastructure.getEntityPersister().setPersistentState(entity, state);
return entity;
}
@@ -168,7 +182,9 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
infrastructure.getTypeRepresentationStrategies().postEntityCreation(node, entityClass);
}
@Override
public void remove(Object entity) {
notNull(entity,"entity");
infrastructure.getEntityRemover().remove(entity);
}
@@ -193,7 +209,8 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return infrastructure.getGraphDatabase().createNode(properties);
}
public <T> T createNode(Class<T> target, Map<String, Object> properties) {
@Override
public <T> T createNodeAs(Class<T> target, Map<String, Object> properties) {
final Node node = createNode(properties);
if (isNodeEntity(target)) {
infrastructure.getTypeRepresentationStrategies().postEntityCreation(node, target);
@@ -201,6 +218,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return convert(node, target);
}
@Override
public Result<Node> createNodes(Map<String, Object> firstNode, Map<String, Object>... otherNodes) {
Collection<Node> result = new ArrayList<Node>(otherNodes.length + 1);
result.add(createNode(firstNode));
@@ -210,7 +228,8 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return convert(result);
}
public <T> Iterable<T> createNodes(Class<T> target, Map<String, Object> firstNode, Map<String, Object>... otherNodes) {
@Override
public <T> Iterable<T> createNodesAs(Class<T> target, Map<String, Object> firstNode, Map<String, Object>... otherNodes) {
final TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy = isNodeEntity(target) ? infrastructure.getTypeRepresentationStrategies().getNodeTypeRepresentationStrategy() : null;
Collection<Node> result = new ArrayList<Node>(otherNodes.length + 1);
result.add(createNode(firstNode, target, nodeTypeRepresentationStrategy));
@@ -243,13 +262,14 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
public boolean isNodeEntity(Class<?> targetType) {
return targetType.isAnnotationPresent(NodeEntity.class);
return infrastructure.getMappingContext().isNodeEntity(targetType);
}
public boolean isRelationshipEntity(Class targetType) {
return targetType.isAnnotationPresent(RelationshipEntity.class);
return infrastructure.getMappingContext().isRelationshipEntity(targetType);
}
@Override
@SuppressWarnings("unchecked")
public <T> T save(T entity) {
return (T) infrastructure.getEntityPersister().persist(entity);
@@ -259,6 +279,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return infrastructure.getEntityStateHandler().isManaged(entity);
}
@Override
public Object query(String statement, Map<String, Object> params, final TypeInformation<?> typeInformation) {
final TypeInformation<?> actualType = typeInformation.getActualType();
final Class<?> targetType = actualType.getType();
@@ -271,6 +292,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return infrastructure.getCypherQueryExecutor().queryForObject(statement, targetType, params);
}
@Override
public <R> R getRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType) {
notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType");
final Relationship relationship = infrastructure.getEntityStateHandler().getRelationshipTo(start, end, relationshipType);
@@ -278,11 +300,13 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
return infrastructure.getEntityPersister().createEntityFromState(relationship, relationshipEntityClass);
}
@Override
public void removeRelationshipBetween(Object start, Object end, String type) {
notNull(start,"start",end,"end",type,"relationshipType");
infrastructure.getEntityRemover().removeRelationshipTo(start, end, type);
}
@Override
public <R> R createRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType, boolean allowDuplicates) {
notNull(start,"start",end,"end",relationshipEntityClass,"relationshipEntityClass",relationshipType,"relationshipType");
final RelationshipResult result = infrastructure.getEntityStateHandler().relateTo(start, end, relationshipType, allowDuplicates);
@@ -420,14 +444,16 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
}
@Override
@SuppressWarnings("unchecked")
public <T> Iterable<T> findAllByTraversal(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
public <T> Iterable<T> traverse(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
notNull(entity,"entity",targetType,"target type",traversalDescription,"traversal description");
return traverse(entity, traversalDescription).to((Class<T>) targetType);
}
@Override
public Result<Path> traverse(Node startNode, TraversalDescription traversal) {
notNull(startNode, "startNode", traversal, "traversal");
notNull(startNode, "start node", traversal, "traversal");
try {
return this.convert(traversal.traverse(startNode));
} catch (RuntimeException e) {
@@ -437,7 +463,7 @@ public class Neo4jTemplate implements Neo4jOperations, EntityPersister {
@Override
public <T extends PropertyContainer> Result<T> lookup(String indexName, String field, Object value) {
notNull(field, "field", value, "value", indexName, "indexName");
notNull(field, "field", value, "value", indexName, "index name");
try {
Index<T> index = getIndex(null, indexName);
return convert(index.get(field, value));

View File

@@ -22,6 +22,18 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
* @since 17.10.11
*/
public class ParameterCheck {
public static void notNull(Object value, String msg) {
if (value==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg + " is required; it must not be null");
}
public static void notNull(Object value, String msg,Object value2, String msg2) {
if (value==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg + " is required; it must not be null");
if (value2==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg2 + " is required; it must not be null");
}
public static void notNull(Object value, String msg,Object value2, String msg2,Object value3, String msg3) {
if (value==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg + " is required; it must not be null");
if (value2==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg2 + " is required; it must not be null");
if (value3==null) throw new InvalidDataAccessApiUsageException("[Assertion failed] - " + msg3 + " is required; it must not be null");
}
public 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) {

View File

@@ -17,15 +17,20 @@
package org.springframework.data.neo4j.template;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.helpers.collection.ClosableIterable;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.data.util.TypeInformation;
import java.util.Map;
/**
* A template with convenience operations, exception translation and implicit transaction for modifying methods
*
* @author mh
* @since 19.02.11
*/
@@ -33,92 +38,72 @@ public interface Neo4jOperations {
/**
* Executes the callback in a NON-transactional context.
*
* @param callback for executing graph operations NON-transactionally, not null
* @param <T> return type
* @param <T> return type
* @return whatever the callback chooses to return
* @throws org.springframework.dao.DataAccessException subclasses
* @throws org.springframework.dao.DataAccessException
* subclasses
*/
<T> T exec(GraphCallback<T> callback);
<T> GraphRepository<T> repositoryFor(Class<T> clazz);
<T> T getReferenceNode(Class<T> target);
/**
* Delegates to the GraphDatabase
*
* @param id node id
* @return the requested node of the underlying graph database
* @throws NotFoundException
*/
Node getNode(long id);
/**
* Transactionally creates the node, sets the properties (if any) and indexes the given fields (if any).
* Two shortcut means of providing the properties (very short with static imports)
* <code>template.createNode(Property._("name","value"));</code>
* <code>template.createNode(Property._("name","value","prop","anotherValue"));</code>
*
*
* @param props properties to be set at node creation might be null
* @return the newly created node
*/
Node createNode(Map<String,Object> props);
Node createNode(Map<String, Object> props);
Node createNode();
<T> T createNodeAs(Class<T> target, Map<String, Object> properties);
Result<Node> createNodes(Map<String, Object> firstNode, Map<String, Object>... otherNodes);
<T> Iterable<T> createNodesAs(Class<T> target, Map<String, Object> firstNode, Map<String, Object>... otherNodes);
/**
* Delegates to the GraphDatabase
*
* @param id relationship id
* @return the requested relationship of the underlying graph database
* @throws NotFoundException
*/
Relationship getRelationship(long id);
/**
* Transactionally creates the relationship, sets the properties (if any) and indexes the given fielss (if any)
* Two shortcut means of providing the properties (very short with static imports)
* <code>template.createRelationship(from,to,TYPE, Property._("name","value"));</code>
* <code>template.createRelationship(from,to,TYPE, Property._("name","value","prop","anotherValue"));</code>
*
* @param startNode start-node of relationship
* @param endNode end-node of relationship
* @param type relationship type, might by an enum implementing RelationshipType or a DynamicRelationshipType.withName("name")
* @param props optional initial properties
* @return the newly created relationship
*/
Relationship createRelationshipBetween(Node startNode, Node endNode, RelationshipType type, Map<String, Object> props);
<R> R getRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType);
void removeRelationshipBetween(Object start, Object end, String type);
<R> R createRelationshipBetween(Object start, Object end, Class<R> relationshipEntityClass, String relationshipType, boolean allowDuplicates);
<S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName);
/**
* Indexes the given field and value for the element.
*
* @param indexName Name of the index, will be checked against existing indexes according to the given element
* assumes a "node" node index or "relationship" relationship index for a null value
* @param element node or relationship to index
* @param field field to index
* @param value value to index
* @param <T> the provided element type
* assumes a "node" node index or "relationship" relationship index for a null value
* @param element node or relationship to index
* @param field field to index
* @param value value to index
* @param <T> the provided element type
* @return the provided element for convenience
*/
<T extends PropertyContainer> T index(String indexName, T element, String field, Object value);
/**
* Converts the Iterable into a QueryResult object for uniform handling. E.g.
* template.convert(node.getRelationships());
*/
<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.
*/
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>.
*/
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.
*/
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.
@@ -131,20 +116,52 @@ public interface Neo4jOperations {
*/
<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);
/**
* Delegates to the GraphDatabase
* @return the reference node of the underlying graph database
*/
<T> T getReferenceNode(Class<T> target);
Object query(String statement, Map<String, Object> params, TypeInformation<?> typeInformation);
QueryEngine queryEngineFor(QueryType type);
/**
* 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.
*/
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>.
*/
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.
*/
Result<Path> traverse(Node startNode, TraversalDescription traversal);
Result<Path> traverse(Object start, TraversalDescription traversal);
<T> Iterable<T> traverse(Object entity, Class<?> targetType, TraversalDescription traversalDescription);
/**
* Converts the Iterable into a QueryResult object for uniform handling. E.g.
* template.convert(node.getRelationships());
*/
<T> Result<T> convert(Iterable<T> iterable);
<T> T convert(Object value, Class<T> type);
<T> ClosableIterable<T> findAll(Class<T> entityClass);
<T> long count(Class<T> entityClass);
<S extends PropertyContainer, T> T projectTo(Object entity, Class<T> targetType);
<T> T save(T entity);
void remove(Object entity);
<S extends PropertyContainer> S getPersistentState(Object entity);
}

View File

@@ -203,7 +203,7 @@ public class GraphDatabaseContextTemplateTest {
@Test
@Transactional
public void testCreateEntityWithProperties() throws Exception {
Person person = neo4jTemplate.createNode(Person.class, map("name", "name"));
Person person = neo4jTemplate.createNodeAs(Person.class, map("name", "name"));
assertNotNull("created node", person);
assertEquals("property created", "name", person.getName());
}
@@ -211,7 +211,7 @@ public class GraphDatabaseContextTemplateTest {
@Test
@Transactional
public void testCreateNodeTypeWithProperties() throws Exception {
Node person = neo4jTemplate.createNode(Node.class, map("name", "name"));
Node person = neo4jTemplate.createNodeAs(Node.class, map("name", "name"));
assertNotNull("created node", person);
assertEquals("property created", "name", person.getProperty("name"));
}