Skip to main content

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;
}[];
}[];
}[]