はじめに
こんにちは、エンジニア2年目のTKDSです!
前回はPGliteの概要・使い方・速度実験について記事にしました。
今回はさらに、PGliteへのSQLクライアントからの接続を可能とするpg-gatewayについて紹介し、活用例について示します。
復習:PGlite
PGliteは、PostgreSQLをWebAssembly(WASM)にコンパイルした軽量なデータベースエンジンです。
これにより、ブラウザ、Node.js、Bun、DenoなどでPostgresの機能を利用でき、開発者はローカルやサーバーレス環境でデータベース操作を行うことが可能です。
PGliteは、インメモリデータベースやファイルシステム(Node.jsやBun)、IndexedDB(ブラウザ)での永続化をサポートします。
pg-gateway
TypeScript library that implements the Postgres wire protocol from the server-side. It provides APIs you can hook into to handle authentication requests, queries, and other client messages yourself.
翻訳:サーバーサイドでPostgresのワイヤープロトコルを実装するTypeScriptライブラリです。このライブラリは、認証リクエスト、クエリ、およびその他のクライアントメッセージを自分で処理するためのAPIを提供します。
簡単にいうとこのライブラリは、データベースとやりとりするための仕組みをサーバー側で実現するものです。
これによって、簡単にPGliteへ外部のクライアントから接続できるようにしてくれます。
pg-gatewayとPGliteを起動してSQLクライアントから接続する
まずはpg-gatewayを使えるようにします。
# クローンする git clone https://github.com/supabase-community/pg-gateway.git # ビルドの設定があるディレクトリに移動 cd pg-gateway/packages/pg-gateway/ # 必要な依存関係のインストール npm install # ビルド npm run build # PGlite+pg-gateway用のディレクトリを作る # 元いたディレクトリに戻る cd - # ディレクトリの作成 mkdir -p pglite-with-gateway/lib cd pglite-with-gateway/lib # ビルド成果物のコピー cp ../../pg-gateway/packages/pg-gateway/dist/index.js ./ cp ../../pg-gateway/packages/pg-gateway/dist/index.mjs ./ cp ../../pg-gateway/packages/pg-gateway/dist/index.d.ts ./ # プロジェクトルートで初期化 npm init
生成されたpackage.jsonの中身を以下のように書き換えてください。
{ "name": "pglite-with-gateway", "version": "1.0.0", "description": "A project integrating PGlite with pg-gateway", "main": "src/app.js", "directories": { "lib": "lib" }, "scripts": { "start": "node src/app.js" }, "author": "", "license": "", "dependencies": { "pg-gateway": "file:./lib/index.js", }, "type": "module" }
PGliteのインストール
npm install @electric-sql/pglite
# dotenvのインストール npm install dotenv # pg-protocolのインストール npm install pg-protocol
準備が整ったので、コードを準備して起動していきます。
pg-gatewayのREADMEを参考にコードを書きます。
"use strict"; import net from "node:net"; import dotenv from "dotenv"; import { PGlite } from "@electric-sql/pglite"; import { PostgresConnection } from "../lib/index.mjs"; // 環境変数読み込み dotenv.config(); // PGliteのインスタンス作成 const pg = new PGlite(); // 平文パスワードでの認証処理 async function validateUserCredentials(credentials) { const { user, password } = credentials; const validUser = process.env.DB_USER; const validPassword = process.env.DB_PASSWORD; // ユーザー名とパスワードが一致するか確認 return user === validUser && password === validPassword; } // クライアントメッセージの処理 async function handleClientMessage(data, isAuthenticated, connection) { if (!isAuthenticated) { return false; } try { const [[_, responseData]] = await db.execProtocol(data); connection.sendData(responseData); } catch (err) { console.error("Error processing message:", err); connection.sendError(err); connection.sendReadyForQuery(); } return true; } // クライアント接続処理 function handleClientConnection(socket) { const connection = new PostgresConnection(socket, { serverVersion: "16.3 (PGlite 0.2.0)", authMode: "cleartextPassword", // 平文パスワード認証 validateCredentials: validateUserCredentials, onStartup: async () => { await db.waitReady; return false; }, onMessage: (data, { isAuthenticated }) => handleClientMessage(data, isAuthenticated, connection), }); socket.on("end", () => { console.log("Client disconnected"); }); socket.on("error", (err) => { console.error("Socket error:", err); }); } // サーバーの起動 function startServer() { const server = net.createServer(handleClientConnection); server.listen(5432, () => { console.log("Server listening on port 5432"); }); server.on("error", (err) => { console.error("Server error:", err); }); } // サーバーを開始 startServer();
pg-protocol関連でインポートできないエラーがでる場合があります。
エラーメッセージを確認し、node_modules内のファイルを書き換えてください。
作業が完了したら起動します。
npm start
別のターミナルを開いて接続します。
# psqlがない場合はインストールする sudo apt install -y postgresql-client # 接続 psql -h localhost -U postgres
以下のように繋がります。
これで、SQLクライアントからPGliteにアクセスすることが可能になりました!
まとめ
pg-gatewayを動かすまでについて解説しました。
情報が少なく、動かせるようになるまで苦労しました。
現時点で実用するには少し厳しいかなと感じました。これからに期待ですね!
(実はpg-gatewayを使ってGoからクエリ実行しようとしてできず、諦めました...。ログインができるのですがpg-gateway側で送信されたクエリを実行できず?)
ここまで読んでいただきありがとうございました!