json_eval_rs/jsoneval/
getters.rs1use super::JSONEval;
2use crate::jsoneval::path_utils;
3use crate::jsoneval::types::ReturnFormat;
4
5use crate::time_block;
6use serde_json::Value;
7
8impl JSONEval {
9 pub(crate) fn is_effective_hidden(&self, schema_pointer: &str) -> bool {
12 let mut end = schema_pointer.len();
13
14 loop {
15 let current_path = &schema_pointer[..end];
16
17 if let Some(schema_node) = self.evaluated_schema.pointer(current_path) {
18 if let Value::Object(map) = schema_node {
19 if let Some(Value::Object(condition)) = map.get("condition") {
20 if let Some(Value::Bool(true)) = condition.get("hidden") {
21 return true;
22 }
23 }
24
25 if let Some(Value::Object(layout)) = map.get("$layout") {
26 if let Some(Value::Object(hide_layout)) = layout.get("hideLayout") {
27 if let Some(Value::Bool(true)) = hide_layout.get("all") {
28 return true;
29 }
30 }
31 }
32 }
33 }
34
35 if end == 0 {
36 break;
37 }
38
39 match schema_pointer[..end].rfind('/') {
41 Some(0) | None => {
42 end = 0;
43 }
44 Some(last_slash) => {
45 end = last_slash;
46 let parent = &schema_pointer[..end];
47 if parent.ends_with("/properties") {
48 end -= "/properties".len();
49 } else if parent.ends_with("/items") {
50 end -= "/items".len();
51 }
52 }
53 }
54 }
55
56 false
57 }
58
59 fn prune_hidden_values(&self, data: &mut Value, current_path: &str) {
61 if let Value::Object(map) = data {
62 let mut keys_to_remove = Vec::new();
64
65 for (key, value) in map.iter_mut() {
66 if key == "$params" || key == "$context" {
68 continue;
69 }
70
71 let schema_path = if current_path.is_empty() {
75 format!("/properties/{}", key)
76 } else {
77 format!("{}/properties/{}", current_path, key)
78 };
79
80 if self.is_effective_hidden(&schema_path) {
82 keys_to_remove.push(key.clone());
83 } else {
84 if value.is_object() {
86 self.prune_hidden_values(value, &schema_path);
87 }
88 }
89 }
90
91 for key in keys_to_remove {
93 map.remove(&key);
94 }
95 }
96 }
97
98 fn resolve_static_markers_in_value(&self, schema_output: &mut Value) {
104 for (static_key, array_arc) in self.static_arrays.iter() {
105 let schema_path = if static_key.starts_with("/$table") {
107 &static_key["/$table".len()..] } else {
109 static_key.as_str() };
111
112 if let Some(target_val) = schema_output.pointer_mut(schema_path) {
114 *target_val = (**array_arc).clone();
116 }
117 }
118 }
119
120
121 pub fn get_evaluated_schema(&mut self, skip_layout: bool) -> Value {
132 time_block!("get_evaluated_schema()", {
133 if !skip_layout {
134 if let Err(e) = self.resolve_layout(false) {
135 eprintln!(
136 "Warning: Layout resolution failed in get_evaluated_schema: {}",
137 e
138 );
139 }
140 }
141 let mut schema = self.evaluated_schema.clone();
142 self.resolve_static_markers_in_value(&mut schema);
143 schema
144 })
145 }
146
147 fn resolve_static_markers_at_path(&self, schema_prefix: &str) -> Option<Value> {
158 let mut subtree = self.evaluated_schema.pointer(schema_prefix)?.clone();
159
160 let prefix_slash = format!("{}/", schema_prefix);
162
163 for (static_key, array_arc) in self.static_arrays.iter() {
164 let schema_path: &str = if static_key.starts_with("/$table") {
166 &static_key["/$table".len()..]
167 } else {
168 static_key.as_str()
169 };
170
171 let relative: &str = if schema_path == schema_prefix {
173 ""
175 } else if schema_path.starts_with(&prefix_slash) {
176 &schema_path[schema_prefix.len()..]
178 } else {
179 continue; };
181
182 if relative.is_empty() {
183 subtree = (**array_arc).clone();
184 } else if let Some(target) = subtree.pointer_mut(relative) {
185 *target = (**array_arc).clone();
186 }
187 }
188
189 Some(subtree)
190 }
191
192 pub fn get_schema_value_by_path(&self, path: &str) -> Option<Value> {
195 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
196 self.resolve_static_markers_at_path(pointer_path.trim_start_matches('#'))
197 }
198
199 pub fn get_schema_value(&mut self) -> Value {
203 let mut current_data = self.eval_data.data().clone();
205
206 if !current_data.is_object() {
208 current_data = Value::Object(serde_json::Map::new());
209 }
210
211 if let Some(obj) = current_data.as_object_mut() {
213 obj.remove("$params");
214 obj.remove("$context");
215 }
216
217 self.prune_hidden_values(&mut current_data, "");
219
220 for eval_key in self.value_evaluations.iter() {
223 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
224
225 if clean_key.starts_with("/$params")
227 || (clean_key.ends_with("/value")
228 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
229 {
230 continue;
231 }
232
233 let path = clean_key.replace("/properties", "").replace("/value", "");
234
235 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
238 if self.is_effective_hidden(schema_path) {
239 continue;
240 }
241
242 let value = match self.resolve_static_markers_at_path(clean_key) {
244 Some(v) => v,
245 None => continue,
246 };
247
248 let path_parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
250
251 if path_parts.is_empty() {
252 continue;
253 }
254
255 let mut current = &mut current_data;
257 for (i, part) in path_parts.iter().enumerate() {
258 let is_last = i == path_parts.len() - 1;
259
260 if is_last {
261 if let Some(obj) = current.as_object_mut() {
263 let should_update = match obj.get(*part) {
264 Some(v) => v.is_null(),
265 None => true,
266 };
267
268 if should_update {
269 obj.insert(
270 (*part).to_string(),
271 crate::utils::clean_float_noise(value.clone()),
272 );
273 }
274 }
275 } else {
276 if let Some(obj) = current.as_object_mut() {
278 if !obj.contains_key(*part) {
279 obj.insert((*part).to_string(), Value::Object(serde_json::Map::new()));
280 }
281
282 current = obj.get_mut(*part).unwrap();
283 } else {
284 break;
286 }
287 }
288 }
289 }
290
291 self.data = current_data.clone();
293
294 crate::utils::clean_float_noise(current_data)
295 }
296
297 pub fn get_schema_value_array(&self) -> Value {
304 let mut result = Vec::new();
305
306 for eval_key in self.value_evaluations.iter() {
307 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
308
309 if clean_key.starts_with("/$params")
311 || (clean_key.ends_with("/value")
312 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
313 {
314 continue;
315 }
316
317 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
319 if self.is_effective_hidden(schema_path) {
320 continue;
321 }
322
323 let dotted_path = clean_key
325 .replace("/properties", "")
326 .replace("/value", "")
327 .trim_start_matches('/')
328 .replace('/', ".");
329
330 if dotted_path.is_empty() {
331 continue;
332 }
333
334 let value = match self.resolve_static_markers_at_path(clean_key) {
336 Some(v) => crate::utils::clean_float_noise(v),
337 None => continue,
338 };
339
340 let mut item = serde_json::Map::new();
342 item.insert("path".to_string(), Value::String(dotted_path));
343 item.insert("value".to_string(), value);
344 result.push(Value::Object(item));
345 }
346
347 Value::Array(result)
348 }
349
350 pub fn get_schema_value_object(&self) -> Value {
357 let mut result = serde_json::Map::new();
358
359 for eval_key in self.value_evaluations.iter() {
360 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
361
362 if clean_key.starts_with("/$params")
364 || (clean_key.ends_with("/value")
365 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
366 {
367 continue;
368 }
369
370 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
372 if self.is_effective_hidden(schema_path) {
373 continue;
374 }
375
376 let dotted_path = clean_key
378 .replace("/properties", "")
379 .replace("/value", "")
380 .trim_start_matches('/')
381 .replace('/', ".");
382
383 if dotted_path.is_empty() {
384 continue;
385 }
386
387 let value = match self.resolve_static_markers_at_path(clean_key) {
389 Some(v) => crate::utils::clean_float_noise(v),
390 None => continue,
391 };
392
393 result.insert(dotted_path, value);
394 }
395
396 Value::Object(result)
397 }
398
399 pub fn get_evaluated_schema_without_params(&mut self, skip_layout: bool) -> Value {
401 let mut schema = self.get_evaluated_schema(skip_layout);
402 if let Value::Object(ref mut map) = schema {
403 map.remove("$params");
404 }
405 schema
406 }
407
408 pub fn get_evaluated_schema_msgpack(&mut self, skip_layout: bool) -> Result<Vec<u8>, String> {
410 let schema = self.get_evaluated_schema(skip_layout);
411 rmp_serde::to_vec(&schema).map_err(|e| format!("MessagePack serialization failed: {}", e))
412 }
413
414 pub fn get_evaluated_schema_by_path(&mut self, path: &str, skip_layout: bool) -> Option<Value> {
416 if !skip_layout {
417 if let Err(e) = self.resolve_layout(false) {
418 eprintln!(
419 "Warning: Layout resolution failed in get_evaluated_schema_by_path: {}",
420 e
421 );
422 }
423 }
424 self.get_schema_value_by_path(path)
425 }
426
427 pub fn get_evaluated_schema_by_paths(
429 &mut self,
430 paths: &[String],
431 skip_layout: bool,
432 format: Option<ReturnFormat>,
433 ) -> Value {
434 if !skip_layout {
435 if let Err(e) = self.resolve_layout(false) {
436 eprintln!(
437 "Warning: Layout resolution failed in get_evaluated_schema_by_paths: {}",
438 e
439 );
440 }
441 }
442
443 match format.unwrap_or(ReturnFormat::Nested) {
444 ReturnFormat::Nested => {
445 let mut result = Value::Object(serde_json::Map::new());
446 for path in paths {
447 if let Some(val) = self.get_schema_value_by_path(path) {
448 Self::insert_at_path(&mut result, path, val);
450 }
451 }
452 result
453 }
454 ReturnFormat::Flat => {
455 let mut result = serde_json::Map::new();
456 for path in paths {
457 if let Some(val) = self.get_schema_value_by_path(path) {
458 result.insert(path.clone(), val);
459 }
460 }
461 Value::Object(result)
462 }
463 ReturnFormat::Array => {
464 let mut result = Vec::new();
465 for path in paths {
466 if let Some(val) = self.get_schema_value_by_path(path) {
467 result.push(val);
468 } else {
469 result.push(Value::Null);
470 }
471 }
472 Value::Array(result)
473 }
474 }
475 }
476
477 pub fn get_schema_by_path(&self, path: &str) -> Option<Value> {
479 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
480 self.schema
481 .pointer(&pointer_path.trim_start_matches('#'))
482 .cloned()
483 }
484
485 pub fn get_schema_by_paths(&self, paths: &[String], format: Option<ReturnFormat>) -> Value {
487 match format.unwrap_or(ReturnFormat::Nested) {
488 ReturnFormat::Nested => {
489 let mut result = Value::Object(serde_json::Map::new());
490 for path in paths {
491 if let Some(val) = self.get_schema_by_path(path) {
492 Self::insert_at_path(&mut result, path, val);
493 }
494 }
495 result
496 }
497 ReturnFormat::Flat => {
498 let mut result = serde_json::Map::new();
499 for path in paths {
500 if let Some(val) = self.get_schema_by_path(path) {
501 result.insert(path.clone(), val);
502 }
503 }
504 Value::Object(result)
505 }
506 ReturnFormat::Array => {
507 let mut result = Vec::new();
508 for path in paths {
509 if let Some(val) = self.get_schema_by_path(path) {
510 result.push(val);
511 } else {
512 result.push(Value::Null);
513 }
514 }
515 Value::Array(result)
516 }
517 }
518 }
519
520 pub(crate) fn insert_at_path(root: &mut Value, path: &str, value: Value) {
522 let parts: Vec<&str> = path.split('.').collect();
523 let mut current = root;
524
525 for (i, part) in parts.iter().enumerate() {
526 if i == parts.len() - 1 {
527 if let Value::Object(map) = current {
529 map.insert(part.to_string(), value);
530 return; }
532 } else {
533 if !current.is_object() {
538 *current = Value::Object(serde_json::Map::new());
539 }
540
541 if let Value::Object(map) = current {
542 if !map.contains_key(*part) {
543 map.insert(part.to_string(), Value::Object(serde_json::Map::new()));
544 }
545 current = map.get_mut(*part).unwrap();
546 }
547 }
548 }
549 }
550
551 pub fn flatten_object(
553 prefix: &str,
554 value: &Value,
555 result: &mut serde_json::Map<String, Value>,
556 ) {
557 match value {
558 Value::Object(map) => {
559 for (k, v) in map {
560 let new_key = if prefix.is_empty() {
561 k.clone()
562 } else {
563 format!("{}.{}", prefix, k)
564 };
565 Self::flatten_object(&new_key, v, result);
566 }
567 }
568 _ => {
569 result.insert(prefix.to_string(), value.clone());
570 }
571 }
572 }
573
574 pub fn convert_to_format(value: Value, format: ReturnFormat) -> Value {
575 match format {
576 ReturnFormat::Nested => value,
577 ReturnFormat::Flat => {
578 let mut result = serde_json::Map::new();
579 Self::flatten_object("", &value, &mut result);
580 Value::Object(result)
581 }
582 ReturnFormat::Array => {
583 if let Value::Object(map) = value {
587 Value::Array(map.values().cloned().collect())
588 } else if let Value::Array(arr) = value {
589 Value::Array(arr)
590 } else {
591 Value::Array(vec![value])
592 }
593 }
594 }
595 }
596}