Rado GitHub

Prepared statements

Queries with named placeholders can be prepared once and executed many times with different inputs. This skips query construction and, on drivers that support it, reusing the database's prepared statement.

Placeholders + prepare

import {eq, sql} from 'rado'

const userByName = db
  .select()
  .from(User)
  .where(eq(User.name, sql.placeholder('name')))
  .prepare('userByName')

const ada = await userByName.execute({name: 'Ada'})
const grace = await userByName.execute({name: 'Grace'})

sql.placeholder(name) marks a named input; prepare(name?) turns the query into a PreparedQuery. The name is forwarded to drivers that use named statements (PostgreSQL, MySQL); SQLite drivers prepare by statement text.

A prepared query exposes the usual executors:

await userByName.all({name: 'Ada'}) // Array<Row>
await userByName.get({name: 'Ada'}) // Row | undefined
await userByName.run({name: 'Ada'}) // void
await userByName.execute({name: 'Ada'})
userByName.free() // release the underlying statement when done

Missing an input? You get an error naming the missing placeholder rather than a silent null.

Placeholders anywhere

Placeholders work wherever values do: conditions, limits and inserted values.

const page = db
  .select()
  .from(Post)
  .orderBy(desc(Post.createdAt))
  .limit(sql.placeholder('pageSize'))
  .offset(sql.placeholder('offset'))
  .prepare('page')

await page.all({pageSize: 10, offset: 20})

One-off execution with inputs

You don't have to prepare to use placeholders. execute(inputs) works on any query:

await db
  .select()
  .from(User)
  .where(eq(User.name, sql.placeholder('name')))
  .execute({name: 'Ada'})

Inspecting generated SQL

Every query can show you what it compiles to:

const {sql: text, params} = db.select().from(User).where(eq(User.id, 1)).toSQL()

// text: 'select "user"."id", "user"."name", ... from "user" where "user"."id" = $1'
// params: [1]

Without a database argument toSQL() uses the dialect the query was built for; you can also pass a database to emit for its dialect. Useful for logging, debugging, snapshot tests and satisfying healthy curiosity.