问题
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));
})};
回答1:
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));
})};
来源:https://stackoverflow.com/questions/28176140/how-to-fix-nested-structure-in-bookshelfjs-transaction