Skip to content

Commit f4f75fd

Browse files
authored
Merge pull request #15143 from codeconsole/7.0.x-mongo-pre-update-snapshot
Take snapshot prior to mongo update then mark any changes during beforeUpdate and update events as dirty.
2 parents 4bfc369 + 4380949 commit f4f75fd

File tree

3 files changed

+27
-13
lines changed

3 files changed

+27
-13
lines changed

grails-data-mongodb/core/src/main/groovy/org/grails/datastore/mapping/mongo/engine/MongoCodecEntityPersister.groovy

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,26 @@ class MongoCodecEntityPersister extends ThirdPartyCacheEntityPersister<Object> {
240240
mongoCodecSession.addPendingUpdate(new PendingUpdateAdapter(entity, id, obj, entityAccess) {
241241
@Override
242242
void run() {
243+
// Take snapshot of all property values BEFORE the PreUpdate event fires
244+
Map<String, Object> beforeUpdateSnapshot = [:]
245+
if (obj instanceof DirtyCheckable) {
246+
for (PersistentProperty prop : entity.persistentProperties) {
247+
beforeUpdateSnapshot[prop.name] = entityAccess.getProperty(prop.name)
248+
}
249+
}
243250
if (!cancelUpdate(entity, entityAccess)) {
251+
// Compare with snapshot and mark modified properties dirty
252+
if (obj instanceof DirtyCheckable) {
253+
DirtyCheckable dirtyCheckable = (DirtyCheckable) obj
254+
for (PersistentProperty prop : entity.persistentProperties) {
255+
Object oldValue = beforeUpdateSnapshot[prop.name]
256+
Object newValue = entityAccess.getProperty(prop.name)
257+
boolean valueChanged = oldValue != newValue && (oldValue == null || !oldValue.equals(newValue))
258+
if (valueChanged) {
259+
dirtyCheckable.markDirty(prop.name, newValue, oldValue)
260+
}
261+
}
262+
}
244263
updateCaches(entity, obj, id)
245264
addCascadeOperation(new PendingOperationAdapter(entity, id, obj) {
246265
@Override

grails-data-mongodb/core/src/main/groovy/org/grails/datastore/mapping/mongo/engine/codecs/PersistentEntityCodec.groovy

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ import org.grails.datastore.mapping.engine.internal.MappingUtils
6464
import org.grails.datastore.mapping.model.EmbeddedPersistentEntity
6565
import org.grails.datastore.mapping.model.PersistentEntity
6666
import org.grails.datastore.mapping.model.PersistentProperty
67-
import org.grails.datastore.mapping.model.config.GormProperties
6867
import org.grails.datastore.mapping.model.types.Association
6968
import org.grails.datastore.mapping.model.types.Embedded
7069
import org.grails.datastore.mapping.model.types.EmbeddedCollection
@@ -249,12 +248,6 @@ class PersistentEntityCodec extends BsonPersistentEntityCodec {
249248
}
250249

251250
}
252-
else {
253-
// schedule lastUpdated if necessary
254-
if (entity.getPropertyByName(GormProperties.LAST_UPDATED) != null) {
255-
dirtyProperties.add(GormProperties.LAST_UPDATED)
256-
}
257-
}
258251

259252
for (propertyName in dirtyProperties) {
260253
def prop = entity.getPropertyByName(propertyName)

grails-data-mongodb/core/src/test/groovy/org/grails/datastore/gorm/mongo/BeforeUpdatePropertyPersistenceSpec.groovy

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
*/
1919
package org.grails.datastore.gorm.mongo
2020

21-
import spock.lang.PendingFeature
22-
21+
import grails.gorm.annotation.AutoTimestamp
2322
import grails.persistence.Entity
2423
import org.apache.grails.data.mongo.core.GrailsDataMongoTckManager
2524
import org.apache.grails.data.testing.tck.base.GrailsDataTckSpec
@@ -37,7 +36,7 @@ class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMo
3736
manager.domainClasses.addAll([UserWithBeforeUpdate, UserWithBeforeUpdateAndAutoTimestamp])
3837
}
3938

40-
@PendingFeature
39+
@Issue('GRAILS-15139')
4140
void "Test that properties set in beforeUpdate are persisted"() {
4241
given: "A user is created"
4342
def user = new UserWithBeforeUpdate(name: "Fred")
@@ -92,7 +91,6 @@ class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMo
9291
user.random.length() == 5
9392
}
9493

95-
@PendingFeature
9694
void "Test that multiple updates continue to trigger beforeUpdate"() {
9795
given: "A user is created"
9896
def user = new UserWithBeforeUpdate(name: "Fred")
@@ -119,8 +117,7 @@ class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMo
119117
user.random.length() == 5
120118
}
121119

122-
@PendingFeature
123-
@Issue('GPMONGODB-XXX')
120+
@Issue('GRAILS-15120')
124121
void "Test that properties set in beforeUpdate with AutoTimestamp are persisted"() {
125122
given: "A user with auto timestamp is created"
126123
def user = new UserWithBeforeUpdateAndAutoTimestamp(name: "Fred")
@@ -136,11 +133,13 @@ class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMo
136133
user.random == "Not Updated"
137134
user.dateCreated != null
138135
user.lastUpdated != null
136+
user.modified != null
139137

140138
when: "The user's name is updated"
141139
sleep 100 // ensure lastUpdated differs
142140
def previousRandom = user.random
143141
def previousLastUpdated = user.lastUpdated
142+
def previousModified = user.modified
144143
user.name = "Bob"
145144
user.save(flush: true)
146145
manager.session.clear()
@@ -153,6 +152,7 @@ class BeforeUpdatePropertyPersistenceSpec extends GrailsDataTckSpec<GrailsDataMo
153152
user.random != "Not Updated"
154153
user.random.length() == 5
155154
user.lastUpdated > previousLastUpdated
155+
user.modified > previousModified
156156
}
157157
}
158158

@@ -184,9 +184,11 @@ class UserWithBeforeUpdateAndAutoTimestamp {
184184
String random
185185
Date dateCreated
186186
Date lastUpdated
187+
@AutoTimestamp Date modified
187188

188189
static constraints = {
189190
random nullable: true
191+
modified nullable: true
190192
}
191193

192194
def beforeInsert() {

0 commit comments

Comments
 (0)