Skip to main content

surrealdb_sql/
operator.rs

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