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