use of org.neo4j.ogm.annotation.Relationship.Direction in project neo4j-ogm by neo4j.
the class EntityCollector method forCollectedEntities.
public void forCollectedEntities(CollectedHandler handler) {
collected.forEach((sourceId, relationshipMap) -> {
relationshipMap.forEach((relationship, targetTypeMap) -> {
String type = relationship.type();
Direction direction = relationship.direction();
targetTypeMap.forEach((targetType, entityTriples) -> {
List<Object> entities = entityTriples.stream().map(TargetTriple::getTarget).collect(toList());
handler.handle(sourceId, type, direction, targetType, entities);
});
});
});
}
use of org.neo4j.ogm.annotation.Relationship.Direction in project neo4j-ogm by neo4j.
the class EntityGraphMapper method bothWayMappingRequired.
/**
* Determines whether or not a two way mapping is required for the relationship.
* Relationships annotated with either {@link Relationship} direction INCOMING or OUTGOING and defined between two entities of the same type
* will be considered for a dual mapping.
* Specifically, if the source and target entity are of the same type, and the related object from the source for relationship type R in direction D
* is the same as the related object from the target for relationship type R in direction D, then the relationship is mapped both ways.
*
* @param srcObject the domain object representing the start node of the relationship
* @param relationshipType the type of the relationship from the srcObject
* @param tgtObject the domain object representing the end node of the relationship
* @param relationshipDirection the direction of the relationship from the srcObject
* @return true if the relationship should be mapped both ways, false otherwise
*/
private boolean bothWayMappingRequired(Object srcObject, String relationshipType, Object tgtObject, Relationship.Direction relationshipDirection) {
boolean mapBothWays = false;
ClassInfo tgtInfo = metaData.classInfo(tgtObject);
if (tgtInfo == null) {
LOGGER.warn("Unable to process {} on {}. Check the mapping.", relationshipType, srcObject.getClass());
// #347. attribute is not a rel ? maybe would be better to change FieldInfo.persistableAsProperty ?
return false;
}
for (FieldInfo tgtRelReader : tgtInfo.relationshipFields()) {
Direction tgtRelationshipDirection = tgtRelReader.relationshipDirection();
// and the source must be related to the target and vice versa in the SAME direction
if (tgtRelationshipDirection != Direction.UNDIRECTED && tgtRelReader.relationshipType().equals(relationshipType) && relationshipDirection.equals(tgtRelationshipDirection)) {
Object target = tgtRelReader.read(tgtObject);
mapBothWays = targetEqualsSource(target, srcObject);
}
// We don't need any other field if we already found a match.
if (mapBothWays) {
break;
}
}
return mapBothWays;
}
use of org.neo4j.ogm.annotation.Relationship.Direction in project neo4j-ogm by neo4j.
the class SaveEventDelegate method mapInstance.
// creates a MappedRelationship between the parent object and the reference. In the case that the reference
// object is a RE, the relationship is created from the start node and the end node of the RE.
// a MappedRelationship therefore represents a directed edge between two nodes in the graph.
private void mapInstance(Set<MappedRelationship> mappedRelationships, ClassInfo parentInfo, long parentId, FieldInfo reader, Object reference) {
String type = reader.relationshipType();
Direction direction = reader.relationshipDirection();
ClassInfo referenceInfo = this.session.metaData().classInfo(reference);
if (referenceInfo == null) {
return;
}
if (referenceInfo.isRelationshipEntity()) {
// The relationship entity might just get created and therefore we must be careful not to
// trigger the creation of it's id place holder, otherwise we can't check wether it's new or not.
Optional<Long> optionalReferenceId = session.context().optionalNativeId(reference);
// graph relationship is transitive across the RE domain object
Object startNode = referenceInfo.getStartNodeReader().read(reference);
ClassInfo startNodeInfo = this.session.metaData().classInfo(startNode);
Long startNodeId = session.context().nativeId(startNode);
Object endNode = referenceInfo.getEndNodeReader().read(reference);
ClassInfo endNodeInfo = this.session.metaData().classInfo(endNode);
Long endNodeId = session.context().nativeId(endNode);
MappedRelationship edge = new MappedRelationship(startNodeId, type, endNodeId, optionalReferenceId.orElse(null), startNodeInfo.getUnderlyingClass(), endNodeInfo.getUnderlyingClass());
mappedRelationships.add(edge);
} else {
// We assume the existence of the reference here
Long referenceId = session.context().nativeId(reference);
if (direction == Direction.OUTGOING) {
MappedRelationship edge = new MappedRelationship(parentId, type, referenceId, null, parentInfo.getUnderlyingClass(), referenceInfo.getUnderlyingClass());
mappedRelationships.add(edge);
} else {
MappedRelationship edge = new MappedRelationship(referenceId, type, parentId, null, referenceInfo.getUnderlyingClass(), parentInfo.getUnderlyingClass());
mappedRelationships.add(edge);
}
}
}
use of org.neo4j.ogm.annotation.Relationship.Direction in project neo4j-ogm by neo4j.
the class SessionDelegate method updateRelationship.
private void updateRelationship(FilterWithRelationship filter, FieldInfo fieldInfo, String relationshipType) {
filter.setRelationshipType(relationshipType);
filter.setRelationshipDirection(Direction.UNDIRECTED);
if (fieldInfo.getAnnotations() != null) {
AnnotationInfo annotation = fieldInfo.getAnnotations().get(Relationship.class);
if (annotation != null) {
filter.setRelationshipType(annotation.get(Relationship.TYPE, relationshipType));
Direction direction = Direction.valueOf(annotation.get(Relationship.DIRECTION, Direction.UNDIRECTED.name()));
filter.setRelationshipDirection(direction);
}
if (fieldInfo.getAnnotations().get(StartNode.class) != null) {
filter.setRelationshipDirection(Direction.OUTGOING);
}
if (fieldInfo.getAnnotations().get(EndNode.class) != null) {
filter.setRelationshipDirection(Direction.INCOMING);
}
}
}
use of org.neo4j.ogm.annotation.Relationship.Direction in project neo4j-ogm by neo4j.
the class FilteredQueryBuilder method constructRelationshipQuery.
private static StringBuilder constructRelationshipQuery(String type, Iterable<Filter> filters, Map<String, Object> properties) {
// Filters are created in 3 steps: For deep nested filter, the improved version
// NodeQueryBuilder is used. For the others the old approach still applies.
FiltersAtStartNode outgoingDeepNestedFilters = new FiltersAtStartNode();
FiltersAtStartNode incomingDeepNestedFilters = new FiltersAtStartNode();
FiltersAtStartNode outgoingFilters = new FiltersAtStartNode();
FiltersAtStartNode incomingFilters = new FiltersAtStartNode();
List<Filter> relationshipFilters = new ArrayList<>();
Direction initialDirection = null;
for (Filter filter : filters) {
if (filter.isNested() || filter.isDeepNested()) {
if (filter.isDeepNested()) {
List<Filter.NestedPathSegment> nestedPath = filter.getNestedPath();
Filter.NestedPathSegment firstNestedPathSegment = nestedPath.get(0);
filter.setOwnerEntityType(firstNestedPathSegment.getPropertyType());
FiltersAtStartNode target;
if (Relationship.Direction.OUTGOING == firstNestedPathSegment.getRelationshipDirection()) {
target = outgoingDeepNestedFilters;
} else {
target = incomingDeepNestedFilters;
}
Filter.NestedPathSegment[] newPath = new Filter.NestedPathSegment[nestedPath.size() - 1];
if (nestedPath.size() > 1) {
// The first element will represent the owning entity, so we need to get rid of it.
nestedPath.subList(1, nestedPath.size()).toArray(newPath);
} else {
// The list of deep nested filters need an anchor only for relationships with one
// nested segments.
target.startNodeLabel = firstNestedPathSegment.getNestedEntityTypeLabel();
}
filter.setNestedPath(newPath);
target.content.add(filter);
if (initialDirection == null) {
initialDirection = firstNestedPathSegment.getRelationshipDirection();
}
} else {
FiltersAtStartNode target;
Direction relationshipDirection = filter.getRelationshipDirection();
if (Relationship.OUTGOING == relationshipDirection) {
target = outgoingFilters;
} else {
target = incomingFilters;
}
if (initialDirection == null) {
initialDirection = filter.getRelationshipDirection();
}
addFilterToList(target, filter);
}
} else {
if (relationshipFilters.size() == 0) {
filter.setBooleanOperator(BooleanOperator.NONE);
} else {
if (filter.getBooleanOperator().equals(BooleanOperator.NONE)) {
throw new MissingOperatorException("BooleanOperator missing for filter with property name " + filter.getPropertyName());
}
}
relationshipFilters.add(filter);
}
}
StringBuilder query = new StringBuilder();
boolean outgoingDeepNested = !outgoingDeepNestedFilters.content.isEmpty();
if (outgoingDeepNested) {
NodeQueryBuilder nqb = new NodeQueryBuilder(outgoingDeepNestedFilters.startNodeLabel, outgoingDeepNestedFilters.content, "n");
FilteredQuery filteredQuery = nqb.build();
query.append(filteredQuery.statement()).append(" ");
properties.putAll(filteredQuery.parameters());
}
if (!incomingDeepNestedFilters.content.isEmpty()) {
NodeQueryBuilder nqb = new NodeQueryBuilder(incomingDeepNestedFilters.startNodeLabel, incomingDeepNestedFilters.content, outgoingDeepNested ? "m" : "n");
FilteredQuery filteredQuery = nqb.build();
query.append(filteredQuery.statement()).append(" ");
if (outgoingDeepNested) {
query.append(", n ");
}
properties.putAll(filteredQuery.parameters());
}
createNodeMatchSubquery(properties, outgoingFilters, query, "n");
createNodeMatchSubquery(properties, incomingFilters, query, "m");
createRelationSubquery(type, properties, relationshipFilters, query, initialDirection);
return query;
}
Aggregations