diesel/pg/expression/expression_methods.rs
1//! PostgreSQL specific expression methods
2
3pub(in crate::pg) use self::private::{
4 ArrayOrNullableArray, CombinedAllNullableValue, InetOrCidr, JsonIndex, JsonOrNullableJson,
5 JsonOrNullableJsonOrJsonbOrNullableJsonb, JsonRemoveIndex, JsonbOrNullableJsonb,
6 MaybeNullableValue, MultirangeOrNullableMultirange, MultirangeOrRangeMaybeNullable,
7 RangeOrMultirange, RangeOrNullableRange, RecordOrNullableRecord, TextArrayOrNullableTextArray,
8 TextOrNullableText,
9};
10use super::date_and_time::{AtTimeZone, DateTimeLike};
11use super::operators::*;
12use crate::dsl;
13use crate::expression::grouped::Grouped;
14use crate::expression::operators::{Asc, Concat, Desc, Like, NotLike};
15use crate::expression::{AsExpression, Expression, IntoSql, TypedExpressionType};
16use crate::pg::expression::expression_methods::private::BinaryOrNullableBinary;
17use crate::sql_types::{Array, Inet, Integer, Range, SqlType, Text, VarChar};
18use crate::EscapeExpressionMethods;
19
20/// PostgreSQL specific methods which are present on all expressions.
21#[cfg(feature = "postgres_backend")]
22pub trait PgExpressionMethods: Expression + Sized {
23 /// Creates a PostgreSQL `IS NOT DISTINCT FROM` expression.
24 ///
25 /// This behaves identically to the `=` operator, except that `NULL` is
26 /// treated as a normal value.
27 ///
28 /// # Example
29 ///
30 /// ```rust
31 /// # include!("../../doctest_setup.rs");
32 /// #
33 /// # fn main() {
34 /// # use schema::users::dsl::*;
35 /// # let connection = &mut establish_connection();
36 /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
37 /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
38 /// assert_eq!(Ok(2), distinct.first(connection));
39 /// assert_eq!(Ok(1), not_distinct.first(connection));
40 /// # }
41 /// ```
42 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
43 fn is_not_distinct_from<T>(self, other: T) -> dsl::IsNotDistinctFrom<Self, T>
44 where
45 Self::SqlType: SqlType,
46 T: AsExpression<Self::SqlType>,
47 {
48 Grouped(IsNotDistinctFrom::new(self, other.as_expression()))
49 }
50
51 /// Creates a PostgreSQL `IS DISTINCT FROM` expression.
52 ///
53 /// This behaves identically to the `!=` operator, except that `NULL` is
54 /// treated as a normal value.
55 ///
56 /// # Example
57 ///
58 /// ```rust
59 /// # include!("../../doctest_setup.rs");
60 /// #
61 /// # fn main() {
62 /// # use schema::users::dsl::*;
63 /// # let connection = &mut establish_connection();
64 /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
65 /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
66 /// assert_eq!(Ok(2), distinct.first(connection));
67 /// assert_eq!(Ok(1), not_distinct.first(connection));
68 /// # }
69 /// ```
70 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
71 fn is_distinct_from<T>(self, other: T) -> dsl::IsDistinctFrom<Self, T>
72 where
73 Self::SqlType: SqlType,
74 T: AsExpression<Self::SqlType>,
75 {
76 Grouped(IsDistinctFrom::new(self, other.as_expression()))
77 }
78
79 /// Creates a PostgreSQL `<@` expression.
80 ///
81 /// This operator returns true whether a element is contained by a range
82 ///
83 /// This operator evaluates to true for the following cases:
84 ///
85 /// ```text
86 /// self: |
87 /// other: [-----]
88 /// ```
89 ///
90 /// ```text
91 /// self: |
92 /// other: [----]
93 /// ```
94 ///
95 /// ```text
96 /// self: |
97 /// other: [----]
98 /// ```
99 ///
100 /// This operator evaluates to false for the following cases:
101 ///
102 /// ```text
103 /// self: |
104 /// other: [-----]
105 /// ```
106 ///
107 /// ```text
108 /// self: |
109 /// other: [----]
110 /// ```
111 ///
112 /// ```text
113 /// self: |
114 /// other: [----)
115 /// ```
116 ///
117 /// # Example
118 ///
119 /// ```rust
120 /// # include!("../../doctest_setup.rs");
121 /// #
122 /// # table! {
123 /// # posts {
124 /// # id -> Integer,
125 /// # versions -> Range<Integer>,
126 /// # }
127 /// # }
128 /// #
129 /// # fn main() {
130 /// # run_test().unwrap();
131 /// # }
132 /// #
133 /// # fn run_test() -> QueryResult<()> {
134 /// # use std::collections::Bound;
135 /// # use diesel::dsl::int4range;
136 /// # use diesel::sql_types::Integer;
137 /// #
138 /// # let conn = &mut establish_connection();
139 /// #
140 /// let my_range = int4range(
141 /// 1,
142 /// 5,
143 /// diesel::sql_types::RangeBound::LowerBoundInclusiveUpperBoundExclusive,
144 /// );
145 ///
146 /// let (first, second) = diesel::select((
147 /// 4.into_sql::<Integer>().is_contained_by_range(my_range),
148 /// 10.into_sql::<Integer>().is_contained_by_range(my_range),
149 /// ))
150 /// .get_result::<(bool, bool)>(conn)?;
151 ///
152 /// assert_eq!(first, true);
153 /// assert_eq!(second, false);
154 /// #
155 /// # Ok(())
156 /// # }
157 /// ```
158 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
159 fn is_contained_by_range<T>(self, other: T) -> dsl::IsContainedByRange<Self, T>
160 where
161 Self::SqlType: SqlType,
162 T: AsExpression<Range<Self::SqlType>>,
163 {
164 Grouped(IsContainedBy::new(self, other.as_expression()))
165 }
166}
167
168impl<T: Expression> PgExpressionMethods for T {}
169
170/// PostgreSQL specific methods present on timestamp expressions.
171#[cfg(feature = "postgres_backend")]
172pub trait PgTimestampExpressionMethods: Expression + Sized {
173 /// Creates a PostgreSQL "AT TIME ZONE" expression.
174 ///
175 /// When this is called on a `TIMESTAMP WITHOUT TIME ZONE` column,
176 /// the value will be treated as if were in the given time zone,
177 /// and then converted to UTC.
178 ///
179 /// When this is called on a `TIMESTAMP WITH TIME ZONE` column,
180 /// the value will be converted to the given time zone,
181 /// and then have its time zone information removed.
182 ///
183 /// # Example
184 ///
185 /// ```rust
186 /// # include!("../../doctest_setup.rs");
187 /// #
188 /// # table! {
189 /// # timestamps (timestamp) {
190 /// # timestamp -> Timestamp,
191 /// # }
192 /// # }
193 /// #
194 /// # fn main() {
195 /// # run_test().unwrap();
196 /// # }
197 /// #
198 /// # #[cfg(all(feature = "postgres", feature = "chrono"))]
199 /// # fn run_test() -> QueryResult<()> {
200 /// # use self::timestamps::dsl::*;
201 /// # use chrono::*;
202 /// # let connection = &mut establish_connection();
203 /// # diesel::sql_query("CREATE TABLE timestamps (\"timestamp\"
204 /// # timestamp NOT NULL)").execute(connection)?;
205 /// let christmas_morning = NaiveDate::from_ymd(2017, 12, 25).and_hms(8, 0, 0);
206 /// diesel::insert_into(timestamps)
207 /// .values(timestamp.eq(christmas_morning))
208 /// .execute(connection)?;
209 ///
210 /// let utc_time = timestamps
211 /// .select(timestamp.at_time_zone("UTC"))
212 /// .first(connection)?;
213 /// assert_eq!(christmas_morning, utc_time);
214 ///
215 /// let eastern_time = timestamps
216 /// .select(timestamp.at_time_zone("EST"))
217 /// .first(connection)?;
218 /// let five_hours_later = christmas_morning + Duration::hours(5);
219 /// assert_eq!(five_hours_later, eastern_time);
220 /// # Ok(())
221 /// # }
222 /// #
223 /// # #[cfg(not(all(feature = "postgres", feature = "chrono")))]
224 /// # fn run_test() -> QueryResult<()> {
225 /// # Ok(())
226 /// # }
227 /// ```
228 fn at_time_zone<T>(self, timezone: T) -> dsl::AtTimeZone<Self, T>
229 where
230 T: AsExpression<VarChar>,
231 {
232 Grouped(AtTimeZone::new(self, timezone.as_expression()))
233 }
234}
235
236impl<T: Expression> PgTimestampExpressionMethods for T where T::SqlType: DateTimeLike {}
237
238/// PostgreSQL specific methods present on array expressions.
239#[cfg(feature = "postgres_backend")]
240pub trait PgArrayExpressionMethods: Expression + Sized {
241 /// Creates a PostgreSQL `&&` expression.
242 ///
243 /// This operator returns whether two arrays have common elements.
244 ///
245 /// # Example
246 ///
247 /// ```rust
248 /// # include!("../../doctest_setup.rs");
249 /// #
250 /// # table! {
251 /// # posts {
252 /// # id -> Integer,
253 /// # tags -> Array<VarChar>,
254 /// # }
255 /// # }
256 /// #
257 /// # fn main() {
258 /// # run_test().unwrap();
259 /// # }
260 /// #
261 /// # fn run_test() -> QueryResult<()> {
262 /// # use self::posts::dsl::*;
263 /// # let conn = &mut establish_connection();
264 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
265 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
266 /// # .execute(conn)
267 /// # .unwrap();
268 /// #
269 /// diesel::insert_into(posts)
270 /// .values(&vec![
271 /// tags.eq(vec!["cool", "awesome"]),
272 /// tags.eq(vec!["awesome", "great"]),
273 /// tags.eq(vec!["cool", "great"]),
274 /// ])
275 /// .execute(conn)?;
276 ///
277 /// let data = posts.select(id)
278 /// .filter(tags.overlaps_with(vec!["horrid", "cool"]))
279 /// .load::<i32>(conn)?;
280 /// assert_eq!(vec![1, 3], data);
281 ///
282 /// let data = posts.select(id)
283 /// .filter(tags.overlaps_with(vec!["cool", "great"]))
284 /// .load::<i32>(conn)?;
285 /// assert_eq!(vec![1, 2, 3], data);
286 ///
287 /// let data = posts.select(id)
288 /// .filter(tags.overlaps_with(vec!["horrid"]))
289 /// .load::<i32>(conn)?;
290 /// assert!(data.is_empty());
291 /// # Ok(())
292 /// # }
293 /// ```
294 fn overlaps_with<T>(self, other: T) -> dsl::OverlapsWith<Self, T>
295 where
296 Self::SqlType: SqlType,
297 T: AsExpression<Self::SqlType>,
298 {
299 Grouped(OverlapsWith::new(self, other.as_expression()))
300 }
301
302 /// Creates a PostgreSQL `@>` expression.
303 ///
304 /// This operator returns whether an array contains another array.
305 ///
306 /// # Example
307 ///
308 /// ```rust
309 /// # include!("../../doctest_setup.rs");
310 /// #
311 /// # table! {
312 /// # posts {
313 /// # id -> Integer,
314 /// # tags -> Array<VarChar>,
315 /// # }
316 /// # }
317 /// #
318 /// # fn main() {
319 /// # run_test().unwrap();
320 /// # }
321 /// #
322 /// # fn run_test() -> QueryResult<()> {
323 /// # use self::posts::dsl::*;
324 /// # let conn = &mut establish_connection();
325 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
326 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
327 /// # .execute(conn)
328 /// # .unwrap();
329 /// #
330 /// diesel::insert_into(posts)
331 /// .values(tags.eq(vec!["cool", "awesome"]))
332 /// .execute(conn)?;
333 ///
334 /// let cool_posts = posts.select(id)
335 /// .filter(tags.contains(vec!["cool"]))
336 /// .load::<i32>(conn)?;
337 /// assert_eq!(vec![1], cool_posts);
338 ///
339 /// let amazing_posts = posts.select(id)
340 /// .filter(tags.contains(vec!["cool", "amazing"]))
341 /// .load::<i32>(conn)?;
342 /// assert!(amazing_posts.is_empty());
343 /// # Ok(())
344 /// # }
345 /// ```
346 fn contains<T>(self, other: T) -> dsl::Contains<Self, T>
347 where
348 Self::SqlType: SqlType,
349 T: AsExpression<Self::SqlType>,
350 {
351 Grouped(Contains::new(self, other.as_expression()))
352 }
353
354 /// Creates a PostgreSQL `<@` expression.
355 ///
356 /// This operator returns whether an array is contained by another array.
357 /// `foo.contains(bar)` is the same as `bar.is_contained_by(foo)`
358 ///
359 /// # Example
360 ///
361 /// ```rust
362 /// # include!("../../doctest_setup.rs");
363 /// #
364 /// # table! {
365 /// # posts {
366 /// # id -> Integer,
367 /// # tags -> Array<VarChar>,
368 /// # }
369 /// # }
370 /// #
371 /// # fn main() {
372 /// # run_test().unwrap();
373 /// # }
374 /// #
375 /// # fn run_test() -> QueryResult<()> {
376 /// # use self::posts::dsl::*;
377 /// # let conn = &mut establish_connection();
378 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
379 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
380 /// # .execute(conn)
381 /// # .unwrap();
382 /// #
383 /// diesel::insert_into(posts)
384 /// .values(tags.eq(vec!["cool", "awesome"]))
385 /// .execute(conn)?;
386 ///
387 /// let data = posts.select(id)
388 /// .filter(tags.is_contained_by(vec!["cool", "awesome", "amazing"]))
389 /// .load::<i32>(conn)?;
390 /// assert_eq!(vec![1], data);
391 ///
392 /// let data = posts.select(id)
393 /// .filter(tags.is_contained_by(vec!["cool"]))
394 /// .load::<i32>(conn)?;
395 /// assert!(data.is_empty());
396 /// # Ok(())
397 /// # }
398 /// ```
399 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
400 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedBy<Self, T>
401 where
402 Self::SqlType: SqlType,
403 T: AsExpression<Self::SqlType>,
404 {
405 Grouped(IsContainedBy::new(self, other.as_expression()))
406 }
407 /// Indexes a PostgreSQL array.
408 ///
409 /// This operator indexes in to an array to access a single element.
410 ///
411 /// Note that PostgreSQL arrays are 1-indexed, so `foo.index(1)` is the
412 /// first element in the array.
413 ///
414 /// # Example
415 ///
416 /// ```rust
417 /// # include!("../../doctest_setup.rs");
418 /// #
419 /// # table! {
420 /// # posts {
421 /// # id -> Integer,
422 /// # tags -> Array<VarChar>,
423 /// # }
424 /// # }
425 /// #
426 /// # fn main() {
427 /// # run_test().unwrap();
428 /// # }
429 /// #
430 /// # fn run_test() -> QueryResult<()> {
431 /// # use self::posts::dsl::*;
432 /// # let conn = &mut establish_connection();
433 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
434 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
435 /// # .execute(conn)
436 /// # .unwrap();
437 /// #
438 /// diesel::insert_into(posts)
439 /// .values(&vec![
440 /// tags.eq(vec!["cool", "awesome"]),
441 /// tags.eq(vec!["splendid", "marvellous"]),
442 /// ])
443 /// .execute(conn)?;
444 ///
445 /// let data = posts.select(tags.index(id))
446 /// .load::<String>(conn)?;
447 /// assert_eq!(vec!["cool", "marvellous"], data);
448 ///
449 /// let data = posts.select(id)
450 /// .filter(tags.index(1).eq("splendid"))
451 /// .load::<i32>(conn)?;
452 /// assert_eq!(vec![2], data);
453 /// # Ok(())
454 /// # }
455 /// ```
456 fn index<T>(self, other: T) -> dsl::Index<Self, T>
457 where
458 Self::SqlType: SqlType,
459 T: AsExpression<Integer>,
460 {
461 ArrayIndex::new(self, other.as_expression())
462 }
463
464 /// Creates a PostgreSQL `||` expression.
465 ///
466 /// This operator concatenates two Array values and returns Array value
467 ///
468 /// # Example
469 ///
470 /// ```rust
471 /// # include!("../../doctest_setup.rs");
472 /// #
473 /// # table! {
474 /// # posts {
475 /// # id -> Integer,
476 /// # tags -> Array<VarChar>,
477 /// # }
478 /// # }
479 /// #
480 /// # fn main() {
481 /// # run_test().unwrap();
482 /// # }
483 /// #
484 /// # fn run_test() -> QueryResult<()> {
485 /// # use self::posts::dsl::*;
486 /// # let conn = &mut establish_connection();
487 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
488 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
489 /// # .execute(conn)
490 /// # .unwrap();
491 /// #
492 /// diesel::insert_into(posts)
493 /// .values(tags.eq(vec!["cool", "awesome"]))
494 /// .execute(conn)?;
495 ///
496 /// let res = posts.select(tags.concat(vec!["amazing"])).load::<Vec<String>>(conn)?;
497 /// let expected_tags = vec!["cool", "awesome", "amazing"];
498 /// assert_eq!(expected_tags, res[0]);
499 /// # Ok(())
500 /// # }
501 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
502 where
503 Self::SqlType: SqlType,
504 T: AsExpression<Self::SqlType>,
505 {
506 Grouped(Concat::new(self, other.as_expression()))
507 }
508}
509
510impl<T> PgArrayExpressionMethods for T
511where
512 T: Expression,
513 T::SqlType: ArrayOrNullableArray,
514{
515}
516
517/// PostgreSQL expression methods related to sorting.
518///
519/// This trait is only implemented for `Asc` and `Desc`. Although `.asc` is
520/// implicit if no order is given, you will need to call `.asc()` explicitly in
521/// order to call these methods.
522#[cfg(feature = "postgres_backend")]
523pub trait PgSortExpressionMethods: Sized {
524 /// Specify that nulls should come before other values in this ordering.
525 ///
526 /// Normally, nulls come last when sorting in ascending order and first
527 /// when sorting in descending order.
528 ///
529 /// # Example
530 ///
531 /// ```rust
532 /// # include!("../../doctest_setup.rs");
533 /// #
534 /// # table! {
535 /// # nullable_numbers (nullable_number) {
536 /// # nullable_number -> Nullable<Integer>,
537 /// # }
538 /// # }
539 /// #
540 /// # fn main() {
541 /// # run_test().unwrap();
542 /// # }
543 /// #
544 /// # fn run_test() -> QueryResult<()> {
545 /// # use self::nullable_numbers::dsl::*;
546 /// # let connection = &mut connection_no_data();
547 /// # diesel::sql_query("CREATE TABLE nullable_numbers (nullable_number INTEGER)").execute(connection)?;
548 /// diesel::insert_into(nullable_numbers)
549 /// .values(&vec![
550 /// nullable_number.eq(None),
551 /// nullable_number.eq(Some(1)),
552 /// nullable_number.eq(Some(2)),
553 /// ])
554 /// .execute(connection)?;
555 ///
556 /// let asc_default_nulls = nullable_numbers.select(nullable_number)
557 /// .order(nullable_number.asc())
558 /// .load::<Option<i32>>(connection)?;
559 /// assert_eq!(vec![Some(1), Some(2), None], asc_default_nulls);
560 ///
561 /// let asc_nulls_first = nullable_numbers.select(nullable_number)
562 /// .order(nullable_number.asc().nulls_first())
563 /// .load::<Option<i32>>(connection)?;
564 /// assert_eq!(vec![None, Some(1), Some(2)], asc_nulls_first);
565 /// # Ok(())
566 /// # }
567 /// ```
568 fn nulls_first(self) -> dsl::NullsFirst<Self> {
569 NullsFirst::new(self)
570 }
571
572 /// Specify that nulls should come after other values in this ordering.
573 ///
574 /// Normally, nulls come last when sorting in ascending order and first
575 /// when sorting in descending order.
576 ///
577 /// # Example
578 ///
579 /// ```rust
580 /// # include!("../../doctest_setup.rs");
581 /// #
582 /// # table! {
583 /// # nullable_numbers (nullable_number) {
584 /// # nullable_number -> Nullable<Integer>,
585 /// # }
586 /// # }
587 /// #
588 /// # fn main() {
589 /// # run_test().unwrap();
590 /// # }
591 /// #
592 /// # fn run_test() -> QueryResult<()> {
593 /// # use self::nullable_numbers::dsl::*;
594 /// # let connection = &mut connection_no_data();
595 /// # diesel::sql_query("CREATE TABLE nullable_numbers (nullable_number INTEGER)").execute(connection)?;
596 /// diesel::insert_into(nullable_numbers)
597 /// .values(&vec![
598 /// nullable_number.eq(None),
599 /// nullable_number.eq(Some(1)),
600 /// nullable_number.eq(Some(2)),
601 /// ])
602 /// .execute(connection)?;
603 ///
604 /// let desc_default_nulls = nullable_numbers.select(nullable_number)
605 /// .order(nullable_number.desc())
606 /// .load::<Option<i32>>(connection)?;
607 /// assert_eq!(vec![None, Some(2), Some(1)], desc_default_nulls);
608 ///
609 /// let desc_nulls_last = nullable_numbers.select(nullable_number)
610 /// .order(nullable_number.desc().nulls_last())
611 /// .load::<Option<i32>>(connection)?;
612 /// assert_eq!(vec![Some(2), Some(1), None], desc_nulls_last);
613 /// # Ok(())
614 /// # }
615 /// ```
616 fn nulls_last(self) -> dsl::NullsLast<Self> {
617 NullsLast::new(self)
618 }
619}
620
621impl<T> PgSortExpressionMethods for Asc<T> {}
622impl<T> PgSortExpressionMethods for Desc<T> {}
623
624/// PostgreSQL specific methods present on text expressions.
625#[cfg(feature = "postgres_backend")]
626pub trait PgTextExpressionMethods: Expression + Sized {
627 /// Creates a PostgreSQL `ILIKE` expression
628 ///
629 /// # Example
630 ///
631 /// ```rust
632 /// # include!("../../doctest_setup.rs");
633 /// #
634 /// # fn main() {
635 /// # run_test().unwrap();
636 /// # }
637 /// #
638 /// # fn run_test() -> QueryResult<()> {
639 /// # use schema::animals::dsl::*;
640 /// # let connection = &mut establish_connection();
641 /// let starts_with_s = animals
642 /// .select(species)
643 /// .filter(name.ilike("s%").or(species.ilike("s%")))
644 /// .get_results::<String>(connection)?;
645 /// assert_eq!(vec!["spider"], starts_with_s);
646 /// # Ok(())
647 /// # }
648 /// ```
649 fn ilike<T>(self, other: T) -> dsl::ILike<Self, T>
650 where
651 T: AsExpression<Text>,
652 {
653 Grouped(ILike::new(self, other.as_expression()))
654 }
655
656 /// Creates a PostgreSQL `NOT ILIKE` expression
657 ///
658 /// # Example
659 ///
660 /// ```rust
661 /// # include!("../../doctest_setup.rs");
662 /// #
663 /// # fn main() {
664 /// # run_test().unwrap();
665 /// # }
666 /// #
667 /// # fn run_test() -> QueryResult<()> {
668 /// # use schema::animals::dsl::*;
669 /// # let connection = &mut establish_connection();
670 /// let doesnt_start_with_s = animals
671 /// .select(species)
672 /// .filter(name.not_ilike("s%").and(species.not_ilike("s%")))
673 /// .get_results::<String>(connection)?;
674 /// assert_eq!(vec!["dog"], doesnt_start_with_s);
675 /// # Ok(())
676 /// # }
677 /// ```
678 fn not_ilike<T>(self, other: T) -> dsl::NotILike<Self, T>
679 where
680 T: AsExpression<Text>,
681 {
682 Grouped(NotILike::new(self, other.as_expression()))
683 }
684
685 /// Creates a PostgreSQL `SIMILAR TO` expression
686 ///
687 /// # Example
688 /// ```
689 /// # include!("../../doctest_setup.rs");
690 /// #
691 /// # fn main() {
692 /// # run_test().unwrap();
693 /// # }
694 /// #
695 /// # fn run_test() -> QueryResult<()> {
696 /// # use schema::animals::dsl::*;
697 /// # let connection = &mut establish_connection();
698 /// let starts_with_s = animals
699 /// .select(species)
700 /// .filter(name.similar_to("s%").or(species.similar_to("s%")))
701 /// .get_results::<String>(connection)?;
702 /// assert_eq!(vec!["spider"], starts_with_s);
703 /// # Ok(())
704 /// # }
705 /// ```
706 fn similar_to<T>(self, other: T) -> dsl::SimilarTo<Self, T>
707 where
708 T: AsExpression<Text>,
709 {
710 Grouped(SimilarTo::new(self, other.as_expression()))
711 }
712
713 /// Creates a PostgreSQL `NOT SIMILAR TO` expression
714 ///
715 /// # Example
716 /// ```
717 /// # include!("../../doctest_setup.rs");
718 /// #
719 /// # fn main() {
720 /// # run_test().unwrap();
721 /// # }
722 /// #
723 /// # fn run_test() -> QueryResult<()> {
724 /// # use schema::animals::dsl::*;
725 /// # let connection = &mut establish_connection();
726 /// let doesnt_start_with_s = animals
727 /// .select(species)
728 /// .filter(name.not_similar_to("s%").and(species.not_similar_to("s%")))
729 /// .get_results::<String>(connection)?;
730 /// assert_eq!(vec!["dog"], doesnt_start_with_s);
731 /// # Ok(())
732 /// # }
733 /// ```
734 fn not_similar_to<T>(self, other: T) -> dsl::NotSimilarTo<Self, T>
735 where
736 T: AsExpression<Text>,
737 {
738 Grouped(NotSimilarTo::new(self, other.as_expression()))
739 }
740
741 /// Creates a PostgreSQL `IS JSON` expression.
742 /// Requires PostgreSQL>=16
743 ///
744 /// This operator returns true whether an object is a valid JSON
745 ///
746 /// # Example
747 ///
748 /// ```rust,no_run
749 /// # include!("../../doctest_setup.rs");
750 /// #
751 /// # fn main() {
752 /// # run_test().unwrap();
753 /// # }
754 /// #
755 /// # fn run_test() -> QueryResult<()> {
756 /// # use std::collections::Bound;
757 /// # use diesel::sql_types::Text;
758 /// #
759 /// # let conn = &mut establish_connection();
760 /// #
761 ///
762 /// let res = diesel::select(("1".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
763 /// assert_eq!(res, true);
764 /// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
765 /// assert_eq!(res, true);
766 /// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_json()))
767 /// .get_result::<bool>(conn)?;
768 /// assert_eq!(res, true);
769 /// let res = diesel::select(("(1,2,3)".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
770 /// assert_eq!(res, false);
771 /// #
772 /// # Ok(())
773 /// # }
774 /// ```
775 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
776 fn is_json(self) -> dsl::IsJson<Self> {
777 IsJson::new(self)
778 }
779
780 /// Creates a PostgreSQL `IS NOT JSON` expression.
781 /// Requires PostgreSQL>=16
782 ///
783 /// This operator returns true whether an object is not a valid JSON
784 ///
785 /// # Example
786 ///
787 /// ```rust,no_run
788 /// # include!("../../doctest_setup.rs");
789 /// #
790 /// # fn main() {
791 /// # run_test().unwrap();
792 /// # }
793 /// #
794 /// # fn run_test() -> QueryResult<()> {
795 /// # use std::collections::Bound;
796 /// # use diesel::sql_types::Text;
797 /// #
798 /// # let conn = &mut establish_connection();
799 /// #
800 ///
801 /// let res = diesel::select(("1".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
802 /// assert_eq!(res, false);
803 /// let res =
804 /// diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
805 /// assert_eq!(res, false);
806 /// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_not_json()))
807 /// .get_result::<bool>(conn)?;
808 /// assert_eq!(res, false);
809 /// let res =
810 /// diesel::select(("(1,2,3)".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
811 /// assert_eq!(res, true);
812 /// #
813 /// # Ok(())
814 /// # }
815 /// ```
816 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
817 fn is_not_json(self) -> dsl::IsNotJson<Self> {
818 IsNotJson::new(self)
819 }
820
821 /// Creates a PostgreSQL `IS JSON OBJECT` expression.
822 /// Requires PostgreSQL>=16
823 ///
824 /// This operator returns true whether an object is a valid JSON
825 ///
826 /// # Example
827 ///
828 /// ```rust,no_run
829 /// # include!("../../doctest_setup.rs");
830 /// #
831 /// # fn main() {
832 /// # run_test().unwrap();
833 /// # }
834 /// #
835 /// # fn run_test() -> QueryResult<()> {
836 /// # use std::collections::Bound;
837 /// # use diesel::sql_types::Text;
838 /// #
839 /// # let conn = &mut establish_connection();
840 /// #
841 ///
842 /// let res =
843 /// diesel::select(("123".into_sql::<Text>().is_json_object())).get_result::<bool>(conn)?;
844 /// assert_eq!(res, false);
845 /// let res =
846 /// diesel::select(("abc".into_sql::<Text>().is_json_object())).get_result::<bool>(conn)?;
847 /// assert_eq!(res, false);
848 /// let res = diesel::select(
849 /// ("{\"products\": [1,2,3]}"
850 /// .into_sql::<Text>()
851 /// .is_json_object()),
852 /// )
853 /// .get_result::<bool>(conn)?;
854 /// assert_eq!(res, true);
855 /// let res =
856 /// diesel::select(("[1,2,3]".into_sql::<Text>().is_json_object())).get_result::<bool>(conn)?;
857 /// assert_eq!(res, false);
858 /// let res =
859 /// diesel::select(("\"abc\"".into_sql::<Text>().is_json_object())).get_result::<bool>(conn)?;
860 /// assert_eq!(res, false);
861 /// #
862 /// # Ok(())
863 /// # }
864 /// ```
865 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
866 fn is_json_object(self) -> dsl::IsJsonObject<Self> {
867 IsJsonObject::new(self)
868 }
869
870 /// Creates a PostgreSQL `IS NOT JSON OBJECT` expression.
871 /// Requires PostgreSQL>=16
872 ///
873 /// This operator returns true whether an object is not a valid JSON
874 ///
875 /// # Example
876 ///
877 /// ```rust,no_run
878 /// # include!("../../doctest_setup.rs");
879 /// #
880 /// # fn main() {
881 /// # run_test().unwrap();
882 /// # }
883 /// #
884 /// # fn run_test() -> QueryResult<()> {
885 /// # use std::collections::Bound;
886 /// # use diesel::sql_types::Text;
887 /// #
888 /// # let conn = &mut establish_connection();
889 /// #
890 ///
891 /// let res =
892 /// diesel::select(("123".into_sql::<Text>().is_not_json_object())).get_result::<bool>(conn)?;
893 /// assert_eq!(res, true);
894 /// let res =
895 /// diesel::select(("abc".into_sql::<Text>().is_not_json_object())).get_result::<bool>(conn)?;
896 /// assert_eq!(res, true);
897 /// let res = diesel::select(
898 /// ("{\"products\": [1,2,3]}"
899 /// .into_sql::<Text>()
900 /// .is_not_json_object()),
901 /// )
902 /// .get_result::<bool>(conn)?;
903 /// assert_eq!(res, false);
904 /// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json_object()))
905 /// .get_result::<bool>(conn)?;
906 /// assert_eq!(res, true);
907 /// let res = diesel::select(("\"abc\"".into_sql::<Text>().is_not_json_object()))
908 /// .get_result::<bool>(conn)?;
909 /// assert_eq!(res, true);
910 /// #
911 /// # Ok(())
912 /// # }
913 /// ```
914 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
915 fn is_not_json_object(self) -> dsl::IsNotJsonObject<Self> {
916 IsNotJsonObject::new(self)
917 }
918
919 /// Creates a PostgreSQL `IS JSON ARRAY` expression.
920 /// Requires PostgreSQL>=16
921 ///
922 /// This operator returns true whether an object is a valid JSON ARRAY
923 ///
924 /// # Example
925 ///
926 /// ```rust,no_run
927 /// # include!("../../doctest_setup.rs");
928 /// #
929 /// # fn main() {
930 /// # run_test().unwrap();
931 /// # }
932 /// #
933 /// # fn run_test() -> QueryResult<()> {
934 /// # use std::collections::Bound;
935 /// # use diesel::sql_types::Text;
936 /// #
937 /// # let conn = &mut establish_connection();
938 /// #
939 ///
940 /// let res =
941 /// diesel::select(("123".into_sql::<Text>().is_json_array())).get_result::<bool>(conn)?;
942 /// assert_eq!(res, false);
943 /// let res =
944 /// diesel::select(("abc".into_sql::<Text>().is_json_array())).get_result::<bool>(conn)?;
945 /// assert_eq!(res, false);
946 /// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_json_array()))
947 /// .get_result::<bool>(conn)?;
948 /// assert_eq!(res, false);
949 /// let res =
950 /// diesel::select(("[1,2,3]".into_sql::<Text>().is_json_array())).get_result::<bool>(conn)?;
951 /// assert_eq!(res, true);
952 /// let res =
953 /// diesel::select(("\"abc\"".into_sql::<Text>().is_json_array())).get_result::<bool>(conn)?;
954 /// assert_eq!(res, false);
955 /// #
956 /// # Ok(())
957 /// # }
958 /// ```
959 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
960 fn is_json_array(self) -> dsl::IsJsonArray<Self> {
961 IsJsonArray::new(self)
962 }
963
964 /// Creates a PostgreSQL `IS NOT JSON ARRAY` expression.
965 /// Requires PostgreSQL>=16
966 ///
967 /// This operator returns true whether an object is not a valid JSON ARRAY
968 ///
969 /// # Example
970 ///
971 /// ```rust,no_run
972 /// # include!("../../doctest_setup.rs");
973 /// #
974 /// # fn main() {
975 /// # run_test().unwrap();
976 /// # }
977 /// #
978 /// # fn run_test() -> QueryResult<()> {
979 /// # use std::collections::Bound;
980 /// # use diesel::sql_types::Text;
981 /// #
982 /// # let conn = &mut establish_connection();
983 /// #
984 ///
985 /// let res =
986 /// diesel::select(("123".into_sql::<Text>().is_not_json_array())).get_result::<bool>(conn)?;
987 /// assert_eq!(res, true);
988 /// let res =
989 /// diesel::select(("abc".into_sql::<Text>().is_not_json_array())).get_result::<bool>(conn)?;
990 /// assert_eq!(res, true);
991 /// let res = diesel::select(
992 /// ("{\"products\": [1,2,3]}"
993 /// .into_sql::<Text>()
994 /// .is_not_json_array()),
995 /// )
996 /// .get_result::<bool>(conn)?;
997 /// assert_eq!(res, true);
998 /// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json_array()))
999 /// .get_result::<bool>(conn)?;
1000 /// assert_eq!(res, false);
1001 /// let res = diesel::select(("\"abc\"".into_sql::<Text>().is_not_json_array()))
1002 /// .get_result::<bool>(conn)?;
1003 /// assert_eq!(res, true);
1004 /// #
1005 /// # Ok(())
1006 /// # }
1007 /// ```
1008 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1009 fn is_not_json_array(self) -> dsl::IsNotJsonArray<Self> {
1010 IsNotJsonArray::new(self)
1011 }
1012
1013 /// Creates a PostgreSQL `IS JSON SCALAR` expression.
1014 /// Requires PostgreSQL>=16
1015 ///
1016 /// This operator returns true whether an object is a valid JSON SCALAR
1017 ///
1018 /// # Example
1019 ///
1020 /// ```rust,no_run
1021 /// # include!("../../doctest_setup.rs");
1022 /// #
1023 /// # fn main() {
1024 /// # run_test().unwrap();
1025 /// # }
1026 /// #
1027 /// # fn run_test() -> QueryResult<()> {
1028 /// # use std::collections::Bound;
1029 /// # use diesel::sql_types::{Text, Nullable};
1030 /// # use diesel::dsl::sql;
1031 /// #
1032 /// # let conn = &mut establish_connection();
1033 /// #
1034 ///
1035 /// let res =
1036 /// diesel::select(("123".into_sql::<Text>().is_json_scalar())).get_result::<bool>(conn)?;
1037 /// assert_eq!(res, true);
1038 /// let res =
1039 /// diesel::select(("abc".into_sql::<Text>().is_json_scalar())).get_result::<bool>(conn)?;
1040 /// assert_eq!(res, false);
1041 /// let res = diesel::select(
1042 /// ("{\"products\": [1,2,3]}"
1043 /// .into_sql::<Text>()
1044 /// .is_json_scalar()),
1045 /// )
1046 /// .get_result::<bool>(conn)?;
1047 /// assert_eq!(res, false);
1048 /// let res =
1049 /// diesel::select(("[1,2,3]".into_sql::<Text>().is_json_scalar())).get_result::<bool>(conn)?;
1050 /// assert_eq!(res, false);
1051 /// let res =
1052 /// diesel::select(("\"abc\"".into_sql::<Text>().is_json_scalar())).get_result::<bool>(conn)?;
1053 /// assert_eq!(res, true);
1054 /// let res = diesel::select(sql::<Nullable<Text>>("NULL").is_json_scalar())
1055 /// .get_result::<Option<bool>>(conn)?;
1056 /// assert!(res.is_none());
1057 /// # Ok(())
1058 /// # }
1059 /// ```
1060 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1061 fn is_json_scalar(self) -> dsl::IsJsonScalar<Self> {
1062 IsJsonScalar::new(self)
1063 }
1064
1065 /// Creates a PostgreSQL `IS NOT JSON SCALAR` expression.
1066 /// Requires PostgreSQL>=16
1067 ///
1068 /// This operator returns true whether an object is not a valid JSON SCALAR
1069 ///
1070 /// # Example
1071 ///
1072 /// ```rust,no_run
1073 /// # include!("../../doctest_setup.rs");
1074 /// #
1075 /// # fn main() {
1076 /// # run_test().unwrap();
1077 /// # }
1078 /// #
1079 /// # fn run_test() -> QueryResult<()> {
1080 /// # use std::collections::Bound;
1081 /// # use diesel::sql_types::Text;
1082 /// #
1083 /// # let conn = &mut establish_connection();
1084 /// #
1085 ///
1086 /// let res =
1087 /// diesel::select(("123".into_sql::<Text>().is_not_json_scalar())).get_result::<bool>(conn)?;
1088 /// assert_eq!(res, false);
1089 /// let res =
1090 /// diesel::select(("abc".into_sql::<Text>().is_not_json_scalar())).get_result::<bool>(conn)?;
1091 /// assert_eq!(res, true);
1092 /// let res = diesel::select(
1093 /// ("{\"products\": [1,2,3]}"
1094 /// .into_sql::<Text>()
1095 /// .is_not_json_scalar()),
1096 /// )
1097 /// .get_result::<bool>(conn)?;
1098 /// assert_eq!(res, true);
1099 /// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json_scalar()))
1100 /// .get_result::<bool>(conn)?;
1101 /// assert_eq!(res, true);
1102 /// let res = diesel::select(("\"abc\"".into_sql::<Text>().is_not_json_scalar()))
1103 /// .get_result::<bool>(conn)?;
1104 /// assert_eq!(res, false);
1105 /// #
1106 /// # Ok(())
1107 /// # }
1108 /// ```
1109 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1110 fn is_not_json_scalar(self) -> dsl::IsNotJsonScalar<Self> {
1111 IsNotJsonScalar::new(self)
1112 }
1113}
1114
1115impl<T> PgTextExpressionMethods for T
1116where
1117 T: Expression,
1118 T::SqlType: TextOrNullableText,
1119{
1120}
1121
1122impl<T, U> EscapeExpressionMethods for Grouped<ILike<T, U>> {
1123 type TextExpression = ILike<T, U>;
1124
1125 fn escape(self, character: char) -> dsl::Escape<Self> {
1126 Grouped(crate::expression::operators::Escape::new(
1127 self.0,
1128 character.to_string().into_sql::<VarChar>(),
1129 ))
1130 }
1131}
1132
1133impl<T, U> EscapeExpressionMethods for Grouped<NotILike<T, U>> {
1134 type TextExpression = NotILike<T, U>;
1135
1136 fn escape(self, character: char) -> dsl::Escape<Self> {
1137 Grouped(crate::expression::operators::Escape::new(
1138 self.0,
1139 character.to_string().into_sql::<VarChar>(),
1140 ))
1141 }
1142}
1143
1144impl<T, U> EscapeExpressionMethods for Grouped<SimilarTo<T, U>> {
1145 type TextExpression = SimilarTo<T, U>;
1146
1147 fn escape(self, character: char) -> dsl::Escape<Self> {
1148 Grouped(crate::expression::operators::Escape::new(
1149 self.0,
1150 character.to_string().into_sql::<VarChar>(),
1151 ))
1152 }
1153}
1154
1155impl<T, U> EscapeExpressionMethods for Grouped<NotSimilarTo<T, U>> {
1156 type TextExpression = NotSimilarTo<T, U>;
1157
1158 fn escape(self, character: char) -> dsl::Escape<Self> {
1159 Grouped(crate::expression::operators::Escape::new(
1160 self.0,
1161 character.to_string().into_sql::<VarChar>(),
1162 ))
1163 }
1164}
1165
1166/// PostgreSQL specific methods present on range expressions.
1167#[cfg(feature = "postgres_backend")]
1168pub trait PgRangeExpressionMethods: Expression + Sized {
1169 /// Creates a PostgreSQL `@>` expression.
1170 ///
1171 /// This operator returns true whether a range contains an specific element
1172 ///
1173 /// This operator evaluates to true for the following cases:
1174 ///
1175 /// ```text
1176 /// self: [-----]
1177 /// other: |
1178 /// ```
1179 ///
1180 /// ```text
1181 /// self: [----]
1182 /// other: |
1183 /// ```
1184 ///
1185 /// ```text
1186 /// self: [----]
1187 /// other: |
1188 /// ```
1189 ///
1190 /// This operator evaluates to false for the following cases:
1191 ///
1192 /// ```text
1193 /// self: [-----]
1194 /// other: |
1195 /// ```
1196 ///
1197 /// ```text
1198 /// self: [----]
1199 /// other: |
1200 /// ```
1201 ///
1202 /// ```text
1203 /// self: [----)
1204 /// other: |
1205 /// ```
1206 ///
1207 /// # Example
1208 ///
1209 /// ```rust
1210 /// # include!("../../doctest_setup.rs");
1211 /// #
1212 /// # fn main() {
1213 /// # run_test().unwrap();
1214 /// # }
1215 /// #
1216 /// # fn run_test() -> QueryResult<()> {
1217 /// # use diesel::sql_types::{Integer, Range, Multirange};
1218 /// #
1219 /// # let conn = &mut establish_connection();
1220 /// assert!(
1221 /// diesel::select((1..5).into_sql::<Range<Integer>>().contains(4))
1222 /// .first::<bool>(conn)
1223 /// .unwrap()
1224 /// );
1225 /// assert!(
1226 /// !diesel::select((1..5).into_sql::<Range<Integer>>().contains(8))
1227 /// .first::<bool>(conn)
1228 /// .unwrap()
1229 /// );
1230 ///
1231 /// assert!(
1232 /// diesel::select((vec![1..5]).into_sql::<Multirange<Integer>>().contains(4))
1233 /// .first::<bool>(conn)
1234 /// .unwrap()
1235 /// );
1236 /// assert!(
1237 /// !diesel::select((vec![1..5]).into_sql::<Multirange<Integer>>().contains(8))
1238 /// .first::<bool>(conn)
1239 /// .unwrap()
1240 /// );
1241 ///
1242 /// # Ok(())
1243 /// # }
1244 /// ```
1245 fn contains<T>(self, other: T) -> dsl::RangeContains<Self, T>
1246 where
1247 Self::SqlType: RangeOrMultirange,
1248 <Self::SqlType as RangeOrMultirange>::Inner: SqlType + TypedExpressionType,
1249 T: AsExpression<<Self::SqlType as RangeOrMultirange>::Inner>,
1250 {
1251 Grouped(Contains::new(self, other.as_expression()))
1252 }
1253
1254 /// Creates a PostgreSQL `@>` expression.
1255 ///
1256 /// This operator returns true whether a range contains another range
1257 ///
1258 /// This operator evaluates to true for the following cases:
1259 ///
1260 /// ```text
1261 /// self: [-------]
1262 /// other: [--]
1263 /// ```
1264 ///
1265 /// ```text
1266 /// self: [------]
1267 /// other: [------]
1268 /// ```
1269 ///
1270 /// This operator evaluates to false for the following cases:
1271 ///
1272 /// ```text
1273 /// self: [-----]
1274 /// other: [----]
1275 /// ```
1276 ///
1277 /// ```text
1278 /// self: [----]
1279 /// other: [--------]
1280 /// ```
1281 ///
1282 /// ```text
1283 /// self: [----)
1284 /// other: [----]
1285 /// ```
1286 ///
1287 /// # Example
1288 ///
1289 /// ```rust
1290 /// # include!("../../doctest_setup.rs");
1291 /// #
1292 /// # fn main() {
1293 /// # run_test().unwrap();
1294 /// # }
1295 /// #
1296 /// # fn run_test() -> QueryResult<()> {
1297 /// # use diesel::sql_types::{Integer, Range, Multirange};
1298 /// # let conn = &mut establish_connection();
1299 /// assert!(
1300 /// diesel::select((1..5).into_sql::<Range<Integer>>().contains_range(1..5))
1301 /// .first::<bool>(conn)
1302 /// .unwrap()
1303 /// );
1304 /// assert!(
1305 /// !diesel::select((1..5).into_sql::<Range<Integer>>().contains_range(3..7))
1306 /// .first::<bool>(conn)
1307 /// .unwrap()
1308 /// );
1309 ///
1310 /// assert!(diesel::select(
1311 /// vec![1..5]
1312 /// .into_sql::<Multirange<Integer>>()
1313 /// .contains_range(vec![1..5])
1314 /// )
1315 /// .first::<bool>(conn)
1316 /// .unwrap());
1317 /// assert!(!diesel::select(
1318 /// vec![1..5]
1319 /// .into_sql::<Multirange<Integer>>()
1320 /// .contains_range(vec![3..7])
1321 /// )
1322 /// .first::<bool>(conn)
1323 /// .unwrap());
1324 /// # Ok(())
1325 /// # }
1326 /// ```
1327 fn contains_range<T>(self, other: T) -> dsl::ContainsRange<Self, T>
1328 where
1329 Self::SqlType: SqlType,
1330 T: AsExpression<Self::SqlType>,
1331 {
1332 Grouped(Contains::new(self, other.as_expression()))
1333 }
1334
1335 /// Creates a PostgreSQL `<@` expression.
1336 ///
1337 /// This operator returns true whether a range is contained by another range
1338 ///
1339 /// This operator evaluates to true for the following cases:
1340 ///
1341 /// ```text
1342 /// self: [-----]
1343 /// other: [-------]
1344 /// ```
1345 ///
1346 /// ```text
1347 /// self: [----]
1348 /// other: [----]
1349 /// ```
1350 ///
1351 /// This operator evaluates to false for the following cases:
1352 ///
1353 /// ```text
1354 /// self: [------]
1355 /// other: [---]
1356 /// ```
1357 ///
1358 /// ```text
1359 /// self: [----]
1360 /// other: [-----)
1361 /// ```
1362 ///
1363 /// ```text
1364 /// self: [----]
1365 /// other: [----]
1366 /// ```
1367 ///
1368 /// # Example
1369 ///
1370 /// ```rust
1371 /// # include!("../../doctest_setup.rs");
1372 /// #
1373 /// # fn main() {
1374 /// # run_test().unwrap();
1375 /// # }
1376 /// #
1377 /// # fn run_test() -> QueryResult<()> {
1378 /// # use diesel::sql_types::{Integer, Range, Multirange};
1379 /// # let conn = &mut establish_connection();
1380 /// assert!(
1381 /// diesel::select((1..5).into_sql::<Range<Integer>>().is_contained_by(1..5))
1382 /// .first::<bool>(conn)
1383 /// .unwrap()
1384 /// );
1385 /// assert!(
1386 /// !diesel::select((1..5).into_sql::<Range<Integer>>().is_contained_by(3..7))
1387 /// .first::<bool>(conn)
1388 /// .unwrap()
1389 /// );
1390 ///
1391 /// assert!(diesel::select(
1392 /// vec![1..5]
1393 /// .into_sql::<Multirange<Integer>>()
1394 /// .is_contained_by(vec![1..5])
1395 /// )
1396 /// .first::<bool>(conn)
1397 /// .unwrap());
1398 /// assert!(!diesel::select(
1399 /// vec![1..5]
1400 /// .into_sql::<Multirange<Integer>>()
1401 /// .is_contained_by(vec![3..7])
1402 /// )
1403 /// .first::<bool>(conn)
1404 /// .unwrap());
1405 /// # Ok(())
1406 /// # }
1407 /// ```
1408 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1409 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedBy<Self, T>
1410 where
1411 Self::SqlType: SqlType,
1412 T: AsExpression<Self::SqlType>,
1413 {
1414 Grouped(IsContainedBy::new(self, other.as_expression()))
1415 }
1416
1417 /// Creates a PostgreSQL `&&` expression.
1418 ///
1419 /// This operator returns true whether two ranges overlap.
1420 ///
1421 /// This operator evaluates to true for the following cases:
1422 ///
1423 /// ```text
1424 /// self: [-----]
1425 /// other: [-----]
1426 /// ```
1427 ///
1428 /// ```text
1429 /// self: [----]
1430 /// other: [----]
1431 /// ```
1432 ///
1433 /// ```text
1434 /// self: [----]
1435 /// other: [-------]
1436 /// ```
1437 ///
1438 /// ```text
1439 /// self: [----]
1440 /// other: [----]
1441 /// ```
1442 ///
1443 /// ```text
1444 /// self: [----]
1445 /// other: [----)
1446 /// ```
1447 ///
1448 /// This operator evaluates to false for the following cases:
1449 ///
1450 /// ```text
1451 /// self: [-----]
1452 /// other: [-----]
1453 /// ```
1454 ///
1455 /// ```text
1456 /// self: [----]
1457 /// other: [--]
1458 /// ```
1459 ///
1460 /// # Example
1461 ///
1462 /// ```rust
1463 /// # include!("../../doctest_setup.rs");
1464 /// #
1465 /// # fn main() {
1466 /// # run_test().unwrap();
1467 /// # }
1468 /// #
1469 /// # fn run_test() -> QueryResult<()> {
1470 /// # use diesel::sql_types::{Integer, Range, Multirange};
1471 /// # let conn = &mut establish_connection();
1472 /// assert!(
1473 /// diesel::select((1..5).into_sql::<Range<Integer>>().overlaps_with(3..7))
1474 /// .first::<bool>(conn)
1475 /// .unwrap()
1476 /// );
1477 /// assert!(
1478 /// !diesel::select((1..5).into_sql::<Range<Integer>>().overlaps_with(10..15))
1479 /// .first::<bool>(conn)
1480 /// .unwrap()
1481 /// );
1482 ///
1483 /// assert!(diesel::select(
1484 /// vec![1..5]
1485 /// .into_sql::<Multirange<Integer>>()
1486 /// .overlaps_with(vec![3..7])
1487 /// )
1488 /// .first::<bool>(conn)
1489 /// .unwrap());
1490 /// assert!(!diesel::select(
1491 /// vec![1..5]
1492 /// .into_sql::<Multirange<Integer>>()
1493 /// .overlaps_with(vec![10..15])
1494 /// )
1495 /// .first::<bool>(conn)
1496 /// .unwrap());
1497 /// # Ok(())
1498 /// # }
1499 /// ```
1500 fn overlaps_with<T>(self, other: T) -> dsl::OverlapsWith<Self, T>
1501 where
1502 Self::SqlType: SqlType,
1503 T: AsExpression<Self::SqlType>,
1504 {
1505 Grouped(OverlapsWith::new(self, other.as_expression()))
1506 }
1507
1508 /// Creates a PostgreSQL `&<` expression.
1509 ///
1510 /// This operator returns true whether the argument range extend to the right of the current range
1511 ///
1512 /// Postgresql defines "extends" as does not have a lower bound smaller than the lower bound of the
1513 /// self range. That means the right hand side range can overlap parts of the left hand side
1514 /// range or be on the right side of the left hand side range
1515 ///
1516 /// The following constelations evaluate to true:
1517 /// ```text
1518 /// self: [------)
1519 /// other: [----)
1520 /// ```
1521 ///
1522 /// ```text
1523 /// self: [----)
1524 /// other: [----)
1525 /// ```
1526 ///
1527 /// ```text
1528 /// self: [------)
1529 /// other: [------)
1530 /// ```
1531 ///
1532 /// The following constelations evaluate to false:
1533 ///
1534 /// ```text
1535 /// self: [------]
1536 /// other: [----]
1537 /// ```
1538 ///
1539 /// ```text
1540 /// self: [------]
1541 /// other: [----]
1542 /// ```
1543 ///
1544 /// ```text
1545 /// self: [------]
1546 /// other: [------)
1547 /// ```
1548 ///
1549 /// # Example
1550 ///
1551 /// ```rust
1552 /// # include!("../../doctest_setup.rs");
1553 /// #
1554 /// # fn main() {
1555 /// # run_test().unwrap();
1556 /// # }
1557 /// #
1558 /// # fn run_test() -> QueryResult<()> {
1559 /// # use diesel::sql_types::{Integer, Range, Multirange};
1560 /// # let conn = &mut establish_connection();
1561 /// #
1562 /// assert!(diesel::select(
1563 /// (1..20)
1564 /// .into_sql::<Range<Integer>>()
1565 /// .range_extends_right_to(18..20)
1566 /// )
1567 /// .first::<bool>(conn)
1568 /// .unwrap());
1569 /// assert!(diesel::select(
1570 /// (1..20)
1571 /// .into_sql::<Range<Integer>>()
1572 /// .range_extends_right_to(25..30)
1573 /// )
1574 /// .first::<bool>(conn)
1575 /// .unwrap());
1576 /// assert!(!diesel::select(
1577 /// (1..20)
1578 /// .into_sql::<Range<Integer>>()
1579 /// .range_extends_right_to(-10..0)
1580 /// )
1581 /// .first::<bool>(conn)
1582 /// .unwrap());
1583 ///
1584 /// assert!(diesel::select(
1585 /// vec![1..20]
1586 /// .into_sql::<Multirange<Integer>>()
1587 /// .range_extends_right_to(vec![18..20])
1588 /// )
1589 /// .first::<bool>(conn)
1590 /// .unwrap());
1591 /// assert!(diesel::select(
1592 /// vec![1..20]
1593 /// .into_sql::<Multirange<Integer>>()
1594 /// .range_extends_right_to(vec![25..30])
1595 /// )
1596 /// .first::<bool>(conn)
1597 /// .unwrap());
1598 /// assert!(!diesel::select(
1599 /// vec![1..20]
1600 /// .into_sql::<Multirange<Integer>>()
1601 /// .range_extends_right_to(vec![-10..0])
1602 /// )
1603 /// .first::<bool>(conn)
1604 /// .unwrap());
1605 /// # Ok(())
1606 /// # }
1607 /// ```
1608 fn range_extends_right_to<T>(self, other: T) -> dsl::RangeExtendsRightTo<Self, T>
1609 where
1610 Self::SqlType: SqlType,
1611 T: AsExpression<Self::SqlType>,
1612 {
1613 Grouped(ExtendsRightTo::new(self, other.as_expression()))
1614 }
1615
1616 /// Creates a PostgreSQL `&>` expression.
1617 ///
1618 /// This operator returns true whether a range does extend to the left of another
1619 ///
1620 /// Postgresql defines "extends" as does not have a upper bound greater than the upper bound of the
1621 /// self range. That means the right hand side range can overlap parts of the left hand side
1622 /// range or be on the left side of the left hand side range
1623 ///
1624 /// The following constelations evaluate to true:
1625 /// ```text
1626 /// self: [------)
1627 /// other: [----)
1628 /// ```
1629 ///
1630 /// ```text
1631 /// self: [----)
1632 /// other: [----)
1633 /// ```
1634 ///
1635 /// ```text
1636 /// self: [------)
1637 /// other: [------)
1638 /// ```
1639 ///
1640 /// The following constelations evaluate to false:
1641 ///
1642 /// ```text
1643 /// self: [--------]
1644 /// other: [----]
1645 /// ```
1646 ///
1647 /// ```text
1648 /// self: [------]
1649 /// other: [----]
1650 /// ```
1651 ///
1652 /// ```text
1653 /// self: [------]
1654 /// other: (------]
1655 /// ```
1656 ///
1657 /// # Example
1658 ///
1659 /// ```rust
1660 /// # include!("../../doctest_setup.rs");
1661 /// #
1662 /// # fn main() {
1663 /// # run_test().unwrap();
1664 /// # }
1665 /// #
1666 /// # fn run_test() -> QueryResult<()> {
1667 /// # use diesel::sql_types::{Integer, Range, Multirange};
1668 /// # let conn = &mut establish_connection();
1669 /// #
1670 /// assert!(diesel::select(
1671 /// (1..20)
1672 /// .into_sql::<Range<Integer>>()
1673 /// .range_extends_left_to(-10..5)
1674 /// )
1675 /// .first::<bool>(conn)
1676 /// .unwrap());
1677 /// assert!(diesel::select(
1678 /// (1..20)
1679 /// .into_sql::<Range<Integer>>()
1680 /// .range_extends_left_to(-10..-5)
1681 /// )
1682 /// .first::<bool>(conn)
1683 /// .unwrap());
1684 /// assert!(!diesel::select(
1685 /// (1..20)
1686 /// .into_sql::<Range<Integer>>()
1687 /// .range_extends_left_to(25..30)
1688 /// )
1689 /// .first::<bool>(conn)
1690 /// .unwrap());
1691 ///
1692 /// assert!(diesel::select(
1693 /// vec![1..20]
1694 /// .into_sql::<Multirange<Integer>>()
1695 /// .range_extends_left_to(vec![-10..5])
1696 /// )
1697 /// .first::<bool>(conn)
1698 /// .unwrap());
1699 /// assert!(diesel::select(
1700 /// vec![1..20]
1701 /// .into_sql::<Multirange<Integer>>()
1702 /// .range_extends_left_to(vec![-10..-5])
1703 /// )
1704 /// .first::<bool>(conn)
1705 /// .unwrap());
1706 /// assert!(!diesel::select(
1707 /// vec![1..20]
1708 /// .into_sql::<Multirange<Integer>>()
1709 /// .range_extends_left_to(vec![25..30])
1710 /// )
1711 /// .first::<bool>(conn)
1712 /// .unwrap());
1713 /// # Ok(())
1714 /// # }
1715 /// ```
1716 fn range_extends_left_to<T>(self, other: T) -> dsl::RangeExtendsLeftTo<Self, T>
1717 where
1718 Self::SqlType: SqlType,
1719 T: AsExpression<Self::SqlType>,
1720 {
1721 Grouped(ExtendsLeftTo::new(self, other.as_expression()))
1722 }
1723
1724 /// Creates a PostgreSQL `<<` expression.
1725 ///
1726 /// Is the first range strictly left of the second?
1727 ///
1728 /// The following constelations evaluate to true:
1729 /// ```text
1730 /// self: [------)
1731 /// other: [----)
1732 /// ```
1733 ///
1734 /// ```text
1735 /// self: [----)
1736 /// other: [----)
1737 /// ```
1738 ///
1739 /// The following constelations evaluate to false:
1740 ///
1741 /// ```text
1742 /// self: [------]
1743 /// other: [----]
1744 /// ```
1745 ///
1746 /// ```text
1747 /// self: [------]
1748 /// other: [----]
1749 /// ```
1750 ///
1751 /// ```text
1752 /// self: [------]
1753 /// other: [------)
1754 /// ```
1755 ///
1756 /// # Example
1757 ///
1758 /// ```rust
1759 /// # include!("../../doctest_setup.rs");
1760 /// #
1761 /// # table! {
1762 /// # posts {
1763 /// # id -> Integer,
1764 /// # versions -> Range<Integer>,
1765 /// # }
1766 /// # }
1767 /// #
1768 /// # fn main() {
1769 /// # run_test().unwrap();
1770 /// # }
1771 /// #
1772 /// # fn run_test() -> QueryResult<()> {
1773 /// # use self::posts::dsl::*;
1774 /// # use std::collections::Bound;
1775 /// # let conn = &mut establish_connection();
1776 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
1777 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, versions INT4RANGE NOT NULL)").execute(conn).unwrap();
1778 /// #
1779 /// diesel::insert_into(posts)
1780 /// .values(&vec![
1781 /// (versions.eq((Bound::Included(1), Bound::Included(2)))),
1782 /// (versions.eq((Bound::Included(3), Bound::Included(4)))),
1783 /// (versions.eq((Bound::Included(5), Bound::Included(6))))
1784 /// ])
1785 /// .execute(conn)?;
1786 ///
1787 /// let data = posts.select(id)
1788 /// .filter(versions.lesser_than((Bound::Included(1), Bound::Included(4))))
1789 /// .load::<i32>(conn)?;
1790 /// assert!(data.is_empty());
1791 ///
1792 /// let data = posts.select(id)
1793 /// .filter(versions.lesser_than((Bound::Included(5), Bound::Included(8))))
1794 /// .load::<i32>(conn)?;
1795 /// assert_eq!(vec![1, 2], data);
1796 /// # Ok(())
1797 /// # }
1798 /// ```
1799 fn lesser_than<T>(self, other: T) -> dsl::LesserThanRange<Self, T>
1800 where
1801 Self::SqlType: SqlType,
1802 T: AsExpression<Self::SqlType>,
1803 {
1804 Grouped(IsContainedByNet::new(self, other.as_expression()))
1805 }
1806
1807 /// Creates a PostgreSQL `>>` expression.
1808 ///
1809 /// Is the first range strictly right of the second?
1810 ///
1811 /// The following constelations evaluate to true:
1812 /// ```text
1813 /// self: [------)
1814 /// other: [----)
1815 /// ```
1816 ///
1817 /// ```text
1818 /// self: [----)
1819 /// other: [----)
1820 /// ```
1821 ///
1822 /// The following constelations evaluate to false:
1823 ///
1824 /// ```text
1825 /// self: [------]
1826 /// other: [----]
1827 /// ```
1828 ///
1829 /// ```text
1830 /// self: [------]
1831 /// other: [----]
1832 /// ```
1833 ///
1834 /// ```text
1835 /// self: [------]
1836 /// other: [------]
1837 /// ```
1838 ///
1839 /// # Example
1840 ///
1841 /// ```rust
1842 /// # include!("../../doctest_setup.rs");
1843 /// #
1844 /// # table! {
1845 /// # posts {
1846 /// # id -> Integer,
1847 /// # versions -> Range<Integer>,
1848 /// # }
1849 /// # }
1850 /// #
1851 /// # fn main() {
1852 /// # run_test().unwrap();
1853 /// # }
1854 /// #
1855 /// # fn run_test() -> QueryResult<()> {
1856 /// # use self::posts::dsl::*;
1857 /// # use std::collections::Bound;
1858 /// # let conn = &mut establish_connection();
1859 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
1860 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, versions INT4RANGE NOT NULL)").execute(conn).unwrap();
1861 /// #
1862 /// diesel::insert_into(posts)
1863 /// .values(&vec![
1864 /// (versions.eq((Bound::Included(1), Bound::Included(2)))),
1865 /// (versions.eq((Bound::Included(3), Bound::Included(4)))),
1866 /// (versions.eq((Bound::Included(5), Bound::Included(6))))
1867 /// ])
1868 /// .execute(conn)?;
1869 ///
1870 /// let data = posts.select(id)
1871 /// .filter(versions.greater_than((Bound::Included(1), Bound::Included(2))))
1872 /// .load::<i32>(conn)?;
1873 /// assert_eq!(vec![2, 3], data);
1874 ///
1875 /// let data = posts.select(id)
1876 /// .filter(versions.greater_than((Bound::Included(5), Bound::Included(8))))
1877 /// .load::<i32>(conn)?;
1878 /// assert!(data.is_empty());
1879 /// # Ok(())
1880 /// # }
1881 /// ```
1882 fn greater_than<T>(self, other: T) -> dsl::GreaterThanRange<Self, T>
1883 where
1884 Self::SqlType: SqlType,
1885 T: AsExpression<Self::SqlType>,
1886 {
1887 Grouped(ContainsNet::new(self, other.as_expression()))
1888 }
1889
1890 /// Creates a PostgreSQL ` -|- ` expression.
1891 ///
1892 /// This operator evaluates to true if the two ranges are adjacent
1893 ///
1894 /// The following constelations evaluate to true:
1895 /// ```text
1896 /// self: [------)
1897 /// other: [----)
1898 /// ```
1899 ///
1900 /// ```text
1901 /// self: [----)
1902 /// other: [----)
1903 /// ```
1904 ///
1905 /// ```text
1906 /// self: [----)
1907 /// other: [----]
1908 /// ```
1909 ///
1910 /// ```text
1911 /// self: [----]
1912 /// other: [----]
1913 /// ```
1914 ///
1915 /// The following constelations evaluate to false:
1916 ///
1917 /// ```text
1918 /// self: [------]
1919 /// other: [----]
1920 /// ```
1921 ///
1922 /// ```text
1923 /// self: [------]
1924 /// other: [----]
1925 /// ```
1926 ///
1927 /// ```text
1928 /// self: [------]
1929 /// other: [------]
1930 /// ```
1931 ///
1932 /// ```text
1933 /// self: [------]
1934 /// other: [------]
1935 /// ```
1936 ///
1937 /// # Example
1938 ///
1939 /// ```rust
1940 /// # include!("../../doctest_setup.rs");
1941 /// #
1942 /// # fn main() {
1943 /// # run_test().unwrap();
1944 /// # }
1945 /// #
1946 /// # fn run_test() -> QueryResult<()> {
1947 /// # use diesel::sql_types::{Integer, Range, Multirange};
1948 /// # let conn = &mut establish_connection();
1949 /// assert!(
1950 /// diesel::select((1..2).into_sql::<Range<Integer>>().range_adjacent(2..=6))
1951 /// .first::<bool>(conn)
1952 /// .unwrap()
1953 /// );
1954 /// assert!(
1955 /// !diesel::select((4..7).into_sql::<Range<Integer>>().range_adjacent(2..=6))
1956 /// .first::<bool>(conn)
1957 /// .unwrap()
1958 /// );
1959 ///
1960 /// assert!(diesel::select(
1961 /// vec![1..2]
1962 /// .into_sql::<Multirange<Integer>>()
1963 /// .range_adjacent(vec![2..=6])
1964 /// )
1965 /// .first::<bool>(conn)
1966 /// .unwrap());
1967 /// assert!(!diesel::select(
1968 /// vec![4..7]
1969 /// .into_sql::<Multirange<Integer>>()
1970 /// .range_adjacent(vec![2..=6])
1971 /// )
1972 /// .first::<bool>(conn)
1973 /// .unwrap());
1974 /// # Ok(())
1975 /// # }
1976 /// ```
1977 fn range_adjacent<T>(self, other: T) -> dsl::RangeAdjacent<Self, T>
1978 where
1979 Self::SqlType: SqlType,
1980 T: AsExpression<Self::SqlType>,
1981 {
1982 Grouped(RangeAdjacent::new(self, other.as_expression()))
1983 }
1984
1985 /// Creates a PostgreSQL ` + ` expression.
1986 ///
1987 /// This operator unions two ranges and returns the union.
1988 ///
1989 /// ```text
1990 /// self: [------)
1991 /// other: [----)
1992 /// result: [--------)
1993 /// ```
1994 ///
1995 /// ```text
1996 /// self: [----)
1997 /// other: [----)
1998 /// result: error
1999 /// ```
2000 ///
2001 /// ```text
2002 /// self: [----)
2003 /// other: [----]
2004 /// result [--------)
2005 /// ```
2006 ///
2007 /// # Example
2008 ///
2009 /// ```rust
2010 /// # include!("../../doctest_setup.rs");
2011 /// #
2012 /// # fn main() {
2013 /// # run_test().unwrap();
2014 /// # }
2015 /// #
2016 /// # fn run_test() -> QueryResult<()> {
2017 /// # use diesel::sql_types::{Integer, Range, Multirange};
2018 /// # let conn = &mut establish_connection();
2019 /// assert!(diesel::select(
2020 /// (1..=2)
2021 /// .into_sql::<Range<Integer>>()
2022 /// .union_range(2..=6)
2023 /// .eq(1..=6)
2024 /// )
2025 /// .first::<bool>(conn)
2026 /// .unwrap());
2027 ///
2028 /// assert!(diesel::select(
2029 /// vec![1..=2]
2030 /// .into_sql::<Multirange<Integer>>()
2031 /// .union_range(vec![1..=6])
2032 /// .eq(vec![1..=6])
2033 /// )
2034 /// .first::<bool>(conn)
2035 /// .unwrap());
2036 /// # Ok(())
2037 /// # }
2038 /// ```
2039 fn union_range<T>(self, other: T) -> dsl::UnionRange<Self, T>
2040 where
2041 Self::SqlType: SqlType,
2042 T: AsExpression<Self::SqlType>,
2043 {
2044 Grouped(UnionsRange::new(self, other.as_expression()))
2045 }
2046
2047 /// Creates a PostgreSQL ` - ` expression.
2048 ///
2049 /// This operator takes two ranges and returns the difference.
2050 ///
2051 /// The second range must not be contained in the first in such a way that the
2052 /// difference would not be a single range.
2053 ///
2054 /// ```text
2055 /// self: [------)
2056 /// other: [----)
2057 /// result: [---)
2058 /// ```
2059 ///
2060 /// ```text
2061 /// self: [----)
2062 /// other: [----)
2063 /// result: [--)
2064 /// ```
2065 ///
2066 /// ```text
2067 /// self: [--------)
2068 /// other: [----]
2069 /// result: error
2070 /// ```
2071 ///
2072 /// # Example
2073 ///
2074 /// ```rust
2075 /// # include!("../../doctest_setup.rs");
2076 /// #
2077 /// # fn main() {
2078 /// # run_test().unwrap();
2079 /// # }
2080 /// #
2081 /// # fn run_test() -> QueryResult<()> {
2082 /// # use diesel::sql_types::{Integer, Range, Multirange};
2083 /// # let conn = &mut establish_connection();
2084 /// assert!(diesel::select(
2085 /// (1..=8)
2086 /// .into_sql::<Range<Integer>>()
2087 /// .difference_range(3..=8)
2088 /// .eq(1..3)
2089 /// )
2090 /// .first::<bool>(conn)
2091 /// .unwrap());
2092 ///
2093 /// assert!(diesel::select(
2094 /// vec![1..=8]
2095 /// .into_sql::<Multirange<Integer>>()
2096 /// .difference_range(vec![3..=8])
2097 /// .eq(vec![1..3])
2098 /// )
2099 /// .first::<bool>(conn)
2100 /// .unwrap());
2101 /// # Ok(())
2102 /// # }
2103 /// ```
2104 fn difference_range<T>(self, other: T) -> dsl::Difference<Self, T>
2105 where
2106 Self::SqlType: SqlType,
2107 T: AsExpression<Self::SqlType>,
2108 {
2109 Grouped(DifferenceRange::new(self, other.as_expression()))
2110 }
2111
2112 /// Creates a PostgreSQL ` * ` expression.
2113 ///
2114 /// This operator takes two ranges and returns the intersection.
2115 ///
2116 /// ```text
2117 /// self: [------)
2118 /// other: [----)
2119 /// result: [--)
2120 /// ```
2121 ///
2122 /// ```text
2123 /// self: [----)
2124 /// other: [----)
2125 /// result: [-)
2126 /// ```
2127 ///
2128 /// ```text
2129 /// self: [--------)
2130 /// other: [----]
2131 /// result: [----]
2132 /// ```
2133 ///
2134 /// ```text
2135 /// self: [--------)
2136 /// other: [----]
2137 /// result: empty range
2138 /// ```
2139 ///
2140 /// # Example
2141 ///
2142 /// ```rust
2143 /// # include!("../../doctest_setup.rs");
2144 /// #
2145 /// # fn main() {
2146 /// # run_test().unwrap();
2147 /// # }
2148 /// #
2149 /// # fn run_test() -> QueryResult<()> {
2150 /// # use diesel::sql_types::{Integer, Range, Multirange};
2151 /// # let conn = &mut establish_connection();
2152 /// assert!(diesel::select(
2153 /// (1..=8)
2154 /// .into_sql::<Range<Integer>>()
2155 /// .intersection_range(3..=8)
2156 /// .eq(3..=8)
2157 /// )
2158 /// .first::<bool>(conn)
2159 /// .unwrap());
2160 ///
2161 /// assert!(diesel::select(
2162 /// vec![1..=8]
2163 /// .into_sql::<Multirange<Integer>>()
2164 /// .intersection_range(vec![3..=8])
2165 /// .eq(vec![3..=8])
2166 /// )
2167 /// .first::<bool>(conn)
2168 /// .unwrap());
2169 /// # Ok(())
2170 /// # }
2171 /// ```
2172 fn intersection_range<T>(self, other: T) -> dsl::Intersection<Self, T>
2173 where
2174 Self::SqlType: SqlType,
2175 T: AsExpression<Self::SqlType>,
2176 {
2177 Grouped(IntersectionRange::new(self, other.as_expression()))
2178 }
2179}
2180
2181impl<T> PgRangeExpressionMethods for T
2182where
2183 T: Expression,
2184 T::SqlType: MultirangeOrRangeMaybeNullable,
2185{
2186}
2187
2188/// PostgreSQL specific methods present between CIDR/INET expressions
2189#[cfg(feature = "postgres_backend")]
2190pub trait PgNetExpressionMethods: Expression + Sized {
2191 /// Creates a PostgreSQL `>>` expression.
2192 ///
2193 /// This operator returns whether a subnet strictly contains another subnet or address.
2194 ///
2195 /// # Example
2196 ///
2197 /// ```rust
2198 /// # include!("../../doctest_setup.rs");
2199 /// #
2200 /// # table! {
2201 /// # hosts {
2202 /// # id -> Integer,
2203 /// # address -> Inet,
2204 /// # }
2205 /// # }
2206 /// #
2207 /// # fn main() {
2208 /// # run_test().unwrap();
2209 /// # }
2210 /// #
2211 /// # #[cfg(feature = "ipnetwork")]
2212 /// # fn run_test() -> QueryResult<()> {
2213 /// # use self::hosts::dsl::*;
2214 /// # use ipnetwork::IpNetwork;
2215 /// # use std::str::FromStr;
2216 /// # let conn = &mut establish_connection();
2217 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2218 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2219 /// diesel::insert_into(hosts)
2220 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
2221 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
2222 /// .execute(conn)?;
2223 ///
2224 /// let my_hosts = hosts.select(id)
2225 /// .filter(address.contains(IpNetwork::from_str("10.0.2.5").unwrap()))
2226 /// .load::<i32>(conn)?;
2227 /// assert_eq!(vec![1, 2], my_hosts);
2228 ///
2229 /// let my_hosts = hosts.select(id)
2230 /// .filter(address.contains(IpNetwork::from_str("10.0.2.5/24").unwrap()))
2231 /// .load::<i32>(conn)?;
2232 /// assert_eq!(vec![2], my_hosts);
2233 ///
2234 /// let my_hosts = hosts.select(id)
2235 /// .filter(address.contains(IpNetwork::from_str("10.0.3.31").unwrap()))
2236 /// .load::<i32>(conn)?;
2237 /// assert_eq!(vec![2], my_hosts);
2238 /// # Ok(())
2239 /// # }
2240 /// #
2241 /// # #[cfg(not(feature = "ipnetwork"))]
2242 /// # fn run_test() -> QueryResult<()> {
2243 /// # Ok(())
2244 /// # }
2245 /// ```
2246 fn contains<T>(self, other: T) -> dsl::ContainsNet<Self, T>
2247 where
2248 T: AsExpression<Inet>,
2249 {
2250 Grouped(ContainsNet::new(self, other.as_expression()))
2251 }
2252
2253 /// Creates a PostgreSQL `>>=` expression.
2254 ///
2255 /// This operator returns whether a subnet contains or is equal to another subnet.
2256 ///
2257 /// # Example
2258 ///
2259 /// ```rust
2260 /// # include!("../../doctest_setup.rs");
2261 /// #
2262 /// # table! {
2263 /// # hosts {
2264 /// # id -> Integer,
2265 /// # address -> Inet,
2266 /// # }
2267 /// # }
2268 /// #
2269 /// # fn main() {
2270 /// # run_test().unwrap();
2271 /// # }
2272 /// #
2273 /// # #[cfg(feature = "ipnetwork")]
2274 /// # fn run_test() -> QueryResult<()> {
2275 /// # use self::hosts::dsl::*;
2276 /// # use ipnetwork::IpNetwork;
2277 /// # use std::str::FromStr;
2278 /// # let conn = &mut establish_connection();
2279 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2280 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2281 /// diesel::insert_into(hosts)
2282 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
2283 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
2284 /// .execute(conn)?;
2285 ///
2286 /// let my_hosts = hosts.select(id)
2287 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.2.5").unwrap()))
2288 /// .load::<i32>(conn)?;
2289 /// assert_eq!(vec![1, 2], my_hosts);
2290 ///
2291 /// let my_hosts = hosts.select(id)
2292 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.2.5/24").unwrap()))
2293 /// .load::<i32>(conn)?;
2294 /// assert_eq!(vec![1, 2], my_hosts);
2295 ///
2296 /// let my_hosts = hosts.select(id)
2297 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.3.31").unwrap()))
2298 /// .load::<i32>(conn)?;
2299 /// assert_eq!(vec![2], my_hosts);
2300 /// # Ok(())
2301 /// # }
2302 /// #
2303 /// # #[cfg(not(feature = "ipnetwork"))]
2304 /// # fn run_test() -> QueryResult<()> {
2305 /// # Ok(())
2306 /// # }
2307 /// ```
2308 fn contains_or_eq<T>(self, other: T) -> dsl::ContainsNetLoose<Self, T>
2309 where
2310 T: AsExpression<Inet>,
2311 {
2312 Grouped(ContainsNetLoose::new(self, other.as_expression()))
2313 }
2314
2315 /// Creates a PostgreSQL `<<` expression.
2316 ///
2317 /// This operator returns whether a subnet or address is strictly contained by another subnet.
2318 ///
2319 /// # Example
2320 ///
2321 /// ```rust
2322 /// # include!("../../doctest_setup.rs");
2323 /// #
2324 /// # table! {
2325 /// # hosts {
2326 /// # id -> Integer,
2327 /// # address -> Inet,
2328 /// # }
2329 /// # }
2330 /// #
2331 /// # fn main() {
2332 /// # run_test().unwrap();
2333 /// # }
2334 /// #
2335 /// # #[cfg(feature = "ipnetwork")]
2336 /// # fn run_test() -> QueryResult<()> {
2337 /// # use self::hosts::dsl::*;
2338 /// # use ipnetwork::IpNetwork;
2339 /// # use std::str::FromStr;
2340 /// # let conn = &mut establish_connection();
2341 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2342 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2343 /// diesel::insert_into(hosts)
2344 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
2345 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
2346 /// .execute(conn)?;
2347 ///
2348 /// let my_hosts = hosts.select(id)
2349 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.2.5/24").unwrap()))
2350 /// .load::<i32>(conn)?;
2351 /// assert_eq!(my_hosts.len(), 0);
2352 ///
2353 /// let my_hosts = hosts.select(id)
2354 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.3.31/23").unwrap()))
2355 /// .load::<i32>(conn)?;
2356 /// assert_eq!(vec![1], my_hosts);
2357 ///
2358 /// let my_hosts = hosts.select(id)
2359 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.3.31/22").unwrap()))
2360 /// .load::<i32>(conn)?;
2361 /// assert_eq!(vec![1, 2], my_hosts);
2362 /// # Ok(())
2363 /// # }
2364 /// #
2365 /// # #[cfg(not(feature = "ipnetwork"))]
2366 /// # fn run_test() -> QueryResult<()> {
2367 /// # Ok(())
2368 /// # }
2369 /// ```
2370 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
2371 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedByNet<Self, T>
2372 where
2373 T: AsExpression<Inet>,
2374 {
2375 Grouped(IsContainedByNet::new(self, other.as_expression()))
2376 }
2377
2378 /// Creates a PostgreSQL `>>=` expression.
2379 ///
2380 /// This operator returns whether a subnet is contained by or equal to another subnet.
2381 ///
2382 /// # Example
2383 ///
2384 /// ```rust
2385 /// # include!("../../doctest_setup.rs");
2386 /// #
2387 /// # table! {
2388 /// # hosts {
2389 /// # id -> Integer,
2390 /// # address -> Inet,
2391 /// # }
2392 /// # }
2393 /// #
2394 /// # fn main() {
2395 /// # run_test().unwrap();
2396 /// # }
2397 /// #
2398 /// # #[cfg(feature = "ipnetwork")]
2399 /// # fn run_test() -> QueryResult<()> {
2400 /// # use self::hosts::dsl::*;
2401 /// # use ipnetwork::IpNetwork;
2402 /// # use std::str::FromStr;
2403 /// # let conn = &mut establish_connection();
2404 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2405 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2406 /// diesel::insert_into(hosts)
2407 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
2408 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
2409 /// .execute(conn)?;
2410 ///
2411 /// let my_hosts = hosts.select(id)
2412 /// .filter(address.is_contained_by_or_eq(IpNetwork::from_str("10.0.2.5/24").unwrap()))
2413 /// .load::<i32>(conn)?;
2414 /// assert_eq!(vec![1], my_hosts);
2415 ///
2416 /// let my_hosts = hosts.select(id)
2417 /// .filter(address.is_contained_by_or_eq(IpNetwork::from_str("10.0.3.31/23").unwrap()))
2418 /// .load::<i32>(conn)?;
2419 /// assert_eq!(vec![1, 2], my_hosts);
2420 /// # Ok(())
2421 /// # }
2422 /// #
2423 /// # #[cfg(not(feature = "ipnetwork"))]
2424 /// # fn run_test() -> QueryResult<()> {
2425 /// # Ok(())
2426 /// # }
2427 /// ```
2428 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
2429 fn is_contained_by_or_eq<T>(self, other: T) -> dsl::IsContainedByNetLoose<Self, T>
2430 where
2431 T: AsExpression<Inet>,
2432 {
2433 Grouped(IsContainedByNetLoose::new(self, other.as_expression()))
2434 }
2435
2436 /// Creates a PostgreSQL `&&` expression.
2437 ///
2438 /// This operator returns whether a subnet contains or is contained by another subnet.
2439 ///
2440 /// # Example
2441 ///
2442 /// ```rust
2443 /// # include!("../../doctest_setup.rs");
2444 /// #
2445 /// # table! {
2446 /// # hosts {
2447 /// # id -> Integer,
2448 /// # address -> Inet,
2449 /// # }
2450 /// # }
2451 /// #
2452 /// # fn main() {
2453 /// # run_test().unwrap();
2454 /// # }
2455 /// #
2456 /// # #[cfg(feature = "ipnetwork")]
2457 /// # fn run_test() -> QueryResult<()> {
2458 /// # use self::hosts::dsl::*;
2459 /// # use ipnetwork::IpNetwork;
2460 /// # use std::str::FromStr;
2461 /// # let conn = &mut establish_connection();
2462 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2463 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2464 /// diesel::insert_into(hosts)
2465 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
2466 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
2467 /// .execute(conn)?;
2468 ///
2469 /// let my_hosts = hosts.select(id)
2470 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.2.5/24").unwrap()))
2471 /// .load::<i32>(conn)?;
2472 /// assert_eq!(vec![1, 2], my_hosts);
2473 ///
2474 /// let my_hosts = hosts.select(id)
2475 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.3.31/24").unwrap()))
2476 /// .load::<i32>(conn)?;
2477 /// assert_eq!(vec![2], my_hosts);
2478 ///
2479 /// let my_hosts = hosts.select(id)
2480 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.3.31/23").unwrap()))
2481 /// .load::<i32>(conn)?;
2482 /// assert_eq!(vec![1, 2], my_hosts);
2483 /// # Ok(())
2484 /// # }
2485 /// #
2486 /// # #[cfg(not(feature = "ipnetwork"))]
2487 /// # fn run_test() -> QueryResult<()> {
2488 /// # Ok(())
2489 /// # }
2490 /// ```
2491 fn overlaps_with<T>(self, other: T) -> dsl::OverlapsWithNet<Self, T>
2492 where
2493 T: AsExpression<Inet>,
2494 {
2495 Grouped(OverlapsWith::new(self, other.as_expression()))
2496 }
2497
2498 /// Creates a PostgreSQL `&` expression.
2499 ///
2500 /// This operator computes the bitwise AND between two network addresses.
2501 ///
2502 /// # Example
2503 ///
2504 /// ```rust
2505 /// # include!("../../doctest_setup.rs");
2506 /// #
2507 /// # table! {
2508 /// # hosts {
2509 /// # id -> Integer,
2510 /// # address -> Inet,
2511 /// # }
2512 /// # }
2513 /// #
2514 /// # fn main() {
2515 /// # run_test().unwrap();
2516 /// # }
2517 /// #
2518 /// # #[cfg(feature = "ipnetwork")]
2519 /// # fn run_test() -> QueryResult<()> {
2520 /// # use self::hosts::dsl::*;
2521 /// # use ipnetwork::IpNetwork;
2522 /// # use std::str::FromStr;
2523 /// # let conn = &mut establish_connection();
2524 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2525 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2526 /// diesel::insert_into(hosts)
2527 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3").unwrap())])
2528 /// .execute(conn)?;
2529 ///
2530 /// let addr = hosts
2531 /// .select(address.and(IpNetwork::from_str("0.0.0.255").unwrap()))
2532 /// .first::<IpNetwork>(conn)?;
2533 /// assert_eq!(addr, IpNetwork::from_str("0.0.0.3").unwrap());
2534 /// # Ok(())
2535 /// # }
2536 /// #
2537 /// # #[cfg(not(feature = "ipnetwork"))]
2538 /// # fn run_test() -> QueryResult<()> {
2539 /// # Ok(())
2540 /// # }
2541 /// ```
2542 fn and<T>(self, other: T) -> dsl::AndNet<Self, T>
2543 where
2544 T: AsExpression<Inet>,
2545 {
2546 Grouped(AndNet::new(self, other.as_expression()))
2547 }
2548
2549 /// Creates a PostgreSQL `|` expression.
2550 ///
2551 /// This operator computes the bitwise OR between two network addresses.
2552 ///
2553 /// # Example
2554 ///
2555 /// ```rust
2556 /// # include!("../../doctest_setup.rs");
2557 /// #
2558 /// # table! {
2559 /// # hosts {
2560 /// # id -> Integer,
2561 /// # address -> Inet,
2562 /// # }
2563 /// # }
2564 /// #
2565 /// # fn main() {
2566 /// # run_test().unwrap();
2567 /// # }
2568 /// #
2569 /// # #[cfg(feature = "ipnetwork")]
2570 /// # fn run_test() -> QueryResult<()> {
2571 /// # use self::hosts::dsl::*;
2572 /// # use ipnetwork::IpNetwork;
2573 /// # use std::str::FromStr;
2574 /// # let conn = &mut establish_connection();
2575 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2576 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2577 /// diesel::insert_into(hosts)
2578 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3").unwrap())])
2579 /// .execute(conn)?;
2580 ///
2581 /// let addr = hosts
2582 /// .select(address.or(IpNetwork::from_str("0.0.0.255").unwrap()))
2583 /// .first::<IpNetwork>(conn)?;
2584 /// assert_eq!(addr, IpNetwork::from_str("10.0.2.255").unwrap());
2585 /// # Ok(())
2586 /// # }
2587 /// #
2588 /// # #[cfg(not(feature = "ipnetwork"))]
2589 /// # fn run_test() -> QueryResult<()> {
2590 /// # Ok(())
2591 /// # }
2592 /// ```
2593 fn or<T>(self, other: T) -> dsl::OrNet<Self, T>
2594 where
2595 T: AsExpression<Inet>,
2596 {
2597 Grouped(OrNet::new(self, other.as_expression()))
2598 }
2599
2600 /// Creates a PostgreSQL `-` expression.
2601 ///
2602 /// This operator subtracts an address from an address to compute the distance between the two
2603 ///
2604 /// # Example
2605 ///
2606 /// ```rust
2607 /// # include!("../../doctest_setup.rs");
2608 /// #
2609 /// # table! {
2610 /// # hosts {
2611 /// # id -> Integer,
2612 /// # address -> Inet,
2613 /// # }
2614 /// # }
2615 /// #
2616 /// # fn main() {
2617 /// # run_test().unwrap();
2618 /// # }
2619 /// #
2620 /// # #[cfg(feature = "ipnetwork")]
2621 /// # fn run_test() -> QueryResult<()> {
2622 /// # use self::hosts::dsl::*;
2623 /// # use ipnetwork::IpNetwork;
2624 /// # use std::str::FromStr;
2625 /// # let conn = &mut establish_connection();
2626 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
2627 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
2628 /// diesel::insert_into(hosts)
2629 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.53").unwrap())])
2630 /// .execute(conn)?;
2631 ///
2632 /// let offset = hosts
2633 /// .select(address.diff(IpNetwork::from_str("10.0.2.42").unwrap()))
2634 /// .first::<i64>(conn)?;
2635 /// assert_eq!(offset, 11);
2636 /// # Ok(())
2637 /// # }
2638 /// #
2639 /// # #[cfg(not(feature = "ipnetwork"))]
2640 /// # fn run_test() -> QueryResult<()> {
2641 /// # Ok(())
2642 /// # }
2643 /// ```
2644 fn diff<T>(self, other: T) -> dsl::DifferenceNet<Self, T>
2645 where
2646 T: AsExpression<Inet>,
2647 {
2648 Grouped(DifferenceNet::new(self, other.as_expression()))
2649 }
2650}
2651
2652impl<T> PgNetExpressionMethods for T
2653where
2654 T: Expression,
2655 T::SqlType: InetOrCidr,
2656{
2657}
2658
2659/// PostgreSQL specific methods present on JSONB expressions.
2660#[cfg(feature = "postgres_backend")]
2661pub trait PgJsonbExpressionMethods: Expression + Sized {
2662 /// Creates a PostgreSQL `||` expression.
2663 ///
2664 /// This operator concatenates two JSONB values and returns JSONB value
2665 ///
2666 /// # Example
2667 ///
2668 /// ```rust
2669 /// # include!("../../doctest_setup.rs");
2670 /// #
2671 /// # table! {
2672 /// # contacts {
2673 /// # id -> Integer,
2674 /// # name -> VarChar,
2675 /// # address -> Jsonb,
2676 /// # }
2677 /// # }
2678 /// #
2679 /// # fn main() {
2680 /// # run_test().unwrap();
2681 /// # }
2682 ///
2683 /// # #[cfg(feature = "serde_json")]
2684 /// # fn run_test() -> QueryResult<()> {
2685 /// # use self::contacts::dsl::*;
2686 /// # let conn = &mut establish_connection();
2687 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2688 /// # diesel::sql_query("CREATE TABLE contacts (
2689 /// # id SERIAL PRIMARY KEY,
2690 /// # name VARCHAR NOT NULL,
2691 /// # address JSONB NOT NULL
2692 /// # )").execute(conn).unwrap();
2693 /// #
2694 /// let santas_address: serde_json::Value = serde_json::json!({
2695 /// "street": "Article Circle Expressway 1",
2696 /// "city": "North Pole",
2697 /// "postcode": "99705",
2698 /// "state": "Alaska"
2699 /// });
2700 /// diesel::insert_into(contacts)
2701 /// .values((name.eq("Claus"), address.eq(&santas_address)))
2702 /// .execute(conn)?;
2703 ///
2704 /// let to_concatenate: serde_json::Value = serde_json::json!({
2705 /// "continent": "NA",
2706 /// "planet": "Earth"
2707 /// });
2708 ///
2709 /// let final_address: serde_json::Value = serde_json::json!({
2710 /// "street": "Article Circle Expressway 1",
2711 /// "city": "North Pole",
2712 /// "postcode": "99705",
2713 /// "state": "Alaska",
2714 /// "continent": "NA",
2715 /// "planet": "Earth"
2716 /// });
2717 ///
2718 /// let final_address_db = contacts.select(address.concat(&to_concatenate)).get_result::<serde_json::Value>(conn)?;
2719 /// assert_eq!(final_address, final_address_db);
2720 /// # Ok(())
2721 /// # }
2722 /// # #[cfg(not(feature = "serde_json"))]
2723 /// # fn run_test() -> QueryResult<()> {
2724 /// # Ok(())
2725 /// # }
2726 /// ```
2727 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
2728 where
2729 Self::SqlType: SqlType,
2730 T: AsExpression<Self::SqlType>,
2731 {
2732 Grouped(Concat::new(self, other.as_expression()))
2733 }
2734
2735 /// Creates a PostgreSQL `?` expression.
2736 ///
2737 /// This operator checks if the right hand side string exists as a top-level key within the JSONB
2738 ///
2739 /// # Example
2740 ///
2741 /// ```rust
2742 /// # include!("../../doctest_setup.rs");
2743 /// #
2744 /// # table! {
2745 /// # contacts {
2746 /// # id -> Integer,
2747 /// # name -> VarChar,
2748 /// # address -> Jsonb,
2749 /// # }
2750 /// # }
2751 /// #
2752 /// # fn main() {
2753 /// # run_test().unwrap();
2754 /// # }
2755 ///
2756 /// # #[cfg(feature = "serde_json")]
2757 /// # fn run_test() -> QueryResult<()> {
2758 /// # use self::contacts::dsl::*;
2759 /// # let conn = &mut establish_connection();
2760 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2761 /// # diesel::sql_query("CREATE TABLE contacts (
2762 /// # id SERIAL PRIMARY KEY,
2763 /// # name VARCHAR NOT NULL,
2764 /// # address JSONB NOT NULL
2765 /// # )").execute(conn).unwrap();
2766 /// #
2767 /// let santas_address: serde_json::Value = serde_json::json!({
2768 /// "street": "Article Circle Expressway 1",
2769 /// "city": "North Pole",
2770 /// "postcode": "99705",
2771 /// "state": "Alaska"
2772 /// });
2773 /// diesel::insert_into(contacts)
2774 /// .values((name.eq("Claus"), address.eq(&santas_address)))
2775 /// .execute(conn)?;
2776 ///
2777 /// let key_exists = contacts.select(address.has_key("street")).get_result::<bool>(conn)?;
2778 /// assert!(key_exists);
2779 ///
2780 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_key("postcode")).get_result::<i32>(conn)?;
2781 /// assert_eq!(1, santas_with_address_postcode);
2782 /// # Ok(())
2783 /// # }
2784 /// # #[cfg(not(feature = "serde_json"))]
2785 /// # fn run_test() -> QueryResult<()> {
2786 /// # Ok(())
2787 /// # }
2788 /// ```
2789 fn has_key<T>(self, other: T) -> dsl::HasKeyJsonb<Self, T>
2790 where
2791 T: AsExpression<VarChar>,
2792 {
2793 Grouped(HasKeyJsonb::new(self, other.as_expression()))
2794 }
2795
2796 /// Creates a PostgreSQL `?|` expression.
2797 ///
2798 /// This operator checks if any of the strings in the right hand side array exists as top level key in the given JSONB
2799 ///
2800 /// # Example
2801 ///
2802 /// ```rust
2803 /// # include!("../../doctest_setup.rs");
2804 /// #
2805 /// # table! {
2806 /// # contacts {
2807 /// # id -> Integer,
2808 /// # name -> VarChar,
2809 /// # address -> Jsonb,
2810 /// # }
2811 /// # }
2812 /// #
2813 /// # fn main() {
2814 /// # run_test().unwrap();
2815 /// # }
2816 ///
2817 /// # #[cfg(feature = "serde_json")]
2818 /// # fn run_test() -> QueryResult<()> {
2819 /// # use self::contacts::dsl::*;
2820 /// # let conn = &mut establish_connection();
2821 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2822 /// # diesel::sql_query("CREATE TABLE contacts (
2823 /// # id SERIAL PRIMARY KEY,
2824 /// # name VARCHAR NOT NULL,
2825 /// # address JSONB NOT NULL
2826 /// # )").execute(conn).unwrap();
2827 /// #
2828 /// let santas_address: serde_json::Value = serde_json::json!({
2829 /// "street": "Article Circle Expressway 1",
2830 /// "city": "North Pole",
2831 /// "postcode": "99705",
2832 /// "state": "Alaska"
2833 /// });
2834 /// diesel::insert_into(contacts)
2835 /// .values((name.eq("Claus"), address.eq(&santas_address)))
2836 /// .execute(conn)?;
2837 ///
2838 /// let any_key_exists = contacts.select(address.has_any_key(vec!["street", "city", "rudolf"])).get_result::<bool>(conn)?;
2839 /// assert!(any_key_exists);
2840 ///
2841 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_any_key(vec!["street", "city", "rudolf"])).get_result::<i32>(conn)?;
2842 /// assert_eq!(1, santas_with_address_postcode);
2843 /// # Ok(())
2844 /// # }
2845 /// # #[cfg(not(feature = "serde_json"))]
2846 /// # fn run_test() -> QueryResult<()> {
2847 /// # Ok(())
2848 /// # }
2849 /// ``````
2850 fn has_any_key<T>(self, other: T) -> dsl::HasAnyKeyJsonb<Self, T>
2851 where
2852 T: AsExpression<Array<VarChar>>,
2853 {
2854 Grouped(HasAnyKeyJsonb::new(self, other.as_expression()))
2855 }
2856
2857 /// Creates a PostgreSQL `?&` expression.
2858 ///
2859 /// This operator checks if all the strings in the right hand side array exist as top level keys in the given JSONB
2860 ///
2861 /// # Example
2862 ///
2863 /// ```rust
2864 /// # include!("../../doctest_setup.rs");
2865 /// #
2866 /// # table! {
2867 /// # contacts {
2868 /// # id -> Integer,
2869 /// # name -> VarChar,
2870 /// # address -> Jsonb,
2871 /// # }
2872 /// # }
2873 /// #
2874 /// # fn main() {
2875 /// # run_test().unwrap();
2876 /// # }
2877 ///
2878 /// # #[cfg(feature = "serde_json")]
2879 /// # fn run_test() -> QueryResult<()> {
2880 /// # use self::contacts::dsl::*;
2881 /// # let conn = &mut establish_connection();
2882 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2883 /// # diesel::sql_query("CREATE TABLE contacts (
2884 /// # id SERIAL PRIMARY KEY,
2885 /// # name VARCHAR NOT NULL,
2886 /// # address JSONB NOT NULL
2887 /// # )").execute(conn).unwrap();
2888 /// #
2889 /// let santas_address: serde_json::Value = serde_json::json!({
2890 /// "street": "Article Circle Expressway 1",
2891 /// "city": "North Pole",
2892 /// "postcode": "99705",
2893 /// "state": "Alaska"
2894 /// });
2895 /// diesel::insert_into(contacts)
2896 /// .values((name.eq("Claus"), address.eq(&santas_address)))
2897 /// .execute(conn)?;
2898 ///
2899 /// let all_keys_exist = contacts.select(address.has_all_keys(vec!["street", "city", "postcode"])).get_result::<bool>(conn)?;
2900 /// assert!(all_keys_exist);
2901 ///
2902 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_all_keys(vec!["street", "city", "postcode"])).get_result::<i32>(conn)?;
2903 /// assert_eq!(1, santas_with_address_postcode);
2904 /// # Ok(())
2905 /// # }
2906 /// # #[cfg(not(feature = "serde_json"))]
2907 /// # fn run_test() -> QueryResult<()> {
2908 /// # Ok(())
2909 /// # }
2910 /// ``````
2911 fn has_all_keys<T>(self, other: T) -> dsl::HasAllKeysJsonb<Self, T>
2912 where
2913 T: AsExpression<Array<VarChar>>,
2914 {
2915 Grouped(HasAllKeysJsonb::new(self, other.as_expression()))
2916 }
2917
2918 /// Creates a PostgreSQL `@>` expression.
2919 ///
2920 /// This operator checks whether left hand side JSONB value contains right hand side JSONB value
2921 ///
2922 /// # Example
2923 ///
2924 /// ```rust
2925 /// # include!("../../doctest_setup.rs");
2926 /// #
2927 /// # table! {
2928 /// # contacts {
2929 /// # id -> Integer,
2930 /// # name -> VarChar,
2931 /// # address -> Jsonb,
2932 /// # }
2933 /// # }
2934 /// #
2935 /// # fn main() {
2936 /// # run_test().unwrap();
2937 /// # }
2938 /// #
2939 /// # #[cfg(feature = "serde_json")]
2940 /// # fn run_test() -> QueryResult<()> {
2941 /// # use self::contacts::dsl::*;
2942 /// # let conn = &mut establish_connection();
2943 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2944 /// # diesel::sql_query("CREATE TABLE contacts (
2945 /// # id SERIAL PRIMARY KEY,
2946 /// # name VARCHAR NOT NULL,
2947 /// # address JSONB NOT NULL
2948 /// # )").execute(conn).unwrap();
2949 /// #
2950 /// let easter_bunny_address: serde_json::Value = serde_json::json!({
2951 /// "street": "123 Carrot Road",
2952 /// "province": "Easter Island",
2953 /// "region": "ValparaÃso",
2954 /// "country": "Chile",
2955 /// "postcode": "88888",
2956 /// });
2957 /// diesel::insert_into(contacts)
2958 /// .values((name.eq("Bunny"), address.eq(&easter_bunny_address)))
2959 /// .execute(conn)?;
2960 ///
2961 /// let country_chile: serde_json::Value = serde_json::json!({"country": "Chile"});
2962 /// let contains_country_chile = contacts.select(address.contains(&country_chile)).get_result::<bool>(conn)?;
2963 /// assert!(contains_country_chile);
2964 /// # Ok(())
2965 /// # }
2966 /// # #[cfg(not(feature = "serde_json"))]
2967 /// # fn run_test() -> QueryResult<()> {
2968 /// # Ok(())
2969 /// # }
2970 /// ```
2971 fn contains<T>(self, other: T) -> dsl::Contains<Self, T>
2972 where
2973 Self::SqlType: SqlType,
2974 T: AsExpression<Self::SqlType>,
2975 {
2976 Grouped(Contains::new(self, other.as_expression()))
2977 }
2978
2979 /// Creates a PostgreSQL `<@` expression.
2980 ///
2981 /// This operator checks whether left hand side JSONB value is contained by right hand side JSON value.
2982 /// `foo.contains(bar)` is the same as `bar.is_contained_by(foo)`.
2983 ///
2984 /// # Example
2985 ///
2986 /// ```rust
2987 /// # include!("../../doctest_setup.rs");
2988 /// #
2989 /// # table! {
2990 /// # contacts {
2991 /// # id -> Integer,
2992 /// # name -> VarChar,
2993 /// # address -> Jsonb,
2994 /// # }
2995 /// # }
2996 /// #
2997 /// # fn main() {
2998 /// # run_test().unwrap();
2999 /// # }
3000 /// #
3001 /// # #[cfg(feature = "serde_json")]
3002 /// # fn run_test() -> QueryResult<()> {
3003 /// # use self::contacts::dsl::*;
3004 /// # let conn = &mut establish_connection();
3005 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3006 /// # diesel::sql_query("CREATE TABLE contacts (
3007 /// # id SERIAL PRIMARY KEY,
3008 /// # name VARCHAR NOT NULL,
3009 /// # address JSONB NOT NULL
3010 /// # )").execute(conn).unwrap();
3011 /// #
3012 /// let partial_easter_bunny_address: serde_json::Value = serde_json::json!({
3013 /// "street": "123 Carrot Road",
3014 /// "country": "Chile",
3015 /// });
3016 /// diesel::insert_into(contacts)
3017 /// .values((name.eq("Bunny"), address.eq(&partial_easter_bunny_address)))
3018 /// .execute(conn)?;
3019 ///
3020 /// let full_easter_bunny_address: serde_json::Value = serde_json::json!({
3021 /// "street": "123 Carrot Road",
3022 /// "province": "Easter Island",
3023 /// "region": "ValparaÃso",
3024 /// "country": "Chile",
3025 /// "postcode": "88888",
3026 /// });
3027 /// let address_is_contained_by = contacts.select(address.is_contained_by(&full_easter_bunny_address)).get_result::<bool>(conn)?;
3028 /// assert!(address_is_contained_by);
3029 /// # Ok(())
3030 /// # }
3031 /// # #[cfg(not(feature = "serde_json"))]
3032 /// # fn run_test() -> QueryResult<()> {
3033 /// # Ok(())
3034 /// # }
3035 /// ```
3036 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
3037 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedBy<Self, T>
3038 where
3039 Self::SqlType: SqlType,
3040 T: AsExpression<Self::SqlType>,
3041 {
3042 Grouped(IsContainedBy::new(self, other.as_expression()))
3043 }
3044
3045 /// Creates a PostgreSQL `-` expression.
3046 ///
3047 /// This operator removes the value associated with the given key, that is provided on the
3048 /// Right Hand Side of the operator.
3049 ///
3050 /// # Example
3051 ///
3052 /// ```rust
3053 /// # include!("../../doctest_setup.rs");
3054 /// #
3055 /// # table! {
3056 /// # contacts {
3057 /// # id -> Integer,
3058 /// # name -> VarChar,
3059 /// # address -> Jsonb,
3060 /// # }
3061 /// # }
3062 /// #
3063 /// # fn main() {
3064 /// # run_test().unwrap();
3065 /// # }
3066 ///
3067 /// # #[cfg(feature = "serde_json")]
3068 /// # fn run_test() -> QueryResult<()> {
3069 /// # use self::contacts::dsl::*;
3070 /// # let conn = &mut establish_connection();
3071 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3072 /// # diesel::sql_query("CREATE TABLE contacts (
3073 /// # id SERIAL PRIMARY KEY,
3074 /// # name VARCHAR NOT NULL,
3075 /// # address JSONB NOT NULL
3076 /// # )").execute(conn)
3077 /// # .unwrap();
3078 /// #
3079 /// let santas_address: serde_json::Value = serde_json::json!({
3080 /// "street": "Article Circle Expressway 1",
3081 /// "city": "North Pole",
3082 /// "postcode": "99705",
3083 /// "state": "Alaska"
3084 /// });
3085 /// diesel::insert_into(contacts)
3086 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3087 /// .execute(conn)?;
3088 ///
3089 /// let santas_modified_address = contacts.select(address.remove("postcode")).get_result::<serde_json::Value>(conn)?;
3090 /// assert_eq!(santas_modified_address, serde_json::json!({
3091 /// "street": "Article Circle Expressway 1",
3092 /// "city": "North Pole",
3093 /// "state": "Alaska"
3094 /// }));
3095 /// diesel::insert_into(contacts)
3096 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3097 /// .execute(conn)?;
3098 ///
3099 /// let santas_modified_address = contacts.select(address.remove(vec!["postcode", "state"])).get_result::<serde_json::Value>(conn)?;
3100 /// assert_eq!(santas_modified_address, serde_json::json!({
3101 /// "street": "Article Circle Expressway 1",
3102 /// "city": "North Pole",
3103 /// }));
3104 ///
3105 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3106 /// {
3107 /// "street": "Somewhere In La 251",
3108 /// "city": "Los Angeles",
3109 /// "postcode": "12231223",
3110 /// "state": "California"
3111 /// },
3112 /// {
3113 /// "street": "Somewhere In Ny 251",
3114 /// "city": "New York",
3115 /// "postcode": "3213212",
3116 /// "state": "New York"
3117 /// }
3118 /// ]);
3119 ///
3120 /// diesel::insert_into(contacts)
3121 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3122 /// .execute(conn)?;
3123 ///
3124 /// let roberts_address_in_db = contacts
3125 /// .filter(name.eq("Robert Downey Jr."))
3126 /// .select(address.remove(1))
3127 /// .get_result::<serde_json::Value>(conn)?;
3128 ///
3129 /// let roberts_first_address = serde_json::json!([{
3130 /// "street": "Somewhere In La 251",
3131 /// "city": "Los Angeles",
3132 /// "postcode": "12231223",
3133 /// "state": "California"
3134 /// }]);
3135 /// assert_eq!(roberts_first_address, roberts_address_in_db);
3136 /// # Ok(())
3137 /// # }
3138 /// # #[cfg(not(feature = "serde_json"))]
3139 /// # fn run_test() -> QueryResult<()> {
3140 /// # Ok(())
3141 /// # }
3142 fn remove<T>(
3143 self,
3144 other: T,
3145 ) -> dsl::RemoveFromJsonb<Self, T::Expression, <T::Expression as Expression>::SqlType>
3146 where
3147 T: JsonRemoveIndex,
3148 <T::Expression as Expression>::SqlType: SqlType,
3149 {
3150 Grouped(RemoveFromJsonb::new(
3151 self,
3152 other.into_json_index_expression(),
3153 ))
3154 }
3155
3156 /// Creates a PostgreSQL `#-` expression.
3157 ///
3158 /// This operator removes the value associated with the given json path, that is provided on the
3159 /// Right Hand Side of the operator.
3160 ///
3161 /// # Example
3162 ///
3163 /// ```rust
3164 /// # include!("../../doctest_setup.rs");
3165 /// #
3166 /// # table! {
3167 /// # contacts {
3168 /// # id -> Integer,
3169 /// # name -> VarChar,
3170 /// # address -> Jsonb,
3171 /// # }
3172 /// # }
3173 /// #
3174 /// # fn main() {
3175 /// # run_test().unwrap();
3176 /// # }
3177 ///
3178 /// # #[cfg(feature = "serde_json")]
3179 /// # fn run_test() -> QueryResult<()> {
3180 /// # use self::contacts::dsl::*;
3181 /// # let conn = &mut establish_connection();
3182 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3183 /// # diesel::sql_query("CREATE TABLE contacts (
3184 /// # id SERIAL PRIMARY KEY,
3185 /// # name VARCHAR NOT NULL,
3186 /// # address JSONB NOT NULL
3187 /// # )").execute(conn)
3188 /// # .unwrap();
3189 /// #
3190 /// let santas_address: serde_json::Value = serde_json::json!({
3191 /// "street": "Article Circle Expressway 1",
3192 /// "city": "North Pole",
3193 /// "postcode": "99705",
3194 /// "state": "Alaska"
3195 /// });
3196 /// diesel::insert_into(contacts)
3197 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3198 /// .execute(conn)?;
3199 ///
3200 /// let santas_modified_address = contacts.select(address.remove("postcode")).get_result::<serde_json::Value>(conn)?;
3201 /// assert_eq!(santas_modified_address, serde_json::json!({
3202 /// "street": "Article Circle Expressway 1",
3203 /// "city": "North Pole",
3204 /// "state": "Alaska"
3205 /// }));
3206 /// diesel::insert_into(contacts)
3207 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3208 /// .execute(conn)?;
3209 ///
3210 /// let santas_modified_address = contacts.select(address.remove_by_path(vec!["postcode"])).get_result::<serde_json::Value>(conn)?;
3211 /// assert_eq!(santas_modified_address, serde_json::json!({
3212 /// "street": "Article Circle Expressway 1",
3213 /// "city": "North Pole",
3214 /// "state": "Alaska"
3215 /// }));
3216 ///
3217 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3218 /// {
3219 /// "street": "Somewhere In La 251",
3220 /// "city": "Los Angeles",
3221 /// "postcode": "12231223",
3222 /// "state": "California"
3223 /// },
3224 /// {
3225 /// "street": "Somewhere In Ny 251",
3226 /// "city": "New York",
3227 /// "postcode": "3213212",
3228 /// "state": "New York"
3229 /// }
3230 /// ]);
3231 ///
3232 /// diesel::insert_into(contacts)
3233 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3234 /// .execute(conn)?;
3235 ///
3236 /// let roberts_address_in_db = contacts
3237 /// .filter(name.eq("Robert Downey Jr."))
3238 /// .select(address.remove_by_path(vec!["1", "postcode"]))
3239 /// .get_result::<serde_json::Value>(conn)?;
3240 ///
3241 /// let roberts_address = serde_json::json!([
3242 /// {
3243 /// "street": "Somewhere In La 251",
3244 /// "city": "Los Angeles",
3245 /// "postcode": "12231223",
3246 /// "state": "California"
3247 /// },
3248 /// {
3249 /// "street": "Somewhere In Ny 251",
3250 /// "city": "New York",
3251 /// "state": "New York"
3252 /// }
3253 /// ]);
3254 /// assert_eq!(roberts_address, roberts_address_in_db);
3255 /// # Ok(())
3256 /// # }
3257 /// # #[cfg(not(feature = "serde_json"))]
3258 /// # fn run_test() -> QueryResult<()> {
3259 /// # Ok(())
3260 /// # }
3261 fn remove_by_path<T>(self, other: T) -> dsl::RemoveByPathFromJsonb<Self, T::Expression>
3262 where
3263 T: AsExpression<Array<Text>>,
3264 {
3265 Grouped(RemoveByPathFromJsonb::new(self, other.as_expression()))
3266 }
3267}
3268
3269impl<T> PgJsonbExpressionMethods for T
3270where
3271 T: Expression,
3272 T::SqlType: JsonbOrNullableJsonb,
3273{
3274}
3275
3276/// PostgreSQL specific methods present on JSON and JSONB expressions.
3277#[cfg(feature = "postgres_backend")]
3278pub trait PgAnyJsonExpressionMethods: Expression + Sized {
3279 /// Creates a PostgreSQL `->` expression.
3280 ///
3281 /// This operator extracts the value associated with the given key, that is provided on the
3282 /// Right Hand Side of the operator.
3283 ///
3284 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
3285 /// Extracts JSON object field with the given key.
3286 /// # Example
3287 ///
3288 /// ```rust
3289 /// # include!("../../doctest_setup.rs");
3290 /// #
3291 /// # table! {
3292 /// # contacts {
3293 /// # id -> Integer,
3294 /// # name -> VarChar,
3295 /// # address -> Jsonb,
3296 /// # }
3297 /// # }
3298 /// #
3299 /// # fn main() {
3300 /// # run_test().unwrap();
3301 /// # }
3302 ///
3303 /// # #[cfg(feature = "serde_json")]
3304 /// # fn run_test() -> QueryResult<()> {
3305 /// # use self::contacts::dsl::*;
3306 /// # let conn = &mut establish_connection();
3307 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3308 /// # diesel::sql_query("CREATE TABLE contacts (
3309 /// # id SERIAL PRIMARY KEY,
3310 /// # name VARCHAR NOT NULL,
3311 /// # address JSONB NOT NULL
3312 /// # )").execute(conn)
3313 /// # .unwrap();
3314 /// #
3315 /// let santas_address: serde_json::Value = serde_json::json!({
3316 /// "street": "Article Circle Expressway 1",
3317 /// "city": "North Pole",
3318 /// "postcode": "99705",
3319 /// "state": "Alaska"
3320 /// });
3321 /// diesel::insert_into(contacts)
3322 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3323 /// .execute(conn)?;
3324 ///
3325 /// let santas_postcode = contacts.select(address.retrieve_as_object("postcode")).get_result::<serde_json::Value>(conn)?;
3326 /// assert_eq!(santas_postcode, serde_json::json!("99705"));
3327 ///
3328 ///
3329 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3330 /// {
3331 /// "street": "Somewhere In La 251",
3332 /// "city": "Los Angeles",
3333 /// "postcode": "12231223",
3334 /// "state": "California"
3335 /// },
3336 /// {
3337 /// "street": "Somewhere In Ny 251",
3338 /// "city": "New York",
3339 /// "postcode": "3213212",
3340 /// "state": "New York"
3341 /// }
3342 /// ]);
3343 ///
3344 /// diesel::insert_into(contacts)
3345 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3346 /// .execute(conn)?;
3347 ///
3348 /// let roberts_second_address_in_db = contacts
3349 /// .filter(name.eq("Robert Downey Jr."))
3350 /// .select(address.retrieve_as_object(1))
3351 /// .get_result::<serde_json::Value>(conn)?;
3352 ///
3353 /// let roberts_second_address = serde_json::json!({
3354 /// "street": "Somewhere In Ny 251",
3355 /// "city": "New York",
3356 /// "postcode": "3213212",
3357 /// "state": "New York"
3358 /// });
3359 /// assert_eq!(roberts_second_address, roberts_second_address_in_db);
3360 /// # Ok(())
3361 /// # }
3362 /// # #[cfg(not(feature = "serde_json"))]
3363 /// # fn run_test() -> QueryResult<()> {
3364 /// # Ok(())
3365 /// # }
3366 /// ```
3367 fn retrieve_as_object<T>(
3368 self,
3369 other: T,
3370 ) -> dsl::RetrieveAsObjectJson<Self, T::Expression, <T::Expression as Expression>::SqlType>
3371 where
3372 T: JsonIndex,
3373 <T::Expression as Expression>::SqlType: SqlType,
3374 {
3375 Grouped(RetrieveAsObjectJson::new(
3376 self,
3377 other.into_json_index_expression(),
3378 ))
3379 }
3380
3381 /// Creates a PostgreSQL `->>` expression.
3382 ///
3383 /// This operator extracts the value associated with the given key, that is provided on the
3384 /// Right Hand Side of the operator.
3385 ///
3386 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
3387 /// Extracts JSON object field as Text with the given key.
3388 /// # Example
3389 ///
3390 /// ```rust
3391 /// # include!("../../doctest_setup.rs");
3392 /// #
3393 /// # table! {
3394 /// # contacts {
3395 /// # id -> Integer,
3396 /// # name -> VarChar,
3397 /// # address -> Jsonb,
3398 /// # }
3399 /// # }
3400 /// #
3401 /// # fn main() {
3402 /// # run_test().unwrap();
3403 /// # }
3404 ///
3405 /// # #[cfg(feature = "serde_json")]
3406 /// # fn run_test() -> QueryResult<()> {
3407 /// # use self::contacts::dsl::*;
3408 /// # let conn = &mut establish_connection();
3409 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3410 /// # diesel::sql_query("CREATE TABLE contacts (
3411 /// # id SERIAL PRIMARY KEY,
3412 /// # name VARCHAR NOT NULL,
3413 /// # address JSONB NOT NULL
3414 /// # )").execute(conn)
3415 /// # .unwrap();
3416 /// #
3417 /// let santas_address: serde_json::Value = serde_json::json!({
3418 /// "street": "Article Circle Expressway 1",
3419 /// "city": "North Pole",
3420 /// "postcode": "99705",
3421 /// "state": "Alaska"
3422 /// });
3423 /// diesel::insert_into(contacts)
3424 /// .values((name.eq("Claus"), address.eq(&santas_address)))
3425 /// .execute(conn)?;
3426 ///
3427 /// let santas_postcode = contacts.select(address.retrieve_as_text("postcode")).get_result::<String>(conn)?;
3428 /// assert_eq!(santas_postcode, "99705");
3429 ///
3430 ///
3431 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3432 /// {
3433 /// "street": "Somewhere In La 251",
3434 /// "city": "Los Angeles",
3435 /// "postcode": "12231223",
3436 /// "state": "California"
3437 /// },
3438 /// {
3439 /// "street": "Somewhere In Ny 251",
3440 /// "city": "New York",
3441 /// "postcode": "3213212",
3442 /// "state": "New York"
3443 /// }
3444 /// ]);
3445 ///
3446 /// diesel::insert_into(contacts)
3447 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3448 /// .execute(conn)?;
3449 ///
3450 /// let roberts_second_address_in_db = contacts
3451 /// .filter(name.eq("Robert Downey Jr."))
3452 /// .select(address.retrieve_as_text(1))
3453 /// .get_result::<String>(conn)?;
3454 ///
3455 /// let roberts_second_address = String::from(
3456 /// "{\"city\": \"New York\", \
3457 /// \"state\": \"New York\", \
3458 /// \"street\": \"Somewhere In Ny 251\", \
3459 /// \"postcode\": \"3213212\"}"
3460 /// );
3461 /// assert_eq!(roberts_second_address, roberts_second_address_in_db);
3462 /// # Ok(())
3463 /// # }
3464 /// # #[cfg(not(feature = "serde_json"))]
3465 /// # fn run_test() -> QueryResult<()> {
3466 /// # Ok(())
3467 /// # }
3468 /// ```
3469 fn retrieve_as_text<T>(
3470 self,
3471 other: T,
3472 ) -> dsl::RetrieveAsTextJson<Self, T::Expression, <T::Expression as Expression>::SqlType>
3473 where
3474 T: JsonIndex,
3475 <T::Expression as Expression>::SqlType: SqlType,
3476 {
3477 Grouped(RetrieveAsTextJson::new(
3478 self,
3479 other.into_json_index_expression(),
3480 ))
3481 }
3482
3483 /// Creates a PostgreSQL `#>` expression.
3484 ///
3485 /// This operator extracts the value associated with the given key, that is provided on the
3486 /// Right Hand Side of the operator.
3487 ///
3488 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
3489 /// Extracts JSON object field with the given key.
3490 /// # Example
3491 ///
3492 /// ```rust
3493 /// # include!("../../doctest_setup.rs");
3494 /// #
3495 /// # table! {
3496 /// # contacts {
3497 /// # id -> Integer,
3498 /// # name -> VarChar,
3499 /// # address -> Jsonb,
3500 /// # }
3501 /// # }
3502 /// #
3503 /// # fn main() {
3504 /// # run_test().unwrap();
3505 /// # }
3506 ///
3507 /// # #[cfg(feature = "serde_json")]
3508 /// # fn run_test() -> QueryResult<()> {
3509 /// # use self::contacts::dsl::*;
3510 /// # let conn = &mut establish_connection();
3511 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3512 /// # diesel::sql_query("CREATE TABLE contacts (
3513 /// # id SERIAL PRIMARY KEY,
3514 /// # name VARCHAR NOT NULL,
3515 /// # address JSONB NOT NULL
3516 /// # )").execute(conn)
3517 /// # .unwrap();
3518 /// #
3519 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3520 /// {
3521 /// "street": "Somewhere In La 251",
3522 /// "city": "Los Angeles",
3523 /// "postcode": "12231223",
3524 /// "state": "California"
3525 /// },
3526 /// {
3527 /// "street": "Somewhere In Ny 251",
3528 /// "city": "New York",
3529 /// "postcode": "3213212",
3530 /// "state": "New York"
3531 /// }
3532 /// ]);
3533 ///
3534 /// diesel::insert_into(contacts)
3535 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3536 /// .execute(conn)?;
3537 ///
3538 /// let roberts_second_street_in_db = contacts
3539 /// .filter(name.eq("Robert Downey Jr."))
3540 /// .select(address.retrieve_by_path_as_object(vec!["1", "street"]))
3541 /// .get_result::<serde_json::Value>(conn)?;
3542 ///
3543 /// assert_eq!(roberts_second_street_in_db, serde_json::json!("Somewhere In Ny 251"));
3544 /// # Ok(())
3545 /// # }
3546 /// # #[cfg(not(feature = "serde_json"))]
3547 /// # fn run_test() -> QueryResult<()> {
3548 /// # Ok(())
3549 /// # }
3550 /// ```
3551 fn retrieve_by_path_as_object<T>(
3552 self,
3553 other: T,
3554 ) -> dsl::RetrieveByPathAsObjectJson<Self, T::Expression>
3555 where
3556 T: AsExpression<Array<Text>>,
3557 {
3558 Grouped(RetrieveByPathAsObjectJson::new(self, other.as_expression()))
3559 }
3560
3561 /// Creates a PostgreSQL `#>>` expression.
3562 ///
3563 /// This operator extracts the value associated with the given key, that is provided on the
3564 /// Right Hand Side of the operator.
3565 ///
3566 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
3567 /// Extracts JSON object field as Text with the given key.
3568 /// # Example
3569 ///
3570 /// ```rust
3571 /// # include!("../../doctest_setup.rs");
3572 /// #
3573 /// # table! {
3574 /// # contacts {
3575 /// # id -> Integer,
3576 /// # name -> VarChar,
3577 /// # address -> Jsonb,
3578 /// # }
3579 /// # }
3580 /// #
3581 /// # fn main() {
3582 /// # run_test().unwrap();
3583 /// # }
3584 ///
3585 /// # #[cfg(feature = "serde_json")]
3586 /// # fn run_test() -> QueryResult<()> {
3587 /// # use self::contacts::dsl::*;
3588 /// # let conn = &mut establish_connection();
3589 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
3590 /// # diesel::sql_query("CREATE TABLE contacts (
3591 /// # id SERIAL PRIMARY KEY,
3592 /// # name VARCHAR NOT NULL,
3593 /// # address JSONB NOT NULL
3594 /// # )").execute(conn)
3595 /// # .unwrap();
3596 /// #
3597 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
3598 /// {
3599 /// "street": "Somewhere In La 251",
3600 /// "city": "Los Angeles",
3601 /// "postcode": "12231223",
3602 /// "state": "California"
3603 /// },
3604 /// {
3605 /// "street": "Somewhere In Ny 251",
3606 /// "city": "New York",
3607 /// "postcode": "3213212",
3608 /// "state": "New York"
3609 /// }
3610 /// ]);
3611 ///
3612 /// diesel::insert_into(contacts)
3613 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
3614 /// .execute(conn)?;
3615 ///
3616 /// let roberts_second_street_in_db = contacts
3617 /// .filter(name.eq("Robert Downey Jr."))
3618 /// .select(address.retrieve_by_path_as_text(vec!["1", "street"]))
3619 /// .get_result::<String>(conn)?;
3620 ///
3621 /// assert_eq!(roberts_second_street_in_db, "Somewhere In Ny 251");
3622 ///
3623 /// # Ok(())
3624 /// # }
3625 /// # #[cfg(not(feature = "serde_json"))]
3626 /// # fn run_test() -> QueryResult<()> {
3627 /// # Ok(())
3628 /// # }
3629 /// ```
3630 fn retrieve_by_path_as_text<T>(
3631 self,
3632 other: T,
3633 ) -> dsl::RetrieveByPathAsTextJson<Self, T::Expression>
3634 where
3635 T: AsExpression<Array<Text>>,
3636 {
3637 Grouped(RetrieveByPathAsTextJson::new(self, other.as_expression()))
3638 }
3639}
3640
3641#[doc(hidden)]
3642impl<T> PgAnyJsonExpressionMethods for T
3643where
3644 T: Expression,
3645 T::SqlType: JsonOrNullableJsonOrJsonbOrNullableJsonb,
3646{
3647}
3648
3649/// PostgreSQL specific methods present on Binary expressions.
3650#[cfg(feature = "postgres_backend")]
3651pub trait PgBinaryExpressionMethods: Expression + Sized {
3652 /// Concatenates two PostgreSQL byte arrays using the `||` operator.
3653 ///
3654 /// # Example
3655 ///
3656 /// ```rust
3657 /// # include!("../../doctest_setup.rs");
3658 /// #
3659 /// # table! {
3660 /// # users {
3661 /// # id -> Integer,
3662 /// # name -> Binary,
3663 /// # hair_color -> Nullable<Binary>,
3664 /// # }
3665 /// # }
3666 /// #
3667 /// # fn main() {
3668 /// # use self::users::dsl::*;
3669 /// # use diesel::insert_into;
3670 /// #
3671 /// # let connection = &mut connection_no_data();
3672 /// # diesel::sql_query("CREATE TABLE users (
3673 /// # id INTEGER PRIMARY KEY,
3674 /// # name BYTEA NOT NULL,
3675 /// # hair_color BYTEA
3676 /// # )").execute(connection).unwrap();
3677 /// #
3678 /// # insert_into(users)
3679 /// # .values(&vec![
3680 /// # (id.eq(1), name.eq("Sean".as_bytes()), Some(hair_color.eq(Some("Green".as_bytes())))),
3681 /// # (id.eq(2), name.eq("Tess".as_bytes()), None),
3682 /// # ])
3683 /// # .execute(connection)
3684 /// # .unwrap();
3685 /// #
3686 /// let names = users.select(name.concat(" the Greatest".as_bytes())).load(connection);
3687 /// let expected_names = vec![
3688 /// b"Sean the Greatest".to_vec(),
3689 /// b"Tess the Greatest".to_vec()
3690 /// ];
3691 /// assert_eq!(Ok(expected_names), names);
3692 ///
3693 /// // If the value is nullable, the output will be nullable
3694 /// let names = users.select(hair_color.concat("ish".as_bytes())).load(connection);
3695 /// let expected_names = vec![
3696 /// Some(b"Greenish".to_vec()),
3697 /// None,
3698 /// ];
3699 /// assert_eq!(Ok(expected_names), names);
3700 /// # }
3701 /// ```
3702 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
3703 where
3704 Self::SqlType: SqlType,
3705 T: AsExpression<Self::SqlType>,
3706 {
3707 Grouped(Concat::new(self, other.as_expression()))
3708 }
3709
3710 /// Creates a PostgreSQL binary `LIKE` expression.
3711 ///
3712 /// This method is case sensitive. There is no case-insensitive
3713 /// equivalent as of PostgreSQL 14.
3714 ///
3715 /// # Examples
3716 ///
3717 /// ```rust
3718 /// # include!("../../doctest_setup.rs");
3719 /// #
3720 /// # table! {
3721 /// # users {
3722 /// # id -> Integer,
3723 /// # name -> Binary,
3724 /// # }
3725 /// # }
3726 /// #
3727 /// # fn main() {
3728 /// # use self::users::dsl::*;
3729 /// # use diesel::insert_into;
3730 /// #
3731 /// # let connection = &mut connection_no_data();
3732 /// # diesel::sql_query("CREATE TABLE users (
3733 /// # id INTEGER PRIMARY KEY,
3734 /// # name BYTEA NOT NULL
3735 /// # )").execute(connection).unwrap();
3736 /// #
3737 /// # insert_into(users)
3738 /// # .values(&vec![
3739 /// # (id.eq(1), name.eq("Sean".as_bytes())),
3740 /// # (id.eq(2), name.eq("Tess".as_bytes()))
3741 /// # ])
3742 /// # .execute(connection)
3743 /// # .unwrap();
3744 /// #
3745 /// let starts_with_s = users
3746 /// .select(name)
3747 /// .filter(name.like(b"S%".to_vec()))
3748 /// .load(connection);
3749 /// assert_eq!(Ok(vec![b"Sean".to_vec()]), starts_with_s);
3750 /// # }
3751 /// ```
3752 fn like<T>(self, other: T) -> dsl::Like<Self, T>
3753 where
3754 Self::SqlType: SqlType,
3755 T: AsExpression<Self::SqlType>,
3756 {
3757 Grouped(Like::new(self, other.as_expression()))
3758 }
3759
3760 /// Creates a PostgreSQL binary `LIKE` expression.
3761 ///
3762 /// This method is case sensitive. There is no case-insensitive
3763 /// equivalent as of PostgreSQL 14.
3764 ///
3765 /// # Examples
3766 ///
3767 /// ```rust
3768 /// # include!("../../doctest_setup.rs");
3769 /// #
3770 /// # table! {
3771 /// # users {
3772 /// # id -> Integer,
3773 /// # name -> Binary,
3774 /// # }
3775 /// # }
3776 /// #
3777 /// # fn main() {
3778 /// # use self::users::dsl::*;
3779 /// # use diesel::insert_into;
3780 /// #
3781 /// # let connection = &mut connection_no_data();
3782 /// # diesel::sql_query("CREATE TABLE users (
3783 /// # id INTEGER PRIMARY KEY,
3784 /// # name BYTEA NOT NULL
3785 /// # )").execute(connection).unwrap();
3786 /// #
3787 /// # insert_into(users)
3788 /// # .values(&vec![
3789 /// # (id.eq(1), name.eq("Sean".as_bytes())),
3790 /// # (id.eq(2), name.eq("Tess".as_bytes()))
3791 /// # ])
3792 /// # .execute(connection)
3793 /// # .unwrap();
3794 /// #
3795 /// let starts_with_s = users
3796 /// .select(name)
3797 /// .filter(name.not_like(b"S%".to_vec()))
3798 /// .load(connection);
3799 /// assert_eq!(Ok(vec![b"Tess".to_vec()]), starts_with_s);
3800 /// # }
3801 /// ```
3802 fn not_like<T>(self, other: T) -> dsl::NotLike<Self, T>
3803 where
3804 Self::SqlType: SqlType,
3805 T: AsExpression<Self::SqlType>,
3806 {
3807 Grouped(NotLike::new(self, other.as_expression()))
3808 }
3809}
3810
3811#[doc(hidden)]
3812impl<T> PgBinaryExpressionMethods for T
3813where
3814 T: Expression,
3815 T::SqlType: BinaryOrNullableBinary,
3816{
3817}
3818
3819pub(in crate::pg) mod private {
3820 use crate::sql_types::{
3821 AllAreNullable, Array, Binary, Cidr, Inet, Integer, Json, Jsonb, MaybeNullableType,
3822 Multirange, Nullable, Range, Record, SingleValue, SqlType, Text,
3823 };
3824 use crate::{Expression, IntoSql};
3825
3826 /// Marker trait used to implement `ArrayExpressionMethods` on the appropriate
3827 /// types. Once coherence takes associated types into account, we can remove
3828 /// this trait.
3829 #[diagnostic::on_unimplemented(
3830 message = "`{Self}` is neither `diesel::sql_types::Array<_>` nor `diesel::sql_types::Nullable<Array<_>>`",
3831 note = "try to provide an expression that produces one of the expected sql types"
3832 )]
3833 pub trait ArrayOrNullableArray {
3834 type Inner;
3835 }
3836
3837 impl<T> ArrayOrNullableArray for Array<T> {
3838 type Inner = T;
3839 }
3840 impl<T> ArrayOrNullableArray for Nullable<Array<T>> {
3841 type Inner = T;
3842 }
3843
3844 /// Marker trait used to implement `PgNetExpressionMethods` on the appropriate types.
3845 #[diagnostic::on_unimplemented(
3846 message = "`{Self}` is neither `diesel::sql_types::Inet`, `diesel::sql_types::Cidr`, `diesel::sql_types::Nullable<Inet>` nor `diesel::sql_types::Nullable<Cidr>",
3847 note = "try to provide an expression that produces one of the expected sql types"
3848 )]
3849 pub trait InetOrCidr {}
3850
3851 impl InetOrCidr for Inet {}
3852 impl InetOrCidr for Cidr {}
3853 impl InetOrCidr for Nullable<Inet> {}
3854 impl InetOrCidr for Nullable<Cidr> {}
3855
3856 /// Marker trait used to implement `PgTextExpressionMethods` on the appropriate
3857 /// types. Once coherence takes associated types into account, we can remove
3858 /// this trait.
3859 #[diagnostic::on_unimplemented(
3860 message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Nullable<Text>`",
3861 note = "try to provide an expression that produces one of the expected sql types"
3862 )]
3863 pub trait TextOrNullableText {}
3864
3865 impl TextOrNullableText for Text {}
3866 impl TextOrNullableText for Nullable<Text> {}
3867
3868 /// Marker trait used to extract the inner type
3869 /// of our `Range<T>` and `Multirange<T>` sql type, used to implement `PgRangeExpressionMethods`
3870 pub trait RangeOrMultirange: SqlType + SingleValue {
3871 type Inner: SingleValue;
3872 }
3873
3874 impl<ST> RangeOrMultirange for Range<ST>
3875 where
3876 Self: 'static,
3877 ST: SingleValue,
3878 {
3879 type Inner = ST;
3880 }
3881
3882 impl<ST> RangeOrMultirange for Multirange<ST>
3883 where
3884 Self: 'static,
3885 ST: SingleValue,
3886 {
3887 type Inner = ST;
3888 }
3889
3890 /// Marker trait used to implement `PgRangeExpressionMethods` on the appropriate
3891 /// types. Once coherence takes associated types into account, we can remove
3892 /// this trait.
3893 #[diagnostic::on_unimplemented(
3894 message = "`{Self}` is neither `diesel::sql_types::Range<_>` nor `diesel::sql_types::Nullable<Range<_>>`",
3895 note = "try to provide an expression that produces one of the expected sql types"
3896 )]
3897 pub trait RangeOrNullableRange {
3898 type Inner: SingleValue;
3899 }
3900
3901 impl<ST: SingleValue> RangeOrNullableRange for Range<ST> {
3902 type Inner = ST;
3903 }
3904 impl<ST: SingleValue> RangeOrNullableRange for Nullable<Range<ST>> {
3905 type Inner = ST;
3906 }
3907
3908 /// Marker trait used to implement `PgRangeExpressionMethods` on the appropriate
3909 /// types. Once coherence takes associated types into account, we can remove
3910 /// this trait.
3911 #[diagnostic::on_unimplemented(
3912 message = "`{Self}` is neither `diesel::sql_types::Range<_>` nor `diesel::sql_types::Nullable<Range<_>>`",
3913 note = "try to provide an expression that produces one of the expected sql types"
3914 )]
3915 pub trait MultirangeOrNullableMultirange {
3916 type Inner: SingleValue;
3917 type Range: SingleValue;
3918 }
3919
3920 impl<ST: SingleValue> MultirangeOrNullableMultirange for Multirange<ST> {
3921 type Inner = ST;
3922 type Range = Range<ST>;
3923 }
3924 impl<ST: SingleValue> MultirangeOrNullableMultirange for Nullable<Multirange<ST>> {
3925 type Inner = ST;
3926 type Range = Nullable<Range<ST>>;
3927 }
3928
3929 /// Marker trait used to implement `PgRangeExpressionMethods` on the appropriate
3930 /// types. Once coherence takes associated types into account, we can remove
3931 /// this trait.
3932 #[diagnostic::on_unimplemented(
3933 message = "`{Self}` is neither `diesel::sql_types::Range<_>` nor `diesel::sql_types::Multirange<_>`",
3934 note = "try to provide an expression that produces one of the expected sql types"
3935 )]
3936 pub trait MultirangeOrRangeMaybeNullable {
3937 type Inner: SingleValue;
3938 }
3939
3940 impl<ST: SingleValue> MultirangeOrRangeMaybeNullable for Range<ST> {
3941 type Inner = ST;
3942 }
3943 impl<ST: SingleValue> MultirangeOrRangeMaybeNullable for Nullable<Range<ST>> {
3944 type Inner = ST;
3945 }
3946 impl<ST: SingleValue> MultirangeOrRangeMaybeNullable for Multirange<ST> {
3947 type Inner = ST;
3948 }
3949 impl<ST: SingleValue> MultirangeOrRangeMaybeNullable for Nullable<Multirange<ST>> {
3950 type Inner = ST;
3951 }
3952
3953 /// Marker trait used to implement `PgJsonbExpressionMethods` on the appropriate types.
3954 #[diagnostic::on_unimplemented(
3955 message = "`{Self}` is neither `diesel::sql_types::Jsonb` nor `diesel::sql_types::Nullable<Jsonb>`",
3956 note = "try to provide an expression that produces one of the expected sql types"
3957 )]
3958 pub trait JsonbOrNullableJsonb {}
3959
3960 impl JsonbOrNullableJsonb for Jsonb {}
3961 impl JsonbOrNullableJsonb for Nullable<Jsonb> {}
3962
3963 #[diagnostic::on_unimplemented(
3964 message = "`{Self}` is neither `diesel::sql_types::Json` nor `diesel::sql_types::Nullable<Json>`",
3965 note = "try to provide an expression that produces one of the expected sql types"
3966 )]
3967 pub trait JsonOrNullableJson {}
3968
3969 impl JsonOrNullableJson for Json {}
3970 impl JsonOrNullableJson for Nullable<Json> {}
3971
3972 /// A trait that describes valid json indices used by postgresql
3973 pub trait JsonRemoveIndex {
3974 /// The Expression node created by this index type
3975 type Expression: Expression;
3976
3977 /// Convert a index value into the corresponding index expression
3978 fn into_json_index_expression(self) -> Self::Expression;
3979 }
3980
3981 impl<'a> JsonRemoveIndex for &'a str {
3982 type Expression = crate::dsl::AsExprOf<&'a str, crate::sql_types::Text>;
3983
3984 fn into_json_index_expression(self) -> Self::Expression {
3985 self.into_sql::<Text>()
3986 }
3987 }
3988
3989 impl JsonRemoveIndex for String {
3990 type Expression = crate::dsl::AsExprOf<String, crate::sql_types::Text>;
3991
3992 fn into_json_index_expression(self) -> Self::Expression {
3993 self.into_sql::<Text>()
3994 }
3995 }
3996
3997 impl JsonRemoveIndex for Vec<String> {
3998 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
3999
4000 fn into_json_index_expression(self) -> Self::Expression {
4001 self.into_sql::<Array<Text>>()
4002 }
4003 }
4004
4005 impl JsonRemoveIndex for Vec<&str> {
4006 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
4007
4008 fn into_json_index_expression(self) -> Self::Expression {
4009 self.into_sql::<Array<Text>>()
4010 }
4011 }
4012
4013 impl<'a> JsonRemoveIndex for &'a [&'a str] {
4014 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
4015
4016 fn into_json_index_expression(self) -> Self::Expression {
4017 self.into_sql::<Array<Text>>()
4018 }
4019 }
4020
4021 impl JsonRemoveIndex for i32 {
4022 type Expression = crate::dsl::AsExprOf<i32, crate::sql_types::Int4>;
4023
4024 fn into_json_index_expression(self) -> Self::Expression {
4025 self.into_sql::<crate::sql_types::Int4>()
4026 }
4027 }
4028
4029 impl<T> JsonRemoveIndex for T
4030 where
4031 T: Expression,
4032 T::SqlType: TextArrayOrTextOrInteger,
4033 {
4034 type Expression = Self;
4035
4036 fn into_json_index_expression(self) -> Self::Expression {
4037 self
4038 }
4039 }
4040
4041 #[diagnostic::on_unimplemented(
4042 message = "`{Self}` is neither `diesel::sql_types::Text`, `diesel::sql_types::Integer` nor `diesel::sql_types::Array<Text>`",
4043 note = "try to provide an expression that produces one of the expected sql types"
4044 )]
4045 pub trait TextArrayOrTextOrInteger {}
4046
4047 impl TextArrayOrTextOrInteger for Array<Text> {}
4048 impl TextArrayOrTextOrInteger for Text {}
4049 impl TextArrayOrTextOrInteger for Integer {}
4050
4051 /// Marker trait used to implement `PgAnyJsonExpressionMethods` on the appropriate types.
4052 #[diagnostic::on_unimplemented(
4053 message = "`{Self}` is neither `diesel::sql_types::Json`, `diesel::sql_types::Jsonb`, `diesel::sql_types::Nullable<Json>` nor `diesel::sql_types::Nullable<Jsonb>`",
4054 note = "try to provide an expression that produces one of the expected sql types"
4055 )]
4056 pub trait JsonOrNullableJsonOrJsonbOrNullableJsonb {}
4057 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Json {}
4058 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Json> {}
4059 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Jsonb {}
4060 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Jsonb> {}
4061
4062 pub trait JsonIndex {
4063 type Expression: Expression;
4064
4065 fn into_json_index_expression(self) -> Self::Expression;
4066 }
4067
4068 impl<'a> JsonIndex for &'a str {
4069 type Expression = crate::dsl::AsExprOf<&'a str, crate::sql_types::Text>;
4070
4071 fn into_json_index_expression(self) -> Self::Expression {
4072 self.into_sql::<Text>()
4073 }
4074 }
4075
4076 impl JsonIndex for String {
4077 type Expression = crate::dsl::AsExprOf<String, crate::sql_types::Text>;
4078
4079 fn into_json_index_expression(self) -> Self::Expression {
4080 self.into_sql::<Text>()
4081 }
4082 }
4083
4084 impl JsonIndex for i32 {
4085 type Expression = crate::dsl::AsExprOf<i32, crate::sql_types::Int4>;
4086
4087 fn into_json_index_expression(self) -> Self::Expression {
4088 self.into_sql::<crate::sql_types::Int4>()
4089 }
4090 }
4091
4092 impl<T> JsonIndex for T
4093 where
4094 T: Expression,
4095 T::SqlType: TextOrInteger,
4096 {
4097 type Expression = Self;
4098
4099 fn into_json_index_expression(self) -> Self::Expression {
4100 self
4101 }
4102 }
4103
4104 #[diagnostic::on_unimplemented(
4105 message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Integer`",
4106 note = "try to provide an expression that produces one of the expected sql types"
4107 )]
4108 pub trait TextOrInteger {}
4109 impl TextOrInteger for Text {}
4110 impl TextOrInteger for Integer {}
4111
4112 #[diagnostic::on_unimplemented(
4113 message = "`{Self}` is neither `diesel::sql_types::Binary` nor `diesel::sql_types::Nullable<Binary>`",
4114 note = "try to provide an expression that produces one of the expected sql types"
4115 )]
4116 pub trait BinaryOrNullableBinary {}
4117
4118 impl BinaryOrNullableBinary for Binary {}
4119 impl BinaryOrNullableBinary for Nullable<Binary> {}
4120
4121 pub trait MaybeNullableValue<T>: SingleValue {
4122 type Out: SingleValue;
4123 }
4124
4125 impl<T, O> MaybeNullableValue<O> for T
4126 where
4127 T: SingleValue,
4128 T::IsNull: MaybeNullableType<O>,
4129 <T::IsNull as MaybeNullableType<O>>::Out: SingleValue,
4130 {
4131 type Out = <T::IsNull as MaybeNullableType<O>>::Out;
4132 }
4133
4134 #[diagnostic::on_unimplemented(
4135 message = "`{Self}` is neither `Array<Text>`, `Array<Nullable<Text>>`,\
4136 `Nullable<Array<Text>>` nor `diesel::sql_types::Nullable<Array<Nullable<Text>>>`",
4137 note = "try to provide an expression that produces one of the expected sql types"
4138 )]
4139 pub trait TextArrayOrNullableTextArray {}
4140
4141 impl TextArrayOrNullableTextArray for Array<Text> {}
4142 impl TextArrayOrNullableTextArray for Array<Nullable<Text>> {}
4143 impl TextArrayOrNullableTextArray for Nullable<Array<Text>> {}
4144 impl TextArrayOrNullableTextArray for Nullable<Array<Nullable<Text>>> {}
4145
4146 #[diagnostic::on_unimplemented(
4147 message = "`{Self}` is neither `Record<T>` nor `Nullable<Record<T>>`",
4148 note = "try to provide an expression that produces one of the expected sql types"
4149 )]
4150 pub trait RecordOrNullableRecord {}
4151
4152 impl<T> RecordOrNullableRecord for Record<T> {}
4153 impl<T> RecordOrNullableRecord for Nullable<Record<T>> {}
4154
4155 pub trait CombinedAllNullableValue<O, Out>: SingleValue {
4156 type Out: SingleValue;
4157 }
4158
4159 impl<T, O, Out> CombinedAllNullableValue<O, Out> for T
4160 where
4161 T: SingleValue,
4162 O: SingleValue,
4163 T::IsNull: AllAreNullable<O::IsNull>,
4164 <T::IsNull as AllAreNullable<O::IsNull>>::Out: MaybeNullableType<Out>,
4165 <<T::IsNull as AllAreNullable<O::IsNull>>::Out as MaybeNullableType<Out>>::Out: SingleValue,
4166 {
4167 type Out = <<T::IsNull as AllAreNullable<O::IsNull>>::Out as MaybeNullableType<Out>>::Out;
4168 }
4169}