Skip to content

Commit cfe7c8d

Browse files
committed
User-defined update thingy (WIP name)
Signed-off-by: Gerrit Meier <[email protected]>
1 parent 65b7bc4 commit cfe7c8d

File tree

10 files changed

+598
-5
lines changed

10 files changed

+598
-5
lines changed

src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@
8787
import org.springframework.data.neo4j.core.mapping.SpringDataCypherDsl;
8888
import org.springframework.data.neo4j.core.mapping.callback.EventSupport;
8989
import org.springframework.data.neo4j.core.schema.TargetNode;
90+
import org.springframework.data.neo4j.core.support.UserDefinedChangeEvaluator;
91+
import org.springframework.data.neo4j.core.support.UserDefinedChangeSupport;
9092
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
9193
import org.springframework.data.neo4j.repository.NoResultException;
9294
import org.springframework.data.neo4j.repository.query.QueryFragments;
@@ -156,6 +158,7 @@ public boolean isReadOnly() {
156158

157159
@Nullable
158160
private TransactionTemplate transactionTemplateReadOnly;
161+
private final Map<Class, UserDefinedChangeEvaluator> userDefinedChangeEvaluators = new HashMap<>();
159162

160163
public Neo4jTemplate(Neo4jClient neo4jClient) {
161164
this(neo4jClient, new Neo4jMappingContext());
@@ -452,7 +455,9 @@ public <T> T save(T instance) {
452455
private <T> T saveImpl(T instance, @Nullable Collection<PropertyFilter.ProjectedPath> includedProperties,
453456
@Nullable NestedRelationshipProcessingStateMachine stateMachine) {
454457

455-
if (stateMachine != null && stateMachine.hasProcessedValue(instance)) {
458+
if ((stateMachine != null && stateMachine.hasProcessedValue(instance))
459+
|| (instance instanceof UserDefinedChangeSupport udcs && !udcs.needsUpdate())
460+
|| (this.userDefinedChangeEvaluators.containsKey(instance.getClass()) && !this.userDefinedChangeEvaluators.get(instance.getClass()).needsUpdate(instance))) {
456461
return instance;
457462
}
458463

@@ -977,11 +982,26 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
977982
.identifyAndExtractRelationshipTargetNode(relatedValueToStore);
978983
Neo4jPersistentEntity<?> targetEntity = this.neo4jMappingContext
979984
.getRequiredPersistentEntity(relatedObjectBeforeCallbacksApplied.getClass());
980-
boolean isNewEntity = targetEntity.isNew(relatedObjectBeforeCallbacksApplied);
985+
var isNewEntity = targetEntity.isNew(relatedObjectBeforeCallbacksApplied);
986+
var skipUpdateOfEntity = false;
987+
if (relatedValueToStore instanceof UserDefinedChangeSupport udcs) {
988+
skipUpdateOfEntity = !isNewEntity && !udcs.needsUpdate();
989+
}
990+
if (relatedValueToStore instanceof MappingSupport.RelationshipPropertiesWithEntityHolder rpweh) {
991+
var relatedEntity = rpweh.getRelatedEntity();
992+
if (relatedEntity instanceof UserDefinedChangeSupport udcs) {
993+
skipUpdateOfEntity = !isNewEntity && !udcs.needsUpdate();
994+
}
995+
}
996+
else if (!skipUpdateOfEntity) {
997+
skipUpdateOfEntity = this.userDefinedChangeEvaluators.containsKey(relatedValueToStore.getClass());
998+
}
981999

9821000
Object newRelatedObject = stateMachine.hasProcessedValue(relatedObjectBeforeCallbacksApplied)
9831001
? stateMachine.getProcessedAs(relatedObjectBeforeCallbacksApplied)
984-
: this.eventSupport.maybeCallBeforeBind(relatedObjectBeforeCallbacksApplied);
1002+
: skipUpdateOfEntity
1003+
? relatedObjectBeforeCallbacksApplied
1004+
: this.eventSupport.maybeCallBeforeBind(relatedObjectBeforeCallbacksApplied);
9851005

9861006
Object relatedInternalId;
9871007
Entity savedEntity = null;
@@ -990,7 +1010,7 @@ private <T> T processNestedRelations(Neo4jPersistentEntity<?> sourceEntity,
9901010
relatedInternalId = stateMachine.getObjectId(relatedValueToStore);
9911011
}
9921012
else {
993-
if (isNewEntity || relationshipDescription.cascadeUpdates()) {
1013+
if ((isNewEntity || relationshipDescription.cascadeUpdates()) && !skipUpdateOfEntity) {
9941014
savedEntity = saveRelatedNode(newRelatedObject, targetEntity, includeProperty,
9951015
currentPropertyPath);
9961016
}
@@ -1101,7 +1121,9 @@ else if (relationshipDescription.hasRelationshipProperties() && fromId != null)
11011121
else {
11021122
if (isNewRelationship && idProperty != null) {
11031123
newRelationshipPropertiesRows.add(properties);
1104-
newRelationshipPropertiesToStore.add(relatedValueToStore);
1124+
if (!skipUpdateOfEntity) {
1125+
newRelationshipPropertiesToStore.add(relatedValueToStore);
1126+
}
11051127
}
11061128
else {
11071129
this.neo4jMappingContext.getEntityConverter()
@@ -1325,6 +1347,8 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
13251347
}
13261348
}
13271349
setTransactionManager(transactionManager);
1350+
this.userDefinedChangeEvaluators.putAll(beanFactory.getBeanProvider(UserDefinedChangeEvaluator.class).stream()
1351+
.collect(Collectors.toMap(e -> e.getEvaluatingClass(), e -> e)));
13281352
}
13291353

13301354
// only used for the CDI configuration
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.springframework.data.neo4j.core.support;
2+
3+
/**
4+
* Interface to attach to a {@link org.springframework.data.neo4j.core.schema.Node}
5+
* to indicate if an entity needs to be processed by built-in update procedures.
6+
* @param <T> type to implement the UserDefinedChangeEvaluator for
7+
* @author Gerrit Meier
8+
*/
9+
public interface UserDefinedChangeEvaluator<T> {
10+
/**
11+
* Report if this entity needs to be considered for an update.
12+
* This includes possible relationships.
13+
* @param instance instance of type `T` to check
14+
* @return true, if it should be processed
15+
*/
16+
default boolean needsUpdate(T instance) {
17+
return true;
18+
}
19+
20+
Class<T> getEvaluatingClass();
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.springframework.data.neo4j.core.support;
2+
3+
/**
4+
* Interface to attach to a {@link org.springframework.data.neo4j.core.schema.Node}
5+
* to indicate if an entity needs to be processed by built-in update procedures.
6+
* @author Gerrit Meier
7+
*/
8+
public interface UserDefinedChangeSupport {
9+
/**
10+
* Report if this entity needs to be considered for an update.
11+
* This includes possible relationships.
12+
* @return true, if it should be processed
13+
*/
14+
boolean needsUpdate();
15+
}

0 commit comments

Comments
 (0)