surrealdb_expr/val/value/
put.rs1use surrealdb_types::ToSql;
2
3use crate::expr::part::{Next, Part};
4use crate::val::Value;
5
6impl Value {
7 pub fn put(&mut self, path: &[Part], val: Value) {
9 match path.first() {
10 Some(p) => match self {
12 Value::Object(v) => match p {
14 Part::Lookup(lookup) => {
15 let entry = v.entry(lookup.to_sql()).or_insert_with(Value::empty_object);
16 if !entry.is_nullish() {
17 entry.put(path.next(), val);
18 } else {
19 let mut obj = Value::empty_object();
20 obj.put(path.next(), val);
21 v.insert(lookup.to_sql(), obj);
22 }
23 }
24 Part::Field(f) => {
25 let entry = v.entry(f.clone()).or_insert_with(Value::empty_object);
26 entry.put(path.next(), val);
27 }
28 Part::All => {
29 let path = path.next();
30 v.iter_mut().for_each(|(_, v)| v.put(path, val.clone()));
31 }
32 x => {
33 if let Some(idx) = x.as_old_index() {
34 let entry =
35 v.entry(idx.to_string()).or_insert_with(Value::empty_object);
36 entry.put(path.next(), val);
37 }
38 }
39 },
40 Value::Array(v) => match p {
42 Part::All => {
43 let path = path.next();
44 v.iter_mut().for_each(|v| v.put(path, val.clone()));
45 }
46 Part::First => {
47 if let Some(v) = v.first_mut() {
48 v.put(path.next(), val)
49 }
50 }
51 Part::Last => {
52 if let Some(v) = v.last_mut() {
53 v.put(path.next(), val)
54 }
55 }
56 x => {
57 if let Some(idx) = x.as_old_index() {
58 if let Some(v) = v.get_mut(idx) {
59 v.put(path.next(), val)
60 }
61 } else {
62 v.iter_mut().for_each(|v| v.put(path, val.clone()));
63 }
64 }
65 },
66 Value::Set(v) => match p {
68 Part::All => {
69 let path = path.next();
70 let len = v.len();
71 for i in 0..len {
72 if let Some(elem) = v.nth_mut(i) {
73 elem.put(path, val.clone());
74 }
75 }
76 }
77 Part::First => {
78 if let Some(v) = v.first_mut() {
79 v.put(path.next(), val)
80 }
81 }
82 Part::Last => {
83 if let Some(v) = v.last_mut() {
84 v.put(path.next(), val)
85 }
86 }
87 x => {
88 if let Some(idx) = x.as_old_index() {
89 if let Some(v) = v.nth_mut(idx) {
90 v.put(path.next(), val)
91 }
92 } else {
93 let len = v.len();
94 for i in 0..len {
95 if let Some(elem) = v.nth_mut(i) {
96 elem.put(path, val.clone());
97 }
98 }
99 }
100 }
101 },
102 Value::Null => {
104 *self = Value::empty_object();
105 self.put(path, val)
106 }
107 Value::None => {
109 *self = Value::empty_object();
110 self.put(path, val)
111 }
112 _ => (),
114 },
115 None => {
117 *self = val;
118 }
119 }
120 }
121}
122
123#[cfg(test)]
124mod tests {
125
126 use super::*;
127 use crate::expr::idiom::Idiom;
128 use crate::syn;
129
130 macro_rules! parse_val {
131 ($input:expr) => {
132 crate::val::convert_public_value_to_internal(syn::value($input).unwrap())
133 };
134 }
135
136 #[tokio::test]
137 async fn put_none() {
138 let idi: Idiom = Idiom::default();
139 let mut val: Value = parse_val!("{ test: { other: null, something: 123 } }");
140 let res: Value = parse_val!("999");
141 val.put(&idi, Value::from(999));
142 assert_eq!(res, val);
143 }
144
145 #[tokio::test]
146 async fn put_empty() {
147 let idi: Idiom = syn::idiom("test").unwrap().into();
148 let mut val = Value::None;
149 let res: Value = parse_val!("{ test: 999 }");
150 val.put(&idi, Value::from(999));
151 assert_eq!(res, val);
152 }
153
154 #[tokio::test]
155 async fn put_blank() {
156 let idi: Idiom = syn::idiom("test.something").unwrap().into();
157 let mut val = Value::None;
158 let res: Value = parse_val!("{ test: { something: 999 } }");
159 val.put(&idi, Value::from(999));
160 assert_eq!(res, val);
161 }
162
163 #[tokio::test]
164 async fn put_reput() {
165 let idi: Idiom = syn::idiom("test").unwrap().into();
166 let mut val: Value = parse_val!("{ test: { other: null, something: 123 } }");
167 let res: Value = parse_val!("{ test: 999 }");
168 val.put(&idi, Value::from(999));
169 assert_eq!(res, val);
170 }
171
172 #[tokio::test]
173 async fn put_basic() {
174 let idi: Idiom = syn::idiom("test.something").unwrap().into();
175 let mut val: Value = parse_val!("{ test: { other: null, something: 123 } }");
176 let res: Value = parse_val!("{ test: { other: null, something: 999 } }");
177 val.put(&idi, Value::from(999));
178 assert_eq!(res, val);
179 }
180
181 #[tokio::test]
182 async fn put_allow() {
183 let idi: Idiom = syn::idiom("test.something.allow").unwrap().into();
184 let mut val: Value = parse_val!("{ test: { other: null } }");
185 let res: Value = parse_val!("{ test: { other: null, something: { allow: 999 } } }");
186 val.put(&idi, Value::from(999));
187 assert_eq!(res, val);
188 }
189
190 #[tokio::test]
191 async fn put_wrong() {
192 let idi: Idiom = syn::idiom("test.something.wrong").unwrap().into();
193 let mut val: Value = parse_val!("{ test: { other: null, something: 123 } }");
194 let res: Value = parse_val!("{ test: { other: null, something: 123 } }");
195 val.put(&idi, Value::from(999));
196 assert_eq!(res, val);
197 }
198
199 #[tokio::test]
200 async fn put_other() {
201 let idi: Idiom = syn::idiom("test.other.something").unwrap().into();
202 let mut val: Value = parse_val!("{ test: { other: null, something: 123 } }");
203 let res: Value = parse_val!("{ test: { other: { something: 999 }, something: 123 } }");
204 val.put(&idi, Value::from(999));
205 assert_eq!(res, val);
206 }
207
208 #[tokio::test]
209 async fn put_set_index() {
210 let idi: Idiom = syn::idiom("test[0]").unwrap().into();
211 let mut val: Value = parse_val!("{ test: { 'a', 'b', } }");
212 val.put(&idi, Value::from("hello"));
213 let Value::Object(obj) = &val else {
214 panic!("expected object");
215 };
216 let Value::Set(set) = obj.get("test").unwrap() else {
217 panic!("expected set");
218 };
219 assert_eq!(set.len(), 2);
220 assert_eq!(set.nth(0), Some(&Value::from("hello")));
221 assert_eq!(set.nth(1), Some(&Value::from("b")));
222 }
223
224 #[tokio::test]
225 async fn put_set_index_normalize() {
226 let idi: Idiom = syn::idiom("test[0]").unwrap().into();
227 let mut val: Value = parse_val!("{ test: { 'a', 'b', } }");
228 let res: Value = parse_val!("{ test: { 'b', 'hello', } }");
229 val.put(&idi, Value::from("hello"));
230 if let Value::Object(obj) = &mut val
233 && let Some(Value::Set(set)) = obj.get_mut("test")
234 {
235 *set = std::mem::take(set).normalize();
236 }
237 assert_eq!(res, val);
238 }
239
240 #[tokio::test]
241 async fn put_array() {
242 let idi: Idiom = syn::idiom("test.something[1]").unwrap().into();
243 let mut val: Value = parse_val!("{ test: { something: [123, 456, 789] } }");
244 let res: Value = parse_val!("{ test: { something: [123, 999, 789] } }");
245 val.put(&idi, Value::from(999));
246 assert_eq!(res, val);
247 }
248
249 #[tokio::test]
250 async fn put_array_field() {
251 let idi: Idiom = syn::idiom("test.something[1].age").unwrap().into();
252 let mut val: Value = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
253 let res: Value = parse_val!("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
254 val.put(&idi, Value::from(21));
255 assert_eq!(res, val);
256 }
257
258 #[tokio::test]
259 async fn put_array_fields() {
260 let idi: Idiom = syn::idiom("test.something[*].age").unwrap().into();
261 let mut val: Value = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
262 let res: Value = parse_val!("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
263 val.put(&idi, Value::from(21));
264 assert_eq!(res, val);
265 }
266
267 #[tokio::test]
268 async fn put_array_fields_flat() {
269 let idi: Idiom = syn::idiom("test.something.age").unwrap().into();
270 let mut val: Value = parse_val!("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
271 let res: Value = parse_val!("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
272 val.put(&idi, Value::from(21));
273 assert_eq!(res, val);
274 }
275}