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