Neo4j Template Api Evolution
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class GraphDescription
|
||||
{
|
||||
|
||||
private Map<String, NodeInfo> nodes = new LinkedHashMap<String, NodeInfo>();
|
||||
|
||||
public GraphDescription(final Properties props)
|
||||
{
|
||||
if (props == null)
|
||||
throw new IllegalArgumentException("Properties must not be null");
|
||||
new PropertyParser(props).load(this);
|
||||
}
|
||||
|
||||
|
||||
public GraphDescription()
|
||||
{
|
||||
}
|
||||
|
||||
public NodeInfo add(final String nodeName, final String attributeName, final Object value)
|
||||
{
|
||||
return getNode(nodeName).setProperty(attributeName, value);
|
||||
}
|
||||
|
||||
private NodeInfo getNode(final String nodeName)
|
||||
{
|
||||
final NodeInfo node = nodes.get(nodeName);
|
||||
if (node != null) return node;
|
||||
final NodeInfo newNode = new NodeInfo(nodeName);
|
||||
nodes.put(nodeName, newNode);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public void relate(final String from, final RelationshipType type, final String to)
|
||||
{
|
||||
getNode(from).relateTo(type, getNode(to));
|
||||
}
|
||||
|
||||
void addToGraph(GraphDatabaseService graph)
|
||||
{
|
||||
boolean first = true;
|
||||
for (NodeInfo nodeInfo : nodes.values())
|
||||
{
|
||||
final Node node = first ? graph.getReferenceNode() : graph.createNode();
|
||||
first = false;
|
||||
nodeInfo.updateProperties(node);
|
||||
}
|
||||
|
||||
for (NodeInfo nodeInfo : nodes.values())
|
||||
{
|
||||
final Node from = graph.getNodeById(nodeInfo.getId());
|
||||
nodeInfo.updateRelations(from, graph);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.graph.UncategorizedGraphStoreException;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 18.02.11
|
||||
*/
|
||||
public abstract class GraphTransactionCallback<T> implements GraphCallback<T> {
|
||||
|
||||
public interface Status {
|
||||
void mustRollback();
|
||||
|
||||
void interimCommit();
|
||||
}
|
||||
|
||||
public abstract T doWithGraph(Status status, GraphDatabaseService graph) throws Exception;
|
||||
|
||||
@Override
|
||||
public T doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
final TransactionStatus status = new TransactionStatus(graph);
|
||||
try {
|
||||
return doWithGraph(status, graph);
|
||||
} catch (Exception e) {
|
||||
status.mustRollback();
|
||||
throw e;
|
||||
} finally {
|
||||
status.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TransactionStatus implements Status {
|
||||
private boolean rollback;
|
||||
private final GraphDatabaseService neo;
|
||||
private Transaction tx;
|
||||
|
||||
private TransactionStatus(final GraphDatabaseService neo) {
|
||||
if (neo == null)
|
||||
throw new IllegalArgumentException("GraphDatabaseService must not be null");
|
||||
this.neo = neo;
|
||||
begin();
|
||||
}
|
||||
|
||||
private void begin() {
|
||||
tx = neo.beginTx();
|
||||
}
|
||||
|
||||
public void mustRollback() {
|
||||
this.rollback = true;
|
||||
}
|
||||
|
||||
public void interimCommit() {
|
||||
finish();
|
||||
begin();
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
try {
|
||||
if (rollback) {
|
||||
tx.failure();
|
||||
} else {
|
||||
tx.success();
|
||||
}
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 19.02.11
|
||||
*/
|
||||
public abstract static class WithoutResult extends GraphTransactionCallback<Void> {
|
||||
@Override
|
||||
public Void doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
doWithGraphWithoutResult(status,graph);
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception;
|
||||
}
|
||||
}
|
||||
@@ -3,42 +3,39 @@ package org.springframework.data.graph.neo4j.template;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 19.02.11
|
||||
*/
|
||||
public interface Neo4jOperations {
|
||||
<T> T doInTransaction(GraphTransactionCallback<T> callback);
|
||||
<T> T update(GraphCallback<T> callback);
|
||||
|
||||
<T> T execute(GraphCallback<T> callback);
|
||||
<T> T exec(GraphCallback<T> callback);
|
||||
|
||||
Node getReferenceNode();
|
||||
|
||||
Node getNode(long id);
|
||||
|
||||
Node createNode(Property... props);
|
||||
Node createNode(Map<String, Object> props, String... indexFields);
|
||||
|
||||
Relationship getRelationship(long id);
|
||||
|
||||
Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props);
|
||||
Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map<String, Object> props, String... indexFields);
|
||||
|
||||
<T> Iterable<T> queryNodes(String indexName, Object queryOrQueryObject, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> query(String indexName, PathMapper<T> pathMapper, Object queryOrQueryObject);
|
||||
|
||||
<T> Iterable<T> retrieveNodes(String indexName, String field, String value, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> query(String indexName, PathMapper<T> pathMapper, String field, String value);
|
||||
|
||||
<T> Iterable<T> queryRelationships(String indexName, Object queryOrQueryObject, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> traverseGraph(Node startNode, PathMapper<T> pathMapper, TraversalDescription traversal);
|
||||
|
||||
<T> Iterable<T> retrieveRelationships(String indexName, String field, String value, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper, RelationshipType type, Direction direction);
|
||||
|
||||
<T> Iterable<T> traverse(Node startNode, TraversalDescription traversal, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper, RelationshipType... type);
|
||||
|
||||
<T> Iterable<T> traverseDirectRelationships(Node startNode, RelationshipType type, Direction direction, PathMapper<T> pathMapper);
|
||||
<T> Iterable<T> traverseNext(Node startNode, PathMapper<T> pathMapper);
|
||||
|
||||
<T> Iterable<T> traverseDirectRelationships(Node startNode, PathMapper<T> pathMapper, RelationshipType... type);
|
||||
|
||||
<T> Iterable<T> traverseDirectRelationships(Node startNode, PathMapper<T> pathMapper);
|
||||
|
||||
void index(Relationship relationship, String indexName, String field, Object value);
|
||||
|
||||
void index(Node node, String indexName, String field, Object value);
|
||||
<T extends PropertyContainer> T index(String indexName, T element, String field, Object value);
|
||||
<T extends PropertyContainer> T autoIndex(String indexName, T element, String... indexFields);
|
||||
}
|
||||
|
||||
@@ -18,20 +18,21 @@ package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.graphdb.index.IndexManager;
|
||||
import org.neo4j.graphdb.index.RelationshipIndex;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTranslator {
|
||||
public class Neo4jTemplate implements Neo4jOperations {
|
||||
|
||||
private final GraphDatabaseService graphDatabaseService;
|
||||
|
||||
private final Neo4jExceptionTranslator exceptionTranslator = new Neo4jExceptionTranslator();
|
||||
private final IndexManager index;
|
||||
|
||||
private static void notNull(Object... pairs) {
|
||||
assert pairs.length % 2 == 0 : "wrong number of pairs to check";
|
||||
@@ -45,22 +46,32 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
public Neo4jTemplate(final GraphDatabaseService graphDatabaseService) {
|
||||
notNull(graphDatabaseService, "graphDatabaseService");
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
index = this.graphDatabaseService.index();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doInTransaction(final GraphTransactionCallback<T> callback) {
|
||||
public <T> T update(final GraphCallback<T> callback) {
|
||||
notNull(callback, "callback");
|
||||
return execute(callback);
|
||||
Transaction tx = graphDatabaseService.beginTx();
|
||||
try {
|
||||
T result = exec(callback);
|
||||
tx.success();
|
||||
return result;
|
||||
} catch (RuntimeException e) {
|
||||
tx.failure();
|
||||
throw e;
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T execute(final GraphCallback<T> callback) {
|
||||
public <T> T exec(final GraphCallback<T> callback) {
|
||||
notNull(callback, "callback");
|
||||
try {
|
||||
return callback.doWithGraph(graphDatabaseService);
|
||||
@@ -81,12 +92,13 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node createNode(final Property... properties) {
|
||||
notNull(properties, "properties");
|
||||
return doInTransaction(new GraphTransactionCallback<Node>() {
|
||||
public Node createNode(final Map<String, Object> properties, final String... indexFields) {
|
||||
return update(new GraphCallback<Node>() {
|
||||
@Override
|
||||
public Node doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
return setProperties(graphDatabaseService.createNode(), properties);
|
||||
public Node doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Node node = graphDatabaseService.createNode();
|
||||
if (properties == null) return node;
|
||||
return autoIndex(null, setProperties(node, properties), indexFields);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -112,35 +124,48 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public void index(final Relationship relationship, final String indexName, final String field, final Object value) {
|
||||
notNull(relationship, "relationship", field, "field", value, "value");
|
||||
doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
relationshipIndex(indexName).add(relationship, field, value);
|
||||
}
|
||||
});
|
||||
public <T extends PropertyContainer> T autoIndex(String indexName, T element, String... indexFields) {
|
||||
for (String indexField : indexFields) {
|
||||
if (!element.hasProperty(indexField)) continue;
|
||||
index(indexName,element, indexField,element.getProperty(indexField));
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void index(final Node node, final String indexName, final String field, final Object value) {
|
||||
notNull(node, "node", field, "field", value, "value");
|
||||
doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
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");
|
||||
update(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
nodeIndex(indexName).add(node, field, value);
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
RelationshipIndex relationshipIndex = relationshipIndex(indexName);
|
||||
if (relationshipIndex != null && element instanceof Relationship) {
|
||||
relationshipIndex.add((Relationship) element, field, value);
|
||||
} else if (element instanceof Node) {
|
||||
nodeIndex(indexName).add((Node) element, field, value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Provided element is neither node nor relationship " + element);
|
||||
}
|
||||
}
|
||||
});
|
||||
return element;
|
||||
}
|
||||
|
||||
private RelationshipIndex relationshipIndex(String indexName) {
|
||||
return graphDatabaseService.index().forRelationships(indexName == null ? "relationship" : indexName);
|
||||
if (indexName != null && index.existsForRelationships(indexName)) {
|
||||
return index.forRelationships(indexName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> queryNodes(String indexName, Object queryOrQueryObject, final PathMapper<T> pathMapper) {
|
||||
public <T> Iterable<T> query(String indexName, final PathMapper<T> pathMapper, Object queryOrQueryObject) {
|
||||
notNull(queryOrQueryObject, "queryOrQueryObject", pathMapper, "pathMapper");
|
||||
try {
|
||||
RelationshipIndex relationshipIndex = relationshipIndex(indexName);
|
||||
if (relationshipIndex!=null) {
|
||||
return mapRelationships(relationshipIndex.query(queryOrQueryObject), pathMapper);
|
||||
}
|
||||
return mapNodes(nodeIndex(indexName).query(queryOrQueryObject), pathMapper);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateExceptionIfPossible(e);
|
||||
@@ -148,35 +173,19 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> retrieveNodes(String indexName, String field, String value, final PathMapper<T> pathMapper) {
|
||||
public <T> Iterable<T> query(String indexName, final PathMapper<T> pathMapper, String field, String value) {
|
||||
notNull(field, "field", value, "value", pathMapper, "pathMapper");
|
||||
try {
|
||||
RelationshipIndex relationshipIndex = relationshipIndex(indexName);
|
||||
if (relationshipIndex!=null) {
|
||||
return mapRelationships(relationshipIndex.get(field, value), pathMapper);
|
||||
}
|
||||
return mapNodes(nodeIndex(indexName).get(field, value), pathMapper);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateExceptionIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> queryRelationships(String indexName, Object queryOrQueryObject, final PathMapper<T> pathMapper) {
|
||||
notNull(queryOrQueryObject, "queryOrQueryObject", pathMapper, "pathMapper");
|
||||
try {
|
||||
return mapRelationships(relationshipIndex(indexName).query(queryOrQueryObject), pathMapper);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateExceptionIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> retrieveRelationships(String indexName, String field, String value, final PathMapper<T> pathMapper) {
|
||||
notNull(field, "field", value, "value", pathMapper, "pathMapper");
|
||||
try {
|
||||
return mapRelationships(relationshipIndex(indexName).get(field, value), pathMapper);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateExceptionIfPossible(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Iterable<T> mapNodes(final Iterable<Node> nodes, final PathMapper<T> pathMapper) {
|
||||
assert nodes != null;
|
||||
assert pathMapper != null;
|
||||
@@ -189,11 +198,11 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
private Index<Node> nodeIndex(String indexName) {
|
||||
return graphDatabaseService.index().forNodes(indexName == null ? "node" : indexName);
|
||||
return index.forNodes(indexName == null ? "node" : indexName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> traverse(Node startNode, TraversalDescription traversal, final PathMapper<T> pathMapper) {
|
||||
public <T> Iterable<T> traverseGraph(Node startNode, final PathMapper<T> pathMapper, TraversalDescription traversal) {
|
||||
notNull(startNode, "startNode", traversal, "traversal", pathMapper, "pathMapper");
|
||||
try {
|
||||
return mapPaths(traversal.traverse(startNode), pathMapper);
|
||||
@@ -214,7 +223,7 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> traverseDirectRelationships(Node startNode, RelationshipType relationshipType, Direction direction, final PathMapper<T> pathMapper) {
|
||||
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);
|
||||
@@ -224,7 +233,7 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> traverseDirectRelationships(Node startNode, final PathMapper<T> pathMapper, RelationshipType... relationshipTypes) {
|
||||
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);
|
||||
@@ -234,7 +243,7 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Iterable<T> traverseDirectRelationships(Node startNode, final PathMapper<T> pathMapper) {
|
||||
public <T> Iterable<T> traverseNext(Node startNode, final PathMapper<T> pathMapper) {
|
||||
notNull(startNode, "startNode", pathMapper, "pathMapper");
|
||||
try {
|
||||
return mapRelationships(startNode.getRelationships(), pathMapper);
|
||||
@@ -255,23 +264,27 @@ public class Neo4jTemplate implements Neo4jOperations, PersistenceExceptionTrans
|
||||
}
|
||||
|
||||
@Override
|
||||
public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Property... properties) {
|
||||
public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Map<String, Object> properties, final String... indexFields) {
|
||||
notNull(startNode, "startNode", endNode, "endNode", relationshipType, "relationshipType", properties, "properties");
|
||||
return doInTransaction(new GraphTransactionCallback<Relationship>() {
|
||||
return update(new GraphCallback<Relationship>() {
|
||||
@Override
|
||||
public Relationship doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
return setProperties(startNode.createRelationshipTo(endNode, relationshipType), properties);
|
||||
public Relationship doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Relationship relationship = startNode.createRelationshipTo(endNode, relationshipType);
|
||||
if (properties == null) return relationship;
|
||||
return autoIndex("relationship", setProperties(relationship, properties), indexFields);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <T extends PropertyContainer> T setProperties(T primitive, Property... properties) {
|
||||
private <T extends PropertyContainer> T setProperties(T primitive, Map<String, Object> properties) {
|
||||
assert primitive != null;
|
||||
assert properties != null;
|
||||
for (Property prop : properties) {
|
||||
if (prop == null)
|
||||
throw new IllegalArgumentException("at least one Property is null: " + Arrays.toString(properties));
|
||||
primitive.setProperty(prop.getName(), prop.getValue());
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class NodeInfo
|
||||
{
|
||||
|
||||
private final String name;
|
||||
private final Map<String, Object> props = new LinkedHashMap<String, Object>();
|
||||
|
||||
private final Set<RelationShipNodeInfo> relations = new LinkedHashSet<RelationShipNodeInfo>();
|
||||
private long id;
|
||||
|
||||
public NodeInfo(final String nodeName)
|
||||
{
|
||||
this.name = nodeName;
|
||||
}
|
||||
|
||||
public NodeInfo setProperty(final String name, final Object value)
|
||||
{
|
||||
this.props.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void relateTo(final RelationshipType type, final NodeInfo node)
|
||||
{
|
||||
this.relations.add(new RelationShipNodeInfo(type, node));
|
||||
}
|
||||
|
||||
public void setId(final long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void updateProperties(final Node node)
|
||||
{
|
||||
node.setProperty("name", name);
|
||||
for (Map.Entry<String, Object> prop : props.entrySet())
|
||||
{
|
||||
node.setProperty(prop.getKey(), prop.getValue());
|
||||
}
|
||||
setId(node.getId());
|
||||
}
|
||||
|
||||
void updateRelations(final Node from, final GraphDatabaseService nodeService)
|
||||
{
|
||||
for (RelationShipNodeInfo relation : relations)
|
||||
{
|
||||
final Node to = nodeService.getNodeById(relation.getNodeInfo().getId());
|
||||
from.createRelationshipTo(to, relation.getRelationshipType());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final NodeInfo nodeInfo = (NodeInfo) o;
|
||||
|
||||
return name.equals(nodeInfo.name);
|
||||
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -16,33 +16,28 @@
|
||||
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
public class Property
|
||||
{
|
||||
private final String name;
|
||||
private final Object value;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
private Property(final String name, final Object value)
|
||||
{
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Name must not be null");
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Value must not be null");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
public class PropertyMap {
|
||||
|
||||
private final Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
||||
public PropertyMap set(String name, Object value) {
|
||||
properties.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static Property _(String name, Object value)
|
||||
{
|
||||
return new Property(name, value);
|
||||
public static PropertyMap props() {
|
||||
return new PropertyMap();
|
||||
}
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
public Map<String, Object> toMap() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
public static Map<String, Object> _(String name, Object value) {
|
||||
return Collections.singletonMap(name,value);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.DynamicRelationshipType;
|
||||
import org.springframework.data.graph.neo4j.template.util.Converter;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class PropertyParser
|
||||
{
|
||||
private final Properties props;
|
||||
private final Converter converter = new Converter();
|
||||
|
||||
public PropertyParser(final Properties props)
|
||||
{
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public void load(final GraphDescription graph)
|
||||
{
|
||||
final SortedMap<Object, Object> sortedSet = new TreeMap<Object, Object>(props);
|
||||
for (Map.Entry<Object, Object> entry : sortedSet.entrySet())
|
||||
{
|
||||
if (entry.getKey() == null || entry.getValue() == null)
|
||||
throw new IllegalArgumentException(format("%s=%s is partially null%nproperties %s",
|
||||
entry.getKey(), entry.getValue(), props));
|
||||
|
||||
final String key = entry.getKey().toString();
|
||||
final String value = entry.getValue().toString();
|
||||
final String[] prop = key.split("\\.");
|
||||
if (prop.length == 2)
|
||||
{
|
||||
final String[] values = value.split(":");
|
||||
if (values.length != 2)
|
||||
graph.add(prop[0], prop[1], value);
|
||||
else
|
||||
{
|
||||
graph.add(prop[0], prop[1], converter.convert(values[0], values[1]));
|
||||
}
|
||||
} else
|
||||
{
|
||||
final String[] relationships = key.split("->");
|
||||
if (relationships.length == 2)
|
||||
{
|
||||
graph.relate(relationships[0], DynamicRelationshipType.withName(relationships[1]), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
class RelationShipNodeInfo
|
||||
{
|
||||
private final RelationshipType relationshipType;
|
||||
private final NodeInfo nodeInfo;
|
||||
|
||||
RelationShipNodeInfo(final RelationshipType relationshipType, final NodeInfo nodeInfo)
|
||||
{
|
||||
this.relationshipType = relationshipType;
|
||||
this.nodeInfo = nodeInfo;
|
||||
}
|
||||
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final RelationShipNodeInfo that = (RelationShipNodeInfo) o;
|
||||
|
||||
return nodeInfo.equals(that.nodeInfo) && relationshipType.name().equals(that.relationshipType.name());
|
||||
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return relationshipType.name().hashCode() * 31 + nodeInfo.hashCode();
|
||||
}
|
||||
|
||||
public NodeInfo getNodeInfo()
|
||||
{
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
public RelationshipType getRelationshipType()
|
||||
{
|
||||
return relationshipType;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,24 @@
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.NumericRangeQuery;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hibernate.ejb.criteria.ParameterContainer;
|
||||
import org.jboss.netty.util.HashedWheelTimer;
|
||||
import org.junit.*;
|
||||
import org.mockito.Mockito;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.kernel.ImpermanentGraphDatabase;
|
||||
import org.neo4j.kernel.Traversal;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.graph.neo4j.support.node.Neo4jHelper;
|
||||
|
||||
import javax.print.attribute.HashAttributeSet;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
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.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.data.graph.neo4j.template.Property._;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.graph.neo4j.template.PropertyMap._;
|
||||
import static org.springframework.data.graph.neo4j.template.PropertyMap.props;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
@@ -34,14 +28,17 @@ public class Neo4jTemplateApiTest {
|
||||
private static final DynamicRelationshipType KNOWS = DynamicRelationshipType.withName("knows");
|
||||
private static final DynamicRelationshipType HAS = DynamicRelationshipType.withName("has");
|
||||
private Neo4jTemplate template;
|
||||
private static ImpermanentGraphDatabase graphDatabase;
|
||||
private static GraphDatabaseService graphDatabase;
|
||||
private static PlatformTransactionManager tm;
|
||||
private Node referenceNode;
|
||||
private Relationship relationship1;
|
||||
private Node node1;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void startDb() throws Exception {
|
||||
graphDatabase = new ImpermanentGraphDatabase();
|
||||
// tm = new JtaTransactionManager(new SpringTransactionManager(graphDatabase));
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -86,9 +83,9 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test
|
||||
public void shouldExecuteCallbackInTransaction() throws Exception {
|
||||
Node refNode = template.doInTransaction(new GraphTransactionCallback<Node>() {
|
||||
Node refNode = template.update(new GraphCallback<Node>() {
|
||||
@Override
|
||||
public Node doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
public Node doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Node referenceNode = graph.getReferenceNode();
|
||||
referenceNode.setProperty("test", "testDoInTransaction");
|
||||
return referenceNode;
|
||||
@@ -101,10 +98,10 @@ public class Neo4jTemplateApiTest {
|
||||
@Test
|
||||
public void shouldRollbackTransactionOnException() {
|
||||
try {
|
||||
template.doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
template.update(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
graph.getReferenceNode().setProperty("test","shouldRollbackTransactionOnException");
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
graph.getReferenceNode().setProperty("test", "shouldRollbackTransactionOnException");
|
||||
throw new RuntimeException("please rollback");
|
||||
}
|
||||
});
|
||||
@@ -115,12 +112,18 @@ public class Neo4jTemplateApiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("until the ImpermanentGraphDatabase cast issue is resolved in neo4j")
|
||||
public void shouldRollbackViaStatus() throws Exception {
|
||||
template.doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
new TransactionTemplate(tm).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
graph.getReferenceNode().setProperty("test","shouldRollbackTransactionOnException");
|
||||
status.mustRollback();
|
||||
protected void doInTransactionWithoutResult(final TransactionStatus status) {
|
||||
template.update(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
graph.getReferenceNode().setProperty("test", "shouldRollbackTransactionOnException");
|
||||
status.setRollbackOnly();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Assert.assertThat((String) graphDatabase.getReferenceNode().getProperty("test","not set"), not("shouldRollbackTransactionOnException"));
|
||||
@@ -128,7 +131,7 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldNotConvertUserRuntimeExceptionToDataAccessException() {
|
||||
template.execute(new GraphCallback.WithoutResult() {
|
||||
template.exec(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
throw new RuntimeException();
|
||||
@@ -138,7 +141,7 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test(expected = DataAccessException.class)
|
||||
public void shouldConvertMissingTransactionExceptionToDataAccessException() {
|
||||
template.execute(new GraphCallback.WithoutResult() {
|
||||
template.exec(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
graph.createNode();
|
||||
@@ -147,7 +150,7 @@ public class Neo4jTemplateApiTest {
|
||||
}
|
||||
@Test(expected = DataAccessException.class)
|
||||
public void shouldConvertNotFoundExceptionToDataAccessException() {
|
||||
template.execute(new GraphCallback.WithoutResult() {
|
||||
template.exec(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
graph.getNodeById(Long.MAX_VALUE);
|
||||
@@ -161,7 +164,7 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test
|
||||
public void shouldExecuteCallback() throws Exception {
|
||||
Long refNodeId = template.execute(new GraphCallback<Long>() {
|
||||
Long refNodeId = template.exec(new GraphCallback<Long>() {
|
||||
@Override
|
||||
public Long doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
return graph.getReferenceNode().getId();
|
||||
@@ -177,17 +180,13 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test
|
||||
public void testCreateNode() throws Exception {
|
||||
Node node=template.createNode();
|
||||
Node node=template.createNode(null);
|
||||
assertNotNull("created node",node);
|
||||
}
|
||||
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void shouldFailForNullProperties() throws Exception {
|
||||
template.createNode(null);
|
||||
}
|
||||
@Test
|
||||
public void testCreateNodeWithProperties() throws Exception {
|
||||
Node node=template.createNode(_("test", "testCreateNodeWithProperties"));
|
||||
Node node=template.createNode(props().set("test", "testCreateNodeWithProperties").toMap());
|
||||
assertTestPropertySet(node, "testCreateNodeWithProperties");
|
||||
}
|
||||
|
||||
@@ -216,47 +215,47 @@ public class Neo4jTemplateApiTest {
|
||||
|
||||
@Test
|
||||
public void testIndexNode() throws Exception {
|
||||
template.index(node1,null,"name","node1");
|
||||
template.index(null, node1, "name","node1");
|
||||
Node lookedUpNode=graphDatabase.index().forNodes("node").get("name","node1").getSingle();
|
||||
assertThat("same node from index",lookedUpNode,is(node1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryNodes() throws Exception {
|
||||
assertSingleResult("node0", template.queryNodes(null, new TermQuery(new Term("name", "node0")), new NodeNameMapper()));
|
||||
assertSingleResult("node0", template.query(null, new NodeNameMapper(), new TermQuery(new Term("name", "node0"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveNodes() throws Exception {
|
||||
assertSingleResult("node0", template.retrieveNodes(null, "name", "node0", new NodeNameMapper()));
|
||||
assertSingleResult("node0", template.query(null, new NodeNameMapper(), "name", "node0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryRelationships() throws Exception {
|
||||
assertSingleResult("rel1", template.queryRelationships(null, new TermQuery(new Term("name", "rel1")), new RelationshipNameMapper()));
|
||||
assertSingleResult("rel1", template.query("relationship", new RelationshipNameMapper(), new TermQuery(new Term("name", "rel1"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveRelationships() throws Exception {
|
||||
assertSingleResult("rel1",template.retrieveRelationships(null, "name", "rel1", new RelationshipNameMapper()));
|
||||
assertSingleResult("rel1",template.query("relationship", new RelationshipNameMapper(), "name", "rel1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTraverse() throws Exception {
|
||||
assertSingleResult("node1",template.traverse(referenceNode, Traversal.description().relationships(KNOWS).prune(Traversal.pruneAfterDepth(1)).filter(Traversal.returnAllButStartNode()), new NodeNameMapper()));
|
||||
assertSingleResult("node1",template.traverseGraph(referenceNode, new NodeNameMapper(), Traversal.description().relationships(KNOWS).prune(Traversal.pruneAfterDepth(1)).filter(Traversal.returnAllButStartNode())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetDirectRelationship() throws Exception {
|
||||
assertSingleResult("rel1", template.traverseDirectRelationships(referenceNode, new RelationshipNameMapper()));
|
||||
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper()));
|
||||
}
|
||||
@Test
|
||||
public void shouldGetDirectRelationshipForType() throws Exception {
|
||||
assertSingleResult("rel1", template.traverseDirectRelationships(referenceNode, new RelationshipNameMapper(),KNOWS));
|
||||
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper(), KNOWS));
|
||||
}
|
||||
@Test
|
||||
public void shouldGetDirectRelationshipForTypeAndDirection() throws Exception {
|
||||
assertSingleResult("rel1", template.traverseDirectRelationships(referenceNode, KNOWS, Direction.OUTGOING, new RelationshipNameMapper()));
|
||||
assertSingleResult("rel1", template.traverseNext(referenceNode, new RelationshipNameMapper(), KNOWS, Direction.OUTGOING));
|
||||
}
|
||||
|
||||
private <T> void assertSingleResult(T expected, Iterable<T> iterable) {
|
||||
|
||||
@@ -15,7 +15,7 @@ public class Neo4jTemplateTest extends NeoApiTest {
|
||||
|
||||
@Test
|
||||
public void testRefNode() {
|
||||
Node refNodeById = new Neo4jTemplate(graph).execute(new GraphCallback<Node>() {
|
||||
Node refNodeById = new Neo4jTemplate(graph).exec(new GraphCallback<Node>() {
|
||||
public Node doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
return graph.getNodeById(refNode.getId());
|
||||
@@ -27,8 +27,8 @@ public class Neo4jTemplateTest extends NeoApiTest {
|
||||
@Test
|
||||
public void testSingleNode() {
|
||||
final Neo4jOperations template = new Neo4jTemplate(graph);
|
||||
template.doInTransaction(new GraphTransactionCallback<Void>() {
|
||||
public Void doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
template.update(new GraphCallback<Void>() {
|
||||
public Void doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
// TODO easy API Node node = graph.createNode(Property._("name", "Test"), Property._("size", 100));
|
||||
Node node = graph.createNode();
|
||||
@@ -43,8 +43,8 @@ public class Neo4jTemplateTest extends NeoApiTest {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
template.doInTransaction(new GraphTransactionCallback<Void>() {
|
||||
public Void doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
template.update(new GraphCallback<Void>() {
|
||||
public Void doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
final Relationship toTestNode = refNode.getSingleRelationship(HAS, Direction.OUTGOING);
|
||||
final Node nodeByRelationship = toTestNode.getEndNode();
|
||||
@@ -58,16 +58,18 @@ public class Neo4jTemplateTest extends NeoApiTest {
|
||||
@Test
|
||||
public void testRollback() {
|
||||
final Neo4jOperations template = new Neo4jTemplate(graph);
|
||||
template.doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
try {
|
||||
template.update(new GraphCallback.WithoutResult() {
|
||||
@Override
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
public void doWithGraphWithoutResult(GraphDatabaseService graph) throws Exception {
|
||||
Node node = graph.getReferenceNode();
|
||||
node.setProperty("test", "test");
|
||||
assertEquals("test", node.getProperty("test"));
|
||||
status.mustRollback();
|
||||
throw new RuntimeException();
|
||||
}
|
||||
});
|
||||
template.execute(new GraphCallback.WithoutResult() {
|
||||
} catch(RuntimeException ignore) {}
|
||||
template.exec(new GraphCallback.WithoutResult() {
|
||||
public void doWithGraphWithoutResult(final GraphDatabaseService graph) throws Exception {
|
||||
Node node = graph.getReferenceNode();
|
||||
assertFalse(node.hasProperty("test"));
|
||||
|
||||
@@ -7,10 +7,13 @@ import org.neo4j.kernel.EmbeddedGraphDatabase;
|
||||
|
||||
public abstract class NeoApiTest {
|
||||
protected GraphDatabaseService graph;
|
||||
protected Neo4jTemplate template;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
graph = new EmbeddedGraphDatabase("target/template-db");
|
||||
template = new Neo4jTemplate(graph);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -23,8 +26,8 @@ public abstract class NeoApiTest {
|
||||
|
||||
private void clear() {
|
||||
try {
|
||||
new Neo4jTemplate(graph).doInTransaction(new GraphTransactionCallback<Void>() {
|
||||
public Void doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
template.update(new GraphCallback<Void>() {
|
||||
public Void doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
for (Node node : graph.getAllNodes()) {
|
||||
for (Relationship relationship : node.getRelationships()) {
|
||||
relationship.delete();
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.Direction;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.data.graph.neo4j.template.NeoGraphDescriptionTest.Type.HAS;
|
||||
|
||||
|
||||
public class NeoGraphDescriptionTest extends NeoApiTest {
|
||||
|
||||
enum Type implements RelationshipType {
|
||||
HAS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadGraph() {
|
||||
final Neo4jOperations template = new Neo4jTemplate(graph);
|
||||
template.doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
final GraphDescription heaven = new GraphDescription();
|
||||
heaven.add("adam", "age", 1);
|
||||
heaven.add("eve", "age", 0);
|
||||
heaven.relate("adam", HAS, "eve");
|
||||
heaven.addToGraph(graph);
|
||||
checkHeaven(graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkHeaven(final GraphDatabaseService graph) {
|
||||
final Node adam = graph.getReferenceNode();
|
||||
assertEquals("adam", adam.getProperty("name"));
|
||||
assertEquals(1, adam.getProperty("age"));
|
||||
final Node eve = adam.getSingleRelationship(HAS, Direction.OUTGOING).getEndNode();
|
||||
assertEquals("eve", eve.getProperty("name"));
|
||||
assertEquals(0, eve.getProperty("age"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadGraphProps() {
|
||||
final Neo4jOperations template = new Neo4jTemplate(graph);
|
||||
template.doInTransaction(new GraphTransactionCallback.WithoutResult() {
|
||||
public void doWithGraphWithoutResult(Status status, GraphDatabaseService graph) throws Exception {
|
||||
final GraphDescription heaven = new GraphDescription(createGraphProperties());
|
||||
heaven.addToGraph(graph);
|
||||
checkHeaven(graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Properties createGraphProperties() throws IOException {
|
||||
Properties props = new Properties();
|
||||
props.load(new ByteArrayInputStream((
|
||||
"adam.age=Integer:1\n" +
|
||||
"eve.age=Integer:0\n" +
|
||||
"adam->HAS=eve"
|
||||
).getBytes("UTF-8")));
|
||||
return props;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
package org.springframework.data.graph.neo4j.template;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Path;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.neo4j.kernel.Traversal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.neo4j.kernel.Traversal.returnAllButStartNode;
|
||||
import static org.springframework.data.graph.neo4j.template.NeoTraversalTest.Type.HAS;
|
||||
import static org.springframework.data.graph.neo4j.template.PropertyMap._;
|
||||
|
||||
public class NeoTraversalTest extends NeoApiTest {
|
||||
|
||||
@@ -22,73 +24,56 @@ public class NeoTraversalTest extends NeoApiTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleTraverse() {
|
||||
runAndCheckTraverse(Traversal.description().filter(returnAllButStartNode()).relationships(HAS), "grandpa", "grandma","daughter","son","man","wife" );
|
||||
}
|
||||
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testComplexTraversal() {
|
||||
final TraversalDescription traversal = Traversal.description().relationships(HAS).prune(Traversal.pruneAfterDepth(1));
|
||||
runAndCheckTraverse(traversal, "grandpa", "grandma", "daughter", "son", "man", "wife");
|
||||
}
|
||||
|
||||
private void runAndCheckTraverse(final TraversalDescription traversal, final String... names) {
|
||||
final Neo4jOperations template = new Neo4jTemplate(graph);
|
||||
template.doInTransaction(new GraphTransactionCallback<Void>() {
|
||||
public Void doWithGraph(Status status, GraphDatabaseService graph) throws Exception {
|
||||
createFamily(graph);
|
||||
template.update(new GraphCallback<Void>() {
|
||||
public Void doWithGraph(GraphDatabaseService graph) throws Exception {
|
||||
createFamily();
|
||||
return null;
|
||||
}});
|
||||
Iterable<String> result=template.traverse(template.getReferenceNode(), traversal,
|
||||
new PathMapper<String>() {
|
||||
@Override
|
||||
public String mapPath(Path path) {
|
||||
return (String) path.endNode().getProperty("name", "");
|
||||
}
|
||||
});
|
||||
assertEquals("all members", asList(names), IteratorUtil.<String>asCollection(result));
|
||||
}
|
||||
});
|
||||
|
||||
final Set<String> resultSet = new HashSet<String>();
|
||||
template.traverseGraph(template.getReferenceNode(), new PathMapper.WithoutResult() {
|
||||
@Override
|
||||
public void eachPath(Path path) {
|
||||
String nodeName = (String) path.endNode().getProperty("name", "");
|
||||
resultSet.add(nodeName);
|
||||
}
|
||||
}, Traversal.description().filter(returnAllButStartNode()).relationships(HAS));
|
||||
assertEquals("all members", new HashSet<String>(asList("grandpa", "grandma", "daughter", "son", "man", "wife", "family")), resultSet);
|
||||
}
|
||||
|
||||
private void createFamily(final GraphDatabaseService graph) {
|
||||
final GraphDescription family = new GraphDescription();
|
||||
family.add("family", "type", "small");
|
||||
family.relate("family", HAS, "wife");
|
||||
family.relate("family", HAS, "man");
|
||||
|
||||
private void createFamily() {
|
||||
|
||||
family.add("man", "age", 35);
|
||||
family.add("wife", "age", 30);
|
||||
family.relate("man", Type.MARRIED, "wife");
|
||||
family.relate("wife", Type.MARRIED, "man");
|
||||
family.relate("man", Type.WIFE, "wife");
|
||||
family.relate("wife", Type.HUSBAND, "man");
|
||||
Node family = template.createNode(_("name", "family"));
|
||||
Node man = template.createNode(_("name", "wife"));
|
||||
Node wife = template.createNode(_("name", "man"));
|
||||
family.createRelationshipTo(man, HAS);
|
||||
family.createRelationshipTo(wife, HAS);
|
||||
|
||||
family.add("daughter", "age", 10);
|
||||
family.add("son", "age", 8);
|
||||
Node daughter = template.createNode(_("name", "daughter"));
|
||||
family.createRelationshipTo(daughter, HAS);
|
||||
Node son = template.createNode(_("name", "son"));
|
||||
family.createRelationshipTo(son, HAS);
|
||||
man.createRelationshipTo(son, Type.CHILD);
|
||||
wife.createRelationshipTo(son, Type.CHILD);
|
||||
man.createRelationshipTo(daughter, Type.CHILD);
|
||||
wife.createRelationshipTo(daughter, Type.CHILD);
|
||||
|
||||
family.relate("family", HAS, "son");
|
||||
family.relate("family", HAS, "daughter");
|
||||
Node grandma = template.createNode(_("name", "grandma"));
|
||||
Node grandpa = template.createNode(_("name", "grandpa"));
|
||||
|
||||
family.relate("man", Type.CHILD, "son");
|
||||
family.relate("wife", Type.CHILD, "son");
|
||||
family.relate("man", Type.CHILD, "daughter");
|
||||
family.relate("wife", Type.CHILD, "daughter");
|
||||
family.createRelationshipTo(grandma, HAS);
|
||||
family.createRelationshipTo(grandpa, HAS);
|
||||
|
||||
family.add("grandma", "age", 60);
|
||||
family.add("grandpa", "age", 75);
|
||||
grandma.createRelationshipTo(man, Type.CHILD);
|
||||
grandpa.createRelationshipTo(man, Type.CHILD);
|
||||
|
||||
family.relate("family", HAS, "grandma");
|
||||
family.relate("family", HAS, "grandpa");
|
||||
grandma.createRelationshipTo(son, Type.GRANDSON);
|
||||
grandpa.createRelationshipTo(son, Type.GRANDSON);
|
||||
grandma.createRelationshipTo(daughter, Type.GRANDDAUGHTER);
|
||||
grandpa.createRelationshipTo(daughter, Type.GRANDDAUGHTER);
|
||||
|
||||
family.relate("grandpa", Type.CHILD, "man");
|
||||
family.relate("grandma", Type.CHILD, "man");
|
||||
|
||||
family.relate("grandpa", Type.GRANDSON, "son");
|
||||
family.relate("grandma", Type.GRANDSON, "son");
|
||||
family.relate("grandpa", Type.GRANDDAUGHTER, "daughter");
|
||||
family.relate("grandma", Type.GRANDDAUGHTER, "daughter");
|
||||
|
||||
family.addToGraph(graph);
|
||||
graph.getReferenceNode().createRelationshipTo(family,HAS);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user