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