Rust dieselを既存DBに適用する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

Rust dieselクレイトを運用中既存DBに適用したので、手順をメモしておきます。

依存関係の定義

データベーススキーマは通常通りDATABASE_URLに定義しておく。

自分の場合は.envに記載しておいた。

DATABASE_URL=postgresql://postgres:password@localhost:5432/databasename

Cargo.toml

[dependencies]
dotenv = "0.15"
diesel = { version = "1.4.4", features = ["postgres", "chrono"] }

diesel-cliのインストールは省略。

運用中のデータベースには以下のテーブルがすでに存在するものとします。

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email TEXT NOT NULL,
  password TEXT NOT NULL,
  created_at timestamp default now()
)


dieselのセットアップ

$ diesel setup

と行っても自分の検証環境では既存DBを壊すような挙動は行いませんでした。

追記:すでにDiesel用のmigrationディレクトリとmigrationファイルがプロジェクト内に存在する場合は、migrationの実行が行われる。既存DBに対しては構成をプロジェクトに合わす/既存のまま運用する、のポリシーに応じてmigrationディレクトリの配置/削除を行う。

多分、setupはDBへmigrationテーブル作成、及びdiesel.toml、migrationディレクトリの作成を行うコマンドだと思うので、今後、migration運用する必要なければ、diesel.tomlを手動で作成して、この手順すらスキップできるような気がする。試してないけど。


既存DBへのつなぎこみ

公式ドキュメント通りに記述すれば簡単に接続できる。

use diesel::pg::PgConnection;
use dotenv::dotenv;

pub fn establish_connection() -> PgConnection {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL")
        .expect("DATABASE_URL must be set");
    PgConnection::establish(&database_url)
        .expect(&format!("Error connecting to {}", database_url))
}

https://diesel.rs/guides/getting-started/

ORMの準備

ORMを利用するには、Resultを格納するモデルとテーブルレイアウトのschema.rsを作成する。要はmigration時に自動で作成されるschema.rsを既存テーブルのレイアウトに応じて自身で作成する。ということ。

models.rs

use crate::schema::*;
use chrono::NaiveDateTime;

#[derive(Clone, Queryable)]
pub struct User {
    pub id: i32,
    pub email: String,
    pub password: String,
    pub created_at: NaiveDateTime,
}

schema.rs

table! {
  users (id) {
      id -> Integer,
      email -> Text,
      password -> Text,
      created_at -> Timestamp,
  }
}

上記で、ORMを扱う準備が整った。


dieselを通してテーブルアクセスを行う

あとは通常通りの使い方で利用すればよい。

#[macro_use]
extern crate diesel;
extern crate dotenv;

use diesel::prelude::*;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;

pub mod schema;
pub mod models;
use models::*;

async fn index() -> String {
    use schema::users::dsl::*;
    let connection = establish_connection();
    let results = users.load::<User>(&connection).expect("error loading users");
    let mut user_name = "Not Found User".to_string();
    if let user = results.first().unwrap() {
        user_name = user.email.clone();
    }
    format!(
        "DB Record {}",
        user_name
    )
}

サンプルコード github.com

多分、schema.rsで解釈可能なテーブルレイアウトな限りORM利用できると思う。命名規則で使えないってことはないんじゃないかな。試してないけど笑