added gremlin REST addon, parameters for queries, updated documentation
This commit is contained in:
@@ -17,10 +17,13 @@
|
||||
package org.springframework.data.neo4j.rest;
|
||||
|
||||
|
||||
import org.neo4j.helpers.collection.MapUtil;
|
||||
import org.springframework.data.neo4j.conversion.*;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngine;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
@@ -42,11 +45,8 @@ public class RestCypherQueryEngine implements QueryEngine<Map<String,Object>> {
|
||||
|
||||
@Override
|
||||
public QueryResult<Map<String, Object>> query(String statement, Map<String, Object> params) {
|
||||
return executeStatement(statement);
|
||||
}
|
||||
|
||||
private RestQueryResult executeStatement(String statement) {
|
||||
final RequestResult requestResult = restRequest.get("ext/CypherPlugin/graphdb/execute_query", JsonHelper.createJsonFrom(Collections.singletonMap("query", statement)));
|
||||
final String parametrizedStatement = QueryResultBuilder.replaceParams(statement, params);
|
||||
final RequestResult requestResult = restRequest.get("ext/CypherPlugin/graphdb/execute_query", JsonHelper.createJsonFrom(MapUtil.map("query", parametrizedStatement)));
|
||||
return new RestQueryResult(restRequest.toMap(requestResult),restGraphDatabase,resultConverter);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.rest.RestGraphDatabase;
|
||||
import org.springframework.data.neo4j.support.query.QueryOperationsTest;
|
||||
import org.springframework.data.neo4j.support.query.QueryEngineTest;
|
||||
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
@@ -39,7 +39,7 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi
|
||||
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/support/Neo4jGraphPersistenceTest-context.xml",
|
||||
"classpath:RestTest-context.xml"})
|
||||
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
|
||||
public class RestQueryEngineTest extends QueryOperationsTest {
|
||||
public class RestQueryEngineTest extends QueryEngineTest {
|
||||
|
||||
@Autowired
|
||||
RestGraphDatabase restGraphDatabase;
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.lang.annotation.Target;
|
||||
@Target({ElementType.FIELD,ElementType.METHOD})
|
||||
public @interface Query {
|
||||
/**
|
||||
* @return Query to be executed %d will be replaced by the node-id of the current entity other placeholders by the given params
|
||||
* @return Query to be executed %start will be replaced by the node-id of the current entity other placeholders (%name) by the given named params
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
@@ -46,7 +46,7 @@ public @interface Query {
|
||||
Class<?> elementClass() default Object.class;
|
||||
|
||||
/**
|
||||
* @return parameters that are replaced in the to the @see query-string
|
||||
* @return tuple list of parameters that are replaced in the to the @see query-string {"name", value}
|
||||
*/
|
||||
String[] params() default {};
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class QueryResultBuilder<T> implements QueryResult<T> {
|
||||
public static String replaceParams(String statement, Map<String, Object> params) {
|
||||
if (params==null || params.isEmpty()) return statement;
|
||||
for (Map.Entry<String, Object> param : params.entrySet()) {
|
||||
statement = statement.replaceAll(":"+param.getKey(),""+param.getValue());
|
||||
statement = statement.replaceAll("%"+param.getKey()+"\\b",""+param.getValue());
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ package org.springframework.data.neo4j.core;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jNodeBacking;
|
||||
import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface introduced to objects annotated with @NodeEntity by the {@link org.springframework.data.neo4j.support.node.Neo4jNodeBacking} aspect.
|
||||
@@ -125,6 +129,11 @@ public interface NodeBacked extends GraphBacked<Node> {
|
||||
<R extends RelationshipBacked> R getRelationshipTo(NodeBacked target, Class<R> relationshipClass, String type);
|
||||
|
||||
|
||||
<T> Iterable<T> findAllByQuery(final String query, final Class<T> targetType,Map<String,Object> params);
|
||||
|
||||
Iterable<Map<String,Object>> findAllByQuery(final String query,Map<String,Object> params);
|
||||
|
||||
<T> T findByQuery(final String query, final Class<T> targetType,Map<String,Object> params);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.data.neo4j.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.support.GenericTypeExtractor;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.data.neo4j.support.DoReturn.doReturn;
|
||||
@@ -48,13 +49,16 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory<NodeBacke
|
||||
protected final Field field;
|
||||
private final String query;
|
||||
private Class<?> target;
|
||||
protected String[] params;
|
||||
protected String[] annotationParams;
|
||||
private boolean iterableResult;
|
||||
|
||||
public QueryFieldAccessor(final Field field) {
|
||||
this.field = field;
|
||||
final Query query = field.getAnnotation(Query.class);
|
||||
this.params = query.params();
|
||||
this.annotationParams = query.params();
|
||||
if ((this.annotationParams.length % 2) != 0) {
|
||||
throw new IllegalArgumentException("Number of parameters has to be even to construct a parameter map");
|
||||
}
|
||||
this.query = query.value();
|
||||
this.iterableResult = Iterable.class.isAssignableFrom(field.getType());
|
||||
this.target = resolveTarget(query,field);
|
||||
@@ -77,23 +81,23 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory<NodeBacke
|
||||
|
||||
@Override
|
||||
public Object getValue(final NodeBacked nodeBacked) {
|
||||
final String queryString = String.format(this.query, (Object[])createPlaceholderParams(nodeBacked));
|
||||
return doReturn(executeQuery(nodeBacked, queryString));
|
||||
return doReturn(executeQuery(nodeBacked, this.query, createPlaceholderParams(nodeBacked)));
|
||||
}
|
||||
|
||||
private Object executeQuery(NodeBacked nodeBacked, String queryString) {
|
||||
if (!iterableResult) return nodeBacked.findByQuery(queryString,this.target);
|
||||
if (Map.class.isAssignableFrom(target)) return nodeBacked.findAllByQuery(queryString);
|
||||
return nodeBacked.findAllByQuery(queryString, this.target);
|
||||
private Object executeQuery(NodeBacked nodeBacked, String queryString, Map<String, Object> params) {
|
||||
if (!iterableResult) return nodeBacked.findByQuery(queryString,this.target,params);
|
||||
if (Map.class.isAssignableFrom(target)) return nodeBacked.findAllByQuery(queryString,params);
|
||||
return nodeBacked.findAllByQuery(queryString, this.target,params);
|
||||
}
|
||||
|
||||
private Object[] createPlaceholderParams(NodeBacked nodeBacked) {
|
||||
if (params.length==0) return new Object[] {nodeBacked.getNodeId()};
|
||||
|
||||
final Object[] parameters = new Object[1 + this.params.length];
|
||||
parameters[0]=nodeBacked.getNodeId();
|
||||
System.arraycopy(this.params,0,parameters,1,this.params.length);
|
||||
return parameters;
|
||||
private Map<String, Object> createPlaceholderParams(NodeBacked nodeBacked) {
|
||||
Map<String,Object> params=new HashMap<String, Object>();
|
||||
params.put("start",nodeBacked.getNodeId());
|
||||
if (annotationParams.length==0) return params;
|
||||
for (int i = 0; i < annotationParams.length; i+=2) {
|
||||
params.put(annotationParams[i],annotationParams[i+1]);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ package org.springframework.data.neo4j.fieldaccess;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.neo4j.annotation.GraphTraversal;
|
||||
import org.springframework.data.neo4j.annotation.Query;
|
||||
import org.springframework.data.neo4j.core.FieldTraversalDescriptionBuilder;
|
||||
import org.springframework.data.neo4j.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory;
|
||||
import org.springframework.data.neo4j.support.GenericTypeExtractor;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -56,11 +58,19 @@ public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeB
|
||||
public TraversalFieldAccessor(final Field field) {
|
||||
this.field = field;
|
||||
final GraphTraversal graphEntityTraversal = field.getAnnotation(GraphTraversal.class);
|
||||
this.target = graphEntityTraversal.elementClass();
|
||||
this.target = resolveTarget(graphEntityTraversal,field);
|
||||
this.params = graphEntityTraversal.params();
|
||||
this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal);
|
||||
}
|
||||
|
||||
private Class<? extends NodeBacked> resolveTarget(GraphTraversal graphTraversal, Field field) {
|
||||
if (!graphTraversal.elementClass().equals(Object.class)) return graphTraversal.elementClass();
|
||||
final Class<?> result = GenericTypeExtractor.resolveFieldType(field);
|
||||
if (!NodeBacked.class.isAssignableFrom(result)) throw new IllegalArgumentException("The target result type of the traversal is no node entity: "+field);
|
||||
return (Class<? extends NodeBacked>) result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(NodeBacked nodeBacked) {
|
||||
return false;
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.util.Assert;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -150,19 +151,28 @@ public class GraphRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
private String prepareQuery(Object[] args) {
|
||||
final Parameters parameters = getParameters();
|
||||
Object[] resolvedParameters = resolveParameters(args,parameters.getBindableParameters());
|
||||
String baseQuery = String.format(query, (Object[]) resolvedParameters);
|
||||
String queryString = this.query;
|
||||
if (parameters.hasSortParameter()) {
|
||||
baseQuery = addSorting(baseQuery, (Sort) args[parameters.getSortIndex()]);
|
||||
queryString = addSorting(queryString, (Sort) args[parameters.getSortIndex()]);
|
||||
}
|
||||
if (parameters.hasPageableParameter()) {
|
||||
final Pageable pageable = getPageable(args);
|
||||
if (pageable!=null) {
|
||||
baseQuery = addSorting(baseQuery, pageable.getSort());
|
||||
baseQuery = addPaging(baseQuery, pageable);
|
||||
queryString = addSorting(queryString, pageable.getSort());
|
||||
queryString = addPaging(queryString, pageable);
|
||||
}
|
||||
}
|
||||
return baseQuery;
|
||||
return queryString;
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Object> resolveParams(Object[] parameters) {
|
||||
Map<String,Object> params=new HashMap<String, Object>();
|
||||
for (Parameter parameter : getParameters().getBindableParameters()) {
|
||||
final Object value = parameters[parameter.getIndex()];
|
||||
params.put(parameter.getName(),resolveParameter(value));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private Pageable getPageable(Object[] args) {
|
||||
@@ -191,17 +201,6 @@ public class GraphRepositoryFactory extends RepositoryFactorySupport {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object[] resolveParameters(Object[] parameters, Parameters bindableParameters) {
|
||||
final int paramCount = bindableParameters.getNumberOfParameters();
|
||||
final Object[] result = new Object[paramCount];
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
final Parameter parameter = bindableParameters.getParameter(i);
|
||||
final Object value = parameters[parameter.getIndex()];
|
||||
result[i] = resolveParameter(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object resolveParameter(Object parameter) {
|
||||
if (parameter instanceof NodeBacked) {
|
||||
return ((NodeBacked)parameter).getNodeId();
|
||||
@@ -251,24 +250,25 @@ public class GraphRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
Map<String, Object> params = queryMethod.resolveParams(parameters);
|
||||
final String queryString = queryMethod.prepareQuery(parameters);
|
||||
return dispatchQuery(queryString,queryMethod.getPageable(parameters));
|
||||
return dispatchQuery(queryString,params,queryMethod.getPageable(parameters));
|
||||
}
|
||||
|
||||
private Object dispatchQuery(String queryString, Pageable pageable) {
|
||||
private Object dispatchQuery(String queryString, Map<String, Object> params, Pageable pageable) {
|
||||
final QueryMethod.Type queryResultType = queryMethod.getType();
|
||||
if (queryResultType== QueryMethod.Type.PAGING) {
|
||||
return queryPaged(queryString,pageable);
|
||||
return queryPaged(queryString,params,pageable);
|
||||
}
|
||||
if (iterableResult) {
|
||||
if (compoundType.isAssignableFrom(Map.class)) return queryExecutor.queryForList(queryString);
|
||||
return queryExecutor.query(queryString, queryMethod.getCompoundType());
|
||||
if (compoundType.isAssignableFrom(Map.class)) return queryExecutor.queryForList(queryString,params);
|
||||
return queryExecutor.query(queryString, queryMethod.getCompoundType(),params);
|
||||
}
|
||||
return queryExecutor.queryForObject(queryString, queryMethod.getReturnType());
|
||||
return queryExecutor.queryForObject(queryString, queryMethod.getReturnType(),params);
|
||||
}
|
||||
|
||||
private Object queryPaged(String queryString, Pageable pageable) {
|
||||
final Iterable<?> result = queryExecutor.query(queryString, queryMethod.getCompoundType());
|
||||
private Object queryPaged(String queryString, Map<String, Object> params, Pageable pageable) {
|
||||
final Iterable<?> result = queryExecutor.query(queryString, queryMethod.getCompoundType(),params);
|
||||
return createPage(result, pageable);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelatedTo;
|
||||
import org.springframework.data.neo4j.annotation.GraphProperty;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.Query;
|
||||
import org.springframework.data.neo4j.annotation.RelatedToVia;
|
||||
import org.springframework.data.neo4j.annotation.GraphTraversal;
|
||||
|
||||
@@ -71,6 +72,7 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
|
||||
declare @field: @RelatedToVia * (@Entity @NodeEntity(partial=true) *).*:@Transient;
|
||||
declare @field: @GraphId * (@Entity @NodeEntity(partial=true) *).*:@Transient;
|
||||
declare @field: @GraphTraversal * (@Entity @NodeEntity(partial=true) *).*:@Transient;
|
||||
declare @field: @Query * (@Entity @NodeEntity(partial=true) *).*:@Transient;
|
||||
|
||||
|
||||
|
||||
@@ -183,19 +185,20 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields<No
|
||||
final Traverser traverser = traversalDescription.traverse(this.getPersistentState());
|
||||
return new NodeBackedNodeIterableWrapper<T>(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
}
|
||||
public <T> Iterable<T> NodeBacked.findAllByQuery(final String query, final Class<T> targetType) {
|
||||
|
||||
public <T> Iterable<T> NodeBacked.findAllByQuery(final String query, final Class<T> targetType, Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
return executor.query(query, targetType);
|
||||
return executor.query(query, targetType,params);
|
||||
}
|
||||
|
||||
public Iterable<Map<String,Object>> NodeBacked.findAllByQuery(final String query) {
|
||||
public Iterable<Map<String,Object>> NodeBacked.findAllByQuery(final String query,Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
return executor.queryForList(query);
|
||||
return executor.queryForList(query,params);
|
||||
}
|
||||
|
||||
public <T> T NodeBacked.findByQuery(final String query, final Class<T> targetType) {
|
||||
public <T> T NodeBacked.findByQuery(final String query, final Class<T> targetType,Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
return executor.queryForObject(query, targetType);
|
||||
return executor.queryForObject(query, targetType,params);
|
||||
}
|
||||
|
||||
public <S extends NodeBacked, E extends NodeBacked> Iterable<EntityPath<S,E>> NodeBacked.findAllPathsByTraversal(TraversalDescription traversalDescription) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.conversion.EntityResultConverter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -36,23 +35,19 @@ public class CypherQueryExecutor implements QueryOperations<Map<String,Object>>
|
||||
queryEngine = new CypherQueryEngine(ctx.getGraphDatabaseService(), converter);
|
||||
}
|
||||
|
||||
public Iterable<Map<String, Object>> queryForList(String statement, Map<String,Object>...params) {
|
||||
public Iterable<Map<String, Object>> queryForList(String statement, Map<String,Object> params) {
|
||||
return queryEngine.query(statement,mergeParams(params));
|
||||
}
|
||||
|
||||
public <T> Iterable<T> query(String statement, Class<T> type, Map<String,Object>...params) {
|
||||
public <T> Iterable<T> query(String statement, Class<T> type, Map<String,Object> params) {
|
||||
return queryEngine.query(statement,mergeParams(params)).to(type);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String statement, Class<T> type, Map<String,Object>...params) {
|
||||
public <T> T queryForObject(String statement, Class<T> type, Map<String,Object> params) {
|
||||
return (T) queryEngine.query(statement,mergeParams(params)).to(type).single();
|
||||
}
|
||||
private Map<String,Object> mergeParams(Map<String,Object>...params) {
|
||||
if (params==null || params.length==0) return Collections.emptyMap();
|
||||
Map<String,Object> result=new HashMap<String, Object>();
|
||||
for (Map<String, Object> map : params) {
|
||||
result.putAll(map);
|
||||
}
|
||||
return result;
|
||||
private Map<String,Object> mergeParams(Map<String,Object> params) {
|
||||
if (params==null) return Collections.emptyMap();
|
||||
return params;
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ import java.util.Map;
|
||||
* @since 28.06.11
|
||||
*/
|
||||
public interface QueryOperations<R> {
|
||||
Iterable<R> queryForList(String statement, Map<String,Object>...params);
|
||||
Iterable<R> queryForList(String statement, Map<String,Object> params);
|
||||
|
||||
<T> Iterable<T> query(String statement, Class<T> type, Map<String,Object>...params);
|
||||
<T> Iterable<T> query(String statement, Class<T> type, Map<String,Object> params);
|
||||
|
||||
<T> T queryForObject(String statement, Class<T> type, Map<String,Object>...params);
|
||||
<T> T queryForObject(String statement, Class<T> type, Map<String,Object> params);
|
||||
}
|
||||
|
||||
@@ -66,16 +66,16 @@ public class Person {
|
||||
@RelatedToVia(type = "knows", elementClass = Friendship.class)
|
||||
private Iterable<Friendship> friendships;
|
||||
|
||||
@Query(value = "start person=(%d) match (person)<-[:boss]-(boss) return boss")
|
||||
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss")
|
||||
private Person bossByQuery;
|
||||
|
||||
@Query(value = "start person=(%d) match (person)<-[:boss]-(boss) return boss.%s",params = "name")
|
||||
@Query(value = "start person=(%start) match (person)<-[:boss]-(boss) return boss.%property",params = {"property","name"})
|
||||
private String bossName;
|
||||
|
||||
@Query(value = "start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
|
||||
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member",elementClass = Person.class)
|
||||
private Iterable<Person> otherTeamMembers;
|
||||
|
||||
@Query(value = "start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
|
||||
@Query(value = "start person=(%start) match (person)<-[:persons]-(team)-[:persons]->(member) return member.name, member.age")
|
||||
private Iterable<Map<String,Object>> otherTeamMemberData;
|
||||
|
||||
public String getBossName() {
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.neo4j.annotation.Query;
|
||||
import org.springframework.data.neo4j.repository.GraphRepository;
|
||||
import org.springframework.data.neo4j.repository.NamedIndexRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,19 +32,19 @@ import java.util.Map;
|
||||
*/
|
||||
public interface PersonRepository extends GraphRepository<Person>, NamedIndexRepository<Person> {
|
||||
|
||||
@Query("start team=(%d) match (team)-[:persons]->(member) return member")
|
||||
Iterable<Person> findAllTeamMembers(Group team);
|
||||
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
|
||||
Iterable<Person> findAllTeamMembers(@Param("team") Group team);
|
||||
|
||||
@Query("start team=(%d) match (team)-[:persons]->(member) return member.name,member.age")
|
||||
Iterable<Map<String,Object>> findAllTeamMemberData(Group team);
|
||||
@Query("start team=(%team) match (team)-[:persons]->(member) return member.name,member.age")
|
||||
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("team") Group team);
|
||||
|
||||
@Query("start person=(%d) match (boss)-[:boss]->(person) return boss")
|
||||
Person findBoss(Person person);
|
||||
@Query("start person=(%person) match (boss)-[:boss]->(person) return boss")
|
||||
Person findBoss(@Param("person") Person person);
|
||||
|
||||
Group findTeam(Person person);
|
||||
Group findTeam(@Param("person") Person person);
|
||||
|
||||
@Query("start team=(%d) match (team)-[:persons]->(member) return member")
|
||||
Page<Person> findAllTeamMembersPaged(Pageable page, Group team);
|
||||
@Query("start team=(%d) match (team)-[:persons]->(member) return member")
|
||||
Iterable<Person> findAllTeamMembersSorted(Group team, Sort sort);
|
||||
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
|
||||
Page<Person> findAllTeamMembersPaged(@Param("team") Group team, Pageable page);
|
||||
@Query("start team=(%team) match (team)-[:persons]->(member) return member")
|
||||
Iterable<Person> findAllTeamMembersSorted(@Param("team") Group team, Sort sort);
|
||||
}
|
||||
|
||||
@@ -93,21 +93,21 @@ public class GraphRepositoryTest {
|
||||
@Transactional
|
||||
public void testFindPaged() {
|
||||
final PageRequest page = new PageRequest(0, 1, Sort.Direction.ASC, "member.name");
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(page, testTeam.sdg);
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(testTeam.sdg,page);
|
||||
assertThat(teamMemberPage1, hasItem(testTeam.david));
|
||||
}
|
||||
@Test
|
||||
@Transactional
|
||||
public void testFindPagedDescending() {
|
||||
final PageRequest page = new PageRequest(0, 2, Sort.Direction.DESC, "member.name");
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(page, testTeam.sdg);
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(testTeam.sdg,page);
|
||||
assertEquals(asList(testTeam.michael, testTeam.emil), asCollection(teamMemberPage1));
|
||||
assertThat(teamMemberPage1.isFirstPage(), is(true));
|
||||
}
|
||||
@Test
|
||||
@Transactional
|
||||
public void testFindPagedNull() {
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(null, testTeam.sdg);
|
||||
Page<Person> teamMemberPage1 = personRepository.findAllTeamMembersPaged(testTeam.sdg,null);
|
||||
assertEquals(asList(testTeam.michael, testTeam.emil,testTeam.david), asCollection(teamMemberPage1));
|
||||
assertThat(teamMemberPage1.isFirstPage(), is(true));
|
||||
assertThat(teamMemberPage1.isLastPage(), is(false));
|
||||
|
||||
@@ -86,7 +86,7 @@ public class QueryEngineTest {
|
||||
@Test
|
||||
@Transactional
|
||||
public void testQueryList() throws Exception {
|
||||
final String queryString = "start person=(:michael,:david) return person.name, person.age";
|
||||
final String queryString = "start person=(%michael,%david) return person.name, person.age";
|
||||
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("michael",idFor(michael), "david",idFor(testTeam.david))));
|
||||
|
||||
assertEquals(asList(testTeam.simpleRowFor(michael,"person"),testTeam.simpleRowFor(testTeam.david,"person")),result);
|
||||
@@ -94,14 +94,14 @@ public class QueryEngineTest {
|
||||
|
||||
@Test
|
||||
public void testQueryListOfTypeNode() throws Exception {
|
||||
final String queryString = "start person=(name_index,name,\":name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final Collection<Node> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Node.class));
|
||||
|
||||
assertEquals(asList(nodeFor(testTeam.emil)),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryListOfTypePerson() throws Exception {
|
||||
final String queryString = "start person=(name_index,name,\":name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final Collection<Person> result = IteratorUtil.asCollection(queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter(graphDatabaseContext)));
|
||||
|
||||
assertEquals(asList(testTeam.emil),result);
|
||||
@@ -113,7 +113,7 @@ public class QueryEngineTest {
|
||||
|
||||
@Test
|
||||
public void testQuerySingleOfTypePerson() throws Exception {
|
||||
final String queryString = "start person=(name_index,name,\":name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:boss]- (boss) return boss";
|
||||
final Person result = queryEngine.query(queryString, michaelsName()).to(Person.class, new EntityResultConverter<Map<String,Object>,Person>(graphDatabaseContext)).single();
|
||||
|
||||
assertEquals(testTeam.emil,result);
|
||||
@@ -141,14 +141,14 @@ public class QueryEngineTest {
|
||||
|
||||
@Test
|
||||
public void testQueryForObjectAsString() throws Exception {
|
||||
final String queryString = "start person=(name_index,name,\":name\") match (person) <-[:persons]- (team) return team.name";
|
||||
final String queryString = "start person=(name_index,name,\"%name\") match (person) <-[:persons]- (team) return team.name";
|
||||
final String result = queryEngine.query(queryString, michaelsName()).to(String.class).single();
|
||||
|
||||
assertEquals(testTeam.sdg.getName(),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsEnum() throws Exception {
|
||||
final String queryString = "start person=(name_index,name,\":name\") return person.personality";
|
||||
final String queryString = "start person=(name_index,name,\"%name\") return person.personality";
|
||||
final Personality result = queryEngine.query(queryString, michaelsName()).to(Personality.class).single();
|
||||
|
||||
assertEquals(michael.getPersonality(),result);
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.neo4j.support.query;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.internal.matchers.IsCollectionContaining;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.neo4j.Group;
|
||||
import org.springframework.data.neo4j.Person;
|
||||
import org.springframework.data.neo4j.Personality;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.TestTeam;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 13.06.11
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/support/Neo4jGraphPersistenceTest-context.xml"})
|
||||
@Transactional
|
||||
public class QueryExecutorTest {
|
||||
@Autowired
|
||||
GraphDatabaseContext graphDatabaseContext;
|
||||
private CypherQueryExecutor queryExecutor;
|
||||
private TestTeam testTeam;
|
||||
private Person michael;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
testTeam = new TestTeam();
|
||||
testTeam.createSDGTeam();
|
||||
queryExecutor = new CypherQueryExecutor(graphDatabaseContext);
|
||||
michael = testTeam.michael;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testQueryList() throws Exception {
|
||||
final String queryString = String.format("start person=(%d,%d) return person.name, person.age", michael.getNodeId(), testTeam.david.getNodeId());
|
||||
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryExecutor.queryForList(queryString));
|
||||
|
||||
assertEquals(asList(testTeam.simpleRowFor(michael,"person"),testTeam.simpleRowFor(testTeam.david,"person")),result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryListOfTypePerson() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:boss]- (boss) return boss", michael.getName());
|
||||
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
|
||||
|
||||
assertEquals(asList(testTeam.emil),result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOtherTeamMembers() throws Exception {
|
||||
final String queryString = String.format("start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member", michael.getNodeId());
|
||||
System.out.println("testTeam = " + testTeam.sdg.getPersons());
|
||||
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
|
||||
|
||||
assertThat(result, IsCollectionContaining.hasItems(testTeam.david, testTeam.emil));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAllTeamMembersByTeam() throws Exception {
|
||||
final String queryString = String.format("start team=(Group,name,\"%s\") match (team)-[:persons]->(member) return member", testTeam.sdg.getName());
|
||||
final Collection<Person> result = IteratorUtil.asCollection(queryExecutor.query(queryString, Person.class));
|
||||
|
||||
assertThat(result, IsCollectionContaining.hasItems(testTeam.david,testTeam.michael));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryForObjectAsGroup() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team", michael.getName());
|
||||
final Group result = queryExecutor.queryForObject(queryString, Group.class);
|
||||
|
||||
assertEquals(testTeam.sdg,result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsString() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team.name", michael.getName());
|
||||
final String result = queryExecutor.queryForObject(queryString, String.class);
|
||||
|
||||
assertEquals(testTeam.sdg.getName(),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsEnum() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") return person.personality", michael.getName());
|
||||
final Personality result = queryExecutor.queryForObject(queryString, Personality.class);
|
||||
|
||||
assertEquals(michael.getPersonality(),result);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
/**
|
||||
* Copyright 2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.neo4j.support.query;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.internal.matchers.IsCollectionContaining;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.neo4j.Person;
|
||||
import org.springframework.data.neo4j.Personality;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.Person;
|
||||
import org.springframework.data.neo4j.Personality;
|
||||
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.TestTeam;
|
||||
import org.springframework.data.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 13.06.11
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/support/Neo4jGraphPersistenceTest-context.xml"})
|
||||
@Transactional
|
||||
public class QueryOperationsTest {
|
||||
@Autowired
|
||||
protected ConversionService conversionService;
|
||||
@Autowired
|
||||
private GraphDatabaseContext graphDatabaseContext;
|
||||
private CypherQueryExecutor queryOperations;
|
||||
private TestTeam testTeam;
|
||||
private Person michael;
|
||||
private GraphDatabase graphDatabase;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
graphDatabase = createGraphDatabase();
|
||||
testTeam = new TestTeam();
|
||||
testTeam.createSDGTeam();
|
||||
queryOperations = new CypherQueryExecutor(graphDatabaseContext);
|
||||
//new DefaultQueryOperations<Map<String,Object>>(graphDatabase.queryEngineFor(QueryEngine.Type.Cypher));
|
||||
michael = testTeam.michael;
|
||||
}
|
||||
|
||||
@BeforeTransaction
|
||||
public void cleanDb() {
|
||||
Neo4jHelper.cleanDb(graphDatabaseContext);
|
||||
}
|
||||
|
||||
protected GraphDatabase createGraphDatabase() throws Exception {
|
||||
final DelegatingGraphDatabase graphDatabase = new DelegatingGraphDatabase(graphDatabaseContext.getGraphDatabaseService());
|
||||
graphDatabase.setConversionService(conversionService);
|
||||
return graphDatabase;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testQueryList() throws Exception {
|
||||
final String queryString = String.format("start person=(%d,%d) return person.name, person.age", idFor(michael), idFor(testTeam.david));
|
||||
final Collection<Map<String,Object>> result = IteratorUtil.asCollection(queryOperations.queryForList(queryString));
|
||||
|
||||
assertEquals(asList(testTeam.simpleRowFor(michael,"person"),testTeam.simpleRowFor(testTeam.david,"person")),result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryListOfTypePerson() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:boss]- (boss) return boss", michael.getName());
|
||||
final Collection<Node> result = IteratorUtil.asCollection(queryOperations.query(queryString, Node.class));
|
||||
|
||||
assertEquals(asList(nodeFor(testTeam.emil)),result);
|
||||
|
||||
}
|
||||
|
||||
private Node nodeFor(final NodeBacked entity) {
|
||||
return entity.getPersistentState();
|
||||
}
|
||||
private long idFor(final NodeBacked entity) {
|
||||
return entity.getNodeId();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryOtherTeamMembers() throws Exception {
|
||||
final String queryString = String.format("start person=(%d) match (person)<-[:persons]-(team)-[:persons]->(member) return member", idFor(michael));
|
||||
System.out.println("testTeam = " + testTeam.sdg.getPersons());
|
||||
final Collection<Node> result = IteratorUtil.asCollection(queryOperations.query(queryString, Node.class));
|
||||
|
||||
assertThat(result, IsCollectionContaining.hasItems(nodeFor(testTeam.david), nodeFor(testTeam.emil)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryAllTeamMembersByTeam() throws Exception {
|
||||
final String queryString = String.format("start team=(Group,name,\"%s\") match (team)-[:persons]->(member) return member", testTeam.sdg.getName());
|
||||
final Collection<Node> result = IteratorUtil.asCollection(queryOperations.query(queryString, Node.class));
|
||||
|
||||
assertThat(result, IsCollectionContaining.hasItems(nodeFor(testTeam.david),nodeFor(testTeam.michael)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryForObjectAsGroup() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team", michael.getName());
|
||||
final Node result = queryOperations.queryForObject(queryString, Node.class);
|
||||
|
||||
assertEquals(nodeFor(testTeam.sdg),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsString() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") match (person) <-[:persons]- (team) return team.name", michael.getName());
|
||||
final String result = queryOperations.queryForObject(queryString, String.class);
|
||||
|
||||
assertEquals(testTeam.sdg.getName(),result);
|
||||
}
|
||||
@Test
|
||||
public void testQueryForObjectAsEnum() throws Exception {
|
||||
final String queryString = String.format("start person=(name_index,name,\"%s\") return person.personality", michael.getName());
|
||||
final Personality result = queryOperations.queryForObject(queryString, Personality.class);
|
||||
|
||||
assertEquals(michael.getPersonality(),result);
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
Person.findTeam=start p=(%d) match (p)<-[:persons]-(group) return group
|
||||
Person.findTeam=start p=(%person) match (p)<-[:persons]-(group) return group
|
||||
@@ -150,7 +150,7 @@
|
||||
<property name="namedQueries">
|
||||
<bean class="org.springframework.data.repository.core.support.PropertiesBasedNamedQueries">
|
||||
<constructor-arg>
|
||||
<props><prop key="Person.findTeam">start p=(%d) match (p)<-[:persons]-(group) return group</prop></props>
|
||||
<props><prop key="Person.findTeam">start p=(%person) match (p)<-[:persons]-(group) return group</prop></props>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</property>
|
||||
|
||||
@@ -48,6 +48,15 @@
|
||||
The current version that does not show incorrect errors is AspectJ 1.6.12.M1 (included in STS 2.7.0.M2), previous versions are reported
|
||||
to mislead the user.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
There might be some issues with the eclipse maven plugin not adding AspectJ files correctly to the build path. If you encounter issues, please try the following:
|
||||
|
||||
Try editing the build path to <code>include **/*.aj</code> for the spring-data-neo4j project.
|
||||
You can do this by selecting "Build Path -> Configure Build Path ..." from the Package Explorer.
|
||||
Then for the <code>spring-data-neo4j/src/main/java</code> add <code>**/*.aj</code> to the Included path.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
The AspectJ support in IntelliJ IDEA lacks some of the features. JetBrains is working on improving
|
||||
the situation in their upcoming 10.5 release of their popular IDE. Their latest work is available
|
||||
|
||||
@@ -114,19 +114,19 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Executes the given query, replacing the first %d with the node-id and returning the results converted to the target type.</term>
|
||||
<term>Executes the given query, replacing <code>%start</code> with the node-id and returning the results converted to the target type.</term>
|
||||
<listitem>
|
||||
<para><code><T> Iterable<T> NodeBacked.findAllByQuery(final String query, final Class<T> targetType)</code></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Executes the given query, replacing the first %d with the node-id and returning the original result, but with nodes and relationships replaced by their appropriate entities.</term>
|
||||
<term>Executes the given query, replacing <code>%start</code> with the node-id and returning the original result, but with nodes and relationships replaced by their appropriate entities.</term>
|
||||
<listitem>
|
||||
<para><code>Iterable<Map<String,Object>> NodeBacked.findAllByQuery(final String query)</code></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Executes the given query, replacing the first %d with the node-id and returns a single result converted to the target type.</term>
|
||||
<term>Executes the given query, replacing <code>%start</code> with the node-id and returns a single result converted to the target type.</term>
|
||||
<listitem>
|
||||
<para><code><T> T NodeBacked.findByQuery(final String query, final Class<T> targetType)</code></para>
|
||||
</listitem>
|
||||
|
||||
@@ -72,28 +72,33 @@ public class Movie {
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>@GraphQuery: fields as query result views</title>
|
||||
<title>@Query: fields as query result views</title>
|
||||
<para>
|
||||
The <code>@GraphQuery</code> annotation leverages the delegation infrastructure used by the
|
||||
The <code>@Query</code> annotation leverages the delegation infrastructure used by the
|
||||
Spring Data Graph aspects. It provides dynamic fields which, when accessed, return the values
|
||||
selected by the provided query language expression. The provided query must contain a placeholder
|
||||
for the id of the current entity <code>start n=(%d) match n-[:FRIEND]->friend return friend</code>
|
||||
As graph queries can return variable number of entities the annotation can be put onto fields
|
||||
with a single value, an Iterable of a type or an Iterable of <code>Map<String,Object></code>.
|
||||
The class of the resulting node entities must right now provided with the <code>elementClass</code> attribute.
|
||||
Additional parameters are added to the query with Java's String.format substitution.
|
||||
selected by the provided query language expression. The provided query must contain a placeholder named <code>%start</code>
|
||||
for the id of the current entity. For instance <code>start n=(%start) match n-[:FRIEND]->friend return friend</code>.
|
||||
Graph queries can return variable number of entities. That's why annotation can be put onto fields
|
||||
with a single value, an Iterable of a concrete type or an Iterable of <code>Map<String,Object></code>.
|
||||
Additional parameters are taken from the params attribute of the <code>@Query</code> annotation.
|
||||
The tuples form key-value pairs that are provided to the query at execution time.
|
||||
</para>
|
||||
<example>
|
||||
<title>@GraphQuery from a node entity</title>
|
||||
<title>@Graph on a node entity field</title>
|
||||
<programlisting language="java"><![CDATA[@NodeEntity
|
||||
public class Group {
|
||||
@GraphQuery(value = "start n=(%d) match (n)-[:%s]->(friend) return friend",
|
||||
elementClass = Person.class, params = "FRIEND")
|
||||
@Query(value = "start n=(%start) match (n)-[:%relType]->(friend) return friend",
|
||||
params = {"relType", "FRIEND"})
|
||||
private Iterable<Person> friends;
|
||||
}
|
||||
]]></programlisting>
|
||||
|
||||
</example>
|
||||
<para>
|
||||
<note>
|
||||
Please note that this annotation can also be used on repository methods.
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>@GraphTraversal: fields as traversal result views</title>
|
||||
|
||||
@@ -132,13 +132,16 @@
|
||||
<section>
|
||||
<title>Annotated Queries</title>
|
||||
<para>
|
||||
Queries for the graph-query language cypher can be supplied with the <code>@GraphQuery</code> annotation.
|
||||
That means every method annotated with <code>@GraphQuery("start n=(%d) match (n)-->(m) return m")</code>
|
||||
will use the query string. The String-format parameters are replaced by the actual method parameters in order,
|
||||
whereby Node and Relationship-Entities are resolved to their respective id's and all other parameters are
|
||||
Queries for the cypher graph-query language can be supplied with the <code>@Query</code> annotation.
|
||||
That means every method annotated with <code>@Query("start n=(%node) match (n)-->(m) return m")</code>
|
||||
will use the query string. The named parameter <code>%node</code> will be replaced by the actual method parameters.
|
||||
Node and Relationship-Entities are resolved to their respective id's and all other parameters are
|
||||
replaced directly (i.e. Strings, Longs, etc). There is special support for the <code>Sort</code> and <code>Pageable</code>
|
||||
parameters from Spring Data Commons, which are supported to add programmatic paging and sorting (alternatively
|
||||
static paging and sorting can be supplied in the query string itself).
|
||||
|
||||
For using the named parameters you have to either annotate the parameters of the method with the
|
||||
<code>@Param("node")</code> annotation or enable debug symbols.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -146,8 +149,9 @@
|
||||
<title>Named Queries</title>
|
||||
<para>Spring Data Graph also supports the notion of named queries which are externalized in property-config-files
|
||||
(<code>META-INF/graph-named-queries.properties</code>). Those files have the format:
|
||||
<code>Entity.finderName=query</code> (e.g. <code>Person.findBoss=start p=(%d) match (p)<-[:BOSS]-(boss) return boss</code>).
|
||||
Otherwise named queries support the same parameters as annotated queries.
|
||||
<code>Entity.finderName=query</code> (e.g. <code>Person.findBoss=start p=(%person) match (p)<-[:BOSS]-(boss) return boss</code>).
|
||||
Otherwise named queries support the same parameters as annotated queries. For using the named parameters you have to either
|
||||
annotate the parameters of the method with the <code>@Param("person")</code> annotation or enable debug symbols.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
|
||||
Reference in New Issue
Block a user