Instead of nesting various functions within success completion handlers, I'd like to separate out my functions so that they can either be used independently or in succession. However, I'm super confused regarding the syntax of promises in Parse and have not been able to chain them together successfully despite looking at many other StackOverflow answers (e.g., here, here, here, and here) and Parse's official documentation, overview, and blog post about the topic.
Here's an example of my Cloud Code where I am trying to use chained promises:
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var account = request.object;
if (account.existed()) {
if (account.dirtyKeys().indexOf("username") >= 0) {
updateUsernameForAccountId(account.get("username"), account.id)
.then(
function() {
console.log("Checkpoint SUCCESS");
response.success();
}, function(error) {
console.log("Checkpoint ERROR");
response.error(error);
});
}
}
});
function updateUsernameForAccountId(username, accountId) {
console.log("Checkpoint A-1 ("+username+", "+accountId+")");
updateUsernameForMessagesSentByAccountId(username, accountId)
.then(
function() {
console.log("Checkpoint A-2");
return updateUsernameForMessagesReceivedByAccountId(username, accountId);
})
.then(
function() {
console.log("Checkpoint A-3");
return Parse.Promise.as();
}, function(error) {
console.log("Checkpoint A-ERROR");
return Parse.Promise.error(error);
});
};
function updateUsernameForMessagesSentByAccountId(username, accountId) {
console.log("Checkpoint B-1");
var query = new Parse.Query(parseClassMessage);
query.equalTo(parseKeySenderId, accountId);
query.find()
.then(
function(results) {
console.log("Checkpoint B-2");
var object;
for (var i = 0; i < results.length; i++) {
console.log("Checkpoint B-2-"+i);
object = results[i];
object.set(parseKeySenderUsername, username);
}
return Parse.Promise.as(results);
})
.then(
function(objects) {
console.log("Checkpoint B-3");
return Parse.Object.saveAll(objects);
})
.then(
function() {
console.log("Checkpoint B-4");
return Parse.Promise.as();
}, function(error) {
console.log("Checkpoint B-ERROR");
return Parse.Promise.error(error);
});
};
function updateUsernameForMessagesReceivedByAccountId(username, accountId) {
console.log("Checkpoint C-1");
var query = new Parse.Query(parseClassMessage);
query.equalTo(parseKeyRecipientId, accountId);
query.find()
.then(
function(results) {
console.log("Checkpoint C-2");
var object;
for (var i = 0; i < results.length; i++) {
console.log("Checkpoint C-2-"+i);
object = results[i];
object.set(parseKeyRecipientUsername, username);
}
return Parse.Promise.as(results);
})
.then(
function(objects) {
console.log("Checkpoint C-3");
return Parse.Object.saveAll(objects);
})
.then(
function() {
console.log("Checkpoint C-4");
return Parse.Promise.as();
}, function(error) {
console.log("Checkpoint C-ERROR");
return Parse.Promise.error(error);
});
};
The expected behavior is:
- Right before saving a User object, check if it is an already existing User (v. a newly created User) and whether the username was changed.
- IF YES: Perform function
updateUsernameForAccountId(username, accountId), which performsupdateUsernameForMessagesSentByAccountId(username, accountId)and thenupdateUsernameForMessagesReceivedByAccountId(username, accountId).- N.b. I don't need these two methods to be synchronous, but I thought it necessary in order to return a single Promise object back to
beforeSave.
- N.b. I don't need these two methods to be synchronous, but I thought it necessary in order to return a single Promise object back to
I am able to upload this code to Cloud Code successfully, but when I go into the data browser on Parse.com and change the username of an existing User object to test, the log produces the following output:
E2015-08-11T21:16:23.467Z]v27 before_save triggered for _User as master:
Input: {"original":{"createdAt":"2015-08-09T16:53:47.194Z","objectId":"mkTluyGbHf","updatedAt":"2015-08-11T17:23:19.523Z","username":"[email protected]"},"update":{"username":"[email protected]"}}
Result: TypeError: Cannot call method 'then' of undefined
at updateUsernameForAccountId (main.js:114:4)
at main.js:16:4
I2015-08-11T21:16:23.533Z]Checkpoint A-1 ([email protected], mkTluyGbHf)
I2015-08-11T21:16:23.534Z]Checkpoint B-1
And I also receive the following error in the Parse.com data browser:
Error: TypeError: Cannot call method 'then' of undefined at updateUsernameForAccountId (main.js:114:4) at main.js:16:4
Please let me know what additional information or clarification I can provide. I apologize in advance that I am not able to articulate my question, errors, or confusions more clearly.