@@ -118,7 +118,7 @@ public <R> R read(Class<R> targetType, MapAccessor mapAccessor) {
118
118
if (queryRoot == null ) {
119
119
throw new MappingException (String .format ("Could not find mappable nodes or relationships inside %s for %s" , mapAccessor , rootNodeDescription ));
120
120
} else {
121
- return map (queryRoot , rootNodeDescription , new KnownObjects (), new HashSet <>());
121
+ return map (queryRoot , queryRoot , rootNodeDescription , new KnownObjects (), new HashSet <>());
122
122
}
123
123
} catch (Exception e ) {
124
124
throw new MappingException ("Error mapping " + mapAccessor .toString (), e );
@@ -195,33 +195,23 @@ private static MapAccessor mergeRootNodeWithRecord(Node node, MapAccessor record
195
195
}
196
196
197
197
/**
198
- * @param queryResult The original query result
198
+ * @param queryResult The original query result or a reduced form like a node or similar
199
+ * @param allValues The original query result
199
200
* @param nodeDescription The node description of the current entity to be mapped from the result
200
201
* @param knownObjects The current list of known objects
202
+ * @param processedSegments Path segments already processed in the mapping process. Only applies to path-based queries
201
203
* @param <ET> As in entity type
202
- * @return
204
+ * @return The mapped entity
203
205
*/
204
- private <ET > ET map (MapAccessor queryResult , Neo4jPersistentEntity <ET > nodeDescription , KnownObjects knownObjects , Set <Path .Segment > processedSegments ) {
205
- return map (queryResult , nodeDescription , knownObjects , null , processedSegments );
206
+ private <ET > ET map (MapAccessor queryResult , MapAccessor allValues , Neo4jPersistentEntity <ET > nodeDescription , KnownObjects knownObjects , Set <Path .Segment > processedSegments ) {
207
+ return map (queryResult , allValues , nodeDescription , knownObjects , null , processedSegments );
206
208
}
207
209
208
- /**
209
- * @param queryResult The original query result
210
- * @param nodeDescription The node description of the current entity to be mapped from the result
211
- * @param knownObjects The current list of known objects
212
- * @param lastMappedEntity Previous created entity for relationships, can be null.
213
- * @param <ET> As in entity type
214
- * @return
215
- */
216
- private <ET > ET map (MapAccessor queryResult , Neo4jPersistentEntity <ET > nodeDescription , KnownObjects knownObjects ,
210
+ private <ET > ET map (MapAccessor queryResult , MapAccessor allValues , Neo4jPersistentEntity <ET > nodeDescription , KnownObjects knownObjects ,
217
211
@ Nullable Object lastMappedEntity , Set <Path .Segment > processedSegments ) {
218
212
219
213
// if the given result does not contain an identifier to the mapped object cannot get temporarily saved
220
- Long internalId = queryResult .get (Constants .NAME_OF_INTERNAL_ID ).isNull ()
221
- ? null
222
- : queryResult instanceof Node
223
- ? ((Node ) queryResult ).id ()
224
- : queryResult .get (Constants .NAME_OF_INTERNAL_ID ).asLong ();
214
+ Long internalId = getInternalId (queryResult );
225
215
226
216
Supplier <Object > mappedObjectSupplier = () -> {
227
217
@@ -233,7 +223,7 @@ private <ET> ET map(MapAccessor queryResult, Neo4jPersistentEntity<ET> nodeDescr
233
223
234
224
Collection <RelationshipDescription > relationships = concreteNodeDescription .getRelationships ();
235
225
236
- ET instance = instantiate (concreteNodeDescription , queryResult , knownObjects , relationships ,
226
+ ET instance = instantiate (concreteNodeDescription , queryResult , allValues , knownObjects , relationships ,
237
227
nodeDescriptionAndLabels .getDynamicLabels (), lastMappedEntity , processedSegments );
238
228
239
229
PersistentPropertyAccessor <ET > propertyAccessor = concreteNodeDescription .getPropertyAccessor (instance );
@@ -253,7 +243,7 @@ private <ET> ET map(MapAccessor queryResult, Neo4jPersistentEntity<ET> nodeDescr
253
243
knownObjects .storeObject (internalId , instance );
254
244
// Fill associations
255
245
concreteNodeDescription .doWithAssociations (
256
- populateFrom (queryResult , propertyAccessor , isConstructorParameter , relationships , knownObjects , processedSegments ));
246
+ populateFrom (queryResult , allValues , propertyAccessor , isConstructorParameter , relationships , knownObjects , processedSegments ));
257
247
}
258
248
ET bean = propertyAccessor .getBean ();
259
249
@@ -270,6 +260,15 @@ private <ET> ET map(MapAccessor queryResult, Neo4jPersistentEntity<ET> nodeDescr
270
260
return (ET ) mappedObject ;
271
261
}
272
262
263
+ @ Nullable
264
+ private Long getInternalId (@ NonNull MapAccessor queryResult ) {
265
+ return queryResult instanceof Node
266
+ ? (Long ) ((Node ) queryResult ).id ()
267
+ : queryResult .get (Constants .NAME_OF_INTERNAL_ID ) == null || queryResult .get (Constants .NAME_OF_INTERNAL_ID ).isNull ()
268
+ ? null
269
+ : queryResult .get (Constants .NAME_OF_INTERNAL_ID ).asLong ();
270
+ }
271
+
273
272
/**
274
273
* Returns the list of labels for the entity to be created from the "main" node returned.
275
274
*
@@ -289,7 +288,7 @@ private List<String> getLabels(MapAccessor queryResult) {
289
288
return labels ;
290
289
}
291
290
292
- private <ET > ET instantiate (Neo4jPersistentEntity <ET > nodeDescription , MapAccessor values , KnownObjects knownObjects ,
291
+ private <ET > ET instantiate (Neo4jPersistentEntity <ET > nodeDescription , MapAccessor values , MapAccessor allValues , KnownObjects knownObjects ,
293
292
Collection <RelationshipDescription > relationships , Collection <String > surplusLabels , Object lastMappedEntity ,
294
293
Set <Path .Segment > processedSegments ) {
295
294
@@ -300,7 +299,7 @@ public Object getParameterValue(PreferredConstructor.Parameter parameter) {
300
299
Neo4jPersistentProperty matchingProperty = nodeDescription .getRequiredPersistentProperty (parameter .getName ());
301
300
302
301
if (matchingProperty .isRelationship ()) {
303
- return createInstanceOfRelationships (matchingProperty , values , knownObjects , relationships , processedSegments ).orElse (null );
302
+ return createInstanceOfRelationships (matchingProperty , values , allValues , knownObjects , relationships , processedSegments ).orElse (null );
304
303
} else if (matchingProperty .isDynamicLabels ()) {
305
304
return createDynamicLabelsProperty (matchingProperty .getTypeInformation (), surplusLabels );
306
305
} else if (matchingProperty .isEntityInRelationshipWithProperties ()) {
@@ -335,7 +334,7 @@ private PropertyHandler<Neo4jPersistentProperty> populateFrom(MapAccessor queryR
335
334
};
336
335
}
337
336
338
- private AssociationHandler <Neo4jPersistentProperty > populateFrom (MapAccessor queryResult ,
337
+ private AssociationHandler <Neo4jPersistentProperty > populateFrom (MapAccessor queryResult , MapAccessor allValues ,
339
338
PersistentPropertyAccessor <?> propertyAccessor , Predicate <Neo4jPersistentProperty > isConstructorParameter ,
340
339
Collection <RelationshipDescription > relationshipDescriptions , KnownObjects knownObjects , Set <Path .Segment > processedSegments ) {
341
340
return association -> {
@@ -345,13 +344,13 @@ private AssociationHandler<Neo4jPersistentProperty> populateFrom(MapAccessor que
345
344
return ;
346
345
}
347
346
348
- createInstanceOfRelationships (persistentProperty , queryResult , knownObjects , relationshipDescriptions , processedSegments )
347
+ createInstanceOfRelationships (persistentProperty , queryResult , allValues , knownObjects , relationshipDescriptions , processedSegments )
349
348
.ifPresent (value -> propertyAccessor .setProperty (persistentProperty , value ));
350
349
};
351
350
}
352
351
353
352
private Optional <Object > createInstanceOfRelationships (Neo4jPersistentProperty persistentProperty , MapAccessor values ,
354
- KnownObjects knownObjects , Collection <RelationshipDescription > relationshipDescriptions , Set <Path .Segment > processedSegments ) {
353
+ MapAccessor allValues , KnownObjects knownObjects , Collection <RelationshipDescription > relationshipDescriptions , Set <Path .Segment > processedSegments ) {
355
354
356
355
RelationshipDescription relationshipDescription = relationshipDescriptions .stream ()
357
356
.filter (r -> r .getFieldName ().equals (persistentProperty .getName ())).findFirst ().get ();
@@ -392,11 +391,11 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
392
391
mappedObjectHandler = (type , mappedObject ) -> value .add (mappedObject );
393
392
}
394
393
395
- Value list = values .get (relationshipDescription .generateRelatedNodesCollectionName ());
394
+ Value list = allValues .get (relationshipDescription .generateRelatedNodesCollectionName ());
396
395
397
396
List <Object > relationshipsAndProperties = new ArrayList <>();
398
397
399
- boolean isGeneratedPathBased = values .containsKey (Constants .NAME_OF_PATHS );
398
+ boolean isGeneratedPathBased = allValues .containsKey (Constants .NAME_OF_PATHS );
400
399
401
400
Predicate <Value > isList = entry -> typeSystem .LIST ().isTypeOf (entry );
402
401
@@ -426,11 +425,11 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
426
425
continue ;
427
426
}
428
427
processedSegments .add (segment );
429
- Object mappedObject = map (extractNextNodeAndAppendPath (segment .end (), allPaths ),
428
+ Object mappedObject = map (extractNextNodeAndAppendPath (segment .end (), allPaths ), allValues ,
430
429
concreteTargetNodeDescription , knownObjects , processedSegments );
431
430
if (relationshipDescription .hasRelationshipProperties ()) {
432
431
433
- Object relationshipProperties = map (segment .relationship (),
432
+ Object relationshipProperties = map (segment .relationship (), allValues ,
434
433
(Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
435
434
knownObjects , mappedObject , processedSegments );
436
435
relationshipsAndProperties .add (relationshipProperties );
@@ -449,11 +448,11 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
449
448
450
449
// find relationships in the result
451
450
List <Relationship > allMatchingTypeRelationshipsInResult = StreamSupport
452
- .stream (values .values ().spliterator (), false ).filter (isList .and (containsOnlyRelationships ))
451
+ .stream (allValues .values ().spliterator (), false ).filter (isList .and (containsOnlyRelationships ))
453
452
.flatMap (entry -> entry .asList (Value ::asRelationship ).stream ()).filter (r -> r .type ().equals (relationshipType ))
454
453
.collect (Collectors .toList ());
455
454
456
- List <Node > allNodesWithMatchingLabelInResult = StreamSupport .stream (values .values ().spliterator (), false )
455
+ List <Node > allNodesWithMatchingLabelInResult = StreamSupport .stream (allValues .values ().spliterator (), false )
457
456
.filter (isList .and (containsOnlyNodes )).flatMap (entry -> entry .asList (Value ::asNode ).stream ())
458
457
.filter (n -> n .hasLabel (targetLabel )).collect (Collectors .toList ());
459
458
@@ -462,16 +461,17 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
462
461
}
463
462
464
463
Function <Relationship , Long > targetIdSelector = relationshipDescription .isIncoming () ? Relationship ::startNodeId : Relationship ::endNodeId ;
465
-
464
+ Function <Relationship , Long > sourceIdSelector = relationshipDescription .isIncoming () ? Relationship ::endNodeId : Relationship ::startNodeId ;
465
+ Long sourceNodeId = getInternalId (values );
466
466
for (Node possibleValueNode : allNodesWithMatchingLabelInResult ) {
467
- long nodeId = possibleValueNode .id ();
467
+ long targetNodeId = possibleValueNode .id ();
468
468
469
469
for (Relationship possibleRelationship : allMatchingTypeRelationshipsInResult ) {
470
- if (targetIdSelector .apply (possibleRelationship ) == nodeId ) {
471
- Object mappedObject = map (possibleValueNode , concreteTargetNodeDescription , knownObjects , processedSegments );
470
+ if (targetIdSelector .apply (possibleRelationship ) == targetNodeId && sourceIdSelector . apply ( possibleRelationship ). equals ( sourceNodeId ) ) {
471
+ Object mappedObject = map (possibleValueNode , values , concreteTargetNodeDescription , knownObjects , processedSegments );
472
472
if (relationshipDescription .hasRelationshipProperties ()) {
473
473
474
- Object relationshipProperties = map (possibleRelationship ,
474
+ Object relationshipProperties = map (possibleRelationship , allValues ,
475
475
(Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
476
476
knownObjects , mappedObject , processedSegments );
477
477
relationshipsAndProperties .add (relationshipProperties );
@@ -487,13 +487,13 @@ private Optional<Object> createInstanceOfRelationships(Neo4jPersistentProperty p
487
487
} else {
488
488
for (Value relatedEntity : list .asList (Function .identity ())) {
489
489
490
- Object valueEntry = map (relatedEntity , concreteTargetNodeDescription , knownObjects , processedSegments );
490
+ Object valueEntry = map (relatedEntity , allValues , concreteTargetNodeDescription , knownObjects , processedSegments );
491
491
492
492
if (relationshipDescription .hasRelationshipProperties ()) {
493
493
Relationship relatedEntityRelationship = relatedEntity .get (RelationshipDescription .NAME_OF_RELATIONSHIP )
494
494
.asRelationship ();
495
495
496
- Object relationshipProperties = map (relatedEntityRelationship ,
496
+ Object relationshipProperties = map (relatedEntityRelationship , allValues ,
497
497
(Neo4jPersistentEntity ) relationshipDescription .getRelationshipPropertiesEntity (),
498
498
knownObjects , valueEntry , processedSegments );
499
499
relationshipsAndProperties .add (relationshipProperties );
0 commit comments