Skip to main content

laterite_core/
db.rs

1//! Database connectivity.
2//!
3//! The pool is `sqlx::Any`, so a deployment runs on Postgres, MySQL, or SQLite
4//! by its configured URL. [`Db`] pairs the pool with the concrete [`DbBackend`]
5//! (inferred from the URL) so the query and migration layers can render SQL for
6//! the running backend.
7
8use std::time::Duration;
9
10use sqlx::any::{install_default_drivers, AnyPoolOptions};
11use sqlx::AnyPool;
12
13use crate::config::DatabaseConfig;
14use crate::error::CoreResult;
15use crate::migration::DbBackend;
16
17/// An application database handle: the connection pool plus the backend it
18/// speaks. Cheap to clone (the pool is reference-counted).
19#[derive(Clone)]
20pub struct Db {
21    pub pool: AnyPool,
22    pub backend: DbBackend,
23}
24
25impl Db {
26    /// Wraps an existing pool with a known backend (used by tests).
27    pub fn new(pool: AnyPool, backend: DbBackend) -> Self {
28        Self { pool, backend }
29    }
30}
31
32/// Creates the application database handle from configuration. Installs the
33/// `sqlx::Any` drivers on first use so any supported backend can be dialled.
34pub async fn connect(cfg: &DatabaseConfig) -> CoreResult<Db> {
35    install_default_drivers();
36    let backend = DbBackend::from_url(&cfg.url)?;
37    let pool = AnyPoolOptions::new()
38        .max_connections(cfg.max_connections)
39        .acquire_timeout(Duration::from_secs(cfg.acquire_timeout_secs))
40        .connect(&cfg.url)
41        .await?;
42    Ok(Db { pool, backend })
43}