In one of my beforeSave functions, I need to check a number of conditions before responding with success or error.
The problem is, my code seems really messy and sometimes success/error isn't called:
Parse.Cloud.beforeSave("Entry", function(request, response) {
var entry = request.object;
var contest = request.object.get("contest");
entry.get("user").fetch().then(function(fetchedUser) {
contest.fetch().then(function(fetchedContest) {
if ( fetchedUser.get("fundsAvailable") < fetchedContest.get("entryFee") ) {
response.error('Insufficient Funds.');
} else {
fetchedContest.get("timeSlot").fetch().then(function(fetchedTimeSlot) {
var now = new Date();
if (fetchedTimeSlot.get("startDate") < now) {
response.error('This contest has already started.');
} else {
contest.increment("entriesCount");
contest.increment("entriesLimit", 0); //have to do this, otherwise entriesLimit is undefined in save callback (?)
contest.save().then(function(fetchedContest) {
if (contest.get("entriesCount") > contest.get("entriesLimit")) {
response.error('The contest is full.');
} else {
response.success();
}
});
}
});
}
});
});
});
I've been trying to learn promises to tidy this up, and here was my (failed) attempt:
Parse.Cloud.beforeSave("Entry", function(request, response) {
var entry = request.object;
var contest = request.object.get("contest");
entry.get("user").fetch().then(function(fetchedUser) {
contest.fetch().then(function(fetchedContest) {
if ( fetchedUser.get("fundsAvailable") < fetchedContest.get("entryFee") ) {
response.error('Insufficient Funds.');
}
return fetchedContest;
});
}).then(function(result) {
result.get("timeSlot").fetch().then(function(fetchedTimeSlot) {
var now = new Date();
if (fetchedTimeSlot.get("startDate") < now) {
response.error('This contest has already started.');
}
});
}).then(function() {
contest.increment("entriesCount");
contest.increment("entriesLimit", 0);
contest.save().then(function(fetchedContest) {
if (contest.get("entriesCount") > contest.get("entriesLimit")) {
response.error('The contest is full.');
}
});
}).then(function() {
response.success();
}, function(error) {
response.error(error);
});
});
Any help or examples on how to use promises for this would be much appreciated. Clearly I do not fully understand how they work syntactically yet.
I cleaned it up a bit by getting the fetched variables assembled first using a chain of promises. This follows a couple style rules that make it more readable (for me anyway)...
Parse.Cloud.beforeSave("Entry", function(request, response) {
var entry = request.object;
var contest = request.object.get("contest");
var fetchedUser, fetchedContest;
var errorMessage;
entry.get("user").fetch().then(function(result) {
fetchedUser = result;
return contest.fetch();
}).then(function(result) {
fetchedContest = result;
return fetchedContest.get("timeSlot").fetch();
}).then(function(fetchedTimeSlot) {
// now we have all the variables we need to determine validity
var now = new Date();
var hasSufficientFunds = fetchedUser.get("fundsAvailable") >= fetchedContest.get("entryFee");
var contestNotStarted = fetchedTimeSlot.get("startDate") >= now;
if (hasSufficientFunds && contestNotStarted) {
contest.increment("entriesCount");
contest.increment("entriesLimit", 0); //have to do this, otherwise entriesLimit is undefined in save callback (?)
return contest.save();
} else {
errorMessage = (hasSufficientFunds)? 'This contest has already started.' : 'Insufficient Funds.';
return null;
}
}).then(function(result) {
if (!result) {
response.error(errorMessage);
} else {
if (contest.get("entriesCount") > contest.get("entriesLimit")) {
response.error('The contest is full.');
} else {
response.success();
}
}
}, function(error) {
response.error(error);
});
});
Note how we never leave a response.anything() dangling, we always make clear what's flowing to the next promise via a return.