コンテンツにスキップ

Node.js の基本

既存のテストに導入する場合は、実行できる quickstartから始められます。

@pgmem/core は pgmem バイナリを起動し、PostgreSQL の URL を渡してくれます。バイナリは npm がオプション依存としてインストールするプラットフォーム別パッケージに入っています。postinstall スクリプトはなく、実行時のダウンロードもありません。pgmem は PostgreSQL クライアントや ORM を置き換えるものではありません。Prisma、Drizzle、TypeORM、Kysely、pg、postgres は、ほかのサーバーと同じように URL へ接続するだけで、プールもそのまま使えます。

pgmem と、使っている公式クライアントを一緒にインストールします。

ターミナルウィンドウ
npm install --save-dev @pgmem/core pg

pg は node-postgres です。postgres.js、Prisma、Drizzle、TypeORM も同じように使えるので、アプリケーションで使っているものを入れてください。Node.js 20 以降が必要です。バイナリのパッケージは Linux と macOS の x64・arm64、Windows の x64・arm64 向けにあります。それ以外の環境では PGMEM_BINARY で cmd/pgmem のビルドを指定してください。

  1. サーバーを起動します。 PgmemServer.start() はバイナリを起動し、テンプレートのデータベースに対して prepare を実行し、その結果をスナップショットにします。フォークはそこから始まります。

    import { PgmemServer } from '@pgmem/core';
    const server = await PgmemServer.start({
    database: 'app',
    async prepare({ url }) {
    await migrate(url);
    await seed(url);
    },
    });
    console.log(server.url); // postgres://postgres@127.0.0.1:54321/app?sslmode=disable

    クライアントを閉じた後に await server.close() を呼びます。スクリプトでは finally を使ってください。明示的なリソース管理が使える環境では await using も選べます。ほかのオプションは user、params({ log_statement: 'all' } のような postgres の設定のオブジェクト)、maxForks、startupTimeoutMs、snapshotTimeoutMs、log、binary です。

  2. スキーマを登録します。 prepare の中で行います。prepare にはテンプレートのサーバー(url、host、port、user、database)が渡されます。マイグレーションツールを参照してください。

  3. シードデータを入れます。 これも prepare の中です。シードデータを参照してください。スナップショットは開いているトランザクションを待つので、prepare で開いた接続はすべて閉じるかコミットしてください。

  4. 公式クライアントから使います。

    import pg from 'pg';
    const pool = new pg.Pool({ connectionString: server.url });
    const { rows } = await pool.query('SELECT name FROM users WHERE id = $1', [1]);
    await pool.end();

    URL の sslmode=disable は残してください。pg は prefer と require を「TLS 必須」と扱いますが、pgmem には TLS がありません。

どのツールも URL を受け取ります。prepare の中で実行すれば、テンプレートに対して一度だけ走ります。

import { readFile } from 'node:fs/promises';
import pg from 'pg';
async function migrate(url: string) {
const client = new pg.Client({ connectionString: url });
await client.connect();
await client.query(await readFile('schema.sql', 'utf8'));
await client.end();
}

node-postgres はパラメータのないクエリを 1 回のシンプルクエリとして送るので、複数の文を書いてかまいません。

prisma migrate dev でマイグレーションを作る

Section titled “prisma migrate dev でマイグレーションを作る”

prisma migrate dev にはシャドウデータベースが必要です。pgmem のサーバーは持っているすべてのデータベースに接続できるので、Prisma は同じメモリ上のサーバーにシャドウデータベースを作ります。ローカルに PostgreSQL がなくてもマイグレーションを作れます。

scripts/migrate-dev.mjs
import { spawnSync } from 'node:child_process';
import { PgmemServer } from '@pgmem/core';
const server = await PgmemServer.start({ database: 'app', control: false });
try {
const run = spawnSync('npx', ['prisma', 'migrate', 'dev', ...process.argv.slice(2)], {
stdio: 'inherit',
env: { ...process.env, DATABASE_URL: server.url },
shell: process.platform === 'win32',
});
process.exitCode = run.status ?? 1;
} finally {
await server.close();
}
ターミナルウィンドウ
node scripts/migrate-dev.mjs --name add_posts
await client.query(await readFile('seed.sql', 'utf8'));
await server.withFork(async (fork) => {
console.log(fork.url);
// Create and close the application's clients inside this callback.
});

生きているフォークが maxForks 個あると、次のフォークは空きが出るまで待ちます。フォークを閉じても、アイドル状態のプール接続はプールに任されます。error リスナーのないプールでもプロセスが落ちることはありません。次のページでは、テストランナーからの使い方を紹介します。