Skip to main content

state_engine/
load.rs

1use crate::ports::required::{
2    DbClient, EnvClient, KVSClient,
3    InMemoryClient,
4};
5use crate::common::bit;
6use serde_json::Value;
7use std::collections::HashMap;
8
9pub struct Load<'a> {
10    db_client: Option<&'a dyn DbClient>,
11    kvs_client: Option<&'a dyn KVSClient>,
12    in_memory: Option<&'a dyn InMemoryClient>,
13    env_client: Option<&'a dyn EnvClient>,
14}
15
16impl<'a> Load<'a> {
17    pub fn new() -> Self {
18        Self {
19            db_client: None,
20            kvs_client: None,
21            in_memory: None,
22            env_client: None,
23        }
24    }
25
26    pub fn with_db_client(mut self, client: &'a dyn DbClient) -> Self {
27        self.db_client = Some(client);
28        self
29    }
30
31    pub fn with_kvs_client(mut self, client: &'a dyn KVSClient) -> Self {
32        self.kvs_client = Some(client);
33        self
34    }
35
36    pub fn with_in_memory(mut self, client: &'a dyn InMemoryClient) -> Self {
37        self.in_memory = Some(client);
38        self
39    }
40
41    pub fn with_env_client(mut self, client: &'a dyn EnvClient) -> Self {
42        self.env_client = Some(client);
43        self
44    }
45
46    pub fn handle(&self, config: &HashMap<String, Value>) -> Result<Value, String> {
47        let client = config
48            .get("client")
49            .and_then(|v| v.as_u64())
50            .ok_or("Load::handle: 'client' not found in _load config")?;
51
52        match client {
53            bit::CLIENT_ENV       => self.load_from_env(config),
54            bit::CLIENT_IN_MEMORY => self.load_from_in_memory(config),
55            bit::CLIENT_KVS       => self.load_from_kvs(config),
56            bit::CLIENT_DB        => self.load_from_db(config),
57            _ => Err(format!("Load::handle: unsupported client '{}'", client)),
58        }
59    }
60
61    fn load_from_env(
62        &self,
63        config: &HashMap<String, Value>,
64    ) -> Result<Value, String> {
65        let env_client = self
66            .env_client
67            .ok_or("Load::load_from_env: EnvClient not configured")?;
68
69        let map = config
70            .get("map")
71            .and_then(|v| v.as_object())
72            .ok_or("Load::load_from_env: 'map' not found")?;
73
74        let mut result = serde_json::Map::new();
75
76        for (config_key, env_key_value) in map {
77            if let Some(env_key) = env_key_value.as_str() {
78                if let Some(value) = env_client.get(env_key) {
79                    result.insert(config_key.clone(), Value::String(value));
80                }
81            }
82        }
83
84        Ok(Value::Object(result))
85    }
86
87    fn load_from_in_memory(
88        &self,
89        config: &HashMap<String, Value>,
90    ) -> Result<Value, String> {
91        let in_memory = self
92            .in_memory
93            .ok_or("Load::load_from_in_memory: InMemoryClient not configured")?;
94
95        let key = config
96            .get("key")
97            .and_then(|v| v.as_str())
98            .ok_or("Load::load_from_in_memory: 'key' not found")?;
99
100        in_memory
101            .get(key)
102            .ok_or_else(|| format!("Load::load_from_in_memory: key '{}' not found", key))
103    }
104
105    fn load_from_kvs(
106        &self,
107        config: &HashMap<String, Value>,
108    ) -> Result<Value, String> {
109        let kvs_client = self
110            .kvs_client
111            .ok_or("Load::load_from_kvs: KVSClient not configured")?;
112
113        let key = config
114            .get("key")
115            .and_then(|v| v.as_str())
116            .ok_or("Load::load_from_kvs: 'key' not found")?;
117
118        let value_str = kvs_client
119            .get(key)
120            .ok_or_else(|| format!("Load::load_from_kvs: key '{}' not found", key))?;
121
122        serde_json::from_str(&value_str)
123            .map_err(|e| format!("Load::load_from_kvs: JSON parse error: {}", e))
124    }
125
126    fn load_from_db(
127        &self,
128        config: &HashMap<String, Value>,
129    ) -> Result<Value, String> {
130        let db_client = self
131            .db_client
132            .ok_or("Load::load_from_db: DbClient not configured")?;
133
134        let table = config
135            .get("table")
136            .and_then(|v| v.as_str())
137            .ok_or("Load::load_from_db: 'table' not found")?;
138
139        let where_clause = config.get("where").and_then(|v| v.as_str());
140
141        let map = config
142            .get("map")
143            .and_then(|v| v.as_object())
144            .ok_or("Load::load_from_db: 'map' not found")?;
145
146        let connection = config
147            .get("connection")
148            .ok_or("Load::load_from_db: 'connection' not specified")?;
149
150        let columns: Vec<&str> = map
151            .values()
152            .filter_map(|v| v.as_str())
153            .collect();
154
155        if columns.is_empty() {
156            return Err("Load::load_from_db: no columns specified in map".to_string());
157        }
158
159        let rows = db_client
160            .fetch(connection, table, &columns, where_clause)
161            .ok_or_else(|| format!("Load::load_from_db: fetch failed for table '{}'", table))?;
162
163        if rows.is_empty() {
164            return Err(format!("Load::load_from_db: no data found in table '{}'", table));
165        }
166
167        let row = &rows[0];
168
169        let mut result = serde_json::Map::new();
170        for (config_key, db_column_value) in map {
171            if let Some(db_column) = db_column_value.as_str() {
172                if let Some(value) = row.get(db_column) {
173                    result.insert(config_key.clone(), value.clone());
174                }
175            }
176        }
177
178        Ok(Value::Object(result))
179    }
180
181    // feature function: load with API Cleint
182    // fn load_from_api(
183    //     &self,
184    //     config: &HashMap<String, Value>,
185    // ) -> Result<Value, String> {
186    //     let api_client = self
187    //         .api_client
188    //         .ok_or("Load::load_from_api: APIClient not configured")?;
189
190    //     let url = config
191    //         .get("url")
192    //         .and_then(|v| v.as_str())
193    //         .ok_or("Load::load_from_api: 'url' not found")?;
194
195    //     // placeholder はすでに resolved_config で解決済み
196
197    //     // headers処理(optional)
198    //     let headers = config.get("headers").and_then(|v| v.as_object()).map(|h| {
199    //         h.iter()
200    //             .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
201    //             .collect::<HashMap<String, String>>()
202    //     });
203
204    //     api_client.get(url, headers.as_ref())
205    // }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    struct MockEnvClient;
213    impl EnvClient for MockEnvClient {
214        fn get(&self, key: &str) -> Option<String> {
215            match key {
216                "Db_HOST" => Some("localhost".to_string()),
217                "Db_PORT" => Some("5432".to_string()),
218                _ => None,
219            }
220        }
221    }
222
223    #[test]
224    fn test_load_from_env() {
225        let env_client = MockEnvClient;
226        let load = Load::new().with_env_client(&env_client);
227
228        let mut config = HashMap::new();
229        config.insert("client".to_string(), Value::Number(bit::CLIENT_ENV.into()));
230
231        let mut map = serde_json::Map::new();
232        map.insert("host".to_string(), Value::String("Db_HOST".to_string()));
233        map.insert("port".to_string(), Value::String("Db_PORT".to_string()));
234        config.insert("map".to_string(), Value::Object(map));
235
236        let result = load.handle(&config).unwrap();
237
238        assert_eq!(result.get("host"), Some(&Value::String("localhost".to_string())));
239        assert_eq!(result.get("port"), Some(&Value::String("5432".to_string())));
240    }
241
242}