Skip to content

Commit

Permalink
Make possible to load a relationship referring to a non annotated abs…
Browse files Browse the repository at this point in the history
…tract class

* Make possible to load a relationship referring to a non annotated abstract class. Fixes #404

Change request generation to ignore label of end node if the end node type
is a non annotated abstract class.

This also required to change the way how simple relationship values are written :
not according to target entity type but according to the collection type
which can be broader than specific target type.

* Add forgotten class and extract checking of abstract classes in separate test.

* Polishing. As a node label can be null, replacing return type
from String to Optional<String>.

* Adding warnings when we can't find a label associated with an entity
to better diagnose problems.
  • Loading branch information
nmervaillie authored and frant-hartm committed Nov 16, 2017
1 parent 425cd74 commit 1722b5b
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 61 deletions.
14 changes: 7 additions & 7 deletions core/src/main/java/org/neo4j/ogm/context/EntityCollector.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class EntityCollector {
* @param targetId id of target element
* @param target The element to add to the collection that will eventually be set on the owning type
*/
public void collectRelationship(Long sourceId, String relationshipType, String relationshipDirection, long relationshipId, long targetId, Object target) {
record(sourceId, target, relationshipType, relationshipDirection, new TargetTriple(relationshipId, targetId, target));
public void collectRelationship(Long sourceId, Class startPropertyType, String relationshipType, String relationshipDirection, long relationshipId, long targetId, Object target) {
record(sourceId, startPropertyType, relationshipType, relationshipDirection, new TargetTriple(relationshipId, targetId, target));
}

/**
Expand All @@ -60,16 +60,16 @@ public void collectRelationship(Long sourceId, String relationshipType, String r
* @param targetId id of target element
* @param target The element to add to the collection that will eventually be set on the owning type
*/
public void collectRelationship(Long sourceId, String relationshipType, String relationshipDirection, long targetId, Object target) {
record(sourceId, target, relationshipType, relationshipDirection, new TargetTriple(targetId, target));
public void collectRelationship(Long sourceId, Class startPropertyType, String relationshipType, String relationshipDirection, long targetId, Object target) {
record(sourceId, startPropertyType, relationshipType, relationshipDirection, new TargetTriple(targetId, target));
}

private void record(Long owningEntityId, Object collectibleElement, String relationshipType, String relationshipDirection, TargetTriple triple) {
private void record(Long owningEntityId, Class startPropertyType, String relationshipType, String relationshipDirection, TargetTriple triple) {
this.collected.computeIfAbsent(owningEntityId, k -> new HashMap<>());
DirectedRelationship directedRelationship = new DirectedRelationship(relationshipType, relationshipDirection);
this.collected.get(owningEntityId).computeIfAbsent(directedRelationship, k -> new HashMap<>());
this.collected.get(owningEntityId).get(directedRelationship).computeIfAbsent(collectibleElement.getClass(), k -> new HashSet<>());
this.collected.get(owningEntityId).get(directedRelationship).get(collectibleElement.getClass()).add(triple);
this.collected.get(owningEntityId).get(directedRelationship).computeIfAbsent(startPropertyType, k -> new HashSet<>());
this.collected.get(owningEntityId).get(directedRelationship).get(startPropertyType).add(triple);
}

public void forCollectedEntities(CollectedHandler handler) {
Expand Down
30 changes: 20 additions & 10 deletions core/src/main/java/org/neo4j/ogm/context/GraphEntityMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@
package org.neo4j.ogm.context;


import static org.neo4j.ogm.annotation.Relationship.*;
import static org.neo4j.ogm.metadata.reflect.EntityAccessManager.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.StartNode;
Expand All @@ -40,8 +48,10 @@
import org.neo4j.ogm.typeconversion.CompositeAttributeConverter;
import org.neo4j.ogm.utils.ClassUtils;
import org.neo4j.ogm.utils.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.neo4j.ogm.annotation.Relationship.INCOMING;
import static org.neo4j.ogm.annotation.Relationship.OUTGOING;
import static org.neo4j.ogm.metadata.reflect.EntityAccessManager.getRelationalWriter;

/**
* @author Vince Bickers
Expand Down Expand Up @@ -406,12 +416,12 @@ private void mapOneToMany(Collection<Edge> oneToManyRelationships) {
// establish a relationship between
FieldInfo outgoingWriter = findIterableWriter(instance, relationshipEntity, edge.getType(), OUTGOING);
if (outgoingWriter != null) {
entityCollector.collectRelationship(edge.getStartNode(), edge.getType(), OUTGOING, edge.getId(), edge.getEndNode(), relationshipEntity);
entityCollector.collectRelationship(edge.getStartNode(), ClassUtils.getType(outgoingWriter.typeParameterDescriptor()), edge.getType(), OUTGOING, edge.getId(), edge.getEndNode(), relationshipEntity);
relationshipsToRegister.add(new MappedRelationship(edge.getStartNode(), edge.getType(), edge.getEndNode(), edge.getId(), instance.getClass(), ClassUtils.getType(outgoingWriter.typeParameterDescriptor())));
}
FieldInfo incomingWriter = findIterableWriter(parameter, relationshipEntity, edge.getType(), INCOMING);
if (incomingWriter != null) {
entityCollector.collectRelationship(edge.getEndNode(), edge.getType(), INCOMING, edge.getId(), edge.getStartNode(), relationshipEntity);
entityCollector.collectRelationship(edge.getEndNode(), ClassUtils.getType(incomingWriter.typeParameterDescriptor()), edge.getType(), INCOMING, edge.getId(), edge.getStartNode(), relationshipEntity);
relationshipsToRegister.add(new MappedRelationship(edge.getStartNode(), edge.getType(), edge.getEndNode(), edge.getId(), instance.getClass(), ClassUtils.getType(incomingWriter.typeParameterDescriptor())));
}
} else {
Expand All @@ -421,7 +431,7 @@ private void mapOneToMany(Collection<Edge> oneToManyRelationships) {
FieldInfo outgoingWriter = getRelationalWriter(metadata.classInfo(instance), edge.getType(), OUTGOING, parameter);
if (outgoingWriter != null) {
if (!outgoingWriter.forScalar()) {
entityCollector.collectRelationship(edge.getStartNode(), edge.getType(), OUTGOING, edge.getEndNode(), parameter);
entityCollector.collectRelationship(edge.getStartNode(), ClassUtils.getType(outgoingWriter.typeParameterDescriptor()), edge.getType(), OUTGOING, edge.getEndNode(), parameter);
} else {
outgoingWriter.write(instance, parameter);
}
Expand All @@ -431,7 +441,7 @@ private void mapOneToMany(Collection<Edge> oneToManyRelationships) {
FieldInfo incomingWriter = getRelationalWriter(metadata.classInfo(parameter), edge.getType(), INCOMING, instance);
if (incomingWriter != null) {
if (!incomingWriter.forScalar()) {
entityCollector.collectRelationship(edge.getEndNode(), edge.getType(), INCOMING, edge.getStartNode(), instance);
entityCollector.collectRelationship(edge.getEndNode(), ClassUtils.getType(incomingWriter.typeParameterDescriptor()), edge.getType(), INCOMING, edge.getStartNode(), instance);
} else {
incomingWriter.write(parameter, instance);
}
Expand Down
33 changes: 27 additions & 6 deletions core/src/main/java/org/neo4j/ogm/metadata/ClassInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,40 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.neo4j.ogm.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.Index;
import org.neo4j.ogm.annotation.Labels;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.PostLoad;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.annotation.Relationship;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;
import org.neo4j.ogm.annotation.Transient;
import org.neo4j.ogm.exception.core.MappingException;
import org.neo4j.ogm.exception.core.MetadataException;
import org.neo4j.ogm.id.IdStrategy;
import org.neo4j.ogm.id.InternalIdStrategy;
import org.neo4j.ogm.id.UuidStrategy;
import org.neo4j.ogm.session.Neo4jException;
import org.neo4j.ogm.utils.ClassUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Maintains object to graph mapping details at the class (type) level
Expand Down Expand Up @@ -222,7 +241,9 @@ public String neo4jName() {
neo4jName = annotationInfo.get(RelationshipEntity.TYPE, simpleName().toUpperCase());
return neo4jName;
}
neo4jName = simpleName();
if (!isAbstract) {
neo4jName = simpleName();
}
}
return neo4jName;
}
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/neo4j/ogm/metadata/schema/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.util.Collection;
import java.util.Map;
import java.util.Optional;

/**
* Node in a {@link Schema}
Expand All @@ -28,7 +29,7 @@ public interface Node {
*
* @return label
*/
String label();
Optional<String> label();

/**
* Labels this node has, usually only 1
Expand Down
11 changes: 5 additions & 6 deletions core/src/main/java/org/neo4j/ogm/metadata/schema/NodeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@

package org.neo4j.ogm.metadata.schema;

import org.neo4j.ogm.metadata.schema.*;
import org.neo4j.ogm.metadata.schema.Relationship;
import org.neo4j.ogm.utils.RelationshipUtils;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.neo4j.ogm.utils.RelationshipUtils;

/**
* Node represents nodes in the schema
Expand All @@ -38,8 +37,8 @@ public NodeImpl(String label, Collection<String> labels) {
}

@Override
public String label() {
return label;
public Optional<String> label() {
return Optional.ofNullable(label);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@
*/
package org.neo4j.ogm.session.delegates;

import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.cypher.Filter;
import org.neo4j.ogm.cypher.query.CypherQuery;
Expand All @@ -35,6 +43,7 @@
*/
public class DeleteDelegate {

private static final Logger LOG = LoggerFactory.getLogger(DeleteDelegate.class);
private final Neo4jSession session;

public DeleteDelegate(Neo4jSession neo4jSession) {
Expand Down Expand Up @@ -134,7 +143,13 @@ private void deleteOneOrMoreObjects(Set<Object> neighbours, List<?> objects) {
public <T> void deleteAll(Class<T> type) {
ClassInfo classInfo = session.metaData().classInfo(type.getName());
if (classInfo != null) {
Statement request = getDeleteStatementsBasedOnType(type).delete(session.entityType(classInfo.name()));
String entityLabel = session.entityType(classInfo.name());
if (entityLabel == null) {
LOG.warn("Unable to find database label for entity " + type.getName()
+ " : no results will be returned. Make sure the class is registered, "
+ "and not abstract without @NodeEntity annotation");
}
Statement request = getDeleteStatementsBasedOnType(type).delete(entityLabel);
RowModelRequest query = new DefaultRowModelRequest(request.getStatement(), request.getParameters());
session.notifyListeners(new PersistenceEvent(type, Event.TYPE.PRE_DELETE));
try (Response<RowModel> response = session.requestHandler().execute(query)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.context.GraphEntityMapper;
import org.neo4j.ogm.cypher.query.DefaultGraphModelRequest;
import org.neo4j.ogm.cypher.query.Pagination;
Expand All @@ -39,7 +42,7 @@
*/
public class LoadByIdsDelegate {


private static final Logger LOG = LoggerFactory.getLogger(LoadByIdsDelegate.class);
private final Neo4jSession session;

public LoadByIdsDelegate(Neo4jSession session) {
Expand All @@ -48,10 +51,15 @@ public LoadByIdsDelegate(Neo4jSession session) {

public <T, ID extends Serializable> Collection<T> loadAll(Class<T> type, Collection<ID> ids, SortOrder sortOrder, Pagination pagination, int depth) {

String entityType = session.entityType(type.getName());
String entityLabel = session.entityType(type.getName());
if (entityLabel == null) {
LOG.warn("Unable to find database label for entity " + type.getName()
+ " : no results will be returned. Make sure the class is registered, "
+ "and not abstract without @NodeEntity annotation");
}
QueryStatements<ID> queryStatements = session.queryStatementsFor(type, depth);

PagingAndSortingQuery qry = queryStatements.findAllByType(entityType, ids, depth)
PagingAndSortingQuery qry = queryStatements.findAllByType(entityLabel, ids, depth)
.setSortOrder(sortOrder)
.setPagination(pagination);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,34 @@
*/
package org.neo4j.ogm.session.delegates;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.context.GraphEntityMapper;
import org.neo4j.ogm.context.GraphRowListModelMapper;
import org.neo4j.ogm.cypher.Filter;
import org.neo4j.ogm.cypher.Filters;
import org.neo4j.ogm.cypher.query.*;
import org.neo4j.ogm.cypher.query.DefaultGraphModelRequest;
import org.neo4j.ogm.cypher.query.DefaultGraphRowListModelRequest;
import org.neo4j.ogm.cypher.query.Pagination;
import org.neo4j.ogm.cypher.query.PagingAndSortingQuery;
import org.neo4j.ogm.cypher.query.SortOrder;
import org.neo4j.ogm.model.GraphModel;
import org.neo4j.ogm.model.GraphRowListModel;
import org.neo4j.ogm.request.GraphModelRequest;
import org.neo4j.ogm.response.Response;
import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.request.strategy.QueryStatements;

import java.util.Collection;

/**
* @author Vince Bickers
* @author Luanne Misquitta
*/
public class LoadByTypeDelegate {

private static final Logger LOG = LoggerFactory.getLogger(LoadByTypeDelegate.class);
private final Neo4jSession session;

public LoadByTypeDelegate(Neo4jSession session) {
Expand All @@ -41,17 +49,22 @@ public LoadByTypeDelegate(Neo4jSession session) {
public <T> Collection<T> loadAll(Class<T> type, Filters filters, SortOrder sortOrder, Pagination pagination, int depth) {

//session.ensureTransaction();
String entityType = session.entityType(type.getName());
String entityLabel = session.entityType(type.getName());
if (entityLabel == null) {
LOG.warn("Unable to find database label for entity " + type.getName()
+ " : no results will be returned. Make sure the class is registered, "
+ "and not abstract without @NodeEntity annotation");
}
QueryStatements queryStatements = session.queryStatementsFor(type, depth);

session.resolvePropertyAnnotations(type, sortOrder);

PagingAndSortingQuery query;
if (filters.isEmpty()) {
query = queryStatements.findByType(entityType, depth);
query = queryStatements.findByType(entityLabel, depth);
} else {
session.resolvePropertyAnnotations(type, filters);
query = queryStatements.findByType(entityType, filters, depth);
query = queryStatements.findByType(entityLabel, filters, depth);
}

query.setSortOrder(sortOrder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
*/
package org.neo4j.ogm.session.delegates;

import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.context.GraphEntityMapper;
import org.neo4j.ogm.cypher.query.DefaultGraphModelRequest;
Expand All @@ -23,10 +28,6 @@
import org.neo4j.ogm.response.Response;
import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.request.strategy.QueryStatements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;

/**
* @author Vince Bickers
Expand Down Expand Up @@ -63,7 +64,13 @@ public <T, ID extends Serializable> T load(Class<T> type, ID id, int depth) {
}

QueryStatements<ID> queryStatements = session.queryStatementsFor(type, depth);
PagingAndSortingQuery qry = queryStatements.findOneByType(session.entityType(type.getName()), id, depth);
String entityType = session.entityType(type.getName());
if (entityType == null) {
logger.warn("Unable to find database label for entity " + type.getName()
+ " : no results will be returned. Make sure the class is registered, "
+ "and not abstract without @NodeEntity annotation");
}
PagingAndSortingQuery qry = queryStatements.findOneByType(entityType, id, depth);

GraphModelRequest request = new DefaultGraphModelRequest(qry.getStatement(), qry.getParameters());
try (Response<GraphModel> response = session.requestHandler().execute(request)) {
Expand Down
Loading

0 comments on commit 1722b5b

Please sign in to comment.