【Rust】sqlxでコンパイルエラーが発生する
はじめに
sqlxでDB接続する処理があってローカルではDBを起動していたのでビルドも通っていました。
Github Actionでビルドして問題ないかチェックするようにしていたのですが、以下のようなエラーが発生してしまいました。
🏗️
error: error communicating with database: Connection refused (os error 111)
--> src/infrastructure/report_repository.rs:87:20
|
87 | let rows = sqlx::query!(
| ____________________^
88 | | "SELECT DISTINCT
89 | | CAST(EXTRACT(YEAR FROM date) AS INTEGER) AS year,
90 | | CAST(EXTRACT(MONTH FROM date) AS INTEGER) AS month,
... |
94 | | year as i64
95 | | )
| |_________^
|
= note: this error originates in the macro `$crate::sqlx_macros::expand_query` which comes from the expansion of the macro `sqlx::query` (in Nightly builds, run with -Z macro-backtrace for more info)
offlineモードでビルドする
発生して原因としては、query!がマクロなのでビルド時に実行するため、DBが必要となるのでこけていました。
一番簡単な解決策としては、ビルド時にコード自体を実行しないquery関数に置き換えるだけで解決します。
ただし、これでは堅安全性が下がるのでマクロをそのまま使いたい方もいると思うので、その場合は、offlineモードを使いましょう。
手順としては以下の通りです。
- 環境変数に以下のofflineモードを有効化する
SQLX_OFFLINE=true
- 実行したクエリのキャッシュを保存する
cargo sqlx prepare
これで、以下のようなjsonファイルが生成されます。
このキャッシュファイルがあることで事前にDBのクエリをキャッシュしておくことができるようになります。
queryを使っている対象のテーブルにおいてマイグレーションが発生する際に実行しておくようにしましょう。
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT \n CAST(EXTRACT(YEAR FROM date) AS INTEGER) AS year, \n CAST(EXTRACT(MONTH FROM date) AS INTEGER) AS month, \n CAST(EXTRACT(DAY FROM date) AS INTEGER) AS day \n FROM reports \n WHERE EXTRACT(YEAR FROM date) = $1;",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "year",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "month",
"type_info": "Int4"
},
{
"ordinal": 2,
"name": "day",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Numeric"
]
},
"nullable": [
null,
null,
null
]
},
"hash": "7296bb3ca62a2c9ec4518a1b52848197c89cf8bacb09915ca4a7065c68585f5e"
}
- ビルドする
これでsqlxはofflineモードでビルドされるのでDBが起動していなくてもビルドが通るようになっているはずです。
cargo build
❯ cargo build
Compiling backend v0.1.0 (/Users/xxxxxx)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.59s
- Github Actionのワークフロー設定ファイルにofflineモードを定義
上までの操作でローカル上でofflineモードでビルドできるようになりましたが、冒頭で言及していた通り、Github Actionでこけていた問題を解消する場合は、ワークフロー設定ファイルにビルド時にofflineモードを有効化するように環境変数を追加してください。
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
working-directory: ./backend
env:
SQLX_OFFLINE: true # offlineモード有効化
run: cargo build --verbose
また、cargo sqlx prepareで生成した.sqlx/query-xxxxx.jsonもcommitしておくようにしてください。
終わりに
sqlxのquery!でこけていたのはビルド時にDBがないためにこけていました。
事前にクエリのキャッシュを使うofflineモードを有効化すれば、DBが起動していなくてもビルドが通るようになります。
Discussion