I'm working on learning express and pg promise and have come across an issue that I suspect is a result from my not as firm as it should be grasp of promises.
Basically I have written some functions that I can use to query the database. I also have a function to use when handling any rejections. Those functions work perfectly when they are used alone (whether they succeed or throw an exception).
Here is a sample example:
const addToColumn = (tableName, columnName, entryId, amountToAdd) => {
return db.one('UPDATE ${table:name} SET ${column:name} = ${column:name} + ${amount:csv} WHERE id = ${id:csv} RETURNING *', {
table: tableName,
column: columnName,
amount: amountToAdd,
id: entryId
}).catch(err => handleQueryErr(err));
};
The functions also work perfectly when passed into a batch transaction manually like this:
const transferEnvelopeBudgetByIds = async (req, res, next) => {
try{
req.updatedEnvelopes = await db.tx(t => {
return t.batch([
addToColumn('envelopes', 'budget', req.envelopeFromId, -req.transferBudget),
addToColumn('envelopes', 'budget', req.envelopeToId, req.transferBudget)
]);
}).catch(err => handleTransactionErr(err));
next();
}catch(err){
next(err);
}
};
But then when I try to call this function in the middleware instead, if there is any database error (such as the database not running), then the server crashes with an uncaught excemption:
const batchQuery = (queryArray) => {
return db.tx(t => {
return t.batch(queryArray);
}).catch(err => handleTransactionErr(err));
};
const transferEnvelopeBudgetByIds = async (req, res, next) => {
try{
req.updatedEnvelopes = await batchQuery([
addToColumn('envelopes', 'budget', req.envelopeToId, -req.transferBudget),
addToColumn('envelopes', 'budget', req.envelopeToId, req.transferBudget)
])
next();
}catch(err){
next(err);
}
};
From what I can tell the rejection never get's caught anywhere and has something to do with passing the array of promises into the function. If the query succeeds then the batchQuery function works. It only fails when it fails to catch a database error. Any ideas? If it's not possible to work I can just write out the whole batchQuery every time I need it, but I would still like to understand why it isn't working.
Thanks in advance!
Edit: Here it is with the callback, it's now catching all errors as expected and works perfectly if everything succeeds. It also catches the error if one of the queries fails, but unfortunately it doesn't rollback when using the batchQuery function. I thought batch was supposed to take an array of promises to resolve, but the current method doesn't seem to quite work as I anticipated.
const transferEnvelopeBudgetByIds = async (req, res, next) => {
try{
req.updatedEnvelopes = await batchQuery(() =>
[
addToColumn('envelopes', 'budget', req.envelopeFromId, -req.transferBudget),
addToColumn('envelopes', 'budget', req.envelopeToId, req.transferBudget)
]);
next();
}catch(err){
next(err);
}
};
Edit 2: I have it working now using functions, but not quite with the batchQuery function. I now pass t as an optional argument into addToColumn and it works great.
const addToColumn = (tableName, columnName, entryId, amountToAdd, t) => {
let context = t;
if(context === undefined){
context = db;
}
return context.one('UPDATE ${table:name} SET ${column:name} = ${column:name} + ${amount:csv} WHERE id = ${id:csv} RETURNING *', {
table: tableName,
column: columnName,
amount: amountToAdd,
id: entryId
}).catch(err => handleQueryErr(err));
};
const transferEnvelopeBudgetByIds = async (req, res, next) => {
try{
req.updatedEnvelopes = await db.tx(t => {
return t.batch([
addToColumn('envelopes', 'budget', req.envelopeFromId, -req.transferBudget, t),
addToColumn('envelopes', 'budget', req.envelopeToId, req.transferBudget, t)
])
}).catch(err => handleTransactionErr(err));
next();
}catch(err){
next(err);
}
};
This should prevent the server from crashing due to an uncaught exception