fraiseql_server/config/
env.rs1use std::{env, time::Duration};
8
9pub fn resolve_env_value(value: &str) -> Result<String, EnvError> {
16 if value.starts_with("${") && value.ends_with('}') {
17 let var_name = &value[2..value.len() - 1];
18
19 if let Some((name, default)) = var_name.split_once(":-") {
21 return env::var(name).or_else(|_| Ok(default.to_string()));
22 }
23
24 if let Some((name, message)) = var_name.split_once(":?") {
26 return env::var(name).map_err(|_| EnvError::MissingVarWithMessage {
27 name: name.to_string(),
28 message: message.to_string(),
29 });
30 }
31
32 env::var(var_name).map_err(|_| EnvError::MissingVar {
33 name: var_name.to_string(),
34 })
35 } else {
36 Ok(value.to_string())
37 }
38}
39
40pub fn get_env_value(env_var_name: &str) -> Result<String, EnvError> {
46 env::var(env_var_name).map_err(|_| EnvError::MissingVar {
47 name: env_var_name.to_string(),
48 })
49}
50
51pub fn parse_size(s: &str) -> Result<usize, ParseError> {
57 let s = s.trim();
58 let s_upper = s.to_uppercase();
59
60 let (num_str, multiplier) = if s_upper.ends_with("GB") {
61 (&s[..s.len() - 2], 1024 * 1024 * 1024)
62 } else if s_upper.ends_with("MB") {
63 (&s[..s.len() - 2], 1024 * 1024)
64 } else if s_upper.ends_with("KB") {
65 (&s[..s.len() - 2], 1024)
66 } else if s_upper.ends_with('B') {
67 (&s[..s.len() - 1], 1)
68 } else {
69 (s, 1)
71 };
72
73 let num: usize = num_str.trim().parse().map_err(|_| ParseError::InvalidSize {
74 value: s.to_string(),
75 reason: "Invalid number".to_string(),
76 })?;
77
78 num.checked_mul(multiplier).ok_or_else(|| ParseError::InvalidSize {
79 value: s.to_string(),
80 reason: "Value too large".to_string(),
81 })
82}
83
84pub fn parse_duration(s: &str) -> Result<Duration, ParseError> {
91 let s = s.trim().to_lowercase();
92
93 let (num_str, multiplier_ms) = if s.ends_with("ms") {
94 (&s[..s.len() - 2], 1u64)
95 } else if s.ends_with('s') {
96 (&s[..s.len() - 1], 1000)
97 } else if s.ends_with('m') {
98 (&s[..s.len() - 1], 60 * 1000)
99 } else if s.ends_with('h') {
100 (&s[..s.len() - 1], 60 * 60 * 1000)
101 } else if s.ends_with('d') {
102 (&s[..s.len() - 1], 24 * 60 * 60 * 1000)
103 } else {
104 return Err(ParseError::InvalidDuration {
105 value: s,
106 reason: "Missing unit (ms, s, m, h, d)".to_string(),
107 });
108 };
109
110 let num: u64 = num_str.trim().parse().map_err(|_| ParseError::InvalidDuration {
111 value: s.clone(),
112 reason: "Invalid number".to_string(),
113 })?;
114
115 Ok(Duration::from_millis(num * multiplier_ms))
116}
117
118#[derive(Debug, thiserror::Error)]
120#[non_exhaustive]
121pub enum EnvError {
122 #[error("Missing environment variable: {name}")]
124 MissingVar {
125 name: String,
127 },
128
129 #[error("Missing environment variable {name}: {message}")]
131 MissingVarWithMessage {
132 name: String,
134 message: String,
136 },
137}
138
139#[derive(Debug, thiserror::Error)]
141#[non_exhaustive]
142pub enum ParseError {
143 #[error("Invalid size value '{value}': {reason}")]
145 InvalidSize {
146 value: String,
148 reason: String,
150 },
151
152 #[error("Invalid duration value '{value}': {reason}")]
154 InvalidDuration {
155 value: String,
157 reason: String,
159 },
160}