Skip to content

Fix dirtyKeys() and dirty(key:) on beforeSave when updating objects. #614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 147 additions & 97 deletions spec/ParseAPI.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// A bunch of different tests are in here - it isn't very thematic.
// It would probably be better to refactor them into different files.
'use strict';

var DatabaseAdapter = require('../src/DatabaseAdapter');
var request = require('request');
Expand Down Expand Up @@ -138,7 +139,7 @@ describe('miscellaneous', function() {
return new Parse.Query(TestObject).find();
}).then((results) => {
expect(results.length).toEqual(100);
done();
done();
}, (error) => {
fail(error);
done();
Expand Down Expand Up @@ -280,7 +281,7 @@ describe('miscellaneous', function() {
// We should have been able to fetch the object again
fail(error);
});
})
});

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

it('test beforeSave get full object on create and update', function(done) {
var triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', function(req, res) {
var object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
if (triggerTime == 0) {
// Create
expect(object.get('foo')).toEqual('bar');
// No objectId/createdAt/updatedAt
expect(object.id).toBeUndefined();
expect(object.createdAt).toBeUndefined();
expect(object.updatedAt).toBeUndefined();
} else if (triggerTime == 1) {
// Update
expect(object.get('foo')).toEqual('baz');
expect(object.id).not.toBeUndefined();
expect(object.createdAt).not.toBeUndefined();
expect(object.updatedAt).not.toBeUndefined();
} else {
res.error();
}
triggerTime++;
res.success();
describe('beforeSave', () => {
beforeEach(done => {
// Make sure the required mock for all tests is unset.
delete Parse.Cloud.Triggers.beforeSave.GameScore;
done();
});

var obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(function() {
// We only update foo
obj.set('foo', 'baz');
return obj.save();
}).then(function() {
// Make sure the checking has been triggered
expect(triggerTime).toBe(2);
// Clear mock beforeSave
afterEach(done => {
// Make sure the required mock for all tests is unset.
delete Parse.Cloud.Triggers.beforeSave.GameScore;
done();
}, function(error) {
fail(error);
done();
});

it('object is set on create and update', done => {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
let object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
if (triggerTime == 0) {
// Create
expect(object.get('foo')).toEqual('bar');
// No objectId/createdAt/updatedAt
expect(object.id).toBeUndefined();
expect(object.createdAt).toBeUndefined();
expect(object.updatedAt).toBeUndefined();
} else if (triggerTime == 1) {
// Update
expect(object.get('foo')).toEqual('baz');
expect(object.id).not.toBeUndefined();
expect(object.createdAt).not.toBeUndefined();
expect(object.updatedAt).not.toBeUndefined();
} else {
res.error();
}
triggerTime++;
res.success();
});

let obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
// We only update foo
obj.set('foo', 'baz');
return obj.save();
}).then(() => {
// Make sure the checking has been triggered
expect(triggerTime).toBe(2);
done();
}, error => {
fail(error);
done();
});
});

it('dirtyKeys are set on update', done => {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
var object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
if (triggerTime == 0) {
// Create
expect(object.get('foo')).toEqual('bar');
} else if (triggerTime == 1) {
// Update
expect(object.dirtyKeys()).toEqual(['foo']);
expect(object.dirty('foo')).toBeTruthy();
expect(object.get('foo')).toEqual('baz');
} else {
res.error();
}
triggerTime++;
res.success();
});

let obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
// We only update foo
obj.set('foo', 'baz');
return obj.save();
}).then(() => {
// Make sure the checking has been triggered
expect(triggerTime).toBe(2);
done();
}, function(error) {
fail(error);
done();
});
});

it('original object is set on update', done => {
let triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => {
let object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
let originalObject = req.original;
if (triggerTime == 0) {
// No id/createdAt/updatedAt
expect(object.id).toBeUndefined();
expect(object.createdAt).toBeUndefined();
expect(object.updatedAt).toBeUndefined();
// Create
expect(object.get('foo')).toEqual('bar');
// Check the originalObject is undefined
expect(originalObject).toBeUndefined();
} else if (triggerTime == 1) {
// Update
expect(object.id).not.toBeUndefined();
expect(object.createdAt).not.toBeUndefined();
expect(object.updatedAt).not.toBeUndefined();
expect(object.get('foo')).toEqual('baz');
// Check the originalObject
expect(originalObject instanceof Parse.Object).toBeTruthy();
expect(originalObject.get('fooAgain')).toEqual('barAgain');
expect(originalObject.id).not.toBeUndefined();
expect(originalObject.createdAt).not.toBeUndefined();
expect(originalObject.updatedAt).not.toBeUndefined();
expect(originalObject.get('foo')).toEqual('bar');
} else {
res.error();
}
triggerTime++;
res.success();
});

let obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(() => {
// We only update foo
obj.set('foo', 'baz');
return obj.save();
}).then(() => {
// Make sure the checking has been triggered
expect(triggerTime).toBe(2);
done();
}, error => {
fail(error);
done();
});
});
});

Expand Down Expand Up @@ -471,62 +577,6 @@ describe('miscellaneous', function() {
});
});

it('test beforeSave get original object on update', function(done) {
var triggerTime = 0;
// Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', function(req, res) {
var object = req.object;
expect(object instanceof Parse.Object).toBeTruthy();
expect(object.get('fooAgain')).toEqual('barAgain');
var originalObject = req.original;
if (triggerTime == 0) {
// No id/createdAt/updatedAt
expect(object.id).toBeUndefined();
expect(object.createdAt).toBeUndefined();
expect(object.updatedAt).toBeUndefined();
// Create
expect(object.get('foo')).toEqual('bar');
// Check the originalObject is undefined
expect(originalObject).toBeUndefined();
} else if (triggerTime == 1) {
// Update
expect(object.id).not.toBeUndefined();
expect(object.createdAt).not.toBeUndefined();
expect(object.updatedAt).not.toBeUndefined();
expect(object.get('foo')).toEqual('baz');
// Check the originalObject
expect(originalObject instanceof Parse.Object).toBeTruthy();
expect(originalObject.get('fooAgain')).toEqual('barAgain');
expect(originalObject.id).not.toBeUndefined();
expect(originalObject.createdAt).not.toBeUndefined();
expect(originalObject.updatedAt).not.toBeUndefined();
expect(originalObject.get('foo')).toEqual('bar');
} else {
res.error();
}
triggerTime++;
res.success();
});

var obj = new Parse.Object('GameScore');
obj.set('foo', 'bar');
obj.set('fooAgain', 'barAgain');
obj.save().then(function() {
// We only update foo
obj.set('foo', 'baz');
return obj.save();
}).then(function() {
// Make sure the checking has been triggered
expect(triggerTime).toBe(2);
// Clear mock beforeSave
delete Parse.Cloud.Triggers.beforeSave.GameScore;
done();
}, function(error) {
fail(error);
done();
});
});

it('test afterSave get original object on update', function(done) {
var triggerTime = 0;
// Register a mock beforeSave hook
Expand Down
1 change: 0 additions & 1 deletion spec/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ var DatabaseAdapter = require('../src/DatabaseAdapter');
var express = require('express');
var facebook = require('../src/oauth/facebook');
var ParseServer = require('../src/index').ParseServer;
var DatabaseAdapter = require('../src/DatabaseAdapter');

var databaseURI = process.env.DATABASE_URI;
var cloudMain = process.env.CLOUD_CODE_MAIN || '../spec/cloud/main.js';
Expand Down
17 changes: 11 additions & 6 deletions src/RestWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,23 @@ RestWrite.prototype.runBeforeTrigger = function() {
if (this.query && this.query.objectId) {
extraData.objectId = this.query.objectId;
}
// Build the inflated object, for a create write, originalData is empty
var inflatedObject = triggers.inflate(extraData, this.originalData);;
inflatedObject._finishFetch(this.data);
// Build the original object, we only do this for a update write
var originalObject;

let originalObject = null;
let updatedObject = null;
if (this.query && this.query.objectId) {
// This is an update for existing object.
originalObject = triggers.inflate(extraData, this.originalData);
updatedObject = triggers.inflate(extraData, this.originalData);
updatedObject.set(Parse._decode(undefined, this.data));
} else {
// This is create of an object, so no original object exists.
// TODO: (nlutsenko) Use the same flow as for creation, when _Session triggers support is removed.
updatedObject = triggers.inflate(extraData, this.data);
}

return Promise.resolve().then(() => {
return triggers.maybeRunTrigger(
'beforeSave', this.auth, inflatedObject, originalObject);
'beforeSave', this.auth, updatedObject, originalObject);
}).then((response) => {
if (response && response.object) {
this.data = response.object;
Expand Down