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 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") {
36 if let Some(Value::Object(hide_layout)) = layout.get("hideLayout") {
37 if let Some(Value::Bool(all)) = hide_layout.get("all") {
38 if *all {
39 return true;
40 }
41 }
42 }
43 }
44 }
45 }
46
47 if current_path.is_empty() {
49 break;
50 }
51
52 if let Some(last_slash_idx) = current_path.rfind('/') {
58 let parent_path_raw = ¤t_path[..last_slash_idx];
59
60 if parent_path_raw.is_empty() {
62 current_path = "".to_string();
63 continue;
64 }
65
66 if parent_path_raw.ends_with("/properties") {
68 current_path = parent_path_raw[..parent_path_raw.len() - "/properties".len()].to_string();
69 } else if parent_path_raw.ends_with("/items") { current_path = parent_path_raw[..parent_path_raw.len() - "/items".len()].to_string();
71 } else {
72 current_path = parent_path_raw.to_string();
76 }
77 } else {
78 break;
81 }
82 }
83
84 false
85 }
86
87 fn prune_hidden_values(&self, data: &mut Value, current_path: &str) {
89 if let Value::Object(map) = data {
90 let mut keys_to_remove = Vec::new();
92
93 for (key, value) in map.iter_mut() {
94 if key == "$params" || key == "$context" {
96 continue;
97 }
98
99 let schema_path = if current_path.is_empty() {
103 format!("/properties/{}", key)
104 } else {
105 format!("{}/properties/{}", current_path, key)
106 };
107
108 if self.is_effective_hidden(&schema_path) {
110 keys_to_remove.push(key.clone());
111 } else {
112 if value.is_object() {
114 self.prune_hidden_values(value, &schema_path);
115 }
116 }
117 }
118
119 for key in keys_to_remove {
121 map.remove(&key);
122 }
123 }
124 }
125
126 pub fn get_evaluated_schema(&mut self, skip_layout: bool) -> Value {
136 time_block!("get_evaluated_schema()", {
137 if !skip_layout {
138 if let Err(e) = self.resolve_layout(false) {
139 eprintln!("Warning: Layout resolution failed in get_evaluated_schema: {}", e);
140 }
141 }
142 self.evaluated_schema.clone()
143 })
144 }
145
146
147
148 pub fn get_schema_value_by_path(&self, path: &str) -> Option<Value> {
150 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
151 self.evaluated_schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
152 }
153
154 pub fn get_schema_value(&mut self) -> Value {
158 let mut current_data = self.eval_data.data().clone();
160
161 if !current_data.is_object() {
163 current_data = Value::Object(serde_json::Map::new());
164 }
165
166 if let Some(obj) = current_data.as_object_mut() {
168 obj.remove("$params");
169 obj.remove("$context");
170 }
171
172 self.prune_hidden_values(&mut current_data, "");
174
175 for eval_key in self.value_evaluations.iter() {
178 let clean_key = eval_key.replace('#', "");
179
180 if clean_key.starts_with("/$params")
182 || (clean_key.ends_with("/value")
183 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
184 {
185 continue;
186 }
187
188 let path = clean_key.replace("/properties", "").replace("/value", "");
189
190 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
193 if self.is_effective_hidden(schema_path) {
194 continue;
195 }
196
197 let value = match self.evaluated_schema.pointer(&clean_key) {
199 Some(v) => v.clone(),
200 None => continue,
201 };
202
203 let path_parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
205
206 if path_parts.is_empty() {
207 continue;
208 }
209
210 let mut current = &mut current_data;
212 for (i, part) in path_parts.iter().enumerate() {
213 let is_last = i == path_parts.len() - 1;
214
215 if is_last {
216 if let Some(obj) = current.as_object_mut() {
218 obj.insert(part.to_string(), crate::utils::clean_float_noise(value.clone()));
219 }
220 } else {
221 if let Some(obj) = current.as_object_mut() {
223 if !obj.contains_key(*part) {
229 obj.insert((*part).to_string(), Value::Object(serde_json::Map::new()));
230 }
231
232 current = obj.get_mut(*part).unwrap();
233 } else {
234 break;
236 }
237 }
238 }
239 }
240
241 self.data = current_data.clone();
243
244 crate::utils::clean_float_noise(current_data)
245 }
246
247 pub fn get_schema_value_array(&self) -> Value {
254 let mut result = Vec::new();
255
256 for eval_key in self.value_evaluations.iter() {
257 let clean_key = eval_key.replace('#', "");
258
259 if clean_key.starts_with("/$params")
261 || (clean_key.ends_with("/value")
262 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
263 {
264 continue;
265 }
266
267 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
269 if self.is_effective_hidden(schema_path) {
270 continue;
271 }
272
273 let dotted_path = clean_key
275 .replace("/properties", "")
276 .replace("/value", "")
277 .trim_start_matches('/')
278 .replace('/', ".");
279
280 if dotted_path.is_empty() {
281 continue;
282 }
283
284 let value = match self.evaluated_schema.pointer(&clean_key) {
286 Some(v) => crate::utils::clean_float_noise(v.clone()),
287 None => continue,
288 };
289
290 let mut item = serde_json::Map::new();
292 item.insert("path".to_string(), Value::String(dotted_path));
293 item.insert("value".to_string(), value);
294 result.push(Value::Object(item));
295 }
296
297 Value::Array(result)
298 }
299
300 pub fn get_schema_value_object(&self) -> Value {
307 let mut result = serde_json::Map::new();
308
309 for eval_key in self.value_evaluations.iter() {
310 let clean_key = eval_key.replace('#', "");
311
312 if clean_key.starts_with("/$params")
314 || (clean_key.ends_with("/value")
315 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
316 {
317 continue;
318 }
319
320 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
322 if self.is_effective_hidden(schema_path) {
323 continue;
324 }
325
326 let dotted_path = clean_key
328 .replace("/properties", "")
329 .replace("/value", "")
330 .trim_start_matches('/')
331 .replace('/', ".");
332
333 if dotted_path.is_empty() {
334 continue;
335 }
336
337 let value = match self.evaluated_schema.pointer(&clean_key) {
339 Some(v) => crate::utils::clean_float_noise(v.clone()),
340 None => continue,
341 };
342
343 result.insert(dotted_path, value);
344 }
345
346 Value::Object(result)
347 }
348
349 pub fn get_evaluated_schema_without_params(&mut self, skip_layout: bool) -> Value {
351 let mut schema = self.get_evaluated_schema(skip_layout);
352 if let Value::Object(ref mut map) = schema {
353 map.remove("$params");
354 }
355 schema
356 }
357
358 pub fn get_evaluated_schema_msgpack(&mut self, skip_layout: bool) -> Result<Vec<u8>, String> {
360 let schema = self.get_evaluated_schema(skip_layout);
361 rmp_serde::to_vec(&schema).map_err(|e| format!("MessagePack serialization failed: {}", e))
362 }
363
364 pub fn get_evaluated_schema_by_path(&mut self, path: &str, skip_layout: bool) -> Option<Value> {
366 if !skip_layout {
367 if let Err(e) = self.resolve_layout(false) {
368 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_path: {}", e);
369 }
370 }
371 self.get_schema_value_by_path(path)
372 }
373
374 pub fn get_evaluated_schema_by_paths(
376 &mut self,
377 paths: &[String],
378 skip_layout: bool,
379 format: Option<ReturnFormat>,
380 ) -> Value {
381 if !skip_layout {
382 if let Err(e) = self.resolve_layout(false) {
383 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_paths: {}", e);
384 }
385 }
386
387 match format.unwrap_or(ReturnFormat::Nested) {
388 ReturnFormat::Nested => {
389 let mut result = Value::Object(serde_json::Map::new());
390 for path in paths {
391 if let Some(val) = self.get_schema_value_by_path(path) {
392 Self::insert_at_path(&mut result, path, val);
394 }
395 }
396 result
397 }
398 ReturnFormat::Flat => {
399 let mut result = serde_json::Map::new();
400 for path in paths {
401 if let Some(val) = self.get_schema_value_by_path(path) {
402 result.insert(path.clone(), val);
403 }
404 }
405 Value::Object(result)
406 }
407 ReturnFormat::Array => {
408 let mut result = Vec::new();
409 for path in paths {
410 if let Some(val) = self.get_schema_value_by_path(path) {
411 result.push(val);
412 } else {
413 result.push(Value::Null);
414 }
415 }
416 Value::Array(result)
417 }
418 }
419 }
420
421 pub fn get_schema_by_path(&self, path: &str) -> Option<Value> {
423 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
424 self.schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
425 }
426
427 pub fn get_schema_by_paths(
429 &self,
430 paths: &[String],
431 format: Option<ReturnFormat>,
432 ) -> Value {
433 match format.unwrap_or(ReturnFormat::Nested) {
434 ReturnFormat::Nested => {
435 let mut result = Value::Object(serde_json::Map::new());
436 for path in paths {
437 if let Some(val) = self.get_schema_by_path(path) {
438 Self::insert_at_path(&mut result, path, val);
439 }
440 }
441 result
442 }
443 ReturnFormat::Flat => {
444 let mut result = serde_json::Map::new();
445 for path in paths {
446 if let Some(val) = self.get_schema_by_path(path) {
447 result.insert(path.clone(), val);
448 }
449 }
450 Value::Object(result)
451 }
452 ReturnFormat::Array => {
453 let mut result = Vec::new();
454 for path in paths {
455 if let Some(val) = self.get_schema_by_path(path) {
456 result.push(val);
457 } else {
458 result.push(Value::Null);
459 }
460 }
461 Value::Array(result)
462 }
463 }
464 }
465
466 pub(crate) fn insert_at_path(root: &mut Value, path: &str, value: Value) {
468 let parts: Vec<&str> = path.split('.').collect();
469 let mut current = root;
470
471 for (i, part) in parts.iter().enumerate() {
472 if i == parts.len() - 1 {
473 if let Value::Object(map) = current {
475 map.insert(part.to_string(), value);
476 return; }
478 } else {
479 if !current.is_object() {
484 *current = Value::Object(serde_json::Map::new());
485 }
486
487 if let Value::Object(map) = current {
488 if !map.contains_key(*part) {
489 map.insert(part.to_string(), Value::Object(serde_json::Map::new()));
490 }
491 current = map.get_mut(*part).unwrap();
492 }
493 }
494 }
495 }
496
497 pub fn flatten_object(prefix: &str, value: &Value, result: &mut serde_json::Map<String, Value>) {
499 match value {
500 Value::Object(map) => {
501 for (k, v) in map {
502 let new_key = if prefix.is_empty() {
503 k.clone()
504 } else {
505 format!("{}.{}", prefix, k)
506 };
507 Self::flatten_object(&new_key, v, result);
508 }
509 }
510 _ => {
511 result.insert(prefix.to_string(), value.clone());
512 }
513 }
514 }
515
516 pub fn convert_to_format(value: Value, format: ReturnFormat) -> Value {
517 match format {
518 ReturnFormat::Nested => value,
519 ReturnFormat::Flat => {
520 let mut result = serde_json::Map::new();
521 Self::flatten_object("", &value, &mut result);
522 Value::Object(result)
523 }
524 ReturnFormat::Array => {
525 if let Value::Object(map) = value {
529 Value::Array(map.values().cloned().collect())
530 } else if let Value::Array(arr) = value {
531 Value::Array(arr)
532 } else {
533 Value::Array(vec![value])
534 }
535 }
536 }
537 }
538}