Matt
Matt

Reputation: 1432

How do you prevent nested queries/catches in sequelize?

I think I'm preventing nested queries as much as possible, but I'm honestly not sure. I understand the calls here can all be executed in a single select query, but I did this to simplify the example.

// This example is in TypeScript

// find user
User.find({where:{username:'user'}})

    // if found user
    .then(function(user) {

        return User.find({where:{username:'other_user'}})

            // if found other_user
            .then(function(other_user) {
                // do stuff
                return whatever_i_need
            }

            // if something went wrong, go straight to parent catch
            .catch(function(err) {
                // do stuff
                throw new Error()
            }
    }

    // if previous .then() returned success
    .then(function(data) {

        return User.find({where:{username:'yet_another_user'}})

            // if found yet_another_user
            .then(function(yet_another_user) {
                // do stuff
                return whatever_i_need_again
            }

            // if something went wrong, go straight to parent catch
            .catch(function(err) {
                // do stuff
                throw new Error()
            }
    }

    // if anything threw an error at any point in time
    .catch(function(err) {
        // handle the error
    }

However, this results in nested promises, which is exactly what promises are meant to prevent. Is this the "max depth" recommended for promises, or am I missing something? Is there a better way to chain queries?

Upvotes: 1

Views: 751

Answers (2)

Season
Season

Reputation: 4376

Return the nested promise instead of handling it in the inner blocks to flatten the structure.

User.find({where:{username:'user'}})
.then(function(user) {
  if (user) { // if found user
    // do stuff
    return User.find({where:{username:'other_user'}});
  }
  throw new Error('user not-found');
})
.then(function(other_user) {
  if (other_user) { // if found other_user
    // do stuff
    return whatever_i_need;
  }
  throw new Error('other_user not-found');
})
.then(function(data) {
  return User.find({where:{username:'yet_another_user'}})
})
.then(function(yet_another_user) {
  if (yet_another_user) { // if found yet_another_user
    // do stuff
    return whatever_i_need_again;
  }
  throw new Error('yet_another_user not-found');
}
.then(function(data){
  // do stuff
})
.catch(function(err) { // if anything threw an error at any point in time
  // handle the error
}

Note that a resolved promise means a query is successfully done. That's it all about. A successful query does't guarantee results to be returned. Empty result is a valid outcome of resolved promises.

Note also that the return value from a resolve or reject callback will be wrapped with a resolved promise, and then passed to the next then block, making a meaningful promise chain. Thanks for @Matt's follow-up feedback below regarding this point.

Upvotes: 2

Bergi
Bergi

Reputation: 664930

Two points:

  • Drop .catch(function(err) { throw new Error() }. It does nothing but remove the error message.
  • You can unnest the inner then calls

So it just should be

User.find({where:{username:'user'}})
.then(function(user) {
    return User.find({where:{username:'other_user'}})
})
.then(function(other_user) {
    // do stuff
     return whatever_i_need
})
// if previous .then() returned success
.then(function(data) {
    return User.find({where:{username:'yet_another_user'}})
})
// if found yet_another_user
.then(function(yet_another_user) {
    // do stuff
    return whatever_i_need_again
})
// if anything threw an error at any point in time
.catch(function(err) {
    // handle the error
})

Upvotes: 1

Related Questions