mcpField
P
postgres-nio

postgres-nio

github.com/wendylabsinc開発6264 回インストール5 週間前に更新
リポジトリ

postgres-nio について

postgres-nio は、非同期データベースアプリケーションを構築する Swift 開発者向けの PostgreSQL クライアントライブラリです。async/await、コネクションプーリング、パラメーター化クエリ、行データのストリーミング処理を備えています。

主な機能

  1. 01async/await 対応 PostgreSQL クライアント
  2. 02コネクションプーリング
  3. 03型安全な補間クエリ
  4. 04位置または列名による行デコード
  5. 05プリペアドステートメントとトランザクション
  6. 06結果のストリーミングと COPY FROM

活用シーン

  1. 01非同期 Swift データベースサービスの構築
  2. 02PostgreSQL へのパラメーター化クエリの実行
  3. 03バックプレッシャー付きで大規模なクエリ結果を処理
  4. 04COPY FROM による行データの一括読み込み

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wendylabsinc/claude-skills --skill postgres-nio

インストール後、Claude Code で/postgres-nioを入力して読み込まれたか確認します。

同梱ファイルreferences/postgres-patterns.md

詳細

PostgreSQL

postgres-nio ライブラリは、完全な async/await サポート、型安全なクエリ構築、コネクションプーリング、プリペアドステートメントを備えた Swift PostgreSQL クライアントを提供します。

クイックスタート

インストール

Package.swift に追加します。

dependencies: [
    .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0")
]
基本的な使い方
import PostgresNIO

// Using PostgresClient (recommended - includes connection pooling)
let client = PostgresClient(
    configuration: .init(
        host: "localhost",
        port: 5432,
        username: "postgres",
        password: "secret",
        database: "myapp",
        tls: .disable
    )
)

// Run as a service
try await withThrowingTaskGroup(of: Void.self) { group in
    group.addTask { try await client.run() }

    // Use client for queries
    let rows = try await client.query("SELECT id, name FROM users")
    for try await row in rows {
        let (id, name) = try row.decode((Int.self, String.self))
        print("User \(id): \(name)")
    }

    group.cancelAll()
}

型安全なクエリ

SQL インジェクションを防ぐため、クエリでは文字列補間を使用します。

let userId = 123
let email = "[email protected]"

// Interpolated values become parameter bindings ($1, $2, ...)
let query: PostgresQuery = "SELECT * FROM users WHERE id = \(userId) AND email = \(email)"
// Generates: "SELECT * FROM users WHERE id = $1 AND email = $2" with bindings [123, "[email protected]"]

let rows = try await client.query(query)
動的な識別子

テーブル名やカラム名には unescaped を使用します(ユーザー入力には使用しないでください)。

let tableName = "users"  // Must be trusted, not user input
let query: PostgresQuery = "SELECT * FROM \(unescaped: tableName) WHERE id = \(userId)"

行のデコード

位置によるデコード
let rows = try await client.query("SELECT id, name, email, created_at FROM users")
for try await row in rows {
    let (id, name, email, createdAt) = try row.decode((Int.self, String.self, String.self, Date.self))
}
カラム名によるデコード
for try await row in rows {
    let id = try row["id"].decode(Int.self)
    let name = try row["name"].decode(String.self)
    let email = try row["email"].decode(String?.self)  // Optional
}
カスタム型
struct User: Decodable {
    let id: Int
    let name: String
    let email: String
}

// Decode into custom type
for try await row in rows {
    let user = try row.decode(User.self)
}

プリペアドステートメント

パフォーマンス向上のため、再利用可能なプリペアドステートメントを定義します。

struct GetUserByEmail: PostgresPreparedStatement {
    typealias Row = (Int, String, Date)

    static let sql = "SELECT id, name, created_at FROM users WHERE email = $1"

    var email: String

    func makeBindings() -> PostgresBindings {
        var bindings = PostgresBindings()
        bindings.append(email)
        return bindings
    }

    func decodeRow(_ row: PostgresRow) throws -> Row {
        try row.decode(Row.self)
    }
}

// Execute prepared statement
let results = try await connection.execute(GetUserByEmail(email: "[email protected]"))
for try await (id, name, createdAt) in results {
    print("Found user \(id)")
}

トランザクション

try await client.withConnection { connection in
    try await connection.query("BEGIN")

    do {
        try await connection.query("INSERT INTO accounts (id, balance) VALUES (\(fromId), \(fromBalance - amount))")
        try await connection.query("INSERT INTO accounts (id, balance) VALUES (\(toId), \(toBalance + amount))")
        try await connection.query("COMMIT")
    } catch {
        try await connection.query("ROLLBACK")
        throw error
    }
}

一括ロード(COPY FROM)

大規模なデータセットを効率的にロードします。

let rowCount = try await connection.copyFrom(
    table: "users",
    columns: ["name", "email", "created_at"],
    format: .csv(delimiter: ",", header: false)
) { writer in
    for user in users {
        var buffer = ByteBuffer()
        buffer.writeString("\(user.name),\(user.email),\(user.createdAt)\n")
        try await writer.write(buffer)
    }
}
print("Inserted \(rowCount) rows")

接続設定

let config = PostgresClient.Configuration(
    host: "localhost",
    port: 5432,
    username: "postgres",
    password: "secret",
    database: "myapp",
    tls: .prefer(.makeClientConfiguration()),
    options: .init(
        minimumConnections: 2,
        maximumConnections: 10,
        connectionIdleTimeout: .minutes(5),
        keepAliveBehavior: .init(frequency: .seconds(30))
    )
)

let client = PostgresClient(configuration: config)
TLS オプション
// Disable TLS (local development)
tls: .disable

// Prefer TLS (use if available)
tls: .prefer(.makeClientConfiguration())

// Require TLS (production)
tls: .require(.makeClientConfiguration())
Unix ドメインソケット
let config = PostgresClient.Configuration(
    unixSocketPath: "/var/run/postgresql/.s.PGSQL.5432",
    username: "postgres",
    database: "myapp"
)

エラー処理

do {
    let rows = try await client.query("SELECT * FROM users WHERE id = \(id)")
    // ...
} catch let error as PSQLError {
    switch error.code {
    case .uniqueViolation:
        throw MyError.duplicateEntry
    case .foreignKeyViolation:
        throw MyError.invalidReference
    default:
        throw error
    }
}

大きな結果セットのストリーミング

結果はバックプレッシャーに対応して自動的にストリーミングされます。

let rows = try await client.query("SELECT * FROM large_table")

// Process one row at a time - memory efficient
for try await row in rows {
    let data = try row.decode(LargeData.self)
    try await processData(data)
}

対応する型

Swift 型PostgreSQL 型
Int、Int32、Int64integer、bigint
Float、Doublereal、double precision
Stringtext、varchar
Boolboolean
Datetimestamp、timestamptz
Databytea
UUIDuuid
[T]array
JSON 型json、jsonb

参考ファイル

トピックに応じて、必要なファイルを読み込んでください。

  • references/postgres-patterns.md - SQL の安全性を確保する文字列補間、エンコード/デコードのプロトコル階層、行のデコードにおける可変長ジェネリクス、プリペアドステートメントのパターン、階層型ステートマシン、バックプレッシャーに対応した行のストリーミング、COPY FROM による一括ロード、ワイヤープロトコルのエンコード

コメント