Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix nested structure in bookshelfjs transaction [duplicate]

I want to update a number of database tables in a single bookshelf transaction. I could use some help refactoring my code. I'm new to node and don't have a good understanding of promises, but the nested structure below is not very pretty, and I'm hoping there is a cleaner way. Any help would be appreciated.

function insertUser(user, cb) {
  bookshelf.transaction(function(t) {
  var key = user.key;
  Developer.forge({key: key})
  .fetch({require: true, transacting: t})
  .then(function(developerModel) {
    var devID = developerModel.get('id');
    Address.forge(user.address)
    .save(null, {transacting: t})
    .then(function(addressModel) {
      var addressID = addressModel.get('addressId');
      Financial.forge(user.financial)
      .save(null, {transacting: t})
      .then(function(financialModel) {
        var financialID = financialModel.get('financialId');
        var userEntity = user.personal;
        userEntity.addressId = addressID;
        userEntity.developerId = devID;
        userEntity.financialId = financialId;
        User.forge(userEntity)
        .save(null, {transacting: t})
        .then(function(userModel) {
          logger.info('saved user: ', userModel);
          logger.info('commiting transaction');
          t.commit(userModel);
        })
        .catch(function(err) {
          logger.error('Error saving user: ', err);
          t.rollback(err);
        });
      })
      .catch(function(err) {
        logger.error('Error saving financial data: ', err);
        t.rollback(err);
      })
    })
    .catch(function(err) {
      logger.error('Error saving address: ', err);
      t.rollback(err);
    })
  })
  .catch(function(err) {
    logger.error('Error saving business : ', err);
    t.rollback(err);
  })
})
.then(function(model) {
  logger.info(model, ' successfully saved');
  return Promise.resolve(respond.success({userId: model.get('userId')}));
})
.catch(function(err) {
  logger.error(err, ' occurred');
  return Promise.reject(new DatabaseError('Unable to write user to database due to error ', err.message));
})};
like image 374
Matt Phinney Avatar asked Sep 28 '22 22:09

Matt Phinney


1 Answers

Save the promises-for-results to variables and you can use them later in the final then where it's guaranteed that they are fulfilled and thus their value can be retrieved with .value() synchronously

function insertUser(user, cb) {
  return bookshelf.transaction(function(t) {
    var key = user.key;

    var devID = Developer.forge({key: key})
      .fetch({require: true, transacting: t})
      .call("get", "id");

    var addressID = devID.then(function() {
      return Address.forge(user.address).fetch({require: true, transacting: t})
    }).call("get", "addressId");

    var financialID = addressModel.then(function() {
      return Financial.forge(user.financial).save(null, {transacting: t})
    }).call("get", "financialId");

    var userModel = financialID.then(function() {
      var userEntity = user.personal;
      userEntity.addressId = addressID.value();
      userEntity.developerId = devID.value();
      userEntity.financialId = financialID.value();
      return User.forge(userEntity).save(null, {transacting: t});
    });

    return userModel.then(function(userModel) {
      logger.info('saved user: ', userModel);
      logger.info('commiting transaction');
      t.commit(userModel);
    }).catch(function(e) {
      t.rollback(e);
      throw e;
    });
  });
}
.then(function(model) {
  logger.info(model, ' successfully saved');
  return Promise.resolve(respond.success({userId: model.get('userId')}));
})
.catch(function(err) {
  logger.error(err, ' occurred');
  return Promise.reject(new DatabaseError('Unable to write user to database due to error ', err.message));
})};

Another way is to use Promise.join:

function insertUser(user, cb) {
  return bookshelf.transaction(function(t) {
    var key = user.key;

    var devID = Developer.forge({key: key})
      .fetch({require: true, transacting: t})
      .call("get", "id");

    var addressID = devID.then(function() {
      return Address.forge(user.address).fetch({require: true, transacting: t})
    }).call("get", "addressId");

    var financialID = addressModel.then(function() {
      return Financial.forge(user.financial).save(null, {transacting: t})
    }).call("get", "financialId");

    var userModel = Promise.join(devID, addressID, financialID,
     function(devID, addressID, financialID) {
      var userEntity = user.personal;
      userEntity.addressId = addressID;
      userEntity.developerId = devID;
      userEntity.financialId = financialID;
      return User.forge(userEntity).save(null, {transacting: t});
    });

    return userModel.then(function(userModel) {
      logger.info('saved user: ', userModel);
      logger.info('commiting transaction');
      t.commit(userModel);
    }).catch(function(e) {
      t.rollback(e);
      throw e;
    });
  });
}
.then(function(model) {
  logger.info(model, ' successfully saved');
  return Promise.resolve(respond.success({userId: model.get('userId')}));
})
.catch(function(err) {
  logger.error(err, ' occurred');
  return Promise.reject(new DatabaseError('Unable to write user to database due to error ', err.message));
})};
like image 158
Esailija Avatar answered Oct 05 '22 06:10

Esailija