Skip to main content

rs_zero/db/
pool.rs

1#[cfg(any(feature = "db-sqlite", feature = "db-postgres", feature = "db-mysql"))]
2use sqlx::Pool as SqlxPool;
3#[cfg(feature = "db-mysql")]
4use sqlx::{MySql, mysql::MySqlPoolOptions};
5#[cfg(feature = "db-postgres")]
6use sqlx::{Postgres, postgres::PgPoolOptions};
7#[cfg(feature = "db-sqlite")]
8use sqlx::{Sqlite, sqlite::SqlitePoolOptions};
9
10use crate::db::{DatabaseConfig, DatabaseError, DatabaseKind, DatabaseResult};
11
12/// SQLite database pool.
13#[cfg(feature = "db-sqlite")]
14pub type SqliteDatabasePool = SqlxPool<Sqlite>;
15
16/// PostgreSQL database pool.
17#[cfg(feature = "db-postgres")]
18pub type PostgresDatabasePool = SqlxPool<Postgres>;
19
20/// MySQL database pool.
21#[cfg(feature = "db-mysql")]
22pub type MySqlDatabasePool = SqlxPool<MySql>;
23
24/// Database pool used by the enabled default adapter.
25#[cfg(feature = "db-sqlite")]
26pub type DatabasePool = SqliteDatabasePool;
27
28/// Database pool used when PostgreSQL is the enabled adapter.
29#[cfg(all(not(feature = "db-sqlite"), feature = "db-postgres"))]
30pub type DatabasePool = PostgresDatabasePool;
31
32/// Database pool used when MySQL is the only enabled adapter.
33#[cfg(all(
34    not(feature = "db-sqlite"),
35    not(feature = "db-postgres"),
36    feature = "db-mysql"
37))]
38pub type DatabasePool = MySqlDatabasePool;
39
40/// Connects a SQLx pool for the default enabled adapter.
41#[cfg(feature = "db-sqlite")]
42pub async fn connect_pool(config: &DatabaseConfig) -> DatabaseResult<DatabasePool> {
43    connect_sqlite_pool(config).await
44}
45
46/// Connects a SQLx pool for the default enabled adapter.
47#[cfg(all(not(feature = "db-sqlite"), feature = "db-postgres"))]
48pub async fn connect_pool(config: &DatabaseConfig) -> DatabaseResult<DatabasePool> {
49    connect_postgres_pool(config).await
50}
51
52/// Connects a SQLx pool for the default enabled adapter.
53#[cfg(all(
54    not(feature = "db-sqlite"),
55    not(feature = "db-postgres"),
56    feature = "db-mysql"
57))]
58pub async fn connect_pool(config: &DatabaseConfig) -> DatabaseResult<DatabasePool> {
59    connect_mysql_pool(config).await
60}
61
62/// Connects a SQLite SQLx pool.
63#[cfg(feature = "db-sqlite")]
64pub async fn connect_sqlite_pool(config: &DatabaseConfig) -> DatabaseResult<SqliteDatabasePool> {
65    if config.kind != DatabaseKind::Sqlite {
66        return Err(DatabaseError::Unsupported(
67            "sqlite database kind required".to_string(),
68        ));
69    }
70    Ok(SqlitePoolOptions::new()
71        .max_connections(config.max_connections)
72        .acquire_timeout(config.connect_timeout)
73        .connect(&config.url)
74        .await?)
75}
76
77/// Connects a PostgreSQL SQLx pool.
78#[cfg(feature = "db-postgres")]
79pub async fn connect_postgres_pool(
80    config: &DatabaseConfig,
81) -> DatabaseResult<PostgresDatabasePool> {
82    if config.kind != DatabaseKind::Postgres {
83        return Err(DatabaseError::Unsupported(
84            "postgres database kind required".to_string(),
85        ));
86    }
87    Ok(PgPoolOptions::new()
88        .max_connections(config.max_connections)
89        .acquire_timeout(config.connect_timeout)
90        .connect(&config.url)
91        .await?)
92}
93
94/// Connects a MySQL SQLx pool.
95#[cfg(feature = "db-mysql")]
96pub async fn connect_mysql_pool(config: &DatabaseConfig) -> DatabaseResult<MySqlDatabasePool> {
97    if config.kind != DatabaseKind::Mysql {
98        return Err(DatabaseError::Unsupported(
99            "mysql database kind required".to_string(),
100        ));
101    }
102    Ok(MySqlPoolOptions::new()
103        .max_connections(config.max_connections)
104        .acquire_timeout(config.connect_timeout)
105        .connect(&config.url)
106        .await?)
107}
108
109/// Runs a lightweight health check on the default pool type.
110pub async fn health_check(pool: &DatabasePool) -> DatabaseResult<()> {
111    sqlx::query("SELECT 1").execute(pool).await?;
112    Ok(())
113}
114
115/// Runs a lightweight PostgreSQL health check.
116#[cfg(all(feature = "db-postgres", feature = "db-sqlite"))]
117pub async fn health_check_postgres(pool: &PostgresDatabasePool) -> DatabaseResult<()> {
118    sqlx::query("SELECT 1").execute(pool).await?;
119    Ok(())
120}
121
122/// Runs a lightweight MySQL health check.
123#[cfg(all(
124    feature = "db-mysql",
125    any(feature = "db-sqlite", feature = "db-postgres")
126))]
127pub async fn health_check_mysql(pool: &MySqlDatabasePool) -> DatabaseResult<()> {
128    sqlx::query("SELECT 1").execute(pool).await?;
129    Ok(())
130}
131
132#[cfg(test)]
133mod tests {
134    use crate::db::{DatabaseConfig, DatabaseKind};
135    #[cfg(feature = "db-sqlite")]
136    use crate::db::{connect_pool, health_check};
137
138    #[cfg(feature = "db-sqlite")]
139    #[tokio::test]
140    async fn sqlite_pool_passes_health_check() {
141        let pool = connect_pool(&DatabaseConfig::default())
142            .await
143            .expect("pool");
144        health_check(&pool).await.expect("health");
145    }
146
147    #[test]
148    fn postgres_config_uses_postgres_kind() {
149        let config = DatabaseConfig::postgres("postgres://localhost/app");
150        assert_eq!(config.kind, DatabaseKind::Postgres);
151    }
152
153    #[test]
154    fn mysql_config_uses_mysql_kind() {
155        let config = DatabaseConfig::mysql("mysql://localhost/app");
156        assert_eq!(config.kind, DatabaseKind::Mysql);
157    }
158}