use of org.neo4j.ogm.response.Response in project neo4j-ogm by neo4j.
the class GraphEntityMapper method map.
/**
* @param type the type of the entities to return
* @param graphModelResponse The response of graph models to work on
* @param additionalNodeFilter An optional filter to exclude entities based on some nodes from the result
* @param <T> The type of the class of the entities to return
* @return The list of entities represented by the list of graph models.
*/
<T> List<T> map(Class<T> type, Response<GraphModel> graphModelResponse, BiFunction<GraphModel, Long, Boolean> additionalNodeFilter) {
// Those are the ids of all mapped nodes.
Set<Long> mappedNodeIds = new LinkedHashSet<>();
Set<Long> returnedNodeIds = new LinkedHashSet<>();
Set<Long> mappedRelationshipIds = new LinkedHashSet<>();
Set<Long> returnedRelationshipIds = new LinkedHashSet<>();
// Execute mapping for each individual model
Consumer<GraphModel> mapContentOfIndividualModel = graphModel -> mapContentOf(graphModel, additionalNodeFilter, returnedNodeIds, mappedRelationshipIds, returnedRelationshipIds, mappedNodeIds);
GraphModel graphModel = null;
while ((graphModel = graphModelResponse.next()) != null) {
mapContentOfIndividualModel.accept(graphModel);
}
graphModelResponse.close();
// Execute postload after all models and only for new ids
executePostLoad(mappedNodeIds, mappedRelationshipIds);
// Collect result
Predicate<Object> entityPresentAndCompatible = entity -> entity != null && type.isAssignableFrom(entity.getClass());
List<T> results = returnedNodeIds.stream().map(mappingContext::getNodeEntity).filter(entityPresentAndCompatible).map(type::cast).collect(toList());
// only look for REs if no node entities were found
if (results.isEmpty()) {
results = returnedRelationshipIds.stream().map(mappingContext::getRelationshipEntity).filter(entityPresentAndCompatible).map(type::cast).collect(toList());
}
return results;
}
use of org.neo4j.ogm.response.Response 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.response.Response in project neo4j-ogm by neo4j.
the class EmbeddedRequest method execute.
@Override
public Response<RowModel> execute(DefaultRequest query) {
// TODO this is a hack to get the embedded driver to work with executing multiple statements
final List<RowModel> rowmodels = new ArrayList<>();
String[] columns = null;
for (Statement statement : query.getStatements()) {
Result result = executeRequest(statement);
if (columns == null) {
columns = result.columns().toArray(new String[result.columns().size()]);
}
RowModelResponse rowModelResponse = new RowModelResponse(result, entityAdapter);
RowModel model;
while ((model = rowModelResponse.next()) != null) {
rowmodels.add(model);
}
result.close();
}
final String[] finalColumns = columns;
return new Response<>() {
int currentRow = 0;
@Override
public RowModel next() {
if (currentRow < rowmodels.size()) {
return rowmodels.get(currentRow++);
}
return null;
}
@Override
public void close() {
}
@Override
public String[] columns() {
return finalColumns;
}
};
}
use of org.neo4j.ogm.response.Response in project neo4j-ogm by neo4j.
the class GraphRowListModelMapper method map.
public <T> Iterable<T> map(Class<T> type, Response<GraphRowListModel> response) {
Set<Long> idsOfResultEntities = new LinkedHashSet<>();
Response<GraphModel> graphResponse = new Response<GraphModel>() {
GraphRowListModel currentIteratedModel;
int currentIndex = 0;
@Override
public GraphModel next() {
if (currentIteratedModel == null) {
currentIteratedModel = response.next();
if (currentIteratedModel == null) {
return null;
}
currentIndex = 0;
}
List<GraphRowModel> listOfRowModels = currentIteratedModel.model();
if (listOfRowModels.size() <= currentIndex) {
currentIteratedModel = null;
return next();
}
GraphRowModel graphRowModel = listOfRowModels.get(currentIndex++);
Set<Long> idsInCurrentRow = Arrays.stream(graphRowModel.getRow()).filter(Number.class::isInstance).map(Number.class::cast).map(Number::longValue).collect(toSet());
idsOfResultEntities.addAll(idsInCurrentRow);
return graphRowModel.getGraph();
}
@Override
public void close() {
response.close();
}
@Override
public String[] columns() {
return response.columns();
}
};
// although it looks like that the `idsOfResultEntities` will stay empty, they won't, trust us.
BiFunction<GraphModel, Long, Boolean> includeModelObject = (graphModel, nativeId) -> idsOfResultEntities.contains(nativeId);
return delegate.map(type, graphResponse, includeModelObject);
}
use of org.neo4j.ogm.response.Response in project neo4j-ogm by neo4j.
the class DeleteDelegate method deleteOneOrMoreObjects.
// TODO : this is being done in multiple requests at the moment, one per object. Why not put them in a single request?
private void deleteOneOrMoreObjects(List<?> objects, Set<Object> neighbours) {
Set<Object> notified = new HashSet<>();
if (session.eventsEnabled()) {
for (Object affectedObject : neighbours) {
if (!notified.contains(affectedObject)) {
session.notifyListeners(new PersistenceEvent(affectedObject, Event.TYPE.PRE_SAVE));
notified.add(affectedObject);
}
}
}
for (Object object : objects) {
MetaData metaData = session.metaData();
ClassInfo classInfo = metaData.classInfo(object);
if (classInfo == null) {
session.warn(object.getClass().getName() + " is not an instance of a persistable class");
} else {
MappingContext mappingContext = session.context();
Long id = mappingContext.optionalNativeId(object).filter(possibleId -> possibleId >= 0).orElseGet(() -> {
session.warn(String.format("Instance of class %s has to be reloaded to be deleted. This can happen if the session has " + "been cleared between loading and deleting or using an object from a different transaction.", object.getClass()));
return classInfo.getPrimaryIndexOrIdReader().apply(object).map(primaryIndexOrId -> session.load(object.getClass(), (Serializable) primaryIndexOrId)).flatMap(reloadedObject -> mappingContext.optionalNativeId(reloadedObject)).orElse(-1L);
});
if (id >= 0) {
Statement request = getDeleteStatement(object, id, classInfo);
if (session.eventsEnabled() && !notified.contains(object)) {
session.notifyListeners(new PersistenceEvent(object, Event.TYPE.PRE_DELETE));
notified.add(object);
}
RowModelRequest query = new DefaultRowModelRequest(request.getStatement(), request.getParameters());
session.doInTransaction(() -> {
try (Response<RowModel> response = session.requestHandler().execute(query)) {
if (request.optimisticLockingConfig().isPresent()) {
List<RowModel> rowModels = response.toList();
session.optimisticLockingChecker().checkResultsCount(rowModels, request);
}
if (metaData.isRelationshipEntity(classInfo.name())) {
session.detachRelationshipEntity(id);
} else {
session.detachNodeEntity(id);
}
// enabled in the first place.
if (notified.contains(object)) {
session.notifyListeners(new PersistenceEvent(object, Event.TYPE.POST_DELETE));
}
}
}, Transaction.Type.READ_WRITE);
}
}
}
if (session.eventsEnabled()) {
for (Object affectedObject : neighbours) {
if (notified.contains(affectedObject)) {
session.notifyListeners(new PersistenceEvent(affectedObject, Event.TYPE.POST_SAVE));
}
}
}
}
Aggregations