36
36
import java .util .List ;
37
37
import java .util .Map ;
38
38
import java .util .Objects ;
39
+ import java .util .Optional ;
39
40
import java .util .Set ;
40
41
import java .util .concurrent .ConcurrentHashMap ;
41
42
import java .util .concurrent .atomic .AtomicReference ;
@@ -446,10 +447,11 @@ private <T> Mono<T> saveImpl(T instance, @Nullable Collection<PropertyFilter.Pro
446
447
447
448
PersistentPropertyAccessor <T > propertyAccessor = entityMetaData .getPropertyAccessor (entityToBeSaved );
448
449
return idMono .doOnNext (newOrUpdatedNode -> {
449
- IdentitySupport .updateInternalId (entityMetaData , propertyAccessor , newOrUpdatedNode );
450
+ var elementId = IdentitySupport .getElementId (newOrUpdatedNode );
451
+ TemplateSupport .setGeneratedIdIfNecessary (entityMetaData , propertyAccessor , elementId , Optional .of (newOrUpdatedNode ));
450
452
TemplateSupport .updateVersionPropertyIfPossible (entityMetaData , propertyAccessor , newOrUpdatedNode );
451
- finalStateMachine .markValueAsProcessed (instance , IdentitySupport . getInternalId ( newOrUpdatedNode ) );
452
- }).map (IdentitySupport ::getInternalId )
453
+ finalStateMachine .markEntityAsProcessed (instance , elementId );
454
+ }).map (IdentitySupport ::getElementId )
453
455
.flatMap (internalId -> processRelations (entityMetaData , propertyAccessor , isNewEntity , finalStateMachine , binderFunction .filter ));
454
456
});
455
457
}
@@ -582,15 +584,15 @@ private <T> Flux<T> saveAllImpl(Iterable<T> instances, @Nullable Collection<Prop
582
584
.query (() -> renderer .render (cypherGenerator .prepareSaveOfMultipleInstancesOf (entityMetaData )))
583
585
.bind (boundedEntityList ).to (Constants .NAME_OF_ENTITY_LIST_PARAM )
584
586
.fetchAs (Tuple2 .class )
585
- .mappedBy ((t , r ) -> Tuples .of (r .get (Constants .NAME_OF_ID ), r .get (Constants .NAME_OF_INTERNAL_ID ). asLong ()))
587
+ .mappedBy ((t , r ) -> Tuples .of (r .get (Constants .NAME_OF_ID ), r .get (Constants .NAME_OF_ELEMENT_ID ). asString ()))
586
588
.all ()
587
- .collectMap (m -> (Value ) m .getT1 (), m -> (Long ) m .getT2 ());
589
+ .collectMap (m -> (Value ) m .getT1 (), m -> (String ) m .getT2 ());
588
590
}).flatMapMany (idToInternalIdMapping -> Flux .fromIterable (entitiesToBeSaved )
589
591
.flatMap (t -> {
590
592
PersistentPropertyAccessor <T > propertyAccessor = entityMetaData .getPropertyAccessor (t .getT3 ());
591
593
Neo4jPersistentProperty idProperty = entityMetaData .getRequiredIdProperty ();
592
594
Object id = convertIdValues (idProperty , propertyAccessor .getProperty (idProperty ));
593
- Long internalId = idToInternalIdMapping .get (id );
595
+ String internalId = idToInternalIdMapping .get (id );
594
596
return processRelations (entityMetaData , propertyAccessor , t .getT2 (), new NestedRelationshipProcessingStateMachine (neo4jMappingContext , t .getT1 (), internalId ),
595
597
TemplateSupport .computeIncludePropertyPredicate (pps , entityMetaData ));
596
598
}))
@@ -709,9 +711,9 @@ private Mono<NodesAndRelationshipsByIdStatementProvider> createNodesAndRelations
709
711
return Mono .deferContextual (ctx -> {
710
712
Class <?> rootClass = entityMetaData .getUnderlyingClass ();
711
713
712
- Set <Long > rootNodeIds = ctx .get ("rootNodes" );
713
- Set <Long > processedRelationshipIds = ctx .get ("processedRelationships" );
714
- Set <Long > processedNodeIds = ctx .get ("processedNodes" );
714
+ Set <String > rootNodeIds = ctx .get ("rootNodes" );
715
+ Set <String > processedRelationshipIds = ctx .get ("processedRelationships" );
716
+ Set <String > processedNodeIds = ctx .get ("processedNodes" );
715
717
return Flux .fromIterable (entityMetaData .getRelationshipsInHierarchy (queryFragments ::includeField ))
716
718
.flatMap (relationshipDescription -> {
717
719
@@ -723,16 +725,19 @@ private Mono<NodesAndRelationshipsByIdStatementProvider> createNodesAndRelations
723
725
usedParameters .putAll (statement .getCatalog ().getParameters ());
724
726
return neo4jClient .query (renderer .render (statement ))
725
727
.bindAll (usedParameters )
726
- .fetchAs (TupleOfLongsHolder .class )
728
+ .fetchAs (Tuple2 .class )
727
729
.mappedBy ((t , r ) -> {
728
- Collection <Long > rootIds = r .get (Constants .NAME_OF_SYNTHESIZED_ROOT_NODE ).asList (Value ::asLong );
730
+ Collection <String > rootIds = r .get (Constants .NAME_OF_SYNTHESIZED_ROOT_NODE ).asList (Value ::asString );
729
731
rootNodeIds .addAll (rootIds );
730
- Collection <Long > newRelationshipIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATIONS ).asList (Value ::asLong );
731
- Collection <Long > newRelatedNodeIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATED_NODES ).asList (Value ::asLong );
732
- return TupleOfLongsHolder . with ( Tuples .of (newRelationshipIds , newRelatedNodeIds ) );
732
+ Collection <String > newRelationshipIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATIONS ).asList (Value ::asString );
733
+ Collection <String > newRelatedNodeIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATED_NODES ).asList (Value ::asString );
734
+ return Tuples .of (newRelationshipIds , newRelatedNodeIds );
733
735
})
734
736
.one ()
735
- .map (TupleOfLongsHolder ::get )
737
+ .map ((t ) -> {
738
+ //noinspection unchecked
739
+ return (Tuple2 <Collection <String >, Collection <String >>) t ;
740
+ })
736
741
.expand (iterateAndMapNextLevel (relationshipDescription , queryFragments , rootClass , PropertyPathWalkStep .empty ()));
737
742
})
738
743
.then (Mono .fromSupplier (() -> new NodesAndRelationshipsByIdStatementProvider (rootNodeIds , processedRelationshipIds , processedNodeIds , queryFragments )));
@@ -744,23 +749,7 @@ private Mono<NodesAndRelationshipsByIdStatementProvider> createNodesAndRelations
744
749
745
750
}
746
751
747
- static class TupleOfLongsHolder {
748
- private final Tuple2 <Collection <Long >, Collection <Long >> content ;
749
-
750
- static TupleOfLongsHolder with (Tuple2 <Collection <Long >, Collection <Long >> content ) {
751
- return new TupleOfLongsHolder (content );
752
- }
753
-
754
- private TupleOfLongsHolder (Tuple2 <Collection <Long >, Collection <Long >> content ) {
755
- this .content = content ;
756
- }
757
-
758
- Tuple2 <Collection <Long >, Collection <Long >> get () {
759
- return content ;
760
- }
761
- }
762
-
763
- private Flux <Tuple2 <Collection <Long >, Collection <Long >>> iterateNextLevel (Collection <Long > relatedNodeIds ,
752
+ private Flux <Tuple2 <Collection <String >, Collection <String >>> iterateNextLevel (Collection <String > relatedNodeIds ,
764
753
RelationshipDescription sourceRelationshipDescription , QueryFragments queryFragments ,
765
754
Class <?> rootClass , PropertyPathWalkStep currentPathStep ) {
766
755
@@ -786,43 +775,46 @@ private Flux<Tuple2<Collection<Long>, Collection<Long>>> iterateNextLevel(Collec
786
775
787
776
Statement statement = cypherGenerator
788
777
.prepareMatchOf (target , relDe , null ,
789
- Functions .id (node ).in (Cypher .parameter (Constants .NAME_OF_ID )))
778
+ Functions .elementId (node ).in (Cypher .parameter (Constants .NAME_OF_ID )))
790
779
.returning (cypherGenerator .createGenericReturnStatement ()).build ();
791
780
792
781
return neo4jClient .query (renderer .render (statement ))
793
782
.bindAll (Collections .singletonMap (Constants .NAME_OF_ID , relatedNodeIds ))
794
- .fetchAs (TupleOfLongsHolder .class )
783
+ .fetchAs (Tuple2 .class )
795
784
.mappedBy ((t , r ) -> {
796
- Collection <Long > newRelationshipIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATIONS ).asList (Value ::asLong );
797
- Collection <Long > newRelatedNodeIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATED_NODES ).asList (Value ::asLong );
785
+ Collection <String > newRelationshipIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATIONS ).asList (Value ::asString );
786
+ Collection <String > newRelatedNodeIds = r .get (Constants .NAME_OF_SYNTHESIZED_RELATED_NODES ).asList (Value ::asString );
798
787
799
- return TupleOfLongsHolder . with ( Tuples .of (newRelationshipIds , newRelatedNodeIds ) );
788
+ return Tuples .of (newRelationshipIds , newRelatedNodeIds );
800
789
})
801
790
.one ()
802
- .map (TupleOfLongsHolder ::get )
791
+ .map ((t ) -> {
792
+ //noinspection unchecked
793
+ return (Tuple2 <Collection <String >, Collection <String >>) t ;
794
+ })
803
795
.expand (object -> iterateAndMapNextLevel (relDe , queryFragments , rootClass , nextPathStep ).apply (object ));
804
796
});
805
797
806
798
}
807
799
808
800
@ NonNull
809
- private Function <Tuple2 <Collection <Long >, Collection <Long >>,
810
- Publisher <Tuple2 <Collection <Long >, Collection <Long >>>> iterateAndMapNextLevel (
801
+ private Function <Tuple2 <Collection <String >, Collection <String >>,
802
+ Publisher <Tuple2 <Collection <String >, Collection <String >>>> iterateAndMapNextLevel (
811
803
RelationshipDescription relationshipDescription , QueryFragments queryFragments , Class <?> rootClass , PropertyPathWalkStep currentPathStep ) {
812
804
813
805
return newRelationshipAndRelatedNodeIds ->
814
806
Flux .deferContextual (ctx -> {
815
- Set <Long > relationshipIds = ctx .get ("processedRelationships" );
816
- Set <Long > processedNodeIds = ctx .get ("processedNodes" );
807
+ Set <String > relationshipIds = ctx .get ("processedRelationships" );
808
+ Set <String > processedNodeIds = ctx .get ("processedNodes" );
817
809
818
- Collection <Long > newRelationshipIds = newRelationshipAndRelatedNodeIds .getT1 ();
819
- Set <Long > tmpProcessedRels = ConcurrentHashMap .newKeySet (newRelationshipIds .size ());
810
+ Collection <String > newRelationshipIds = newRelationshipAndRelatedNodeIds .getT1 ();
811
+ Set <String > tmpProcessedRels = ConcurrentHashMap .newKeySet (newRelationshipIds .size ());
820
812
tmpProcessedRels .addAll (newRelationshipIds );
821
813
tmpProcessedRels .removeAll (relationshipIds );
822
814
relationshipIds .addAll (newRelationshipIds );
823
815
824
- Collection <Long > newRelatedNodeIds = newRelationshipAndRelatedNodeIds .getT2 ();
825
- Set <Long > tmpProcessedNodes = ConcurrentHashMap .newKeySet (newRelatedNodeIds .size ());
816
+ Collection <String > newRelatedNodeIds = newRelationshipAndRelatedNodeIds .getT2 ();
817
+ Set <String > tmpProcessedNodes = ConcurrentHashMap .newKeySet (newRelatedNodeIds .size ());
826
818
tmpProcessedNodes .addAll (newRelatedNodeIds );
827
819
tmpProcessedNodes .removeAll (processedNodeIds );
828
820
processedNodeIds .addAll (newRelatedNodeIds );
@@ -904,14 +896,14 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
904
896
// This avoids the usage of cache but might have significant impact on overall performance
905
897
if (!isParentObjectNew && !stateMachine .hasProcessedRelationship (fromId , relationshipDescription )) {
906
898
907
- List <Long > knownRelationshipsIds = new ArrayList <>();
899
+ List <Object > knownRelationshipsIds = new ArrayList <>();
908
900
if (idProperty != null ) {
909
901
for (Object relatedValueToStore : relatedValuesToStore ) {
910
902
if (relatedValueToStore == null ) {
911
903
continue ;
912
904
}
913
905
914
- Long id = ( Long ) relationshipContext
906
+ Object id = relationshipContext
915
907
.getRelationshipPropertiesPropertyAccessor (relatedValueToStore )
916
908
.getProperty (idProperty );
917
909
if (id != null ) {
@@ -950,44 +942,38 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
950
942
.flatMap (newRelatedObject -> {
951
943
Neo4jPersistentEntity <?> targetEntity = neo4jMappingContext .getRequiredPersistentEntity (relatedObjectBeforeCallbacksApplied .getClass ());
952
944
953
- Mono <Tuple2 <AtomicReference <Long >, AtomicReference <Entity >>> queryOrSave ;
945
+ Mono <Tuple2 <AtomicReference <String >, AtomicReference <Entity >>> queryOrSave ;
954
946
if (stateMachine .hasProcessedValue (relatedValueToStore )) {
955
- AtomicReference <Long > relatedInternalId = new AtomicReference <>();
956
- Long possibleValue = stateMachine .getInternalId (relatedValueToStore );
947
+ AtomicReference <String > relatedInternalId = new AtomicReference <>();
948
+ String possibleValue = stateMachine .getObjectId (relatedValueToStore );
957
949
if (possibleValue != null ) {
958
950
relatedInternalId .set (possibleValue );
959
951
}
960
952
queryOrSave = Mono .just (Tuples .of (relatedInternalId , new AtomicReference <>()));
961
953
} else {
962
954
queryOrSave = saveRelatedNode (newRelatedObject , targetEntity , includeProperty , currentPropertyPath )
963
- .map (entity -> Tuples .of (new AtomicReference <>(IdentitySupport .getInternalId (entity )), new AtomicReference <>(entity )))
964
- .doOnNext (entity -> {
965
- stateMachine .markValueAsProcessed (relatedValueToStore , entity .getT1 ().get ());
955
+ .map (entity -> Tuples .of (new AtomicReference <>(IdentitySupport .getElementId (entity )), new AtomicReference <>(entity )))
956
+ .doOnNext (t -> {
957
+ var relatedInternalId = t .getT1 ().get ();
958
+ stateMachine .markEntityAsProcessed (relatedValueToStore , relatedInternalId );
966
959
if (relatedValueToStore instanceof MappingSupport .RelationshipPropertiesWithEntityHolder ) {
967
- Object value = ((MappingSupport .RelationshipPropertiesWithEntityHolder ) relatedValueToStore ).getRelatedEntity ();
968
- stateMachine .markValueAsProcessedAs ( value , entity . getT1 (). get () );
960
+ Object entity = ((MappingSupport .RelationshipPropertiesWithEntityHolder ) relatedValueToStore ).getRelatedEntity ();
961
+ stateMachine .markAsAliased ( entity , relatedInternalId );
969
962
}
970
963
});
971
964
}
972
965
return queryOrSave .flatMap (idAndEntity -> {
973
- Long relatedInternalId = idAndEntity .getT1 ().get ();
966
+ String relatedInternalId = idAndEntity .getT1 ().get ();
974
967
Entity savedEntity = idAndEntity .getT2 ().get ();
975
968
Neo4jPersistentProperty requiredIdProperty = targetEntity .getRequiredIdProperty ();
976
969
PersistentPropertyAccessor <?> targetPropertyAccessor = targetEntity .getPropertyAccessor (newRelatedObject );
977
- Object actualRelatedId = targetPropertyAccessor .getProperty (requiredIdProperty );
978
- // if an internal id is used this must be set to link this entity in the next iteration
979
- if (targetEntity .isUsingInternalIds ()) {
980
- if (relatedInternalId == null && actualRelatedId != null ) {
981
- relatedInternalId = (Long ) targetPropertyAccessor .getProperty (requiredIdProperty );
982
- } else if (actualRelatedId == null ) {
983
- targetPropertyAccessor .setProperty (requiredIdProperty , relatedInternalId );
984
- }
985
- }
970
+ Object possibleInternalLongId = targetPropertyAccessor .getProperty (requiredIdProperty );
971
+ relatedInternalId = TemplateSupport .retrieveOrSetRelatedId (targetEntity , targetPropertyAccessor , Optional .ofNullable (savedEntity ), relatedInternalId );
986
972
if (savedEntity != null ) {
987
973
TemplateSupport .updateVersionPropertyIfPossible (targetEntity , targetPropertyAccessor , savedEntity );
988
974
}
989
- stateMachine .markValueAsProcessedAs (relatedObjectBeforeCallbacksApplied , targetPropertyAccessor .getBean ());
990
- stateMachine .markRelationshipAsProcessed (actualRelatedId == null ? relatedInternalId : actualRelatedId ,
975
+ stateMachine .markAsAliased (relatedObjectBeforeCallbacksApplied , targetPropertyAccessor .getBean ());
976
+ stateMachine .markRelationshipAsProcessed (possibleInternalLongId == null ? relatedInternalId : possibleInternalLongId ,
991
977
relationshipDescription .getRelationshipObverse ());
992
978
993
979
Object idValue = idProperty != null
@@ -1016,8 +1002,8 @@ private <T> Mono<T> processNestedRelations(Neo4jPersistentEntity<?> sourceEntity
1016
1002
.bind (idValue ) //
1017
1003
.to (Constants .NAME_OF_KNOWN_RELATIONSHIP_PARAM ) //
1018
1004
.bindAll (statementHolder .getProperties ())
1019
- .fetchAs (Long .class )
1020
- .mappedBy (IdentitySupport :: getInternalId )
1005
+ .fetchAs (Object .class )
1006
+ .mappedBy (( t , r ) -> IdentitySupport . mapperForRelatedIdValues ( idProperty ). apply ( r ) )
1021
1007
.one ()
1022
1008
.flatMap (relationshipInternalId -> {
1023
1009
if (idProperty != null && isNewRelationship ) {
0 commit comments