データベースの利用

Diesel

use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection};
use once_cell::sync::OnceCell;
use salvo::prelude::*;

const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world";
type PgPool = Pool<ConnectionManager<PgConnection>>;

static DB_POOL: OnceCell<PgPool> = OnceCell::new();

fn connect() -> Result<PooledConnection<ConnectionManager<PgConnection>>, PoolError> {
    DB_POOL.get().unwrap().get()
}
fn build_pool(database_url: &str, size: u32) -> Result<PgPool, PoolError> {
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    diesel::r2d2::Pool::builder()
        .max_size(size)
        .min_idle(Some(size))
        .test_on_check_out(false)
        .idle_timeout(None)
        .max_lifetime(None)
        .build(manager)
}

fn main() {
    DB_POOL
        .set(build_pool(&DB_URL, 10).expect(&format!("Error connecting to {}", &DB_URL)))
        .ok();
}

#[handler]
async fn show_article(req: &mut Request, res: &mut Response) -> Result<(), Error> {
    let id: i64 = req.param::<i64>("id").unwrap_or_default();
    let conn = connect()?;
    let article = articles::table.find(id).first::<Article>(&conn)?;
    res.render(Json(row));
    Ok(())
}

Sqlx

main.rs
Cargo.toml
use std::sync::OnceLock;

use salvo::prelude::*;
use serde::Serialize;
use sqlx::{FromRow, PgPool};

// Global PostgreSQL connection pool instance
static POSTGRES: OnceLock<PgPool> = OnceLock::new();

// Helper function to get the PostgreSQL connection pool
#[inline]
pub fn get_postgres() -> &'static PgPool {
    POSTGRES.get().unwrap()
}

// User model representing the database table structure
// Implements FromRow for SQL query results and Serialize for JSON responses
#[derive(FromRow, Serialize, Debug)]
pub struct User {
    pub id: i64,
    pub username: String,
    pub password: String,
}

// Handler for retrieving a user by ID from the database
#[handler]
pub async fn get_user(req: &mut Request, res: &mut Response) {
    // Extract user ID from query parameters
    let uid = req.query::<i64>("uid").unwrap();
    // Execute SQL query to fetch user by ID
    let data = sqlx::query_as::<_, User>("select * from users where id = $1")
        .bind(uid)
        .fetch_one(get_postgres())
        .await
        .unwrap();
    // Return user data as JSON response
    res.render(serde_json::to_string(&data).unwrap());
}

#[tokio::main]
async fn main() {
    // Initialize logging system
    tracing_subscriber::fmt().init();

    // Configure PostgreSQL connection
    let postgres_uri = "postgres://postgres:password@localhost/test";
    // Create and initialize connection pool
    let pool = PgPool::connect(postgres_uri).await.unwrap();
    // Store pool in global state
    POSTGRES.set(pool).unwrap();

    // Configure router with user endpoint:
    // - GET /users?uid={id} : Get user by ID
    let router = Router::with_path("users").get(get_user);

    // Start server on port 8698
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

rbatis

main.rs
Cargo.toml
#[macro_use]
extern crate rbatis;
extern crate rbdc;

use std::sync::LazyLock;

use rbatis::RBatis;
use rbdc_mysql::driver::MysqlDriver;
use salvo::prelude::*;
use serde::{Deserialize, Serialize};

// Global RBatis instance for database operations
pub static RB: LazyLock<RBatis> = LazyLock::new(RBatis::new);

// User model representing the database table structure
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct User {
    pub id: i64,
    pub username: String,
    pub password: String,
}

// Implement select query for User model
// Generates SQL: SELECT * FROM user WHERE id = #{id} LIMIT 1
impl_select!(User{select_by_id(id:String) -> Option => "`where id = #{id} limit 1`"});

// Handler for retrieving a user by ID from the database
#[handler]
pub async fn get_user(req: &mut Request, res: &mut Response) {
    // Extract user ID from query parameters
    let uid = req.query::<i64>("uid").unwrap();
    // Execute select query and get user data
    let data = User::select_by_id(&*RB, uid.to_string()).await.unwrap();
    println!("{data:?}");
    // Return user data as JSON response
    res.render(serde_json::to_string(&data).unwrap());
}

#[tokio::main]
async fn main() {
    // Initialize logging system
    tracing_subscriber::fmt().init();

    // Configure MySQL connection
    let mysql_uri = "mysql://root:123456@localhost/test";
    // Initialize RBatis with MySQL driver and connection URI
    RB.init(MysqlDriver {}, mysql_uri).unwrap();

    // Configure router with user endpoint:
    // - GET /users?uid={id} : Get user by ID
    let router = Router::with_path("users").get(get_user);

    // Start server on port 8698
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

SeaORM

SeaORMは非同期・動的型付けのORMで、エンティティ関係、マイグレーションシステム、完全な型安全クエリビルダーを含む強力なリレーショナルデータベースサポートを提供します。フル機能ORMを必要とする中規模から大規模プロジェクトに適しています。

Tokio ORM (Toasty)

ToastyはTokioチームによって開発されているORMで、現在も活発に開発が進められており、Tokioエコシステムと緊密に統合されたORMソリューションの提供に注力しています。Tokioに依存し、新興技術を採用する意欲のあるプロジェクトに適している可能性があります。

SurrealDB Rust SDK

SurrealDBのRust SDKは、このマルチモデルデータベースとの接続機能を提供し、グラフデータ、ドキュメントデータ、リレーショナルデータを扱う必要があるアプリケーションに適しています。柔軟なデータモデルを必要とするプロジェクトにとって優れた選択肢です。