use of org.neo4j.ogm.cypher.compiler.CompileContext in project neo4j-ogm by neo4j.
the class EntityGraphMapper method mapEntity.
/**
* Builds Cypher to save the specified object and all its composite objects into the graph database.
*
* @param entity The object to persist into the graph database as a node
* @return The "root" node of the object graph that matches
*/
private NodeBuilder mapEntity(Object entity, int horizon) {
// if this object is transient it won't have a classinfo, and isn't persistable
ClassInfo classInfo = metaData.classInfo(entity);
if (classInfo == null) {
return null;
}
CompileContext context = compiler.context();
NodeBuilder nodeBuilder = context.visitedNode(entity);
if (context.visited(entity, horizon)) {
LOGGER.debug("already visited: {}", entity);
return nodeBuilder;
}
if (nodeBuilder == null) {
nodeBuilder = newNodeBuilder(entity, horizon);
if (!isWriteProtected(WriteProtectionTarget.PROPERTIES, entity)) {
updateNode(entity, context, nodeBuilder);
}
}
if (horizon != 0) {
mapEntityReferences(entity, nodeBuilder, horizon - 1);
} else {
LOGGER.debug("at horizon 0: {} ", entity);
}
return nodeBuilder;
}
use of org.neo4j.ogm.cypher.compiler.CompileContext in project neo4j-ogm by neo4j.
the class EntityGraphMapper method mapRelatedEntity.
/**
* Attempts to build a simple directed relationship in the graph between
* two objects represented as srcEntity and tgtEntity. This function recursively calls mapEntity on the
* target entity first before attempting to create the relationship. In this way, the object graph
* is traversed in depth-first order, and the relationships between the leaf nodes are created
* first.
*
* @param srcNodeBuilder a {@link NodeBuilder} that knows how to create cypher phrases about nodes
* @param relationshipBuilder a {@link RelationshipBuilder} that knows how to create cypher phrases about relationships
* @param horizon a value representing how deep we are mapping
* @param relNodes {@link EntityGraphMapper.RelationshipNodes} representing the nodes at the end of this relationship
*/
private void mapRelatedEntity(NodeBuilder srcNodeBuilder, RelationshipBuilder relationshipBuilder, int level, int horizon, RelationshipNodes relNodes) {
// context.visited fails if the class isn't a mapped class, so we have to check this first, even if mapEntity will do it again
ClassInfo classInfo = metaData.classInfo(relNodes.target);
if (classInfo == null) {
return;
}
CompileContext context = compiler.context();
boolean alreadyVisitedNode = context.visited(relNodes.target, horizon);
boolean selfReferentialUndirectedRelationship = relationshipBuilder.hasDirection(Direction.UNDIRECTED) && relNodes.source.getClass() == relNodes.target.getClass();
boolean relationshipFromExplicitlyMappedObject = level == 1;
// Map this entity (mapEntity checks whether the entity has been visited before)
NodeBuilder tgtNodeBuilder = mapEntity(relNodes.target, horizon);
// - or the relationships is defined on an object being explicitly mapped
if (!alreadyVisitedNode || !selfReferentialUndirectedRelationship || relationshipFromExplicitlyMappedObject) {
LOGGER.debug("trying to map relationship between {} and {}", relNodes.source, relNodes.target);
relNodes.targetId = mappingContext.nativeId(relNodes.target);
updateRelationship(context, srcNodeBuilder, tgtNodeBuilder, relationshipBuilder, relNodes);
}
}
use of org.neo4j.ogm.cypher.compiler.CompileContext 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();
}
}
}
use of org.neo4j.ogm.cypher.compiler.CompileContext in project neo4j-ogm by neo4j.
the class RequestExecutor method executeSave.
/**
* Execute a save request.
* Decides how the request is split depending upon characteristics of what is to be saved.
* Processes the response(s) and updates the mapping context.
*
* @param context the CompileContext for this request
*/
public void executeSave(CompileContext context) {
Compiler compiler = context.getCompiler();
compiler.useStatementFactory(new RowStatementFactory());
List<ReferenceMapping> entityReferenceMappings = new ArrayList<>();
List<ReferenceMapping> relReferenceMappings = new ArrayList<>();
boolean forceTx = compiler.updateNodesStatements().stream().anyMatch(st -> st.optimisticLockingConfig().isPresent()) || compiler.updateRelationshipStatements().stream().anyMatch(st -> st.optimisticLockingConfig().isPresent());
session.doInTransaction(() -> {
// we must create the new nodes first, and then use their node IDs when creating relationships between them
if (compiler.hasStatementsDependentOnNewNodes()) {
// execute the statements to create new nodes. The ids will be returned
// and will be used in subsequent statements that refer to these new nodes.
executeStatements(context, entityReferenceMappings, relReferenceMappings, compiler.createNodesStatements());
List<Statement> statements = new ArrayList<>();
statements.addAll(compiler.createRelationshipsStatements());
statements.addAll(compiler.updateNodesStatements());
statements.addAll(compiler.updateRelationshipStatements());
statements.addAll(compiler.deleteRelationshipStatements());
statements.addAll(compiler.deleteRelationshipEntityStatements());
executeStatements(context, entityReferenceMappings, relReferenceMappings, statements);
} else {
// only update / delete statements
List<Statement> statements = compiler.getAllStatements();
executeStatements(context, entityReferenceMappings, relReferenceMappings, statements);
}
}, forceTx, Transaction.Type.READ_WRITE);
// Update the mapping context now that the request is successful
updateNodeEntities(context, entityReferenceMappings);
updateRelationshipEntities(context, relReferenceMappings);
updateRelationships(context, relReferenceMappings);
}
use of org.neo4j.ogm.cypher.compiler.CompileContext in project neo4j-ogm by neo4j.
the class MergeWithPrimaryIndexTests method mapAndCompile.
private Compiler mapAndCompile(Object object) {
CompileContext context = this.mapper.map(object);
Compiler compiler = context.getCompiler();
compiler.useStatementFactory(new RowStatementFactory());
return compiler;
}
Aggregations