Search in sources :

Example 1 with RelationshipBuilder

use of org.neo4j.ogm.cypher.compiler.RelationshipBuilder in project neo4j-ogm by neo4j.

the class EntityGraphMapper method getRelationshipBuilder.

/**
 * Fetches and initialises an appropriate {@link RelationshipBuilder} for the specified relationship type
 * and direction to the supplied domain object, which may be a node or relationship in the graph.
 * In the event that the domain object is a {@link RelationshipEntity}, we create a new relationship, collect
 * its properties and return a builder associated to the RE's end node instead
 *
 * @param cypherBuilder        the {@link org.neo4j.ogm.cypher.compiler.Compiler}
 * @param entity               an object representing a node or relationship entity in the graph
 * @param directedRelationship the {@link DirectedRelationship} representing the relationship type and direction we want to establish
 * @param mapBothDirections    whether the nodes should be linked in both directions
 * @return The appropriate {@link RelationshipBuilder}
 */
private RelationshipBuilder getRelationshipBuilder(Compiler cypherBuilder, Object entity, DirectedRelationship directedRelationship, boolean mapBothDirections) {
    RelationshipBuilder relationshipBuilder;
    if (isRelationshipEntity(entity)) {
        Long relId = mappingContext.nativeId(entity);
        boolean relationshipIsNew = relId < 0;
        boolean relationshipEndsChanged = haveRelationEndsChanged(entity, relId);
        if (relationshipIsNew || relationshipEndsChanged) {
            relationshipBuilder = cypherBuilder.newRelationship(directedRelationship.type());
            if (relationshipEndsChanged) {
                // since this relationship will get recreated and all properties will be copied in the process,
                // we have to reset the control fields for version and identifier.
                FieldInfo versionField = metaData.classInfo(entity).getVersionField();
                if (versionField != null) {
                    versionField.write(entity, null);
                }
                EntityUtils.setIdentity(entity, null, metaData);
            }
        } else {
            relationshipBuilder = cypherBuilder.existingRelationship(relId, directedRelationship.direction(), directedRelationship.type(), mappingContext.isDirty(entity));
            this.mappingContext.getSnapshotOf(entity).ifPresent(snapshot -> relationshipBuilder.setPreviousCompositeProperties(snapshot.getDynamicCompositeProperties()));
        }
    } else {
        relationshipBuilder = cypherBuilder.newRelationship(directedRelationship.type(), mapBothDirections);
    }
    relationshipBuilder.direction(directedRelationship.direction());
    if (isRelationshipEntity(entity)) {
        // indicates that this relationship type can be mapped multiple times between 2 nodes
        relationshipBuilder.setSingleton(false);
        relationshipBuilder.setReference(mappingContext.nativeId(entity));
        relationshipBuilder.setRelationshipEntity(true);
        ClassInfo classInfo = metaData.classInfo(entity);
        if (classInfo.primaryIndexField() != null) {
            relationshipBuilder.setPrimaryIdName(classInfo.primaryIndexField().propertyName());
        }
    }
    return relationshipBuilder;
}
Also used : FieldInfo(org.neo4j.ogm.metadata.FieldInfo) RelationshipBuilder(org.neo4j.ogm.cypher.compiler.RelationshipBuilder) ClassInfo(org.neo4j.ogm.metadata.ClassInfo)

Example 2 with RelationshipBuilder

use of org.neo4j.ogm.cypher.compiler.RelationshipBuilder in project neo4j-ogm by neo4j.

the class EntityGraphMapper method deleteObsoleteRelationships.

/**
 * Detects object references (including from lists) that have been deleted in the domain.
 * These must be persisted as explicit requests to delete the corresponding relationship in the graph
 */
private void deleteObsoleteRelationships() {
    CompileContext context = compiler.context();
    Map<Long, Object> snapshotOfKnownRelationshipEntities = mappingContext.getSnapshotOfRelationshipEntityRegister();
    Iterator<MappedRelationship> mappedRelationshipIterator = mappingContext.getRelationships().iterator();
    while (mappedRelationshipIterator.hasNext()) {
        MappedRelationship mappedRelationship = mappedRelationshipIterator.next();
        // means the user has deleted the relationship
        if (!context.removeRegisteredRelationship(mappedRelationship)) {
            LOGGER.debug("context-del: {}", mappedRelationship);
            // tell the compiler to prepare a statement that will delete the relationship from the graph
            RelationshipBuilder builder = compiler.unrelate(mappedRelationship.getStartNodeId(), mappedRelationship.getRelationshipType(), mappedRelationship.getEndNodeId(), mappedRelationship.getRelationshipId());
            Object entity = snapshotOfKnownRelationshipEntities.get(mappedRelationship.getRelationshipId());
            if (entity != null) {
                ClassInfo classInfo = metaData.classInfo(entity);
                if (classInfo.hasVersionField()) {
                    FieldInfo field = classInfo.getVersionField();
                    builder.setVersionProperty(field.propertyName(), (Long) field.read(entity));
                }
            }
            // remove all nodes that are referenced by this relationship in the mapping context
            // this will ensure that stale versions of these objects don't exist
            clearRelatedObjects(mappedRelationship.getStartNodeId());
            clearRelatedObjects(mappedRelationship.getEndNodeId());
            // finally remove the relationship from the mapping context
            // mappingContext.removeRelationship(mappedRelationship);
            mappedRelationshipIterator.remove();
        }
    }
}
Also used : CompileContext(org.neo4j.ogm.cypher.compiler.CompileContext) FieldInfo(org.neo4j.ogm.metadata.FieldInfo) RelationshipBuilder(org.neo4j.ogm.cypher.compiler.RelationshipBuilder) ClassInfo(org.neo4j.ogm.metadata.ClassInfo)

Example 3 with RelationshipBuilder

use of org.neo4j.ogm.cypher.compiler.RelationshipBuilder in project neo4j-ogm by neo4j.

the class EntityGraphMapper method map.

@Override
public CompileContext map(Object entity, int horizon) {
    this.currentDepth.set(0);
    if (entity == null) {
        throw new NullPointerException("Cannot map null object");
    }
    // won't be modified by the mapping request.
    for (MappedRelationship mappedRelationship : mappingContext.getRelationships()) {
        LOGGER.debug("context-init: ({})-[:{}]->({})", mappedRelationship.getStartNodeId(), mappedRelationship.getRelationshipType(), mappedRelationship.getEndNodeId());
        compiler.context().registerRelationship(mappedRelationship);
    }
    LOGGER.debug("context initialised with {} relationships", mappingContext.getRelationships().size());
    // and then ensure the relationship between the two is created or updated as necessary
    if (isRelationshipEntity(entity)) {
        ClassInfo reInfo = metaData.classInfo(entity);
        Object startNode = reInfo.getStartNodeReader().read(entity);
        if (startNode == null) {
            throw new RuntimeException("@StartNode of relationship entity may not be null");
        }
        Object endNode = reInfo.getEndNodeReader().read(entity);
        if (endNode == null) {
            throw new RuntimeException("@EndNode of relationship entity may not be null");
        }
        // map both sides as far as the specified horizon
        NodeBuilder startNodeBuilder = mapEntity(startNode, horizon);
        NodeBuilder endNodeBuilder = mapEntity(endNode, horizon);
        // create or update the relationship if its not already been visited in the current compile context
        if (!compiler.context().visitedRelationshipEntity(mappingContext.nativeId(entity))) {
            AnnotationInfo annotationInfo = reInfo.annotationsInfo().get(RelationshipEntity.class);
            String relationshipType = annotationInfo.get(RelationshipEntity.TYPE, null);
            DirectedRelationship directedRelationship = new DirectedRelationship(relationshipType, Direction.OUTGOING);
            RelationshipBuilder relationshipBuilder = getRelationshipBuilder(compiler, entity, directedRelationship, mappingContext.isDirty(entity));
            // 2. create or update the actual relationship (edge) in the graph
            updateRelationshipEntity(compiler.context(), entity, relationshipBuilder, reInfo);
            Long srcIdentity = mappingContext.nativeId(startNode);
            Long tgtIdentity = mappingContext.nativeId(endNode);
            RelationshipNodes relNodes = new RelationshipNodes(srcIdentity, tgtIdentity, startNode.getClass(), endNode.getClass());
            // 2. update the fact of the relationship in the compile context
            updateRelationship(compiler.context(), startNodeBuilder, endNodeBuilder, relationshipBuilder, relNodes);
        }
    } else {
        // not an RE, simply map the entity
        mapEntity(entity, horizon);
    }
    deleteObsoleteRelationships();
    return compiler.context();
}
Also used : NodeBuilder(org.neo4j.ogm.cypher.compiler.NodeBuilder) ClassInfo(org.neo4j.ogm.metadata.ClassInfo) AnnotationInfo(org.neo4j.ogm.metadata.AnnotationInfo) RelationshipBuilder(org.neo4j.ogm.cypher.compiler.RelationshipBuilder)

Example 4 with RelationshipBuilder

use of org.neo4j.ogm.cypher.compiler.RelationshipBuilder in project neo4j-ogm by neo4j.

the class EntityGraphMapper method link.

/**
 * Handles the requirement to link two nodes in the graph for the cypher compiler. Either node may or
 * may not already exist in the graph. The nodes at the ends of the relationships are represented
 * by source and target, but the use of these names does not imply any particular direction in the graph.
 * Instead, the direction of the relationship is established between source and target by means of
 * the relationshipDirection argument.
 * In the event that the relationship being managed is represented by an instance of RelationshipEntity
 * then the target will always be a RelationshipEntity, and the actual relationship will be
 * established between the relevant start and end nodes.
 *
 * @param directedRelationship the {@link DirectedRelationship} representing the relationship type and direction
 * @param nodeBuilder          a {@link NodeBuilder} that knows how to create cypher node phrases
 * @param horizon              the current depth we have mapped the domain model to.
 * @param mapBothDirections    whether the nodes should be linked in both directions
 * @param relNodes             {@link EntityGraphMapper.RelationshipNodes} representing the nodes to be linked
 */
private void link(DirectedRelationship directedRelationship, NodeBuilder nodeBuilder, int horizon, boolean mapBothDirections, RelationshipNodes relNodes) {
    LOGGER.debug("linking to entity {} in {} direction", relNodes.target, mapBothDirections ? "both" : "one");
    if (relNodes.target != null) {
        CompileContext context = compiler.context();
        RelationshipBuilder relationshipBuilder = getRelationshipBuilder(compiler, relNodes.target, directedRelationship, mapBothDirections);
        if (isRelationshipEntity(relNodes.target)) {
            LOGGER.debug("mapping relationship entity");
            Long reIdentity = mappingContext.nativeId(relNodes.target);
            if (!context.visitedRelationshipEntity(reIdentity)) {
                mapRelationshipEntity(relNodes.target, relNodes.source, relationshipBuilder, context, nodeBuilder, horizon, relNodes.sourceType, relNodes.targetType);
            } else {
                LOGGER.debug("RE already visited {}: ", relNodes.target);
            }
        } else {
            LOGGER.debug("mapping related entity");
            mapRelatedEntity(nodeBuilder, relationshipBuilder, currentDepth.get(), horizon, relNodes);
        }
    } else {
        LOGGER.debug("cannot create relationship: ({})-[:{}]->(null)", relNodes.sourceId, directedRelationship.type());
    }
}
Also used : CompileContext(org.neo4j.ogm.cypher.compiler.CompileContext) RelationshipBuilder(org.neo4j.ogm.cypher.compiler.RelationshipBuilder)

Aggregations

RelationshipBuilder (org.neo4j.ogm.cypher.compiler.RelationshipBuilder)4 ClassInfo (org.neo4j.ogm.metadata.ClassInfo)3 CompileContext (org.neo4j.ogm.cypher.compiler.CompileContext)2 FieldInfo (org.neo4j.ogm.metadata.FieldInfo)2 NodeBuilder (org.neo4j.ogm.cypher.compiler.NodeBuilder)1 AnnotationInfo (org.neo4j.ogm.metadata.AnnotationInfo)1