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}