30
30
import java .util .function .Function ;
31
31
import java .util .function .Predicate ;
32
32
import java .util .function .Supplier ;
33
+ import java .util .stream .Collectors ;
33
34
import java .util .stream .StreamSupport ;
34
35
35
36
import org .neo4j .driver .Value ;
@@ -105,7 +106,7 @@ public <R> R read(Class<R> targetType, MapAccessor mapAccessor) {
105
106
}
106
107
107
108
try {
108
- return map (queryRoot , queryRoot , rootNodeDescription , new HashSet <>() );
109
+ return map (queryRoot , queryRoot , rootNodeDescription );
109
110
} catch (Exception e ) {
110
111
throw new MappingException ("Error mapping " + mapAccessor .toString (), e );
111
112
}
@@ -241,11 +242,13 @@ private static MapAccessor mergeRootNodeWithRecord(Node node, MapAccessor record
241
242
* @return The mapped entity
242
243
*/
243
244
private <ET > ET map (MapAccessor queryResult , MapAccessor allValues , Neo4jPersistentEntity <ET > nodeDescription ) {
244
- return map (queryResult , allValues , nodeDescription , null );
245
+ Collection <Relationship > relationshipsFromResult = extractRelationships (allValues );
246
+ Collection <Node > nodesFromResult = extractNodes (allValues );
247
+ return map (queryResult , nodeDescription , null , relationshipsFromResult , nodesFromResult );
245
248
}
246
249
247
- private <ET > ET map (MapAccessor queryResult , MapAccessor allValues , Neo4jPersistentEntity <ET > nodeDescription ,
248
- @ Nullable Object lastMappedEntity ) {
250
+ private <ET > ET map (MapAccessor queryResult , Neo4jPersistentEntity <ET > nodeDescription ,
251
+ @ Nullable Object lastMappedEntity , Collection < Relationship > relationshipsFromResult , Collection < Node > nodesFromResult ) {
249
252
250
253
// if the given result does not contain an identifier to the mapped object cannot get temporarily saved
251
254
Long internalId = getInternalId (queryResult );
@@ -258,13 +261,8 @@ private <ET> ET map(MapAccessor queryResult, MapAccessor allValues, Neo4jPersist
258
261
Neo4jPersistentEntity <ET > concreteNodeDescription = (Neo4jPersistentEntity <ET >) nodeDescriptionAndLabels
259
262
.getNodeDescription ();
260
263
261
- Predicate <String > includeAllFields = (field ) -> true ;
262
-
263
- Collection <RelationshipDescription > relationships = nodeDescription
264
- .getRelationshipsInHierarchy (includeAllFields );
265
-
266
- ET instance = instantiate (concreteNodeDescription , queryResult , allValues , relationships ,
267
- nodeDescriptionAndLabels .getDynamicLabels (), lastMappedEntity );
264
+ ET instance = instantiate (concreteNodeDescription , queryResult ,
265
+ nodeDescriptionAndLabels .getDynamicLabels (), lastMappedEntity , relationshipsFromResult , nodesFromResult );
268
266
269
267
PersistentPropertyAccessor <ET > propertyAccessor = concreteNodeDescription .getPropertyAccessor (instance );
270
268
@@ -283,7 +281,7 @@ private <ET> ET map(MapAccessor queryResult, MapAccessor allValues, Neo4jPersist
283
281
knownObjects .storeObject (internalId , instance );
284
282
// Fill associations
285
283
concreteNodeDescription .doWithAssociations (
286
- populateFrom (queryResult , allValues , propertyAccessor , isConstructorParameter ));
284
+ populateFrom (queryResult , propertyAccessor , isConstructorParameter , relationshipsFromResult , nodesFromResult ));
287
285
}
288
286
ET bean = propertyAccessor .getBean ();
289
287
@@ -357,9 +355,9 @@ private boolean containsOnePlainNode(MapAccessor queryResult) {
357
355
.filter (value -> value .hasType (nodeType )).count () == 1L ;
358
356
}
359
357
360
- private <ET > ET instantiate (Neo4jPersistentEntity <ET > nodeDescription , MapAccessor values , MapAccessor allValues ,
361
- Collection <RelationshipDescription > relationships , Collection < String > surplusLabels ,
362
- @ Nullable Object lastMappedEntity ) {
358
+ private <ET > ET instantiate (Neo4jPersistentEntity <ET > nodeDescription , MapAccessor values ,
359
+ Collection <String > surplusLabels , @ Nullable Object lastMappedEntity ,
360
+ Collection < Relationship > relationshipsFromResult , Collection < Node > nodesFromResult ) {
363
361
364
362
ParameterValueProvider <Neo4jPersistentProperty > parameterValueProvider = new ParameterValueProvider <Neo4jPersistentProperty >() {
365
363
@ Override
@@ -373,7 +371,7 @@ public Object getParameterValue(PreferredConstructor.Parameter parameter) {
373
371
String propertyFieldName = matchingProperty .getFieldName ();
374
372
return r .getFieldName ().equals (propertyFieldName );
375
373
}).findFirst ().get ();
376
- return createInstanceOfRelationships (matchingProperty , values , allValues , relationshipDescription ).orElse (null );
374
+ return createInstanceOfRelationships (matchingProperty , values , relationshipDescription , relationshipsFromResult , nodesFromResult ).orElse (null );
377
375
} else if (matchingProperty .isDynamicLabels ()) {
378
376
return createDynamicLabelsProperty (matchingProperty .getTypeInformation (), surplusLabels );
379
377
} else if (matchingProperty .isEntityWithRelationshipProperties ()) {
@@ -408,22 +406,22 @@ private PropertyHandler<Neo4jPersistentProperty> populateFrom(MapAccessor queryR
408
406
};
409
407
}
410
408
411
- private AssociationHandler <Neo4jPersistentProperty > populateFrom (MapAccessor queryResult , MapAccessor allValues ,
412
- PersistentPropertyAccessor <?> propertyAccessor , Predicate <Neo4jPersistentProperty > isConstructorParameter ) {
409
+ private AssociationHandler <Neo4jPersistentProperty > populateFrom (MapAccessor queryResult ,
410
+ PersistentPropertyAccessor <?> propertyAccessor , Predicate <Neo4jPersistentProperty > isConstructorParameter , Collection < Relationship > relationshipsFromResult , Collection < Node > nodesFromResult ) {
413
411
return association -> {
414
412
415
413
Neo4jPersistentProperty persistentProperty = association .getInverse ();
416
414
if (isConstructorParameter .test (persistentProperty )) {
417
415
return ;
418
416
}
419
417
420
- createInstanceOfRelationships (persistentProperty , queryResult , allValues , (RelationshipDescription ) association )
418
+ createInstanceOfRelationships (persistentProperty , queryResult , (RelationshipDescription ) association , relationshipsFromResult , nodesFromResult )
421
419
.ifPresent (value -> propertyAccessor .setProperty (persistentProperty , value ));
422
420
};
423
421
}
424
422
425
423
private Optional <Object > createInstanceOfRelationships (Neo4jPersistentProperty persistentProperty , MapAccessor values ,
426
- MapAccessor allValues , RelationshipDescription relationshipDescription ) {
424
+ RelationshipDescription relationshipDescription , Collection < Relationship > relationshipsFromResult , Collection < Node > nodesFromResult ) {
427
425
428
426
String typeOfRelationship = relationshipDescription .getType ();
429
427
String sourceLabel = relationshipDescription .getSource ().getPrimaryLabel ();
@@ -464,30 +462,35 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
464
462
List <Object > relationshipsAndProperties = new ArrayList <>();
465
463
466
464
if (Values .NULL .equals (list )) {
465
+ Long sourceNodeId = getInternalId (values );
466
+
467
+ Function <Relationship , Long > sourceIdSelector = relationshipDescription .isIncoming () ? Relationship ::endNodeId : Relationship ::startNodeId ;
468
+ Function <Relationship , Long > targetIdSelector = relationshipDescription .isIncoming () ? Relationship ::startNodeId : Relationship ::endNodeId ;
469
+
470
+ // Retrieve all matching relationships from the result's list(s)
471
+ Collection <Relationship > allMatchingTypeRelationshipsInResult =
472
+ extractMatchingRelationships (relationshipsFromResult , relationshipDescription , typeOfRelationship ,
473
+ (possibleRelationship ) -> sourceIdSelector .apply (possibleRelationship ).equals (sourceNodeId ));
467
474
468
- // Retrieve all relationships from the result's list(s)
469
- Collection <Relationship > allMatchingTypeRelationshipsInResult = extractMatchingRelationships (allValues , relationshipDescription , typeOfRelationship );
470
475
// Retrieve all nodes from the result's list(s)
471
- Collection <Node > allNodesWithMatchingLabelInResult = extractMatchingNodes (allValues , targetLabel );
476
+ Collection <Node > allNodesWithMatchingLabelInResult = extractMatchingNodes (nodesFromResult , targetLabel );
472
477
473
- Function <Relationship , Long > targetIdSelector = relationshipDescription .isIncoming () ? Relationship ::startNodeId : Relationship ::endNodeId ;
474
- Function <Relationship , Long > sourceIdSelector = relationshipDescription .isIncoming () ? Relationship ::endNodeId : Relationship ::startNodeId ;
475
- Long sourceNodeId = getInternalId (values );
476
478
for (Node possibleValueNode : allNodesWithMatchingLabelInResult ) {
477
479
long targetNodeId = possibleValueNode .id ();
480
+
481
+ Neo4jPersistentEntity <?> concreteTargetNodeDescription =
482
+ getMostConcreteTargetNodeDescription (genericTargetNodeDescription , possibleValueNode );
483
+
478
484
Set <Relationship > relationshipsProcessed = new HashSet <>();
479
485
for (Relationship possibleRelationship : allMatchingTypeRelationshipsInResult ) {
480
- if (targetIdSelector .apply (possibleRelationship ) == targetNodeId && sourceIdSelector .apply (possibleRelationship ).equals (sourceNodeId )) {
481
-
482
- Neo4jPersistentEntity <?> concreteTargetNodeDescription =
483
- getMostConcreteTargetNodeDescription (genericTargetNodeDescription , possibleValueNode );
486
+ if (targetIdSelector .apply (possibleRelationship ) == targetNodeId ) {
484
487
485
- Object mappedObject = map (possibleValueNode , allValues , concreteTargetNodeDescription );
488
+ Object mappedObject = map (possibleValueNode , concreteTargetNodeDescription , null , relationshipsFromResult , nodesFromResult );
486
489
if (relationshipDescription .hasRelationshipProperties ()) {
487
490
488
- Object relationshipProperties = map (possibleRelationship , allValues ,
491
+ Object relationshipProperties = map (possibleRelationship ,
489
492
(Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
490
- mappedObject );
493
+ mappedObject , relationshipsFromResult , nodesFromResult );
491
494
relationshipsAndProperties .add (relationshipProperties );
492
495
mappedObjectHandler .accept (possibleRelationship .type (), relationshipProperties );
493
496
} else {
@@ -504,17 +507,17 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
504
507
Neo4jPersistentEntity <?> concreteTargetNodeDescription =
505
508
getMostConcreteTargetNodeDescription (genericTargetNodeDescription , relatedEntity );
506
509
507
- Object valueEntry = map (relatedEntity , allValues , concreteTargetNodeDescription );
510
+ Object valueEntry = map (relatedEntity , concreteTargetNodeDescription , null , relationshipsFromResult , nodesFromResult );
508
511
509
512
if (relationshipDescription .hasRelationshipProperties ()) {
510
513
String relationshipSymbolicName = sourceLabel
511
514
+ RelationshipDescription .NAME_OF_RELATIONSHIP + targetLabel ;
512
515
Relationship relatedEntityRelationship = relatedEntity .get (relationshipSymbolicName )
513
516
.asRelationship ();
514
517
515
- Object relationshipProperties = map (relatedEntityRelationship , allValues ,
518
+ Object relationshipProperties = map (relatedEntityRelationship ,
516
519
(Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
517
- valueEntry );
520
+ valueEntry , relationshipsFromResult , nodesFromResult );
518
521
relationshipsAndProperties .add (relationshipProperties );
519
522
mappedObjectHandler .accept (relatedEntity .get (RelationshipDescription .NAME_OF_RELATIONSHIP_TYPE ).asString (), relationshipProperties );
520
523
} else {
@@ -540,46 +543,54 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
540
543
}
541
544
}
542
545
543
- private Collection <Node > extractMatchingNodes (MapAccessor allValues , String targetLabel ) {
546
+ private Collection <Node > extractMatchingNodes (Collection < Node > allNodesInResult , String targetLabel ) {
544
547
545
- Collection <Node > allNodesWithMatchingLabelInResult = new ArrayList <>();
546
548
Predicate <Node > onlyWithMatchingLabels = n -> n .hasLabel (targetLabel );
549
+ return allNodesInResult .stream ()
550
+ .filter (onlyWithMatchingLabels )
551
+ .collect (Collectors .toSet ());
552
+ }
553
+
554
+ private Collection <Node > extractNodes (MapAccessor allValues ) {
555
+ Collection <Node > allNodesInResult = new ArrayList <>();
547
556
StreamSupport .stream (allValues .values ().spliterator (), false )
548
557
.filter (MappingSupport .isListContainingOnly (listType , this .nodeType ))
549
558
.flatMap (entry -> MappingSupport .extractNodes (listType , entry ).stream ())
550
- .filter (onlyWithMatchingLabels )
551
- .forEach (allNodesWithMatchingLabelInResult ::add );
559
+ .forEach (allNodesInResult ::add );
552
560
553
- if (allNodesWithMatchingLabelInResult .isEmpty ()) {
561
+ if (allNodesInResult .isEmpty ()) {
554
562
StreamSupport .stream (allValues .values ().spliterator (), false )
555
563
.filter (this .nodeType ::isTypeOf )
556
564
.map (Value ::asNode )
557
- .filter (onlyWithMatchingLabels )
558
- .forEach (allNodesWithMatchingLabelInResult ::add );
565
+ .forEach (allNodesInResult ::add );
559
566
}
560
567
561
- return allNodesWithMatchingLabelInResult ;
568
+ return allNodesInResult ;
562
569
}
563
570
564
- private Collection <Relationship > extractMatchingRelationships (MapAccessor allValues , RelationshipDescription relationshipDescription , String typeOfRelationship ) {
571
+ private Collection <Relationship > extractMatchingRelationships (Collection < Relationship > relationshipsFromResult , RelationshipDescription relationshipDescription , String typeOfRelationship , Predicate < Relationship > relationshipPredicate ) {
565
572
566
- Collection <Relationship > allMatchingTypeRelationshipsInResult = new ArrayList <>();
567
573
Predicate <Relationship > onlyWithMatchingType = r -> r .type ().equals (typeOfRelationship ) || relationshipDescription .isDynamic ();
574
+ return relationshipsFromResult .stream ()
575
+ .filter (onlyWithMatchingType .and (relationshipPredicate ))
576
+ .collect (Collectors .toSet ());
577
+ }
578
+
579
+ private Collection <Relationship > extractRelationships (MapAccessor allValues ) {
580
+ Collection <Relationship > allRelationshipsInResult = new ArrayList <>();
568
581
StreamSupport .stream (allValues .values ().spliterator (), false )
569
582
.filter (MappingSupport .isListContainingOnly (listType , this .relationshipType ))
570
583
.flatMap (entry -> MappingSupport .extractRelationships (listType , entry ).stream ())
571
- .filter (onlyWithMatchingType )
572
- .forEach (allMatchingTypeRelationshipsInResult ::add );
584
+ .forEach (allRelationshipsInResult ::add );
573
585
574
- if (allMatchingTypeRelationshipsInResult .isEmpty ()) {
586
+ if (allRelationshipsInResult .isEmpty ()) {
575
587
StreamSupport .stream (allValues .values ().spliterator (), false )
576
588
.filter (this .relationshipType ::isTypeOf )
577
589
.map (Value ::asRelationship )
578
- .filter (onlyWithMatchingType )
579
- .forEach (allMatchingTypeRelationshipsInResult ::add );
590
+ .forEach (allRelationshipsInResult ::add );
580
591
}
581
592
582
- return allMatchingTypeRelationshipsInResult ;
593
+ return allRelationshipsInResult ;
583
594
}
584
595
585
596
private static Value extractValueOf (Neo4jPersistentProperty property , MapAccessor propertyContainer ) {
0 commit comments