diff --git a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Settings.java b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Settings.java index 0ff51a61497..12f4acb1a4a 100644 --- a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Settings.java +++ b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Settings.java @@ -70,4 +70,6 @@ public interface Settings { */ String SETTING_DB_CREATE = SETTING_DATASOURCE + ".dbCreate"; + String SETTING_AUTO_TIMESTAMP_INSERT_OVERWRITE = PREFIX + '.' + "events.autoTimestampInsertOverwrite"; + } diff --git a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/CustomAutoTimestampSpec.groovy b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/CustomAutoTimestampSpec.groovy index ce6f8f6e28d..0aa41abb3ed 100644 --- a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/CustomAutoTimestampSpec.groovy +++ b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/CustomAutoTimestampSpec.groovy @@ -1,6 +1,8 @@ package org.grails.datastore.gorm import grails.gorm.annotation.AutoTimestamp +import org.grails.datastore.gorm.events.AutoTimestampEventListener + import static grails.gorm.annotation.AutoTimestamp.EventType.*; import grails.gorm.tests.GormDatastoreSpec import grails.persistence.Entity @@ -30,6 +32,65 @@ class CustomAutoTimestampSpec extends GormDatastoreSpec { r.modified != null && previousModified < r.modified previousCreated == r.created } + + void "Test when the auto timestamp properties are already set, they are overwritten"() { + when:"An entity is persisted" + def r = new RecordCustom(name: "Test") + def now = new Date() + r.created = new Date() + r.modified = r.created + r.save(flush:true, failOnError:true) + session.clear() + r = RecordCustom.get(r.id) + + then:"the custom lastUpdated and dateCreated are set" + now < r.modified + now < r.created + + when:"An entity is modified" + Date previousCreated = r.created + Date previousModified = r.modified + r.name = "Test 2" + r.save(flush:true) + session.clear() + r = RecordCustom.get(r.id) + + then:"the custom lastUpdated property is updated and dateCreated is not" + r.modified != null && previousModified < r.modified + previousCreated == r.created + } + + void "Test when the auto timestamp properties are already set, they are not overwritten if config is set"() { + when:"An entity is persisted and insertOverwrite is false" + AutoTimestampEventListener autoTimestampEventListener = + RecordCustom.gormPersistentEntity.mappingContext.eventListeners.find { it.class == AutoTimestampEventListener} + autoTimestampEventListener.insertOverwrite = false + + def r = new RecordCustom(name: "Test") + def now = new Date() + r.created = new Date() + r.modified = r.created + r.save(flush:true, failOnError:true) + session.clear() + r = RecordCustom.get(r.id) + + then:"the custom lastUpdated and dateCreated are not overwritten" + now == r.modified + now == r.created + + when:"An entity is modified" + Date previousCreated = r.created + Date previousModified = r.modified + r.name = "Test 2" + r.save(flush:true) + session.clear() + r = RecordCustom.get(r.id) + + then:"the custom lastUpdated property is updated and dateCreated is not" + r.modified != null && previousModified < r.modified + previousCreated == r.created + } + @Override List getDomainClasses() { [RecordCustom] diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/events/AutoTimestampEventListener.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/events/AutoTimestampEventListener.java index d48e7be4d19..0aea81358d7 100644 --- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/events/AutoTimestampEventListener.java +++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/events/AutoTimestampEventListener.java @@ -23,6 +23,7 @@ import org.grails.datastore.gorm.timestamp.DefaultTimestampProvider; import org.grails.datastore.gorm.timestamp.TimestampProvider; import org.grails.datastore.mapping.config.Entity; +import org.grails.datastore.mapping.config.Settings; import org.grails.datastore.mapping.core.Datastore; import org.grails.datastore.mapping.engine.EntityAccess; import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent; @@ -34,6 +35,7 @@ import org.grails.datastore.mapping.model.MappingContext; import org.grails.datastore.mapping.model.PersistentEntity; import org.grails.datastore.mapping.model.PersistentProperty; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEvent; /** @@ -44,6 +46,10 @@ */ public class AutoTimestampEventListener extends AbstractPersistenceEventListener implements MappingContext.Listener { + // if false, will not set timestamp on insert event if value is not null + @Value("${" + Settings.SETTING_AUTO_TIMESTAMP_INSERT_OVERWRITE + ":true}") + boolean insertOverwrite = true; + public static final String DATE_CREATED_PROPERTY = "dateCreated"; public static final String LAST_UPDATED_PROPERTY = "lastUpdated"; @@ -98,19 +104,23 @@ public boolean beforeInsert(PersistentEntity entity, EntityAccess ea) { Set props = getDateCreatedPropertyNames(name); if (props != null) { for (String prop : props) { - dateCreatedType = ea.getPropertyType(prop); - timestamp = timestampProvider.createTimestamp(dateCreatedType); - ea.setProperty(prop, timestamp); + if (insertOverwrite || ea.getPropertyValue(prop) == null) { + dateCreatedType = ea.getPropertyType(prop); + timestamp = timestampProvider.createTimestamp(dateCreatedType); + ea.setProperty(prop, timestamp); + } } } props = getLastUpdatedPropertyNames(name); if (props != null) { for (String prop : props) { - Class lastUpdateType = ea.getPropertyType(prop); - if (dateCreatedType == null || !lastUpdateType.isAssignableFrom(dateCreatedType)) { - timestamp = timestampProvider.createTimestamp(lastUpdateType); + if (insertOverwrite || ea.getPropertyValue(prop) == null) { + Class lastUpdateType = ea.getPropertyType(prop); + if (dateCreatedType == null || !lastUpdateType.isAssignableFrom(dateCreatedType)) { + timestamp = timestampProvider.createTimestamp(lastUpdateType); + } + ea.setProperty(prop, timestamp); } - ea.setProperty(prop, timestamp); } } return true;