Postgres Node.js Transaction
The Transaction
object represents a transaction happening on a single physical connection to the underlying database. You can use it to execute queries, or start "nested transactions". Depending on the isolationLevel
you specified when creating the Transaction
, you can get varying levels of guarantee about how well isolated your transactions are, but you can always guarantee that all your changes will either be "committed" or "rolled back" at the end. Your database will never be left in an inconsistent state.
Transaction.query(SQLQuery): Promise<any[]>
Run an SQL Query and get a promise for an array of results. If your query contains multiple statements, only the results of the final statement are returned.
const result = await task.query(sql`SELECT 1 + 1 AS a`);
result[0].a;
// => 2
N.B. if a query throws an error, that transaction will become unusable. If you need to run a query that might error (e.g. selecting from a table that may or may not exist), you can wrap the query in a nested transaction to keep the error localised.
Transaction.query(SQLQuery[]): Promise<any[]>
If you pass an array of SQLQueries, you will get an array in response where each element of the array is the results of one of the queries.
const [resultA, resultB] = await task.query([
sql`SELECT 1 + 1 AS a`,
sql`SELECT 1 + 1 AS b`,
]);
resultA[0].a + resultB[0].b;
// => 4
Transaction.queryStream(SQLQuery): AsyncIterable<any>
Run an SQL Query and get an async iterable of the results. e.g.
for await (const record of db.queryStream(sql`SELECT * FROM massive_table`)) {
console.log(result);
}
Transaction.queryNodeStream(SQLQuery): ReadableStream
Run an SQL Query and get a node.js readable stream of the results. e.g.
const Stringifier = require('newline-json').Stringifier;
db.queryNodeStream(sql`SELECT * FROM massive_table`)
.pipe(new Stringifier())
.pipe(process.stdout);
Transaction.tx<T>(fn: (tx: Transaction) => Promise<T>, options?): Promise<T>
Executes the callback fn
within a "nested transaction" on that connection.
A nested transaction wraps a regular transaction with 3 additional queries:
it executes
SAVEPOINT unique_id
just before invoking the callback functionit executes
ROLLBACK TO SAVEPOINT unique_id
, if the callback throws an error or returns a rejected promiseit executes
RELEASE SAVEPOINT unique_id
, if the callback does throw any error and does not return a rejected promise
const result = await db.task(async (db) => {
const resultA = await db.query(sql`SELECT 1 + 1 AS a`);
const resultB = await db.query(sql`SELECT 1 + 1 AS b`);
return resultA[0].a + resultB[0].b;
});
// => 4
Transaction.task(fn): Promise<T>
This method exists to mimic the API in ConnectionPool.task
. It does not allocate a fresh connection or transaction, and simply returns fn(this)
.
Transaction.addPostCommitStep(fn): Promise<void>
Queue fn
to be called after the top-level transaction is successfully committed. If this transaction is nested inside another transaction, fn
will not be called until the outer most transaction has been committed. This can be used to clear caches after updating values.