Skip to main content

slave_framework/
database.rs

1//! The application's [Toasty](https://github.com/tokio-rs/toasty) database.
2//!
3//! Models are Rust structs with `#[derive(toasty::Model)]`; this module opens
4//! the connection pool they run on, on PostgreSQL. Configure it with
5//! `DATABASE_URL` (default [`DEFAULT_URL`]). Several processes and machines
6//! can share the database.
7//!
8//! Schema changes are Toasty migrations: generated from the models by the
9//! app's `migrate` binary (built on `toasty-cli`) and applied by it.
10
11use toasty::{Db, ModelSet};
12
13use crate::Result;
14
15/// Transaction isolation levels, for [`toasty::TransactionBuilder::isolation`].
16/// `Serializable` transactions may fail with a serialization failure under
17/// contention; retry them ([`SERIALIZABLE_ATTEMPTS`]).
18pub use toasty_core::driver::operation::IsolationLevel;
19
20/// How many times to run a `Serializable` transaction that keeps failing
21/// with a serialization failure before giving up.
22pub const SERIALIZABLE_ATTEMPTS: usize = 5;
23
24/// Environment variable holding the database URL.
25pub const URL_ENV: &str = "DATABASE_URL";
26
27/// The database used when `DATABASE_URL` is not set: a local PostgreSQL.
28pub const DEFAULT_URL: &str = "postgresql://localhost:5432/postgres";
29
30/// Where to connect.
31#[derive(Debug, Clone)]
32pub struct DatabaseConfig {
33    /// A Toasty connection URL, e.g. `postgresql://user:pass@host:5432/app`.
34    pub url: String,
35}
36
37impl DatabaseConfig {
38    /// Reads `DATABASE_URL`, falling back to [`DEFAULT_URL`].
39    pub fn from_env() -> Self {
40        Self {
41            url: crate::env::var_or(URL_ENV, DEFAULT_URL),
42        }
43    }
44}
45
46/// Opens a pooled handle to the database for `models`. Cheap to clone: clones
47/// share the pool.
48pub async fn connect(models: ModelSet, config: &DatabaseConfig) -> Result<Db> {
49    Ok(Db::builder().models(models).connect(&config.url).await?)
50}