1use 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
9pub 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, }
23
24impl<'a> State<'a> {
25 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 pub fn with_in_memory(mut self, client: &'a mut dyn InMemoryClient) -> Self {
41 self.in_memory = Some(client);
42 self
43 }
44
45 pub fn with_kvs_client(mut self, client: &'a mut dyn KVSClient) -> Self {
47 self.kvs_client = Some(client);
48 self
49 }
50
51 fn extract_field_from_value(key: &str, value: Value, meta: &HashMap<String, Value>) -> Value {
56 if let Some(store_meta) = meta.get("_store") {
59 if let Some(_store_obj) = store_meta.as_object() {
60 let parts: Vec<&str> = key.split('.').collect();
67 if parts.len() < 2 {
68 return value;
69 }
70
71 let last_field = parts[parts.len() - 1];
73 if let Some(field_value) = value.get(last_field) {
74 return field_value.clone();
76 }
77 }
78 }
79
80 value
82 }
83
84 fn resolve_placeholder(&mut self, name: &str) -> Option<Value> {
89 if let Some(cached) = self.dot_accessor.get(&self.cache, name) {
91 return Some(cached.clone());
92 }
93
94 self.get(name)
96 }
97
98 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 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 serde_json::from_str(&value_str).ok()
131 }
132 _ => None,
133 }
134 }
135
136 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 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 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 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 fn merge_with_manifest_static_values(&mut self, manifest_key: &str, data: Value) -> Value {
233 let Value::Object(data_obj) = data else {
235 return data;
236 };
237
238 let manifest_value = self.manifest.get(manifest_key, None);
240
241 let manifest_obj = match manifest_value {
243 Value::Object(obj) => obj,
244 _ => return Value::Object(data_obj),
245 };
246
247 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 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 if let Some(cached) = self.dot_accessor.get(&self.cache, key) {
272 self.recursion_depth -= 1;
273 return Some(cached.clone());
274 }
275
276 let meta = self.manifest.get_meta(key);
278 if meta.is_empty() {
279 self.recursion_depth -= 1;
280 return None;
281 }
282
283 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 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 let resolved_store_config = self.resolve_load_config(&store_config);
300
301 if let Some(value) = self.get_from_store(&resolved_store_config) {
302 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 let merged_value = self.merge_with_manifest_static_values(&owner_key, value);
313
314 DotArrayAccessor::merge(&mut self.cache, &owner_key, merged_value.clone());
316
317 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 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 if !load_config.contains_key("client") {
339 self.recursion_depth -= 1;
340 return None;
341 }
342
343 let mut resolved_config = self.resolve_load_config(&load_config);
345
346 let client_value = resolved_config.get("client").and_then(|v| v.as_str());
348
349 if client_value == Some("State") {
350 if let Some(key_value) = resolved_config.get("key") {
352 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 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 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 if let Ok(loaded) = self.load.handle(&resolved_config) {
379 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 let merged_loaded = self.merge_with_manifest_static_values(&owner_key, loaded);
391
392 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 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 DotArrayAccessor::merge(&mut self.cache, &owner_key, merged_loaded.clone());
408
409 if key == owner_key {
411 Some(merged_loaded)
413 } else {
414 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 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 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 let resolved_store_config = self.resolve_load_config(&store_config_map);
454
455 let result = self.set_to_store(&resolved_store_config, value.clone(), ttl);
457
458 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 let meta = self.manifest.get_meta(key);
469 if meta.is_empty() {
470 return false;
471 }
472
473 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 let resolved_store_config = self.resolve_load_config(&store_config_map);
484
485 let result = self.delete_from_store(&resolved_store_config);
487
488 if result {
490 DotArrayAccessor::unset(&mut self.cache, key);
491 }
492
493 result
494 }
495
496 fn exists(&mut self, key: &str) -> bool {
497 if self.dot_accessor.get(&self.cache, key).is_some() {
499 return true;
500 }
501
502 let meta = self.manifest.get_meta(key);
504 if meta.is_empty() {
505 return false;
506 }
507
508 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 let resolved_store_config = self.resolve_load_config(&store_config_map);
519
520 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 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 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 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 let value = Value::String("test_value".to_string());
595 state.set("connection.common", value, None);
596
597 let result = state.delete("connection.common");
599 assert!(result, "delete should succeed");
600
601 let retrieved = state.get("connection.common");
603 assert_eq!(retrieved, None);
604 }
605}