0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BunのPostgreSQLアクセス機能を使った簡易なSQLクライアント

Last updated at Posted at 2025-04-04

概要

BunでデフォルトとなったPostgreSQLアクセス機能を使った簡単なSQLクライアントを作成してみたので、備忘のため作成

プロジェクトの作成手順

# 適当な作業ディレクトリを作成してプロジェクトを初期化
mkdir bun-sql-client
cd bun-sql-client

# Bun初期化(Blankで作成)
bun init

# types/bunを追加
bun add -D @types/bun

SQLクライアントコード

DBへの接続情報と、SQLファイルを指定して実行します。
コードの9割は、Geminiさんが作ってくれましたw

sql-client.ts

import { SQL } from "bun";
import fs from "node:fs/promises";

async function main() {
  // 引数の数をチェック (実行ファイルパスを含めて8つ必要)
  if (process.argv.length !== 8) {
    console.error(
      "Usage: bun sql-client.ts      "
    );
    process.exit(1);
  }

  // コマンドライン引数を取得 (Non-null assertion operator (!) を使用)
  const [_, __, host, portStr, database, user, password, sqlFilePath] =
    process.argv;
  const port = parseInt(portStr!, 10); // portStrがundefinedでないことを示す

  // NaNチェックを追加
  if (isNaN(port)) {
    console.error("Invalid port number provided.");
    process.exit(1);
  }

  let db: SQL | undefined;

  try {
    // PostgreSQLに接続 (bun:postgresを使用)
    db = new SQL({
      hostname: host!,
      port: port,
      database: database!,
      user: user!, // 'username'ではなく'user'を使用
      password: password!,
      // 必要に応じて他の接続オプションを追加
    });

    console.log("Connected to PostgreSQL using bun:postgres");

    // SQLファイルを読み込む (sqlFilePathがundefinedでないことを示す)
    const sqlQuery = await fs.readFile(sqlFilePath!, "utf-8");
    console.log(`Executing SQL from: ${sqlFilePath!}`);
    console.log(`\n${sqlQuery}\n`);

    // SQLクエリを実行
    const result = await db.file(sqlFilePath!);

    // 表形式で結果を出力
    if (result.length > 0) {
      // result は オブジェクトの配列 なので、最初の行から列名を取得
      const columns = Object.keys(result[0]!); // Non-null assertion
      console.log(columns.join(" | "));

      // ヘッダーの下線 (より堅牢な計算方法)
      const colWidths = columns.map((col) =>
        Math.max(
          col.length,
          // result の各行 (row) の対応する列 (col) の文字列長を計算
          ...result.map((row: any) => String(row[col] ?? '').length) // null/undefined の場合に備えて空文字に
        )
      );
      const separator = colWidths.map((w) => "-".repeat(w)).join("-+-");
      console.log(separator);

      // 各行の値を出力 (パディングを追加)
      result.forEach((row: any) => {
        const values = columns.map((col, i) =>
          // null/undefined の場合に備えて空文字にしてから padEnd
          String(row[col] ?? '').padEnd(colWidths[i]!) // Non-null assertion
        );
        console.log(values.join(" | "));
      });
    } else {
      console.log("No rows returned.");
    }

    // result.length を使用して行数を表示
    console.log(`\nQuery returned ${result.length} row(s).`);

  } catch (error) {
    console.error("Error:", error);
    process.exit(1);
  } finally {
    // 接続を閉じる
    if (db) {
      db.end();
      console.log("Disconnected from PostgreSQL");
    }
  }
}

main().catch(console.error);

sample.sql

select 1 as column1 , 2 as column2

実行結果

  • sample.sqlを実行してみる
bun sql-client localhost 5432 sample sample sample sample.sql
Connected to PostgreSQL using bun:postgres
Executing SQL from: sample.sql

select 1 as column1 , 2 as column2

column1 | column2
--------+--------
1       | 2      

Query returned 1 row(s).
Disconnected from PostgreSQL

まとめ

  • BunだけでTypeScript実行もでき、PostgreSQLにもパッケージ不要でアクセスできるので、手軽なスクリプティング環境としても便利でいいですね
  • この手軽さを活かして、社内DBなどにアクセスする専用MCPサーバとかも簡単に作れそうです
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?