fraiseql_server/config/
env.rs1use std::{env, time::Duration};
2
3pub fn resolve_env_value(value: &str) -> Result<String, EnvError> {
5 if value.starts_with("${") && value.ends_with("}") {
6 let var_name = &value[2..value.len() - 1];
7
8 if let Some((name, default)) = var_name.split_once(":-") {
10 return env::var(name).or_else(|_| Ok(default.to_string()));
11 }
12
13 if let Some((name, message)) = var_name.split_once(":?") {
15 return env::var(name).map_err(|_| EnvError::MissingVarWithMessage {
16 name: name.to_string(),
17 message: message.to_string(),
18 });
19 }
20
21 env::var(var_name).map_err(|_| EnvError::MissingVar {
22 name: var_name.to_string(),
23 })
24 } else {
25 Ok(value.to_string())
26 }
27}
28
29pub fn get_env_value(env_var_name: &str) -> Result<String, EnvError> {
31 env::var(env_var_name).map_err(|_| EnvError::MissingVar {
32 name: env_var_name.to_string(),
33 })
34}
35
36pub fn parse_size(s: &str) -> Result<usize, ParseError> {
38 let s = s.trim();
39 let s_upper = s.to_uppercase();
40
41 let (num_str, multiplier) = if s_upper.ends_with("GB") {
42 (&s[..s.len() - 2], 1024 * 1024 * 1024)
43 } else if s_upper.ends_with("MB") {
44 (&s[..s.len() - 2], 1024 * 1024)
45 } else if s_upper.ends_with("KB") {
46 (&s[..s.len() - 2], 1024)
47 } else if s_upper.ends_with("B") {
48 (&s[..s.len() - 1], 1)
49 } else {
50 (s, 1)
52 };
53
54 let num: usize = num_str.trim().parse().map_err(|_| ParseError::InvalidSize {
55 value: s.to_string(),
56 reason: "Invalid number".to_string(),
57 })?;
58
59 num.checked_mul(multiplier).ok_or_else(|| ParseError::InvalidSize {
60 value: s.to_string(),
61 reason: "Value too large".to_string(),
62 })
63}
64
65pub fn parse_duration(s: &str) -> Result<Duration, ParseError> {
67 let s = s.trim().to_lowercase();
68
69 let (num_str, multiplier_ms) = if s.ends_with("ms") {
70 (&s[..s.len() - 2], 1u64)
71 } else if s.ends_with('s') {
72 (&s[..s.len() - 1], 1000)
73 } else if s.ends_with('m') {
74 (&s[..s.len() - 1], 60 * 1000)
75 } else if s.ends_with('h') {
76 (&s[..s.len() - 1], 60 * 60 * 1000)
77 } else if s.ends_with('d') {
78 (&s[..s.len() - 1], 24 * 60 * 60 * 1000)
79 } else {
80 return Err(ParseError::InvalidDuration {
81 value: s,
82 reason: "Missing unit (ms, s, m, h, d)".to_string(),
83 });
84 };
85
86 let num: u64 = num_str.trim().parse().map_err(|_| ParseError::InvalidDuration {
87 value: s.clone(),
88 reason: "Invalid number".to_string(),
89 })?;
90
91 Ok(Duration::from_millis(num * multiplier_ms))
92}
93
94#[derive(Debug, thiserror::Error)]
95pub enum EnvError {
96 #[error("Missing environment variable: {name}")]
97 MissingVar { name: String },
98
99 #[error("Missing environment variable {name}: {message}")]
100 MissingVarWithMessage { name: String, message: String },
101}
102
103#[derive(Debug, thiserror::Error)]
104pub enum ParseError {
105 #[error("Invalid size value '{value}': {reason}")]
106 InvalidSize { value: String, reason: String },
107
108 #[error("Invalid duration value '{value}': {reason}")]
109 InvalidDuration { value: String, reason: String },
110}