Skip to main content

naru_core/core/
config_model.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Serialize, Deserialize, Clone)]
5pub struct ConfigFile {
6    pub project_name: String,
7    pub version: String,
8    pub environments: HashMap<String, EnvironmentConfig>,
9    pub salt: Option<String>,
10}
11
12#[derive(Debug, Serialize, Deserialize, Clone, Default)]
13pub struct EnvironmentConfig {
14    pub parent: Option<String>,
15    pub entries: HashMap<String, ConfigValueEntry>,
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone)]
19pub struct ConfigValueEntry {
20    pub value: String,
21    pub r#type: String,
22    pub is_secret: bool,
23    pub encrypted: bool,
24}
25
26impl ConfigValueEntry {
27    pub fn new(value: &str, r#type: &str, is_secret: bool) -> Self {
28        ConfigValueEntry {
29            value: value.to_string(),
30            r#type: r#type.to_string(),
31            is_secret,
32            encrypted: false,
33        }
34    }
35
36    pub fn validate(
37        &self,
38        field: &crate::core::schema_model::FieldDefinition,
39    ) -> Result<(), String> {
40        crate::core::validator::validate_value(&self.value, field)
41    }
42}
43
44impl ConfigFile {
45    pub fn new(project_name: &str) -> Self {
46        ConfigFile {
47            project_name: project_name.to_string(),
48            version: "1.0.0".to_string(),
49            environments: HashMap::new(),
50            salt: None,
51        }
52    }
53
54    pub fn add_environment(&mut self, name: &str) -> &mut EnvironmentConfig {
55        self.environments
56            .entry(name.to_string())
57            .or_insert_with(|| EnvironmentConfig::default())
58    }
59
60    pub fn get_environment(&self, name: &str) -> Option<&EnvironmentConfig> {
61        self.environments.get(name)
62    }
63
64    pub fn get_environment_mut(&mut self, name: &str) -> Option<&mut EnvironmentConfig> {
65        self.environments.get_mut(name)
66    }
67}
68
69impl EnvironmentConfig {
70    pub fn new() -> Self {
71        EnvironmentConfig {
72            parent: None,
73            entries: HashMap::new(),
74        }
75    }
76
77    pub fn with_parent(parent: &str) -> Self {
78        EnvironmentConfig {
79            parent: Some(parent.to_string()),
80            entries: HashMap::new(),
81        }
82    }
83
84    pub fn set_value(&mut self, key: &str, value: ConfigValueEntry) {
85        self.entries.insert(key.to_string(), value);
86    }
87
88    pub fn get_value(&self, key: &str) -> Option<&ConfigValueEntry> {
89        self.entries.get(key)
90    }
91
92    pub fn remove_value(&mut self, key: &str) -> Option<ConfigValueEntry> {
93        self.entries.remove(key)
94    }
95
96    pub fn keys(&self) -> impl Iterator<Item = &String> {
97        self.entries.keys()
98    }
99
100    pub fn values(&self) -> impl Iterator<Item = &ConfigValueEntry> {
101        self.entries.values()
102    }
103
104    pub fn is_empty(&self) -> bool {
105        self.entries.is_empty()
106    }
107
108    pub fn len(&self) -> usize {
109        self.entries.len()
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_config_value_entry_new() {
119        let entry = ConfigValueEntry::new("test_value", "string", true);
120        assert_eq!(entry.value, "test_value");
121        assert_eq!(entry.r#type, "string");
122        assert!(entry.is_secret);
123        assert!(!entry.encrypted);
124    }
125
126    #[test]
127    fn test_config_file_new() {
128        let config = ConfigFile::new("TestProject");
129        assert_eq!(config.project_name, "TestProject");
130        assert_eq!(config.version, "1.0.0");
131        assert!(config.environments.is_empty());
132    }
133
134    #[test]
135    fn test_environment_config_new() {
136        let env = EnvironmentConfig::new();
137        assert!(env.parent.is_none());
138        assert!(env.entries.is_empty());
139    }
140
141    #[test]
142    fn test_environment_config_with_parent() {
143        let env = EnvironmentConfig::with_parent("development");
144        assert_eq!(env.parent, Some("development".to_string()));
145    }
146
147    #[test]
148    fn test_config_file_add_environment() {
149        let mut config = ConfigFile::new("Test");
150        config.add_environment("production");
151        assert!(config.environments.contains_key("production"));
152    }
153
154    #[test]
155    fn test_config_value_entry_validate_mismatch() {
156        let entry = ConfigValueEntry::new("not_an_int", "integer", false);
157        let field = crate::core::schema_model::FieldDefinition {
158            key: "test".into(),
159            r#type: "integer".into(),
160            description: None,
161            validation: None,
162            is_secret: false,
163        };
164        assert!(entry.validate(&field).is_err());
165    }
166
167    #[test]
168    fn test_config_file_clone() {
169        let mut environments = HashMap::new();
170        let mut entries = HashMap::new();
171        entries.insert("K1".into(), ConfigValueEntry::new("V1", "string", false));
172        environments.insert(
173            "dev".into(),
174            EnvironmentConfig {
175                parent: None,
176                entries,
177            },
178        );
179
180        let config = ConfigFile {
181            project_name: "Test".into(),
182            version: "1.0".into(),
183            environments,
184            salt: None,
185        };
186
187        let cloned = config.clone();
188        assert_eq!(cloned.project_name, config.project_name);
189        assert_eq!(cloned.environments.len(), config.environments.len());
190    }
191
192    #[test]
193    fn test_empty_config_value_entry() {
194        let entry = ConfigValueEntry::new("", "string", false);
195        assert_eq!(entry.value, "");
196    }
197
198    #[test]
199    fn test_environment_set_and_get_value() {
200        let mut env = EnvironmentConfig::new();
201        env.set_value("KEY1", ConfigValueEntry::new("value1", "string", false));
202
203        assert!(env.get_value("KEY1").is_some());
204        assert_eq!(env.get_value("KEY1").unwrap().value, "value1");
205    }
206
207    #[test]
208    fn test_environment_remove_value() {
209        let mut env = EnvironmentConfig::new();
210        env.set_value("KEY1", ConfigValueEntry::new("value1", "string", false));
211
212        let removed = env.remove_value("KEY1");
213        assert!(removed.is_some());
214        assert!(env.get_value("KEY1").is_none());
215    }
216
217    #[test]
218    fn test_environment_len_and_is_empty() {
219        let mut env = EnvironmentConfig::new();
220        assert!(env.is_empty());
221        assert_eq!(env.len(), 0);
222
223        env.set_value("KEY1", ConfigValueEntry::new("value1", "string", false));
224        assert!(!env.is_empty());
225        assert_eq!(env.len(), 1);
226    }
227}