runlot

@runlot/pg

env.db の上で、node-postgres に近い Pool・Client API を提供します。接続文字列は不要です。

env.db よりも node-postgres に近い API が必要な場合は、@runlot/pg を使用してください。

import { Pool } from "@runlot/pg";

export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const pool = new Pool({ db: env.db });
    const { rows } = await pool.query("select id, name from users where id = $1", [1]);
    return Response.json(rows);
  },
};

必要な設定は db だけです

new Pool({ db: env.db });
new Client({ db: env.db });

ホスト、ポート、パスワードの設定は不要です。node-postgres との互換性のために他のオプションキーも受け付けますが、使用しません。db を省略すると、次のエラーが表示されます。

@runlot/pg: `db` がありません — new Pool({ db: env.db }) で作成してください。

提供する機能

  • pool.query(text, values) — 呼び出しごとに新しいセッションを開きます。単一の SQL 文に適しています。
  • pool.connect() / new Client({ db }) — セッションを 1 つ開きます。BEGIN … COMMIT、prepared statement、SET の設定がセッション内で保持されます。使い終わったら release() または end() を呼び出してください。
  • エラーは DatabaseError として送出され、err.code で SQLSTATE を確認できます。
  • types.setTypeParser(oid, fn) で型変換を変更できます。既定値は pg と同じで、timestamptzdateDateint8numeric は文字列です。
import { Pool, DatabaseError } from "@runlot/pg";

const pool = new Pool({ db: env.db });
try {
  await pool.query("insert into users (email) values ($1)", [email]);
} catch (e) {
  if (e instanceof DatabaseError && e.code === "23505") {
    return new Response("このメールアドレスは既に登録されています", { status: 409 });
  }
  throw e;
}

トランザクション

const client = await pool.connect();
try {
  await client.query("begin");
  await client.query("update accounts set balance = balance - $1 where id = $2", [100, 1]);
  await client.query("update accounts set balance = balance + $1 where id = $2", [100, 2]);
  await client.query("commit");
} catch (e) {
  await client.query("rollback");
  throw e;
} finally {
  client.release();
}

pool.query() は呼び出しごとに新しいセッションを使うため、呼び出しをまたいでトランザクションは保持されません。トランザクションには必ず connect() を使用してください。

名前は Pool ですが、接続を再利用しません

Pool という名前とは異なり、コネクションプーリングは行いません。connect() を呼び出すたびに新しいエンジンセッションを開きます。理由はセッションを参照してください。

nodejs_compat なしで利用できます

このパッケージは Node の組み込みモジュールを import しません。EventEmitter の代わりに最小限の emitter を使用するため、このパッケージだけを使うワーカーには互換性フラグが不要です。

デプロイ時の設定

追加の設定は不要です。runlot deploy のバンドラーが pg の import をこのパッケージに解決します。ORM が Node の組み込みモジュールを使用する場合は nodejs_compat を自動的に有効にし、Prisma の WASM クエリコンパイラは別モジュールとしてマニフェストに含めます。

自分でバンドルする場合も、同じバンドラーを使用できます。

import { buildWorker } from "@runlot/pg/bundler";

const { code, report } = await buildWorker({ entry: "src/index.ts", absWorkingDir: process.cwd() });
// report.nodeImports が空でない場合は nodejs_compat が必要です。
// report.wasmModules は、デプロイに同梱する必要があるファイルです。

このページの目次