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 end = schema_pointer.len();
16
17 loop {
18 let current_path = &schema_pointer[..end];
19
20 if let Some(schema_node) = self.evaluated_schema.pointer(current_path) {
21 if let Value::Object(map) = schema_node {
22 if let Some(Value::Object(condition)) = map.get("condition") {
23 if let Some(Value::Bool(true)) = condition.get("hidden") {
24 return true;
25 }
26 }
27
28 if let Some(Value::Object(layout)) = map.get("$layout") {
29 if let Some(Value::Object(hide_layout)) = layout.get("hideLayout") {
30 if let Some(Value::Bool(true)) = hide_layout.get("all") {
31 return true;
32 }
33 }
34 }
35 }
36 }
37
38 if end == 0 {
39 break;
40 }
41
42 match schema_pointer[..end].rfind('/') {
44 Some(0) | None => {
45 end = 0;
46 }
47 Some(last_slash) => {
48 end = last_slash;
49 let parent = &schema_pointer[..end];
50 if parent.ends_with("/properties") {
51 end -= "/properties".len();
52 } else if parent.ends_with("/items") {
53 end -= "/items".len();
54 }
55 }
56 }
57 }
58
59 false
60 }
61
62 fn prune_hidden_values(&self, data: &mut Value, current_path: &str) {
64 if let Value::Object(map) = data {
65 let mut keys_to_remove = Vec::new();
67
68 for (key, value) in map.iter_mut() {
69 if key == "$params" || key == "$context" {
71 continue;
72 }
73
74 let schema_path = if current_path.is_empty() {
78 format!("/properties/{}", key)
79 } else {
80 format!("{}/properties/{}", current_path, key)
81 };
82
83 if self.is_effective_hidden(&schema_path) {
85 keys_to_remove.push(key.clone());
86 } else {
87 if value.is_object() {
89 self.prune_hidden_values(value, &schema_path);
90 }
91 }
92 }
93
94 for key in keys_to_remove {
96 map.remove(&key);
97 }
98 }
99 }
100
101 pub fn get_evaluated_schema(&mut self, skip_layout: bool) -> Value {
111 time_block!("get_evaluated_schema()", {
112 if !skip_layout {
113 if let Err(e) = self.resolve_layout(false) {
114 eprintln!("Warning: Layout resolution failed in get_evaluated_schema: {}", e);
115 }
116 }
117 self.evaluated_schema.clone()
118 })
119 }
120
121
122
123 pub fn get_schema_value_by_path(&self, path: &str) -> Option<Value> {
125 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
126 self.evaluated_schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
127 }
128
129 pub fn get_schema_value(&mut self) -> Value {
133 let mut current_data = self.eval_data.data().clone();
135
136 if !current_data.is_object() {
138 current_data = Value::Object(serde_json::Map::new());
139 }
140
141 if let Some(obj) = current_data.as_object_mut() {
143 obj.remove("$params");
144 obj.remove("$context");
145 }
146
147 self.prune_hidden_values(&mut current_data, "");
149
150 for eval_key in self.value_evaluations.iter() {
153 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
154
155 if clean_key.starts_with("/$params")
157 || (clean_key.ends_with("/value")
158 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
159 {
160 continue;
161 }
162
163 let path = clean_key.replace("/properties", "").replace("/value", "");
164
165 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
168 if self.is_effective_hidden(schema_path) {
169 continue;
170 }
171
172 let value = match self.evaluated_schema.pointer(&clean_key) {
174 Some(v) => v.clone(),
175 None => continue,
176 };
177
178 let path_parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
180
181 if path_parts.is_empty() {
182 continue;
183 }
184
185 let mut current = &mut current_data;
187 for (i, part) in path_parts.iter().enumerate() {
188 let is_last = i == path_parts.len() - 1;
189
190 if is_last {
191 if let Some(obj) = current.as_object_mut() {
193 let should_update = match obj.get(*part) {
194 Some(v) => v.is_null(),
195 None => true,
196 };
197
198 if should_update {
199 obj.insert((*part).to_string(), crate::utils::clean_float_noise(value.clone()));
200 }
201 }
202 } else {
203 if let Some(obj) = current.as_object_mut() {
205 if !obj.contains_key(*part) {
211 obj.insert((*part).to_string(), Value::Object(serde_json::Map::new()));
212 }
213
214 current = obj.get_mut(*part).unwrap();
215 } else {
216 break;
218 }
219 }
220 }
221 }
222
223 self.data = current_data.clone();
225
226 crate::utils::clean_float_noise(current_data)
227 }
228
229 pub fn get_schema_value_array(&self) -> Value {
236 let mut result = Vec::new();
237
238 for eval_key in self.value_evaluations.iter() {
239 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
240
241 if clean_key.starts_with("/$params")
243 || (clean_key.ends_with("/value")
244 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
245 {
246 continue;
247 }
248
249 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
251 if self.is_effective_hidden(schema_path) {
252 continue;
253 }
254
255 let dotted_path = clean_key
257 .replace("/properties", "")
258 .replace("/value", "")
259 .trim_start_matches('/')
260 .replace('/', ".");
261
262 if dotted_path.is_empty() {
263 continue;
264 }
265
266 let value = match self.evaluated_schema.pointer(&clean_key) {
268 Some(v) => crate::utils::clean_float_noise(v.clone()),
269 None => continue,
270 };
271
272 let mut item = serde_json::Map::new();
274 item.insert("path".to_string(), Value::String(dotted_path));
275 item.insert("value".to_string(), value);
276 result.push(Value::Object(item));
277 }
278
279 Value::Array(result)
280 }
281
282 pub fn get_schema_value_object(&self) -> Value {
289 let mut result = serde_json::Map::new();
290
291 for eval_key in self.value_evaluations.iter() {
292 let clean_key = eval_key.strip_prefix('#').unwrap_or(eval_key);
293
294 if clean_key.starts_with("/$params")
296 || (clean_key.ends_with("/value")
297 && (clean_key.contains("/rules/") || clean_key.contains("/options/")))
298 {
299 continue;
300 }
301
302 let schema_path = clean_key.strip_suffix("/value").unwrap_or(&clean_key);
304 if self.is_effective_hidden(schema_path) {
305 continue;
306 }
307
308 let dotted_path = clean_key
310 .replace("/properties", "")
311 .replace("/value", "")
312 .trim_start_matches('/')
313 .replace('/', ".");
314
315 if dotted_path.is_empty() {
316 continue;
317 }
318
319 let value = match self.evaluated_schema.pointer(&clean_key) {
321 Some(v) => crate::utils::clean_float_noise(v.clone()),
322 None => continue,
323 };
324
325 result.insert(dotted_path, value);
326 }
327
328 Value::Object(result)
329 }
330
331 pub fn get_evaluated_schema_without_params(&mut self, skip_layout: bool) -> Value {
333 let mut schema = self.get_evaluated_schema(skip_layout);
334 if let Value::Object(ref mut map) = schema {
335 map.remove("$params");
336 }
337 schema
338 }
339
340 pub fn get_evaluated_schema_msgpack(&mut self, skip_layout: bool) -> Result<Vec<u8>, String> {
342 let schema = self.get_evaluated_schema(skip_layout);
343 rmp_serde::to_vec(&schema).map_err(|e| format!("MessagePack serialization failed: {}", e))
344 }
345
346 pub fn get_evaluated_schema_by_path(&mut self, path: &str, skip_layout: bool) -> Option<Value> {
348 if !skip_layout {
349 if let Err(e) = self.resolve_layout(false) {
350 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_path: {}", e);
351 }
352 }
353 self.get_schema_value_by_path(path)
354 }
355
356 pub fn get_evaluated_schema_by_paths(
358 &mut self,
359 paths: &[String],
360 skip_layout: bool,
361 format: Option<ReturnFormat>,
362 ) -> Value {
363 if !skip_layout {
364 if let Err(e) = self.resolve_layout(false) {
365 eprintln!("Warning: Layout resolution failed in get_evaluated_schema_by_paths: {}", e);
366 }
367 }
368
369 match format.unwrap_or(ReturnFormat::Nested) {
370 ReturnFormat::Nested => {
371 let mut result = Value::Object(serde_json::Map::new());
372 for path in paths {
373 if let Some(val) = self.get_schema_value_by_path(path) {
374 Self::insert_at_path(&mut result, path, val);
376 }
377 }
378 result
379 }
380 ReturnFormat::Flat => {
381 let mut result = serde_json::Map::new();
382 for path in paths {
383 if let Some(val) = self.get_schema_value_by_path(path) {
384 result.insert(path.clone(), val);
385 }
386 }
387 Value::Object(result)
388 }
389 ReturnFormat::Array => {
390 let mut result = Vec::new();
391 for path in paths {
392 if let Some(val) = self.get_schema_value_by_path(path) {
393 result.push(val);
394 } else {
395 result.push(Value::Null);
396 }
397 }
398 Value::Array(result)
399 }
400 }
401 }
402
403 pub fn get_schema_by_path(&self, path: &str) -> Option<Value> {
405 let pointer_path = path_utils::dot_notation_to_schema_pointer(path);
406 self.schema.pointer(&pointer_path.trim_start_matches('#')).cloned()
407 }
408
409 pub fn get_schema_by_paths(
411 &self,
412 paths: &[String],
413 format: Option<ReturnFormat>,
414 ) -> Value {
415 match format.unwrap_or(ReturnFormat::Nested) {
416 ReturnFormat::Nested => {
417 let mut result = Value::Object(serde_json::Map::new());
418 for path in paths {
419 if let Some(val) = self.get_schema_by_path(path) {
420 Self::insert_at_path(&mut result, path, val);
421 }
422 }
423 result
424 }
425 ReturnFormat::Flat => {
426 let mut result = serde_json::Map::new();
427 for path in paths {
428 if let Some(val) = self.get_schema_by_path(path) {
429 result.insert(path.clone(), val);
430 }
431 }
432 Value::Object(result)
433 }
434 ReturnFormat::Array => {
435 let mut result = Vec::new();
436 for path in paths {
437 if let Some(val) = self.get_schema_by_path(path) {
438 result.push(val);
439 } else {
440 result.push(Value::Null);
441 }
442 }
443 Value::Array(result)
444 }
445 }
446 }
447
448 pub(crate) fn insert_at_path(root: &mut Value, path: &str, value: Value) {
450 let parts: Vec<&str> = path.split('.').collect();
451 let mut current = root;
452
453 for (i, part) in parts.iter().enumerate() {
454 if i == parts.len() - 1 {
455 if let Value::Object(map) = current {
457 map.insert(part.to_string(), value);
458 return; }
460 } else {
461 if !current.is_object() {
466 *current = Value::Object(serde_json::Map::new());
467 }
468
469 if let Value::Object(map) = current {
470 if !map.contains_key(*part) {
471 map.insert(part.to_string(), Value::Object(serde_json::Map::new()));
472 }
473 current = map.get_mut(*part).unwrap();
474 }
475 }
476 }
477 }
478
479 pub fn flatten_object(prefix: &str, value: &Value, result: &mut serde_json::Map<String, Value>) {
481 match value {
482 Value::Object(map) => {
483 for (k, v) in map {
484 let new_key = if prefix.is_empty() {
485 k.clone()
486 } else {
487 format!("{}.{}", prefix, k)
488 };
489 Self::flatten_object(&new_key, v, result);
490 }
491 }
492 _ => {
493 result.insert(prefix.to_string(), value.clone());
494 }
495 }
496 }
497
498 pub fn convert_to_format(value: Value, format: ReturnFormat) -> Value {
499 match format {
500 ReturnFormat::Nested => value,
501 ReturnFormat::Flat => {
502 let mut result = serde_json::Map::new();
503 Self::flatten_object("", &value, &mut result);
504 Value::Object(result)
505 }
506 ReturnFormat::Array => {
507 if let Value::Object(map) = value {
511 Value::Array(map.values().cloned().collect())
512 } else if let Value::Array(arr) = value {
513 Value::Array(arr)
514 } else {
515 Value::Array(vec![value])
516 }
517 }
518 }
519 }
520}