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 Not,
12 Positive,
14 Negate,
16 Range,
18 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 Subtract,
72 Add,
74 Multiply,
76 Divide,
78 Remainder,
80 Power,
82 Equal,
84 ExactEqual,
86 NotEqual,
88 AllEqual,
90 AnyEqual,
92
93 Or,
95 And,
97 NullCoalescing,
99 TenaryCondition,
101
102 LessThan,
104 LessThanEqual,
106 MoreThan,
108 MoreThanEqual,
110
111 Contain,
113 NotContain,
115 ContainAll,
117 ContainAny,
119 ContainNone,
121 Inside,
123 NotInside,
125 AllInside,
127 AnyInside,
129 NoneInside,
131
132 Outside,
134 Intersects,
136
137 Range,
139 RangeInclusive,
141 RangeSkip,
143 RangeSkipInclusive,
145
146 Matches(MatchesOperator),
148 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 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 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#[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(u32, Distance),
207 KTree(u32),
209 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#[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 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 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}