surrealdb_core/sql/value/
put.rs

1use crate::sql::part::Next;
2use crate::sql::part::Part;
3use crate::sql::value::Value;
4
5impl Value {
6	/// Synchronous method for setting a field on a `Value`
7	pub fn put(&mut self, path: &[Part], val: Value) {
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::Graph(g) => match v.get_mut(g.to_raw().as_str()) {
14						Some(v) if v.is_some() => v.put(path.next(), val),
15						_ => {
16							let mut obj = Value::base();
17							obj.put(path.next(), val);
18							v.insert(g.to_raw(), obj);
19						}
20					},
21					Part::Field(f) => match v.get_mut(f.to_raw().as_str()) {
22						Some(v) if v.is_some() => v.put(path.next(), val),
23						_ => {
24							let mut obj = Value::base();
25							obj.put(path.next(), val);
26							v.insert(f.to_raw(), obj);
27						}
28					},
29					Part::Index(i) => match v.get_mut(&i.to_string()) {
30						Some(v) if v.is_some() => v.put(path.next(), val),
31						_ => {
32							let mut obj = Value::base();
33							obj.put(path.next(), val);
34							v.insert(i.to_string(), obj);
35						}
36					},
37					Part::All => {
38						let path = path.next();
39						v.iter_mut().for_each(|(_, v)| v.put(path, val.clone()));
40					}
41					_ => (),
42				},
43				// Current value at path is an array
44				Value::Array(v) => match p {
45					Part::All => {
46						let path = path.next();
47						v.iter_mut().for_each(|v| v.put(path, val.clone()));
48					}
49					Part::First => {
50						if let Some(v) = v.first_mut() {
51							v.put(path.next(), val)
52						}
53					}
54					Part::Last => {
55						if let Some(v) = v.last_mut() {
56							v.put(path.next(), val)
57						}
58					}
59					Part::Index(i) => {
60						if let Some(v) = v.get_mut(i.to_usize()) {
61							v.put(path.next(), val)
62						}
63					}
64					_ => {
65						v.iter_mut().for_each(|v| v.put(path, val.clone()));
66					}
67				},
68				// Current value at path is empty
69				Value::Null => {
70					*self = Value::base();
71					self.put(path, val)
72				}
73				// Current value at path is empty
74				Value::None => {
75					*self = Value::base();
76					self.put(path, val)
77				}
78				// Ignore everything else
79				_ => (),
80			},
81			// No more parts so put the value
82			None => {
83				*self = val;
84			}
85		}
86	}
87}
88
89#[cfg(test)]
90mod tests {
91
92	use super::*;
93	use crate::sql::idiom::Idiom;
94	use crate::syn::Parse;
95
96	#[tokio::test]
97	async fn put_none() {
98		let idi = Idiom::default();
99		let mut val = Value::parse("{ test: { other: null, something: 123 } }");
100		let res = Value::parse("999");
101		val.put(&idi, Value::from(999));
102		assert_eq!(res, val);
103	}
104
105	#[tokio::test]
106	async fn put_empty() {
107		let idi = Idiom::parse("test");
108		let mut val = Value::None;
109		let res = Value::parse("{ test: 999 }");
110		val.put(&idi, Value::from(999));
111		assert_eq!(res, val);
112	}
113
114	#[tokio::test]
115	async fn put_blank() {
116		let idi = Idiom::parse("test.something");
117		let mut val = Value::None;
118		let res = Value::parse("{ test: { something: 999 } }");
119		val.put(&idi, Value::from(999));
120		assert_eq!(res, val);
121	}
122
123	#[tokio::test]
124	async fn put_reput() {
125		let idi = Idiom::parse("test");
126		let mut val = Value::parse("{ test: { other: null, something: 123 } }");
127		let res = Value::parse("{ test: 999 }");
128		val.put(&idi, Value::from(999));
129		assert_eq!(res, val);
130	}
131
132	#[tokio::test]
133	async fn put_basic() {
134		let idi = Idiom::parse("test.something");
135		let mut val = Value::parse("{ test: { other: null, something: 123 } }");
136		let res = Value::parse("{ test: { other: null, something: 999 } }");
137		val.put(&idi, Value::from(999));
138		assert_eq!(res, val);
139	}
140
141	#[tokio::test]
142	async fn put_allow() {
143		let idi = Idiom::parse("test.something.allow");
144		let mut val = Value::parse("{ test: { other: null } }");
145		let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }");
146		val.put(&idi, Value::from(999));
147		assert_eq!(res, val);
148	}
149
150	#[tokio::test]
151	async fn put_wrong() {
152		let idi = Idiom::parse("test.something.wrong");
153		let mut val = Value::parse("{ test: { other: null, something: 123 } }");
154		let res = Value::parse("{ test: { other: null, something: 123 } }");
155		val.put(&idi, Value::from(999));
156		assert_eq!(res, val);
157	}
158
159	#[tokio::test]
160	async fn put_other() {
161		let idi = Idiom::parse("test.other.something");
162		let mut val = Value::parse("{ test: { other: null, something: 123 } }");
163		let res = Value::parse("{ test: { other: { something: 999 }, something: 123 } }");
164		val.put(&idi, Value::from(999));
165		assert_eq!(res, val);
166	}
167
168	#[tokio::test]
169	async fn put_array() {
170		let idi = Idiom::parse("test.something[1]");
171		let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
172		let res = Value::parse("{ test: { something: [123, 999, 789] } }");
173		val.put(&idi, Value::from(999));
174		assert_eq!(res, val);
175	}
176
177	#[tokio::test]
178	async fn put_array_field() {
179		let idi = Idiom::parse("test.something[1].age");
180		let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
181		let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
182		val.put(&idi, Value::from(21));
183		assert_eq!(res, val);
184	}
185
186	#[tokio::test]
187	async fn put_array_fields() {
188		let idi = Idiom::parse("test.something[*].age");
189		let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
190		let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
191		val.put(&idi, Value::from(21));
192		assert_eq!(res, val);
193	}
194
195	#[tokio::test]
196	async fn put_array_fields_flat() {
197		let idi = Idiom::parse("test.something.age");
198		let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
199		let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
200		val.put(&idi, Value::from(21));
201		assert_eq!(res, val);
202	}
203}