json_eval_rs/jsoneval/
getters.rs

1use super::JSONEval;
2use crate::jsoneval::path_utils;
3use crate::jsoneval::types::ReturnFormat;
4
5
6
7use serde_json::Value;
8use crate::time_block;
9
10
11impl JSONEval {
12    /// Get the evaluated schema with optional layout resolution.
13    ///
14    /// # Arguments
15    ///
16    /// * `skip_layout` - Whether to skip layout resolution.
17    ///
18    /// # Returns
19    ///
20    /// The evaluated schema as a JSON value.
21    pub fn get_evaluated_schema(&mut self, skip_layout: bool) -> Value {
22        time_block!("get_evaluated_schema()", {
23            if !skip_layout {
24                if let Err(e) = self.resolve_layout(false) {
25                    eprintln!("Warning: Layout resolution failed in get_evaluated_schema: {}", e);
26                }
27            }
28            self.evaluated_schema.clone()
29        })
30    }
31
32
33
34    /// Get specific schema value by path
35    pub fn get_schema_value_by_path(&self, path: &str) -> Option<Value> {
36        let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
37        self.evaluated_schema.pointer(&pointer_path).cloned()
38    }
39
40    /// Get all schema values (data view)
41    /// This corresponds to subform.get_schema_value() usage
42    pub fn get_schema_value(&self) -> Value {
43        self.eval_data.data().clone()
44    }
45
46    /// Get evaluated schema without $params
47    pub fn get_evaluated_schema_without_params(&mut self, skip_layout: bool) -> Value {
48        let mut schema = self.get_evaluated_schema(skip_layout);
49        if let Value::Object(ref mut map) = schema {
50            map.remove("$params");
51        }
52        schema
53    }
54
55    /// Get evaluated schema as MessagePack bytes
56    pub fn get_evaluated_schema_msgpack(&mut self, skip_layout: bool) -> Result<Vec<u8>, String> {
57        let schema = self.get_evaluated_schema(skip_layout);
58        rmp_serde::to_vec(&schema).map_err(|e| format!("MessagePack serialization failed: {}", e))
59    }
60
61    /// Get value from evaluated schema by path
62    pub fn get_evaluated_schema_by_path(&mut self, path: &str, skip_layout: bool) -> Option<Value> {
63        if !skip_layout {
64            if let Err(e) = self.resolve_layout(false) {
65                eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_path: {}", e);
66            }
67        }
68        self.get_schema_value_by_path(path)
69    }
70
71    /// Get evaluated schema parts by multiple paths
72    pub fn get_evaluated_schema_by_paths(
73        &mut self,
74        paths: &[String],
75        skip_layout: bool,
76        format: Option<ReturnFormat>,
77    ) -> Value {
78        if !skip_layout {
79            if let Err(e) = self.resolve_layout(false) {
80                eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_paths: {}", e);
81            }
82        }
83
84        match format.unwrap_or(ReturnFormat::Nested) {
85            ReturnFormat::Nested => {
86                let mut result = Value::Object(serde_json::Map::new());
87                for path in paths {
88                    if let Some(val) = self.get_schema_value_by_path(path) {
89                         // Insert into result object at proper path nesting
90                         Self::insert_at_path(&mut result, path, val);
91                    }
92                }
93                result
94            }
95            ReturnFormat::Flat => {
96                 let mut result = serde_json::Map::new();
97                 for path in paths {
98                    if let Some(val) = self.get_schema_value_by_path(path) {
99                        result.insert(path.clone(), val);
100                    }
101                }
102                Value::Object(result)
103            }
104            ReturnFormat::Array => {
105                 let mut result = Vec::new();
106                 for path in paths {
107                    if let Some(val) = self.get_schema_value_by_path(path) {
108                        result.push(val);
109                    } else {
110                        result.push(Value::Null);
111                    }
112                }
113                Value::Array(result)
114            }
115        }
116    }
117
118    /// Get original (unevaluated) schema by path
119    pub fn get_schema_by_path(&self, path: &str) -> Option<Value> {
120        let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
121        self.schema.pointer(&pointer_path).cloned()
122    }
123
124    /// Get original schema by multiple paths
125    pub fn get_schema_by_paths(
126        &self,
127        paths: &[String],
128        format: Option<ReturnFormat>,
129    ) -> Value {
130        match format.unwrap_or(ReturnFormat::Nested) {
131            ReturnFormat::Nested => {
132                let mut result = Value::Object(serde_json::Map::new());
133                for path in paths {
134                    if let Some(val) = self.get_schema_by_path(path) {
135                         Self::insert_at_path(&mut result, path, val);
136                    }
137                }
138                result
139            }
140            ReturnFormat::Flat => {
141                 let mut result = serde_json::Map::new();
142                 for path in paths {
143                    if let Some(val) = self.get_schema_by_path(path) {
144                        result.insert(path.clone(), val);
145                    }
146                }
147                Value::Object(result)
148            }
149            ReturnFormat::Array => {
150                 let mut result = Vec::new();
151                 for path in paths {
152                    if let Some(val) = self.get_schema_by_path(path) {
153                        result.push(val);
154                    } else {
155                        result.push(Value::Null);
156                    }
157                }
158                Value::Array(result)
159            }
160        }
161    }
162
163    /// Helper to insert value into nested object at dotted path
164    pub(crate) fn insert_at_path(root: &mut Value, path: &str, value: Value) {
165        let parts: Vec<&str> = path.split('.').collect();
166        let mut current = root;
167        
168        for (i, part) in parts.iter().enumerate() {
169            if i == parts.len() - 1 {
170                // Last part - set value
171                if let Value::Object(map) = current {
172                    map.insert(part.to_string(), value);
173                    return; // Done
174                }
175            } else {
176                // Intermediate part - traverse or create
177                // We need to temporarily take the value or use raw pointer manipulation?
178                // serde_json pointer is read-only or requires mutable reference
179                
180                 if !current.is_object() {
181                     *current = Value::Object(serde_json::Map::new());
182                 }
183                 
184                 if let Value::Object(map) = current {
185                     if !map.contains_key(*part) {
186                         map.insert(part.to_string(), Value::Object(serde_json::Map::new()));
187                     }
188                     current = map.get_mut(*part).unwrap();
189                 }
190            }
191        }
192    }
193    
194    /// Flatten a nested object key-value pair to dotted keys
195    pub fn flatten_object(prefix: &str, value: &Value, result: &mut serde_json::Map<String, Value>) {
196        match value {
197            Value::Object(map) => {
198                for (k, v) in map {
199                     let new_key = if prefix.is_empty() {
200                         k.clone()
201                     } else {
202                         format!("{}.{}", prefix, k)
203                     };
204                     Self::flatten_object(&new_key, v, result);
205                }
206            }
207            _ => {
208                result.insert(prefix.to_string(), value.clone());
209            }
210        }
211    }
212
213    pub fn convert_to_format(value: Value, format: ReturnFormat) -> Value {
214         match format {
215             ReturnFormat::Nested => value,
216             ReturnFormat::Flat => {
217                 let mut result = serde_json::Map::new();
218                 Self::flatten_object("", &value, &mut result);
219                 Value::Object(result)
220             }
221             ReturnFormat::Array => {
222                 // Convert object values to array? Only if source was object?
223                 // Or flattened values?
224                 // Usually converting to array disregards keys.
225                 if let Value::Object(map) = value {
226                     Value::Array(map.values().cloned().collect())
227                 } else if let Value::Array(arr) = value {
228                     Value::Array(arr)
229                 } else {
230                     Value::Array(vec![value])
231                 }
232             }
233         }
234    }
235}