Skip to main content
zerotal

Documentation


Documentation / @zerotal/orm / index / DB

Variable: DB

const DB: object

Defined in: packages/orm/src/db/DB.ts:169

The DB facade — the entry point for database access outside the model layer.

Bundles table queries, raw SQL, transactions, replica routing and N+1 detection over the connection resolved for the current call site. Connection resolution is context-aware: inside a DB.transaction callback every query automatically uses the transaction connection (via TransactionContext AsyncLocalStorage), and when read replicas are configured, reads route to a replica while writes and transactions go to the primary.

Type Declaration

Connections

onPrimary()

onPrimary(): object

Return a query builder scoped to the primary connection, bypassing the replica pool entirely.

Use this for read-your-writes scenarios — when you need to query data immediately after a mutation and cannot wait for replication lag.

Returns

object

table()

table(name): QueryBuilder

Parameters
name

string

Returns

QueryBuilder

Example
await DB.table('orders').insert({ total: 99 });

// Read the just-inserted row from primary, not a potentially-lagging replica:
const order = await DB.onPrimary().table('orders').where('id', id).first();

advisoryLock()

advisoryLock<T>(key, callback): Promise<T>

Acquire a database advisory lock for the duration of a callback. The lock is released automatically when the callback resolves or rejects.

Dialect-aware: pg_advisory_lock() on PostgreSQL, GET_LOCK() on MySQL. Throws UnsupportedDialectError (E_UNSUPPORTED_DIALECT) on SQLite, which has no advisory-lock primitive.

Type Parameters
T

T

Parameters
key

number

Integer lock key (application-defined).

callback

() => Promise<T>

Work to perform while the lock is held.

Returns

Promise<T>

Throws

On SQLite (no advisory-lock primitive).

Queries

raw()

raw<T>(sql, ...rest): Promise<T[]>

Execute raw SQL.

Tagged-template form (parameterized, safe): await DB.rawSELECT * FROM users WHERE id = ${id}

String form (splits on ? placeholders, same safety): await DB.raw('SELECT * FROM users WHERE id = ?', [id]) await DB.raw('SELECT 1 + 1 AS n')

Type Parameters
T

T = Record<string, unknown>

Parameters
sql

string | TemplateStringsArray

rest

...unknown[]

Returns

Promise<T[]>

preventNPlusOne()

preventNPlusOne(options?): void

Configure N+1 query detection.

Detection is automatically active in local and development environments (warn mode, threshold 5). Call this to change the threshold, switch to 'throw' mode, or enable detection in other environments.

Parameters
options?

NPlusOneOptions

Returns

void

Example
// bootstrap/app.ts
DB.preventNPlusOne({ threshold: 3, mode: 'throw' });

allowNPlusOne()

allowNPlusOne(pattern, options?): void

Suppress N+1 warnings for queries containing pattern as a substring.

Parameters
pattern

string

A table name or any substring of the SQL shape.

options?

{ once: true } suppresses only for the current request.

once?

boolean

Returns

void

Example
DB.allowNPlusOne('activity_logs');              // all requests
DB.allowNPlusOne('taggings', { once: true });   // this request only

Tables

table()

table(tableName): QueryBuilder

Start a chainable QueryBuilder against a table on the current connection.

Parameters
tableName

string

Returns

QueryBuilder

Transactions

transaction()

transaction<T>(callback, attempts?): Promise<T>

Run a callback inside a database transaction.

All BaseModel and DB queries made within the callback automatically use the transaction connection via AsyncLocalStorage (TransactionContext). Works in any environment — request handlers, console commands, seeders.

Bun auto-commits on resolve and auto-rolls-back on throw. NEVER call tx.commit() or tx.rollback() manually.

Nested calls use a SAVEPOINT so an inner rollback does not abort the outer transaction. Pass attempts > 1 to automatically retry on deadlock / serialization failures.

Type Parameters
T

T

Parameters
callback

(tx?) => Promise<T>

Work to run inside the transaction.

attempts?

number = 1

Max attempts on deadlock-like errors (default 1 = no retry).

Returns

Promise<T>

beginTransaction()

beginTransaction(): Promise<ManualTransaction>

Begin a transaction with manual commit/rollback control. Run queries via the returned handle (handle.sql or handle.table()), then call handle.commit() or handle.rollback().

Prefer DB.transaction(cb) for automatic commit/rollback — this is for the rarer cases where the transaction boundary cannot be expressed as a callback.

Returns

Promise<ManualTransaction>

Example
const t = await DB.beginTransaction();
try {
  await t.table('accounts').where('id', 1).decrement('balance', 100);
  await t.commit();
} catch (e) { await t.rollback(); throw e; }

currentTx()

currentTx(): unknown

Return the active transaction connection (from the ALS transaction context or the legacy request-scoped transaction), or undefined when none is open.

Returns

unknown

Example

// Raw SQL (parameterised)
const rows = await DB.raw`SELECT * FROM users WHERE id = ${id}`;

// Fluent query builder
const active = await DB.table('users').where('active', true).get();

// Transaction — all queries inside use the tx connection automatically
await DB.transaction(async () => {
  await DB.table('accounts').where('id', 1).decrement('balance', 100);
  await DB.table('accounts').where('id', 2).increment('balance', 100);
});