tain/postgres/
postgres_config.rs

1use std::{collections::HashMap, path::PathBuf, str::FromStr};
2
3use anyhow::{Result, anyhow};
4use dotenvy::{dotenv, vars};
5use typed_builder::TypedBuilder;
6
7use crate::Mount;
8
9#[derive(Clone, TypedBuilder)]
10pub struct PostgresConfig {
11    #[builder(setter(into))]
12    pub container_name: String,
13
14    #[builder(default, setter(strip_option), setter(into))]
15    pub db: Option<String>,
16
17    #[builder(default, setter(strip_option), setter(into))]
18    pub password: Option<String>,
19
20    #[builder(default, setter(strip_option))]
21    pub data: Option<Mount>,
22
23    #[builder(default = 5432)]
24    pub port: u16,
25}
26
27impl PostgresConfig {
28    pub fn from_env() -> Result<Self> {
29        #[cfg(not(target_os = "windows"))]
30        fn data_host(vars: &HashMap<String, String>) -> Result<String> {
31            Ok(vars
32                .get("POSTGRES_DATA_HOST")
33                .ok_or(anyhow!("No POSTGRES_DATA_HOST in .env"))?
34                .to_string())
35        }
36
37        #[cfg(target_os = "windows")]
38        fn data_host(vars: &HashMap<String, String>) -> Result<String> {
39            let home = dirs::home_dir().expect("No HOME");
40            let host = vars.get("POSTGRES_DATA_HOST").ok_or(anyhow!("No POSTGRES_DATA_HOST in .env"))?;
41            let host = format!("{}{host}", home.display());
42            Ok(host)
43        }
44
45        dotenv()?;
46
47        let vars: HashMap<String, String> = vars().collect();
48
49        let db = vars.get("POSTGRES_DB").ok_or(anyhow!("No POSTGRES_DB in .env"))?;
50        let password = vars.get("POSTGRES_PASSWORD").ok_or(anyhow!("No POSTGRES_PASSWORD in .env"))?;
51        let port = vars.get("POSTGRES_PORT").ok_or(anyhow!("No POSTGRES_PORT in .env"))?;
52
53        let data_container = vars
54            .get("POSTGRES_DATA_CONTAINER")
55            .ok_or(anyhow!("No POSTGRES_DATA_CONTAINER in .env"))?;
56        let container_name = vars
57            .get("POSTGRES_CONTAINER_NAME")
58            .ok_or(anyhow!("No POSTGRES_CONTAINER_NAME in .env"))?;
59
60        let new = Self::builder()
61            .container_name(container_name)
62            .db(db)
63            .password(password)
64            .data(Mount {
65                host:      PathBuf::from_str(&data_host(&vars)?)?,
66                container: PathBuf::from_str(data_container)?,
67            })
68            .port(port.parse()?)
69            .build();
70
71        Ok(new)
72    }
73}