Quick start
Two commands and one file to go from zero to typed queries.
1. Generate a typed schema
pnpm exec biref gen \
--url postgres://user:pass@localhost/mydb \
--all-namespaces
This connects to the live database, scans every non-system schema, and emits a BirefSchema type at ./biref/biref.schema.ts.
2. Scan and query
Postgres
import pg from 'pg';
import { Biref, postgresAdapter } from '@biref/scanner';
import type { BirefSchema } from './biref/biref.schema';
const client = new pg.Client({ connectionString: 'postgres://localhost/mydb' });
await client.connect();
const biref = Biref.builder()
.withAdapter(postgresAdapter.create(client))
.build();
const model = await biref.scan({ namespaces: 'all' });
const rows = await biref
.query<BirefSchema>(model)
.public.users
.select('id', 'email')
.where('status', 'eq', 'active')
.include('orders', (order) =>
order
.select('id', 'total')
.include('order_items', (item) => item.select('variant_id', 'quantity')),
)
.findMany();
MySQL
import mysql from 'mysql2/promise';
import { Biref, mysqlAdapter } from '@biref/scanner';
import type { BirefSchema } from './biref/biref.schema';
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'secret',
database: 'mydb',
});
const biref = Biref.builder()
.withAdapter(mysqlAdapter.create(connection))
.build();
const model = await biref.scan();
const rows = await biref
.query<BirefSchema>(model)
.mydb.users
.select('id', 'email')
.where('is_active', 'eq', 1)
.include('orders', (order) => order.select('id', 'total'))
.findMany();
What you get
Every .select(), .where(), .include() call narrows both its input and its return type based on the live schema. The return type of rows above is fully typed:
readonly {
readonly id: bigint;
readonly email: string;
readonly orders: readonly {
readonly id: bigint;
readonly total: string;
readonly order_items: readonly {
readonly variant_id: number;
readonly quantity: number;
}[];
}[];
}[]