surrealdb_core/sql/value/
walk.rs1use crate::sql::idiom::Idiom;
2use crate::sql::part::Next;
3use crate::sql::part::Part;
4use crate::sql::value::Value;
5
6impl Value {
7 pub fn walk(&self, path: &[Part]) -> Vec<(Idiom, Self)> {
8 self._walk(path, Idiom::default())
9 }
10 fn _walk(&self, path: &[Part], prev: Idiom) -> Vec<(Idiom, Self)> {
11 match path.first() {
12 Some(p) => match self {
14 Value::Object(v) => match p {
16 Part::Field(f) => match v.get(f as &str) {
17 Some(v) => v._walk(path.next(), prev.push(p.clone())),
18 None => Value::None._walk(path.next(), prev.push(p.clone())),
19 },
20 Part::Index(i) => match v.get(&i.to_string()) {
21 Some(v) => v._walk(path.next(), prev.push(p.clone())),
22 None => Value::None._walk(path.next(), prev.push(p.clone())),
23 },
24 Part::All => v
25 .iter()
26 .flat_map(|(field, v)| {
27 v._walk(
28 path.next(),
29 prev.clone().push(Part::Field(field.to_owned().into())),
30 )
31 })
32 .collect::<Vec<_>>(),
33 _ => vec![],
34 },
35 Value::Array(v) => match p {
37 Part::First => match v.first() {
38 Some(v) => v._walk(path.next(), prev.push(p.clone())),
39 None => vec![],
40 },
41 Part::Last => match v.last() {
42 Some(v) => v._walk(path.next(), prev.push(p.clone())),
43 None => vec![],
44 },
45 Part::Index(i) => match v.get(i.to_usize()) {
46 Some(v) => v._walk(path.next(), prev.push(p.clone())),
47 None => vec![],
48 },
49 _ => v
50 .iter()
51 .enumerate()
52 .flat_map(|(i, v)| v._walk(path.next(), prev.clone().push(Part::from(i))))
53 .collect::<Vec<_>>(),
54 },
55 _ => match p {
57 Part::Field(_) => Value::None._walk(path.next(), prev.push(p.clone())),
58 Part::Index(_) => Value::None._walk(path.next(), prev.push(p.clone())),
59 _ => vec![],
60 },
61 },
62 None => vec![(prev, self.clone())],
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70
71 use super::*;
72 use crate::syn::Parse;
73
74 #[test]
75 fn walk_blank() {
76 let idi = Idiom::default();
77 let val = Value::parse("{ test: { other: null, something: 123 } }");
78 let res =
79 vec![(Idiom::default(), Value::parse("{ test: { other: null, something: 123 } }"))];
80 assert_eq!(res, val.walk(&idi));
81 }
82
83 #[test]
84 fn walk_basic() {
85 let idi = Idiom::parse("test.something");
86 let val = Value::parse("{ test: { other: null, something: 123 } }");
87 let res = vec![(Idiom::parse("test.something"), Value::from(123))];
88 assert_eq!(res, val.walk(&idi));
89 }
90
91 #[test]
92 fn walk_empty() {
93 let idi = Idiom::parse("test.missing");
94 let val = Value::parse("{ test: { other: null, something: 123 } }");
95 let res = vec![(Idiom::parse("test.missing"), Value::None)];
96 assert_eq!(res, val.walk(&idi));
97 }
98
99 #[test]
100 fn walk_empty_object() {
101 let idi = Idiom::parse("none.something.age");
102 let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
103 let res = vec![(Idiom::parse("none.something.age"), Value::None)];
104 assert_eq!(res, val.walk(&idi));
105 }
106
107 #[test]
108 fn walk_empty_array() {
109 let idi = Idiom::parse("none.something.*.age");
110 let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
111 let res: Vec<(Idiom, Value)> = vec![];
112 assert_eq!(res, val.walk(&idi));
113 }
114
115 #[test]
116 fn walk_empty_array_index() {
117 let idi = Idiom::parse("none.something[0].age");
118 let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
119 let res = vec![(Idiom::parse("none.something[0].age"), Value::None)];
120 assert_eq!(res, val.walk(&idi));
121 }
122
123 #[test]
124 fn walk_array() {
125 let idi = Idiom::parse("test.something");
126 let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
127 let res =
128 vec![(Idiom::parse("test.something"), Value::parse("[{ age: 34 }, { age: 36 }]"))];
129 assert_eq!(res, val.walk(&idi));
130 }
131
132 #[test]
133 fn walk_array_field() {
134 let idi = Idiom::parse("test.something[*].age");
135 let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
136 let res = vec![
137 (Idiom::parse("test.something[0].age"), Value::from(34)),
138 (Idiom::parse("test.something[1].age"), Value::from(36)),
139 ];
140 assert_eq!(res, val.walk(&idi));
141 }
142
143 #[test]
144 fn walk_array_field_embedded() {
145 let idi = Idiom::parse("test.something[*].tags");
146 let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }");
147 let res = vec![
148 (Idiom::parse("test.something[0].tags"), Value::parse("['code', 'databases']")),
149 (Idiom::parse("test.something[1].tags"), Value::parse("['design', 'operations']")),
150 ];
151 assert_eq!(res, val.walk(&idi));
152 }
153
154 #[test]
155 fn walk_array_field_embedded_index() {
156 let idi = Idiom::parse("test.something[*].tags[1]");
157 let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }");
158 let res = vec![
159 (Idiom::parse("test.something[0].tags[1]"), Value::from("databases")),
160 (Idiom::parse("test.something[1].tags[1]"), Value::from("operations")),
161 ];
162 assert_eq!(res, val.walk(&idi));
163 }
164
165 #[test]
166 fn walk_array_field_embedded_index_all() {
167 let idi = Idiom::parse("test.something[*].tags[*]");
168 let val = Value::parse("{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }");
169 let res = vec![
170 (Idiom::parse("test.something[0].tags[0]"), Value::from("code")),
171 (Idiom::parse("test.something[0].tags[1]"), Value::from("databases")),
172 (Idiom::parse("test.something[1].tags[0]"), Value::from("design")),
173 (Idiom::parse("test.something[1].tags[1]"), Value::from("operations")),
174 ];
175 assert_eq!(res, val.walk(&idi));
176 }
177}