json_eval_rs/jsoneval/
getters.rs1use 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 pub(crate) fn is_effective_hidden(&self, schema_pointer: &str) -> bool {
15 let mut current_path = schema_pointer.to_string();
16
17 loop {
19 if let Some(schema_node) = self.evaluated_schema.pointer(¤t_path) {
21 if let Value::Object(map) = schema_node {
22 if let Some(Value::Object(condition)) = map.get("condition") {
24 if let Some(Value::Bool(hidden)) = condition.get("hidden") {
25 if *hidden {
26 return true;
27 }
28 }
29 }
30
31 if let Some(Value::Object(layout)) = map.get("$layout") {
33 if let Some(Value::Object(hide_layout)) = layout.get("hideLayout") {
34 if let Some(Value::Bool(all)) = hide_layout.get("all") {
35 if *all {
36 return true;
37 }
38 }
39 }
40 }
41 }
42 }
43
44 if current_path.is_empty() {
46 break;
47 }
48
49 if let Some(last_slash_idx) = current_path.rfind('/') {
51 let parent_path_raw = ¤t_path[..last_slash_idx];
52
53 if parent_path_raw.is_empty() {
54 current_path = "".to_string();
55 continue;
56 }
57
58 if parent_path_raw.ends_with("/properties") {
60 current_path = parent_path_raw[..parent_path_raw.len() - "/properties".len()].to_string();
61 } else if parent_path_raw.ends_with("/items") {
62 current_path = parent_path_raw[..parent_path_raw.len() - "/items".len()].to_string();
63 } else {
64 current_path = parent_path_raw.to_string();
65 }
66 } else {
67 break;
68 }
69 }
70
71 false
72 }
73
74 fn prune_hidden_values(&self, data: &mut Value, current_path: &str) {
76 if let Value::Object(map) = data {
77 let mut keys_to_remove = Vec::new();
79
80 for (key, value) in map.iter_mut() {
81 if key == "$params" || key == "$context" {
83 continue;
84 }
85
86 let schema_path = if current_path.is_empty() {
90 format!("/properties/{}", key)
91 } else {
92 format!("{}/properties/{}", current_path, key)
93 };
94
95 if self.is_effective_hidden(&schema_path) {
97 keys_to_remove.push(key.clone());
98 } else {
99 if value.is_object() {
101 self.prune_hidden_values(value, &schema_path);
102 }
103 }
104 }
105
106 for key in keys_to_remove {
108 map.remove(&key);
109 }
110 }
111 }
112
113 pub fn get_evaluated_schema(&mut self, skip_layout: bool) -> Value {
123 time_block!("get_evaluated_schema()", {
124 if !skip_layout {
125 if let Err(e) = self.resolve_layout(false) {
126 eprintln!("Warning: Layout resolution failed in get_evaluated_schema: {}", e);
127 }
128 }
129 self.evaluated_schema.clone()
130 })
131 }
132
133
134
135 pub fn get_schema_value_by_path(&self, path: &str) -> Option<Value> {
137 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
138 self.evaluated_schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
139 }
140
141 pub fn get_schema_value(&mut self) -> Value {
145 let mut current_data = self.eval_data.data().clone();
147
148 if !current_data.is_object() {
150 current_data = Value::Object(serde_json::Map::new());
151 }
152
153 if let Some(obj) = current_data.as_object_mut() {
155 obj.remove("$params");
156 obj.remove("$context");
157 }
158
159 self.prune_hidden_values(&mut current_data, "");
161
162 for eval_key in self.value_evaluations.iter() {
165 let clean_key = eval_key.replace('#', "");
166
167 if clean_key.starts_with("/$params")
169 || (clean_key.ends_with("/value")
170 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
171 {
172 continue;
173 }
174
175 let path = clean_key.replace("/properties", "").replace("/value", "");
176
177 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
180 if self.is_effective_hidden(schema_path) {
181 continue;
182 }
183
184 let value = match self.evaluated_schema.pointer(&clean_key) {
186 Some(v) => v.clone(),
187 None => continue,
188 };
189
190 let path_parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
192
193 if path_parts.is_empty() {
194 continue;
195 }
196
197 let mut current = &mut current_data;
199 for (i, part) in path_parts.iter().enumerate() {
200 let is_last = i == path_parts.len() - 1;
201
202 if is_last {
203 if let Some(obj) = current.as_object_mut() {
205 obj.insert(part.to_string(), crate::utils::clean_float_noise(value.clone()));
206 }
207 } else {
208 if let Some(obj) = current.as_object_mut() {
210 if !obj.contains_key(*part) {
216 obj.insert((*part).to_string(), Value::Object(serde_json::Map::new()));
217 }
218
219 current = obj.get_mut(*part).unwrap();
220 } else {
221 break;
223 }
224 }
225 }
226 }
227
228 self.data = current_data.clone();
230
231 crate::utils::clean_float_noise(current_data)
232 }
233
234 pub fn get_schema_value_array(&self) -> Value {
241 let mut result = Vec::new();
242
243 for eval_key in self.value_evaluations.iter() {
244 let clean_key = eval_key.replace('#', "");
245
246 if clean_key.starts_with("/$params")
248 || (clean_key.ends_with("/value")
249 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
250 {
251 continue;
252 }
253
254 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
256 if self.is_effective_hidden(schema_path) {
257 continue;
258 }
259
260 let dotted_path = clean_key
262 .replace("/properties", "")
263 .replace("/value", "")
264 .trim_start_matches('/')
265 .replace('/', ".");
266
267 if dotted_path.is_empty() {
268 continue;
269 }
270
271 let value = match self.evaluated_schema.pointer(&clean_key) {
273 Some(v) => crate::utils::clean_float_noise(v.clone()),
274 None => continue,
275 };
276
277 let mut item = serde_json::Map::new();
279 item.insert("path".to_string(), Value::String(dotted_path));
280 item.insert("value".to_string(), value);
281 result.push(Value::Object(item));
282 }
283
284 Value::Array(result)
285 }
286
287 pub fn get_schema_value_object(&self) -> Value {
294 let mut result = serde_json::Map::new();
295
296 for eval_key in self.value_evaluations.iter() {
297 let clean_key = eval_key.replace('#', "");
298
299 if clean_key.starts_with("/$params")
301 || (clean_key.ends_with("/value")
302 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
303 {
304 continue;
305 }
306
307 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
309 if self.is_effective_hidden(schema_path) {
310 continue;
311 }
312
313 let dotted_path = clean_key
315 .replace("/properties", "")
316 .replace("/value", "")
317 .trim_start_matches('/')
318 .replace('/', ".");
319
320 if dotted_path.is_empty() {
321 continue;
322 }
323
324 let value = match self.evaluated_schema.pointer(&clean_key) {
326 Some(v) => crate::utils::clean_float_noise(v.clone()),
327 None => continue,
328 };
329
330 result.insert(dotted_path, value);
331 }
332
333 Value::Object(result)
334 }
335
336 pub fn get_evaluated_schema_without_params(&mut self, skip_layout: bool) -> Value {
338 let mut schema = self.get_evaluated_schema(skip_layout);
339 if let Value::Object(ref mut map) = schema {
340 map.remove("$params");
341 }
342 schema
343 }
344
345 pub fn get_evaluated_schema_msgpack(&mut self, skip_layout: bool) -> Result<Vec<u8>, String> {
347 let schema = self.get_evaluated_schema(skip_layout);
348 rmp_serde::to_vec(&schema).map_err(|e| format!("MessagePack serialization failed: {}", e))
349 }
350
351 pub fn get_evaluated_schema_by_path(&mut self, path: &str, skip_layout: bool) -> Option<Value> {
353 if !skip_layout {
354 if let Err(e) = self.resolve_layout(false) {
355 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_path: {}", e);
356 }
357 }
358 self.get_schema_value_by_path(path)
359 }
360
361 pub fn get_evaluated_schema_by_paths(
363 &mut self,
364 paths: &[String],
365 skip_layout: bool,
366 format: Option<ReturnFormat>,
367 ) -> Value {
368 if !skip_layout {
369 if let Err(e) = self.resolve_layout(false) {
370 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_paths: {}", e);
371 }
372 }
373
374 match format.unwrap_or(ReturnFormat::Nested) {
375 ReturnFormat::Nested => {
376 let mut result = Value::Object(serde_json::Map::new());
377 for path in paths {
378 if let Some(val) = self.get_schema_value_by_path(path) {
379 Self::insert_at_path(&mut result, path, val);
381 }
382 }
383 result
384 }
385 ReturnFormat::Flat => {
386 let mut result = serde_json::Map::new();
387 for path in paths {
388 if let Some(val) = self.get_schema_value_by_path(path) {
389 result.insert(path.clone(), val);
390 }
391 }
392 Value::Object(result)
393 }
394 ReturnFormat::Array => {
395 let mut result = Vec::new();
396 for path in paths {
397 if let Some(val) = self.get_schema_value_by_path(path) {
398 result.push(val);
399 } else {
400 result.push(Value::Null);
401 }
402 }
403 Value::Array(result)
404 }
405 }
406 }
407
408 pub fn get_schema_by_path(&self, path: &str) -> Option<Value> {
410 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
411 self.schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
412 }
413
414 pub fn get_schema_by_paths(
416 &self,
417 paths: &[String],
418 format: Option<ReturnFormat>,
419 ) -> Value {
420 match format.unwrap_or(ReturnFormat::Nested) {
421 ReturnFormat::Nested => {
422 let mut result = Value::Object(serde_json::Map::new());
423 for path in paths {
424 if let Some(val) = self.get_schema_by_path(path) {
425 Self::insert_at_path(&mut result, path, val);
426 }
427 }
428 result
429 }
430 ReturnFormat::Flat => {
431 let mut result = serde_json::Map::new();
432 for path in paths {
433 if let Some(val) = self.get_schema_by_path(path) {
434 result.insert(path.clone(), val);
435 }
436 }
437 Value::Object(result)
438 }
439 ReturnFormat::Array => {
440 let mut result = Vec::new();
441 for path in paths {
442 if let Some(val) = self.get_schema_by_path(path) {
443 result.push(val);
444 } else {
445 result.push(Value::Null);
446 }
447 }
448 Value::Array(result)
449 }
450 }
451 }
452
453 pub(crate) fn insert_at_path(root: &mut Value, path: &str, value: Value) {
455 let parts: Vec<&str> = path.split('.').collect();
456 let mut current = root;
457
458 for (i, part) in parts.iter().enumerate() {
459 if i == parts.len() - 1 {
460 if let Value::Object(map) = current {
462 map.insert(part.to_string(), value);
463 return; }
465 } else {
466 if !current.is_object() {
471 *current = Value::Object(serde_json::Map::new());
472 }
473
474 if let Value::Object(map) = current {
475 if !map.contains_key(*part) {
476 map.insert(part.to_string(), Value::Object(serde_json::Map::new()));
477 }
478 current = map.get_mut(*part).unwrap();
479 }
480 }
481 }
482 }
483
484 pub fn flatten_object(prefix: &str, value: &Value, result: &mut serde_json::Map<String, Value>) {
486 match value {
487 Value::Object(map) => {
488 for (k, v) in map {
489 let new_key = if prefix.is_empty() {
490 k.clone()
491 } else {
492 format!("{}.{}", prefix, k)
493 };
494 Self::flatten_object(&new_key, v, result);
495 }
496 }
497 _ => {
498 result.insert(prefix.to_string(), value.clone());
499 }
500 }
501 }
502
503 pub fn convert_to_format(value: Value, format: ReturnFormat) -> Value {
504 match format {
505 ReturnFormat::Nested => value,
506 ReturnFormat::Flat => {
507 let mut result = serde_json::Map::new();
508 Self::flatten_object("", &value, &mut result);
509 Value::Object(result)
510 }
511 ReturnFormat::Array => {
512 if let Value::Object(map) = value {
516 Value::Array(map.values().cloned().collect())
517 } else if let Value::Array(arr) = value {
518 Value::Array(arr)
519 } else {
520 Value::Array(vec![value])
521 }
522 }
523 }
524 }
525}