ORMなんていらない?!生SQLクエリ開発を超絶楽にするVSCode拡張を作った [TS+Rust+WASM]
TL;DR
これができる機能です。
TypeScript with Prisma ⇩
Rust with SQLx ⇩
SQL ファイルだけでなく、他のファイルの生 SQL クエリ(Raw SQL Query)に対しても SQL の LSP が効きます。
現在は TypeScript 上 の Prisma と Rust の SQLx をデフォルトでサポートしています。Prisma のみ、SQL のシンタックスハイライトが効きます。
なお、タイトル詐欺です。
sqlsurge の設定
名前は sqlsurge[1] です。sqlsurge では SQL の Language Server に Golang 製 の sqls を使っているので、
- Golang
- sqls
が必須となります。sqls をインストールしている人は限られていると思うのでインストールガイドを用意しました。
TypeScript や Rust ファイルを開くと出てくるポップアップで"Install with command"を選ぶとターミナルでインストールコマンドが走ります[2]。画面リロードしたら補完が効くようになります。
また、自動補完したい場合、VSCode では文字列中の自動補完はデフォルトで無効になっているので、以下の設定をする必要があります。
{
"editor.quickSuggestions": {
"strings": true
}
}
sqlsurge の仕組み
他言語上での SQL Language Server の有効化
これがなければおそらく私の拡張機能も作れませんでした。@mizchi さんバンザイ。
この記事では触れていませんがどうやっているかというと、VSCode API の Virtual Document を使って、仮想ファイル及びドキュメントを作成します(今回は SQL ファイル)。
そして、以下の部分で仮想化されたドキュメントに対して SQL の LSP を発火します。
今開いているファイルと仮想的な SQL ファイルが同じエディターを共有しているので、ポジションを指定してあげれば TypeScript や Rust の上に SQL の補完が効くわけです。
おそらくですが、HTML 上で CSS や JS の補完が効くのも同じ仕組みだと思います。
[2024/4/29 追記] 色々調べていたらそれに該当する公式ドキュメントを見つけました
Request Forwarding というのがそれです。補完やエラーといった Language Service の機能を VSCode API を通じて橋渡しできます。今回の補完で言えば Go で作られた SQL Language Server が vscode.executeCompletionItemProvider
を通じて提供できているというわけです。
読み間違ってなければ HTML 上での CSS や JS の Language Server が効くのも、 CSS, JS のそれぞれで Language Service を実装し、それを Request Forwarding で HTML に適用しているということですね。
おそらく @mizchi さんもこちらを見て実装されたんだと思います。
この機能は VSCode だけなんですかね。Vim とかでもできるんでしょうかね。
生 SQL の検出
生 SQL は TypeScript や Rust の AST を解析し、prisma.$queryRaw
やsqlx::query!
を探し、引数の SQL を抽出しています。TypeScript は 公式の Compiler API を使って、Rust では syn を使って AST を解析しています。
syn で AST を扱ってく中で SQL の開始位置と終了位置を取得する必要があったのですが、syn を入れるだけでは取得できず、proc-macro2 でこのように feature を指定する必要があった点にハマりました。
ドキュメントにしっかり Available on crate feature span-locations only.
って書いてあるのでちゃんと読むべきでしたね、、
なお、AST の確認は astexplorer.net が便利でした(TS は TypeScript AST Viewer のほうが見やすいです)
今後 Prisma や SQLx に限らず他のライブラリや自作関数なども対応できるように、カスタマイズ設定もできるようにするつもりです。
Rust を WASM に変換して VSCode で動かす
上で説明した SQL を検出する Rust コードをどうやって動かしているかというと、wasm-pack で WASM に変換して JavaScript から呼び出して動かしています。VSCode は Electron でバックエンドで WASI サポートの Node.js が動いているので WASM が動きます。
Rust + WASM はこちらの記事が大変参考になりました。というかパクりました
この記事の通りに今はバンドラーに Webpack を使っているのですが、esbuild の開発体験が良いので本当は esbuild が使いたいです。でもちょっと試してできなかったので一旦断念しました。また再チャレンジします。
なお、Go や Python など他の言語もサポートがほしい人がいればぜひ Issue にどうぞ。ついでに PR ください(傲慢)
(SQL の範囲と SQL 文字列さえ返せばいいので、コントリビュートしやすいとは思います)
GitHub Actions での CI
Rust の単体テストと、 @vscode/test-electron + Jest で VSCode 上での結合テストを GitHub Actions で行っています。Ubuntu と macOS でテストを行っています。
詳しくは過去記事で。
なお、無駄にキャッシュもりもりにして CI 時間を半分くらいにしたりしています(wasm-pack のインストールと Rust のビルドに時間がかかって 10 分以上かかることがあるので、、)
TODOs
- Support for Prisma in TypeScript
- Support for SQLx in Rust
- Install guide for sqls
- Format SQL (2024/5/3 Support)
- Support custom functions for raw SQL queries, not just Prisma and SQLx (2024/6/21 Support)
- Execute SQL query
- Syntax highlight for SQL
- Show quick info symbol
- Show sqls config with tree view
まとめ
生 SQL クエリで補完が効く拡張機能を作りました。既にあるかなと思って調べてみましたがない感じですかね?もしあれば教えてください。
仕事で生 SQL を強いられている方や ORM に恨みを感じている方などはぜひ使ってみてください。
GitHub の Star や拡張機能のレビューなどがもらえると非常にやる気が上がります :pray:
また、この拡張機能を通じて @mizchi さんと @canalun さんには大変お世話になったので、この場を借りて感謝申し上げます。
おまけ
Prisma に同じような機能を欲している Issue があったので拡張機能作ったよとコメントした[3]ところ、なんと Prisma の方から Star をいただきました!!大変感謝!恐悦至極!唯我独尊!
-
もちろん sqls が由来です。surge は急上昇とか躍進とかの意味があるみたいです。ChatGPT と一緒に考えました。気に入ってます。 ↩︎
-
Go モジュールのキャッシュがあるので GIF では sqls のインストールが 3 秒くらいで終わってますが、初回は 30 秒くらいはかかると思います。 ↩︎
-
Prisma にコントリビュートすれば良かったのでは?という考えもありますが、sqlsurge は色んな言語・ライブラリ上で動作することを目指しているので、ちょっと方向性がずれているかなと思いました。というかプライベートで SQLx を使っていく予定なので、ついでに Prisma にも対応したという感じです。 ↩︎
Discussion