Skip to main content

state_engine/state/
mod.rs

1// State impl
2use crate::load::Load;
3use crate::ports::provided::{Manifest as ManifestTrait, State as StateTrait};
4use crate::ports::required::{KVSClient, InMemoryClient};
5use crate::common::{DotArrayAccessor, PlaceholderResolver};
6use serde_json::Value;
7use std::collections::HashMap;
8
9/// State impl
10///
11/// depends on: Manifest YAML meta data(_state, _store, _load)
12/// func: placeholder resolution, self calling, store CRUD
13pub struct State<'a> {
14    dot_accessor: DotArrayAccessor,
15    manifest: &'a mut dyn ManifestTrait,
16    load: Load<'a>,
17    in_memory: Option<&'a mut dyn InMemoryClient>,
18    kvs_client: Option<&'a mut dyn KVSClient>,
19    recursion_depth: usize,
20    max_recursion: usize,
21    cache: Value,  // instance cache(single collection object)
22}
23
24impl<'a> State<'a> {
25    /// create a new State instance
26    pub fn new(manifest: &'a mut dyn ManifestTrait, load: Load<'a>) -> Self {
27        Self {
28            manifest,
29            load,
30            in_memory: None,
31            kvs_client: None,
32            recursion_depth: 0,
33            max_recursion: 10,
34            cache: Value::Object(serde_json::Map::new()),
35            dot_accessor: DotArrayAccessor::new(),
36        }
37    }
38
39    /// move InMemoryClient ownership
40    pub fn with_in_memory(mut self, client: &'a mut dyn InMemoryClient) -> Self {
41        self.in_memory = Some(client);
42        self
43    }
44
45    /// move KVSClient ownership
46    pub fn with_kvs_client(mut self, client: &'a mut dyn KVSClient) -> Self {
47        self.kvs_client = Some(client);
48        self
49    }
50
51    /// storeから取得した値から、要求された子フィールドを抽出
52    ///
53    /// key="cache.user.org_id" で _store が "cache.user" レベルで定義されている場合、
54    /// storeには user オブジェクト全体が保存されているため、"org_id" フィールドを抽出する。
55    fn extract_field_from_value(key: &str, value: Value, meta: &HashMap<String, Value>) -> Value {
56        // metaに _store が含まれている場合、直接マッチしたので値をそのまま返す
57        // (cache.user を取得した場合)
58        if let Some(store_meta) = meta.get("_store") {
59            if let Some(_store_obj) = store_meta.as_object() {
60                // _store の定義が継承でなく、このレベルで直接定義されているか確認
61                // ここでは簡易的に、keyの最後の部分とvalueの構造で判断
62                // cache.user → value全体を返す
63                // cache.user.org_id → valueから org_id を抽出
64
65                // keyの階層を分解
66                let parts: Vec<&str> = key.split('.').collect();
67                if parts.len() < 2 {
68                    return value;
69                }
70
71                // 最後の部分が value の中のフィールドとして存在するか確認
72                let last_field = parts[parts.len() - 1];
73                if let Some(field_value) = value.get(last_field) {
74                    // 子フィールドが存在する → 抽出して返す
75                    return field_value.clone();
76                }
77            }
78        }
79
80        // それ以外は値をそのまま返す
81        value
82    }
83
84    /// placeholder を解決
85    ///
86    /// Manifestが既に完全修飾パス(manifestDir path)を返すため、
87    /// nameをそのままkeyとして使用
88    fn resolve_placeholder(&mut self, name: &str) -> Option<Value> {
89        // キャッシュを優先チェック(高速パス)
90        if let Some(cached) = self.dot_accessor.get(&self.cache, name) {
91            return Some(cached.clone());
92        }
93
94        // キャッシュミス時はフル処理
95        self.get(name)
96    }
97
98    /// load_config 内の placeholder を解決
99    fn resolve_load_config(&mut self, load_config: &HashMap<String, Value>) -> HashMap<String, Value> {
100        let config_value = Value::Object(load_config.iter().map(|(k, v)| (k.clone(), v.clone())).collect());
101        let mut resolver = |placeholder_name: &str| -> Option<Value> {
102            self.resolve_placeholder(placeholder_name)
103        };
104        let resolved_value = PlaceholderResolver::resolve_typed(config_value, &mut resolver);
105        if let Value::Object(map) = resolved_value {
106            map.into_iter().collect()
107        } else {
108            HashMap::new()
109        }
110    }
111
112    /// _store 設定から値を取得
113    fn get_from_store(&self, store_config: &HashMap<String, Value>) -> Option<Value> {
114        let client = store_config.get("client")?.as_str()?;
115
116        match client {
117            "InMemory" => {
118                let in_memory = self.in_memory.as_ref()?;
119                let key = store_config.get("key")?.as_str()?;
120                in_memory.get(key)
121            }
122            "KVS" => {
123                let kvs_client = self.kvs_client.as_ref()?;
124                let key = store_config.get("key")?.as_str()?;
125                let value_str = kvs_client.get(key)?;
126
127                // deserialize処理
128                // 全ての値はJSON形式で保存されている(型情報保持)
129                // JSON parse → Number/String/Bool/Null/Array/Objectを正確に復元
130                serde_json::from_str(&value_str).ok()
131            }
132            _ => None,
133        }
134    }
135
136    /// _store 設定に値を保存
137    fn set_to_store(
138        &mut self,
139        store_config: &HashMap<String, Value>,
140        value: Value,
141        ttl: Option<u64>,
142    ) -> bool {
143        let client = match store_config.get("client").and_then(|v| v.as_str()) {
144            Some(c) => c,
145            None => return false,
146        };
147
148        match client {
149            "InMemory" => {
150                if let Some(in_memory) = self.in_memory.as_mut() {
151                    if let Some(key) = store_config.get("key").and_then(|v| v.as_str()) {
152                        in_memory.set(key, value);
153                        return true;
154                    }
155                }
156                false
157            }
158            "KVS" => {
159                if let Some(kvs_client) = self.kvs_client.as_mut() {
160                    if let Some(key) = store_config.get("key").and_then(|v| v.as_str()) {
161                        // serialize処理
162                        // 全ての値をJSON形式で保存(型情報を保持)
163                        // JSON内でNumber/String/Bool/Null/Array/Objectを区別
164                        let serialized = match serde_json::to_string(&value) {
165                            Ok(s) => s,
166                            Err(_) => return false,
167                        };
168
169                        let final_ttl =
170                            ttl.or_else(|| store_config.get("ttl").and_then(|v| v.as_u64()));
171                        return kvs_client.set(key, serialized, final_ttl);
172                    }
173                }
174                false
175            }
176            _ => false,
177        }
178    }
179
180    /// _store 設定から値を削除
181    fn delete_from_store(&mut self, store_config: &HashMap<String, Value>) -> bool {
182        let client = match store_config.get("client").and_then(|v| v.as_str()) {
183            Some(c) => c,
184            None => return false,
185        };
186
187        match client {
188            "InMemory" => {
189                if let Some(in_memory) = self.in_memory.as_mut() {
190                    if let Some(key) = store_config.get("key").and_then(|v| v.as_str()) {
191                        return in_memory.delete(key);
192                    }
193                }
194                false
195            }
196            "KVS" => {
197                if let Some(kvs_client) = self.kvs_client.as_mut() {
198                    if let Some(key) = store_config.get("key").and_then(|v| v.as_str()) {
199                        return kvs_client.delete(key);
200                    }
201                }
202                false
203            }
204            _ => false,
205        }
206    }
207
208    /// 親キーを取得
209    ///
210    /// "cache.user.org_id" → "cache.user"
211    /// "cache.user" → "cache"
212    /// "cache" → ""
213    fn get_parent_key(key: &str) -> String {
214        let segments: Vec<&str> = key.split('.').collect();
215        if segments.len() <= 1 {
216            return String::new();
217        }
218        segments[..segments.len() - 1].join(".")
219    }
220
221    /// Manifest の静的値とマージ
222    ///
223    /// Load/Store から取得した値に Manifest の静的値をマージする。
224    /// Load/Store の値が優先される(後から上書き)。
225    ///
226    /// # Arguments
227    /// * `manifest_key` - Manifest から取得するキー
228    /// * `data` - Load/Store から取得した値
229    ///
230    /// # Returns
231    /// マージ後の値(data が Object でない場合はそのまま返す)
232    fn merge_with_manifest_static_values(&mut self, manifest_key: &str, data: Value) -> Value {
233        // data が Object でない場合はマージ不要
234        let Value::Object(data_obj) = data else {
235            return data;
236        };
237
238        // Manifest から静的値を取得
239        let manifest_value = self.manifest.get(manifest_key, None);
240
241        // Manifest の値が Object でない場合はマージ不要
242        let manifest_obj = match manifest_value {
243            Value::Object(obj) => obj,
244            _ => return Value::Object(data_obj),
245        };
246
247        // Manifest の静的値を先に入れ、data で上書き(data が優先)
248        let mut merged = manifest_obj.clone();
249        for (key, value) in data_obj {
250            merged.insert(key, value);
251        }
252
253        Value::Object(merged)
254    }
255}
256
257impl<'a> StateTrait for State<'a> {
258    fn get(&mut self, key: &str) -> Option<Value> {
259        // 再帰深度チェック
260        if self.recursion_depth >= self.max_recursion {
261            eprintln!(
262                "State::get: max recursion depth ({}) reached for key '{}'",
263                self.max_recursion, key
264            );
265            return None;
266        }
267
268        self.recursion_depth += 1;
269
270        // 1. インスタンスキャッシュをチェック(最優先)
271        if let Some(cached) = self.dot_accessor.get(&self.cache, key) {
272            self.recursion_depth -= 1;
273            return Some(cached.clone());
274        }
275
276        // 2. メタデータ取得
277        let meta = self.manifest.get_meta(key);
278        if meta.is_empty() {
279            self.recursion_depth -= 1;
280            return None;
281        }
282
283        // 3. _load.client: State の場合は _store をスキップ
284        //    明示的なState参照は親の _store を使わない
285        let has_state_client = meta.get("_load")
286            .and_then(|v| v.as_object())
287            .and_then(|obj| obj.get("client"))
288            .and_then(|v| v.as_str())
289            == Some("State");
290
291        // 4. _store から値を取得(client: State でない場合のみ)
292        if !has_state_client {
293            if let Some(store_config_value) = meta.get("_store") {
294                if let Some(store_config_obj) = store_config_value.as_object() {
295                    let store_config: HashMap<String, Value> =
296                        store_config_obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
297
298                    // store_config 内の placeholder を解決
299                    let resolved_store_config = self.resolve_load_config(&store_config);
300
301                    if let Some(value) = self.get_from_store(&resolved_store_config) {
302                        // map の最初のキーから owner_key を逆算
303                        let owner_key = meta.get("_load")
304                            .and_then(|v| v.as_object())
305                            .and_then(|obj| obj.get("map"))
306                            .and_then(|v| v.as_object())
307                            .and_then(|map| map.keys().next())
308                            .map(|first_key| Self::get_parent_key(first_key))
309                            .unwrap_or_else(|| Self::get_parent_key(key));
310
311                        // owner_key で Manifest の静的値とマージ
312                        let merged_value = self.merge_with_manifest_static_values(&owner_key, value);
313
314                        // owner_key で cache にマージ
315                        DotArrayAccessor::merge(&mut self.cache, &owner_key, merged_value.clone());
316
317                        // 要求されたフィールドを抽出
318                        let extracted = if key == owner_key {
319                            merged_value
320                        } else {
321                            Self::extract_field_from_value(key, merged_value, &meta)
322                        };
323
324                        self.recursion_depth -= 1;
325                        return Some(extracted);
326                    }
327                }
328            }
329        }
330
331        // 5. miss時は自動ロード
332        let result = if let Some(load_config_value) = meta.get("_load") {
333            if let Some(load_config_obj) = load_config_value.as_object() {
334                let load_config: HashMap<String, Value> =
335                    load_config_obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
336
337                // client が無い場合は自動ロードしない
338                if !load_config.contains_key("client") {
339                    self.recursion_depth -= 1;
340                    return None;
341                }
342
343                // placeholder 解決
344                let mut resolved_config = self.resolve_load_config(&load_config);
345
346                // client: State の場合は key の値を直接返す(State内参照)
347                let client_value = resolved_config.get("client").and_then(|v| v.as_str());
348
349                if client_value == Some("State") {
350                    // _load.key の値を返す(placeholder 解決済みの値)
351                    if let Some(key_value) = resolved_config.get("key") {
352                        // key_value は既に resolve_load_config で値に解決されている
353                        // インスタンスキャッシュに保存
354                        DotArrayAccessor::set(&mut self.cache, key, key_value.clone());
355
356                        self.recursion_depth -= 1;
357                        return Some(key_value.clone());
358                    }
359                    self.recursion_depth -= 1;
360                    None
361                } else {
362                    // Load に渡す前に map を denormalize(絶対パス → 相対パス)
363                    if let Some(map_value) = resolved_config.get("map") {
364                        if let Value::Object(map_obj) = map_value {
365                            let mut denormalized_map = serde_json::Map::new();
366                            for (absolute_key, db_column) in map_obj {
367                                // 絶対パスから最後のセグメントを抽出(相対フィールド名)
368                                let segments: Vec<&str> = absolute_key.split('.').collect();
369                                if let Some(relative_key) = segments.last() {
370                                    denormalized_map.insert(relative_key.to_string(), db_column.clone());
371                                }
372                            }
373                            resolved_config.insert("map".to_string(), Value::Object(denormalized_map));
374                        }
375                    }
376
377                    // Load 実行
378                    if let Ok(loaded) = self.load.handle(&resolved_config) {
379                        // map の最初のキーから owner_key を逆算
380                        // declare-e L120-130: map から所有者キーを算出
381                        let owner_key = meta.get("_load")
382                            .and_then(|v| v.as_object())
383                            .and_then(|obj| obj.get("map"))
384                            .and_then(|v| v.as_object())
385                            .and_then(|map| map.keys().next())
386                            .map(|first_key| Self::get_parent_key(first_key))
387                            .unwrap_or_else(|| key.to_string());
388
389                        // owner_key で Manifest の静的値とマージ
390                        let merged_loaded = self.merge_with_manifest_static_values(&owner_key, loaded);
391
392                        // ロード成功 → _store に保存(マージ後の値を保存)
393                        if let Some(store_config_value) = meta.get("_store") {
394                            if let Some(store_config_obj) = store_config_value.as_object() {
395                                let store_config: HashMap<String, Value> = store_config_obj
396                                    .iter()
397                                    .map(|(k, v)| (k.clone(), v.clone()))
398                                    .collect();
399
400                                // store_config の placeholder も解決
401                                let resolved_store_config = self.resolve_load_config(&store_config);
402                                self.set_to_store(&resolved_store_config, merged_loaded.clone(), None);
403                            }
404                        }
405
406                        // owner_key で cache にマージ
407                        DotArrayAccessor::merge(&mut self.cache, &owner_key, merged_loaded.clone());
408
409                        // 要求されたフィールドを抽出して返す
410                        if key == owner_key {
411                            // 親辞書そのものを取得した場合
412                            Some(merged_loaded)
413                        } else {
414                            // 子フィールドを取得した場合
415                            Some(Self::extract_field_from_value(key, merged_loaded, &meta))
416                        }
417                    } else {
418                        None
419                    }
420                }
421            } else {
422                None
423            }
424        } else {
425            None
426        };
427
428        self.recursion_depth -= 1;
429        result
430    }
431
432    fn set(&mut self, key: &str, value: Value, ttl: Option<u64>) -> bool {
433        // メタデータ取得
434        let meta = self.manifest.get_meta(key);
435        if meta.is_empty() {
436            eprintln!("State::set: meta is empty for key '{}'", key);
437            return false;
438        }
439
440        // _store 設定取得
441        let store_config = match meta.get("_store").and_then(|v| v.as_object()) {
442            Some(config) => config,
443            None => {
444                eprintln!("State::set: no _store config for key '{}'", key);
445                return false;
446            }
447        };
448
449        let store_config_map: HashMap<String, Value> =
450            store_config.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
451
452        // store_config 内の placeholder 解決
453        let resolved_store_config = self.resolve_load_config(&store_config_map);
454
455        // _store に保存
456        let result = self.set_to_store(&resolved_store_config, value.clone(), ttl);
457
458        // 成功時はインスタンスキャッシュにも保存
459        if result {
460            DotArrayAccessor::set(&mut self.cache, key, value);
461        }
462
463        result
464    }
465
466    fn delete(&mut self, key: &str) -> bool {
467        // メタデータ取得
468        let meta = self.manifest.get_meta(key);
469        if meta.is_empty() {
470            return false;
471        }
472
473        // _store 設定取得
474        let store_config = match meta.get("_store").and_then(|v| v.as_object()) {
475            Some(config) => config,
476            None => return false,
477        };
478
479        let store_config_map: HashMap<String, Value> =
480            store_config.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
481
482        // store_config 内の placeholder 解決
483        let resolved_store_config = self.resolve_load_config(&store_config_map);
484
485        // _store から削除
486        let result = self.delete_from_store(&resolved_store_config);
487
488        // 成功時はインスタンスキャッシュからも削除
489        if result {
490            DotArrayAccessor::unset(&mut self.cache, key);
491        }
492
493        result
494    }
495
496    fn exists(&mut self, key: &str) -> bool {
497        // 1. インスタンスキャッシュをチェック(最優先・最速)
498        if self.dot_accessor.get(&self.cache, key).is_some() {
499            return true;
500        }
501
502        // 2. メタデータ取得
503        let meta = self.manifest.get_meta(key);
504        if meta.is_empty() {
505            return false;
506        }
507
508        // 3. _store 設定取得
509        let store_config = match meta.get("_store").and_then(|v| v.as_object()) {
510            Some(config) => config,
511            None => return false,
512        };
513
514        let store_config_map: HashMap<String, Value> =
515            store_config.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
516
517        // 4. store_config 内の placeholder 解決
518        let resolved_store_config = self.resolve_load_config(&store_config_map);
519
520        // 5. _store から値を取得(自動ロードなし)
521        self.get_from_store(&resolved_store_config).is_some()
522    }
523}
524
525#[cfg(test)]
526mod tests {
527    use super::*;
528    use crate::manifest::Manifest;
529    use crate::ports::required::InMemoryClient;
530
531    // Mock InMemoryClient
532    struct MockInMemory {
533        data: HashMap<String, Value>,
534    }
535
536    impl MockInMemory {
537        fn new() -> Self {
538            Self {
539                data: HashMap::new(),
540            }
541        }
542    }
543
544    impl InMemoryClient for MockInMemory {
545        fn get(&self, key: &str) -> Option<Value> {
546            self.data.get(key).cloned()
547        }
548
549        fn set(&mut self, key: &str, value: Value) {
550            self.data.insert(key.to_string(), value);
551        }
552
553        fn delete(&mut self, key: &str) -> bool {
554            self.data.remove(key).is_some()
555        }
556    }
557
558    #[test]
559    fn test_state_set_and_get() {
560        let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
561            .join("examples/manifest");
562        let mut manifest = Manifest::new(manifest_path.to_str().unwrap());
563
564        let load = Load::new();
565        let mut in_memory = MockInMemory::new();
566
567        let mut state = State::new(&mut manifest, load).with_in_memory(&mut in_memory);
568
569        // connection.common は InMemory で placeholder なし
570        let mut conn_value = serde_json::Map::new();
571        conn_value.insert("host".to_string(), Value::String("localhost".to_string()));
572        let value = Value::Object(conn_value);
573
574        let result = state.set("connection.common", value.clone(), None);
575        assert!(result, "set should succeed");
576
577        // get
578        let retrieved = state.get("connection.common");
579        assert_eq!(retrieved, Some(value));
580    }
581
582    #[test]
583    fn test_state_delete() {
584        let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
585            .join("examples/manifest");
586        let mut manifest = Manifest::new(manifest_path.to_str().unwrap());
587
588        let load = Load::new();
589        let mut in_memory = MockInMemory::new();
590
591        let mut state = State::new(&mut manifest, load).with_in_memory(&mut in_memory);
592
593        // connection.common でテスト
594        let value = Value::String("test_value".to_string());
595        state.set("connection.common", value, None);
596
597        // delete
598        let result = state.delete("connection.common");
599        assert!(result, "delete should succeed");
600
601        // get (should be None)
602        let retrieved = state.get("connection.common");
603        assert_eq!(retrieved, None);
604    }
605}