Skip to main content

データベースを使えるようにする

このページでは、データベースにアクセスする準備をします。

あらかじめ、Dockerなどでデータベースを準備しておいてください。今回はPostgreSQLを例に説明します。

データベースドライバーの導入#

rocketでデータベースを使用するために、データベースドライバーを導入します。Rustでは diesel と呼ばれるライブラリが使用できるので、これを使用します。

Cargo.toml の依存ライブラリに追記しましょう。

Cargo.toml
  [package]  name = "rustwi"  version = "0.1.0"  edition = "2018"    # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html    [dependencies]  rocket = "0.4"- rocket_contrib = { version = "0.4", default-features = false, features = ["handlebars_templates"] }+ rocket_contrib = { version = "0.4", default-features = false, features = ["handlebars_templates", "diesel_postgres_pool"] }  chrono = { version = "0.4", features = ["serde"] }  serde = { version = "1.0", features = ["derive"] }+ diesel = { version = "1.4", features = ["postgres", "chrono"] }

Diesel CLIの導入#

続いて、DieselのコマンドラインツールをCargo経由でインストールします。これは、データベースのバージョン管理などを行ってくれるツールです。

$ cargo install diesel_cli --no-default-features --features "postgres"

これで diesel コマンドが使えるようになります。コマンドには --database-url オプションで接続先URLを指定できるのですが、常に指定するのは面倒なので、dotenvファイルに環境変数として定義します。

下記は適宜読み替えてください

  • [username]
  • [password]
  • [host]
  • [db]
.env
DATABASE_URL=postgres://[username]:[password]@[host]/[db]

これでコマンドを使用する準備ができました。まずはセットアップしましょう。

$ diesel setup

このコマンドを実行することで、データベースに [db] で指定した名前でデータベースが作成されます。

また、下記のディレクトリとファイルが自動生成されます。

.├── diesel.toml├── migrations│   └── 00000000000000_diesel_initial_setup│       ├── down.sql│       └── up.sql├── src...

テーブルの作成#

まずはTweetを保存するテーブルを作成します。これもコマンドを使って生成します。

$ diesel migrate generate create_tweets

これで、migrationsディレクトリの中に、新たに create_tweets を含むディレクトリが作成されているはずです。また、 up.sqldown.sql ファイルも生成されています。

up.sql にはテーブルの作成を、 down.sql には up.sql を打ち消すSQL(今回はテーブルを作成しているのでテーブルを削除するSQL)を記載します。

migrations/yyyy-mm-dd-hhmmss_create-tweets/up.sql
CREATE TABLE tweets(    id        SERIAL PRIMARY KEY,    message   TEXT        NOT NULL,    posted_at TIMESTAMPTZ NOT NULL);
migrations/yyyy-mm-dd-hhmmss_create-tweets/down.sql
DROP TABLE tweets IF EXISTS;

作成したら、下記のマイグレーションコマンドを実行しましょう。新たに定義した tweets テーブルがデータベースに作成されます。

$ diesel migrate runRunning migration yyyy-mm-dd-hhmmss_create_tweets

また、テーブル定義を規定する src/schema.rs ファイルも生成されます。

src/schema.rs
table! {    tweets (id) {        id -> Int4,        message -> Text,        posted_at -> Timestamptz,    }}

このファイルはモジュールとして利用するため、 src/lib.rs にモジュールとして定義します。また、このファイルはdieselの table! というマクロを利用しているため、マクロ利用も追加します。

mod schema;
#[macro_use] extern crate diesel;

データベースコネクションの実装#

最後にアプリケーションからデータベースに接続するための実装をします。

まずは設定ファイルを作成します。

Rocket.toml
[global.databases]rustwi = { url = "postgres://[username]:[password]@[host]/[db]" }

続いてデータベースコネクションを実装します。具体的には、データベースの接続情報を取り扱う構造体を定義します。

#[macro_use] extern crate rocket_contrib;#[macro_use] extern crate diesel;
#[database("rustwi")] // --(1)pub struct DbConn(diesel::PgConnection); // --(2)

(1) は構造体にデータベースの関連付けを行うマクロで、引数にはデータベース名を指定します。

info

マクロを使うために、 extern crate rocket_contrib;#[macro_use] を追加する必要があります。

(2) は、データベースの接続情報の構造体です。引数にはデータベースの種類( Poolable Type )を指定します。何を指定できるかは公式サイトを見てください。

最後に、これをRocketに組み込みます。 #[database] によりFairingが実装されているため、rocketに追加します。

fn run() {    rocket::ignite()        .attach(DbConn::fairing()) // 追加        .launch();}

これでデータベースを使う準備が整いました。最後に、ここまでの変更を示します。

src/lib.rs
  #![feature(proc_macro_hygiene, decl_macro)]    pub mod controllers {      pub mod index;      pub mod tweets;  }  pub mod services {      pub mod tweets;  }  pub mod entities {      pub mod tweet;        pub use tweet::Tweet;  }+ pub mod schema;  pub mod helpers;  + #[macro_use] extern crate diesel;  #[macro_use] extern crate rocket;- extern crate rocket_contrib;+ #[macro_use] extern crate rocket_contrib;  extern crate chrono;  #[macro_use] extern crate serde;    use rocket_contrib::templates::Template;+ + #[database("rustwi")]+ pub struct DbConn(diesel::PgConnection);    pub fn run() {      rocket::ignite()          .mount("/", routes![controllers::index::index])          .mount("/tweets", routes![controllers::tweets::post_tweet])          .attach(Template::custom(|e| {              e.handlebars.register_helper("datetimeformat", Box::new(datetimeformat));          }))+         .attach(DbConn::fairing())          .launch();  }

次の章では、データを保存するためのコードを書いていきます。