Update

レコード更新する方法です。

環境は Postgres のバージョン 11 を使います。またその環境は Docker を用いて以下のコマンドで建てたサーバーを使います。

docker run \
  --name postgres \
  --detach \
  --publish 5432:5432 \
  --env POSTGRES_HOST_AUTH_METHOD=trust \
  postgres:11

準備

Insert 時と同じ内容です。

Query 時と同じようにマイグレーションファイルを作り、いくつか適当なレコードが入ってる環境を作ります。

diesel migration generate create_users

作られたup.sqldown.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;

プライマリーキーからデータを更新する

src/main.rsを書いていきます。

まずはプライマリキーでレコードを直接を取得し、その値を更新する方法です。その場合diesel::update関数を使います。

diesel::updateの引数には、table!マクロで生成されるtable_name::dsl::table_name構造体の.findメソッドを対象のプライマリーキー値と共に使います。

更新後に期待する値は.setメソッドを使います。table!マクロはtable_name::dsl以下にそのテーブルのカラム名の構造体を持ちます。その中から更新したいカラム構造体の.eqメソッドを、期待する次の値と共に使い、.setメソッドの引数とします。

use diesel::pg::PgConnection;
use diesel::prelude::*;
use get_started_diesel_insert::schema;

const DATABASE_URL: &'static str = "postgres://postgres:@localhost:5432";

fn main() {
  let connection =
    PgConnection::establish(DATABASE_URL).expect(&format!("Error connecting to {}", DATABASE_URL));

  diesel::update(schema::users::dsl::users.find(1))
    .set(schema::users::dsl::name.eq("baz"))
    .execute(&connection)
    .expect("Error saving new users");
}

条件に当てはまるレコードの値を更新

diesel::update引数で使うtable_name構造体で.eqメソッドではなく.filterを使います。その引数ではカラム名の構造体の.eqを使い、「カラム値がこの値のもの」のようにします。

use diesel::pg::PgConnection;
use diesel::prelude::*;
use get_started_diesel_insert::schema;

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 target = schema::users::dsl::users.filter(schema::users::dsl::name.eq("bar"));
  diesel::update(target))
    .set(schema::users::dsl::name.eq("baz"))
    .execute(&connection)
    .expect("Error updating an users");
}

すべてのレコードを更新

単にすべてを更新したければdiesel::updateの引数にそのままtable_name構造体を渡すだけです。

diesel::update(schema::users::dsl::users))
  .set(schema::users::dsl::name.eq("baz"))
  .execute(&connection)

サンプルコード

動作確認できるコードは nju33-com/get-started-diesel-update に置かれています。