Skip to content

Commit 3a96140

Browse files
committed
Fix issue with pointers getting un-hydrated when there is a beforeSave (#1884)
* Add failing test and simplify RestWrite * simplify and add test stubs * Fix issue
1 parent 614e1ac commit 3a96140

File tree

2 files changed

+59
-30
lines changed

2 files changed

+59
-30
lines changed

spec/CloudCode.spec.js

+32
Original file line numberDiff line numberDiff line change
@@ -557,4 +557,36 @@ describe('Cloud Code', () => {
557557
});
558558
});
559559
});
560+
561+
it('trivial beforeSave should not affect fetched pointers (regression test for #1238)', done => {
562+
Parse.Cloud.beforeSave('BeforeSaveUnchanged', (req, res) => {
563+
res.success();
564+
});
565+
566+
var TestObject = Parse.Object.extend("TestObject");
567+
var NoBeforeSaveObject = Parse.Object.extend("NoBeforeSave");
568+
var BeforeSaveObject = Parse.Object.extend("BeforeSaveUnchanged");
569+
570+
var aTestObject = new TestObject();
571+
aTestObject.set("foo", "bar");
572+
aTestObject.save()
573+
.then(aTestObject => {
574+
var aNoBeforeSaveObj = new NoBeforeSaveObject();
575+
aNoBeforeSaveObj.set("aTestObject", aTestObject);
576+
expect(aNoBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
577+
return aNoBeforeSaveObj.save();
578+
})
579+
.then(aNoBeforeSaveObj => {
580+
expect(aNoBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
581+
582+
var aBeforeSaveObj = new BeforeSaveObject();
583+
aBeforeSaveObj.set("aTestObject", aTestObject);
584+
expect(aBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
585+
return aBeforeSaveObj.save();
586+
})
587+
.then(aBeforeSaveObj => {
588+
expect(aBeforeSaveObj.get("aTestObject").get("foo")).toEqual("bar");
589+
done();
590+
});
591+
});
560592
});

src/RestWrite.js

+27-30
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var passwordCrypto = require('./password');
1212
var Parse = require('parse/node');
1313
var triggers = require('./triggers');
1414
import RestQuery from './RestQuery';
15+
import _ from 'lodash';
1516

1617
// query and data are both provided in REST API format. So data
1718
// types are encoded by plain old objects.
@@ -165,8 +166,10 @@ RestWrite.prototype.runBeforeTrigger = function() {
165166
return triggers.maybeRunTrigger(triggers.Types.beforeSave, this.auth, updatedObject, originalObject, this.config);
166167
}).then((response) => {
167168
if (response && response.object) {
169+
if (!_.isEqual(this.data, response.object)) {
170+
this.storage.changedByTrigger = true;
171+
}
168172
this.data = response.object;
169-
this.storage['changedByTrigger'] = true;
170173
// We should delete the objectId for an update write
171174
if (this.query && this.query.objectId) {
172175
delete this.data.objectId
@@ -733,19 +736,16 @@ RestWrite.prototype.runDatabaseOperation = function() {
733736
this.data.ACL[this.query.objectId] = { read: true, write: true };
734737
}
735738
// Run an update
736-
return this.config.database.update(
737-
this.className, this.query, this.data, this.runOptions).then((resp) => {
738-
resp.updatedAt = this.updatedAt;
739-
if (this.storage['changedByTrigger']) {
740-
resp = Object.keys(this.data).reduce((memo, key) => {
741-
memo[key] = resp[key] || this.data[key];
742-
return memo;
743-
}, resp);
744-
}
745-
this.response = {
746-
response: resp
747-
};
748-
});
739+
return this.config.database.update(this.className, this.query, this.data, this.runOptions)
740+
.then(response => {
741+
response.updatedAt = this.updatedAt;
742+
if (this.storage.changedByTrigger) {
743+
Object.keys(this.data).forEach(fieldName => {
744+
response[fieldName] = response[fieldName] || this.data[fieldName];
745+
});
746+
}
747+
this.response = { response };
748+
});
749749
} else {
750750
// Set the default ACL for the new _User
751751
if (this.className === '_User') {
@@ -762,23 +762,20 @@ RestWrite.prototype.runDatabaseOperation = function() {
762762

763763
// Run a create
764764
return this.config.database.create(this.className, this.data, this.runOptions)
765-
.then((resp) => {
766-
Object.assign(resp, {
767-
objectId: this.data.objectId,
768-
createdAt: this.data.createdAt
765+
.then(response => {
766+
response.objectId = this.data.objectId;
767+
response.createdAt = this.data.createdAt;
768+
if (this.storage.changedByTrigger) {
769+
Object.keys(this.data).forEach(fieldName => {
770+
response[fieldName] = response[fieldName] || this.data[fieldName];
769771
});
770-
if (this.storage['changedByTrigger']) {
771-
resp = Object.keys(this.data).reduce((memo, key) => {
772-
memo[key] = resp[key] || this.data[key];
773-
return memo;
774-
}, resp);
775-
}
776-
this.response = {
777-
status: 201,
778-
response: resp,
779-
location: this.location()
780-
};
781-
});
772+
}
773+
this.response = {
774+
status: 201,
775+
response,
776+
location: this.location()
777+
};
778+
});
782779
}
783780
};
784781

0 commit comments

Comments
 (0)