surrealdb_expr/val/value/
pick.rs1use crate::expr::part::{Next, Part};
2use crate::val::Value;
3
4impl Value {
5 pub fn pick(&self, path: &[Part]) -> Self {
7 match path.first() {
8 Some(p) => match self {
10 Value::Object(v) => match p {
12 Part::Field(f) => match v.get(f as &str) {
13 Some(v) => v.pick(path.next()),
14 None => Value::None,
15 },
16 Part::All => v.values().map(|v| v.pick(path.next())).collect::<Vec<_>>().into(),
17 x => {
18 if let Some(idx) = x.as_old_index() {
19 match v.get(&idx.to_string()) {
20 Some(v) => v.pick(path.next()),
21 None => Value::None,
22 }
23 } else {
24 Value::None
25 }
26 }
27 },
28 Value::Array(v) => match p {
30 Part::All => v.iter().map(|v| v.pick(path.next())).collect::<Vec<_>>().into(),
31 Part::First => match v.first() {
32 Some(v) => v.pick(path.next()),
33 None => Value::None,
34 },
35 Part::Last => match v.last() {
36 Some(v) => v.pick(path.next()),
37 None => Value::None,
38 },
39 x => {
40 if let Some(idx) = x.as_old_index() {
41 match v.get(idx) {
42 Some(v) => v.pick(path.next()),
43 None => Value::None,
44 }
45 } else {
46 v.iter().map(|v| v.pick(path)).collect::<Vec<_>>().into()
47 }
48 }
49 },
50 Value::Set(v) => match p {
52 Part::All => Value::Set(v.iter().map(|v| v.pick(path.next())).collect()),
53 Part::First => match v.first() {
54 Some(v) => v.pick(path.next()),
55 None => Value::None,
56 },
57 Part::Last => match v.last() {
58 Some(v) => v.pick(path.next()),
59 None => Value::None,
60 },
61 x => {
62 if let Some(idx) = x.as_old_index() {
63 match v.nth(idx) {
64 Some(v) => v.pick(path.next()),
65 None => Value::None,
66 }
67 } else {
68 Value::Set(v.iter().map(|v| v.pick(path)).collect())
69 }
70 }
71 },
72 _ => Value::None,
74 },
75 None => self.clone(),
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use surrealdb_strand::Strand;
84
85 use super::*;
86 use crate::expr::idiom::Idiom;
87 use crate::sql::idiom::Idiom as SqlIdiom;
88 use crate::syn;
89 use crate::val::{RecordId, RecordIdKey};
90
91 macro_rules! parse_val {
92 ($input:expr) => {
93 crate::val::convert_public_value_to_internal(syn::value($input).unwrap())
94 };
95 }
96
97 #[test]
98 fn pick_none() {
99 let idi: Idiom = SqlIdiom::default().into();
100 let val = parse_val!("{ test: { other: null, something: 123 } }");
101 let res = val.pick(&idi);
102 assert_eq!(res, val);
103 }
104
105 #[test]
106 fn pick_basic() {
107 let idi: Idiom = syn::idiom("test.something").unwrap().into();
108 let val = parse_val!("{ test: { other: null, something: 123 } }");
109 let res = val.pick(&idi);
110 assert_eq!(res, Value::from(123));
111 }
112
113 #[test]
114 fn pick_thing() {
115 let idi: Idiom = syn::idiom("test.other").unwrap().into();
116 let val = parse_val!("{ test: { other: test:tobie, something: 123 } }");
117 let res = val.pick(&idi);
118 assert_eq!(
119 res,
120 Value::from(RecordId {
121 table: "test".into(),
122 key: RecordIdKey::String(Strand::new_static("tobie"))
123 })
124 );
125 }
126
127 #[test]
128 fn pick_array() {
129 let idi: Idiom = syn::idiom("test.something[1]").unwrap().into();
130 let val = parse_val!("{ test: { something: [123, 456, 789] } }");
131 let res = val.pick(&idi);
132 assert_eq!(res, Value::from(456));
133 }
134
135 #[test]
136 fn pick_array_thing() {
137 let idi: Idiom = syn::idiom("test.something[1]").unwrap().into();
138 let val = parse_val!("{ test: { something: [test:tobie, test:jaime] } }");
139 let res = val.pick(&idi);
140 assert_eq!(
141 res,
142 Value::from(RecordId {
143 table: "test".into(),
144 key: RecordIdKey::String(Strand::new_static("jaime"))
145 })
146 );
147 }
148
149 #[test]
150 fn pick_array_field() {
151 let idi: Idiom = syn::idiom("test.something[1].age").unwrap().into();
152 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
153 let res = val.pick(&idi);
154 assert_eq!(res, Value::from(36));
155 }
156
157 #[test]
158 fn pick_array_fields() {
159 let idi: Idiom = syn::idiom("test.something[*].age").unwrap().into();
160 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
161 let res = val.pick(&idi);
162 assert_eq!(res, [Value::from(34i64), Value::from(36i64)].into_iter().collect::<Value>());
163 }
164
165 #[test]
166 fn pick_array_fields_flat() {
167 let idi: Idiom = syn::idiom("test.something.age").unwrap().into();
168 let val = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
169 let res = val.pick(&idi);
170 assert_eq!(res, [Value::from(34i64), Value::from(36i64)].into_iter().collect::<Value>());
171 }
172}