56
56
import org .springframework .data .mapping .AssociationHandler ;
57
57
import org .springframework .data .mapping .PersistentPropertyAccessor ;
58
58
import org .springframework .data .mapping .callback .EntityCallbacks ;
59
+ import org .springframework .data .neo4j .core .TemplateSupport .NodesAndRelationshipsByIdStatementProvider ;
59
60
import org .springframework .data .neo4j .core .mapping .Constants ;
60
61
import org .springframework .data .neo4j .core .mapping .CreateRelationshipStatementHolder ;
61
62
import org .springframework .data .neo4j .core .mapping .CypherGenerator ;
70
71
import org .springframework .data .neo4j .core .mapping .RelationshipDescription ;
71
72
import org .springframework .data .neo4j .core .mapping .callback .EventSupport ;
72
73
import org .springframework .data .neo4j .repository .NoResultException ;
74
+ import org .springframework .data .neo4j .repository .query .QueryFragments ;
73
75
import org .springframework .data .neo4j .repository .query .QueryFragmentsAndParameters ;
74
76
import org .springframework .data .projection .ProjectionFactory ;
75
77
import org .springframework .data .projection .ProjectionInformation ;
@@ -362,7 +364,7 @@ private <T> T saveImpl(T instance, @Nullable List<PropertyDescriptor> includedPr
362
364
private <T > DynamicLabels determineDynamicLabels (T entityToBeSaved , Neo4jPersistentEntity <?> entityMetaData ) {
363
365
return entityMetaData .getDynamicLabelsProperty ().map (p -> {
364
366
365
- PersistentPropertyAccessor propertyAccessor = entityMetaData .getPropertyAccessor (entityToBeSaved );
367
+ PersistentPropertyAccessor < T > propertyAccessor = entityMetaData .getPropertyAccessor (entityToBeSaved );
366
368
Neo4jClient .RunnableSpecTightToDatabase runnableQuery = neo4jClient
367
369
.query (() -> renderer .render (cypherGenerator .createStatementReturningDynamicLabels (entityMetaData )))
368
370
.bind (propertyAccessor .getProperty (entityMetaData .getRequiredIdProperty ()))
@@ -410,14 +412,14 @@ private <T> List<T> saveAllImpl(Iterable<T> instances, @Nullable List<PropertyDe
410
412
}
411
413
412
414
class Tuple3 <T > {
413
- T t1 ;
414
- boolean t2 ;
415
- T t3 ;
416
-
417
- Tuple3 (T t1 , boolean t2 , T t3 ) {
418
- this .t1 = t1 ;
419
- this .t2 = t2 ;
420
- this .t3 = t3 ;
415
+ final T originalInstance ;
416
+ final boolean wasNew ;
417
+ final T modifiedInstance ;
418
+
419
+ Tuple3 (T originalInstance , boolean wasNew , T modifiedInstance ) {
420
+ this .originalInstance = originalInstance ;
421
+ this .wasNew = wasNew ;
422
+ this .modifiedInstance = modifiedInstance ;
421
423
}
422
424
}
423
425
@@ -427,7 +429,7 @@ class Tuple3<T> {
427
429
428
430
// Save roots
429
431
Function <T , Map <String , Object >> binderFunction = neo4jMappingContext .getRequiredBinderFunctionFor (domainClass );
430
- List <Map <String , Object >> entityList = entitiesToBeSaved .stream ().map (h -> h .t3 ).map (binderFunction )
432
+ List <Map <String , Object >> entityList = entitiesToBeSaved .stream ().map (h -> h .modifiedInstance ).map (binderFunction )
431
433
.collect (Collectors .toList ());
432
434
ResultSummary resultSummary = neo4jClient
433
435
.query (() -> renderer .render (cypherGenerator .prepareSaveOfMultipleInstancesOf (entityMetaData )))
@@ -441,8 +443,8 @@ class Tuple3<T> {
441
443
442
444
// Save related
443
445
return entitiesToBeSaved .stream ().map (t -> {
444
- PersistentPropertyAccessor <T > propertyAccessor = entityMetaData .getPropertyAccessor (t .t3 );
445
- return processRelations (entityMetaData , t .t1 , propertyAccessor , t .t2 , TemplateSupport .computeIncludePropertyPredicate (includedProperties ));
446
+ PersistentPropertyAccessor <T > propertyAccessor = entityMetaData .getPropertyAccessor (t .modifiedInstance );
447
+ return processRelations (entityMetaData , t .originalInstance , propertyAccessor , t .wasNew , TemplateSupport .computeIncludePropertyPredicate (includedProperties ));
446
448
}).collect (Collectors .toList ());
447
449
}
448
450
@@ -848,21 +850,21 @@ private Optional<Neo4jClient.RecordFetchSpec<T>> createFetchSpec() {
848
850
String cypherQuery = queryFragmentsAndParameters .getCypherQuery ();
849
851
Map <String , Object > finalParameters = queryFragmentsAndParameters .getParameters ();
850
852
851
- QueryFragmentsAndParameters . QueryFragments queryFragments = queryFragmentsAndParameters .getQueryFragments ();
853
+ QueryFragments queryFragments = queryFragmentsAndParameters .getQueryFragments ();
852
854
Neo4jPersistentEntity <?> entityMetaData = (Neo4jPersistentEntity <?>) queryFragmentsAndParameters .getNodeDescription ();
853
855
854
856
boolean containsPossibleCircles = entityMetaData != null && entityMetaData .containsPossibleCircles (queryFragments ::includeField );
855
857
if (cypherQuery == null || containsPossibleCircles ) {
856
858
857
859
if (containsPossibleCircles && !queryFragments .isScalarValueReturn ()) {
858
- GenericQueryAndParameters genericQueryAndParameters =
859
- createQueryAndParameters (entityMetaData , queryFragments , queryFragmentsAndParameters .getParameters ());
860
+ NodesAndRelationshipsByIdStatementProvider nodesAndRelationshipsById =
861
+ createNodesAndRelationshipsByIdStatementProvider (entityMetaData , queryFragments , queryFragmentsAndParameters .getParameters ());
860
862
861
- if (genericQueryAndParameters . isEmpty ()) {
863
+ if (nodesAndRelationshipsById . hasRootNodeIds ()) {
862
864
return Optional .empty ();
863
865
}
864
- cypherQuery = renderer .render (queryFragments . generateGenericStatement ());
865
- finalParameters = genericQueryAndParameters .getParameters ();
866
+ cypherQuery = renderer .render (nodesAndRelationshipsById . toStatement ());
867
+ finalParameters = nodesAndRelationshipsById .getParameters ();
866
868
} else {
867
869
Statement statement = queryFragments .toStatement ();
868
870
cypherQuery = renderer .render (statement );
@@ -876,8 +878,8 @@ private Optional<Neo4jClient.RecordFetchSpec<T>> createFetchSpec() {
876
878
.map (f -> newMappingSpec .mappedBy (f )).orElse (newMappingSpec ));
877
879
}
878
880
879
- private GenericQueryAndParameters createQueryAndParameters (Neo4jPersistentEntity <?> entityMetaData ,
880
- QueryFragmentsAndParameters . QueryFragments queryFragments , Map <String , Object > parameters ) {
881
+ private NodesAndRelationshipsByIdStatementProvider createNodesAndRelationshipsByIdStatementProvider (Neo4jPersistentEntity <?> entityMetaData ,
882
+ QueryFragments queryFragments , Map <String , Object > parameters ) {
881
883
882
884
// first check if the root node(s) exist(s) at all
883
885
Statement rootNodesStatement = cypherGenerator
@@ -896,7 +898,7 @@ private GenericQueryAndParameters createQueryAndParameters(Neo4jPersistentEntity
896
898
897
899
if (rootNodeIds .isEmpty ()) {
898
900
// fast return if no matching root node(s) are found
899
- return GenericQueryAndParameters .EMPTY ;
901
+ return NodesAndRelationshipsByIdStatementProvider .EMPTY ;
900
902
}
901
903
// load first level relationships
902
904
final Set <Long > relationshipIds = new HashSet <>();
@@ -917,7 +919,7 @@ private GenericQueryAndParameters createQueryAndParameters(Neo4jPersistentEntity
917
919
.ifPresent (iterateAndMapNextLevel (relationshipIds , relatedNodeIds , relationshipDescription ));
918
920
}
919
921
920
- return new GenericQueryAndParameters (rootNodeIds , relationshipIds , relatedNodeIds );
922
+ return new NodesAndRelationshipsByIdStatementProvider (rootNodeIds , relationshipIds , relatedNodeIds , queryFragments );
921
923
}
922
924
923
925
private void iterateNextLevel (Collection <Long > nodeIds , Neo4jPersistentEntity <?> target , Set <Long > relationshipIds ,
0 commit comments