Я пытаюсь переучивать NodeJS через пару лет после его сдачи, поэтому я строю небольшой банковский веб-сайт в качестве теста. Я решил использовать Sequelize для своего ORM, но у меня проблемы с отправкой денег между людьми так, как мне нравится. Вот моя первая попытка:
// myUsername - who to take the money from
// sendUsername - who to send the money to
// money - amount of money to be sent from 'myUsername'->'sendUsername'
// Transaction is created to keep a log of banking transactions for record-keeping.
module.exports = (myUsername, sendUsername, money, done) => {
// Create transaction so that errors will roll back
connection.transaction(t => {
return Promise.all([
User.increment('balance', {
by: money,
where: { username: myUsername },
transaction: t
}),
User.increment('balance', {
by: -money,
where: { username: sendUsername },
transaction: t
}),
Transaction.create({
fromUser: myUsername,
toUser: sendUsername,
value: money
}, { transaction: t })
]);
}).then(result => {
return done(null);
}).catch(err => {
return done(err);
});
};
Это сработало, но оно не подтвердило модель, когда она была увеличена. Я бы хотел, чтобы транзакция завершилась неудачей, когда модель не подтвердила. Моя следующая попытка состояла в том, чтобы перейти к обратным вызовам, показанным здесь (тот же заголовок функции):
connection.transaction(t => {
// Find the user to take money from
return User
.findOne({ where: { username: myUsername } }, { transaction: t }) .then(myUser => {
// Decrement money
return myUser
.decrement('balance', { by: money, transaction: t })
.then(myUser => {
// Reload model to validate data
return myUser.reload(myUser => {
// Validate modified model
return myUser.validate(() => {
// Find user to give money to
return User
.findOne({ where: { username: sendUsername } }, { transaction: t })
.then(sendUser => {
// Increment balance
return sendUser
.increment('balance', { by: money, transaction: t })
.then(sendUser => {
// Reload model
return sendUser.reload(sendUser => {
// Validate model
return sendUser.validate(() => {
// Create a transaction for record-keeping
return Transaction
.create({
fromUser: myUser.id,
toUser: sendUser.id,
value: money
}, { transaction: t });
});
});
});
});
});
});
});
});
}).then(result => {
return done(null);
}).catch(err => {
return done(err);
});
Это работает, поскольку деньги все еще передаются между людьми, но он все еще не подтверждает модели. Я думаю, причина в том, что .validate()
и .reload()
не имеют возможности добавить на нее параметр transaction: t
. Мой вопрос в том, есть ли способ сделать валидацию в транзакции, но мне также нужна помощь в исправлении этого "обратного ада". Опять же, я не делал JS через некоторое время, поэтому, вероятно, есть лучшие способы сделать это сейчас, о чем я сейчас знаю.
Спасибо!
Я считаю, что вы не можете получить валидации, чтобы Model
increment
и decrement
Model
и должны иметь экземпляры. В некоторых методах Seelize Model вы можете настроить проверки для запуска, но это не похоже на это здесь.
Я бы сделал это так
module.exports = async function(myUserId, sendUserId, money) {
const transaction = await connection.transaction();
try {
const [myUser, sendUser] = await Promise.all([
User.findById(myUserId, { transaction }),
User.findById(sendUserId, { transaction })
]);
await Promise.all([
myUser.increment('balance', {
by: money,
transaction
}),
myUser.increment('balance', {
by: -money,
transaction
})
]);
await Transaction.create({...}, { transaction })
await transaction.commit();
} catch(e) {
await transaction.rollback();
throw e;
}
}