pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

Rust失敗録:Crateちゃんと書いたはずなのに、日付型、Decimal型読めない(MariaDB+sqlx+tokio)

Rust初心者爺の失敗の種は尽きませぬ。今回は、Rust+MariaDBで日付型、Decimal型を読み取れなかったという「失敗録」です。Copilotに助けてもらい、解決できました。

Rust:Cargo.tomlのdependenciesのsqlxにfeaturesで外部crateを書き込み準備完了
Rust:Cargo.tomlのdependenciesのsqlxにfeaturesで外部crateを書き込み準備完了

前説:LinuxMint+MariaDB+Rustほか

前回までのプログラムで、非同期で整数、Stringを読み取りできました。

tokio+sqlx+query_as の組み合わせでした。
「構造体は?」「query_as!は?」とピンときた方、スミマセン、今回の記事にも登場しません。悪しからず。

Crate.toml:sqlxは外部Crateを知らず、featuresへの記載必須

今回は、日付型(日付のみ)とDecimal型を読み取れなかった、というのが失敗事象です。「sqlxは機能を features で明示する設計」とCopilotが教えてくれました。これが
sqlxがMariaDBからデータ読み取りする時、日付型、Decimal型データが対象なら、features欄にも「日付型、Decimal型を使います」という塩梅に外部crate情報を明示します。単に、crateに日付型とDecimal型の外部crateを書くだけでは依存関係の準備が完了しておらず、機能しませんでした。

Crate.toml:「sqlx」featuresに追記し依存関係準備が一段落

冒頭図「宅内LANのMariaDBへSSH経由で接続(開発用)」は依存関係を整え「動く」ようになった関係図です。失敗原因は、「sqlx」featuresへの外部crate書き込み欠落でした。この内容を書きます。

暴走気味の爺は、Cargo.toml「dependencies」内に、sqlxを使う際に必要な機能として

  • tokio
  • chrono
  • rust_decimal

の内容を書き、「依存関係は整った」と思ったです。「sqlx」featuresに追記してないという、自覚ゼロ状態で、コンパイル時にエラーの連続...。前回、「tokio」を「sqlx」featuresへ記入し経験済みなのに、懲りない・身に浸みない・短期記憶ほぼゼロ爺の実力...。

稼働したCargo.toml
[package]
name = "x_proj" # ご自身のプロジェクト名に合わせてください
version = "0.1.0"
edition = "2024"

[dependencies]
sqlx = { version = "0.7", features = ["runtime-tokio", "mysql", "chrono", "rust_decimal"] }
tokio = { version = "1", features = ["full"] }
chrono={version="0.4", features=["serde"]}
rust_decimal = "1.36"

「sqlx」featuresに追記し、依存関係を整える準備ができたことになります。
「sqlx」features = ["runtime-tokio", "mysql", "chrono", "rust_decimal"]

main.rs:「use」を書き依存関係が確立

Crate.tomlで依存関係を整え、実際に働くようにするには、main.rs冒頭に「use」で明示することが必須です。tokioの扱いと、chrono、rust_decimalのそれが異なるのは、様式・仕様ということで....。

MariaDBの読み取りは、前回までと同様にタプル+quaery_asで行ってます。日付型は日付のみです。
ご自身の環境に合わせ、適宜書き直し、「自己責任」でお試しください。

use sqlx::mysql::MySqlPoolOptions;
use chrono::{NaiveDate};
use rust_decimal::Decimal;

#[tokio::main]
async fn main() ->std::result::Result<(), Box<dyn std::error::Error>>{
    connect_with_db_name()
    .await?;
    Ok(())
}

async fn connect_with_db_name() ->std::result::Result<(), Box<dyn std::error::Error>>{
    println!("RDB接続します");
    let url ="mysql://user_name:password@192.168.x.x:3306/db_name";
    let pool = MySqlPoolOptions::new()
        .max_connections(5)
        .connect(url)
        .await?;
    let row =sqlx::query_as::<_, (i32, String, NaiveDate, Decimal) > (
        "SELECT num, cd, date, dec FROM table_name LIMIT 1"
        )
        .fetch_optional(&pool)
        .await?;
    match row {
        Some((num, cd, date, dec)) => println!("num:{}, cd:{}, date:{}, dec:{}", num, cd, date, dec),
        None => println!("データがありません"),
    }
    Ok(())
}

まとめ:Rust は “依存関係の宣言” が厳格

Python のように、pip install → import で済む世界と違い、Rust は、

  • Cargo.toml に書く-
  • sqlx の features にも書く
  • main.rs の use でも書く

という 三段構え が必要です。

面倒ですが、「大番頭(Cargo)が全部の帳簿を見て整合性を取っている」と思えば、これはこれで安心感があると思うほかなさそうです。今回の失敗を克服し、Rustで、整数、String、日付(NaiveDate)・十進数(Decimal)の読み取りできるようになりました。めでたし・めでたし。

さて、次の「失敗録」のテーマは...?