Skip to main content

surrealdb_expr/expr/
field.rs

1use std::slice::Iter;
2
3use revision::revisioned;
4use surrealdb_types::{SqlFormat, ToSql};
5
6use super::paths::ID;
7use crate::expr::{Expr, Function, Idiom};
8
9/// The `foo,bar,*` part of statements like `SELECT foo,bar.* FROM faz`.
10#[revisioned(revision = 1)]
11#[derive(Clone, Debug, Eq, PartialEq, Hash)]
12pub enum Fields {
13	/// Fields had the `VALUE` clause and should only return the given selector
14	///
15	/// This variant should not contain Field::All
16	/// TODO: Encode the above variant into the type.
17	Value(Box<Selector>),
18	/// Normal fields where an object with the selected fields is expected
19	Select(Vec<Field>),
20}
21
22impl ToSql for Fields {
23	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
24		let fields: crate::sql::field::Fields = self.clone().into();
25		fields.fmt_sql(f, fmt);
26	}
27}
28
29impl Fields {
30	/// Returns true if computing this value can be done on a read only
31	/// transaction.
32	pub fn read_only(&self) -> bool {
33		match self {
34			Fields::Value(field) => field.read_only(),
35			Fields::Select(fields) => fields.iter().all(|x| x.read_only()),
36		}
37	}
38
39	/// Create a new `*` field projection
40	pub fn all() -> Self {
41		Fields::Select(vec![Field::All])
42	}
43
44	/// Check to see if this field is a `*` projection
45	pub fn has_all_selection(&self) -> bool {
46		match self {
47			Fields::Select(x) => x.iter().any(|x| matches!(x, Field::All)),
48			Fields::Value(_) => false,
49		}
50	}
51	/// Create a new `VALUE id` field projection
52	pub fn value_id() -> Self {
53		Fields::Value(Box::new(Selector {
54			expr: Expr::Idiom(Idiom(ID.to_vec())),
55			alias: None,
56		}))
57	}
58
59	/// Returns an iterator which returns all fields which are not `Field::All`.
60	pub fn iter_non_all_fields(&self) -> FieldsIter<'_> {
61		match self {
62			Fields::Value(selector) => FieldsIter::Single(Some(selector)),
63			Fields::Select(fields) => FieldsIter::Multiple(fields.iter()),
64		}
65	}
66
67	/// Check to see if this field is a single VALUE clause
68	pub fn is_single(&self) -> bool {
69		matches!(self, Fields::Value(_))
70	}
71	/// Check if the fields are only about counting
72	pub fn is_count_all_only(&self) -> bool {
73		fn field_is_count(f: &Field) -> bool {
74			match f {
75				Field::All => false,
76				Field::Single(selector) => selector_is_count(selector),
77			}
78		}
79		fn selector_is_count(f: &Selector) -> bool {
80			let Expr::FunctionCall(x) = &f.expr else {
81				return false;
82			};
83			if !x.arguments.is_empty() {
84				return false;
85			}
86			let Function::Normal(name) = &x.receiver else {
87				return false;
88			};
89			name == "count"
90		}
91
92		match self {
93			Fields::Value(field) => selector_is_count(field),
94			Fields::Select(fields) => !fields.is_empty() && fields.iter().all(field_is_count),
95		}
96	}
97}
98
99pub enum FieldsIter<'a> {
100	Single(Option<&'a Selector>),
101	Multiple(Iter<'a, Field>),
102}
103
104impl<'a> Iterator for FieldsIter<'a> {
105	type Item = &'a Selector;
106
107	fn next(&mut self) -> Option<Self::Item> {
108		match self {
109			FieldsIter::Single(field) => field.take(),
110			FieldsIter::Multiple(iter) => loop {
111				if let Field::Single(x) = iter.next()? {
112					return Some(x);
113				}
114			},
115		}
116	}
117
118	fn size_hint(&self) -> (usize, Option<usize>) {
119		match self {
120			FieldsIter::Single(field) => {
121				if field.is_some() {
122					(1, Some(1))
123				} else {
124					(0, Some(0))
125				}
126			}
127			FieldsIter::Multiple(iter) => iter.size_hint(),
128		}
129	}
130}
131impl ExactSizeIterator for FieldsIter<'_> {}
132
133#[revisioned(revision = 1)]
134#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
135pub enum Field {
136	/// The `*` in `SELECT * FROM ...`
137	#[default]
138	All,
139	/// The 'rating' in `SELECT rating FROM ...`
140	Single(Selector),
141}
142
143impl Field {
144	/// Check if computing this type can be done on a read only transaction.
145	pub fn read_only(&self) -> bool {
146		match self {
147			Field::All => true,
148			Field::Single(x) => x.read_only(),
149		}
150	}
151}
152
153impl ToSql for Field {
154	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
155		match self {
156			Self::All => f.push('*'),
157			Self::Single(s) => s.fmt_sql(f, fmt),
158		}
159	}
160}
161
162#[revisioned(revision = 1)]
163#[derive(Clone, Debug, Eq, PartialEq, Hash)]
164pub struct Selector {
165	pub expr: Expr,
166	/// The `quality` in `SELECT rating AS quality FROM ...`
167	pub alias: Option<Idiom>,
168}
169
170impl Selector {
171	pub fn read_only(&self) -> bool {
172		self.expr.read_only()
173	}
174}
175
176impl ToSql for Selector {
177	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
178		self.expr.fmt_sql(f, fmt);
179		if let Some(alias) = &self.alias {
180			f.push_str(" AS ");
181			alias.fmt_sql(f, fmt);
182		}
183	}
184}