Skip to content

Query @ydbjs/query

High-level, type-safe client for YQL queries and transactions.

This is the high-level overview of the @ydbjs/query client. For details, continue with:

Quick Start

ts
import { Driver } from '@ydbjs/core'
import { query } from '@ydbjs/query'

const driver = new Driver('grpc://localhost:2136/local')
await driver.ready()

const sql = query(driver)
const rows = await sql`SELECT 1 + 1 AS sum`
console.log(rows)

Examples

Parameters and AS_TABLE

ts
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
]
await sql`INSERT INTO users SELECT * FROM AS_TABLE(${users})`

Named parameters

ts
await sql`SELECT * FROM users WHERE id = $id`.parameter('id', 42)

Collecting stats

ts
import { StatsMode } from '@ydbjs/api/query'

const q = sql`SELECT * FROM users`.withStats(StatsMode.FULL)
q.on('stats', (s) => console.log('Stats:', s))
await q

Result formats

ts
// Array of values (column order)
const vals = await sql`SELECT 1 AS a, 2 AS b`.values()
console.log(vals) // [ [1, 2] ]

// Raw TypedValue
const raw = await sql`SELECT 1`.raw()

Per-call isolation

ts
await sql`SELECT * FROM users`
  .isolation('snapshotReadOnly')
  .timeout(3000)

Error handling

ts
import { YDBError } from '@ydbjs/error'

try {
  await sql`SELECT * FROM non_existent`
} catch (e) {
  if (e instanceof YDBError) {
    console.error('YDB error code:', e.code)
  }
}

Dynamic identifiers and unsafe fragments

ts
// Safe dynamic table/column names
const table = sql.identifier('users')
const column = sql.identifier('created_at')
const rows = await sql`SELECT ${column} FROM ${table} WHERE id = ${42}`

// Unsafe fragments for trusted code only (migrations, DDL)
await sql`PRAGMA TablePathPrefix(${sql.unsafe('/Root/dev')});`

Query events and retries

ts
import { StatsMode } from '@ydbjs/api/query'

const q = sql`SELECT * FROM heavy_table`
  .idempotent(true)
  .withStats(StatsMode.FULL)

q.on('retry', (ctx) => console.log('retry attempt', ctx.attempt, ctx.error))
q.on('stats', (s) => console.log('cpu(us)=', s.queryPhaseStats?.cpuTimeUs))
await q

Cancellation and timeouts

ts
const ac = new AbortController()
setTimeout(() => ac.abort('user cancelled'), 1000)

await sql`SELECT pg_sleep(10)`
  .timeout(5000)
  .signal(ac.signal)

Isolation modes

ts
// Snapshot read-only single-call transaction
await sql`SELECT COUNT(*) FROM users`.isolation('snapshotReadOnly')

// Online read-only with inconsistent reads allowed
await sql`SELECT COUNT(*) FROM users`
  .isolation('onlineReadOnly', { allowInconsistentReads: true })

Syntax and pool

ts
import { Syntax } from '@ydbjs/api/query'

await sql`SELECT 1`.syntax(Syntax.YQL_V1)
await sql`SELECT 1`.pool('analytics')

Transaction hooks

ts
const result = await sql.begin(async (tx, signal) => {
  tx.onCommit(() => console.log('committing tx', tx.transactionId))
  tx.onRollback((err) => console.log('rolling back tx', err))

  await tx`UPSERT INTO audit(id, ts) VALUES (${1}, CurrentUtcDatetime())`
  return await tx`SELECT * FROM audit WHERE id = ${1}`
})