データベースにレコードを新しく登録する方法です。
環境は Postgres のバージョン 11 を使います。またその環境は Docker を用いて以下のコマンドで建てたサーバーを使います。
docker run \
--name postgres \
--detach \
--publish 5432:5432 \
--env POSTGRES_HOST_AUTH_METHOD=trust \
postgres:11
準備
Query 時と同じようにマイグレーションファイルを作り、いくつか適当なレコードが入ってる環境を作ります。
diesel migration generate create_users
作られたup.sql
とdown.sql
をそれぞれ以下のように編集します。
-- Your SQL goes here
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(30) NOT NULL
);
INSERT INTO users (name) VALUES
('foo'),
('bar');
-- This file should undo anything in `up.sql`
DROP TABLE IF EXISTS users;
以下のコマンドでデータを流し込んで完了です。
diesel migration run \
--database-url postgres://postgres:@localhost:5432
psql postgres://postgres:@localhost:5432 \
--tuples-only \
--command \
'select json_agg(users) from users' \
| tr -d '\n+' \
| jq .
[
{
"id": 1,
"name": "foo"
},
{
"id": 2,
"name": "bar"
}
]
src/schema.rs
ができているので、いつものsrc/lib.rs
を雛形の形にしておきます。
#[macro_use]
extern crate diesel;
pub mod schema;
挿入用の構造体を作る
取得する時の構造体ではQueryable
トレイトを継承しましたが、挿入用のものにはInsertable
トレイトを継承させます。その構造体ではDEFAULT
値が設定されているカラムなど、いらない挿入時には要らない情報を落とて定義します。
また#[table_name = schema.rs にあるテーブル名]
で実際のテーブル名の指定が必要になります。その際にはschema.rs
から指定したテーブル名の名前空間をスコープに持ってこなければなりません。
// #[table_name="users"] を使うため
use schema::users;
#[derive(Insertable)]
#[table_name="users"]
pub struct NewUser {
name: String,
}
これをsrc/lib.rs
の最後に追記しておきます。
データを挿入する
src/main.rs
を書いていきます。
データの挿入にはdiesel::insert_into
関数を使います。
use diesel::pg::PgConnection;
use diesel::prelude::*;
use get_started_diesel_query::{schema, NewUser};
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 new_user = NewUser { name: "baz".into() };
diesel::insert_into(schema::users::table)
.values(&new_user)
.execute(&connection)
.expect("Error saving new user");
}
これをcargo run
で実行し以下の結果が得られれば完了です。
psql postgres://postgres:@localhost:5432 \
--tuples-only \
--command \
'select json_agg(users) from users' \
| tr -d '\n+' \
| jq .
[
{
"id": 1,
"name": "foo"
},
{
"id": 2,
"name": "bar"
},
{
"id": 3,
"name": "baz"
}
]
挿入時に取得も行う
RETURNING
を含んだINSERT INTO
も行えます。その場合execute
メソッドではなくget_result
メソッドを呼び出します。またその際はQueryable
トレイトを継承した構造体の指定が必要です。
src/lib.rs
に取得用の構造体を定義します。
#[derive(Queryable, Debug)]
pub struct User {
pub id: i32,
pub name: String,
}
これをsrc/main.rs
で読み込み、またdiesel::insert_into
箇所を以下のように修正します。
fn main() {
// ... 略
let user = diesel::insert_into(schema::users::table)
.values(&new_user)
.get_result::(&connection)
.expect("Error saving new user");
println!("{:#?}", user);
// User {
// id: 3,
// name: "baz",
// }
}
複数のデータを挿入する
.values
メソッドに Vector で複数のNewUser
を渡すことで 1 つのINSERT INTO
で複数の値を挿入できます。複数時には.get_result
も.get_results
と複数形に代わります。
勿論戻り値が必要ないのであれば.execute
も使えます。
fn main() {
// ... 略
let baz_user = NewUser { name: "baz".into() };
let qux_user = NewUser { name: "qux".into() };
let users = diesel::insert_into(schema::users::table)
.values(vec![baz_user, qux_user])
.get_results::(&connection)
.expect("Error saving new users");
println!("{:#?}", users);
// [
// User {
// id: 6,
// name: "baz",
// },
// User {
// id: 7,
// name: "qux",
// },
// ]
}
サンプルコード
動作確認できるコードは nju33-com/get-started-diesel-insert に置かれています。