surrealdb_sql/value/
pick.rs

1use crate::part::Next;
2use crate::part::Part;
3use crate::value::Value;
4
5impl Value {
6	/// Synchronous method for getting a field from a `Value`
7	pub fn pick(&self, path: &[Part]) -> Self {
8		match path.first() {
9			// Get the current value at path
10			Some(p) => match self {
11				// Current value at path is an object
12				Value::Object(v) => match p {
13					Part::Field(f) => match v.get(f as &str) {
14						Some(v) => v.pick(path.next()),
15						None => Value::None,
16					},
17					Part::Index(i) => match v.get(&i.to_string()) {
18						Some(v) => v.pick(path.next()),
19						None => Value::None,
20					},
21					Part::All => self.pick(path.next()),
22					_ => Value::None,
23				},
24				// Current value at path is an array
25				Value::Array(v) => match p {
26					Part::All => v.iter().map(|v| v.pick(path.next())).collect::<Vec<_>>().into(),
27					Part::First => match v.first() {
28						Some(v) => v.pick(path.next()),
29						None => Value::None,
30					},
31					Part::Last => match v.last() {
32						Some(v) => v.pick(path.next()),
33						None => Value::None,
34					},
35					Part::Index(i) => match v.get(i.to_usize()) {
36						Some(v) => v.pick(path.next()),
37						None => Value::None,
38					},
39					_ => v.iter().map(|v| v.pick(path)).collect::<Vec<_>>().into(),
40				},
41				// Ignore everything else
42				_ => Value::None,
43			},
44			// No more parts so get the value
45			None => self.clone(),
46		}
47	}
48}
49
50#[cfg(test)]
51mod tests {
52
53	use super::*;
54	use crate::id::Id;
55	use crate::idiom::Idiom;
56	use crate::syn::test::Parse;
57	use crate::thing::Thing;
58
59	#[test]
60	fn pick_none() {
61		let idi = Idiom::default();
62		let val = Value::parse("{ test: { other: null, something: 123 } }");
63		let res = val.pick(&idi);
64		assert_eq!(res, val);
65	}
66
67	#[test]
68	fn pick_basic() {
69		let idi = Idiom::parse("test.something");
70		let val = Value::parse("{ test: { other: null, something: 123 } }");
71		let res = val.pick(&idi);
72		assert_eq!(res, Value::from(123));
73	}
74
75	#[test]
76	fn pick_thing() {
77		let idi = Idiom::parse("test.other");
78		let val = Value::parse("{ test: { other: test:tobie, something: 123 } }");
79		let res = val.pick(&idi);
80		assert_eq!(
81			res,
82			Value::from(Thing {
83				tb: String::from("test"),
84				id: Id::from("tobie")
85			})
86		);
87	}
88
89	#[test]
90	fn pick_array() {
91		let idi = Idiom::parse("test.something[1]");
92		let val = Value::parse("{ test: { something: [123, 456, 789] } }");
93		let res = val.pick(&idi);
94		assert_eq!(res, Value::from(456));
95	}
96
97	#[test]
98	fn pick_array_thing() {
99		let idi = Idiom::parse("test.something[1]");
100		let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }");
101		let res = val.pick(&idi);
102		assert_eq!(
103			res,
104			Value::from(Thing {
105				tb: String::from("test"),
106				id: Id::from("jaime")
107			})
108		);
109	}
110
111	#[test]
112	fn pick_array_field() {
113		let idi = Idiom::parse("test.something[1].age");
114		let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
115		let res = val.pick(&idi);
116		assert_eq!(res, Value::from(36));
117	}
118
119	#[test]
120	fn pick_array_fields() {
121		let idi = Idiom::parse("test.something[*].age");
122		let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
123		let res = val.pick(&idi);
124		assert_eq!(res, Value::from(vec![34, 36]));
125	}
126
127	#[test]
128	fn pick_array_fields_flat() {
129		let idi = Idiom::parse("test.something.age");
130		let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
131		let res = val.pick(&idi);
132		assert_eq!(res, Value::from(vec![34, 36]));
133	}
134}