Skip to content

Commit 19271fa

Browse files
jbpringueyflovilmart
authored andcommitted
Adding support for AfterFind (#2968)
1 parent b80d8a0 commit 19271fa

File tree

4 files changed

+202
-2
lines changed

4 files changed

+202
-2
lines changed

spec/CloudCode.spec.js

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

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() {
@@ -185,6 +186,15 @@ export function getRequestQueryObject(triggerType, auth, query, config) {
185186
export function getResponseObject(request, resolve, reject) {
186187
return {
187188
success: function(response) {
189+
if (request.triggerName === Types.afterFind) {
190+
if(!response){
191+
response = request.objects;
192+
}
193+
response = response.map(object => {
194+
return object.toJSON();
195+
});
196+
return resolve(response);
197+
}
188198
// Use the JSON response
189199
if (response && !request.object.equals(response)
190200
&& request.triggerName === Types.beforeSave) {
@@ -240,6 +250,42 @@ function logTriggerErrorBeforeHook(triggerType, className, input, auth, error) {
240250
});
241251
}
242252

253+
export function maybeRunAfterFindTrigger(triggerType, auth, className, objects, config) {
254+
return new Promise((resolve, reject) => {
255+
const trigger = getTrigger(className, triggerType, config.applicationId);
256+
if (!trigger) {
257+
return resolve();
258+
}
259+
const request = getRequestObject(triggerType, auth, null, null, config);
260+
const response = getResponseObject(request,
261+
object => {
262+
resolve(object);
263+
},
264+
error => {
265+
reject(error);
266+
});
267+
logTriggerSuccessBeforeHook(triggerType, className, 'AfterFind', JSON.stringify(objects), auth);
268+
request.objects = objects.map(object => {
269+
//setting the class name to transform into parse object
270+
object.className=className;
271+
return Parse.Object.fromJSON(object);
272+
});
273+
const triggerPromise = trigger(request, response);
274+
if (triggerPromise && typeof triggerPromise.then === "function") {
275+
return triggerPromise.then(promiseResults => {
276+
if(promiseResults) {
277+
resolve(promiseResults);
278+
}else{
279+
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
280+
}
281+
});
282+
}
283+
}).then((results) => {
284+
logTriggerAfterHook(triggerType, className, JSON.stringify(results), auth);
285+
return results;
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)