env.db
워커에서 사용하는 데이터베이스 API입니다. exec, tryExec, session, identity를 제공합니다.
export interface Db {
exec(sql: string, params?: unknown[]): Promise<unknown[]>;
tryExec(sql: string, params?: unknown[]): Promise<TryExecResult>;
session(): Promise<DbSession>;
identity(): Promise<{ project: string; epoch: number }>;
}exec
성공하면 행 배열을 반환하고, SQL 실행에 실패하면 오류를 던집니다.
const rows = await env.db.exec(
"insert into posts (title) values ($1) returning id",
["hello"],
);바인딩 파라미터 번호는 $1부터 시작합니다. SQL 문자열을 이어 붙이지 말고 두 번째 인자로 파라미터를 전달하세요.
문장 하나에는 10초 상한이 있습니다. 넘으면 57014로 끊깁니다.
tryExec
오류를 던지지 않고 결과 객체를 반환합니다. SQLSTATE를 코드에서 안정적으로 확인하려면 이 API를 사용하세요.
const r = await env.db.tryExec("insert into users (email) values ($1)", [email]);
if (!r.ok) {
if (r.error.code === "23505") return new Response("이미 있는 이메일입니다", { status: 409 });
throw new Error(r.error.message);
}성공한 결과의 형식은 다음과 같습니다.
{
ok: true,
columns: [{ name: "id", typeOid: 23 }],
values: [[1]], // 위치 기반 배열: 같은 열 이름이 있어도 값을 보존합니다
rows: [{ id: 1 }],
commandTag: "SELECT 1",
transactionStatus: "I",
}실패한 결과의 형식은 다음과 같습니다.
{
ok: false,
error: { code: "23505", message: "…", detail: null, hint: null, position: null, severity: "ERROR" },
}exec가 던지는 Error에는 .code 속성이 없습니다. 워커 경계를 통과하는 오류 객체에서는 사용자 정의 속성이 보존되지 않기 때문입니다. 오류 메시지 앞에는 [42P01]처럼 SQLSTATE를 넣지만, 프로그램에서 사용해야 하는 값은 tryExec(...).error.code입니다. @runlot/pg를 사용하면 워커 내부 JavaScript에서 처리하므로 err.code를 사용할 수 있습니다.session
BEGIN … COMMIT처럼 여러 SQL 문이 같은 세션에서 실행되어야 할 때 사용합니다.
const s = await env.db.session();
try {
await s.exec("begin");
await s.exec("update accounts set balance = balance - $1 where id = $2", [100, 1]);
await s.exec("update accounts set balance = balance + $1 where id = $2", [100, 2]);
await s.exec("commit");
} finally {
await s.close();
}close()는 여러 번 호출해도 안전하며, 열려 있는 트랜잭션은 롤백합니다. 커밋하려면 close()에 의존하지 말고 직접 COMMIT을 보내야 합니다. 자세한 내용은 세션을 참고하세요.
identity
현재 요청이 연결된 프로젝트와 데이터베이스 세대 번호를 반환합니다. 디버깅과 로그 기록에 사용할 수 있습니다.
const { project, epoch } = await env.db.identity();SQL 값이 JavaScript로 변환되는 방식
값을 조용히 손실하지 않는 것을 원칙으로 합니다.
| SQL 타입 | JavaScript 값 |
|---|---|
int2 int4 float4 float8 | number |
int8 numeric | string — number로 변환하며 반올림하지 않음 |
bool | boolean |
text varchar uuid | string |
bytea | ArrayBuffer |
json jsonb | 파싱한 값. 파싱에 실패하면 원본 문자열 |
timestamp timestamptz date | string — 시간대와 정밀도를 보존 |
| 배열, 도메인, 확장 타입 | { text, typeOid } 또는 string |
표에 없는 타입은 문자열로 반환합니다. 기본 타입을 추측해서 변환하지 않습니다.
timestamptz의 문자열은 PostgreSQL 표기(2026-09-04 13:38:14+00)입니다. 브라우저의 new Date()가 이 모양을 모든 곳에서 읽지는 못합니다(Safari는 Invalid Date). ISO 8601이 필요하면 SQL에서 to_json(col)을 씌우거나 @runlot/pg를 쓰세요.
timestamptz와 date가 Date 객체로 반환됩니다. 두 API의 날짜 타입이 다르다는 점에 유의하세요.