4 ポイント 投稿者 GN⁺ 2023-10-16 | 1件のコメント | WhatsAppで共有
  • Node.js と Deno で使用する PostgreSQL クライアントで、ES6 tagged template strings を中核 API とし、npm パッケージ postgres としてインストールする構成
  • クエリパラメータは補間前に処理され、PostgreSQL プロトコルのプレースホルダー $1, $2, ... に置き換えられ、値は別途データベースに渡されて、エスケープとキャストをデータベースが処理する方式
  • sql``...`` 呼び出しは、安全なクエリ生成と動的クエリ構築をサポートし、通常の文字列連結による SQL injection のリスクなしに、部分クエリ、動的フィルター、動的ソート、テーブル名・カラム名の識別子構築を扱える
  • 接続は postgres:// URL、オプションオブジェクト、または psql で使われる環境変数ベースで設定でき、オプションオブジェクトの値が URL の値を上書きする方式
  • クエリは await されたときに実行され、結果はカラム名を各行オブジェクトにマッピングした Result 配列として返される。.execute() を使うと即時実行できる
  • 主な利用フローは、動的 insert/update、複数行 insert、where in の値リスト、トランザクション sql.begin、savepoint、prepared transaction、ファイルベースのクエリ、カーソル、.forEach.describe.values.raw などの高度なクエリメソッドで構成される
  • PostgreSQL 機能との連携として、LISTEN/NOTIFY、論理レプリケーションプロトコルベースのリアルタイム購読COPY ... の Node.js ストリーム公開、実行中クエリのキャンセルをサポート
    • リアルタイム購読には、データベース publication の作成、postgresql.confwal_level = logical、replication ユーザーまたは superuser 接続が必要
    • COPY ... ストリーム API は型安全性を提供せず、copy クエリパラメータと Node.js ストリームの読み書きコード、および backpressure 処理を合わせる必要がある
  • データ変換オプションは、camelCase、PascalCase、Kebab-Case と snake_case 間の変換、undefined 値の変換、ユーザー定義の column/value/row 変換関数をサポート
  • コネクションプールはクエリが作られるときに遅延生成され、デフォルトの最大接続数は max: 10。トランザクション中は接続をプールから予約し、終了後に返却する方式
  • Cloudflare Workers の TCP socket API をサポートし、Workers 環境で動作させるには wrangler.tomlcompatibility_flags = ["nodejs_compat"] の設定が必要
  • TypeScript サポートは公開 API の型提供を目標としているが、機能追加や変更時に型が常に同時に更新されるとは限らないという制約がある

1件のコメント

 
GN⁺ 2023-10-16
Hacker News の意見
  • Postgres の優れた機能を活かして直接 SQLを書きたいなら、このライブラリで作業するのは本当に楽しい
    Prisma のような派手で今風を装った抽象化もなく、ほかの TypeScript ライブラリのような複雑な型注釈もなく、ただ JavaScript らしく普通の SQL 文を書けばよい
    数年前、Prisma に無理やり合わせて使うのにうんざりして Postgres をきちんと学び始め、いくつか代替を試したが、これを数分使ってみてもう戻らないと感じた

    • JavaScript にも Elixir の Ecto のようなライブラリがあるといい。SQL を扱うツールの中で、これまで見た中では最高で、シンプルで強力、理解しやすかった
    • SQL の上に層を積むやり方は昔からあまり好きではない。SQL は死んでも手放したくないほどだ
    • 責任感のある開発者が会社を去った後で、こういうコードを引き継ぐことになったら本当に面白そうだ。型も、コメントも、抽象化も、マイグレーションもなく、ただ純粋な SQLだけが残るわけだ
    • Prisma の raw query 機能のどの点が気に入らなかったのか気になる
  • このライブラリは本当に速い。似たような文字列テンプレート構文だけを見て他のライブラリと比べていると、肝心な点を見落としてしまう
    pg に依存せず、独自の低レベルクライアントを実装している
    これで一度に1万件単位のレコードを何度も投入するシステムを作ったが、性能は圧倒的だった

    • もう少し詳しく言うと、1万〜2万件程度のレコードを 20ms 未満で投入でき、もともとなら 150ms ほどかかる処理だった
      ユースケースによっては、これだけで状況を一変させ得るし、Ruby のような環境で可能だと思っていた水準に慣れているなら、さらに印象的だ
      また論理デコーディングもサポートしており、遷移イベント処理にさまざまな可能性を開いてくれる。本当に印象的なプロジェクトなので見逃すのは惜しい
  • 関連記事:
    Show HN: Postgres.js – Fastest Full-Featured PostgreSQL Client for Node and Deno - https://news.ycombinator.com/item?id=30794332 - 2022年3月、コメント83件
    Show HN: Postgres.js – Fast PostgreSQL Client for Node.js - https://news.ycombinator.com/item?id=21864245 - 2019年12月、コメント12件

  • 元記事のライブラリほど機能は多くないかもしれないが、https://pgtyped.dev/ も便利だった
    クエリを SQL ファイルとして書くと、pgtyped がクエリパラメータで呼び出せる型付き関数を生成してくれる

  • 作者です。今は Cloudflare もサポートしていることを付け加えておきたい

  • 依存関係が0個なのが気に入っている

    • 最近では十分に珍しいことなので、別途強調する価値がある
  • 「静的クエリだと推論できるすべてのクエリについて、prepared statement が自動生成される」という文が実際に何を意味するのか気になる
    バインド変数がなく、そのクエリが一度しか実行されない場合でも、DB セッションに実際のprepared statementが作られるということなのか?
    だとすると興味深いが、かなり強い主張を含んだアプローチに見える

    • パラメータ化クエリを使うなら、PostgreSQL の拡張クエリフローを必ず使う必要があり、多くの人はこれを prepared statement だと考えるだろう。これ自体は特に強い意見の入った選択ではない
      ただし通常は名前なしの prepared statement やポータルを使い、PostgreSQL がそれを整理してくれるため、セッション、つまり接続ごとに実質1つだけ維持されるような形になる
      その文が理解できなかったのでコードを見たところ、ここで言っているのは名前付き prepared statement を自動的に使い、PostgreSQL とドライバ内部に prepared statement をキャッシュするという意味だった。文のシグネチャを作っているので、これは確かに意見の入った設計だ
      parse/describe/bind/execute/sync データが主に作られている箇所のコードは、個人的にはかなり微妙だと思う: https://github.com/porsager/postgres/blob/bf082a5c0ffe214924...
    • Postgres は2種類の prepared statement をサポートしている。パラメータを受け取れる generic prepared statement と、特定の実行のために準備され、パラメータをプランに反映する custom prepared statement がある
      https://www.postgresql.org/docs/current/sql-prepare.html に説明されており、プランの種類については “Notes” セクションを見ればよい
  • ここでは Zapatos にも触れておくべきだと思う。テンプレート文字列の中に SQL を書く、非常によく似た設計のもう一つの Postgres JavaScript クライアントで、完全な型安全性を提供している
    TypeScript が好きなら気に入るかもしれない: https://jawj.github.io/zapatos/
    個人的には、設計とドキュメント化が最もよくできた TypeScript ライブラリの一つだと感じており、あまり知られていないのが惜しい

    • Zapatos は結局あきらめざるを得なかった。複数のスキーマをサポートしておらず、型が常に読みやすく出るわけでもなかったためだ
      代替として PgTyped を選び、2年経った今では移行して本当に良かったと思っている
    • 同意。lateral join 機能とショートカット関数の組み合わせのおかげで、実際の SQL を書きながらも使い勝手を犠牲にせずにバックエンドを作るのがとても簡単だ
    • ざっと見たところ、Zapatos は Cloudflare Workers と互換性がないように見えるが、違うなら訂正してほしい
    • zapatos が PostgresJs ではなく pg に依存している理由を知っているか気になる
  • このプロジェクトがどれくらい古いのか気になって見てみた:
    v1.0.1 - 2020年1月
    v2.0.0 - 2020年6月、ただしベータを抜けられず
    v3.0.0 - 2022年3月、この頃からプロジェクトが本格的に始まったように見える
    かなり興味深そうなので、どれくらい堅牢なのかも気になる

    • Deno でしばらく本番環境に使ってきた。かなり堅牢だが、ドキュメントが大幅に不足しているので、複雑な作業をするときは自分で手探りで方法を見つけなければならないことが多い
  • Postgres.js はこれまで使ってきたライブラリの中でも最高水準だ
    JavaScript のテンプレートの活用方法が本当に直感的だ