ゆるふわです
やりたいこと
Rustで簡単にサクッとローカルのPostgreSQLと連携し、こんな感じのテーブルをRust側から操作して作ります
id | name
-------------+----------
-838073477 | John Doe
-1966422589 | John Doe
-2115227795 | John Doe
(3 rows)
id
や name
には特に深い意味はありません
サンプルとして適当な値を入れているだけです
Rust側では標準入力で
標準入力 | 機能 |
---|---|
a | 乱数のidと名前(今回はJohn Doe固定)をrecordというdbに追加 |
s | テーブルを全表示 |
d | テーブルを全削除 |
といった機能をつけました。
動作環境
項目 | 値 |
---|---|
OS | Ubuntu22.04 On WSL2 |
Rust | 1.70.0 |
psql (PostgreSQL) | 15.3 |
流れ
- postgreSQLでrecordという名前の空のDBを作成
- Rustでプログラムを作成
- a, s, d等を入力してRust側でrecordを操作
- PostgreSQL側でテーブルを確認
といった手順になります。
それではそれぞれの項目について述べます。
1. postgreSQLで空のDB(名:record)を作成
1.インストール等の事前準備
sudo apt update
sudo apt install postgresql
sudo systemctl status postgresql
2. ターミナルを開いてpostgres
ユーザーに切り替え
sudo -u postgres psql
3. アカウントとrecord
DBの作成
CREATE USER your_username WITH PASSWORD 'your_password';
CREATE DATABASE record;
your_username
, your_password
を自分で設定してください
DB名を変えたい場合は、recordを任意の名前に置き換えてください
4. ユーザー"your_username"に対して権限付与
GRANT ALL PRIVILEGES ON DATABASE type_record TO your_username;
GRANT ALL PRIVILEGES ON SCHEMA public TO your_username;
データベースとスキーマ、両方にアクセス権限を付与することに注意してください
(私はここでDBにしか与えておらず、後に2時間ほど詰まりました)
2. Rustでプログラムを作成
1. dependenciesにクレートを追加
[dependencies]
+ tokio-postgres = "0.7"
+ tokio = { version = "1", features = ["full"] }
+ dotenv = "0.15.0"
+ rand = "0.8.4"
2. .envファイルに追記
+ DB_HOST=localhost
+ DB_PORT=5432
+ DB_USER=your_username
+ DB_PASSWORD=your_password
+ DB_NAME=record
your_username
, your_password
は
3.アカウントとrecord
DBの作成
で作成したものと同じです
.envファイルが無い方は、rustで作業しているディレクトリのルートに戻って
code .env
等で作成してください
3. Rustで実装
以下に例を示します。
適宜コメントを入れました。
use dotenv::dotenv;
use std::env;
use std::io::{self, BufRead};
use tokio_postgres::{NoTls, Error};
use rand::Rng;
#[tokio::main]
async fn main() -> Result<(), Error> {
// .env ファイルを読み込み
dotenv().ok();
// 環境変数から接続情報を取得
let db_host = env::var("DB_HOST").expect("DB_HOST not set");
let db_port = env::var("DB_PORT").expect("DB_PORT not set");
let db_user = env::var("DB_USER").expect("DB_USER not set");
let db_password = env::var("DB_PASSWORD").expect("DB_PASSWORD not set");
let db_name = env::var("DB_NAME").expect("DB_NAME not set");
// PostgreSQLの接続情報を設定
let connection_string = format!(
"host={} port={} user={} password={} dbname={}",
db_host, db_port, db_user, db_password, db_name
);
let (client, connection) = tokio_postgres::connect(&connection_string, NoTls).await?;
// 接続タスクをスポーンして実行
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
// テーブル作成のクエリを実行
client
.batch_execute(
"
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
)
",
)
.await?;
// 標準入力からキー入力を受け取るためのストリームを作成
let stdin = io::stdin();
let mut input_stream = stdin.lock().lines();
println!("Press 'a' to add a record, 'd' to delete all records, 's' to sort and display records, or any other key to exit.");
// キー入力を監視し、対応する操作を実行
while let Some(Ok(input)) = input_stream.next() {
match input.as_str() {
"a" => {
// レコードの追加
let mut rng = rand::thread_rng();
let id: i32 = rng.gen();
client
.execute(
"INSERT INTO users (id, name) VALUES ($1, $2)",
&[&id, &"John Doe"],
)
.await?;
println!("Record added.");
}
"d" => {
// レコードの削除
client.execute("DELETE FROM users", &[]).await?;
println!("All records deleted.");
}
"s" => {
// レコードのソートと表示
let rows = client
.query("SELECT id, name FROM users ORDER BY id", &[])
.await?;
for row in rows {
let id: i32 = row.get(0);
let name: &str = row.get(1);
println!("ID: {}, Name: {}", id, name);
}
}
_ => {
break;
}
}
}
Ok(())
}
3. [a, s, d]等を入力してRust側でrecordを操作
cargo run
で
Press 'a' to add a record, 'd' to delete all records, 's' to sort and display records, or any other key to exit.
などと表示されるので、[a]や[d], [s]をポチポチしてrecord
を操作していきましょう。
Press 'a' to add a record, 'd' to delete all records, 's' to sort and display records, or any other key to exit.
a
Record added.
a
Record added.
a
Record added.
s
ID: -2115227795, Name: John Doe
ID: -1966422589, Name: John Doe
ID: -838073477, Name: John Doe
正しくテーブルを作成することができました。
地味にIDでソートされています。
4. postgreSQL側でテーブルを確認
sudo -u postgres
psql -d type_record -c "SELECT * FROM users;"
を実行します。
以下のような結果が得られると成功です。
postgres=# \c type_record
You are now connected to database "type_record" as user "postgres".
type_record=# SELECT * FROM users;
id | name
-------------+----------
-838073477 | John Doe
-1966422589 | John Doe
-2115227795 | John Doe
(3 rows)
おわりに
Rust側からローカルのPostgreSQLをいじることができました。
HerokuやRender.com上のPostgreSQLとも連携できれば、Webアプリ開発の幅が広がりそうです。
お疲れさまでした。