surrealdb_expr/val/value/
each.rs1use crate::expr::idiom::Idiom;
2use crate::expr::part::Part;
3use crate::val::Value;
4
5impl Value {
6 pub fn each(&self, path: &[Part]) -> Vec<Idiom> {
13 let mut accum = Vec::new();
14 let mut build = Vec::new();
15 self._each(path, &mut accum, &mut build);
16 build
17 }
18
19 fn _each(&self, path: &[Part], accum: &mut Vec<Part>, build: &mut Vec<Idiom>) {
20 let Some((first, rest)) = path.split_first() else {
21 build.push(Idiom(accum.clone()));
22 return;
23 };
24
25 match self {
27 Value::Object(v) => match first {
29 Part::Field(f) => {
30 if let Some(v) = v.get(f) {
31 accum.push(Part::Field(f.clone()));
32 v._each(rest, accum, build);
33 accum.pop();
34 }
35 }
36 Part::All => {
37 for (k, v) in v.iter() {
38 accum.push(Part::Field(k.clone()));
39 v._each(rest, accum, build);
40 accum.pop();
41 }
42 }
43 _ => {}
44 },
45 Value::Array(v) => match first {
47 Part::All => {
48 for (idx, v) in v.iter().enumerate() {
49 accum.push(Part::index_int(idx as i64));
50 v._each(rest, accum, build);
51 accum.pop();
52 }
53 }
54 Part::First => {
55 if !v.is_empty() {
56 accum.push(Part::index_int(0));
57 v[0]._each(rest, accum, build);
58 accum.pop();
59 }
60 }
61 Part::Last => {
62 let len = v.len();
63 if len > 0 {
64 accum.push(Part::index_int(len as i64 - 1));
65 v[len - 1]._each(rest, accum, build);
66 accum.pop();
67 }
68 }
69 x => {
70 if let Some(idx) = x.as_old_index() {
71 if let Some(v) = v.get(idx) {
72 accum.push(x.clone());
73 v._each(rest, accum, build);
74 accum.pop();
75 }
76 } else {
77 for (idx, v) in v.iter().enumerate() {
87 accum.push(Part::index_int(idx as i64));
88 v._each(path, accum, build);
89 accum.pop();
90 }
91 }
92 }
93 },
94 Value::Set(v) => match first {
96 Part::All => {
97 for (idx, v) in v.iter().enumerate() {
98 accum.push(Part::index_int(idx as i64));
99 v._each(rest, accum, build);
100 accum.pop();
101 }
102 }
103 Part::First => {
104 if let Some(v) = v.first() {
105 accum.push(Part::First);
106 v._each(rest, accum, build);
107 accum.pop();
108 }
109 }
110 Part::Last => {
111 if let Some(v) = v.last() {
112 accum.push(Part::Last);
113 v._each(rest, accum, build);
114 accum.pop();
115 }
116 }
117 x => {
118 if let Some(idx) = x.as_old_index() {
119 if let Some(v) = v.nth(idx) {
120 accum.push(x.clone());
121 v._each(rest, accum, build);
122 accum.pop();
123 }
124 } else {
125 for (idx, v) in v.iter().enumerate() {
128 accum.push(Part::index_int(idx as i64));
129 v._each(path, accum, build);
130 accum.pop();
131 }
132 }
133 }
134 },
135 _ => {}
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143
144 use super::*;
145 use crate::syn;
146
147 macro_rules! parse_val {
148 ($input:expr) => {
149 crate::val::convert_public_value_to_internal(syn::value($input).unwrap())
150 };
151 }
152
153 #[test]
154 fn each_none() {
155 let idi: Idiom = Idiom::default();
156 let val = parse_val!("{ test: { other: null, something: 123 } }");
157 let res: Vec<Idiom> = vec![Idiom::default()];
158 assert_eq!(res, val.each(&idi));
159 assert_eq!(val.pick(&res[0]), parse_val!("{ test: { other: null, something: 123 } }"));
160 }
161
162 #[test]
163 fn each_basic() {
164 let idi: Idiom = syn::idiom("test.something").unwrap().into();
165 let val = parse_val!("{ test: { other: null, something: 123 } }");
166 let res: Vec<Idiom> = vec![syn::idiom("test.something").unwrap().into()];
167 assert_eq!(res, val.each(&idi));
168 assert_eq!(val.pick(&res[0]), Value::from(123));
169 }
170
171 #[test]
172 fn each_array() {
173 let idi: Idiom = syn::idiom("test.something").unwrap().into();
174 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
175 let res: Vec<Idiom> = vec![syn::idiom("test.something").unwrap().into()];
176 assert_eq!(res, val.each(&idi));
177 assert_eq!(val.pick(&res[0]), parse_val!("[{ age: 34 }, { age: 36 }]"));
178 }
179
180 #[test]
181 fn each_array_implicit_field() {
182 let idi: Idiom = syn::idiom("test.something.age").unwrap().into();
187 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
188 let res: Vec<Idiom> = vec![
189 syn::idiom("test.something[0].age").unwrap().into(),
190 syn::idiom("test.something[1].age").unwrap().into(),
191 ];
192 assert_eq!(res, val.each(&idi));
193 assert_eq!(val.pick(&res[0]), Value::from(34));
194 assert_eq!(val.pick(&res[1]), Value::from(36));
195 }
196
197 #[test]
198 fn each_array_implicit_field_absent() {
199 let idi: Idiom = syn::idiom("test.something.missing").unwrap().into();
203 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
204 assert_eq!(Vec::<Idiom>::new(), val.each(&idi));
205 }
206
207 #[test]
208 fn each_array_implicit_field_partial() {
209 let idi: Idiom = syn::idiom("test.something.age").unwrap().into();
211 let val = parse_val!("{ test: { something: [{ age: 34 }, { name: 'tobie' }] } }");
212 let res: Vec<Idiom> = vec![syn::idiom("test.something[0].age").unwrap().into()];
213 assert_eq!(res, val.each(&idi));
214 assert_eq!(val.pick(&res[0]), Value::from(34));
215 }
216
217 #[test]
218 fn each_array_field() {
219 let idi: Idiom = syn::idiom("test.something[*].age").unwrap().into();
220 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
221 let res: Vec<Idiom> = vec![
222 syn::idiom("test.something[0].age").unwrap().into(),
223 syn::idiom("test.something[1].age").unwrap().into(),
224 ];
225 assert_eq!(res, val.each(&idi));
226 assert_eq!(val.pick(&res[0]), Value::from(34));
227 assert_eq!(val.pick(&res[1]), Value::from(36));
228 }
229
230 #[test]
231 fn each_array_field_embedded() {
232 let idi: Idiom = syn::idiom("test.something[*].tags").unwrap().into();
233 let val = parse_val!(
234 "{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"
235 );
236 let res: Vec<Idiom> = vec![
237 syn::idiom("test.something[0].tags").unwrap().into(),
238 syn::idiom("test.something[1].tags").unwrap().into(),
239 ];
240 assert_eq!(res, val.each(&idi));
241 assert_eq!(val.pick(&res[0]), parse_val!("['code', 'databases']"));
242 assert_eq!(val.pick(&res[1]), parse_val!("['design', 'operations']"));
243 }
244
245 #[test]
246 fn each_array_field_embedded_index() {
247 let idi: Idiom = syn::idiom("test.something[*].tags[1]").unwrap().into();
248 let val = parse_val!(
249 "{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"
250 );
251 let res: Vec<Idiom> = vec![
252 syn::idiom("test.something[0].tags[1]").unwrap().into(),
253 syn::idiom("test.something[1].tags[1]").unwrap().into(),
254 ];
255 assert_eq!(res, val.each(&idi));
256 assert_eq!(val.pick(&res[0]), Value::from("databases"));
257 assert_eq!(val.pick(&res[1]), Value::from("operations"));
258 }
259
260 #[test]
261 fn each_array_field_embedded_index_all() {
262 let idi: Idiom = syn::idiom("test.something[*].tags[*]").unwrap().into();
263 let val = parse_val!(
264 "{ test: { something: [{ age: 34, tags: ['code', 'databases'] }, { age: 36, tags: ['design', 'operations'] }] } }"
265 );
266 let res: Vec<Idiom> = vec![
267 syn::idiom("test.something[0].tags[0]").unwrap().into(),
268 syn::idiom("test.something[0].tags[1]").unwrap().into(),
269 syn::idiom("test.something[1].tags[0]").unwrap().into(),
270 syn::idiom("test.something[1].tags[1]").unwrap().into(),
271 ];
272 assert_eq!(res, val.each(&idi));
273 assert_eq!(val.pick(&res[0]), Value::from("code"));
274 assert_eq!(val.pick(&res[1]), Value::from("databases"));
275 assert_eq!(val.pick(&res[2]), Value::from("design"));
276 assert_eq!(val.pick(&res[3]), Value::from("operations"));
277 }
278
279 #[test]
280 fn each_wildcards() {
281 let val = parse_val!(
282 "{ test: { a: { color: 'red' }, b: { color: 'blue' }, c: { color: 'green' } } }"
283 );
284
285 let res: Vec<Idiom> = vec![
286 syn::idiom("test.a.color").unwrap().into(),
287 syn::idiom("test.b.color").unwrap().into(),
288 syn::idiom("test.c.color").unwrap().into(),
289 ];
290
291 assert_eq!(res, val.each(&Idiom::from(syn::idiom("test.*.color").unwrap())));
292 }
293
294 #[test]
299 fn each_array_last() {
300 let idi: Idiom = syn::idiom("test.something[$]").unwrap().into();
301 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }, { age: 42 }] } }");
302 let res: Vec<Idiom> = vec![syn::idiom("test.something[2]").unwrap().into()];
303 assert_eq!(res, val.each(&idi));
304 assert_eq!(val.pick(&res[0]), parse_val!("{ age: 42 }"));
305 }
306
307 #[test]
309 fn each_array_last_empty() {
310 let idi: Idiom = syn::idiom("test.something[$]").unwrap().into();
311 let val = parse_val!("{ test: { something: [] } }");
312 assert_eq!(val.each(&idi), Vec::<Idiom>::new());
313 }
314
315 #[test]
316 fn each_set_last() {
317 let idi: Idiom = syn::idiom("tags[$]").unwrap().into();
318 let val = parse_val!("{ tags: {1, 3, 5} }");
319 let res: Vec<Idiom> = vec![syn::idiom("tags[$]").unwrap().into()];
320 assert_eq!(res, val.each(&idi));
321 assert_eq!(val.pick(&res[0]), Value::from(5));
322 }
323}