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