Skip to content

Commit 1ae61c9

Browse files
committed
Merge pull request #614 from ParsePlatform/nlutsenko.beforeSave.dirty
Fix dirtyKeys() and dirty(key:) on beforeSave when updating objects.
2 parents 63a7e85 + 24a25d1 commit 1ae61c9

File tree

3 files changed

+158
-104
lines changed

3 files changed

+158
-104
lines changed

spec/ParseAPI.spec.js

Lines changed: 147 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// A bunch of different tests are in here - it isn't very thematic.
22
// It would probably be better to refactor them into different files.
3+
'use strict';
34

45
var DatabaseAdapter = require('../src/DatabaseAdapter');
56
var request = require('request');
@@ -138,7 +139,7 @@ describe('miscellaneous', function() {
138139
return new Parse.Query(TestObject).find();
139140
}).then((results) => {
140141
expect(results.length).toEqual(100);
141-
done();
142+
done();
142143
}, (error) => {
143144
fail(error);
144145
done();
@@ -280,7 +281,7 @@ describe('miscellaneous', function() {
280281
// We should have been able to fetch the object again
281282
fail(error);
282283
});
283-
})
284+
});
284285

285286
it('basic beforeDelete rejection via promise', function(done) {
286287
var obj = new Parse.Object('BeforeDeleteFailWithPromise');
@@ -383,49 +384,154 @@ describe('miscellaneous', function() {
383384
});
384385
});
385386

386-
it('test beforeSave get full object on create and update', function(done) {
387-
var triggerTime = 0;
388-
// Register a mock beforeSave hook
389-
Parse.Cloud.beforeSave('GameScore', function(req, res) {
390-
var object = req.object;
391-
expect(object instanceof Parse.Object).toBeTruthy();
392-
expect(object.get('fooAgain')).toEqual('barAgain');
393-
if (triggerTime == 0) {
394-
// Create
395-
expect(object.get('foo')).toEqual('bar');
396-
// No objectId/createdAt/updatedAt
397-
expect(object.id).toBeUndefined();
398-
expect(object.createdAt).toBeUndefined();
399-
expect(object.updatedAt).toBeUndefined();
400-
} else if (triggerTime == 1) {
401-
// Update
402-
expect(object.get('foo')).toEqual('baz');
403-
expect(object.id).not.toBeUndefined();
404-
expect(object.createdAt).not.toBeUndefined();
405-
expect(object.updatedAt).not.toBeUndefined();
406-
} else {
407-
res.error();
408-
}
409-
triggerTime++;
410-
res.success();
387+
describe('beforeSave', () => {
388+
beforeEach(done => {
389+
// Make sure the required mock for all tests is unset.
390+
delete Parse.Cloud.Triggers.beforeSave.GameScore;
391+
done();
411392
});
412393

413-
var obj = new Parse.Object('GameScore');
414-
obj.set('foo', 'bar');
415-
obj.set('fooAgain', 'barAgain');
416-
obj.save().then(function() {
417-
// We only update foo
418-
obj.set('foo', 'baz');
419-
return obj.save();
420-
}).then(function() {
421-
// Make sure the checking has been triggered
422-
expect(triggerTime).toBe(2);
423-
// Clear mock beforeSave
394+
afterEach(done => {
395+
// Make sure the required mock for all tests is unset.
424396
delete Parse.Cloud.Triggers.beforeSave.GameScore;
425397
done();
426-
}, function(error) {
427-
fail(error);
428-
done();
398+
});
399+
400+
it('object is set on create and update', done => {
401+
let triggerTime = 0;
402+
// Register a mock beforeSave hook
403+
Parse.Cloud.beforeSave('GameScore', (req, res) => {
404+
let object = req.object;
405+
expect(object instanceof Parse.Object).toBeTruthy();
406+
expect(object.get('fooAgain')).toEqual('barAgain');
407+
if (triggerTime == 0) {
408+
// Create
409+
expect(object.get('foo')).toEqual('bar');
410+
// No objectId/createdAt/updatedAt
411+
expect(object.id).toBeUndefined();
412+
expect(object.createdAt).toBeUndefined();
413+
expect(object.updatedAt).toBeUndefined();
414+
} else if (triggerTime == 1) {
415+
// Update
416+
expect(object.get('foo')).toEqual('baz');
417+
expect(object.id).not.toBeUndefined();
418+
expect(object.createdAt).not.toBeUndefined();
419+
expect(object.updatedAt).not.toBeUndefined();
420+
} else {
421+
res.error();
422+
}
423+
triggerTime++;
424+
res.success();
425+
});
426+
427+
let obj = new Parse.Object('GameScore');
428+
obj.set('foo', 'bar');
429+
obj.set('fooAgain', 'barAgain');
430+
obj.save().then(() => {
431+
// We only update foo
432+
obj.set('foo', 'baz');
433+
return obj.save();
434+
}).then(() => {
435+
// Make sure the checking has been triggered
436+
expect(triggerTime).toBe(2);
437+
done();
438+
}, error => {
439+
fail(error);
440+
done();
441+
});
442+
});
443+
444+
it('dirtyKeys are set on update', done => {
445+
let triggerTime = 0;
446+
// Register a mock beforeSave hook
447+
Parse.Cloud.beforeSave('GameScore', (req, res) => {
448+
var object = req.object;
449+
expect(object instanceof Parse.Object).toBeTruthy();
450+
expect(object.get('fooAgain')).toEqual('barAgain');
451+
if (triggerTime == 0) {
452+
// Create
453+
expect(object.get('foo')).toEqual('bar');
454+
} else if (triggerTime == 1) {
455+
// Update
456+
expect(object.dirtyKeys()).toEqual(['foo']);
457+
expect(object.dirty('foo')).toBeTruthy();
458+
expect(object.get('foo')).toEqual('baz');
459+
} else {
460+
res.error();
461+
}
462+
triggerTime++;
463+
res.success();
464+
});
465+
466+
let obj = new Parse.Object('GameScore');
467+
obj.set('foo', 'bar');
468+
obj.set('fooAgain', 'barAgain');
469+
obj.save().then(() => {
470+
// We only update foo
471+
obj.set('foo', 'baz');
472+
return obj.save();
473+
}).then(() => {
474+
// Make sure the checking has been triggered
475+
expect(triggerTime).toBe(2);
476+
done();
477+
}, function(error) {
478+
fail(error);
479+
done();
480+
});
481+
});
482+
483+
it('original object is set on update', done => {
484+
let triggerTime = 0;
485+
// Register a mock beforeSave hook
486+
Parse.Cloud.beforeSave('GameScore', (req, res) => {
487+
let object = req.object;
488+
expect(object instanceof Parse.Object).toBeTruthy();
489+
expect(object.get('fooAgain')).toEqual('barAgain');
490+
let originalObject = req.original;
491+
if (triggerTime == 0) {
492+
// No id/createdAt/updatedAt
493+
expect(object.id).toBeUndefined();
494+
expect(object.createdAt).toBeUndefined();
495+
expect(object.updatedAt).toBeUndefined();
496+
// Create
497+
expect(object.get('foo')).toEqual('bar');
498+
// Check the originalObject is undefined
499+
expect(originalObject).toBeUndefined();
500+
} else if (triggerTime == 1) {
501+
// Update
502+
expect(object.id).not.toBeUndefined();
503+
expect(object.createdAt).not.toBeUndefined();
504+
expect(object.updatedAt).not.toBeUndefined();
505+
expect(object.get('foo')).toEqual('baz');
506+
// Check the originalObject
507+
expect(originalObject instanceof Parse.Object).toBeTruthy();
508+
expect(originalObject.get('fooAgain')).toEqual('barAgain');
509+
expect(originalObject.id).not.toBeUndefined();
510+
expect(originalObject.createdAt).not.toBeUndefined();
511+
expect(originalObject.updatedAt).not.toBeUndefined();
512+
expect(originalObject.get('foo')).toEqual('bar');
513+
} else {
514+
res.error();
515+
}
516+
triggerTime++;
517+
res.success();
518+
});
519+
520+
let obj = new Parse.Object('GameScore');
521+
obj.set('foo', 'bar');
522+
obj.set('fooAgain', 'barAgain');
523+
obj.save().then(() => {
524+
// We only update foo
525+
obj.set('foo', 'baz');
526+
return obj.save();
527+
}).then(() => {
528+
// Make sure the checking has been triggered
529+
expect(triggerTime).toBe(2);
530+
done();
531+
}, error => {
532+
fail(error);
533+
done();
534+
});
429535
});
430536
});
431537

@@ -471,62 +577,6 @@ describe('miscellaneous', function() {
471577
});
472578
});
473579

474-
it('test beforeSave get original object on update', function(done) {
475-
var triggerTime = 0;
476-
// Register a mock beforeSave hook
477-
Parse.Cloud.beforeSave('GameScore', function(req, res) {
478-
var object = req.object;
479-
expect(object instanceof Parse.Object).toBeTruthy();
480-
expect(object.get('fooAgain')).toEqual('barAgain');
481-
var originalObject = req.original;
482-
if (triggerTime == 0) {
483-
// No id/createdAt/updatedAt
484-
expect(object.id).toBeUndefined();
485-
expect(object.createdAt).toBeUndefined();
486-
expect(object.updatedAt).toBeUndefined();
487-
// Create
488-
expect(object.get('foo')).toEqual('bar');
489-
// Check the originalObject is undefined
490-
expect(originalObject).toBeUndefined();
491-
} else if (triggerTime == 1) {
492-
// Update
493-
expect(object.id).not.toBeUndefined();
494-
expect(object.createdAt).not.toBeUndefined();
495-
expect(object.updatedAt).not.toBeUndefined();
496-
expect(object.get('foo')).toEqual('baz');
497-
// Check the originalObject
498-
expect(originalObject instanceof Parse.Object).toBeTruthy();
499-
expect(originalObject.get('fooAgain')).toEqual('barAgain');
500-
expect(originalObject.id).not.toBeUndefined();
501-
expect(originalObject.createdAt).not.toBeUndefined();
502-
expect(originalObject.updatedAt).not.toBeUndefined();
503-
expect(originalObject.get('foo')).toEqual('bar');
504-
} else {
505-
res.error();
506-
}
507-
triggerTime++;
508-
res.success();
509-
});
510-
511-
var obj = new Parse.Object('GameScore');
512-
obj.set('foo', 'bar');
513-
obj.set('fooAgain', 'barAgain');
514-
obj.save().then(function() {
515-
// We only update foo
516-
obj.set('foo', 'baz');
517-
return obj.save();
518-
}).then(function() {
519-
// Make sure the checking has been triggered
520-
expect(triggerTime).toBe(2);
521-
// Clear mock beforeSave
522-
delete Parse.Cloud.Triggers.beforeSave.GameScore;
523-
done();
524-
}, function(error) {
525-
fail(error);
526-
done();
527-
});
528-
});
529-
530580
it('test afterSave get original object on update', function(done) {
531581
var triggerTime = 0;
532582
// Register a mock beforeSave hook

spec/helper.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ var DatabaseAdapter = require('../src/DatabaseAdapter');
77
var express = require('express');
88
var facebook = require('../src/oauth/facebook');
99
var ParseServer = require('../src/index').ParseServer;
10-
var DatabaseAdapter = require('../src/DatabaseAdapter');
1110

1211
var databaseURI = process.env.DATABASE_URI;
1312
var cloudMain = process.env.CLOUD_CODE_MAIN || '../spec/cloud/main.js';

src/RestWrite.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,23 @@ RestWrite.prototype.runBeforeTrigger = function() {
116116
if (this.query && this.query.objectId) {
117117
extraData.objectId = this.query.objectId;
118118
}
119-
// Build the inflated object, for a create write, originalData is empty
120-
var inflatedObject = triggers.inflate(extraData, this.originalData);;
121-
inflatedObject._finishFetch(this.data);
122-
// Build the original object, we only do this for a update write
123-
var originalObject;
119+
120+
let originalObject = null;
121+
let updatedObject = null;
124122
if (this.query && this.query.objectId) {
123+
// This is an update for existing object.
125124
originalObject = triggers.inflate(extraData, this.originalData);
125+
updatedObject = triggers.inflate(extraData, this.originalData);
126+
updatedObject.set(Parse._decode(undefined, this.data));
127+
} else {
128+
// This is create of an object, so no original object exists.
129+
// TODO: (nlutsenko) Use the same flow as for creation, when _Session triggers support is removed.
130+
updatedObject = triggers.inflate(extraData, this.data);
126131
}
127132

128133
return Promise.resolve().then(() => {
129134
return triggers.maybeRunTrigger(
130-
'beforeSave', this.auth, inflatedObject, originalObject);
135+
'beforeSave', this.auth, updatedObject, originalObject);
131136
}).then((response) => {
132137
if (response && response.object) {
133138
this.data = response.object;

0 commit comments

Comments
 (0)