indexing, short property-names as default
This commit is contained in:
@@ -12,5 +12,7 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface GraphEntity {
|
||||
boolean useShortNames() default false;
|
||||
boolean useShortNames() default true;
|
||||
|
||||
boolean fullIndex() default false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.neo4j.index.IndexHits;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.springframework.datastore.graph.neo4j.spi.node.Neo4jHelper;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
@@ -17,13 +20,15 @@ public class Finder<T extends NodeBacked> {
|
||||
|
||||
private final Class<T> clazz;
|
||||
private final GraphDatabaseService graphDatabaseService;
|
||||
private final IndexService indexService;
|
||||
private final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
|
||||
public Finder(Class<T> clazz, GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
|
||||
public Finder(Class<T> clazz, GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator, IndexService indexService) {
|
||||
this.clazz = clazz;
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
}
|
||||
this.indexService = indexService;
|
||||
}
|
||||
|
||||
public long count() {
|
||||
return Neo4jHelper.count(clazz, graphDatabaseService);
|
||||
@@ -32,13 +37,13 @@ public class Finder<T extends NodeBacked> {
|
||||
public Iterable<T> findAll() {
|
||||
Node subrefNode = Neo4jHelper.findSubreferenceNode(clazz, graphDatabaseService);
|
||||
if (subrefNode==null) return Collections.emptyList();
|
||||
// TODO add lazy list on top of graph
|
||||
List<T> result = new ArrayList<T>((int) count());
|
||||
for (Relationship rel : subrefNode.getRelationships(Neo4jHelper.INSTANCE_OF_RELATIONSHIP_TYPE, Direction.INCOMING)) {
|
||||
Node node = rel.getStartNode();
|
||||
result.add(graphEntityInstantiator.createEntityFromState(node, clazz));
|
||||
}
|
||||
return result;
|
||||
return new IterableWrapper<T,Relationship>(subrefNode.getRelationships(Neo4jHelper.INSTANCE_OF_RELATIONSHIP_TYPE, Direction.INCOMING)) {
|
||||
@Override
|
||||
protected T underlyingObjectToObject(Relationship rel) {
|
||||
Node node = rel.getStartNode();
|
||||
return graphEntityInstantiator.createEntityFromState(node, clazz);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public T findById(long id) {
|
||||
@@ -48,4 +53,30 @@ public class Finder<T extends NodeBacked> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public T getByIndex(String property, Object value) {
|
||||
try {
|
||||
final Node node = indexService.getSingleNode(property, value);
|
||||
if (node==null) return null;
|
||||
return graphEntityInstantiator.createEntityFromState(node, clazz);
|
||||
} catch(NotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
public Iterable<T> getAllByIndex(String property, Object value) {
|
||||
try {
|
||||
final IndexHits<Node> nodes = indexService.getNodes(property, value);
|
||||
if (nodes==null) return Collections.emptyList();
|
||||
return new IterableWrapper<T,Node>(nodes) {
|
||||
@Override
|
||||
protected T underlyingObjectToObject(Node node) {
|
||||
return graphEntityInstantiator.createEntityFromState(node, clazz);
|
||||
}
|
||||
};
|
||||
} catch(NotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.springframework.datastore.graph.neo4j.finder;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.datastore.graph.neo4j.spi.node.Neo4jHelper;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
@@ -10,14 +11,16 @@ public class FinderFactory {
|
||||
|
||||
private final GraphDatabaseService graphDatabaseService;
|
||||
private final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
private final IndexService indexService;
|
||||
|
||||
public FinderFactory(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
|
||||
public FinderFactory(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator, IndexService indexService) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
this.indexService = indexService;
|
||||
}
|
||||
|
||||
public <T extends NodeBacked> Finder<T> getFinderForClass(Class<T> clazz) {
|
||||
return new Finder<T>(clazz, graphDatabaseService, graphEntityInstantiator);
|
||||
return new Finder<T>(clazz, graphDatabaseService, graphEntityInstantiator, indexService);
|
||||
}
|
||||
|
||||
public Class<NodeBacked> getEntityClass(String shortName) {
|
||||
|
||||
@@ -2,15 +2,14 @@ package org.springframework.datastore.graph.neo4j.jpa;
|
||||
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.neo4j.kernel.EmbeddedGraphDatabase;
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.datastore.graph.neo4j.finder.FinderFactory;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.transaction.*;
|
||||
@@ -25,24 +24,26 @@ import java.util.Map;
|
||||
@Transactional
|
||||
@Configurable
|
||||
public class Neo4jEntityManager implements EntityManager {
|
||||
GraphDatabaseService graphDatabaseService;
|
||||
EntityInstantiator<NodeBacked, Node> nodeInstantiator;
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
private EntityInstantiator<NodeBacked, Node> nodeInstantiator;
|
||||
private PersistenceUnitInfo info;
|
||||
|
||||
private Map params;
|
||||
private IndexService indexService;
|
||||
private volatile boolean closed;
|
||||
private final FinderFactory finderFactory;
|
||||
|
||||
public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator<NodeBacked, Node> nodeInstantiator, PersistenceUnitInfo info, Map params) {
|
||||
public Neo4jEntityManager(final GraphDatabaseService graphDatabaseService, final EntityInstantiator<NodeBacked, Node> nodeInstantiator, PersistenceUnitInfo info, Map params, IndexService indexService) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
this.nodeInstantiator = nodeInstantiator;
|
||||
this.info = info;
|
||||
this.params = params;
|
||||
finderFactory = new FinderFactory(graphDatabaseService, nodeInstantiator);
|
||||
this.indexService = indexService;
|
||||
finderFactory = new FinderFactory(graphDatabaseService, nodeInstantiator, indexService);
|
||||
}
|
||||
|
||||
public Neo4jEntityManager() {
|
||||
finderFactory = new FinderFactory(graphDatabaseService, nodeInstantiator);
|
||||
finderFactory = new FinderFactory(graphDatabaseService, nodeInstantiator, indexService);
|
||||
}
|
||||
|
||||
private Node nodeFor(final Object entity) {
|
||||
|
||||
@@ -2,10 +2,10 @@ package org.springframework.datastore.graph.neo4j.jpa;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
@@ -20,23 +20,25 @@ public class Neo4jEntityManagerFactory implements EntityManagerFactory {
|
||||
EntityInstantiator<NodeBacked, Node> nodeInstantiator;
|
||||
private PersistenceUnitInfo info;
|
||||
private Map params;
|
||||
private IndexService indexService;
|
||||
|
||||
public Neo4jEntityManagerFactory(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> nodeInstantiator, PersistenceUnitInfo info, Map params) {
|
||||
public Neo4jEntityManagerFactory(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> nodeInstantiator, IndexService indexService, PersistenceUnitInfo info, Map params) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
this.nodeInstantiator = nodeInstantiator;
|
||||
this.indexService = indexService;
|
||||
this.info = info;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager createEntityManager() {
|
||||
return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator,info,params);
|
||||
return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator,info,params, indexService);
|
||||
}
|
||||
|
||||
/* TODO handle different directories for target datastore */
|
||||
@Override
|
||||
public EntityManager createEntityManager(Map map) {
|
||||
return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator,info,params);
|
||||
return new Neo4jEntityManager(graphDatabaseService,nodeInstantiator,info,params, indexService);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,9 +2,9 @@ package org.springframework.datastore.graph.neo4j.jpa;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.springframework.beans.factory.annotation.Configurable;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.datastore.graph.neo4j.spi.node.Neo4jHelper;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -21,16 +21,18 @@ import java.util.Map;
|
||||
@Configurable
|
||||
public class Neo4jPersistenceProvider implements PersistenceProvider {
|
||||
@Resource
|
||||
GraphDatabaseService graphDatabaseService;
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
|
||||
@Resource
|
||||
EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
private EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
@Resource
|
||||
private IndexService indexService;
|
||||
|
||||
@Override
|
||||
public EntityManagerFactory createEntityManagerFactory(String emName, Map params) {
|
||||
System.out.println("emName = " + emName);
|
||||
System.out.println("params = " + params);
|
||||
return new Neo4jEntityManagerFactory(graphDatabaseService,graphEntityInstantiator,null,params);
|
||||
return new Neo4jEntityManagerFactory(graphDatabaseService,graphEntityInstantiator, indexService, null,params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,6 +44,6 @@ public class Neo4jPersistenceProvider implements PersistenceProvider {
|
||||
System.out.println("info.getProperties() = " + info.getProperties());
|
||||
System.out.println("info.getPersistenceUnitName() = " + info.getPersistenceUnitName());
|
||||
System.out.println("params = " + params);
|
||||
return new Neo4jEntityManagerFactory(graphDatabaseService,graphEntityInstantiator,info,params);
|
||||
return new Neo4jEntityManagerFactory(graphDatabaseService,graphEntityInstantiator, indexService, info,params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.*;
|
||||
|
||||
import org.aspectj.lang.reflect.FieldSignature;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.neo4j.kernel.EmbeddedGraphDatabase;
|
||||
import org.neo4j.util.GraphDatabaseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -47,13 +48,15 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
|
||||
private FieldAccessorFactory fieldAccessorFactory;
|
||||
|
||||
private EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator;
|
||||
|
||||
@Autowired
|
||||
public void init(GraphDatabaseService gds, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator, EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator) {
|
||||
private IndexService indexService;
|
||||
|
||||
@Autowired
|
||||
public void init(GraphDatabaseService gds, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator, EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator, IndexService indexService) {
|
||||
this.graphDatabaseService = gds;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
this.relationshipEntityInstantiator = relationshipEntityInstantiator;
|
||||
this.fieldAccessorFactory = new FieldAccessorFactory(graphEntityInstantiator, relationshipEntityInstantiator);
|
||||
this.indexService = indexService;
|
||||
this.fieldAccessorFactory = new FieldAccessorFactory(graphEntityInstantiator, relationshipEntityInstantiator);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,14 +154,14 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
|
||||
/*
|
||||
public <R extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N node, Class<R> relationshipType, String type) {
|
||||
Relationship rel = this.getUnderlyingNode().createRelationshipTo(node.getUnderlyingNode(), DynamicRelationshipType.withName(type));
|
||||
return relationshipEntityInstantiator.createEntityFromState(rel, relationshipType);
|
||||
return (R)createRelationshipEntity(relationshipType,rel);
|
||||
// relationshipEntityInstantiator.createEntityFromState(rel, relationshipType);
|
||||
}
|
||||
*/
|
||||
public RelationshipBacked NodeBacked.relateTo(NodeBacked node, Class<? extends RelationshipBacked> relationshipType, String type) {
|
||||
Relationship rel = this.getUnderlyingNode().createRelationshipTo(node.getUnderlyingNode(), DynamicRelationshipType.withName(type));
|
||||
return createRelationshipEntity(relationshipType,rel);
|
||||
}
|
||||
|
||||
private static RelationshipBacked createRelationshipEntity(Class<? extends RelationshipBacked> relationshipType, Relationship rel) {
|
||||
try {
|
||||
final Constructor<? extends RelationshipBacked> constructor = relationshipType.getDeclaredConstructor();
|
||||
@@ -298,10 +301,13 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
|
||||
if (Modifier.isFinal(field.getModifiers())) return new ShouldProceedOrReturn(newVal);
|
||||
if (isPropertyType(field.getType())) {
|
||||
String propName = FieldAccessorFactory.getNeo4jPropertyName(field);
|
||||
Node node = entity.getUnderlyingNode();
|
||||
if (newVal==null) {
|
||||
entity.getUnderlyingNode().removeProperty(propName);
|
||||
node.removeProperty(propName);
|
||||
if (isIndexedProperty(field)) indexService.removeIndex(node,propName);
|
||||
} else {
|
||||
entity.getUnderlyingNode().setProperty(propName, newVal);
|
||||
node.setProperty(propName, newVal);
|
||||
if (isIndexedProperty(field)) indexService.index(node,propName,newVal);
|
||||
}
|
||||
log.info("SET " + field + " -> Neo4J simple node property [" + propName + "] with value=[" + newVal + "]");
|
||||
return new ShouldProceedOrReturn(true,newVal);
|
||||
@@ -379,5 +385,12 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
|
||||
|| fieldType.equals(Boolean.class)
|
||||
|| (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType));
|
||||
}
|
||||
|
||||
|
||||
// todo @property annotation
|
||||
// todo fieldlist in @graphentity
|
||||
private boolean isIndexedProperty(Field field) {
|
||||
final GraphEntity graphEntity = field.getDeclaringClass().getAnnotation(GraphEntity.class);
|
||||
if (graphEntity==null) return false;
|
||||
return graphEntity.fullIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.springframework.datastore.graph.api.GraphEntityRelationship;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@GraphEntity(useShortNames = true)
|
||||
@GraphEntity(fullIndex = true)
|
||||
public class Group {
|
||||
|
||||
@GraphEntityRelationship(type = "persons", direction = Direction.OUTGOING, elementClass = Person.class)
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.springframework.datastore.graph.api.GraphEntityRelationship;
|
||||
import org.springframework.datastore.graph.api.GraphEntityRelationshipEntity;
|
||||
|
||||
|
||||
@GraphEntity
|
||||
@GraphEntity(useShortNames = false)
|
||||
public class Person {
|
||||
|
||||
private Long id;
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package org.springframework.datastore.graph.neo4j.spi;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.neo4j.index.IndexService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.datastore.graph.api.NodeBacked;
|
||||
import org.springframework.datastore.graph.neo4j.Friendship;
|
||||
import org.springframework.datastore.graph.neo4j.Group;
|
||||
@@ -42,8 +40,11 @@ public class Neo4jGraphPersistenceTest {
|
||||
|
||||
@Autowired
|
||||
private FinderFactory finderFactory;
|
||||
|
||||
@Test
|
||||
|
||||
@Autowired
|
||||
private IndexService indexService;
|
||||
|
||||
@Test
|
||||
public void testStuffWasAutowired() {
|
||||
Assert.assertNotNull( graphDatabaseService );
|
||||
Assert.assertNotNull( graphEntityInstantiator );
|
||||
@@ -214,7 +215,7 @@ public class Neo4jGraphPersistenceTest {
|
||||
|
||||
@Test
|
||||
public void testFindOutsideTransaction() {
|
||||
final FinderFactory factory = new FinderFactory(graphDatabaseService, graphEntityInstantiator);
|
||||
final FinderFactory factory = new FinderFactory(graphDatabaseService, graphEntityInstantiator, indexService);
|
||||
final Finder<Person> finder = factory.getFinderForClass(Person.class);
|
||||
Assert.assertEquals(false,finder.findAll().iterator().hasNext());
|
||||
}
|
||||
@@ -399,4 +400,25 @@ public class Neo4jGraphPersistenceTest {
|
||||
Group group = new Group();
|
||||
group.setReadOnlyPersons(new HashSet<Person>());
|
||||
}
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
@Transactional
|
||||
public void testFindGroupByIndex() {
|
||||
Group group = new Group();
|
||||
group.setName("test");
|
||||
final Finder<Group> finder = finderFactory.getFinderForClass(Group.class);
|
||||
final Group found = finder.getByIndex("name", "test");
|
||||
Assert.assertEquals(group,found);
|
||||
}
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
@Transactional
|
||||
public void testFindAllGroupsByIndex() {
|
||||
Group group = new Group();
|
||||
group.setName("test");
|
||||
Group group2 = new Group();
|
||||
group.setName("test");
|
||||
final Finder<Group> finder = finderFactory.getFinderForClass(Group.class);
|
||||
final Iterable<Group> found = finder.getAllByIndex("name", "test");
|
||||
final Collection<Group> result = IteratorUtil.addToCollection(found.iterator(), new HashSet<Group>());
|
||||
Assert.assertEquals(new HashSet<Group>(Arrays.asList(group,group2)), result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,16 @@
|
||||
destroy-method="shutdown" scope="singleton">
|
||||
<constructor-arg index="0" value="${neo4j.databaseDirectory}" />
|
||||
</bean>
|
||||
|
||||
<bean id="indexService" class="org.neo4j.index.lucene.LuceneIndexService" destroy-method="shutdown">
|
||||
<constructor-arg index="0" ref="graphDbService" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="finderFactory" class="org.springframework.datastore.graph.neo4j.finder.FinderFactory">
|
||||
<constructor-arg ref="graphDbService" />
|
||||
<constructor-arg ref="graphEntityInstantiator" />
|
||||
<constructor-arg ref="indexService" />
|
||||
</bean>
|
||||
|
||||
<bean id="graphEntityInstantiator" name="gei" class="org.springframework.datastore.graph.neo4j.spi.node.Neo4jConstructorGraphEntityInstantiator" />
|
||||
|
||||
Reference in New Issue
Block a user