Adding support for AfterFind (#2968)

This commit is contained in:
jb
2016-11-12 09:35:34 -08:00
committed by Florent Vilmart
parent b80d8a0d3d
commit 19271fa1ef
4 changed files with 202 additions and 2 deletions

View File

@@ -1306,4 +1306,134 @@ describe('beforeFind hooks', () => {
done();
});
});
})
});
describe('afterFind hooks', () => {
it('should add afterFind trigger using get',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
for(let i = 0 ; i < req.objects.length ; i++){
req.objects[i].set("secretField","###");
}
res.success(req.objects);
});
let obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
query.get(obj.id).then(function(result) {
expect(result.get('secretField')).toEqual('###');
done();
}, function(error) {
fail(error);
done();
});
}, function(error) {
fail(error);
done();
});
});
it('should add afterFind trigger using find',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
for(let i = 0 ; i < req.objects.length ; i++){
req.objects[i].set("secretField","###");
}
res.success(req.objects);
});
let obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('###');
done();
}, function(error) {
fail(error);
done();
});
}, function(error) {
fail(error);
done();
});
});
it('should filter out results',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
let filteredResults = [];
for(let i = 0 ; i < req.objects.length ; i++){
if(req.objects[i].get("secretField")==="SSID1") {
filteredResults.push(req.objects[i]);
}
}
res.success(filteredResults);
});
let obj0 = new Parse.Object('MyObject');
obj0.set('secretField', 'SSID1');
let obj1 = new Parse.Object('MyObject');
obj1.set('secretField', 'SSID2');
Parse.Object.saveAll([obj0, obj1]).then(function() {
let query = new Parse.Query('MyObject');
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('SSID1');
expect(results.length).toEqual(1);
done();
}, function(error) {
fail(error);
done();
});
}, function(error) {
fail(error);
done();
});
});
it('should handle failures',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
res.error(Parse.Error.SCRIPT_FAILED, "It should fail");
});
let obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function(results) {
fail("AfterFind should handle response failure correctly");
done();
}, function(error) {
done();
});
}, function(error) {
done();
});
});
it('should also work with promise',(done) => {
Parse.Cloud.afterFind('MyObject', (req, res) => {
let promise = new Parse.Promise();
setTimeout(function(){
for(let i = 0 ; i < req.objects.length ; i++){
req.objects[i].set("secretField","###");
}
promise.resolve(req.objects);
}, 1000);
return promise;
});
let obj = new Parse.Object('MyObject');
obj.set('secretField', 'SSID');
obj.save().then(function() {
let query = new Parse.Query('MyObject');
query.equalTo('objectId',obj.id);
query.find().then(function(results) {
expect(results[0].get('secretField')).toEqual('###');
done();
}, function(error) {
fail(error);
});
}, function(error) {
fail(error);
});
});
});

View File

@@ -3,6 +3,7 @@
var SchemaController = require('./Controllers/SchemaController');
var Parse = require('parse/node').Parse;
const triggers = require('./triggers');
import { default as FilesController } from './Controllers/FilesController';
@@ -122,6 +123,8 @@ RestQuery.prototype.execute = function(executeOptions) {
return this.runCount();
}).then(() => {
return this.handleInclude();
}).then(() => {
return this.runAfterFindTrigger();
}).then(() => {
return this.response;
});
@@ -468,6 +471,22 @@ RestQuery.prototype.handleInclude = function() {
return pathResponse;
};
//Returns a promise of a processed set of results
RestQuery.prototype.runAfterFindTrigger = function() {
if (!this.response) {
return;
}
// Avoid doing any setup for triggers if there is no 'afterFind' trigger for this class.
const hasAfterFindHook = triggers.triggerExists(this.className, triggers.Types.afterFind, this.config.applicationId);
if (!hasAfterFindHook) {
return Promise.resolve();
}
// Run afterFind trigger and set the new results
return triggers.maybeRunAfterFindTrigger(triggers.Types.afterFind, this.auth, this.className,this.response.results, this.config).then((results) => {
this.response.results = results;
});
};
// Adds included values to the response.
// Path is a list of field names.
// Returns a promise for an augmented response.

View File

@@ -50,6 +50,11 @@ ParseCloud.beforeFind = function(parseClass, handler) {
triggers.addTrigger(triggers.Types.beforeFind, className, handler, Parse.applicationId);
};
ParseCloud.afterFind = function(parseClass, handler) {
const className = getClassName(parseClass);
triggers.addTrigger(triggers.Types.afterFind, className, handler, Parse.applicationId);
};
ParseCloud._removeAllHooks = () => {
triggers._unregisterAll();
}

View File

@@ -8,7 +8,8 @@ export const Types = {
afterSave: 'afterSave',
beforeDelete: 'beforeDelete',
afterDelete: 'afterDelete',
beforeFind: 'beforeFind'
beforeFind: 'beforeFind',
afterFind: 'afterFind'
};
const baseStore = function() {
@@ -185,6 +186,15 @@ export function getRequestQueryObject(triggerType, auth, query, config) {
export function getResponseObject(request, resolve, reject) {
return {
success: function(response) {
if (request.triggerName === Types.afterFind) {
if(!response){
response = request.objects;
}
response = response.map(object => {
return object.toJSON();
});
return resolve(response);
}
// Use the JSON response
if (response && !request.object.equals(response)
&& request.triggerName === Types.beforeSave) {
@@ -240,6 +250,42 @@ function logTriggerErrorBeforeHook(triggerType, className, input, auth, error) {
});
}
export function maybeRunAfterFindTrigger(triggerType, auth, className, objects, config) {
return new Promise((resolve, reject) => {
const trigger = getTrigger(className, triggerType, config.applicationId);
if (!trigger) {
return resolve();
}
const request = getRequestObject(triggerType, auth, null, null, config);
const response = getResponseObject(request,
object => {
resolve(object);
},
error => {
reject(error);
});
logTriggerSuccessBeforeHook(triggerType, className, 'AfterFind', JSON.stringify(objects), auth);
request.objects = objects.map(object => {
//setting the class name to transform into parse object
object.className=className;
return Parse.Object.fromJSON(object);
});
const triggerPromise = trigger(request, response);
if (triggerPromise && typeof triggerPromise.then === "function") {
return triggerPromise.then(promiseResults => {
if(promiseResults) {
resolve(promiseResults);
}else{
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
}
});
}
}).then((results) => {
logTriggerAfterHook(triggerType, className, JSON.stringify(results), auth);
return results;
});
}
export function maybeRunQueryTrigger(triggerType, className, restWhere, restOptions, config, auth) {
let trigger = getTrigger(className, triggerType, config.applicationId);
if (!trigger) {