sqlint/ast/compare.rs
1use super::ExpressionKind;
2use crate::ast::{Column, ConditionTree, Expression};
3use std::borrow::Cow;
4
5/// For modeling comparison expressions.
6#[derive(Debug, Clone, PartialEq)]
7pub enum Compare<'a> {
8 /// `left = right`
9 Equals(Box<Expression<'a>>, Box<Expression<'a>>),
10 /// `left <> right`
11 NotEquals(Box<Expression<'a>>, Box<Expression<'a>>),
12 /// `left < right`
13 LessThan(Box<Expression<'a>>, Box<Expression<'a>>),
14 /// `left <= right`
15 LessThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
16 /// `left > right`
17 GreaterThan(Box<Expression<'a>>, Box<Expression<'a>>),
18 /// `left >= right`
19 GreaterThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
20 /// `left IN (..)`
21 In(Box<Expression<'a>>, Box<Expression<'a>>),
22 /// `left NOT IN (..)`
23 NotIn(Box<Expression<'a>>, Box<Expression<'a>>),
24 /// `left LIKE %..%`
25 Like(Box<Expression<'a>>, Box<Expression<'a>>),
26 /// `left NOT LIKE %..%`
27 NotLike(Box<Expression<'a>>, Box<Expression<'a>>),
28 /// `value IS NULL`
29 Null(Box<Expression<'a>>),
30 /// `value IS NOT NULL`
31 NotNull(Box<Expression<'a>>),
32 /// `value` BETWEEN `left` AND `right`
33 Between(Box<Expression<'a>>, Box<Expression<'a>>, Box<Expression<'a>>),
34 /// `value` NOT BETWEEN `left` AND `right`
35 NotBetween(Box<Expression<'a>>, Box<Expression<'a>>, Box<Expression<'a>>),
36 /// Raw comparator, allows to use an operator `left <raw> right` as is,
37 /// without visitor transformation in between.
38 Raw(Box<Expression<'a>>, Cow<'a, str>, Box<Expression<'a>>),
39 /// All json related comparators
40 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
41 JsonCompare(JsonCompare<'a>),
42 /// `left` @@ to_tsquery(`value`)
43 #[cfg(feature = "postgresql")]
44 Matches(Box<Expression<'a>>, Cow<'a, str>),
45 /// (NOT `left` @@ to_tsquery(`value`))
46 #[cfg(feature = "postgresql")]
47 NotMatches(Box<Expression<'a>>, Cow<'a, str>),
48 /// ANY (`left`)
49 #[cfg(feature = "postgresql")]
50 Any(Box<Expression<'a>>),
51 /// ALL (`left`)
52 #[cfg(feature = "postgresql")]
53 All(Box<Expression<'a>>),
54}
55
56#[derive(Debug, Clone, PartialEq)]
57pub enum JsonCompare<'a> {
58 ArrayContains(Box<Expression<'a>>, Box<Expression<'a>>),
59 ArrayNotContains(Box<Expression<'a>>, Box<Expression<'a>>),
60 TypeEquals(Box<Expression<'a>>, JsonType<'a>),
61 TypeNotEquals(Box<Expression<'a>>, JsonType<'a>),
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum JsonType<'a> {
66 Array,
67 Object,
68 String,
69 Number,
70 Boolean,
71 Null,
72 ColumnRef(Box<Column<'a>>),
73}
74
75impl<'a> From<Column<'a>> for JsonType<'a> {
76 fn from(col: Column<'a>) -> Self {
77 JsonType::ColumnRef(Box::new(col))
78 }
79}
80
81impl<'a> Compare<'a> {
82 /// Finds a possible `(a,y) IN (SELECT x,z FROM B)`, takes the select out and
83 /// converts the comparison into `a IN (SELECT x FROM cte_n where z = y)`.
84 ///
85 /// Left side means a match and the CTE should be handled, right side is a
86 /// no-op.
87 #[cfg(feature = "mssql")]
88 pub(crate) fn convert_tuple_select_to_cte(
89 self,
90 level: &mut usize,
91 ) -> either::Either<Self, (Self, Vec<super::CommonTableExpression<'a>>)> {
92 use super::IntoCommonTableExpression;
93
94 fn convert<'a>(
95 row: super::Row<'a>,
96 select: super::SelectQuery<'a>,
97 mut selected_columns: Vec<String>,
98 level: &mut usize,
99 ) -> (super::Column<'a>, super::Select<'a>, Vec<super::CommonTableExpression<'a>>) {
100 // Get the columns out from the row.
101 let mut cols = row.into_columns();
102
103 // The name of the CTE in the query
104 let ident = format!("cte_{level}");
105
106 let (select, ctes) = select.convert_tuple_selects_to_ctes(level);
107
108 let mut combined_ctes = Vec::with_capacity(ctes.len() + 1);
109 combined_ctes.push(select.into_cte(ident.clone()));
110 combined_ctes.extend(ctes);
111
112 // The left side column of the comparison, `*this* IN (...)`. We can
113 // support a single value comparisons in all databases, so we try to
114 // find the first value of the tuple, converting the select to hold
115 // the rest of the values in its comparison.
116 let comp_col = cols.remove(0);
117
118 // The right side `SELECT` of the comparison, replacing the original
119 // `SELECT`. At this point we just select the first column from the
120 // original select, changing the `SELECT` into
121 // `(SELECT first_col FROM cte_n)`.
122 let base_select = super::Select::from_table(ident).column(selected_columns.remove(0));
123
124 // We know we have the same amount of columns on both sides,
125 let column_pairs = cols.into_iter().zip(selected_columns.into_iter());
126
127 // Adding to the new select a condition to filter out the rest of
128 // the tuple, so if our tuple is `(a, b) IN (SELECT x, y ..)`, this
129 // will then turn into `a IN (SELECT x WHERE b = y)`.
130 let inner_select =
131 column_pairs.fold(base_select, |acc, (left_col, right_col)| acc.and_where(right_col.equals(left_col)));
132
133 // Now we added one cte, so we must increment the count for the
134 // possible other expressions.
135 *level += 1;
136
137 // Return the comparison data to the caller.
138 (comp_col, inner_select, combined_ctes)
139 }
140
141 match self {
142 Self::In(left, right) if left.is_row() && right.is_selection() => {
143 let row = left.into_row().unwrap();
144 let select = right.into_selection().unwrap();
145 let selection = select.named_selection();
146
147 if row.len() != selection.len() {
148 let left = Expression::row(row);
149 let right = Expression::selection(select);
150
151 return either::Either::Left(left.in_selection(right));
152 }
153
154 if row.is_only_columns() && row.len() > 1 {
155 let (comp_col, inner_select, ctes) = convert(row, select, selection, level);
156 let cond = comp_col.in_selection(inner_select);
157
158 either::Either::Right((cond, ctes))
159 } else if row.len() == 1 {
160 let left = Expression::row(row);
161 let (select, ctes) = select.convert_tuple_selects_to_ctes(level);
162
163 let select = Expression::selection(select);
164 let cond = Self::In(Box::new(left), Box::new(select));
165
166 either::Either::Right((cond, ctes))
167 } else {
168 let left = Expression::row(row);
169 let select = Expression::selection(select);
170 let cond = Self::In(Box::new(left), Box::new(select));
171
172 either::Either::Left(cond)
173 }
174 }
175 Self::In(left, right) if right.is_selection() => {
176 let (selection, ctes) = right.into_selection().unwrap().convert_tuple_selects_to_ctes(level);
177 let cond = Self::In(left, Box::new(Expression::selection(selection)));
178
179 either::Either::Right((cond, ctes))
180 }
181 Self::NotIn(left, right) if left.is_row() && right.is_selection() => {
182 let row = left.into_row().unwrap();
183 let select = right.into_selection().unwrap();
184 let selection = select.named_selection();
185
186 if row.len() != selection.len() {
187 let left = Expression::row(row);
188 let right = Expression::selection(select);
189
190 return either::Either::Left(left.not_in_selection(right));
191 }
192
193 if row.is_only_columns() && row.len() > 1 {
194 let (comp_col, inner_select, ctes) = convert(row, select, selection, level);
195 let cond = comp_col.not_in_selection(inner_select);
196
197 either::Either::Right((cond, ctes))
198 } else if row.len() == 1 {
199 let left = Expression::row(row);
200 let (select, ctes) = select.convert_tuple_selects_to_ctes(level);
201
202 let select = Expression::selection(select);
203 let cond = Self::NotIn(Box::new(left), Box::new(select));
204
205 either::Either::Right((cond, ctes))
206 } else {
207 let left = Expression::row(row);
208 let select = Expression::selection(select);
209 let cond = Self::NotIn(Box::new(left), Box::new(select));
210
211 either::Either::Left(cond)
212 }
213 }
214 Self::NotIn(left, right) if right.is_selection() => {
215 let (selection, ctes) = right.into_selection().unwrap().convert_tuple_selects_to_ctes(level);
216 let cond = Self::NotIn(left, Box::new(Expression::selection(selection)));
217
218 either::Either::Right((cond, ctes))
219 }
220 _ => either::Either::Left(self),
221 }
222 }
223}
224
225impl<'a> From<Compare<'a>> for ConditionTree<'a> {
226 fn from(cmp: Compare<'a>) -> Self {
227 ConditionTree::single(Expression::from(cmp))
228 }
229}
230
231impl<'a> From<Compare<'a>> for Expression<'a> {
232 fn from(cmp: Compare<'a>) -> Self {
233 Expression { kind: ExpressionKind::Compare(cmp), alias: None }
234 }
235}
236
237/// An item that can be compared against other values in the database.
238pub trait Comparable<'a> {
239 /// Tests if both sides are the same value.
240 ///
241 /// ```rust
242 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
243 /// # fn main() -> Result<(), sqlint::error::Error> {
244 /// let query = Select::from_table("users").so_that("foo".equals("bar"));
245 /// let (sql, params) = Sqlite::build(query)?;
246 ///
247 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` = ?", sql);
248 ///
249 /// assert_eq!(
250 /// vec![
251 /// Value::from("bar"),
252 /// ],
253 /// params
254 /// );
255 /// # Ok(())
256 /// # }
257 /// ```
258 fn equals<T>(self, comparison: T) -> Compare<'a>
259 where
260 T: Into<Expression<'a>>;
261
262 /// Tests if both sides are not the same value.
263 ///
264 /// ```rust
265 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
266 /// # fn main() -> Result<(), sqlint::error::Error> {
267 /// let query = Select::from_table("users").so_that("foo".not_equals("bar"));
268 /// let (sql, params) = Sqlite::build(query)?;
269 ///
270 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` <> ?", sql);
271 ///
272 /// assert_eq!(
273 /// vec![
274 /// Value::from("bar"),
275 /// ],
276 /// params
277 /// );
278 /// # Ok(())
279 /// # }
280 /// ```
281 fn not_equals<T>(self, comparison: T) -> Compare<'a>
282 where
283 T: Into<Expression<'a>>;
284
285 /// Tests if the left side is smaller than the right side.
286 ///
287 /// ```rust
288 /// # fn main() -> Result<(), sqlint::error::Error> {
289 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
290 /// let query = Select::from_table("users").so_that("foo".less_than(10));
291 /// let (sql, params) = Sqlite::build(query)?;
292 ///
293 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` < ?", sql);
294 ///
295 /// assert_eq!(
296 /// vec![
297 /// Value::from(10),
298 /// ],
299 /// params
300 /// );
301 /// # Ok(())
302 /// # }
303 /// ```
304 fn less_than<T>(self, comparison: T) -> Compare<'a>
305 where
306 T: Into<Expression<'a>>;
307
308 /// Tests if the left side is smaller than the right side or the same.
309 ///
310 /// ```rust
311 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
312 /// # fn main() -> Result<(), sqlint::error::Error> {
313 /// let query = Select::from_table("users").so_that("foo".less_than_or_equals(10));
314 /// let (sql, params) = Sqlite::build(query)?;
315 ///
316 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` <= ?", sql);
317 ///
318 /// assert_eq!(
319 /// vec![
320 /// Value::from(10),
321 /// ],
322 /// params
323 /// );
324 /// # Ok(())
325 /// # }
326 /// ```
327 fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
328 where
329 T: Into<Expression<'a>>;
330
331 /// Tests if the left side is bigger than the right side.
332 ///
333 /// ```rust
334 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
335 /// # fn main() -> Result<(), sqlint::error::Error> {
336 /// let query = Select::from_table("users").so_that("foo".greater_than(10));
337 /// let (sql, params) = Sqlite::build(query)?;
338 ///
339 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` > ?", sql);
340 ///
341 /// assert_eq!(
342 /// vec![
343 /// Value::from(10),
344 /// ],
345 /// params
346 /// );
347 /// # Ok(())
348 /// # }
349 /// ```
350 fn greater_than<T>(self, comparison: T) -> Compare<'a>
351 where
352 T: Into<Expression<'a>>;
353
354 /// Tests if the left side is bigger than the right side or the same.
355 ///
356 /// ```rust
357 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
358 /// # fn main() -> Result<(), sqlint::error::Error> {
359 /// let query = Select::from_table("users").so_that("foo".greater_than_or_equals(10));
360 /// let (sql, params) = Sqlite::build(query)?;
361 ///
362 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` >= ?", sql);
363 ///
364 /// assert_eq!(
365 /// vec![
366 /// Value::from(10),
367 /// ],
368 /// params
369 /// );
370 /// # Ok(())
371 /// # }
372 /// ```
373 fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
374 where
375 T: Into<Expression<'a>>;
376
377 /// Tests if the left side is included in the right side collection.
378 ///
379 /// ```rust
380 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
381 /// # fn main() -> Result<(), sqlint::error::Error> {
382 /// let query = Select::from_table("users").so_that("foo".in_selection(vec![1, 2]));
383 /// let (sql, params) = Sqlite::build(query)?;
384 ///
385 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` IN (?,?)", sql);
386 /// assert_eq!(vec![
387 /// Value::from(1),
388 /// Value::from(2),
389 /// ], params);
390 /// # Ok(())
391 /// # }
392 /// ```
393 fn in_selection<T>(self, selection: T) -> Compare<'a>
394 where
395 T: Into<Expression<'a>>;
396
397 /// Tests if the left side is not included in the right side collection.
398 ///
399 /// ```rust
400 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
401 /// # fn main() -> Result<(), sqlint::error::Error> {
402 /// let query = Select::from_table("users").so_that("foo".not_in_selection(vec![1, 2]));
403 /// let (sql, params) = Sqlite::build(query)?;
404 ///
405 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` NOT IN (?,?)", sql);
406 ///
407 /// assert_eq!(vec![
408 /// Value::from(1),
409 /// Value::from(2),
410 /// ], params);
411 /// # Ok(())
412 /// # }
413 /// ```
414 fn not_in_selection<T>(self, selection: T) -> Compare<'a>
415 where
416 T: Into<Expression<'a>>;
417
418 /// Tests if the left side includes the right side string.
419 ///
420 /// ```rust
421 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
422 /// # fn main() -> Result<(), sqlint::error::Error> {
423 /// let query = Select::from_table("users").so_that("foo".like("%bar%"));
424 /// let (sql, params) = Sqlite::build(query)?;
425 ///
426 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` LIKE ?", sql);
427 ///
428 /// assert_eq!(
429 /// vec![
430 /// Value::from("%bar%"),
431 /// ],
432 /// params
433 /// );
434 /// # Ok(())
435 /// # }
436 /// ```
437 fn like<T>(self, pattern: T) -> Compare<'a>
438 where
439 T: Into<Expression<'a>>;
440
441 /// Tests if the left side does not include the right side string.
442 ///
443 /// ```rust
444 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
445 /// # fn main() -> Result<(), sqlint::error::Error> {
446 /// let query = Select::from_table("users").so_that("foo".not_like("%bar%"));
447 /// let (sql, params) = Sqlite::build(query)?;
448 ///
449 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` NOT LIKE ?", sql);
450 ///
451 /// assert_eq!(
452 /// vec![
453 /// Value::from("%bar%"),
454 /// ],
455 /// params
456 /// );
457 /// # Ok(())
458 /// # }
459 /// ```
460 fn not_like<T>(self, pattern: T) -> Compare<'a>
461 where
462 T: Into<Expression<'a>>;
463
464 /// Tests if the left side is `NULL`.
465 ///
466 /// ```rust
467 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
468 /// # fn main() -> Result<(), sqlint::error::Error> {
469 /// let query = Select::from_table("users").so_that("foo".is_null());
470 /// let (sql, _) = Sqlite::build(query)?;
471 ///
472 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` IS NULL", sql);
473 /// # Ok(())
474 /// # }
475 /// ```
476 #[allow(clippy::wrong_self_convention)]
477 fn is_null(self) -> Compare<'a>;
478
479 /// Tests if the left side is not `NULL`.
480 ///
481 /// ```rust
482 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
483 /// # fn main() -> Result<(), sqlint::error::Error> {
484 /// let query = Select::from_table("users").so_that("foo".is_not_null());
485 /// let (sql, _) = Sqlite::build(query)?;
486 ///
487 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` IS NOT NULL", sql);
488 /// # Ok(())
489 /// # }
490 /// ```
491 #[allow(clippy::wrong_self_convention)]
492 fn is_not_null(self) -> Compare<'a>;
493
494 /// Tests if the value is between two given values.
495 ///
496 /// ```rust
497 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
498 /// # fn main() -> Result<(), sqlint::error::Error> {
499 /// let query = Select::from_table("users").so_that("foo".between(420, 666));
500 /// let (sql, params) = Sqlite::build(query)?;
501 ///
502 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` BETWEEN ? AND ?", sql);
503 ///
504 /// assert_eq!(vec![
505 /// Value::from(420),
506 /// Value::from(666),
507 /// ], params);
508 /// # Ok(())
509 /// # }
510 /// ```
511 fn between<T, V>(self, left: T, right: V) -> Compare<'a>
512 where
513 T: Into<Expression<'a>>,
514 V: Into<Expression<'a>>;
515
516 /// Tests if the value is not between two given values.
517 ///
518 /// ```rust
519 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
520 /// # fn main() -> Result<(), sqlint::error::Error> {
521 /// let query = Select::from_table("users").so_that("foo".not_between(420, 666));
522 /// let (sql, params) = Sqlite::build(query)?;
523 ///
524 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` NOT BETWEEN ? AND ?", sql);
525 ///
526 /// assert_eq!(vec![
527 /// Value::from(420),
528 /// Value::from(666),
529 /// ], params);
530 /// # Ok(())
531 /// # }
532 /// ```
533 fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
534 where
535 T: Into<Expression<'a>>,
536 V: Into<Expression<'a>>;
537
538 /// Tests if the JSON array contains a value.
539 ///
540 /// ```rust
541 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
542 /// # fn main() -> Result<(), sqlint::error::Error> {
543 /// let query = Select::from_table("users")
544 /// .so_that("json".json_array_contains(serde_json::json!(1)));
545 /// let (sql, params) = Mysql::build(query)?;
546 ///
547 /// assert_eq!("SELECT `users`.* FROM `users` WHERE JSON_CONTAINS(`json`, ?)", sql);
548 ///
549 /// assert_eq!(vec![Value::from(serde_json::json!(1))], params);
550 /// # Ok(())
551 /// # }
552 /// ```
553 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
554 fn json_array_contains<T>(self, item: T) -> Compare<'a>
555 where
556 T: Into<Expression<'a>>;
557
558 /// Tests if the JSON array does not contain a value.
559 ///
560 /// ```rust
561 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
562 /// # fn main() -> Result<(), sqlint::error::Error> {
563 /// let query = Select::from_table("users")
564 /// .so_that("json".json_array_not_contains(serde_json::json!(1)));
565 /// let (sql, params) = Mysql::build(query)?;
566 ///
567 /// assert_eq!("SELECT `users`.* FROM `users` WHERE JSON_CONTAINS(`json`, ?) = FALSE", sql);
568 /// assert_eq!(vec![Value::from(serde_json::json!(1))], params);
569 ///
570 /// # Ok(())
571 /// # }
572 /// ```
573 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
574 fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
575 where
576 T: Into<Expression<'a>>;
577
578 /// Tests if the JSON array starts with a value.
579 ///
580 /// ```rust
581 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
582 /// # fn main() -> Result<(), sqlint::error::Error> {
583 /// let query = Select::from_table("users")
584 /// .so_that("json".json_array_begins_with(serde_json::json!(1)));
585 /// let (sql, params) = Mysql::build(query)?;
586 ///
587 /// assert_eq!(
588 /// "SELECT `users`.* FROM `users` WHERE \
589 /// (JSON_CONTAINS(JSON_EXTRACT(`json`, ?), ?) AND \
590 /// JSON_CONTAINS(?, JSON_EXTRACT(`json`, ?)))",
591 /// sql
592 /// );
593 /// assert_eq!(vec![
594 /// Value::from("$[0]"),
595 /// Value::from(serde_json::json!(1)),
596 /// Value::from(serde_json::json!(1)),
597 /// Value::from("$[0]"),
598 /// ], params);
599 ///
600 /// # Ok(())
601 /// # }
602 /// ```
603 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
604 fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
605 where
606 T: Into<Expression<'a>>;
607
608 /// Tests if the JSON array does not start with a value.
609 ///
610 /// ```rust
611 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
612 /// # fn main() -> Result<(), sqlint::error::Error> {
613 /// let query = Select::from_table("users")
614 /// .so_that("json".json_array_not_begins_with(serde_json::json!(1)));
615 /// let (sql, params) = Mysql::build(query)?;
616 ///
617 /// assert_eq!(
618 /// "SELECT `users`.* FROM `users` WHERE \
619 /// (NOT JSON_CONTAINS(JSON_EXTRACT(`json`, ?), ?) OR \
620 /// NOT JSON_CONTAINS(?, JSON_EXTRACT(`json`, ?)))",
621 /// sql
622 /// );
623 /// assert_eq!(vec![
624 /// Value::from("$[0]"),
625 /// Value::from(serde_json::json!(1)),
626 /// Value::from(serde_json::json!(1)),
627 /// Value::from("$[0]"),
628 /// ], params);
629 ///
630 /// # Ok(())
631 /// # }
632 /// ```
633 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
634 fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
635 where
636 T: Into<Expression<'a>>;
637
638 /// Tests if the JSON array ends with a value.
639 ///
640 /// ```rust
641 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
642 /// # fn main() -> Result<(), sqlint::error::Error> {
643 /// let query = Select::from_table("users")
644 /// .so_that("json".json_array_ends_into(serde_json::json!(1)));
645 /// let (sql, params) = Mysql::build(query)?;
646 ///
647 /// assert_eq!(
648 /// "SELECT `users`.* FROM `users` WHERE \
649 /// (JSON_CONTAINS(JSON_EXTRACT(`json`, CONCAT('$[', JSON_LENGTH(`json`) - 1, ']')), ?) AND \
650 /// JSON_CONTAINS(?, JSON_EXTRACT(`json`, CONCAT('$[', JSON_LENGTH(`json`) - 1, ']'))))",
651 /// sql
652 /// );
653 /// assert_eq!(vec![
654 /// Value::from(serde_json::json!(1)),
655 /// Value::from(serde_json::json!(1)),
656 /// ], params);
657 ///
658 /// # Ok(())
659 /// # }
660 /// ```
661 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
662 fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
663 where
664 T: Into<Expression<'a>>;
665
666 /// Tests if the JSON array does not end with a value.
667 ///
668 /// ```rust
669 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
670 /// # fn main() -> Result<(), sqlint::error::Error> {
671 /// let query = Select::from_table("users").so_that("json".json_array_not_ends_into(serde_json::json!(1)));
672 /// let (sql, params) = Mysql::build(query)?;
673 ///
674 /// assert_eq!(
675 /// "SELECT `users`.* FROM `users` WHERE \
676 /// (NOT JSON_CONTAINS(JSON_EXTRACT(`json`, CONCAT('$[', JSON_LENGTH(`json`) - 1, ']')), ?) OR \
677 /// NOT JSON_CONTAINS(?, JSON_EXTRACT(`json`, CONCAT('$[', JSON_LENGTH(`json`) - 1, ']'))))",
678 /// sql
679 /// );
680 ///
681 /// assert_eq!(vec![
682 /// Value::from(serde_json::json!(1)),
683 /// Value::from(serde_json::json!(1)),
684 /// ], params);
685 ///
686 /// # Ok(())
687 /// # }
688 /// ```
689 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
690 fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
691 where
692 T: Into<Expression<'a>>;
693
694 /// Tests if the JSON value is of a certain type.
695 ///
696 /// ```rust
697 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
698 /// # fn main() -> Result<(), sqlint::error::Error> {
699 /// let query = Select::from_table("users").so_that("json".json_type_equals(JsonType::Array));
700 /// let (sql, params) = Mysql::build(query)?;
701 ///
702 /// assert_eq!("SELECT `users`.* FROM `users` WHERE (JSON_TYPE(`json`) = ?)", sql);
703 ///
704 /// assert_eq!(vec![Value::from("ARRAY")], params);
705 /// # Ok(())
706 /// # }
707 /// ```
708 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
709 fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
710 where
711 T: Into<JsonType<'a>>;
712
713 /// Tests if the JSON value is not of a certain type.
714 ///
715 /// ```rust
716 /// # use sqlint::{ast::*, visitor::{Visitor, Mysql}};
717 /// # fn main() -> Result<(), sqlint::error::Error> {
718 /// let query = Select::from_table("users").so_that("json".json_type_not_equals(JsonType::Array));
719 /// let (sql, params) = Mysql::build(query)?;
720 ///
721 /// assert_eq!("SELECT `users`.* FROM `users` WHERE (JSON_TYPE(`json`) != ?)", sql);
722 ///
723 /// assert_eq!(vec![Value::from("ARRAY")], params);
724 /// # Ok(())
725 /// # }
726 /// ```
727 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
728 fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
729 where
730 T: Into<JsonType<'a>>;
731
732 /// Tests if a full-text search matches a certain query. Use it in combination with the `text_search()` function
733 ///
734 /// ```rust
735 /// # use sqlint::{ast::*, visitor::{Visitor, Postgres}};
736 /// # fn main() -> Result<(), sqlint::error::Error> {
737 /// let search: Expression = text_search(&[Column::from("name"), Column::from("ingredients")]).into();
738 /// let query = Select::from_table("recipes").so_that(search.matches("chicken"));
739 /// let (sql, params) = Postgres::build(query)?;
740 ///
741 /// assert_eq!(
742 /// "SELECT \"recipes\".* FROM \"recipes\" \
743 /// WHERE to_tsvector(concat_ws(' ', \"name\",\"ingredients\")) @@ to_tsquery($1)", sql
744 /// );
745 ///
746 /// assert_eq!(params, vec![Value::from("chicken")]);
747 ///
748 /// # Ok(())
749 /// # }
750 /// ```
751 #[cfg(feature = "postgresql")]
752 fn matches<T>(self, query: T) -> Compare<'a>
753 where
754 T: Into<Cow<'a, str>>;
755
756 /// Tests if a full-text search does not match a certain query. Use it in combination with the `text_search()` function
757 ///
758 /// ```rust
759 /// # use sqlint::{ast::*, visitor::{Visitor, Postgres}};
760 /// # fn main() -> Result<(), sqlint::error::Error> {
761 /// let search: Expression = text_search(&[Column::from("name"), Column::from("ingredients")]).into();
762 /// let query = Select::from_table("recipes").so_that(search.not_matches("chicken"));
763 /// let (sql, params) = Postgres::build(query)?;
764 ///
765 /// assert_eq!(
766 /// "SELECT \"recipes\".* FROM \"recipes\" \
767 /// WHERE (NOT to_tsvector(concat_ws(' ', \"name\",\"ingredients\")) @@ to_tsquery($1))", sql
768 /// );
769 ///
770 /// assert_eq!(params, vec![Value::from("chicken")]);
771 ///
772 /// # Ok(())
773 /// # }
774 /// ```
775 #[cfg(feature = "postgresql")]
776 fn not_matches<T>(self, query: T) -> Compare<'a>
777 where
778 T: Into<Cow<'a, str>>;
779
780 /// Matches at least one elem of a list of values.
781 ///
782 /// ```rust
783 /// # use sqlint::{ast::*, col, visitor::{Visitor, Postgres}};
784 /// # fn main() -> Result<(), sqlint::error::Error> {
785 /// let query = Select::from_table("users").so_that(col!("name").equals(col!("list").any()));
786 /// let (sql, _) = Postgres::build(query)?;
787 /// assert_eq!(r#"SELECT "users".* FROM "users" WHERE "name" = ANY("list")"#, sql);
788 /// # Ok(())
789 /// # }
790 /// ```
791 #[cfg(feature = "postgresql")]
792 fn any(self) -> Compare<'a>;
793
794 /// Matches all elem of a list of values.
795 ///
796 /// ```rust
797 /// # use sqlint::{ast::*, col, visitor::{Visitor, Postgres}};
798 /// # fn main() -> Result<(), sqlint::error::Error> {
799 /// let query = Select::from_table("users").so_that(col!("name").equals(col!("list").all()));
800 /// let (sql, _) = Postgres::build(query)?;
801 /// assert_eq!(r#"SELECT "users".* FROM "users" WHERE "name" = ALL("list")"#, sql);
802 /// # Ok(())
803 /// # }
804 /// ```
805 #[cfg(feature = "postgresql")]
806 fn all(self) -> Compare<'a>;
807
808 /// Compares two expressions with a custom operator.
809 ///
810 /// ```rust
811 /// # use sqlint::{ast::*, visitor::{Visitor, Sqlite}};
812 /// # fn main() -> Result<(), sqlint::error::Error> {
813 /// let query = Select::from_table("users").so_that("foo".compare_raw("ILIKE", "%bar%"));
814 /// let (sql, params) = Sqlite::build(query)?;
815 ///
816 /// assert_eq!("SELECT `users`.* FROM `users` WHERE `foo` ILIKE ?", sql);
817 ///
818 /// assert_eq!(vec![
819 /// Value::from("%bar%"),
820 /// ], params);
821 ///
822 /// # Ok(())
823 /// # }
824 /// ```
825 fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
826 where
827 T: Into<Cow<'a, str>>,
828 V: Into<Expression<'a>>;
829}
830
831impl<'a, U> Comparable<'a> for U
832where
833 U: Into<Column<'a>>,
834{
835 fn equals<T>(self, comparison: T) -> Compare<'a>
836 where
837 T: Into<Expression<'a>>,
838 {
839 let col: Column<'a> = self.into();
840 let val: Expression<'a> = col.into();
841
842 val.equals(comparison)
843 }
844
845 fn not_equals<T>(self, comparison: T) -> Compare<'a>
846 where
847 T: Into<Expression<'a>>,
848 {
849 let col: Column<'a> = self.into();
850 let val: Expression<'a> = col.into();
851 val.not_equals(comparison)
852 }
853
854 fn less_than<T>(self, comparison: T) -> Compare<'a>
855 where
856 T: Into<Expression<'a>>,
857 {
858 let col: Column<'a> = self.into();
859 let val: Expression<'a> = col.into();
860 val.less_than(comparison)
861 }
862
863 fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
864 where
865 T: Into<Expression<'a>>,
866 {
867 let col: Column<'a> = self.into();
868 let val: Expression<'a> = col.into();
869 val.less_than_or_equals(comparison)
870 }
871
872 fn greater_than<T>(self, comparison: T) -> Compare<'a>
873 where
874 T: Into<Expression<'a>>,
875 {
876 let col: Column<'a> = self.into();
877 let val: Expression<'a> = col.into();
878 val.greater_than(comparison)
879 }
880
881 fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
882 where
883 T: Into<Expression<'a>>,
884 {
885 let col: Column<'a> = self.into();
886 let val: Expression<'a> = col.into();
887 val.greater_than_or_equals(comparison)
888 }
889
890 fn in_selection<T>(self, selection: T) -> Compare<'a>
891 where
892 T: Into<Expression<'a>>,
893 {
894 let col: Column<'a> = self.into();
895 let val: Expression<'a> = col.into();
896 val.in_selection(selection)
897 }
898
899 fn not_in_selection<T>(self, selection: T) -> Compare<'a>
900 where
901 T: Into<Expression<'a>>,
902 {
903 let col: Column<'a> = self.into();
904 let val: Expression<'a> = col.into();
905 val.not_in_selection(selection)
906 }
907
908 fn like<T>(self, pattern: T) -> Compare<'a>
909 where
910 T: Into<Expression<'a>>,
911 {
912 let col: Column<'a> = self.into();
913 let val: Expression<'a> = col.into();
914 val.like(pattern)
915 }
916
917 fn not_like<T>(self, pattern: T) -> Compare<'a>
918 where
919 T: Into<Expression<'a>>,
920 {
921 let col: Column<'a> = self.into();
922 let val: Expression<'a> = col.into();
923 val.not_like(pattern)
924 }
925
926 #[allow(clippy::wrong_self_convention)]
927 fn is_null(self) -> Compare<'a> {
928 let col: Column<'a> = self.into();
929 let val: Expression<'a> = col.into();
930 val.is_null()
931 }
932
933 #[allow(clippy::wrong_self_convention)]
934 fn is_not_null(self) -> Compare<'a> {
935 let col: Column<'a> = self.into();
936 let val: Expression<'a> = col.into();
937 val.is_not_null()
938 }
939
940 fn between<T, V>(self, left: T, right: V) -> Compare<'a>
941 where
942 T: Into<Expression<'a>>,
943 V: Into<Expression<'a>>,
944 {
945 let col: Column<'a> = self.into();
946 let val: Expression<'a> = col.into();
947 val.between(left, right)
948 }
949
950 fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
951 where
952 T: Into<Expression<'a>>,
953 V: Into<Expression<'a>>,
954 {
955 let col: Column<'a> = self.into();
956 let val: Expression<'a> = col.into();
957 val.not_between(left, right)
958 }
959
960 fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
961 where
962 T: Into<Cow<'a, str>>,
963 V: Into<Expression<'a>>,
964 {
965 let left: Column<'a> = self.into();
966 let left: Expression<'a> = left.into();
967 let right: Expression<'a> = right.into();
968
969 left.compare_raw(raw_comparator.into(), right)
970 }
971
972 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
973 fn json_array_contains<T>(self, item: T) -> Compare<'a>
974 where
975 T: Into<Expression<'a>>,
976 {
977 let col: Column<'a> = self.into();
978 let val: Expression<'a> = col.into();
979
980 val.json_array_contains(item)
981 }
982
983 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
984 fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
985 where
986 T: Into<Expression<'a>>,
987 {
988 let col: Column<'a> = self.into();
989 let val: Expression<'a> = col.into();
990
991 val.json_array_not_contains(item)
992 }
993
994 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
995 fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
996 where
997 T: Into<Expression<'a>>,
998 {
999 let col: Column<'a> = self.into();
1000 let val: Expression<'a> = col.into();
1001
1002 val.json_array_begins_with(item)
1003 }
1004
1005 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
1006 fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
1007 where
1008 T: Into<Expression<'a>>,
1009 {
1010 let col: Column<'a> = self.into();
1011 let val: Expression<'a> = col.into();
1012
1013 val.json_array_not_begins_with(item)
1014 }
1015
1016 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
1017 fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
1018 where
1019 T: Into<Expression<'a>>,
1020 {
1021 let col: Column<'a> = self.into();
1022 let val: Expression<'a> = col.into();
1023
1024 val.json_array_ends_into(item)
1025 }
1026
1027 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
1028 fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
1029 where
1030 T: Into<Expression<'a>>,
1031 {
1032 let col: Column<'a> = self.into();
1033 let val: Expression<'a> = col.into();
1034
1035 val.json_array_not_ends_into(item)
1036 }
1037
1038 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
1039 fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
1040 where
1041 T: Into<JsonType<'a>>,
1042 {
1043 let col: Column<'a> = self.into();
1044 let val: Expression<'a> = col.into();
1045
1046 val.json_type_equals(json_type)
1047 }
1048
1049 #[cfg(all(feature = "json", any(feature = "postgresql", feature = "mysql")))]
1050 fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
1051 where
1052 T: Into<JsonType<'a>>,
1053 {
1054 let col: Column<'a> = self.into();
1055 let val: Expression<'a> = col.into();
1056
1057 val.json_type_not_equals(json_type)
1058 }
1059
1060 #[cfg(feature = "postgresql")]
1061 fn matches<T>(self, query: T) -> Compare<'a>
1062 where
1063 T: Into<Cow<'a, str>>,
1064 {
1065 let col: Column<'a> = self.into();
1066 let val: Expression<'a> = col.into();
1067
1068 val.matches(query)
1069 }
1070
1071 #[cfg(feature = "postgresql")]
1072 fn not_matches<T>(self, query: T) -> Compare<'a>
1073 where
1074 T: Into<Cow<'a, str>>,
1075 {
1076 let col: Column<'a> = self.into();
1077 let val: Expression<'a> = col.into();
1078
1079 val.not_matches(query)
1080 }
1081
1082 #[cfg(feature = "postgresql")]
1083 fn any(self) -> Compare<'a> {
1084 let col: Column<'a> = self.into();
1085 let val: Expression<'a> = col.into();
1086
1087 val.any()
1088 }
1089
1090 #[cfg(feature = "postgresql")]
1091 fn all(self) -> Compare<'a> {
1092 let col: Column<'a> = self.into();
1093 let val: Expression<'a> = col.into();
1094
1095 val.all()
1096 }
1097}