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
71pub(crate) fn describe_kind(value: &OwnedDataValue) -> &'static str {
74 match value {
75 OwnedDataValue::Null => "null",
76 OwnedDataValue::Bool(_) => "a boolean",
77 OwnedDataValue::Number(_) => "a number",
78 OwnedDataValue::String(_) => "a string",
79 OwnedDataValue::Array(_) => "an array",
80 OwnedDataValue::Object(_) => "an object",
81 #[allow(unreachable_patterns)]
83 _ => "a non-array value",
84 }
85}
86
87pub(crate) fn get_nested_value_parts_mut<'b>(
90 data: &'b mut OwnedDataValue,
91 parts: &[Arc<str>],
92) -> Option<&'b mut OwnedDataValue> {
93 let mut current = data;
94 for part in parts {
95 current = match current {
96 OwnedDataValue::Object(pairs) => {
97 let key = strip_hash_prefix(part);
98 &mut pairs.iter_mut().find(|(k, _)| k == key)?.1
99 }
100 OwnedDataValue::Array(items) => items.get_mut(part.parse::<usize>().ok()?)?,
101 _ => return None,
102 };
103 }
104 Some(current)
105}
106
107fn get_nested_value_impl<'b, 'p>(
116 data: &'b OwnedDataValue,
117 parts: impl Iterator<Item = &'p str>,
118) -> Option<&'b OwnedDataValue> {
119 let mut current = data;
120 for part in parts {
121 match current {
122 OwnedDataValue::Object(pairs) => {
123 let key = strip_hash_prefix(part);
124 let slot = pairs.iter().find(|(k, _)| k == key)?;
125 current = &slot.1;
126 }
127 OwnedDataValue::Array(items) => {
128 let idx: usize = part.parse().ok()?;
129 current = items.get(idx)?;
130 }
131 _ => return None,
132 }
133 }
134 Some(current)
135}
136
137pub fn set_nested_value_parts(
143 data: &mut OwnedDataValue,
144 parts: &[Arc<str>],
145 value: OwnedDataValue,
146) {
147 if parts.is_empty() {
148 return;
149 }
150 set_nested_value_impl(data, parts, value);
151}
152
153fn set_nested_value_impl<P: AsRef<str>>(
163 data: &mut OwnedDataValue,
164 parts: &[P],
165 value: OwnedDataValue,
166) {
167 let last = parts.len() - 1;
168 let mut current = data;
169
170 for (i, part) in parts.iter().enumerate() {
171 let part = part.as_ref();
172 if i == last {
173 match current {
174 OwnedDataValue::Object(pairs) => {
175 let key = strip_hash_prefix(part);
176 if let Some(slot) = pairs.iter_mut().find(|(k, _)| k == key) {
177 slot.1 = value;
178 } else {
179 pairs.push((key.to_string(), value));
180 }
181 }
182 OwnedDataValue::Array(items) => {
183 if let Ok(idx) = part.parse::<usize>() {
184 while items.len() <= idx {
185 items.push(OwnedDataValue::Null);
186 }
187 items[idx] = value;
188 }
189 }
190 _ => {}
191 }
192 return;
193 }
194
195 let next_is_array = parts[i + 1].as_ref().parse::<usize>().is_ok();
199
200 match current {
201 OwnedDataValue::Object(pairs) => {
202 let key = strip_hash_prefix(part);
203 let idx = match pairs.iter().position(|(k, _)| k == key) {
204 Some(idx) => idx,
205 None => {
206 let child = if next_is_array {
207 OwnedDataValue::Array(Vec::new())
208 } else {
209 OwnedDataValue::Object(Vec::new())
210 };
211 pairs.push((key.to_string(), child));
212 pairs.len() - 1
213 }
214 };
215 current = &mut pairs[idx].1;
216 }
217 OwnedDataValue::Array(items) => {
218 let Ok(idx) = part.parse::<usize>() else {
219 return; };
221 while items.len() <= idx {
222 items.push(OwnedDataValue::Null);
223 }
224 if matches!(items[idx], OwnedDataValue::Null) {
225 items[idx] = if next_is_array {
226 OwnedDataValue::Array(Vec::new())
227 } else {
228 OwnedDataValue::Object(Vec::new())
229 };
230 }
231 current = &mut items[idx];
232 }
233 _ => return,
234 }
235 }
236}
237
238pub fn remove_nested_value(data: &mut OwnedDataValue, path: &str) -> Option<OwnedDataValue> {
276 if path.is_empty() {
277 return None;
278 }
279 let parts: Vec<&str> = path.split('.').collect();
280 remove_nested_value_parts(data, &parts)
281}
282
283pub(crate) fn remove_nested_value_parts<P: AsRef<str>>(
287 data: &mut OwnedDataValue,
288 parts: &[P],
289) -> Option<OwnedDataValue> {
290 let (last, parents) = parts.split_last()?;
291 let last = last.as_ref();
292
293 let mut current = data;
294 for part in parents {
295 let part = part.as_ref();
296 current = match current {
297 OwnedDataValue::Object(pairs) => {
298 let key = strip_hash_prefix(part);
299 let idx = pairs.iter().position(|(k, _)| k == key)?;
300 &mut pairs[idx].1
301 }
302 OwnedDataValue::Array(items) => {
303 let idx: usize = part.parse().ok()?;
304 items.get_mut(idx)?
305 }
306 _ => return None,
307 };
308 }
309
310 match current {
311 OwnedDataValue::Object(pairs) => {
312 let key = strip_hash_prefix(last);
313 let pos = pairs.iter().position(|(k, _)| k == key)?;
314 Some(pairs.remove(pos).1)
315 }
316 OwnedDataValue::Array(items) => {
317 let idx: usize = last.parse().ok()?;
318 if idx < items.len() {
319 Some(items.remove(idx))
320 } else {
321 None
322 }
323 }
324 _ => None,
325 }
326}
327
328#[inline]
331pub(crate) fn strip_hash_prefix(part: &str) -> &str {
332 part.strip_prefix('#').unwrap_or(part)
333}
334
335pub(crate) fn compute_data_path(target: &str) -> (Arc<str>, Arc<[Arc<str>]>) {
342 (
343 Arc::from(format!("data.{target}")),
344 compute_path_parts("data", target),
345 )
346}
347
348pub(crate) fn compute_path_parts(prefix: &str, target: &str) -> Arc<[Arc<str>]> {
355 std::iter::once(Arc::from(prefix))
356 .chain(target.split('.').map(Arc::from))
357 .collect()
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363 use serde_json::json;
364
365 fn dv(v: serde_json::Value) -> OwnedDataValue {
367 OwnedDataValue::from(&v)
368 }
369
370 #[test]
371 fn test_get_nested_value() {
372 let data = dv(json!({
373 "user": {
374 "name": "John",
375 "age": 30,
376 "addresses": [
377 {"city": "New York", "zip": "10001"},
378 {"city": "San Francisco", "zip": "94102"}
379 ],
380 "preferences": {
381 "theme": "dark",
382 "notifications": true
383 }
384 },
385 "items": [1, 2, 3]
386 }));
387
388 assert_eq!(
389 get_nested_value(&data, "user.name"),
390 Some(&dv(json!("John")))
391 );
392 assert_eq!(get_nested_value(&data, "user.age"), Some(&dv(json!(30))));
393
394 assert_eq!(
395 get_nested_value(&data, "user.preferences.theme"),
396 Some(&dv(json!("dark")))
397 );
398 assert_eq!(
399 get_nested_value(&data, "user.preferences.notifications"),
400 Some(&dv(json!(true)))
401 );
402
403 assert_eq!(get_nested_value(&data, "items.0"), Some(&dv(json!(1))));
404 assert_eq!(get_nested_value(&data, "items.2"), Some(&dv(json!(3))));
405
406 assert_eq!(
407 get_nested_value(&data, "user.addresses.0.city"),
408 Some(&dv(json!("New York")))
409 );
410 assert_eq!(
411 get_nested_value(&data, "user.addresses.1.zip"),
412 Some(&dv(json!("94102")))
413 );
414
415 assert_eq!(get_nested_value(&data, "user.missing"), None);
416 assert_eq!(get_nested_value(&data, "items.10"), None);
417 assert_eq!(get_nested_value(&data, "user.addresses.2.city"), None);
418 assert_eq!(get_nested_value(&data, "nonexistent.path"), None);
419 }
420
421 #[test]
422 fn test_set_nested_value() {
423 let mut data = dv(json!({}));
424
425 set_nested_value(&mut data, "name", dv(json!("Alice")));
426 assert_eq!(data, dv(json!({"name": "Alice"})));
427
428 set_nested_value(&mut data, "user.email", dv(json!("alice@example.com")));
429 assert_eq!(
430 data,
431 dv(json!({
432 "name": "Alice",
433 "user": {"email": "alice@example.com"}
434 }))
435 );
436
437 set_nested_value(&mut data, "name", dv(json!("Bob")));
438 assert_eq!(
439 data,
440 dv(json!({
441 "name": "Bob",
442 "user": {"email": "alice@example.com"}
443 }))
444 );
445
446 set_nested_value(&mut data, "settings.theme.mode", dv(json!("dark")));
447 assert_eq!(data["settings"]["theme"]["mode"], dv(json!("dark")));
448
449 set_nested_value(&mut data, "user.age", dv(json!(25)));
450 assert_eq!(data["user"]["age"], dv(json!(25)));
451 assert_eq!(data["user"]["email"], dv(json!("alice@example.com")));
452 }
453
454 #[test]
455 fn test_set_nested_value_with_arrays() {
456 let mut data = dv(json!({ "items": [1, 2, 3] }));
457
458 set_nested_value(&mut data, "items.0", dv(json!(10)));
459 assert_eq!(data["items"], dv(json!([10, 2, 3])));
460
461 set_nested_value(&mut data, "items.5", dv(json!(50)));
462 assert_eq!(data["items"], dv(json!([10, 2, 3, null, null, 50])));
463
464 let mut data2 = dv(json!({}));
465 set_nested_value(&mut data2, "matrix.0.0", dv(json!(1)));
466 set_nested_value(&mut data2, "matrix.0.1", dv(json!(2)));
467 set_nested_value(&mut data2, "matrix.1.0", dv(json!(3)));
468 assert_eq!(data2, dv(json!({ "matrix": [[1, 2], [3]] })));
469 }
470
471 #[test]
472 fn test_set_nested_value_array_expansion() {
473 let mut data = dv(json!({}));
474
475 set_nested_value(&mut data, "array.2", dv(json!("value")));
476 assert_eq!(data, dv(json!({ "array": [null, null, "value"] })));
477
478 let mut data2 = dv(json!({}));
479 set_nested_value(&mut data2, "deep.nested.0.field", dv(json!("test")));
480 assert_eq!(
481 data2,
482 dv(json!({ "deep": { "nested": [{ "field": "test" }] } }))
483 );
484 }
485
486 #[test]
487 fn test_get_nested_value_cloned() {
488 let data = dv(json!({
489 "user": {
490 "profile": {
491 "name": "Alice",
492 "settings": {"theme": "dark"}
493 }
494 }
495 }));
496
497 assert_eq!(
498 get_nested_value_cloned(&data, "user.profile.name"),
499 Some(dv(json!("Alice")))
500 );
501 assert_eq!(
502 get_nested_value_cloned(&data, "user.profile.settings"),
503 Some(dv(json!({ "theme": "dark" })))
504 );
505 assert_eq!(get_nested_value_cloned(&data, "user.missing"), None);
506 }
507
508 #[test]
509 fn test_get_nested_value_bounds_checking() {
510 let data = dv(json!({
511 "items": [1, 2, 3],
512 "nested": {
513 "array": [
514 {"id": 1},
515 {"id": 2}
516 ]
517 }
518 }));
519
520 assert_eq!(get_nested_value(&data, "items.0"), Some(&dv(json!(1))));
521 assert_eq!(get_nested_value(&data, "items.2"), Some(&dv(json!(3))));
522
523 assert_eq!(get_nested_value(&data, "items.10"), None);
524 assert_eq!(get_nested_value(&data, "items.999999"), None);
525
526 assert_eq!(get_nested_value(&data, "items.abc"), None);
527 assert_eq!(get_nested_value(&data, "items.-1"), None);
528 assert_eq!(get_nested_value(&data, "items.2.5"), None);
529
530 assert_eq!(
531 get_nested_value(&data, "nested.array.0.id"),
532 Some(&dv(json!(1)))
533 );
534 assert_eq!(get_nested_value(&data, "nested.array.5.id"), None);
535
536 assert_eq!(get_nested_value(&data, ""), Some(&data));
537 }
538
539 #[test]
540 fn test_set_nested_value_bounds_safety() {
541 let mut data = dv(json!({}));
542
543 set_nested_value(&mut data, "large.10", dv(json!("value")));
544 assert_eq!(data["large"].as_array().unwrap().len(), 11);
545 assert_eq!(data["large"][10], dv(json!("value")));
546 for i in 0..10usize {
547 assert_eq!(data["large"][i], dv(json!(null)));
548 }
549
550 let mut data2 = dv(json!({ "matrix": [] }));
551 set_nested_value(&mut data2, "matrix.2.1", dv(json!(5)));
552 assert_eq!(data2["matrix"][0], dv(json!(null)));
553 assert_eq!(data2["matrix"][1], dv(json!(null)));
554 assert_eq!(data2["matrix"][2][0], dv(json!(null)));
555 assert_eq!(data2["matrix"][2][1], dv(json!(5)));
556
557 let mut data3 = dv(json!({ "arr": [1, 2, 3] }));
558 set_nested_value(&mut data3, "arr.1", dv(json!("replaced")));
559 assert_eq!(data3["arr"], dv(json!([1, "replaced", 3])));
560 }
561
562 #[test]
563 fn test_hash_prefix_in_paths() {
564 let data = dv(json!({
565 "fields": {
566 "20": "numeric field name",
567 "#": "hash field",
568 "##": "double hash field",
569 "normal": "normal field"
570 }
571 }));
572
573 assert_eq!(
574 get_nested_value(&data, "fields.#20"),
575 Some(&dv(json!("numeric field name")))
576 );
577 assert_eq!(
578 get_nested_value(&data, "fields.##"),
579 Some(&dv(json!("hash field")))
580 );
581 assert_eq!(
582 get_nested_value(&data, "fields.###"),
583 Some(&dv(json!("double hash field")))
584 );
585 assert_eq!(
586 get_nested_value(&data, "fields.normal"),
587 Some(&dv(json!("normal field")))
588 );
589 assert_eq!(get_nested_value(&data, "fields.#999"), None);
590 }
591
592 #[test]
593 fn test_set_hash_prefix_in_paths() {
594 let mut data = dv(json!({}));
595
596 set_nested_value(&mut data, "fields.#20", dv(json!("value for 20")));
597 assert_eq!(data["fields"]["20"], dv(json!("value for 20")));
598
599 set_nested_value(&mut data, "fields.##", dv(json!("hash value")));
600 assert_eq!(data["fields"]["#"], dv(json!("hash value")));
601
602 set_nested_value(&mut data, "fields.###", dv(json!("double hash value")));
603 assert_eq!(data["fields"]["##"], dv(json!("double hash value")));
604
605 set_nested_value(&mut data, "fields.normal", dv(json!("normal value")));
606 assert_eq!(data["fields"]["normal"], dv(json!("normal value")));
607
608 assert_eq!(
609 data,
610 dv(json!({
611 "fields": {
612 "20": "value for 20",
613 "#": "hash value",
614 "##": "double hash value",
615 "normal": "normal value"
616 }
617 }))
618 );
619 }
620
621 #[test]
622 fn test_hash_prefix_with_arrays() {
623 let mut data = dv(json!({
624 "items": [
625 {"0": "field named zero", "id": 1},
626 {"1": "field named one", "id": 2}
627 ]
628 }));
629
630 assert_eq!(
631 get_nested_value(&data, "items.0.#0"),
632 Some(&dv(json!("field named zero")))
633 );
634 assert_eq!(
635 get_nested_value(&data, "items.1.#1"),
636 Some(&dv(json!("field named one")))
637 );
638
639 set_nested_value(&mut data, "items.0.#2", dv(json!("field named two")));
640 assert_eq!(data["items"][0]["2"], dv(json!("field named two")));
641
642 assert_eq!(get_nested_value(&data, "items.0.id"), Some(&dv(json!(1))));
643 assert_eq!(get_nested_value(&data, "items.1.id"), Some(&dv(json!(2))));
644 }
645
646 #[test]
647 fn test_hash_prefix_field_with_array_value() {
648 let data = dv(json!({
649 "data": {
650 "fields": {
651 "72": ["first", "second", "third"],
652 "100": ["alpha", "beta", "gamma"],
653 "normal": ["one", "two", "three"]
654 }
655 }
656 }));
657
658 assert_eq!(
659 get_nested_value(&data, "data.fields.#72.0"),
660 Some(&dv(json!("first")))
661 );
662 assert_eq!(
663 get_nested_value(&data, "data.fields.#72.1"),
664 Some(&dv(json!("second")))
665 );
666 assert_eq!(
667 get_nested_value(&data, "data.fields.#72.2"),
668 Some(&dv(json!("third")))
669 );
670
671 assert_eq!(
672 get_nested_value(&data, "data.fields.#100.0"),
673 Some(&dv(json!("alpha")))
674 );
675 assert_eq!(
676 get_nested_value(&data, "data.fields.#100.1"),
677 Some(&dv(json!("beta")))
678 );
679
680 assert_eq!(
681 get_nested_value(&data, "data.fields.normal.0"),
682 Some(&dv(json!("one")))
683 );
684
685 let mut data_mut = data.clone();
686 set_nested_value(&mut data_mut, "data.fields.#72.0", dv(json!("modified")));
687 assert_eq!(data_mut["data"]["fields"]["72"][0], dv(json!("modified")));
688
689 set_nested_value(&mut data_mut, "data.fields.#999.0", dv(json!("new value")));
690 assert_eq!(data_mut["data"]["fields"]["999"][0], dv(json!("new value")));
691
692 let complex_data = dv(json!({
693 "fields": {
694 "42": [
695 {"name": "item1", "value": 100},
696 {"name": "item2", "value": 200}
697 ]
698 }
699 }));
700
701 assert_eq!(
702 get_nested_value(&complex_data, "fields.#42.0.name"),
703 Some(&dv(json!("item1")))
704 );
705 assert_eq!(
706 get_nested_value(&complex_data, "fields.#42.1.value"),
707 Some(&dv(json!(200)))
708 );
709
710 let multi_hash_data = dv(json!({
711 "data": {
712 "#fields": {
713 "##": ["hash array"],
714 "10": ["numeric array"]
715 }
716 }
717 }));
718
719 assert_eq!(
720 get_nested_value(&multi_hash_data, "data.##fields.###.0"),
721 Some(&dv(json!("hash array")))
722 );
723 assert_eq!(
724 get_nested_value(&multi_hash_data, "data.##fields.#10.0"),
725 Some(&dv(json!("numeric array")))
726 );
727 }
728
729 fn as_json(v: &OwnedDataValue) -> serde_json::Value {
736 serde_json::Value::from(v)
737 }
738
739 #[test]
740 fn test_remove_nested_value_object() {
741 let mut data = dv(json!({"data": {"a": 1, "_b": 2}}));
742
743 assert_eq!(
744 remove_nested_value(&mut data, "data._b"),
745 Some(dv(json!(2)))
746 );
747 assert_eq!(as_json(&data), json!({"data": {"a": 1}}));
749
750 assert_eq!(remove_nested_value(&mut data, "data._b"), None);
752 assert_eq!(as_json(&data), json!({"data": {"a": 1}}));
753 }
754
755 #[test]
756 fn test_remove_nested_value_array_shifts_tail() {
757 let mut data = dv(json!({"items": [1, 2, 3]}));
758
759 assert_eq!(
760 remove_nested_value(&mut data, "items.1"),
761 Some(dv(json!(2)))
762 );
763 assert_eq!(as_json(&data), json!({"items": [1, 3]}));
765 }
766
767 #[test]
768 fn test_remove_nested_value_returns_subtree_intact() {
769 let mut data = dv(json!({"data": {"nested": {"x": [1, 2]}}}));
770
771 assert_eq!(
772 remove_nested_value(&mut data, "data.nested"),
773 Some(dv(json!({"x": [1, 2]})))
774 );
775 assert_eq!(as_json(&data), json!({"data": {}}));
776 }
777
778 #[test]
779 fn test_remove_nested_value_traverses_array_in_non_terminal_position() {
780 let mut data = dv(json!({"a": [{"k": 1}, {"k": 2}]}));
781
782 assert_eq!(remove_nested_value(&mut data, "a.1.k"), Some(dv(json!(2))));
783 assert_eq!(as_json(&data), json!({"a": [{"k": 1}, {}]}));
784 }
785
786 #[test]
787 fn test_remove_hash_prefix_in_paths() {
788 let mut data = dv(json!({"fields": {"20": "x", "#": "y", "##": "z"}}));
791
792 assert_eq!(
793 remove_nested_value(&mut data, "fields.#20"),
794 Some(dv(json!("x")))
795 );
796 assert_eq!(
797 remove_nested_value(&mut data, "fields.##"),
798 Some(dv(json!("y")))
799 );
800 assert_eq!(
801 remove_nested_value(&mut data, "fields.###"),
802 Some(dv(json!("z")))
803 );
804 assert_eq!(as_json(&data), json!({"fields": {}}));
805 }
806
807 #[test]
808 fn test_remove_nested_value_negative_cases_leave_tree_untouched() {
809 let original = json!({
812 "items": [1, 2, 3],
813 "a": [{"k": 1}],
814 "data": {"x": 1},
815 "b": 1
816 });
817
818 for path in [
819 "", "data.nope", "nope.x", "items.9", "a.5.k", "items.abc", "items.-1", "b.c", "b.c.d", ] {
829 let mut data = dv(original.clone());
830 assert_eq!(
831 remove_nested_value(&mut data, path),
832 None,
833 "path '{path}' should not resolve"
834 );
835 assert_eq!(
836 as_json(&data),
837 original,
838 "path '{path}' must leave the tree untouched"
839 );
840 }
841 }
842
843 #[test]
844 fn test_remove_nested_value_scalar_root() {
845 let mut scalar = dv(json!("scalar"));
846 assert_eq!(remove_nested_value(&mut scalar, "a"), None);
847 assert_eq!(as_json(&scalar), json!("scalar"));
848 }
849
850 #[test]
851 fn test_remove_nested_value_non_ascii_keys() {
852 let mut data = dv(json!({"データ": {"ключ": "значение"}}));
853
854 assert_eq!(
855 remove_nested_value(&mut data, "データ.ключ"),
856 Some(dv(json!("значение")))
857 );
858 assert_eq!(as_json(&data), json!({"データ": {}}));
859 }
860}