Skip to content

Commit 9f37723

Browse files
committed
fix: return correct response when revert is used in beforeSave (parse-community#7839)
1 parent a579eeb commit 9f37723

File tree

2 files changed

+9
-77
lines changed

2 files changed

+9
-77
lines changed

spec/CloudCode.spec.js

-42
Original file line numberDiff line numberDiff line change
@@ -1652,22 +1652,6 @@ describe('Cloud Code', () => {
16521652
expect(obj.get('foo')).toBe('bar');
16531653
});
16541654

1655-
it('create role with name and ACL and a beforeSave', async () => {
1656-
Parse.Cloud.beforeSave(Parse.Role, ({ object }) => {
1657-
return object;
1658-
});
1659-
1660-
const obj = new Parse.Role('TestRole', new Parse.ACL({ '*': { read: true, write: true } }));
1661-
await obj.save();
1662-
1663-
expect(obj.getACL()).toEqual(new Parse.ACL({ '*': { read: true, write: true } }));
1664-
expect(obj.get('name')).toEqual('TestRole');
1665-
await obj.fetch();
1666-
1667-
expect(obj.getACL()).toEqual(new Parse.ACL({ '*': { read: true, write: true } }));
1668-
expect(obj.get('name')).toEqual('TestRole');
1669-
});
1670-
16711655
it('can unset in afterSave', async () => {
16721656
Parse.Cloud.beforeSave('TestObject', ({ object }) => {
16731657
if (!object.existed()) {
@@ -1718,32 +1702,6 @@ describe('Cloud Code', () => {
17181702
expect(obj.get('count')).toBe(0);
17191703
});
17201704

1721-
it('pointer should not be cleared by triggers', async () => {
1722-
Parse.Cloud.afterSave('MyObject', () => {});
1723-
const foo = await new Parse.Object('Test', { foo: 'bar' }).save();
1724-
const obj = await new Parse.Object('MyObject', { foo }).save();
1725-
const foo2 = obj.get('foo');
1726-
expect(foo2.get('foo')).toBe('bar');
1727-
});
1728-
1729-
it('can set a pointer in triggers', async () => {
1730-
Parse.Cloud.beforeSave('MyObject', () => {});
1731-
Parse.Cloud.afterSave(
1732-
'MyObject',
1733-
async ({ object }) => {
1734-
const foo = await new Parse.Object('Test', { foo: 'bar' }).save();
1735-
object.set({ foo });
1736-
await object.save(null, { useMasterKey: true });
1737-
},
1738-
{
1739-
skipWithMasterKey: true,
1740-
}
1741-
);
1742-
const obj = await new Parse.Object('MyObject').save();
1743-
const foo2 = obj.get('foo');
1744-
expect(foo2.get('foo')).toBe('bar');
1745-
});
1746-
17471705
it('beforeSave should not sanitize database', async done => {
17481706
const { adapter } = Config.get(Parse.applicationId).database;
17491707
const spy = spyOn(adapter, 'findOneAndUpdate').and.callThrough();

src/RestWrite.js

+9-35
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,7 @@ function RestWrite(config, auth, className, query, data, originalData, clientSDK
8484
// Shared SchemaController to be reused to reduce the number of loadSchema() calls per request
8585
// Once set the schemaData should be immutable
8686
this.validSchemaController = null;
87-
this.pendingOps = {
88-
operations: null,
89-
identifier: null,
90-
};
87+
this.pendingOps = {};
9188
}
9289

9390
// A convenient method to perform all the steps of processing the
@@ -236,13 +233,10 @@ RestWrite.prototype.runBeforeSaveTrigger = function () {
236233
}
237234

238235
const { originalObject, updatedObject } = this.buildParseObjects();
239-
const identifier = updatedObject._getStateIdentifier();
236+
240237
const stateController = Parse.CoreManager.getObjectStateController();
241-
const [pending] = stateController.getPendingOps(identifier);
242-
this.pendingOps = {
243-
operations: { ...pending },
244-
identifier,
245-
};
238+
const [pending] = stateController.getPendingOps(updatedObject._getStateIdentifier());
239+
this.pendingOps = { ...pending };
246240

247241
return Promise.resolve()
248242
.then(() => {
@@ -1674,11 +1668,11 @@ RestWrite.prototype.runAfterSaveTrigger = function () {
16741668
.then(result => {
16751669
const jsonReturned = result && !result._toFullJSON;
16761670
if (jsonReturned) {
1677-
this.pendingOps.operations = {};
1671+
this.pendingOps = {};
16781672
this.response.response = result;
16791673
} else {
16801674
this.response.response = this._updateResponseWithData(
1681-
(result || updatedObject).toJSON(),
1675+
(result || updatedObject)._toFullJSON(),
16821676
this.data
16831677
);
16841678
}
@@ -1778,35 +1772,15 @@ RestWrite.prototype.cleanUserAuthData = function () {
17781772
};
17791773

17801774
RestWrite.prototype._updateResponseWithData = function (response, data) {
1775+
const { updatedObject } = this.buildParseObjects();
17811776
const stateController = Parse.CoreManager.getObjectStateController();
1782-
const [pending] = stateController.getPendingOps(this.pendingOps.identifier);
1783-
for (const key in this.pendingOps.operations) {
1777+
const [pending] = stateController.getPendingOps(updatedObject._getStateIdentifier());
1778+
for (const key in this.pendingOps) {
17841779
if (!pending[key]) {
17851780
data[key] = this.originalData ? this.originalData[key] : { __op: 'Delete' };
17861781
this.storage.fieldsChangedByTrigger.push(key);
17871782
}
17881783
}
1789-
const skipKeys = [...(requiredColumns.read[this.className] || [])];
1790-
if (!this.query) {
1791-
skipKeys.push('objectId', 'createdAt');
1792-
} else {
1793-
skipKeys.push('updatedAt');
1794-
delete response.objectId;
1795-
}
1796-
for (const key in response) {
1797-
if (skipKeys.includes(key)) {
1798-
continue;
1799-
}
1800-
const value = response[key];
1801-
if (
1802-
value == null ||
1803-
(value.__type && value.__type === 'Pointer') ||
1804-
util.isDeepStrictEqual(data[key], value) ||
1805-
util.isDeepStrictEqual((this.originalData || {})[key], value)
1806-
) {
1807-
delete response[key];
1808-
}
1809-
}
18101784
if (_.isEmpty(this.storage.fieldsChangedByTrigger)) {
18111785
return response;
18121786
}

0 commit comments

Comments
 (0)