Skip to main content

surrealdb_expr/val/value/
cut.rs

1use crate::expr::part::{Next, Part};
2use crate::val::Value;
3
4impl Value {
5	/// Synchronous method for deleting a field from a `Value`
6	pub fn cut(&mut self, path: &[Part]) {
7		if let Some(p) = path.first() {
8			// Get the current value at path
9			match self {
10				// Current value at path is an object
11				Value::Object(v) => match p {
12					Part::Field(f) => match path.len() {
13						1 => {
14							v.remove(f);
15						}
16						_ => {
17							if let Some(v) = v.get_mut(f) {
18								v.cut(path.next())
19							}
20						}
21					},
22					Part::All => match path.len() {
23						1 => {
24							v.clear();
25						}
26						_ => {
27							let path = path.next();
28							v.iter_mut().for_each(|(_, v)| v.cut(path));
29						}
30					},
31					x => {
32						if let Some(i) = x.as_old_index() {
33							match path.len() {
34								1 => {
35									v.remove(&i.to_string());
36								}
37								_ => {
38									if let Some(v) = v.get_mut(&i.to_string()) {
39										v.cut(path.next())
40									}
41								}
42							}
43						}
44					}
45				},
46				// Current value at path is an array
47				Value::Array(v) => match p {
48					Part::All => match path.len() {
49						1 => {
50							v.clear();
51						}
52						_ => {
53							let path = path.next();
54							v.iter_mut().for_each(|v| v.cut(path));
55						}
56					},
57					Part::First => match path.len() {
58						1 => {
59							if !v.is_empty() {
60								let i = 0;
61								v.remove(i);
62							}
63						}
64						_ => {
65							if let Some(v) = v.first_mut() {
66								v.cut(path.next())
67							}
68						}
69					},
70					Part::Last => match path.len() {
71						1 => {
72							if !v.is_empty() {
73								let i = v.len() - 1;
74								v.remove(i);
75							}
76						}
77						_ => {
78							if let Some(v) = v.last_mut() {
79								v.cut(path.next())
80							}
81						}
82					},
83					x => {
84						if let Some(i) = x.as_old_index() {
85							match path.len() {
86								1 => {
87									if v.len() > i {
88										v.remove(i);
89									}
90								}
91								_ => {
92									if let Some(v) = v.get_mut(i) {
93										v.cut(path.next())
94									}
95								}
96							}
97						} else {
98							v.iter_mut().for_each(|v| v.cut(path));
99						}
100					}
101				},
102				// Ignore everything else
103				_ => (),
104			}
105		}
106	}
107}
108
109#[cfg(test)]
110mod tests {
111
112	use crate::expr::idiom::Idiom;
113	use crate::syn;
114
115	macro_rules! parse_val {
116		($input:expr) => {
117			crate::val::convert_public_value_to_internal(syn::value($input).unwrap())
118		};
119	}
120
121	#[tokio::test]
122	async fn cut_none() {
123		let idi: Idiom = Idiom::default();
124		let mut val = parse_val!("{ test: { other: null, something: 123 } }");
125		let res = parse_val!("{ test: { other: null, something: 123 } }");
126		val.cut(&idi);
127		assert_eq!(res, val);
128	}
129
130	#[tokio::test]
131	async fn cut_reset() {
132		let idi: Idiom = syn::idiom("test").unwrap().into();
133		let mut val = parse_val!("{ test: { other: null, something: 123 } }");
134		let res = parse_val!("{ }");
135		val.cut(&idi);
136		assert_eq!(res, val);
137	}
138
139	#[tokio::test]
140	async fn cut_basic() {
141		let idi: Idiom = syn::idiom("test.something").unwrap().into();
142		let mut val = parse_val!("{ test: { other: null, something: 123 } }");
143		let res = parse_val!("{ test: { other: null } }");
144		val.cut(&idi);
145		assert_eq!(res, val);
146	}
147
148	#[tokio::test]
149	async fn cut_wrong() {
150		let idi: Idiom = syn::idiom("test.something.wrong").unwrap().into();
151		let mut val = parse_val!("{ test: { other: null, something: 123 } }");
152		let res = parse_val!("{ test: { other: null, something: 123 } }");
153		val.cut(&idi);
154		assert_eq!(res, val);
155	}
156
157	#[tokio::test]
158	async fn cut_other() {
159		let idi: Idiom = syn::idiom("test.other.something").unwrap().into();
160		let mut val = parse_val!("{ test: { other: null, something: 123 } }");
161		let res = parse_val!("{ test: { other: null, something: 123 } }");
162		val.cut(&idi);
163		assert_eq!(res, val);
164	}
165
166	#[tokio::test]
167	async fn cut_array() {
168		let idi: Idiom = syn::idiom("test.something[1]").unwrap().into();
169		let mut val = parse_val!("{ test: { something: [123, 456, 789] } }");
170		let res = parse_val!("{ test: { something: [123, 789] } }");
171		val.cut(&idi);
172		assert_eq!(res, val);
173	}
174
175	#[tokio::test]
176	async fn cut_array_field() {
177		let idi: Idiom = syn::idiom("test.something[1].age").unwrap().into();
178		let mut val =
179			parse_val!("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }");
180		let res = parse_val!("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
181		val.cut(&idi);
182		assert_eq!(res, val);
183	}
184
185	#[tokio::test]
186	async fn cut_array_fields() {
187		let idi: Idiom = syn::idiom("test.something[*].age").unwrap().into();
188		let mut val =
189			parse_val!("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }");
190		let res = parse_val!("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
191		val.cut(&idi);
192		assert_eq!(res, val);
193	}
194
195	#[tokio::test]
196	async fn cut_array_fields_flat() {
197		let idi: Idiom = syn::idiom("test.something.age").unwrap().into();
198		let mut val =
199			parse_val!("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }");
200		let res = parse_val!("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
201		val.cut(&idi);
202		assert_eq!(res, val);
203	}
204}