-- a maintained fork of Zapatos 6.6.1
Your types, cast from your database::
pgcast reads your Postgres schema and writes the TypeScript types. Its shortcuts produce SQL you can read and predict, and you can always drop down to a plain sql template. No ORM, no models, no hidden state.
npm install zapatos@npm:@pgcast/pgcastTSYou write
ts
const films = await db.select('films', db.all, {
lateral: {
cast: db.select('roles', {
film_id: db.parent('id'),
}, {
order: { by: 'billing', direction: 'ASC' },
}),
},
}).run(pool);SQLPostgres runs
sql
SELECT coalesce(jsonb_agg(result), '[]') AS result
FROM (
SELECT to_jsonb("films".*) ||
jsonb_build_object($1::text, "lateral_cast".result) AS result
FROM "films"
LEFT JOIN LATERAL (
SELECT coalesce(jsonb_agg(result), '[]') AS result
FROM (
SELECT to_jsonb("roles".*) AS result
FROM "roles"
WHERE ("film_id" = "films"."id")
ORDER BY "billing" ASC
) AS "sq_roles"
) AS "lateral_cast" ON true
) AS "sq_films"
values ["cast"]
::TypeScript knows
ts
const films: (films.JSONSelectable & db.LateralResult<{
cast: db.SQLFragment<roles.JSONSelectable[], never>;
}>)[]
// that is
const films: {
genres: string[];
id: number;
release_year: number;
runtime_minutes: number;
studio_id: number;
tagline: string | null;
title: string;
cast: roles.JSONSelectable[];
}[]
Films with their cast, in one query and one round trip.Hover a dashed name to see its type.
Postgres is the source
Types come from pg_catalog, never written by hand. Change a column, regenerate, and the compiler finds every query that broke.
SQL you can read
Each shortcut writes one documented query. Log it, test it, or write it yourself in a sql template.
Values are parameters
Values travel as $1, $2. Names are quoted as Postgres quotes them, so a stray " cannot change your query.
Live playground
Write a query and see its SQL and its type as you type. Press Run, and a real Postgres answers, in your browser.