TypeScript¶
Backends: typescript-postgres (postgres.js), typescript-pg (node-postgres) | Engine: PostgreSQL
Both backends share the same type mappings and TypeScript interfaces. They differ in query execution.
SQL input¶
-- @name GetUser
-- @returns :one
SELECT id, name, email, created_at FROM users WHERE id = $1;
-- @name ListUsers
-- @returns :many
SELECT id, name FROM users ORDER BY name LIMIT $1;
-- @name CreateUser
-- @returns :exec
INSERT INTO users (name, email) VALUES ($1, $2);
Schema:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Generated code -- shared interfaces¶
export interface GetUserRow {
id: number;
name: string;
email: string | null;
createdAt: Date;
}
export interface ListUsersRow {
id: number;
name: string;
}
Note: field names use camelCase per the manifest naming convention.
postgres.js¶
Uses tagged template literals for query parameterization.
:one¶
import postgres from "postgres";
export async function getUser(
sql: postgres.Sql,
id: number
): Promise<GetUserRow> {
const [row] = await sql<GetUserRow[]>`
SELECT id, name, email, created_at
FROM users WHERE id = ${id}
`;
return row;
}
:many¶
export async function listUsers(
sql: postgres.Sql,
limit: number
): Promise<ListUsersRow[]> {
return await sql<ListUsersRow[]>`
SELECT id, name FROM users ORDER BY name LIMIT ${limit}
`;
}
:exec¶
export async function createUser(
sql: postgres.Sql,
name: string,
email: string | null
): Promise<void> {
await sql`
INSERT INTO users (name, email) VALUES (${name}, ${email})
`;
}
pg (node-postgres)¶
Uses $N positional parameters with client.query().
:one¶
import { Client } from "pg";
export async function getUser(
client: Client,
id: number
): Promise<GetUserRow> {
const { rows } = await client.query<GetUserRow>(
"SELECT id, name, email, created_at FROM users WHERE id = $1",
[id]
);
return rows[0];
}
:many¶
export async function listUsers(
client: Client,
limit: number
): Promise<ListUsersRow[]> {
const { rows } = await client.query<ListUsersRow>(
"SELECT id, name FROM users ORDER BY name LIMIT $1",
[limit]
);
return rows;
}
:exec¶
export async function createUser(
client: Client,
name: string,
email: string | null
): Promise<void> {
await client.query(
"INSERT INTO users (name, email) VALUES ($1, $2)",
[name, email]
);
}
Enum generation¶
Type mappings¶
| SQL Type | Neutral | TypeScript |
|---|---|---|
SERIAL / INTEGER |
int32 |
number |
BIGINT |
int64 |
number |
TEXT / VARCHAR |
string |
string |
BOOLEAN |
bool |
boolean |
BYTEA |
bytes |
Buffer |
UUID |
uuid |
string |
NUMERIC |
decimal |
string |
DATE / TIME |
date / time |
string |
TIMESTAMPTZ |
datetime_tz |
Date |
INTERVAL |
interval |
string |
JSON / JSONB |
json |
Record<string, unknown> |
TEXT[] |
array<string> |
string[] |
| nullable column | nullable |
T \| null |