Skip to content

Commit ea2038c

Browse files
jb pringueyjb pringuey
authored andcommitted
Adding support for AfterFind
1 parent 94178df commit ea2038c

File tree

4 files changed

+200
-2
lines changed

4 files changed

+200
-2
lines changed

spec/CloudCode.spec.js

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1306,4 +1306,132 @@ describe('beforeFind hooks', () => {
13061306
done();
13071307
});
13081308
});
1309-
})
1309+
});
1310+
1311+
describe('afterFind hooks', () => {
1312+
it('should add afterFind trigger using get',(done) => {
1313+
Parse.Cloud.afterFind('MyObject', (req, res) => {
1314+
for(let i = 0 ; i < res.results.length ; i++){
1315+
res.results[i].set("secretField","###");
1316+
}
1317+
});
1318+
let obj = new Parse.Object('MyObject');
1319+
obj.set('secretField', 'SSID');
1320+
obj.save().then(function() {
1321+
let query = new Parse.Query('MyObject');
1322+
query.get(obj.id).then(function(result) {
1323+
expect(result.get('secretField')).toEqual('###');
1324+
done();
1325+
}, function(error) {
1326+
fail(error);
1327+
done();
1328+
});
1329+
}, function(error) {
1330+
fail(error);
1331+
done();
1332+
});
1333+
});
1334+
1335+
it('should add afterFind trigger using find',(done) => {
1336+
Parse.Cloud.afterFind('MyObject', (req, res) => {
1337+
for(let i = 0 ; i < res.results.length ; i++){
1338+
res.results[i].set("secretField","###");
1339+
}
1340+
});
1341+
let obj = new Parse.Object('MyObject');
1342+
obj.set('secretField', 'SSID');
1343+
obj.save().then(function() {
1344+
let query = new Parse.Query('MyObject');
1345+
query.equalTo('objectId',obj.id);
1346+
query.find().then(function(results) {
1347+
expect(results[0].get('secretField')).toEqual('###');
1348+
done();
1349+
}, function(error) {
1350+
fail(error);
1351+
done();
1352+
});
1353+
}, function(error) {
1354+
fail(error);
1355+
done();
1356+
});
1357+
});
1358+
1359+
it('should filter out results',(done) => {
1360+
Parse.Cloud.afterFind('MyObject', (req, res) => {
1361+
let filteredResults = [];
1362+
for(let i = 0 ; i < res.results.length ; i++){
1363+
if(res.results[i].get("secretField")==="SSID1") {
1364+
filteredResults.push(res.results[i]);
1365+
}
1366+
}
1367+
res.results = filteredResults;
1368+
});
1369+
let obj0 = new Parse.Object('MyObject');
1370+
obj0.set('secretField', 'SSID1');
1371+
let obj1 = new Parse.Object('MyObject');
1372+
obj1.set('secretField', 'SSID2');
1373+
Parse.Object.saveAll([obj0, obj1]).then(function() {
1374+
let query = new Parse.Query('MyObject');
1375+
query.find().then(function(results) {
1376+
expect(results[0].get('secretField')).toEqual('SSID1');
1377+
expect(results.length).toEqual(1);
1378+
done();
1379+
}, function(error) {
1380+
fail(error);
1381+
done();
1382+
});
1383+
}, function(error) {
1384+
fail(error);
1385+
done();
1386+
});
1387+
});
1388+
1389+
it('should handle failures',(done) => {
1390+
Parse.Cloud.afterFind('MyObject', (req, res) => {
1391+
res.error(Parse.Error.SCRIPT_FAILED, "It should fail");
1392+
});
1393+
let obj = new Parse.Object('MyObject');
1394+
obj.set('secretField', 'SSID');
1395+
obj.save().then(function() {
1396+
let query = new Parse.Query('MyObject');
1397+
query.equalTo('objectId',obj.id);
1398+
query.find().then(function(results) {
1399+
fail("AfterFind should handle response failure correctly");
1400+
done();
1401+
}, function(error) {
1402+
done();
1403+
});
1404+
}, function(error) {
1405+
done();
1406+
});
1407+
});
1408+
1409+
it('should also work with promise',(done) => {
1410+
Parse.Cloud.afterFind('MyObject', (req, res) => {
1411+
let promise = new Parse.Promise();
1412+
setTimeout(function(){
1413+
for(let i = 0 ; i < res.results.length ; i++){
1414+
res.results[i].set("secretField","###");
1415+
}
1416+
promise.resolve(res.results);
1417+
}, 1000);
1418+
return promise;
1419+
});
1420+
let obj = new Parse.Object('MyObject');
1421+
obj.set('secretField', 'SSID');
1422+
obj.save().then(function() {
1423+
let query = new Parse.Query('MyObject');
1424+
query.equalTo('objectId',obj.id);
1425+
query.find().then(function(results) {
1426+
expect(results[0].get('secretField')).toEqual('###');
1427+
done();
1428+
}, function(error) {
1429+
fail(error);
1430+
});
1431+
}, function(error) {
1432+
fail(error);
1433+
});
1434+
});
1435+
1436+
});
1437+

src/RestQuery.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
var SchemaController = require('./Controllers/SchemaController');
55
var Parse = require('parse/node').Parse;
6+
const triggers = require('./triggers');
67

78
import { default as FilesController } from './Controllers/FilesController';
89

@@ -122,6 +123,8 @@ RestQuery.prototype.execute = function(executeOptions) {
122123
return this.runCount();
123124
}).then(() => {
124125
return this.handleInclude();
126+
}).then(() => {
127+
return this.runAfterFindTrigger();
125128
}).then(() => {
126129
return this.response;
127130
});
@@ -468,6 +471,22 @@ RestQuery.prototype.handleInclude = function() {
468471
return pathResponse;
469472
};
470473

474+
//Returns a promise of a processed set of results
475+
RestQuery.prototype.runAfterFindTrigger = function() {
476+
if (!this.response) {
477+
return;
478+
}
479+
// Avoid doing any setup for triggers if there is no 'afterFind' trigger for this class.
480+
const hasAfterFindHook = triggers.triggerExists(this.className, triggers.Types.afterFind, this.config.applicationId);
481+
if (!hasAfterFindHook) {
482+
return Promise.resolve();
483+
}
484+
// Run afterFind trigger and set the new results
485+
return triggers.maybeRunAfterFindTrigger(triggers.Types.afterFind, this.auth, this.className,this.response.results, this.config).then((results) => {
486+
this.response.results = results;
487+
});
488+
};
489+
471490
// Adds included values to the response.
472491
// Path is a list of field names.
473492
// Returns a promise for an augmented response.

src/cloud-code/Parse.Cloud.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ ParseCloud.beforeFind = function(parseClass, handler) {
5050
triggers.addTrigger(triggers.Types.beforeFind, className, handler, Parse.applicationId);
5151
};
5252

53+
ParseCloud.afterFind = function(parseClass, handler) {
54+
const className = getClassName(parseClass);
55+
triggers.addTrigger(triggers.Types.afterFind, className, handler, Parse.applicationId);
56+
};
57+
5358
ParseCloud._removeAllHooks = () => {
5459
triggers._unregisterAll();
5560
}

src/triggers.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export const Types = {
88
afterSave: 'afterSave',
99
beforeDelete: 'beforeDelete',
1010
afterDelete: 'afterDelete',
11-
beforeFind: 'beforeFind'
11+
beforeFind: 'beforeFind',
12+
afterFind: 'afterFind'
1213
};
1314

1415
const baseStore = function() {
@@ -240,6 +241,51 @@ function logTriggerErrorBeforeHook(triggerType, className, input, auth, error) {
240241
});
241242
}
242243

244+
export function maybeRunAfterFindTrigger(triggerType, auth, className, results, config) {
245+
return new Promise(function (resolve, reject) {
246+
const trigger = getTrigger(className, triggerType, config.applicationId);
247+
if (!trigger) {
248+
return resolve();
249+
}
250+
const request = getRequestObject(triggerType, auth, null, null, config);
251+
const response = {
252+
error: function(code, message) {
253+
if (!message) {
254+
message = code;
255+
code = Parse.Error.SCRIPT_FAILED;
256+
}
257+
const scriptError = new Parse.Error(code, message);
258+
return reject(scriptError);
259+
}
260+
};
261+
logTriggerSuccessBeforeHook(triggerType, className, 'AfterFind', JSON.stringify(results), auth);
262+
response.results = results.map(result => {
263+
//setting the class name to transform into parse object
264+
result.className=className;
265+
return Parse.Object.fromJSON(result);
266+
});
267+
const triggerPromise = trigger(request, response);
268+
logTriggerAfterHook(triggerType, className, JSON.stringify(modifiedJSONResults), auth);
269+
if (triggerPromise && typeof triggerPromise.then === "function") {
270+
return triggerPromise.then(function(promiseResults){
271+
if(promiseResults) {
272+
var modifiedJSONResults = promiseResults.map(result => {
273+
return result.toJSON();
274+
});
275+
resolve(modifiedJSONResults);
276+
}else{
277+
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
278+
}
279+
});
280+
} else {
281+
var modifiedJSONResults = response.results.map(result => {
282+
return result.toJSON();
283+
});
284+
return resolve(modifiedJSONResults);
285+
}
286+
});
287+
}
288+
243289
export function maybeRunQueryTrigger(triggerType, className, restWhere, restOptions, config, auth) {
244290
let trigger = getTrigger(className, triggerType, config.applicationId);
245291
if (!trigger) {

0 commit comments

Comments
 (0)