データベースにレコードを新しく登録する方法です。
環境は 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 に置かれています。