Search code examples
javascriptnode.jsasync-awaitpg-promise

Pg-promise - Reusable queries that may participate in a transaction/task


I am trying to achieve a reuse pattern where query functions may receive a parameter trx=tx/task if they are participating in an existing transaction/task, and reuse that tx/task context... otherwise if trx=undefined passed in, creates a new task for the queries. The idea is for the function to be agnostic of whether it is being used singularly, or is participating in a higher-order block transaction.

What I desire (ideally) is a promise-function that will return a task context so that I can write clean like the following (which doesn't work):

async function trxRunQueries(trx:ITask<any>|undefined = undefined):Promise<any[]>
{
  if(!trx)
    trx=await db.task(); // if !trx then create new task context from db

  const dataset1 = await trx.many(`select * from tableA`);
  const dataset2 = await trx.many(`select * from tableB`);
  return [dataset1,dataset2];

}

However seems like db.task() needs to execute the contextual queries in the cb parameter, but it leaves me hanging & wondering how I can achieve the desired pattern without writing the code out twice -- once with db.task(trx => ) wrapper, and another executing trx.many(...) directly.

I was wondering if it is ok to do something hacky, like below, to achieve this pattern of participating-optionally-in-a-transaction, and will it work (or is it really not a recommended way of doing things) -- or is there a better way that I am not thinking of?

async function runQueries(trx:ITask<any>):Promise<any[]>
{
  const dataset1 = await trx.many(`select * from tableA`);
  const dataset2 = await trx.many(`select * from tableB`);
  return [dataset1,dataset2];
}

async function trxRunQueries(trx:ITask<any>|undefined = undefined ):Promise<any[]>
{
  let result:any[]=[];
  try {
    // If trx not passed in the create task context
    if(!trx)
      await db.task(async trx => {result=await runQueries(trx)})
    else
      result=await runQueries(trx);
    return result;
  }
  catch (err) {
    throw(err);
  }
}

Solution

  • Such pattern is implemented by pg-promise-demo, which uses event extend to extend the database protocol with context-agnostic entity repositories.