user2719094 user2719094 - 2 months ago 8
Node.js Question

How do I conditionally perform a second task using Promises?

I'm using Bookshelf.js, a Promise-based ORM module, to perform a couple database lookups. Given a key that a user provides, I need to determine if the key matches a record in one of two tables. If I find it in the first table, I need to return that record. However, if I don't find it in the first table, I need to look in the second table. Basically, I need to conditionally execute a

then
block. How do I accomplish this using promises? Here's what I currently have, which is very messy, and, in fact, I'm a little unclear about what happens if I call
resolve
in the first
School
lookup -- does the second
then
block execute as well?

exports.findTargetRecord = function(code){

return new Promise(function(resolve, reject){
Schools
.query({ where: { code: code }})
.fetchOne()
.then(school => {
if(school) return resolve(school);
return Organizations
.query({ where: { code: code }})
.fetchOne();
})
.then(org => {
if(org) return resolve(org);
resolve(null);
})
.catch(err => reject(err));
});
};


Is there a cleaner way to write this?

Answer

Use promises as proxies and a regular if:

exports.findTargetRecord = function(code){

  const school = Schools.query({ where: { code: code }}).fetchOne();
  school = school.then(school => 
    school || Organizations.query({ where: { code: code }}).fetchOne())
  return school;
}

Or with coroutines which bluebird supports (bluebird ships with bookshelf):

exports.findTargetRecord = Promise.coroutine(function*(code) {
   var school = yield Schools.query({ where: { code: code }}).fetchOne();
   if(school) return school;
   return Organizations.query({ where: { code: code }}).fetchOne();
});