surrealdb_sql/
field.rs

1use crate::ctx::Context;
2use crate::dbs::{Options, Transaction};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::syn;
6use crate::{fmt::Fmt, Idiom, Part, Value};
7use revision::revisioned;
8use serde::{Deserialize, Serialize};
9use std::borrow::Cow;
10use std::fmt::{self, Display, Formatter, Write};
11use std::ops::Deref;
12
13#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
14#[revisioned(revision = 1)]
15pub struct Fields(pub Vec<Field>, pub bool);
16
17impl Fields {
18	pub fn all() -> Self {
19		Self(vec![Field::All], false)
20	}
21	/// Check to see if this field is a * projection
22	pub fn is_all(&self) -> bool {
23		self.0.iter().any(|v| matches!(v, Field::All))
24	}
25	/// Get all fields which are not an * projection
26	pub fn other(&self) -> impl Iterator<Item = &Field> {
27		self.0.iter().filter(|v| !matches!(v, Field::All))
28	}
29	/// Check to see if this field is a single VALUE clause
30	pub fn single(&self) -> Option<&Field> {
31		match (self.0.len(), self.1) {
32			(1, true) => match self.0.first() {
33				Some(Field::All) => None,
34				Some(v) => Some(v),
35				_ => None,
36			},
37			_ => None,
38		}
39	}
40}
41
42impl Deref for Fields {
43	type Target = Vec<Field>;
44	fn deref(&self) -> &Self::Target {
45		&self.0
46	}
47}
48
49impl IntoIterator for Fields {
50	type Item = Field;
51	type IntoIter = std::vec::IntoIter<Self::Item>;
52	fn into_iter(self) -> Self::IntoIter {
53		self.0.into_iter()
54	}
55}
56
57impl Display for Fields {
58	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59		match self.single() {
60			Some(v) => write!(f, "VALUE {}", &v),
61			None => Display::fmt(&Fmt::comma_separated(&self.0), f),
62		}
63	}
64}
65
66impl Fields {
67	/// Process this type returning a computed simple Value
68	pub(crate) async fn compute(
69		&self,
70		ctx: &Context<'_>,
71		opt: &Options,
72		txn: &Transaction,
73		doc: Option<&CursorDoc<'_>>,
74		group: bool,
75	) -> Result<Value, Error> {
76		if let Some(doc) = doc {
77			self.compute_value(ctx, opt, txn, doc, group).await
78		} else {
79			let doc = (&Value::None).into();
80			self.compute_value(ctx, opt, txn, &doc, group).await
81		}
82	}
83
84	async fn compute_value(
85		&self,
86		ctx: &Context<'_>,
87		opt: &Options,
88		txn: &Transaction,
89		doc: &CursorDoc<'_>,
90		group: bool,
91	) -> Result<Value, Error> {
92		// Ensure futures are run
93		let opt = &opt.new_with_futures(true);
94		// Process the desired output
95		let mut out = match self.is_all() {
96			true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?,
97			false => Value::base(),
98		};
99		for v in self.other() {
100			match v {
101				Field::All => (),
102				Field::Single {
103					expr,
104					alias,
105				} => {
106					let name = alias
107						.as_ref()
108						.map(Cow::Borrowed)
109						.unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
110					match expr {
111						// This expression is a grouped aggregate function
112						Value::Function(f) if group && f.is_aggregate() => {
113							let x = match f.args().len() {
114								// If no function arguments, then compute the result
115								0 => f.compute(ctx, opt, txn, Some(doc)).await?,
116								// If arguments, then pass the first value through
117								_ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?,
118							};
119							// Check if this is a single VALUE field expression
120							match self.single().is_some() {
121								false => out.set(ctx, opt, txn, name.as_ref(), x).await?,
122								true => out = x,
123							}
124						}
125						// This expression is a multi-output graph traversal
126						Value::Idiom(v) if v.is_multi_yield() => {
127							// Store the different output yields here
128							let mut res: Vec<(&[Part], Value)> = Vec::new();
129							// Split the expression by each output alias
130							for v in v.split_inclusive(Idiom::split_multi_yield) {
131								// Use the last fetched value for each fetch
132								let x = match res.last() {
133									Some((_, r)) => r,
134									None => doc.doc.as_ref(),
135								};
136								// Continue fetching the next idiom part
137								let x = x
138									.get(ctx, opt, txn, Some(doc), v)
139									.await?
140									.compute(ctx, opt, txn, Some(doc))
141									.await?
142									.flatten();
143								// Add the result to the temporary store
144								res.push((v, x));
145							}
146							// Assign each fetched yield to the output
147							for (p, x) in res {
148								match p.last().unwrap().alias() {
149									// This is an alias expression part
150									Some(a) => {
151										if let Some(i) = alias {
152											out.set(ctx, opt, txn, i, x.clone()).await?;
153										}
154										out.set(ctx, opt, txn, a, x).await?;
155									}
156									// This is the end of the expression
157									None => {
158										out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x)
159											.await?
160									}
161								}
162							}
163						}
164						// This expression is a variable fields expression
165						Value::Function(f) if f.name() == Some("type::fields") => {
166							// Process the function using variable field projections
167							let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
168							// Check if this is a single VALUE field expression
169							match self.single().is_some() {
170								false => {
171									// Get the first argument which is guaranteed to exist
172									let args = match f.args().first().unwrap() {
173										Value::Param(v) => {
174											v.compute(ctx, opt, txn, Some(doc)).await?
175										}
176										v => v.to_owned(),
177									};
178									// This value is always an array, so we can convert it
179									let expr: Vec<Value> = expr.try_into()?;
180									// This value is always an array, so we can convert it
181									let args: Vec<Value> = args.try_into()?;
182									// This value is always an array, so we can convert it
183									for (name, expr) in args.into_iter().zip(expr) {
184										// This value is always a string, so we can convert it
185										let name = syn::idiom(&name.to_raw_string())?;
186										// Check if this is a single VALUE field expression
187										out.set(ctx, opt, txn, name.as_ref(), expr).await?
188									}
189								}
190								true => out = expr,
191							}
192						}
193						// This expression is a variable field expression
194						Value::Function(f) if f.name() == Some("type::field") => {
195							// Process the function using variable field projections
196							let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
197							// Check if this is a single VALUE field expression
198							match self.single().is_some() {
199								false => {
200									// Get the first argument which is guaranteed to exist
201									let name = match f.args().first().unwrap() {
202										Value::Param(v) => {
203											v.compute(ctx, opt, txn, Some(doc)).await?
204										}
205										v => v.to_owned(),
206									};
207									// find the name for the field, either from the argument or the
208									// alias.
209									let name = if let Some(x) = alias.as_ref().map(Cow::Borrowed) {
210										x
211									} else {
212										Cow::Owned(syn::idiom(&name.to_raw_string())?)
213									};
214									// Add the projected field to the output document
215									out.set(ctx, opt, txn, name.as_ref(), expr).await?
216								}
217								true => out = expr,
218							}
219						}
220						// This expression is a normal field expression
221						_ => {
222							let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
223							// Check if this is a single VALUE field expression
224							match self.single().is_some() {
225								false => out.set(ctx, opt, txn, name.as_ref(), expr).await?,
226								true => out = expr,
227							}
228						}
229					}
230				}
231			}
232		}
233		Ok(out)
234	}
235}
236
237#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
238#[revisioned(revision = 1)]
239pub enum Field {
240	/// The `*` in `SELECT * FROM ...`
241	#[default]
242	All,
243	/// The 'rating' in `SELECT rating FROM ...`
244	Single {
245		expr: Value,
246		/// The `quality` in `SELECT rating AS quality FROM ...`
247		alias: Option<Idiom>,
248	},
249}
250
251impl Display for Field {
252	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
253		match self {
254			Self::All => f.write_char('*'),
255			Self::Single {
256				expr,
257				alias,
258			} => {
259				Display::fmt(expr, f)?;
260				if let Some(alias) = alias {
261					f.write_str(" AS ")?;
262					Display::fmt(alias, f)
263				} else {
264					Ok(())
265				}
266			}
267		}
268	}
269}