AJ_
AJ_

Reputation: 3987

JS - Knex, Pass function to Transaction

I created a node.js application that uses the knex library to make database operations. The database is Microsoft SQL Server. I created a script called db.js that returns the knex object, and i have a controller.js script that makes the actually needed database operations. I have all the operations wrapped inside a translation statement, which brings me to my question. What i would like to do, is pass in a parameter that tells the transaction to rollback or commit. However, whenever i try to pass this function in, it just fails. Does anyone know if this feature achievable ? I was able to do this feature with the catch function.

I don't think its db specific, so anyone can download knex, hook it up a db and give it a shot with the code below.

example.js

/**
 * @param {userID} Int 
 * @param {rollback} Boolean 
 */
const getUsers = (userID, rollback) => {
    // Using tran as a transaction object:
    return db('master').transaction((tran) => {
        db('master')
        .select()
        .from('users')
        .where({ 'user_id': userID })
        .transacting(tran)
        .then(tran.rollback) // Works
        // .then(transact(tran, rollback)) throws error 
        .catch((error) => {
            logError(error, tran); // Works 
        });
        // .catch(tran.rollback);
    });
};
const logError = (error, transaction) => {
    transaction.rollback; 
    console.log('transaction error: ',error);
    console.log('transaction log: ',transaction);
};
const transact = (transaction, rollback) => {
    try {
        if (rollback) return transaction.rollback; 
        else return transaction.commit;
    } catch (error) {
        console.log(error); 
    }
}; 
const user = await getUsers(1, true); // error is thrown
assert.strictEqual(user.constructor === Array, true);
assert.strictEqual(user.length == 0, true);

Error Message

Error: the array [   {
    "user_id": 1
    "user_name": "JonnyBoy"
    "zip": 1200
    "email": "[email protected]"
  } ] was thrown, throw an Error :)

Upvotes: 0

Views: 1154

Answers (1)

Daniel Rearden
Daniel Rearden

Reputation: 84687

then takes a function as its first parameter. If the Promise resolves, the function that's passed to then is called with the value the Promise resolved to. The rollback property on the transaction object is a function so you can write:

someQuery().then(trans.rollback)

and rollback will be called when someQuery resolves. You could also write:

someQuery.then(result => trans.rollback(result))

These statements are equivalent.

That said, minimally, there's two changes that you need to make. One, fix how you're calling transact. For example:

.then(() => transact(tran, rollback))

And change how transact calls rollback:

const transact = (trx, rollback) => {
  const action = rollback ? trx.rollback : trx.commit
  return action()
}

Also bear in mind that rollback itself will return a rejected Promise with a generic error. You can pass a custom error to rollback and it will reject with that error instead.

Upvotes: 1

Related Questions