データベースから情報を取る方法です。
環境は Postgres のバージョン 11 を使います。またその環境は Docker を用いて以下のコマンドで建てたサーバーを使います。
docker run \
--name postgres \
--detach \
--publish 5432:5432 \
--env POSTGRES_HOST_AUTH_METHOD=trust \
postgres:11
準備
動作を見るためにusers
というテーブルを作り、その中に適当なデータを入れておきたいと思います。
まずはdiesel_cli
でマイグレーションファイルを作ります。名前はcreate_users
とし、以下のコマンドを実行します。実行後migrations
ディレクトリ以下に雛形が作られます。
# セットアップがまだの場合
diesel migration setup \
--database-url postgres://postgres:@loccalhost:5432
# diesel.toml が作られる
diesel migration generate create_users \
--database-url postgres://postgres:@loccalhost:5432
# migrations/20xx..._create_users/{up,down}.sql
# が作られた
migrations/20xx..._create_users/up.sql
を以下のように編集します。
-- Your SQL goes here
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(30) NOT NULL,
nickname VARCHAR(30),
age INTEGER NOT NULL,
active BOOLEAN DEFAULT 't' NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL
);
INSERT INTO users (name, nickname, age, created_at) VALUES
('foo', 'nickfoo', 20, '2020-04-29T01:17:16.644130000+00:00'),
('bar', null, 20, '2020-04-29T01:18:16.644130000+00:00');
users
テーブルの作成と、そのレコードの挿入をしてます。
一応戻せるようにdown.sql
も書いておきます。
-- This file should undo anything in `up.sql`
DROP TABLE IF EXISTS users;
できたら以下のコマンドで実行します。
diesel migration run
ちゃんとデータが入っているか以下で確認します。(jq
コマンドを使用します)
psql postgres://postgres:@localhost:5432 \
--tuples-only \
--command \
'select json_agg(users) from users' \
| tr -d '\n+' \
| jq .
以下のような出力があれば準備完了です。
[
{
"id": 1,
"name": "foo",
"nickname": "nickfoo",
"age": 20,
"active": true,
"created_at": "2020-04-29T01:17:16.64413"
},
{
"id": 2,
"name": "bar",
"nickname": null,
"age": 20,
"active": true,
"created_at": "2020-04-29T01:18:16.64413"
}
]
スキーマの確認
実は上記のdiesel migration run ...
した際にスキーマモジュールが自動的に作成されているハズです。
例えば今回はこんな感じで作成されてました。
table! {
users (id) {
id -> Int4,
name -> Varchar,
nickname -> Nullable,
age -> Int4,
active -> Bool,
created_at -> Timestamp,
}
}
このファイルはdiesel migration setup ...
した際に作られるprint_schema.file
に指定されたパスで作られます。
# デフォルト
[print_schema]
file = "src/schema.rs"
この自動作成のモジュールを使うためにsrc/lib.rs
を作り以下のようにして、main.rs
などで読み込めるうようにしておきます。またその際table!
マクロが解決できるようにdiesel
にmacro_use
しておきます。
#[macro_use]
extern crate diesel;
pub mod schema;
このtable!
マクロでschema::users::dsl::{users,id,name,...}
のようにインポートできるコードが生成されます。
アナログでスキーマモジュールを作る
diesel migration
コマンドを使わないプロジェクトなどで使いたい場合は、自分で手書きて用意しても問題なく動かすことができます。ただしそのパスはdiesel.toml
のprint_schema.file
パス先でなければなりません。
スキーマで使用できる型は以下の通りです。
BigInt
Binary
Bool
Date
Double
Float
Integer
Interval
Nullable
Numeric
SmallInt
Text
Time
Timestamp
Tinyint
取得レコード用の入れ物(構造体)の作成
SQLのデータを入れれるような構造体を作ります。守る必要のあるルールで、その構造体はQueryable
トレイトを継承してなければなりません。このトレイトはderive
で継承できます。
今回の場合構造体はこのようになります。
#[derive(Queryable, Debug)]
pub struct User {
pub id: i32,
pub name: String,
pub nickname: Option,
pub age: i32,
pub active: bool,
pub created_at: chrono::NaiveDateTime
}
これをsrc/lib.rs
のpub mod schema;
の後に追記しておきます。
ここでTimestamp
型の扱いに関してですが、chrono
というライブラリを使います。これによりCargo.toml
の依存関係を以下のように修正します。diesel
のfeatures
にもchrono
の追加が必要です。
[dependencies]
diesel = { version = "1.4.4", features = [ "postgres", "chrono" ] }
chrono = "0.4.11"
データを取得する
src/main.rs
を作り、最初のマイグレーションで挿入したデータを取得してみます。
use diesel::pg::PgConnection;
use diesel::prelude::*;
use ::{schema, User};
const DATABASE_URL: &'static str = "postgres://postgres:@localhost:5432";
fn main() {
let connection =
PgConnection::establish(DATABASE_URL).expect(&format!("Error connecting to {}", DATABASE_URL));
let users = schema::users::dsl::users
.load::(&connection)
.expect("Error loading users");
println!("{:#?}", users);
}
cargo run
で実行して以下のような結果が出力されれば完了です!
[
User {
id: 1,
name: "foo",
nickname: Some(
"nickfoo",
),
age: 20,
active: true,
created_at: 2020-04-29T01:17:16.644130,
},
User {
id: 2,
name: "bar",
nickname: None,
age: 20,
active: true,
created_at: 2020-04-29T01:18:16.644130,
},
]
サンプルコード
動作確認できるコードは nju33-com/get-started-diesel-query に置かれています。