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