1use super::ExpressionKind;
2use crate::ast::{Column, ConditionTree, Expression};
3use std::borrow::Cow;
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum Compare<'a> {
8 Equals(Box<Expression<'a>>, Box<Expression<'a>>),
10 NotEquals(Box<Expression<'a>>, Box<Expression<'a>>),
12 LessThan(Box<Expression<'a>>, Box<Expression<'a>>),
14 LessThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
16 GreaterThan(Box<Expression<'a>>, Box<Expression<'a>>),
18 GreaterThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
20 In(Box<Expression<'a>>, Box<Expression<'a>>),
22 NotIn(Box<Expression<'a>>, Box<Expression<'a>>),
24 Like(Box<Expression<'a>>, Box<Expression<'a>>),
26 NotLike(Box<Expression<'a>>, Box<Expression<'a>>),
28 Null(Box<Expression<'a>>),
30 NotNull(Box<Expression<'a>>),
32 Between(
34 Box<Expression<'a>>,
35 Box<Expression<'a>>,
36 Box<Expression<'a>>,
37 ),
38 NotBetween(
40 Box<Expression<'a>>,
41 Box<Expression<'a>>,
42 Box<Expression<'a>>,
43 ),
44 Raw(Box<Expression<'a>>, Cow<'a, str>, Box<Expression<'a>>),
47 #[cfg(any(feature = "postgresql", feature = "mysql"))]
49 JsonCompare(JsonCompare<'a>),
50 #[cfg(feature = "postgresql")]
52 Any(Box<Expression<'a>>),
53 #[cfg(feature = "postgresql")]
55 All(Box<Expression<'a>>),
56}
57
58#[derive(Debug, Clone, PartialEq)]
59pub enum JsonCompare<'a> {
60 ArrayOverlaps(Box<Expression<'a>>, Box<Expression<'a>>),
61 ArrayContains(Box<Expression<'a>>, Box<Expression<'a>>),
62 ArrayContained(Box<Expression<'a>>, Box<Expression<'a>>),
63 ArrayNotContains(Box<Expression<'a>>, Box<Expression<'a>>),
64 TypeEquals(Box<Expression<'a>>, JsonType<'a>),
65 TypeNotEquals(Box<Expression<'a>>, JsonType<'a>),
66}
67
68#[derive(Debug, Clone, PartialEq)]
69pub enum JsonType<'a> {
70 Array,
71 Object,
72 String,
73 Number,
74 Boolean,
75 Null,
76 ColumnRef(Box<Column<'a>>),
77}
78
79impl<'a> From<Column<'a>> for JsonType<'a> {
80 fn from(col: Column<'a>) -> Self {
81 JsonType::ColumnRef(Box::new(col))
82 }
83}
84
85impl<'a> From<Compare<'a>> for ConditionTree<'a> {
86 fn from(cmp: Compare<'a>) -> Self {
87 ConditionTree::single(Expression::from(cmp))
88 }
89}
90
91impl<'a> From<Compare<'a>> for Expression<'a> {
92 fn from(cmp: Compare<'a>) -> Self {
93 Expression {
94 kind: ExpressionKind::Compare(cmp),
95 alias: None,
96 }
97 }
98}
99
100pub trait Comparable<'a> {
102 fn equals<T>(self, comparison: T) -> Compare<'a>
104 where
105 T: Into<Expression<'a>>;
106
107 fn not_equals<T>(self, comparison: T) -> Compare<'a>
109 where
110 T: Into<Expression<'a>>;
111
112 fn less_than<T>(self, comparison: T) -> Compare<'a>
114 where
115 T: Into<Expression<'a>>;
116
117 fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
119 where
120 T: Into<Expression<'a>>;
121
122 fn greater_than<T>(self, comparison: T) -> Compare<'a>
124 where
125 T: Into<Expression<'a>>;
126
127 fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
129 where
130 T: Into<Expression<'a>>;
131
132 fn in_selection<T>(self, selection: T) -> Compare<'a>
134 where
135 T: Into<Expression<'a>>;
136
137 fn not_in_selection<T>(self, selection: T) -> Compare<'a>
139 where
140 T: Into<Expression<'a>>;
141
142 fn like<T>(self, pattern: T) -> Compare<'a>
144 where
145 T: Into<Expression<'a>>;
146
147 fn not_like<T>(self, pattern: T) -> Compare<'a>
149 where
150 T: Into<Expression<'a>>;
151
152 #[allow(clippy::wrong_self_convention)]
154 fn is_null(self) -> Compare<'a>;
155
156 #[allow(clippy::wrong_self_convention)]
158 fn is_not_null(self) -> Compare<'a>;
159
160 fn between<T, V>(self, left: T, right: V) -> Compare<'a>
162 where
163 T: Into<Expression<'a>>,
164 V: Into<Expression<'a>>;
165
166 fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
168 where
169 T: Into<Expression<'a>>,
170 V: Into<Expression<'a>>;
171
172 #[cfg(any(feature = "postgresql", feature = "mysql"))]
174 fn array_overlaps<T>(self, item: T) -> Compare<'a>
175 where
176 T: Into<Expression<'a>>;
177
178 #[cfg(any(feature = "postgresql", feature = "mysql"))]
180 fn array_contains<T>(self, item: T) -> Compare<'a>
181 where
182 T: Into<Expression<'a>>;
183
184 #[cfg(any(feature = "postgresql", feature = "mysql"))]
186 fn array_contained<T>(self, item: T) -> Compare<'a>
187 where
188 T: Into<Expression<'a>>;
189
190 #[cfg(any(feature = "postgresql", feature = "mysql"))]
192 fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
193 where
194 T: Into<Expression<'a>>;
195
196 #[cfg(any(feature = "postgresql", feature = "mysql"))]
198 fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
199 where
200 T: Into<Expression<'a>>;
201
202 #[cfg(any(feature = "postgresql", feature = "mysql"))]
204 fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
205 where
206 T: Into<Expression<'a>>;
207
208 #[cfg(any(feature = "postgresql", feature = "mysql"))]
210 fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
211 where
212 T: Into<Expression<'a>>;
213
214 #[cfg(any(feature = "postgresql", feature = "mysql"))]
216 fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
217 where
218 T: Into<Expression<'a>>;
219
220 #[cfg(any(feature = "postgresql", feature = "mysql"))]
222 fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
223 where
224 T: Into<JsonType<'a>>;
225
226 #[cfg(any(feature = "postgresql", feature = "mysql"))]
228 fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
229 where
230 T: Into<JsonType<'a>>;
231
232 #[cfg(feature = "postgresql")]
234 fn any(self) -> Compare<'a>;
235
236 #[cfg(feature = "postgresql")]
238 fn all(self) -> Compare<'a>;
239
240 fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
242 where
243 T: Into<Cow<'a, str>>,
244 V: Into<Expression<'a>>;
245}
246
247impl<'a, U> Comparable<'a> for U
248where
249 U: Into<Column<'a>>,
250{
251 fn equals<T>(self, comparison: T) -> Compare<'a>
252 where
253 T: Into<Expression<'a>>,
254 {
255 let col: Column<'a> = self.into();
256 let val: Expression<'a> = col.into();
257
258 val.equals(comparison)
259 }
260
261 fn not_equals<T>(self, comparison: T) -> Compare<'a>
262 where
263 T: Into<Expression<'a>>,
264 {
265 let col: Column<'a> = self.into();
266 let val: Expression<'a> = col.into();
267 val.not_equals(comparison)
268 }
269
270 fn less_than<T>(self, comparison: T) -> Compare<'a>
271 where
272 T: Into<Expression<'a>>,
273 {
274 let col: Column<'a> = self.into();
275 let val: Expression<'a> = col.into();
276 val.less_than(comparison)
277 }
278
279 fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
280 where
281 T: Into<Expression<'a>>,
282 {
283 let col: Column<'a> = self.into();
284 let val: Expression<'a> = col.into();
285 val.less_than_or_equals(comparison)
286 }
287
288 fn greater_than<T>(self, comparison: T) -> Compare<'a>
289 where
290 T: Into<Expression<'a>>,
291 {
292 let col: Column<'a> = self.into();
293 let val: Expression<'a> = col.into();
294 val.greater_than(comparison)
295 }
296
297 fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
298 where
299 T: Into<Expression<'a>>,
300 {
301 let col: Column<'a> = self.into();
302 let val: Expression<'a> = col.into();
303 val.greater_than_or_equals(comparison)
304 }
305
306 fn in_selection<T>(self, selection: T) -> Compare<'a>
307 where
308 T: Into<Expression<'a>>,
309 {
310 let col: Column<'a> = self.into();
311 let val: Expression<'a> = col.into();
312 val.in_selection(selection)
313 }
314
315 fn not_in_selection<T>(self, selection: T) -> Compare<'a>
316 where
317 T: Into<Expression<'a>>,
318 {
319 let col: Column<'a> = self.into();
320 let val: Expression<'a> = col.into();
321 val.not_in_selection(selection)
322 }
323
324 fn like<T>(self, pattern: T) -> Compare<'a>
325 where
326 T: Into<Expression<'a>>,
327 {
328 let col: Column<'a> = self.into();
329 let val: Expression<'a> = col.into();
330 val.like(pattern)
331 }
332
333 fn not_like<T>(self, pattern: T) -> Compare<'a>
334 where
335 T: Into<Expression<'a>>,
336 {
337 let col: Column<'a> = self.into();
338 let val: Expression<'a> = col.into();
339 val.not_like(pattern)
340 }
341
342 #[allow(clippy::wrong_self_convention)]
343 fn is_null(self) -> Compare<'a> {
344 let col: Column<'a> = self.into();
345 let val: Expression<'a> = col.into();
346 val.is_null()
347 }
348
349 #[allow(clippy::wrong_self_convention)]
350 fn is_not_null(self) -> Compare<'a> {
351 let col: Column<'a> = self.into();
352 let val: Expression<'a> = col.into();
353 val.is_not_null()
354 }
355
356 fn between<T, V>(self, left: T, right: V) -> Compare<'a>
357 where
358 T: Into<Expression<'a>>,
359 V: Into<Expression<'a>>,
360 {
361 let col: Column<'a> = self.into();
362 let val: Expression<'a> = col.into();
363 val.between(left, right)
364 }
365
366 fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
367 where
368 T: Into<Expression<'a>>,
369 V: Into<Expression<'a>>,
370 {
371 let col: Column<'a> = self.into();
372 let val: Expression<'a> = col.into();
373 val.not_between(left, right)
374 }
375
376 fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
377 where
378 T: Into<Cow<'a, str>>,
379 V: Into<Expression<'a>>,
380 {
381 let left: Column<'a> = self.into();
382 let left: Expression<'a> = left.into();
383 let right: Expression<'a> = right.into();
384
385 left.compare_raw(raw_comparator.into(), right)
386 }
387
388 #[cfg(any(feature = "postgresql", feature = "mysql"))]
389 fn array_overlaps<T>(self, item: T) -> Compare<'a>
390 where
391 T: Into<Expression<'a>>,
392 {
393 let col: Column<'a> = self.into();
394 let val: Expression<'a> = col.into();
395
396 val.array_overlaps(item)
397 }
398
399 #[cfg(any(feature = "postgresql", feature = "mysql"))]
400 fn array_contains<T>(self, item: T) -> Compare<'a>
401 where
402 T: Into<Expression<'a>>,
403 {
404 let col: Column<'a> = self.into();
405 let val: Expression<'a> = col.into();
406
407 val.array_contains(item)
408 }
409
410 #[cfg(any(feature = "postgresql", feature = "mysql"))]
411 fn array_contained<T>(self, item: T) -> Compare<'a>
412 where
413 T: Into<Expression<'a>>,
414 {
415 let col: Column<'a> = self.into();
416 let val: Expression<'a> = col.into();
417
418 val.array_contained(item)
419 }
420
421 #[cfg(any(feature = "postgresql", feature = "mysql"))]
422 fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
423 where
424 T: Into<Expression<'a>>,
425 {
426 let col: Column<'a> = self.into();
427 let val: Expression<'a> = col.into();
428
429 val.json_array_not_contains(item)
430 }
431
432 #[cfg(any(feature = "postgresql", feature = "mysql"))]
433 fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
434 where
435 T: Into<Expression<'a>>,
436 {
437 let col: Column<'a> = self.into();
438 let val: Expression<'a> = col.into();
439
440 val.json_array_begins_with(item)
441 }
442
443 #[cfg(any(feature = "postgresql", feature = "mysql"))]
444 fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
445 where
446 T: Into<Expression<'a>>,
447 {
448 let col: Column<'a> = self.into();
449 let val: Expression<'a> = col.into();
450
451 val.json_array_not_begins_with(item)
452 }
453
454 #[cfg(any(feature = "postgresql", feature = "mysql"))]
455 fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
456 where
457 T: Into<Expression<'a>>,
458 {
459 let col: Column<'a> = self.into();
460 let val: Expression<'a> = col.into();
461
462 val.json_array_ends_into(item)
463 }
464
465 #[cfg(any(feature = "postgresql", feature = "mysql"))]
466 fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
467 where
468 T: Into<Expression<'a>>,
469 {
470 let col: Column<'a> = self.into();
471 let val: Expression<'a> = col.into();
472
473 val.json_array_not_ends_into(item)
474 }
475
476 #[cfg(any(feature = "postgresql", feature = "mysql"))]
477 fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
478 where
479 T: Into<JsonType<'a>>,
480 {
481 let col: Column<'a> = self.into();
482 let val: Expression<'a> = col.into();
483
484 val.json_type_equals(json_type)
485 }
486
487 #[cfg(any(feature = "postgresql", feature = "mysql"))]
488 fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
489 where
490 T: Into<JsonType<'a>>,
491 {
492 let col: Column<'a> = self.into();
493 let val: Expression<'a> = col.into();
494
495 val.json_type_not_equals(json_type)
496 }
497
498 #[cfg(feature = "postgresql")]
499 fn any(self) -> Compare<'a> {
500 let col: Column<'a> = self.into();
501 let val: Expression<'a> = col.into();
502
503 val.any()
504 }
505
506 #[cfg(feature = "postgresql")]
507 fn all(self) -> Compare<'a> {
508 let col: Column<'a> = self.into();
509 let val: Expression<'a> = col.into();
510
511 val.all()
512 }
513}