|
36 | 36 | import org.springframework.data.domain.Sort; |
37 | 37 | import org.springframework.data.mapping.MappingException; |
38 | 38 | import org.springframework.data.mapping.PersistentProperty; |
39 | | -import org.springframework.data.neo4j.core.schema.Relationship.Direction; |
40 | 39 | import org.springframework.lang.NonNull; |
41 | 40 | import org.springframework.lang.Nullable; |
42 | 41 | import org.springframework.util.Assert; |
43 | 42 |
|
44 | 43 | import java.util.ArrayList; |
45 | 44 | import java.util.Arrays; |
46 | 45 | import java.util.Collection; |
47 | | -import java.util.HashSet; |
48 | 46 | import java.util.List; |
49 | | -import java.util.Set; |
50 | 47 | import java.util.function.Predicate; |
51 | 48 | import java.util.function.UnaryOperator; |
52 | | -import java.util.stream.Collectors; |
53 | 49 |
|
54 | 50 | import static org.neo4j.cypherdsl.core.Cypher.anyNode; |
55 | 51 | import static org.neo4j.cypherdsl.core.Cypher.listBasedOn; |
@@ -506,183 +502,13 @@ private MapProjection projectPropertiesAndRelationships(NodeDescription<?> nodeD |
506 | 502 | List<Object> propertiesProjection = projectNodeProperties(nodeDescription, nodeName, includedProperties); |
507 | 503 | List<Object> contentOfProjection = new ArrayList<>(propertiesProjection); |
508 | 504 |
|
509 | | - Collection<RelationshipDescription> relationships = getRelationshipDescriptionsUpAndDown(nodeDescription, includedProperties); |
| 505 | + Collection<RelationshipDescription> relationships = nodeDescription.getRelationshipsInHierarchy(includedProperties); |
510 | 506 | relationships.removeIf(r -> !includedProperties.test(r.getFieldName())); |
511 | 507 |
|
512 | 508 | contentOfProjection.addAll(generateListsFor(relationships, nodeName, processedRelationships)); |
513 | 509 | return Cypher.anyNode(nodeName).project(contentOfProjection); |
514 | 510 | } |
515 | 511 |
|
516 | | - @NonNull |
517 | | - static Collection<RelationshipDescription> getRelationshipDescriptionsUpAndDown(NodeDescription<?> nodeDescription, |
518 | | - Predicate<String> includedProperties) { |
519 | | - |
520 | | - Collection<RelationshipDescription> relationships = new HashSet<>(nodeDescription.getRelationships()); |
521 | | - for (NodeDescription<?> childDescription : nodeDescription.getChildNodeDescriptionsInHierarchy()) { |
522 | | - childDescription.getRelationships().forEach(concreteRelationship -> { |
523 | | - |
524 | | - String fieldName = concreteRelationship.getFieldName(); |
525 | | - |
526 | | - if (relationships.stream().noneMatch(relationship -> relationship.getFieldName().equals(fieldName))) { |
527 | | - relationships.add(concreteRelationship); |
528 | | - } |
529 | | - }); |
530 | | - } |
531 | | - |
532 | | - return relationships.stream().filter(relationshipDescription -> |
533 | | - includedProperties.test(relationshipDescription.getFieldName())) |
534 | | - .collect(Collectors.toSet()); |
535 | | - } |
536 | | - |
537 | | - private RelationshipPattern createRelationships(Node node, Collection<RelationshipDescription> relationshipDescriptions) { |
538 | | - RelationshipPattern relationship; |
539 | | - |
540 | | - Direction determinedDirection = determineDirection(relationshipDescriptions); |
541 | | - if (Direction.OUTGOING.equals(determinedDirection)) { |
542 | | - relationship = node.relationshipTo(anyNode(), collectFirstLevelRelationshipTypes(relationshipDescriptions)) |
543 | | - .min(0).max(1); |
544 | | - } else if (Direction.INCOMING.equals(determinedDirection)) { |
545 | | - relationship = node.relationshipFrom(anyNode(), collectFirstLevelRelationshipTypes(relationshipDescriptions)) |
546 | | - .min(0).max(1); |
547 | | - } else { |
548 | | - relationship = node.relationshipBetween(anyNode(), collectFirstLevelRelationshipTypes(relationshipDescriptions)) |
549 | | - .min(0).max(1); |
550 | | - } |
551 | | - |
552 | | - Set<RelationshipDescription> processedRelationshipDescriptions = new HashSet<>(relationshipDescriptions); |
553 | | - for (RelationshipDescription relationshipDescription : relationshipDescriptions) { |
554 | | - Collection<RelationshipDescription> relationships = relationshipDescription.getTarget().getRelationships(); |
555 | | - if (relationships.size() > 0) { |
556 | | - relationship = createRelationships(relationship, relationships, processedRelationshipDescriptions) |
557 | | - .relationship; |
558 | | - } |
559 | | - } |
560 | | - |
561 | | - return relationship; |
562 | | - } |
563 | | - |
564 | | - private RelationshipProcessState createRelationships(RelationshipPattern existingRelationship, |
565 | | - Collection<RelationshipDescription> relationshipDescriptions, |
566 | | - Set<RelationshipDescription> processedRelationshipDescriptions) { |
567 | | - |
568 | | - RelationshipPattern relationship = existingRelationship; |
569 | | - String[] relationshipTypes = collectAllRelationshipTypes(relationshipDescriptions); |
570 | | - if (processedRelationshipDescriptions.containsAll(relationshipDescriptions)) { |
571 | | - return new RelationshipProcessState( |
572 | | - relationship.relationshipBetween(anyNode(), |
573 | | - relationshipTypes).unbounded().min(0), true); |
574 | | - } |
575 | | - processedRelationshipDescriptions.addAll(relationshipDescriptions); |
576 | | - |
577 | | - // we can process through the path |
578 | | - if (relationshipDescriptions.size() == 1) { |
579 | | - RelationshipDescription relationshipDescription = relationshipDescriptions.iterator().next(); |
580 | | - switch (relationshipDescription.getDirection()) { |
581 | | - case OUTGOING: |
582 | | - relationship = existingRelationship.relationshipTo(anyNode(), |
583 | | - collectFirstLevelRelationshipTypes(relationshipDescriptions)).unbounded().min(0).max(1); |
584 | | - break; |
585 | | - case INCOMING: |
586 | | - relationship = existingRelationship.relationshipFrom(anyNode(), |
587 | | - collectFirstLevelRelationshipTypes(relationshipDescriptions)).unbounded().min(0).max(1); |
588 | | - break; |
589 | | - default: |
590 | | - relationship = existingRelationship.relationshipBetween(anyNode(), |
591 | | - collectFirstLevelRelationshipTypes(relationshipDescriptions)).unbounded().min(0).max(1); |
592 | | - } |
593 | | - |
594 | | - RelationshipProcessState relationships = createRelationships(relationship, |
595 | | - relationshipDescription.getTarget().getRelationships(), processedRelationshipDescriptions); |
596 | | - |
597 | | - if (!relationships.done) { |
598 | | - relationship = relationships.relationship; |
599 | | - } |
600 | | - } else { |
601 | | - Direction determinedDirection = determineDirection(relationshipDescriptions); |
602 | | - if (Direction.OUTGOING.equals(determinedDirection)) { |
603 | | - relationship = existingRelationship.relationshipTo(anyNode(), relationshipTypes).unbounded().min(0); |
604 | | - } else if (Direction.INCOMING.equals(determinedDirection)) { |
605 | | - relationship = existingRelationship.relationshipFrom(anyNode(), relationshipTypes).unbounded().min(0); |
606 | | - } else { |
607 | | - relationship = existingRelationship.relationshipBetween(anyNode(), relationshipTypes).unbounded().min(0); |
608 | | - } |
609 | | - return new RelationshipProcessState(relationship, true); |
610 | | - } |
611 | | - return new RelationshipProcessState(relationship, false); |
612 | | - } |
613 | | - |
614 | | - @Nullable |
615 | | - Direction determineDirection(Collection<RelationshipDescription> relationshipDescriptions) { |
616 | | - |
617 | | - Direction direction = null; |
618 | | - for (RelationshipDescription relationshipDescription : relationshipDescriptions) { |
619 | | - if (direction == null) { |
620 | | - direction = relationshipDescription.getDirection(); |
621 | | - } |
622 | | - if (!direction.equals(relationshipDescription.getDirection())) { |
623 | | - return null; |
624 | | - } |
625 | | - } |
626 | | - return direction; |
627 | | - } |
628 | | - |
629 | | - private String[] collectFirstLevelRelationshipTypes(Collection<RelationshipDescription> relationshipDescriptions) { |
630 | | - Set<String> relationshipTypes = new HashSet<>(); |
631 | | - |
632 | | - for (RelationshipDescription relationshipDescription : relationshipDescriptions) { |
633 | | - String relationshipType = relationshipDescription.getType(); |
634 | | - if (relationshipTypes.contains(relationshipType)) { |
635 | | - continue; |
636 | | - } |
637 | | - if (relationshipDescription.isDynamic()) { |
638 | | - handleDynamicRelationship(relationshipTypes, (DefaultRelationshipDescription) relationshipDescription); |
639 | | - continue; |
640 | | - } |
641 | | - relationshipTypes.add(relationshipType); |
642 | | - } |
643 | | - return relationshipTypes.toArray(new String[0]); |
644 | | - } |
645 | | - |
646 | | - private String[] collectAllRelationshipTypes(Collection<RelationshipDescription> relationshipDescriptions) { |
647 | | - Set<String> relationshipTypes = new HashSet<>(); |
648 | | - |
649 | | - for (RelationshipDescription relationshipDescription : relationshipDescriptions) { |
650 | | - String relationshipType = relationshipDescription.getType(); |
651 | | - if (relationshipDescription.isDynamic()) { |
652 | | - handleDynamicRelationship(relationshipTypes, (DefaultRelationshipDescription) relationshipDescription); |
653 | | - continue; |
654 | | - } |
655 | | - relationshipTypes.add(relationshipType); |
656 | | - collectAllRelationshipTypes(relationshipDescription.getTarget(), relationshipTypes, new HashSet<>(relationshipDescriptions)); |
657 | | - } |
658 | | - return relationshipTypes.toArray(new String[0]); |
659 | | - } |
660 | | - |
661 | | - private void handleDynamicRelationship(Set<String> relationshipTypes, DefaultRelationshipDescription relationshipDescription) { |
662 | | - Class<?> componentType = relationshipDescription.getInverse().getComponentType(); |
663 | | - if (componentType != null && componentType.isEnum()) { |
664 | | - Arrays.stream(componentType.getEnumConstants()) |
665 | | - .forEach(constantName -> relationshipTypes.add(constantName.toString())); |
666 | | - } else { |
667 | | - relationshipTypes.clear(); |
668 | | - } |
669 | | - } |
670 | | - |
671 | | - private void collectAllRelationshipTypes(NodeDescription<?> nodeDescription, Set<String> relationshipTypes, |
672 | | - Collection<RelationshipDescription> processedRelationshipDescriptions) { |
673 | | - |
674 | | - for (RelationshipDescription relationshipDescription : nodeDescription.getRelationships()) { |
675 | | - String relationshipType = relationshipDescription.getType(); |
676 | | - if (processedRelationshipDescriptions.contains(relationshipDescription)) { |
677 | | - continue; |
678 | | - } |
679 | | - relationshipTypes.add(relationshipType); |
680 | | - processedRelationshipDescriptions.add(relationshipDescription); |
681 | | - collectAllRelationshipTypes(relationshipDescription.getTarget(), relationshipTypes, |
682 | | - processedRelationshipDescriptions); |
683 | | - } |
684 | | - } |
685 | | - |
686 | 512 | /** |
687 | 513 | * Creates a list of objects that represents a very basic of {@code MapEntry<String, Object>} with the exception that |
688 | 514 | * this list can also contain two "keys" in a row. The {@link MapProjection} will take care to handle them as |
|
0 commit comments