Skip to content

Transactions

Pulsabase SDKs support database transactions, allowing you to execute multiple queries as a single, atomic operation.

If any query within the transaction fails, the entire transaction is rolled back, ensuring your database remains in a consistent state. If all queries succeed, the transaction is committed.

Transactions in Pulsabase are built using the pb.transaction() method. You construct your individual queries using the standard query builder methods prefixed with build (e.g., buildInsert, buildUpdate, buildDelete), extract the raw JSON requests using .toPayload(), and pass them as an array to the transaction executor.

import pb from 'pulsabase';
try {
// Execute an atomic transaction
const results = await pb.transaction([
pb.from('accounts').where('id', '=', 1).buildUpdate({ balance: 50 }).toPayload(),
pb.from('accounts').where('id', '=', 2).buildUpdate({ balance: 150 }).toPayload(),
pb.from('audit_logs').buildInsert({ action: 'transfer', amount: 50 }).toPayload()
]);
console.log('Transaction succeeded!', results);
} catch (error) {
console.error('Transaction failed and was rolled back:', error);
}

Transactions in Pulsabase support a wide range of atomic operations. The transaction executor in the Core engine uses the exact same execution paths as standalone queries.

  • buildInsert(payload).toPayload(): Inserts one or more records. Returns the inserted records with generated fields (like id and created_at).
  • buildUpdate(payload).toPayload(): Updates records matching a .where() condition. Returns the updated records.
  • buildDelete().toPayload(): Deletes records matching a .where() condition. Returns the deleted records.
  • buildUpsert(payload, onConflict).toPayload(): Inserts new records or updates existing ones automatically if a conflict occurs on specific columns (PostgreSQL ON CONFLICT DO UPDATE).
  • buildBulkUpdate(instructions).toPayload(): Executes multiple different updates in a single core operation using an instruction array.
  • buildBulkDelete(instructions).toPayload(): Executes multiple different deletes using varied filters in a single core operation.

While transactions are primarily used for atomic writes, you can include read queries to ensure they are executed against the exact same data snapshot:

  • buildFind().toPayload(): Selects multiple rows inside the transaction snapshot.
  • buildFindOne().toPayload(): Selects a single row inside the transaction snapshot.

Note: Complex nested relation insertion (insertWith) is currently not supported inside transaction arrays. Real-time publication events are emitted only after the database transaction is successfully committed.