1use datavalue::OwnedDataValue;
9use std::sync::Arc;
10
11pub(crate) fn default_condition() -> serde_json::Value {
15 serde_json::Value::Bool(true)
16}
17
18pub fn get_nested_value<'b>(data: &'b OwnedDataValue, path: &str) -> Option<&'b OwnedDataValue> {
30 if path.is_empty() {
31 return Some(data);
32 }
33 let parts: Vec<&str> = path.split('.').collect();
34 get_nested_value_impl(data, &parts)
35}
36
37pub fn set_nested_value(data: &mut OwnedDataValue, path: &str, value: OwnedDataValue) {
49 if path.is_empty() {
50 return;
51 }
52 let parts: Vec<&str> = path.split('.').collect();
53 set_nested_value_impl(data, &parts, value);
54}
55
56#[inline]
58pub fn get_nested_value_cloned(data: &OwnedDataValue, path: &str) -> Option<OwnedDataValue> {
59 get_nested_value(data, path).cloned()
60}
61
62pub fn get_nested_value_parts<'b>(
66 data: &'b OwnedDataValue,
67 parts: &[Arc<str>],
68) -> Option<&'b OwnedDataValue> {
69 if parts.is_empty() {
70 return Some(data);
71 }
72 let parts: Vec<&str> = parts.iter().map(Arc::as_ref).collect();
73 get_nested_value_impl(data, &parts)
74}
75
76fn get_nested_value_impl<'b>(
81 data: &'b OwnedDataValue,
82 parts: &[&str],
83) -> Option<&'b OwnedDataValue> {
84 let mut current = data;
85 for part in parts {
86 match current {
87 OwnedDataValue::Object(pairs) => {
88 let key = strip_hash_prefix(part);
89 let slot = pairs.iter().find(|(k, _)| k == key)?;
90 current = &slot.1;
91 }
92 OwnedDataValue::Array(items) => {
93 let idx: usize = part.parse().ok()?;
94 current = items.get(idx)?;
95 }
96 _ => return None,
97 }
98 }
99 Some(current)
100}
101
102pub fn set_nested_value_parts(
108 data: &mut OwnedDataValue,
109 parts: &[Arc<str>],
110 value: OwnedDataValue,
111) {
112 if parts.is_empty() {
113 return;
114 }
115 let parts: Vec<&str> = parts.iter().map(Arc::as_ref).collect();
116 set_nested_value_impl(data, &parts, value);
117}
118
119fn set_nested_value_impl(data: &mut OwnedDataValue, parts: &[&str], value: OwnedDataValue) {
124 let last = parts.len() - 1;
125 let mut current = data;
126
127 for (i, part) in parts.iter().enumerate() {
128 if i == last {
129 match current {
130 OwnedDataValue::Object(pairs) => {
131 let key = strip_hash_prefix(part);
132 if let Some(slot) = pairs.iter_mut().find(|(k, _)| k == key) {
133 slot.1 = value;
134 } else {
135 pairs.push((key.to_string(), value));
136 }
137 }
138 OwnedDataValue::Array(items) => {
139 if let Ok(idx) = part.parse::<usize>() {
140 while items.len() <= idx {
141 items.push(OwnedDataValue::Null);
142 }
143 items[idx] = value;
144 }
145 }
146 _ => {}
147 }
148 return;
149 }
150
151 let next_is_array = parts[i + 1].parse::<usize>().is_ok();
155
156 match current {
157 OwnedDataValue::Object(pairs) => {
158 let key = strip_hash_prefix(part);
159 let idx = match pairs.iter().position(|(k, _)| k == key) {
160 Some(idx) => idx,
161 None => {
162 let child = if next_is_array {
163 OwnedDataValue::Array(Vec::new())
164 } else {
165 OwnedDataValue::Object(Vec::new())
166 };
167 pairs.push((key.to_string(), child));
168 pairs.len() - 1
169 }
170 };
171 current = &mut pairs[idx].1;
172 }
173 OwnedDataValue::Array(items) => {
174 let Ok(idx) = part.parse::<usize>() else {
175 return; };
177 while items.len() <= idx {
178 items.push(OwnedDataValue::Null);
179 }
180 if matches!(items[idx], OwnedDataValue::Null) {
181 items[idx] = if next_is_array {
182 OwnedDataValue::Array(Vec::new())
183 } else {
184 OwnedDataValue::Object(Vec::new())
185 };
186 }
187 current = &mut items[idx];
188 }
189 _ => return,
190 }
191 }
192}
193
194pub fn remove_nested_value(data: &mut OwnedDataValue, path: &str) -> Option<OwnedDataValue> {
232 if path.is_empty() {
233 return None;
234 }
235 let parts: Vec<&str> = path.split('.').collect();
236 let (last, parents) = parts.split_last()?;
237
238 let mut current = data;
239 for part in parents {
240 current = match current {
241 OwnedDataValue::Object(pairs) => {
242 let key = strip_hash_prefix(part);
243 let idx = pairs.iter().position(|(k, _)| k == key)?;
244 &mut pairs[idx].1
245 }
246 OwnedDataValue::Array(items) => {
247 let idx: usize = part.parse().ok()?;
248 items.get_mut(idx)?
249 }
250 _ => return None,
251 };
252 }
253
254 match current {
255 OwnedDataValue::Object(pairs) => {
256 let key = strip_hash_prefix(last);
257 let pos = pairs.iter().position(|(k, _)| k == key)?;
258 Some(pairs.remove(pos).1)
259 }
260 OwnedDataValue::Array(items) => {
261 let idx: usize = last.parse().ok()?;
262 if idx < items.len() {
263 Some(items.remove(idx))
264 } else {
265 None
266 }
267 }
268 _ => None,
269 }
270}
271
272#[inline]
275pub(crate) fn strip_hash_prefix(part: &str) -> &str {
276 part.strip_prefix('#').unwrap_or(part)
277}
278
279pub(crate) fn compute_data_path(target: &str) -> (Arc<str>, Arc<[Arc<str>]>) {
286 let path = format!("data.{target}");
287 let parts: Vec<Arc<str>> = path.split('.').map(Arc::from).collect();
288 (Arc::from(path), parts.into())
289}
290
291pub(crate) fn precompute_target_path(
296 target: &str,
297 path_arc: &mut Arc<str>,
298 path_parts: &mut Arc<[Arc<str>]>,
299) {
300 (*path_arc, *path_parts) = compute_data_path(target);
301}
302
303pub(crate) fn resolve_target_path(
308 target: &str,
309 path_arc: &Arc<str>,
310 path_parts: &Arc<[Arc<str>]>,
311) -> (Arc<str>, Arc<[Arc<str>]>) {
312 if path_parts.is_empty() {
313 compute_data_path(target)
314 } else {
315 (Arc::clone(path_arc), Arc::clone(path_parts))
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use super::*;
322 use serde_json::json;
323
324 fn dv(v: serde_json::Value) -> OwnedDataValue {
326 OwnedDataValue::from(&v)
327 }
328
329 #[test]
330 fn test_get_nested_value() {
331 let data = dv(json!({
332 "user": {
333 "name": "John",
334 "age": 30,
335 "addresses": [
336 {"city": "New York", "zip": "10001"},
337 {"city": "San Francisco", "zip": "94102"}
338 ],
339 "preferences": {
340 "theme": "dark",
341 "notifications": true
342 }
343 },
344 "items": [1, 2, 3]
345 }));
346
347 assert_eq!(
348 get_nested_value(&data, "user.name"),
349 Some(&dv(json!("John")))
350 );
351 assert_eq!(get_nested_value(&data, "user.age"), Some(&dv(json!(30))));
352
353 assert_eq!(
354 get_nested_value(&data, "user.preferences.theme"),
355 Some(&dv(json!("dark")))
356 );
357 assert_eq!(
358 get_nested_value(&data, "user.preferences.notifications"),
359 Some(&dv(json!(true)))
360 );
361
362 assert_eq!(get_nested_value(&data, "items.0"), Some(&dv(json!(1))));
363 assert_eq!(get_nested_value(&data, "items.2"), Some(&dv(json!(3))));
364
365 assert_eq!(
366 get_nested_value(&data, "user.addresses.0.city"),
367 Some(&dv(json!("New York")))
368 );
369 assert_eq!(
370 get_nested_value(&data, "user.addresses.1.zip"),
371 Some(&dv(json!("94102")))
372 );
373
374 assert_eq!(get_nested_value(&data, "user.missing"), None);
375 assert_eq!(get_nested_value(&data, "items.10"), None);
376 assert_eq!(get_nested_value(&data, "user.addresses.2.city"), None);
377 assert_eq!(get_nested_value(&data, "nonexistent.path"), None);
378 }
379
380 #[test]
381 fn test_set_nested_value() {
382 let mut data = dv(json!({}));
383
384 set_nested_value(&mut data, "name", dv(json!("Alice")));
385 assert_eq!(data, dv(json!({"name": "Alice"})));
386
387 set_nested_value(&mut data, "user.email", dv(json!("alice@example.com")));
388 assert_eq!(
389 data,
390 dv(json!({
391 "name": "Alice",
392 "user": {"email": "alice@example.com"}
393 }))
394 );
395
396 set_nested_value(&mut data, "name", dv(json!("Bob")));
397 assert_eq!(
398 data,
399 dv(json!({
400 "name": "Bob",
401 "user": {"email": "alice@example.com"}
402 }))
403 );
404
405 set_nested_value(&mut data, "settings.theme.mode", dv(json!("dark")));
406 assert_eq!(data["settings"]["theme"]["mode"], dv(json!("dark")));
407
408 set_nested_value(&mut data, "user.age", dv(json!(25)));
409 assert_eq!(data["user"]["age"], dv(json!(25)));
410 assert_eq!(data["user"]["email"], dv(json!("alice@example.com")));
411 }
412
413 #[test]
414 fn test_set_nested_value_with_arrays() {
415 let mut data = dv(json!({ "items": [1, 2, 3] }));
416
417 set_nested_value(&mut data, "items.0", dv(json!(10)));
418 assert_eq!(data["items"], dv(json!([10, 2, 3])));
419
420 set_nested_value(&mut data, "items.5", dv(json!(50)));
421 assert_eq!(data["items"], dv(json!([10, 2, 3, null, null, 50])));
422
423 let mut data2 = dv(json!({}));
424 set_nested_value(&mut data2, "matrix.0.0", dv(json!(1)));
425 set_nested_value(&mut data2, "matrix.0.1", dv(json!(2)));
426 set_nested_value(&mut data2, "matrix.1.0", dv(json!(3)));
427 assert_eq!(data2, dv(json!({ "matrix": [[1, 2], [3]] })));
428 }
429
430 #[test]
431 fn test_set_nested_value_array_expansion() {
432 let mut data = dv(json!({}));
433
434 set_nested_value(&mut data, "array.2", dv(json!("value")));
435 assert_eq!(data, dv(json!({ "array": [null, null, "value"] })));
436
437 let mut data2 = dv(json!({}));
438 set_nested_value(&mut data2, "deep.nested.0.field", dv(json!("test")));
439 assert_eq!(
440 data2,
441 dv(json!({ "deep": { "nested": [{ "field": "test" }] } }))
442 );
443 }
444
445 #[test]
446 fn test_get_nested_value_cloned() {
447 let data = dv(json!({
448 "user": {
449 "profile": {
450 "name": "Alice",
451 "settings": {"theme": "dark"}
452 }
453 }
454 }));
455
456 assert_eq!(
457 get_nested_value_cloned(&data, "user.profile.name"),
458 Some(dv(json!("Alice")))
459 );
460 assert_eq!(
461 get_nested_value_cloned(&data, "user.profile.settings"),
462 Some(dv(json!({ "theme": "dark" })))
463 );
464 assert_eq!(get_nested_value_cloned(&data, "user.missing"), None);
465 }
466
467 #[test]
468 fn test_get_nested_value_bounds_checking() {
469 let data = dv(json!({
470 "items": [1, 2, 3],
471 "nested": {
472 "array": [
473 {"id": 1},
474 {"id": 2}
475 ]
476 }
477 }));
478
479 assert_eq!(get_nested_value(&data, "items.0"), Some(&dv(json!(1))));
480 assert_eq!(get_nested_value(&data, "items.2"), Some(&dv(json!(3))));
481
482 assert_eq!(get_nested_value(&data, "items.10"), None);
483 assert_eq!(get_nested_value(&data, "items.999999"), None);
484
485 assert_eq!(get_nested_value(&data, "items.abc"), None);
486 assert_eq!(get_nested_value(&data, "items.-1"), None);
487 assert_eq!(get_nested_value(&data, "items.2.5"), None);
488
489 assert_eq!(
490 get_nested_value(&data, "nested.array.0.id"),
491 Some(&dv(json!(1)))
492 );
493 assert_eq!(get_nested_value(&data, "nested.array.5.id"), None);
494
495 assert_eq!(get_nested_value(&data, ""), Some(&data));
496 }
497
498 #[test]
499 fn test_set_nested_value_bounds_safety() {
500 let mut data = dv(json!({}));
501
502 set_nested_value(&mut data, "large.10", dv(json!("value")));
503 assert_eq!(data["large"].as_array().unwrap().len(), 11);
504 assert_eq!(data["large"][10], dv(json!("value")));
505 for i in 0..10usize {
506 assert_eq!(data["large"][i], dv(json!(null)));
507 }
508
509 let mut data2 = dv(json!({ "matrix": [] }));
510 set_nested_value(&mut data2, "matrix.2.1", dv(json!(5)));
511 assert_eq!(data2["matrix"][0], dv(json!(null)));
512 assert_eq!(data2["matrix"][1], dv(json!(null)));
513 assert_eq!(data2["matrix"][2][0], dv(json!(null)));
514 assert_eq!(data2["matrix"][2][1], dv(json!(5)));
515
516 let mut data3 = dv(json!({ "arr": [1, 2, 3] }));
517 set_nested_value(&mut data3, "arr.1", dv(json!("replaced")));
518 assert_eq!(data3["arr"], dv(json!([1, "replaced", 3])));
519 }
520
521 #[test]
522 fn test_hash_prefix_in_paths() {
523 let data = dv(json!({
524 "fields": {
525 "20": "numeric field name",
526 "#": "hash field",
527 "##": "double hash field",
528 "normal": "normal field"
529 }
530 }));
531
532 assert_eq!(
533 get_nested_value(&data, "fields.#20"),
534 Some(&dv(json!("numeric field name")))
535 );
536 assert_eq!(
537 get_nested_value(&data, "fields.##"),
538 Some(&dv(json!("hash field")))
539 );
540 assert_eq!(
541 get_nested_value(&data, "fields.###"),
542 Some(&dv(json!("double hash field")))
543 );
544 assert_eq!(
545 get_nested_value(&data, "fields.normal"),
546 Some(&dv(json!("normal field")))
547 );
548 assert_eq!(get_nested_value(&data, "fields.#999"), None);
549 }
550
551 #[test]
552 fn test_set_hash_prefix_in_paths() {
553 let mut data = dv(json!({}));
554
555 set_nested_value(&mut data, "fields.#20", dv(json!("value for 20")));
556 assert_eq!(data["fields"]["20"], dv(json!("value for 20")));
557
558 set_nested_value(&mut data, "fields.##", dv(json!("hash value")));
559 assert_eq!(data["fields"]["#"], dv(json!("hash value")));
560
561 set_nested_value(&mut data, "fields.###", dv(json!("double hash value")));
562 assert_eq!(data["fields"]["##"], dv(json!("double hash value")));
563
564 set_nested_value(&mut data, "fields.normal", dv(json!("normal value")));
565 assert_eq!(data["fields"]["normal"], dv(json!("normal value")));
566
567 assert_eq!(
568 data,
569 dv(json!({
570 "fields": {
571 "20": "value for 20",
572 "#": "hash value",
573 "##": "double hash value",
574 "normal": "normal value"
575 }
576 }))
577 );
578 }
579
580 #[test]
581 fn test_hash_prefix_with_arrays() {
582 let mut data = dv(json!({
583 "items": [
584 {"0": "field named zero", "id": 1},
585 {"1": "field named one", "id": 2}
586 ]
587 }));
588
589 assert_eq!(
590 get_nested_value(&data, "items.0.#0"),
591 Some(&dv(json!("field named zero")))
592 );
593 assert_eq!(
594 get_nested_value(&data, "items.1.#1"),
595 Some(&dv(json!("field named one")))
596 );
597
598 set_nested_value(&mut data, "items.0.#2", dv(json!("field named two")));
599 assert_eq!(data["items"][0]["2"], dv(json!("field named two")));
600
601 assert_eq!(get_nested_value(&data, "items.0.id"), Some(&dv(json!(1))));
602 assert_eq!(get_nested_value(&data, "items.1.id"), Some(&dv(json!(2))));
603 }
604
605 #[test]
606 fn test_hash_prefix_field_with_array_value() {
607 let data = dv(json!({
608 "data": {
609 "fields": {
610 "72": ["first", "second", "third"],
611 "100": ["alpha", "beta", "gamma"],
612 "normal": ["one", "two", "three"]
613 }
614 }
615 }));
616
617 assert_eq!(
618 get_nested_value(&data, "data.fields.#72.0"),
619 Some(&dv(json!("first")))
620 );
621 assert_eq!(
622 get_nested_value(&data, "data.fields.#72.1"),
623 Some(&dv(json!("second")))
624 );
625 assert_eq!(
626 get_nested_value(&data, "data.fields.#72.2"),
627 Some(&dv(json!("third")))
628 );
629
630 assert_eq!(
631 get_nested_value(&data, "data.fields.#100.0"),
632 Some(&dv(json!("alpha")))
633 );
634 assert_eq!(
635 get_nested_value(&data, "data.fields.#100.1"),
636 Some(&dv(json!("beta")))
637 );
638
639 assert_eq!(
640 get_nested_value(&data, "data.fields.normal.0"),
641 Some(&dv(json!("one")))
642 );
643
644 let mut data_mut = data.clone();
645 set_nested_value(&mut data_mut, "data.fields.#72.0", dv(json!("modified")));
646 assert_eq!(data_mut["data"]["fields"]["72"][0], dv(json!("modified")));
647
648 set_nested_value(&mut data_mut, "data.fields.#999.0", dv(json!("new value")));
649 assert_eq!(data_mut["data"]["fields"]["999"][0], dv(json!("new value")));
650
651 let complex_data = dv(json!({
652 "fields": {
653 "42": [
654 {"name": "item1", "value": 100},
655 {"name": "item2", "value": 200}
656 ]
657 }
658 }));
659
660 assert_eq!(
661 get_nested_value(&complex_data, "fields.#42.0.name"),
662 Some(&dv(json!("item1")))
663 );
664 assert_eq!(
665 get_nested_value(&complex_data, "fields.#42.1.value"),
666 Some(&dv(json!(200)))
667 );
668
669 let multi_hash_data = dv(json!({
670 "data": {
671 "#fields": {
672 "##": ["hash array"],
673 "10": ["numeric array"]
674 }
675 }
676 }));
677
678 assert_eq!(
679 get_nested_value(&multi_hash_data, "data.##fields.###.0"),
680 Some(&dv(json!("hash array")))
681 );
682 assert_eq!(
683 get_nested_value(&multi_hash_data, "data.##fields.#10.0"),
684 Some(&dv(json!("numeric array")))
685 );
686 }
687
688 fn as_json(v: &OwnedDataValue) -> serde_json::Value {
695 serde_json::Value::from(v)
696 }
697
698 #[test]
699 fn test_remove_nested_value_object() {
700 let mut data = dv(json!({"data": {"a": 1, "_b": 2}}));
701
702 assert_eq!(
703 remove_nested_value(&mut data, "data._b"),
704 Some(dv(json!(2)))
705 );
706 assert_eq!(as_json(&data), json!({"data": {"a": 1}}));
708
709 assert_eq!(remove_nested_value(&mut data, "data._b"), None);
711 assert_eq!(as_json(&data), json!({"data": {"a": 1}}));
712 }
713
714 #[test]
715 fn test_remove_nested_value_array_shifts_tail() {
716 let mut data = dv(json!({"items": [1, 2, 3]}));
717
718 assert_eq!(
719 remove_nested_value(&mut data, "items.1"),
720 Some(dv(json!(2)))
721 );
722 assert_eq!(as_json(&data), json!({"items": [1, 3]}));
724 }
725
726 #[test]
727 fn test_remove_nested_value_returns_subtree_intact() {
728 let mut data = dv(json!({"data": {"nested": {"x": [1, 2]}}}));
729
730 assert_eq!(
731 remove_nested_value(&mut data, "data.nested"),
732 Some(dv(json!({"x": [1, 2]})))
733 );
734 assert_eq!(as_json(&data), json!({"data": {}}));
735 }
736
737 #[test]
738 fn test_remove_nested_value_traverses_array_in_non_terminal_position() {
739 let mut data = dv(json!({"a": [{"k": 1}, {"k": 2}]}));
740
741 assert_eq!(remove_nested_value(&mut data, "a.1.k"), Some(dv(json!(2))));
742 assert_eq!(as_json(&data), json!({"a": [{"k": 1}, {}]}));
743 }
744
745 #[test]
746 fn test_remove_hash_prefix_in_paths() {
747 let mut data = dv(json!({"fields": {"20": "x", "#": "y", "##": "z"}}));
750
751 assert_eq!(
752 remove_nested_value(&mut data, "fields.#20"),
753 Some(dv(json!("x")))
754 );
755 assert_eq!(
756 remove_nested_value(&mut data, "fields.##"),
757 Some(dv(json!("y")))
758 );
759 assert_eq!(
760 remove_nested_value(&mut data, "fields.###"),
761 Some(dv(json!("z")))
762 );
763 assert_eq!(as_json(&data), json!({"fields": {}}));
764 }
765
766 #[test]
767 fn test_remove_nested_value_negative_cases_leave_tree_untouched() {
768 let original = json!({
771 "items": [1, 2, 3],
772 "a": [{"k": 1}],
773 "data": {"x": 1},
774 "b": 1
775 });
776
777 for path in [
778 "", "data.nope", "nope.x", "items.9", "a.5.k", "items.abc", "items.-1", "b.c", "b.c.d", ] {
788 let mut data = dv(original.clone());
789 assert_eq!(
790 remove_nested_value(&mut data, path),
791 None,
792 "path '{path}' should not resolve"
793 );
794 assert_eq!(
795 as_json(&data),
796 original,
797 "path '{path}' must leave the tree untouched"
798 );
799 }
800 }
801
802 #[test]
803 fn test_remove_nested_value_scalar_root() {
804 let mut scalar = dv(json!("scalar"));
805 assert_eq!(remove_nested_value(&mut scalar, "a"), None);
806 assert_eq!(as_json(&scalar), json!("scalar"));
807 }
808
809 #[test]
810 fn test_remove_nested_value_non_ascii_keys() {
811 let mut data = dv(json!({"データ": {"ключ": "значение"}}));
812
813 assert_eq!(
814 remove_nested_value(&mut data, "データ.ключ"),
815 Some(dv(json!("значение")))
816 );
817 assert_eq!(as_json(&data), json!({"データ": {}}));
818 }
819}