RustでMySQLを操作してみる(書き込み)
前回はRustでMySQLの読み込み操作について書きました。
引き続き、書き込み操作について書いていきます。
今回もdieselのチュートリアル参考にしていきます。
http://diesel.rs/guides/getting-started/
読み込みではチュートリアルとの違いはそこまでなかったのですが、
書き込みに関しては、異なる部分がほんの少し増えました。
書き込み処理追加
- src/models.rs
#[derive(Queryable)] pub struct Post { pub id: i32, pub title: String, pub body: String, pub published: bool, } // 以下、追加部分 use super::schema::posts; #[derive(Insertable)] #[table_name="posts"] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, }
modelsには、postsテーブルを使うことを宣言しています。
そのため、schema.rsからposts
を読み込んでいます。
NewPostの構造体には、titleとbody定義しています。
これにより、DBに入力する際はtitleとbobyに対して値を代入することができます。
- src/lib.rs
#[macro_use] extern crate diesel; extern crate dotenv; pub mod schema; pub mod models; use diesel::prelude::*; use dotenv::dotenv; use diesel::mysql::MysqlConnection; use std::env; pub fn establish_connection() -> MysqlConnection { dotenv().ok(); let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); MysqlConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url)) } // 以下、追加部分 use self::models::{NewPost, Post}; pub fn create_post(conn: &MysqlConnection, title: &str, body: &str) -> Post { use self::schema::posts::dsl::{id, posts}; let new_post = NewPost { title: title, body: body, }; diesel::insert_into(posts) .values(&new_post) .execute(conn) .expect("Error saving new post"); posts.order(id.desc()).first(conn).unwrap() }
postsテーブルに書き込みを行うために必要な処理を書いています。
読み込み同様にPgConnection
の部分をMysqlConnection
に置き換えます。
チュートリアルではdiesel::insert_into
以下の処理は次のようになっています。
diesel::insert_into(posts::table) .values(&new_post) .get_result(conn) .expect("Error saving new post")
PostgreSQLでは.get_result(conn)
となっていますが、
MySQLでは execute(conn)
を使います。
dieselのドキュメントには、PostgreSQLなどのReturning句をサポートするものはexecute
の代わりにget_results
を使うと書いてあります。
https://docs.diesel.rs/diesel/fn.insert_into.html#examples
下記に関しては、自分で付け加えた部分になります。
戻り値をPostにしているため、行っていることとしてはidで降順にし、Postが返るようにしています。
ここでid
を使用しているため、use self::schema::posts::dsl::{id, posts};
でidを宣言している感じですね。
posts.order(id.desc()).first(conn).unwrap()
以下のwrite_post.rs
に関してはチュートリアルと変更はありません。
- src/bin/write_post.rs
extern crate diesel_demo; extern crate diesel; use self::diesel_demo::*; use std::io::{stdin, Read}; fn main() { let connection = establish_connection(); println!("What would you like your title to be?"); let mut title = String::new(); stdin().read_line(&mut title).unwrap(); let title = &title[..(title.len() - 1)]; // Drop the newline character println!("\nOk! Let's write {} (Press {} when finished)\n", title, EOF); let mut body = String::new(); stdin().read_to_string(&mut body).unwrap(); let post = create_post(&connection, title, &body); println!("\nSaved draft {} with id {}", title, post.id); } #[cfg(not(windows))] const EOF: &str = "CTRL+D"; #[cfg(windows)] const EOF: &str = "CTRL+Z";
ここまでできたら
docker-compose run --rm rust cargo run --bin write_post
で実行します。
What would you like your title to be? write_test Ok! Let's write write_test (Press CTRL+D when finished) hello Saved draft write_test with id 1
sqlに登録されているか確認すると
mysql> select * from posts; +----+------------+-------+-----------+ | id | title | body | published | +----+------------+-------+-----------+ | 1 | write_test | hello | 0 | +----+------------+-------+-----------+ 1 row in set (0.00 sec)
ちゃんと書き込みできていますね!
まとめ
前回に引き続き、dieselを用いたMySQL操作を行いました。 チュートリアルには、更新と削除処理もあるので試してみてください。
チュートリアルを一通り試すと、簡単なTODOリスト的なものはできそうですね!