3030import java .util .function .Function ;
3131import java .util .function .Predicate ;
3232import java .util .function .Supplier ;
33+ import java .util .stream .Collectors ;
3334import java .util .stream .StreamSupport ;
3435
3536import org .neo4j .driver .Value ;
@@ -105,7 +106,7 @@ public <R> R read(Class<R> targetType, MapAccessor mapAccessor) {
105106 }
106107
107108 try {
108- return map (queryRoot , queryRoot , rootNodeDescription , new HashSet <>() );
109+ return map (queryRoot , queryRoot , rootNodeDescription );
109110 } catch (Exception e ) {
110111 throw new MappingException ("Error mapping " + mapAccessor .toString (), e );
111112 }
@@ -241,11 +242,13 @@ private static MapAccessor mergeRootNodeWithRecord(Node node, MapAccessor record
241242 * @return The mapped entity
242243 */
243244 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 );
245248 }
246249
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 ) {
249252
250253 // if the given result does not contain an identifier to the mapped object cannot get temporarily saved
251254 Long internalId = getInternalId (queryResult );
@@ -258,13 +261,8 @@ private <ET> ET map(MapAccessor queryResult, MapAccessor allValues, Neo4jPersist
258261 Neo4jPersistentEntity <ET > concreteNodeDescription = (Neo4jPersistentEntity <ET >) nodeDescriptionAndLabels
259262 .getNodeDescription ();
260263
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 );
268266
269267 PersistentPropertyAccessor <ET > propertyAccessor = concreteNodeDescription .getPropertyAccessor (instance );
270268
@@ -283,7 +281,7 @@ private <ET> ET map(MapAccessor queryResult, MapAccessor allValues, Neo4jPersist
283281 knownObjects .storeObject (internalId , instance );
284282 // Fill associations
285283 concreteNodeDescription .doWithAssociations (
286- populateFrom (queryResult , allValues , propertyAccessor , isConstructorParameter ));
284+ populateFrom (queryResult , propertyAccessor , isConstructorParameter , relationshipsFromResult , nodesFromResult ));
287285 }
288286 ET bean = propertyAccessor .getBean ();
289287
@@ -357,9 +355,9 @@ private boolean containsOnePlainNode(MapAccessor queryResult) {
357355 .filter (value -> value .hasType (nodeType )).count () == 1L ;
358356 }
359357
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 ) {
363361
364362 ParameterValueProvider <Neo4jPersistentProperty > parameterValueProvider = new ParameterValueProvider <Neo4jPersistentProperty >() {
365363 @ Override
@@ -373,7 +371,7 @@ public Object getParameterValue(PreferredConstructor.Parameter parameter) {
373371 String propertyFieldName = matchingProperty .getFieldName ();
374372 return r .getFieldName ().equals (propertyFieldName );
375373 }).findFirst ().get ();
376- return createInstanceOfRelationships (matchingProperty , values , allValues , relationshipDescription ).orElse (null );
374+ return createInstanceOfRelationships (matchingProperty , values , relationshipDescription , relationshipsFromResult , nodesFromResult ).orElse (null );
377375 } else if (matchingProperty .isDynamicLabels ()) {
378376 return createDynamicLabelsProperty (matchingProperty .getTypeInformation (), surplusLabels );
379377 } else if (matchingProperty .isEntityWithRelationshipProperties ()) {
@@ -408,22 +406,22 @@ private PropertyHandler<Neo4jPersistentProperty> populateFrom(MapAccessor queryR
408406 };
409407 }
410408
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 ) {
413411 return association -> {
414412
415413 Neo4jPersistentProperty persistentProperty = association .getInverse ();
416414 if (isConstructorParameter .test (persistentProperty )) {
417415 return ;
418416 }
419417
420- createInstanceOfRelationships (persistentProperty , queryResult , allValues , (RelationshipDescription ) association )
418+ createInstanceOfRelationships (persistentProperty , queryResult , (RelationshipDescription ) association , relationshipsFromResult , nodesFromResult )
421419 .ifPresent (value -> propertyAccessor .setProperty (persistentProperty , value ));
422420 };
423421 }
424422
425423 private Optional <Object > createInstanceOfRelationships (Neo4jPersistentProperty persistentProperty , MapAccessor values ,
426- MapAccessor allValues , RelationshipDescription relationshipDescription ) {
424+ RelationshipDescription relationshipDescription , Collection < Relationship > relationshipsFromResult , Collection < Node > nodesFromResult ) {
427425
428426 String typeOfRelationship = relationshipDescription .getType ();
429427 String sourceLabel = relationshipDescription .getSource ().getPrimaryLabel ();
@@ -464,30 +462,35 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
464462 List <Object > relationshipsAndProperties = new ArrayList <>();
465463
466464 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 ));
467474
468- // Retrieve all relationships from the result's list(s)
469- Collection <Relationship > allMatchingTypeRelationshipsInResult = extractMatchingRelationships (allValues , relationshipDescription , typeOfRelationship );
470475 // Retrieve all nodes from the result's list(s)
471- Collection <Node > allNodesWithMatchingLabelInResult = extractMatchingNodes (allValues , targetLabel );
476+ Collection <Node > allNodesWithMatchingLabelInResult = extractMatchingNodes (nodesFromResult , targetLabel );
472477
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 );
476478 for (Node possibleValueNode : allNodesWithMatchingLabelInResult ) {
477479 long targetNodeId = possibleValueNode .id ();
480+
481+ Neo4jPersistentEntity <?> concreteTargetNodeDescription =
482+ getMostConcreteTargetNodeDescription (genericTargetNodeDescription , possibleValueNode );
483+
478484 Set <Relationship > relationshipsProcessed = new HashSet <>();
479485 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 ) {
484487
485- Object mappedObject = map (possibleValueNode , allValues , concreteTargetNodeDescription );
488+ Object mappedObject = map (possibleValueNode , concreteTargetNodeDescription , null , relationshipsFromResult , nodesFromResult );
486489 if (relationshipDescription .hasRelationshipProperties ()) {
487490
488- Object relationshipProperties = map (possibleRelationship , allValues ,
491+ Object relationshipProperties = map (possibleRelationship ,
489492 (Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
490- mappedObject );
493+ mappedObject , relationshipsFromResult , nodesFromResult );
491494 relationshipsAndProperties .add (relationshipProperties );
492495 mappedObjectHandler .accept (possibleRelationship .type (), relationshipProperties );
493496 } else {
@@ -504,17 +507,17 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
504507 Neo4jPersistentEntity <?> concreteTargetNodeDescription =
505508 getMostConcreteTargetNodeDescription (genericTargetNodeDescription , relatedEntity );
506509
507- Object valueEntry = map (relatedEntity , allValues , concreteTargetNodeDescription );
510+ Object valueEntry = map (relatedEntity , concreteTargetNodeDescription , null , relationshipsFromResult , nodesFromResult );
508511
509512 if (relationshipDescription .hasRelationshipProperties ()) {
510513 String relationshipSymbolicName = sourceLabel
511514 + RelationshipDescription .NAME_OF_RELATIONSHIP + targetLabel ;
512515 Relationship relatedEntityRelationship = relatedEntity .get (relationshipSymbolicName )
513516 .asRelationship ();
514517
515- Object relationshipProperties = map (relatedEntityRelationship , allValues ,
518+ Object relationshipProperties = map (relatedEntityRelationship ,
516519 (Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
517- valueEntry );
520+ valueEntry , relationshipsFromResult , nodesFromResult );
518521 relationshipsAndProperties .add (relationshipProperties );
519522 mappedObjectHandler .accept (relatedEntity .get (RelationshipDescription .NAME_OF_RELATIONSHIP_TYPE ).asString (), relationshipProperties );
520523 } else {
@@ -540,46 +543,54 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
540543 }
541544 }
542545
543- private Collection <Node > extractMatchingNodes (MapAccessor allValues , String targetLabel ) {
546+ private Collection <Node > extractMatchingNodes (Collection < Node > allNodesInResult , String targetLabel ) {
544547
545- Collection <Node > allNodesWithMatchingLabelInResult = new ArrayList <>();
546548 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 <>();
547556 StreamSupport .stream (allValues .values ().spliterator (), false )
548557 .filter (MappingSupport .isListContainingOnly (listType , this .nodeType ))
549558 .flatMap (entry -> MappingSupport .extractNodes (listType , entry ).stream ())
550- .filter (onlyWithMatchingLabels )
551- .forEach (allNodesWithMatchingLabelInResult ::add );
559+ .forEach (allNodesInResult ::add );
552560
553- if (allNodesWithMatchingLabelInResult .isEmpty ()) {
561+ if (allNodesInResult .isEmpty ()) {
554562 StreamSupport .stream (allValues .values ().spliterator (), false )
555563 .filter (this .nodeType ::isTypeOf )
556564 .map (Value ::asNode )
557- .filter (onlyWithMatchingLabels )
558- .forEach (allNodesWithMatchingLabelInResult ::add );
565+ .forEach (allNodesInResult ::add );
559566 }
560567
561- return allNodesWithMatchingLabelInResult ;
568+ return allNodesInResult ;
562569 }
563570
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 ) {
565572
566- Collection <Relationship > allMatchingTypeRelationshipsInResult = new ArrayList <>();
567573 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 <>();
568581 StreamSupport .stream (allValues .values ().spliterator (), false )
569582 .filter (MappingSupport .isListContainingOnly (listType , this .relationshipType ))
570583 .flatMap (entry -> MappingSupport .extractRelationships (listType , entry ).stream ())
571- .filter (onlyWithMatchingType )
572- .forEach (allMatchingTypeRelationshipsInResult ::add );
584+ .forEach (allRelationshipsInResult ::add );
573585
574- if (allMatchingTypeRelationshipsInResult .isEmpty ()) {
586+ if (allRelationshipsInResult .isEmpty ()) {
575587 StreamSupport .stream (allValues .values ().spliterator (), false )
576588 .filter (this .relationshipType ::isTypeOf )
577589 .map (Value ::asRelationship )
578- .filter (onlyWithMatchingType )
579- .forEach (allMatchingTypeRelationshipsInResult ::add );
590+ .forEach (allRelationshipsInResult ::add );
580591 }
581592
582- return allMatchingTypeRelationshipsInResult ;
593+ return allRelationshipsInResult ;
583594 }
584595
585596 private static Value extractValueOf (Neo4jPersistentProperty property , MapAccessor propertyContainer ) {
0 commit comments