Skip to main content

surql_parser/upstream/sql/
operator.rs

1use crate::upstream::fmt::{CoverStmts, EscapeKwFreeIdent, Fmt};
2use crate::upstream::sql::index::Distance;
3use crate::upstream::sql::{Expr, Kind};
4use surrealdb_types::{SqlFormat, ToSql, write_sql};
5#[derive(Clone, Debug, Eq, PartialEq)]
6#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
7pub enum PrefixOperator {
8	/// `!`
9	Not,
10	/// `+`
11	Positive,
12	/// `-`
13	Negate,
14	/// `..`
15	Range,
16	/// `..=`
17	RangeInclusive,
18	Cast(Kind),
19}
20impl ToSql for PrefixOperator {
21	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
22		match self {
23			Self::Not => f.push('!'),
24			Self::Positive => f.push('+'),
25			Self::Negate => f.push('-'),
26			Self::Range => f.push_str(".."),
27			Self::RangeInclusive => f.push_str("..="),
28			Self::Cast(kind) => write_sql!(f, fmt, "<{kind}> "),
29		}
30	}
31}
32#[derive(Clone, Debug, Eq, PartialEq)]
33#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
34pub enum PostfixOperator {
35	Range,
36	RangeSkip,
37	#[cfg_attr(feature = "arbitrary", arbitrary(skip))]
38	MethodCall(String, Vec<Expr>),
39	Call(Vec<Expr>),
40}
41impl ToSql for PostfixOperator {
42	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
43		match self {
44			Self::Range => f.push_str(".."),
45			Self::RangeSkip => f.push_str(">.."),
46			Self::MethodCall(name, x) => {
47				write_sql!(
48					f,
49					fmt,
50					".{}({})",
51					EscapeKwFreeIdent(name),
52					Fmt::comma_separated(x.iter().map(CoverStmts))
53				);
54			}
55			Self::Call(args) => {
56				write_sql!(
57					f,
58					fmt,
59					"({})",
60					Fmt::comma_separated(args.iter().map(CoverStmts))
61				)
62			}
63		}
64	}
65}
66#[derive(Clone, Debug, Eq, PartialEq)]
67#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
68pub enum BinaryOperator {
69	/// `-`
70	Subtract,
71	/// `+`
72	Add,
73	/// `*`, `×`
74	Multiply,
75	/// `/`
76	Divide,
77	/// `%`
78	Remainder,
79	/// `**`
80	Power,
81	/// `=`
82	Equal,
83	/// `==`
84	ExactEqual,
85	/// `!=`
86	NotEqual,
87	/// `*=`
88	AllEqual,
89	/// `?=`
90	AnyEqual,
91	/// `||`, `OR`
92	Or,
93	/// `&&`, `AND`
94	And,
95	/// `??`
96	NullCoalescing,
97	TenaryCondition,
98	/// `<`
99	LessThan,
100	/// `<=`
101	LessThanEqual,
102	/// `>`
103	MoreThan,
104	/// `>=`
105	MoreThanEqual,
106	/// `∋`
107	Contain,
108	/// `∌`
109	NotContain,
110	/// `⊇`
111	ContainAll,
112	/// `⊃`
113	ContainAny,
114	/// `⊅`
115	ContainNone,
116	/// `∈`
117	Inside,
118	/// `∉`
119	NotInside,
120	/// `⊆`
121	AllInside,
122	/// `⊂`
123	AnyInside,
124	/// `⊄`
125	NoneInside,
126	/// `OUTSIDE`
127	Outside,
128	/// `INTERSECTS`
129	Intersects,
130	/// `..`
131	Range,
132	/// `..=`
133	RangeInclusive,
134	/// `>..`
135	RangeSkip,
136	/// `>..=`
137	RangeSkipInclusive,
138	Matches(MatchesOperator),
139	NearestNeighbor(Box<NearestNeighbor>),
140}
141#[derive(Clone, Debug, Eq, PartialEq)]
142#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
143pub struct MatchesOperator {
144	pub rf: Option<u8>,
145	pub operator: Option<BooleanOperator>,
146}
147impl ToSql for MatchesOperator {
148	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
149		if let Some(r) = self.rf {
150			if let Some(ref o) = self.operator {
151				if !matches!(o, BooleanOperator::And) {
152					write_sql!(f, fmt, "@{r},{o}@");
153				} else {
154					write_sql!(f, fmt, "@{r}@");
155				}
156			} else {
157				write_sql!(f, fmt, "@{r}@");
158			}
159		} else if let Some(ref o) = self.operator {
160			if !matches!(o, BooleanOperator::And) {
161				write_sql!(f, fmt, "@{o}@");
162			} else {
163				f.push_str("@@");
164			}
165		} else {
166			f.push_str("@@");
167		}
168	}
169}
170/// Boolean operation executed by the full-text index
171#[derive(Clone, Debug, Eq, PartialEq)]
172#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
173pub enum BooleanOperator {
174	And,
175	Or,
176}
177impl ToSql for BooleanOperator {
178	fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
179		match self {
180			Self::And => f.push_str("AND"),
181			Self::Or => f.push_str("OR"),
182		}
183	}
184}
185#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
186#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
187pub enum NearestNeighbor {
188	/// `<|k, dist|>`
189	K(u32, Distance),
190	/// `<|k|>`
191	KTree(u32),
192	/// `<|k, ef|>`
193	Approximate(u32, u32),
194}
195impl ToSql for NearestNeighbor {
196	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
197		match self {
198			Self::K(k, d) => write_sql!(f, fmt, "<|{k},{d}|>"),
199			Self::KTree(k) => write_sql!(f, fmt, "<|{k}|>"),
200			Self::Approximate(k, ef) => write_sql!(f, fmt, "<|{k},{ef}|>"),
201		}
202	}
203}
204impl ToSql for BinaryOperator {
205	fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
206		match self {
207			Self::Or => f.push_str("OR"),
208			Self::And => f.push_str("AND"),
209			Self::NullCoalescing => f.push_str("??"),
210			Self::TenaryCondition => f.push_str("?:"),
211			Self::Add => f.push('+'),
212			Self::Subtract => f.push('-'),
213			Self::Multiply => f.push('*'),
214			Self::Divide => f.push('/'),
215			Self::Remainder => f.push('%'),
216			Self::Power => f.push_str("**"),
217			Self::Equal => f.push('='),
218			Self::ExactEqual => f.push_str("=="),
219			Self::NotEqual => f.push_str("!="),
220			Self::AllEqual => f.push_str("*="),
221			Self::AnyEqual => f.push_str("?="),
222			Self::LessThan => f.push('<'),
223			Self::LessThanEqual => f.push_str("<="),
224			Self::MoreThan => f.push('>'),
225			Self::MoreThanEqual => f.push_str(">="),
226			Self::Contain => f.push_str("CONTAINS"),
227			Self::NotContain => f.push_str("CONTAINSNOT"),
228			Self::ContainAll => f.push_str("CONTAINSALL"),
229			Self::ContainAny => f.push_str("CONTAINSANY"),
230			Self::ContainNone => f.push_str("CONTAINSNONE"),
231			Self::Inside => f.push_str("INSIDE"),
232			Self::NotInside => f.push_str("NOTINSIDE"),
233			Self::AllInside => f.push_str("ALLINSIDE"),
234			Self::AnyInside => f.push_str("ANYINSIDE"),
235			Self::NoneInside => f.push_str("NONEINSIDE"),
236			Self::Outside => f.push_str("OUTSIDE"),
237			Self::Intersects => f.push_str("INTERSECTS"),
238			Self::Matches(m) => m.fmt_sql(f, fmt),
239			Self::Range => f.push_str(".."),
240			Self::RangeInclusive => f.push_str("..="),
241			Self::RangeSkip => f.push_str(">.."),
242			Self::RangeSkipInclusive => f.push_str(">..="),
243			Self::NearestNeighbor(n) => match &**n {
244				NearestNeighbor::KTree(k) => {
245					write_sql!(f, fmt, "<|{k}|>");
246				}
247				NearestNeighbor::K(k, distance) => {
248					write_sql!(f, fmt, "<|{k},{distance}|>");
249				}
250				NearestNeighbor::Approximate(k, ef) => {
251					write_sql!(f, fmt, "<|{k},{ef}|>");
252				}
253			},
254		}
255	}
256}
257#[derive(Clone, Debug, Eq, PartialEq, PartialOrd)]
258#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
259pub enum AssignOperator {
260	Assign,
261	Add,
262	Subtract,
263	Extend,
264}
265impl ToSql for AssignOperator {
266	fn fmt_sql(&self, f: &mut String, _fmt: SqlFormat) {
267		match self {
268			Self::Assign => f.push('='),
269			Self::Add => f.push_str("+="),
270			Self::Subtract => f.push_str("-="),
271			Self::Extend => f.push_str("+?="),
272		}
273	}
274}
275/// An enum which defines how strong a operator binds it's operands.
276///
277/// If a binding power is higher the operator is more likely to directly operate
278/// on it's neighbours.
279#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
280pub enum BindingPower {
281	Base,
282	Or,
283	And,
284	Equality,
285	Relation,
286	AddSub,
287	MulDiv,
288	Power,
289	Nullish,
290	Prefix,
291	Range,
292	Call,
293	Prime,
294}
295impl BindingPower {
296	/// Returns the binding power of this operator.
297	///
298	/// Note that there are some variants here which can have multiple meanings.
299	/// `Operator::Equal` can be assignment but can also be equality.
300	/// `Operator::Add` can be the add operator but also the plus prefix
301	/// operator which have different binding powers.
302	///
303	/// This function returns the binding power for if the operator is used in
304	/// the infix position.
305	pub fn for_binary_operator(op: &BinaryOperator) -> Self {
306		match op {
307			BinaryOperator::Or => BindingPower::Or,
308			BinaryOperator::And => BindingPower::And,
309			BinaryOperator::Equal
310			| BinaryOperator::ExactEqual
311			| BinaryOperator::NotEqual
312			| BinaryOperator::AllEqual
313			| BinaryOperator::AnyEqual => BindingPower::Equality,
314			BinaryOperator::LessThan
315			| BinaryOperator::LessThanEqual
316			| BinaryOperator::MoreThan
317			| BinaryOperator::MoreThanEqual
318			| BinaryOperator::Matches(_)
319			| BinaryOperator::Contain
320			| BinaryOperator::NotContain
321			| BinaryOperator::ContainAll
322			| BinaryOperator::ContainAny
323			| BinaryOperator::ContainNone
324			| BinaryOperator::Inside
325			| BinaryOperator::NotInside
326			| BinaryOperator::AllInside
327			| BinaryOperator::AnyInside
328			| BinaryOperator::NoneInside
329			| BinaryOperator::Outside
330			| BinaryOperator::Intersects
331			| BinaryOperator::NearestNeighbor(_) => BindingPower::Relation,
332			BinaryOperator::Add | BinaryOperator::Subtract => BindingPower::AddSub,
333			BinaryOperator::Multiply | BinaryOperator::Divide | BinaryOperator::Remainder => {
334				BindingPower::MulDiv
335			}
336			BinaryOperator::Power => BindingPower::Power,
337			BinaryOperator::NullCoalescing | BinaryOperator::TenaryCondition => {
338				BindingPower::Nullish
339			}
340			BinaryOperator::Range
341			| BinaryOperator::RangeInclusive
342			| BinaryOperator::RangeSkip
343			| BinaryOperator::RangeSkipInclusive => BindingPower::Range,
344		}
345	}
346	pub fn for_postfix_operator(op: &PostfixOperator) -> Self {
347		match op {
348			PostfixOperator::Range | PostfixOperator::RangeSkip => BindingPower::Range,
349			PostfixOperator::MethodCall(..) | PostfixOperator::Call(..) => BindingPower::Call,
350		}
351	}
352	pub fn for_prefix_operator(op: &PrefixOperator) -> Self {
353		match op {
354			PrefixOperator::Range | PrefixOperator::RangeInclusive => BindingPower::Range,
355			PrefixOperator::Not
356			| PrefixOperator::Positive
357			| PrefixOperator::Negate
358			| PrefixOperator::Cast(_) => BindingPower::Prefix,
359		}
360	}
361	/// Returns the binding power for this expression. This is generally
362	/// `BindingPower::Prime` as most value variants are prime expressions,
363	/// however some like Value::Expression and Value::Range have a different
364	/// binding power.
365	pub fn for_expr(expr: &Expr) -> BindingPower {
366		match expr {
367			Expr::Prefix { op, .. } => {
368				if let PrefixOperator::Range | PrefixOperator::RangeInclusive = *op {
369					BindingPower::Range
370				} else {
371					BindingPower::Prefix
372				}
373			}
374			Expr::Postfix { op, .. } => {
375				if let PostfixOperator::Range | PostfixOperator::RangeSkip = *op {
376					BindingPower::Range
377				} else {
378					BindingPower::Prefix
379				}
380			}
381			Expr::Binary { op, .. } => BindingPower::for_binary_operator(op),
382			_ => BindingPower::Prime,
383		}
384	}
385}