surrealdb_core/sql/value/
fetch.rs

1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::err::Error;
4use crate::sql::edges::Edges;
5use crate::sql::field::{Field, Fields};
6use crate::sql::part::Next;
7use crate::sql::part::Part;
8use crate::sql::statements::select::SelectStatement;
9use crate::sql::value::{Value, Values};
10use futures::future::try_join_all;
11use reblessive::tree::Stk;
12
13impl Value {
14	pub(crate) async fn fetch(
15		&mut self,
16		stk: &mut Stk,
17		ctx: &Context,
18		opt: &Options,
19		path: &[Part],
20	) -> Result<(), Error> {
21		let mut this = self;
22		let mut iter = path.iter();
23		let mut prev = path;
24
25		// Loop over the path.
26		// If the we just need to select a sub section of a value we update this to point to the
27		// new subsection of the value. Otherwise we call into fetch again and then immediately
28		// return.
29		// If we encounter a idiom application which does not make sense, like `(1).foo` just
30		// return Ok(())
31		while let Some(p) = iter.next() {
32			match p {
33				Part::Graph(g) => match this {
34					Value::Object(o) => {
35						let Some(v) = o.rid() else {
36							return Ok(());
37						};
38
39						let mut v = Value::Thing(v);
40						return stk.run(|stk| v.fetch(stk, ctx, opt, iter.as_slice())).await;
41					}
42					Value::Thing(x) => {
43						let stm = SelectStatement {
44							expr: g.expr.clone().unwrap_or(Fields::all()),
45							what: Values(vec![Value::from(Edges {
46								from: x.clone(),
47								dir: g.dir.clone(),
48								what: g.what.clone(),
49							})]),
50							cond: g.cond.clone(),
51							limit: g.limit.clone(),
52							order: g.order.clone(),
53							split: g.split.clone(),
54							group: g.group.clone(),
55							start: g.start.clone(),
56							..SelectStatement::default()
57						};
58						*this = stm
59							.compute(stk, ctx, opt, None)
60							.await?
61							.all()
62							.get(stk, ctx, opt, None, path.next())
63							.await?
64							.flatten()
65							.ok()?;
66						return Ok(());
67					}
68					Value::Array(x) => {
69						// apply this path to every entry of the array.
70						stk.scope(|scope| {
71							let futs =
72								x.iter_mut().map(|v| scope.run(|stk| v.fetch(stk, ctx, opt, prev)));
73							try_join_all(futs)
74						})
75						.await?;
76						return Ok(());
77					}
78					// break her to be comp
79					_ => return Ok(()),
80				},
81				Part::Field(f) => match this {
82					Value::Object(o) => {
83						let Some(x) = o.get_mut(f.0.as_str()) else {
84							return Ok(());
85						};
86						this = x;
87					}
88					Value::Array(x) => {
89						// apply this path to every entry of the array.
90						stk.scope(|scope| {
91							let futs =
92								x.iter_mut().map(|v| scope.run(|stk| v.fetch(stk, ctx, opt, prev)));
93							try_join_all(futs)
94						})
95						.await?;
96						return Ok(());
97					}
98					_ => break,
99				},
100				Part::Index(i) => match this {
101					Value::Object(v) => {
102						let Some(x) = v.get_mut(&i.to_string()) else {
103							return Ok(());
104						};
105						this = x;
106					}
107					Value::Array(v) => {
108						let Some(x) = v.get_mut(i.to_usize()) else {
109							return Ok(());
110						};
111						this = x;
112					}
113					_ => break,
114				},
115				Part::Value(v) => {
116					let v = v.compute(stk, ctx, opt, None).await?;
117					match this {
118						Value::Object(obj) => {
119							let Some(x) = obj.get_mut(v.coerce_to_string()?.as_str()) else {
120								return Ok(());
121							};
122							this = x;
123						}
124						Value::Array(array) => {
125							if let Value::Range(x) = v {
126								let Some(range) = x.slice(array) else {
127									return Ok(());
128								};
129								let mut range = Value::Array(range.to_vec().into());
130								return stk
131									.run(|stk| range.fetch(stk, ctx, opt, iter.as_slice()))
132									.await;
133							}
134							let Some(x) = array.get_mut(v.coerce_to_u64()? as usize) else {
135								return Ok(());
136							};
137							this = x;
138						}
139						_ => return Ok(()),
140					}
141				}
142				Part::Destructure(p) => match this {
143					Value::Array(x) => {
144						// apply this path to every entry of the array.
145						stk.scope(|scope| {
146							let futs =
147								x.iter_mut().map(|v| scope.run(|stk| v.fetch(stk, ctx, opt, prev)));
148							try_join_all(futs)
149						})
150						.await?;
151					}
152					Value::Object(_) => {
153						for p in p.iter() {
154							let mut destructure_path = p.path();
155							destructure_path.extend_from_slice(path);
156							stk.run(|stk| this.fetch(stk, ctx, opt, &destructure_path)).await?;
157						}
158						return Ok(());
159					}
160					_ => return Ok(()),
161				},
162				Part::All => match this {
163					Value::Object(x) => {
164						let next_path = iter.as_slice();
165						// no need to spawn all those futures if their is no more paths to
166						// calculate
167						if next_path.is_empty() {
168							break;
169						}
170
171						stk.scope(|scope| {
172							let futs = x
173								.iter_mut()
174								.map(|(_, v)| scope.run(|stk| v.fetch(stk, ctx, opt, next_path)));
175							try_join_all(futs)
176						})
177						.await?;
178						return Ok(());
179					}
180					Value::Array(x) => {
181						let next_path = iter.as_slice();
182						// no need to spawn all those futures if their is no more paths to
183						// calculate
184						if next_path.is_empty() {
185							break;
186						}
187
188						stk.scope(|scope| {
189							let futs = x
190								.iter_mut()
191								.map(|v| scope.run(|stk| v.fetch(stk, ctx, opt, next_path)));
192							try_join_all(futs)
193						})
194						.await?;
195						return Ok(());
196					}
197					_ => break,
198				},
199				Part::First => match this {
200					Value::Array(x) => {
201						let Some(x) = x.first_mut() else {
202							return Ok(());
203						};
204						this = x;
205					}
206					_ => return Ok(()),
207				},
208				Part::Last => match this {
209					Value::Array(x) => {
210						let Some(x) = x.last_mut() else {
211							return Ok(());
212						};
213						this = x;
214					}
215					_ => return Ok(()),
216				},
217				Part::Where(w) => match this {
218					Value::Array(x) => {
219						for v in x.iter_mut() {
220							let doc = v.clone().into();
221							if w.compute(stk, ctx, opt, Some(&doc)).await?.is_truthy() {
222								stk.run(|stk| v.fetch(stk, ctx, opt, iter.as_slice())).await?;
223							}
224						}
225					}
226					_ => return Ok(()),
227				},
228				_ => break,
229			}
230			prev = iter.as_slice();
231		}
232
233		// If the final value is on of following types we still need to compute it.
234		match this {
235			Value::Array(v) => {
236				stk.scope(|scope| {
237					let futs = v.iter_mut().map(|v| scope.run(|stk| v.fetch(stk, ctx, opt, path)));
238					try_join_all(futs)
239				})
240				.await?;
241				Ok(())
242			}
243			Value::Thing(v) => {
244				// Clone the thing
245				let val = v.clone();
246				// Fetch the remote embedded record
247				let stm = SelectStatement {
248					expr: Fields(vec![Field::All], false),
249					what: Values(vec![Value::from(val)]),
250					..SelectStatement::default()
251				};
252				*this = stm.compute(stk, ctx, opt, None).await?.first();
253				Ok(())
254			}
255			_ => Ok(()),
256		}
257	}
258}