Adapters
The same QuerySchema can drive Drizzle, Kysely, raw SQL, and TanStack DB adapters.
Raw SQL (PostgreSQL)
Section titled “Raw SQL (PostgreSQL)”import { toSql } from 'agnostic-query/sql/pg'
const { sql, params } = toSql({ table: 'users', ...schema,})!// → sql: SELECT * FROM "users" WHERE "age" >= ? AND "status" IN (?, ?) ORDER BY "name" ASC LIMIT 20 OFFSET 0// → params: [18, 'active', 'pending']Or compose parts yourself using toSqlWhere / toSqlOrderBy for partial queries.
Drizzle
Section titled “Drizzle”One-shot with toDrizzle:
import { toDrizzle } from 'agnostic-query/drizzle/pg'
const rows = await toDrizzle<User>(db, userTable, data)Or compose manually:
import { toDrizzleWhere, toDrizzleOrderBy } from 'agnostic-query/drizzle/pg'import { and, eq } from 'drizzle-orm'
const conditions = [ toDrizzleWhere(schema.user, data.where), eq(schema.user.orgId, currentOrgId),].filter(Boolean)
const rows = await db .select() .from(schema.user) .where(and(...conditions)) .orderBy(...toDrizzleOrderBy(schema.user, data.orderBy)) .limit(data.limit ?? 50) .offset(data.offset ?? 0)Kysely
Section titled “Kysely”Extract schema from a Kysely query:
import { fromKysely } from 'agnostic-query/kysely/pg'
const query = db .selectFrom('user') .selectAll() .where('age', '>=', 18) .where('status', 'in', ['active', 'pending']) .orderBy('name', 'asc') .limit(20)
const schema = fromKysely(query)JSON.stringify(schema) // send to clientApply schema to a Kysely query:
import { toKyselyWhere, toKyselyOrderBy } from 'agnostic-query/kysely/pg'
let query = db.selectFrom('user').selectAll()
if (schema.where) query = query.where(toKyselyWhere(schema.where))if (schema.orderBy) query = toKyselyOrderBy(query, schema.orderBy)if (schema.limit) query = query.limit(schema.limit)if (schema.offset) query = query.offset(schema.offset)
const users = await query.execute()TanStack DB
Section titled “TanStack DB”Convert TanStack DB expressions into agnostic-query format:
import { fromTanDbWhere, fromTanDbOrderBy, fromTanDb } from 'agnostic-query/tanstack-db'
// Manual compositionconst data = { where: newWhere(fromTanDbWhere(where)) .where(fromTanDbWhere(cursor?.whereFrom)) .toJSON(), orderBy: fromTanDbOrderBy(orderBy),}
// Convenience — handles where, cursor, limit, orderBy in one callconst data = fromTanDb(meta?.loadSubsetOptions)Execute a QuerySchema as parameterised SQL. toDb0 accepts any driver with a { prepare, all } interface — not just db0. Bun SQLite, better-sqlite3, and others also work.
import { toDb0 } from 'agnostic-query/db0/pg'import type { Db } from 'agnostic-query/db0/types'
// db0, Bun SQLite, better-sqlite3, node:sqlite, etc.const rows = await toDb0(db, schema)The Db type is exported for use in your own signatures:
import type { Db } from 'agnostic-query/db0/types'
function run<D extends Db>(db: D, sql: string) { ... }Use agnostic-query/db0/pg for PostgreSQL-flavored SQL, or agnostic-query/db0/sqlite for SQLite-flavored SQL with json_extract support.