diesel/pg/expression/expression_methods.rs
1//! PostgreSQL specific expression methods
2
3pub(in crate::pg) use self::private::{
4 ArrayOrNullableArray, InetOrCidr, JsonIndex, JsonOrNullableJsonOrJsonbOrNullableJsonb,
5 JsonRemoveIndex, JsonbOrNullableJsonb, RangeHelper, RangeOrNullableRange, TextOrNullableText,
6};
7use super::date_and_time::{AtTimeZone, DateTimeLike};
8use super::operators::*;
9use crate::dsl;
10use crate::expression::grouped::Grouped;
11use crate::expression::operators::{Asc, Concat, Desc, Like, NotLike};
12use crate::expression::{AsExpression, Expression, IntoSql, TypedExpressionType};
13use crate::pg::expression::expression_methods::private::BinaryOrNullableBinary;
14use crate::sql_types::{Array, Inet, Integer, SqlType, Text, VarChar};
15use crate::EscapeExpressionMethods;
16
17/// PostgreSQL specific methods which are present on all expressions.
18#[cfg(feature = "postgres_backend")]
19pub trait PgExpressionMethods: Expression + Sized {
20 /// Creates a PostgreSQL `IS NOT DISTINCT FROM` expression.
21 ///
22 /// This behaves identically to the `=` operator, except that `NULL` is
23 /// treated as a normal value.
24 ///
25 /// # Example
26 ///
27 /// ```rust
28 /// # include!("../../doctest_setup.rs");
29 /// #
30 /// # fn main() {
31 /// # use schema::users::dsl::*;
32 /// # let connection = &mut establish_connection();
33 /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
34 /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
35 /// assert_eq!(Ok(2), distinct.first(connection));
36 /// assert_eq!(Ok(1), not_distinct.first(connection));
37 /// # }
38 /// ```
39 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
40 fn is_not_distinct_from<T>(self, other: T) -> dsl::IsNotDistinctFrom<Self, T>
41 where
42 Self::SqlType: SqlType,
43 T: AsExpression<Self::SqlType>,
44 {
45 Grouped(IsNotDistinctFrom::new(self, other.as_expression()))
46 }
47
48 /// Creates a PostgreSQL `IS DISTINCT FROM` expression.
49 ///
50 /// This behaves identically to the `!=` operator, except that `NULL` is
51 /// treated as a normal value.
52 ///
53 /// # Example
54 ///
55 /// ```rust
56 /// # include!("../../doctest_setup.rs");
57 /// #
58 /// # fn main() {
59 /// # use schema::users::dsl::*;
60 /// # let connection = &mut establish_connection();
61 /// let distinct = users.select(id).filter(name.is_distinct_from("Sean"));
62 /// let not_distinct = users.select(id).filter(name.is_not_distinct_from("Sean"));
63 /// assert_eq!(Ok(2), distinct.first(connection));
64 /// assert_eq!(Ok(1), not_distinct.first(connection));
65 /// # }
66 /// ```
67 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
68 fn is_distinct_from<T>(self, other: T) -> dsl::IsDistinctFrom<Self, T>
69 where
70 Self::SqlType: SqlType,
71 T: AsExpression<Self::SqlType>,
72 {
73 Grouped(IsDistinctFrom::new(self, other.as_expression()))
74 }
75}
76
77impl<T: Expression> PgExpressionMethods for T {}
78
79/// PostgreSQL specific methods present on timestamp expressions.
80#[cfg(feature = "postgres_backend")]
81pub trait PgTimestampExpressionMethods: Expression + Sized {
82 /// Creates a PostgreSQL "AT TIME ZONE" expression.
83 ///
84 /// When this is called on a `TIMESTAMP WITHOUT TIME ZONE` column,
85 /// the value will be treated as if were in the given time zone,
86 /// and then converted to UTC.
87 ///
88 /// When this is called on a `TIMESTAMP WITH TIME ZONE` column,
89 /// the value will be converted to the given time zone,
90 /// and then have its time zone information removed.
91 ///
92 /// # Example
93 ///
94 /// ```rust
95 /// # include!("../../doctest_setup.rs");
96 /// #
97 /// # table! {
98 /// # timestamps (timestamp) {
99 /// # timestamp -> Timestamp,
100 /// # }
101 /// # }
102 /// #
103 /// # fn main() {
104 /// # run_test().unwrap();
105 /// # }
106 /// #
107 /// # #[cfg(all(feature = "postgres", feature = "chrono"))]
108 /// # fn run_test() -> QueryResult<()> {
109 /// # use self::timestamps::dsl::*;
110 /// # use chrono::*;
111 /// # let connection = &mut establish_connection();
112 /// # diesel::sql_query("CREATE TABLE timestamps (\"timestamp\"
113 /// # timestamp NOT NULL)").execute(connection)?;
114 /// let christmas_morning = NaiveDate::from_ymd(2017, 12, 25)
115 /// .and_hms(8, 0, 0);
116 /// diesel::insert_into(timestamps)
117 /// .values(timestamp.eq(christmas_morning))
118 /// .execute(connection)?;
119 ///
120 /// let utc_time = timestamps
121 /// .select(timestamp.at_time_zone("UTC"))
122 /// .first(connection)?;
123 /// assert_eq!(christmas_morning, utc_time);
124 ///
125 /// let eastern_time = timestamps
126 /// .select(timestamp.at_time_zone("EST"))
127 /// .first(connection)?;
128 /// let five_hours_later = christmas_morning + Duration::hours(5);
129 /// assert_eq!(five_hours_later, eastern_time);
130 /// # Ok(())
131 /// # }
132 /// #
133 /// # #[cfg(not(all(feature = "postgres", feature = "chrono")))]
134 /// # fn run_test() -> QueryResult<()> {
135 /// # Ok(())
136 /// # }
137 /// ```
138 fn at_time_zone<T>(self, timezone: T) -> dsl::AtTimeZone<Self, T>
139 where
140 T: AsExpression<VarChar>,
141 {
142 Grouped(AtTimeZone::new(self, timezone.as_expression()))
143 }
144}
145
146impl<T: Expression> PgTimestampExpressionMethods for T where T::SqlType: DateTimeLike {}
147
148/// PostgreSQL specific methods present on array expressions.
149#[cfg(feature = "postgres_backend")]
150pub trait PgArrayExpressionMethods: Expression + Sized {
151 /// Creates a PostgreSQL `&&` expression.
152 ///
153 /// This operator returns whether two arrays have common elements.
154 ///
155 /// # Example
156 ///
157 /// ```rust
158 /// # include!("../../doctest_setup.rs");
159 /// #
160 /// # table! {
161 /// # posts {
162 /// # id -> Integer,
163 /// # tags -> Array<VarChar>,
164 /// # }
165 /// # }
166 /// #
167 /// # fn main() {
168 /// # run_test().unwrap();
169 /// # }
170 /// #
171 /// # fn run_test() -> QueryResult<()> {
172 /// # use self::posts::dsl::*;
173 /// # let conn = &mut establish_connection();
174 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
175 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
176 /// # .execute(conn)
177 /// # .unwrap();
178 /// #
179 /// diesel::insert_into(posts)
180 /// .values(&vec![
181 /// tags.eq(vec!["cool", "awesome"]),
182 /// tags.eq(vec!["awesome", "great"]),
183 /// tags.eq(vec!["cool", "great"]),
184 /// ])
185 /// .execute(conn)?;
186 ///
187 /// let data = posts.select(id)
188 /// .filter(tags.overlaps_with(vec!["horrid", "cool"]))
189 /// .load::<i32>(conn)?;
190 /// assert_eq!(vec![1, 3], data);
191 ///
192 /// let data = posts.select(id)
193 /// .filter(tags.overlaps_with(vec!["cool", "great"]))
194 /// .load::<i32>(conn)?;
195 /// assert_eq!(vec![1, 2, 3], data);
196 ///
197 /// let data = posts.select(id)
198 /// .filter(tags.overlaps_with(vec!["horrid"]))
199 /// .load::<i32>(conn)?;
200 /// assert!(data.is_empty());
201 /// # Ok(())
202 /// # }
203 /// ```
204 fn overlaps_with<T>(self, other: T) -> dsl::OverlapsWith<Self, T>
205 where
206 Self::SqlType: SqlType,
207 T: AsExpression<Self::SqlType>,
208 {
209 Grouped(OverlapsWith::new(self, other.as_expression()))
210 }
211
212 /// Creates a PostgreSQL `@>` expression.
213 ///
214 /// This operator returns whether an array contains another array.
215 ///
216 /// # Example
217 ///
218 /// ```rust
219 /// # include!("../../doctest_setup.rs");
220 /// #
221 /// # table! {
222 /// # posts {
223 /// # id -> Integer,
224 /// # tags -> Array<VarChar>,
225 /// # }
226 /// # }
227 /// #
228 /// # fn main() {
229 /// # run_test().unwrap();
230 /// # }
231 /// #
232 /// # fn run_test() -> QueryResult<()> {
233 /// # use self::posts::dsl::*;
234 /// # let conn = &mut establish_connection();
235 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
236 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
237 /// # .execute(conn)
238 /// # .unwrap();
239 /// #
240 /// diesel::insert_into(posts)
241 /// .values(tags.eq(vec!["cool", "awesome"]))
242 /// .execute(conn)?;
243 ///
244 /// let cool_posts = posts.select(id)
245 /// .filter(tags.contains(vec!["cool"]))
246 /// .load::<i32>(conn)?;
247 /// assert_eq!(vec![1], cool_posts);
248 ///
249 /// let amazing_posts = posts.select(id)
250 /// .filter(tags.contains(vec!["cool", "amazing"]))
251 /// .load::<i32>(conn)?;
252 /// assert!(amazing_posts.is_empty());
253 /// # Ok(())
254 /// # }
255 /// ```
256 fn contains<T>(self, other: T) -> dsl::Contains<Self, T>
257 where
258 Self::SqlType: SqlType,
259 T: AsExpression<Self::SqlType>,
260 {
261 Grouped(Contains::new(self, other.as_expression()))
262 }
263
264 /// Creates a PostgreSQL `<@` expression.
265 ///
266 /// This operator returns whether an array is contained by another array.
267 /// `foo.contains(bar)` is the same as `bar.is_contained_by(foo)`
268 ///
269 /// # Example
270 ///
271 /// ```rust
272 /// # include!("../../doctest_setup.rs");
273 /// #
274 /// # table! {
275 /// # posts {
276 /// # id -> Integer,
277 /// # tags -> Array<VarChar>,
278 /// # }
279 /// # }
280 /// #
281 /// # fn main() {
282 /// # run_test().unwrap();
283 /// # }
284 /// #
285 /// # fn run_test() -> QueryResult<()> {
286 /// # use self::posts::dsl::*;
287 /// # let conn = &mut establish_connection();
288 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
289 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
290 /// # .execute(conn)
291 /// # .unwrap();
292 /// #
293 /// diesel::insert_into(posts)
294 /// .values(tags.eq(vec!["cool", "awesome"]))
295 /// .execute(conn)?;
296 ///
297 /// let data = posts.select(id)
298 /// .filter(tags.is_contained_by(vec!["cool", "awesome", "amazing"]))
299 /// .load::<i32>(conn)?;
300 /// assert_eq!(vec![1], data);
301 ///
302 /// let data = posts.select(id)
303 /// .filter(tags.is_contained_by(vec!["cool"]))
304 /// .load::<i32>(conn)?;
305 /// assert!(data.is_empty());
306 /// # Ok(())
307 /// # }
308 /// ```
309 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
310 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedBy<Self, T>
311 where
312 Self::SqlType: SqlType,
313 T: AsExpression<Self::SqlType>,
314 {
315 Grouped(IsContainedBy::new(self, other.as_expression()))
316 }
317 /// Indexes a PostgreSQL array.
318 ///
319 /// This operator indexes in to an array to access a single element.
320 ///
321 /// Note that PostgreSQL arrays are 1-indexed, so `foo.index(1)` is the
322 /// first element in the array.
323 ///
324 /// # Example
325 ///
326 /// ```rust
327 /// # include!("../../doctest_setup.rs");
328 /// #
329 /// # table! {
330 /// # posts {
331 /// # id -> Integer,
332 /// # tags -> Array<VarChar>,
333 /// # }
334 /// # }
335 /// #
336 /// # fn main() {
337 /// # run_test().unwrap();
338 /// # }
339 /// #
340 /// # fn run_test() -> QueryResult<()> {
341 /// # use self::posts::dsl::*;
342 /// # let conn = &mut establish_connection();
343 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
344 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
345 /// # .execute(conn)
346 /// # .unwrap();
347 /// #
348 /// diesel::insert_into(posts)
349 /// .values(&vec![
350 /// tags.eq(vec!["cool", "awesome"]),
351 /// tags.eq(vec!["splendid", "marvellous"]),
352 /// ])
353 /// .execute(conn)?;
354 ///
355 /// let data = posts.select(tags.index(id))
356 /// .load::<String>(conn)?;
357 /// assert_eq!(vec!["cool", "marvellous"], data);
358 ///
359 /// let data = posts.select(id)
360 /// .filter(tags.index(1).eq("splendid"))
361 /// .load::<i32>(conn)?;
362 /// assert_eq!(vec![2], data);
363 /// # Ok(())
364 /// # }
365 /// ```
366 fn index<T>(self, other: T) -> dsl::Index<Self, T>
367 where
368 Self::SqlType: SqlType,
369 T: AsExpression<Integer>,
370 {
371 ArrayIndex::new(self, other.as_expression())
372 }
373
374 /// Creates a PostgreSQL `||` expression.
375 ///
376 /// This operator concatenates two Array values and returns Array value
377 ///
378 /// # Example
379 ///
380 /// ```rust
381 /// # include!("../../doctest_setup.rs");
382 /// #
383 /// # table! {
384 /// # posts {
385 /// # id -> Integer,
386 /// # tags -> Array<VarChar>,
387 /// # }
388 /// # }
389 /// #
390 /// # fn main() {
391 /// # run_test().unwrap();
392 /// # }
393 /// #
394 /// # fn run_test() -> QueryResult<()> {
395 /// # use self::posts::dsl::*;
396 /// # let conn = &mut establish_connection();
397 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
398 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, tags TEXT[] NOT NULL)")
399 /// # .execute(conn)
400 /// # .unwrap();
401 /// #
402 /// diesel::insert_into(posts)
403 /// .values(tags.eq(vec!["cool", "awesome"]))
404 /// .execute(conn)?;
405 ///
406 /// let res = posts.select(tags.concat(vec!["amazing"])).load::<Vec<String>>(conn)?;
407 /// let expected_tags = vec!["cool", "awesome", "amazing"];
408 /// assert_eq!(expected_tags, res[0]);
409 /// # Ok(())
410 /// # }
411 ///
412 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
413 where
414 Self::SqlType: SqlType,
415 T: AsExpression<Self::SqlType>,
416 {
417 Grouped(Concat::new(self, other.as_expression()))
418 }
419}
420
421impl<T> PgArrayExpressionMethods for T
422where
423 T: Expression,
424 T::SqlType: ArrayOrNullableArray,
425{
426}
427
428/// PostgreSQL expression methods related to sorting.
429///
430/// This trait is only implemented for `Asc` and `Desc`. Although `.asc` is
431/// implicit if no order is given, you will need to call `.asc()` explicitly in
432/// order to call these methods.
433#[cfg(feature = "postgres_backend")]
434pub trait PgSortExpressionMethods: Sized {
435 /// Specify that nulls should come before other values in this ordering.
436 ///
437 /// Normally, nulls come last when sorting in ascending order and first
438 /// when sorting in descending order.
439 ///
440 /// # Example
441 ///
442 /// ```rust
443 /// # include!("../../doctest_setup.rs");
444 /// #
445 /// # table! {
446 /// # nullable_numbers (nullable_number) {
447 /// # nullable_number -> Nullable<Integer>,
448 /// # }
449 /// # }
450 /// #
451 /// # fn main() {
452 /// # run_test().unwrap();
453 /// # }
454 /// #
455 /// # fn run_test() -> QueryResult<()> {
456 /// # use self::nullable_numbers::dsl::*;
457 /// # let connection = &mut connection_no_data();
458 /// # diesel::sql_query("CREATE TABLE nullable_numbers (nullable_number INTEGER)").execute(connection)?;
459 /// diesel::insert_into(nullable_numbers)
460 /// .values(&vec![
461 /// nullable_number.eq(None),
462 /// nullable_number.eq(Some(1)),
463 /// nullable_number.eq(Some(2)),
464 /// ])
465 /// .execute(connection)?;
466 ///
467 /// let asc_default_nulls = nullable_numbers.select(nullable_number)
468 /// .order(nullable_number.asc())
469 /// .load::<Option<i32>>(connection)?;
470 /// assert_eq!(vec![Some(1), Some(2), None], asc_default_nulls);
471 ///
472 /// let asc_nulls_first = nullable_numbers.select(nullable_number)
473 /// .order(nullable_number.asc().nulls_first())
474 /// .load::<Option<i32>>(connection)?;
475 /// assert_eq!(vec![None, Some(1), Some(2)], asc_nulls_first);
476 /// # Ok(())
477 /// # }
478 /// ```
479 fn nulls_first(self) -> dsl::NullsFirst<Self> {
480 NullsFirst::new(self)
481 }
482
483 /// Specify that nulls should come after other values in this ordering.
484 ///
485 /// Normally, nulls come last when sorting in ascending order and first
486 /// when sorting in descending order.
487 ///
488 /// # Example
489 ///
490 /// ```rust
491 /// # include!("../../doctest_setup.rs");
492 /// #
493 /// # table! {
494 /// # nullable_numbers (nullable_number) {
495 /// # nullable_number -> Nullable<Integer>,
496 /// # }
497 /// # }
498 /// #
499 /// # fn main() {
500 /// # run_test().unwrap();
501 /// # }
502 /// #
503 /// # fn run_test() -> QueryResult<()> {
504 /// # use self::nullable_numbers::dsl::*;
505 /// # let connection = &mut connection_no_data();
506 /// # diesel::sql_query("CREATE TABLE nullable_numbers (nullable_number INTEGER)").execute(connection)?;
507 /// diesel::insert_into(nullable_numbers)
508 /// .values(&vec![
509 /// nullable_number.eq(None),
510 /// nullable_number.eq(Some(1)),
511 /// nullable_number.eq(Some(2)),
512 /// ])
513 /// .execute(connection)?;
514 ///
515 /// let desc_default_nulls = nullable_numbers.select(nullable_number)
516 /// .order(nullable_number.desc())
517 /// .load::<Option<i32>>(connection)?;
518 /// assert_eq!(vec![None, Some(2), Some(1)], desc_default_nulls);
519 ///
520 /// let desc_nulls_last = nullable_numbers.select(nullable_number)
521 /// .order(nullable_number.desc().nulls_last())
522 /// .load::<Option<i32>>(connection)?;
523 /// assert_eq!(vec![Some(2), Some(1), None], desc_nulls_last);
524 /// # Ok(())
525 /// # }
526 /// ```
527 fn nulls_last(self) -> dsl::NullsLast<Self> {
528 NullsLast::new(self)
529 }
530}
531
532impl<T> PgSortExpressionMethods for Asc<T> {}
533impl<T> PgSortExpressionMethods for Desc<T> {}
534
535/// PostgreSQL specific methods present on text expressions.
536#[cfg(feature = "postgres_backend")]
537pub trait PgTextExpressionMethods: Expression + Sized {
538 /// Creates a PostgreSQL `ILIKE` expression
539 ///
540 /// # Example
541 ///
542 /// ```rust
543 /// # include!("../../doctest_setup.rs");
544 /// #
545 /// # fn main() {
546 /// # run_test().unwrap();
547 /// # }
548 /// #
549 /// # fn run_test() -> QueryResult<()> {
550 /// # use schema::animals::dsl::*;
551 /// # let connection = &mut establish_connection();
552 /// let starts_with_s = animals
553 /// .select(species)
554 /// .filter(name.ilike("s%").or(species.ilike("s%")))
555 /// .get_results::<String>(connection)?;
556 /// assert_eq!(vec!["spider"], starts_with_s);
557 /// # Ok(())
558 /// # }
559 /// ```
560 fn ilike<T>(self, other: T) -> dsl::ILike<Self, T>
561 where
562 T: AsExpression<Text>,
563 {
564 Grouped(ILike::new(self, other.as_expression()))
565 }
566
567 /// Creates a PostgreSQL `NOT ILIKE` expression
568 ///
569 /// # Example
570 ///
571 /// ```rust
572 /// # include!("../../doctest_setup.rs");
573 /// #
574 /// # fn main() {
575 /// # run_test().unwrap();
576 /// # }
577 /// #
578 /// # fn run_test() -> QueryResult<()> {
579 /// # use schema::animals::dsl::*;
580 /// # let connection = &mut establish_connection();
581 /// let doesnt_start_with_s = animals
582 /// .select(species)
583 /// .filter(name.not_ilike("s%").and(species.not_ilike("s%")))
584 /// .get_results::<String>(connection)?;
585 /// assert_eq!(vec!["dog"], doesnt_start_with_s);
586 /// # Ok(())
587 /// # }
588 /// ```
589 fn not_ilike<T>(self, other: T) -> dsl::NotILike<Self, T>
590 where
591 T: AsExpression<Text>,
592 {
593 Grouped(NotILike::new(self, other.as_expression()))
594 }
595
596 /// Creates a PostgreSQL `SIMILAR TO` expression
597 ///
598 /// # Example
599 /// ```
600 /// # include!("../../doctest_setup.rs");
601 /// #
602 /// # fn main() {
603 /// # run_test().unwrap();
604 /// # }
605 /// #
606 /// # fn run_test() -> QueryResult<()> {
607 /// # use schema::animals::dsl::*;
608 /// # let connection = &mut establish_connection();
609 /// let starts_with_s = animals
610 /// .select(species)
611 /// .filter(name.similar_to("s%").or(species.similar_to("s%")))
612 /// .get_results::<String>(connection)?;
613 /// assert_eq!(vec!["spider"], starts_with_s);
614 /// # Ok(())
615 /// # }
616 /// ```
617 fn similar_to<T>(self, other: T) -> dsl::SimilarTo<Self, T>
618 where
619 T: AsExpression<Text>,
620 {
621 Grouped(SimilarTo::new(self, other.as_expression()))
622 }
623
624 /// Creates a PostgreSQL `NOT SIMILAR TO` expression
625 ///
626 /// # Example
627 /// ```
628 /// # include!("../../doctest_setup.rs");
629 /// #
630 /// # fn main() {
631 /// # run_test().unwrap();
632 /// # }
633 /// #
634 /// # fn run_test() -> QueryResult<()> {
635 /// # use schema::animals::dsl::*;
636 /// # let connection = &mut establish_connection();
637 /// let doesnt_start_with_s = animals
638 /// .select(species)
639 /// .filter(name.not_similar_to("s%").and(species.not_similar_to("s%")))
640 /// .get_results::<String>(connection)?;
641 /// assert_eq!(vec!["dog"], doesnt_start_with_s);
642 /// # Ok(())
643 /// # }
644 /// ```
645 fn not_similar_to<T>(self, other: T) -> dsl::NotSimilarTo<Self, T>
646 where
647 T: AsExpression<Text>,
648 {
649 Grouped(NotSimilarTo::new(self, other.as_expression()))
650 }
651}
652
653impl<T> PgTextExpressionMethods for T
654where
655 T: Expression,
656 T::SqlType: TextOrNullableText,
657{
658}
659
660impl<T, U> EscapeExpressionMethods for Grouped<ILike<T, U>> {
661 type TextExpression = ILike<T, U>;
662
663 fn escape(self, character: char) -> dsl::Escape<Self> {
664 Grouped(crate::expression::operators::Escape::new(
665 self.0,
666 character.to_string().into_sql::<VarChar>(),
667 ))
668 }
669}
670
671impl<T, U> EscapeExpressionMethods for Grouped<NotILike<T, U>> {
672 type TextExpression = NotILike<T, U>;
673
674 fn escape(self, character: char) -> dsl::Escape<Self> {
675 Grouped(crate::expression::operators::Escape::new(
676 self.0,
677 character.to_string().into_sql::<VarChar>(),
678 ))
679 }
680}
681
682impl<T, U> EscapeExpressionMethods for Grouped<SimilarTo<T, U>> {
683 type TextExpression = SimilarTo<T, U>;
684
685 fn escape(self, character: char) -> dsl::Escape<Self> {
686 Grouped(crate::expression::operators::Escape::new(
687 self.0,
688 character.to_string().into_sql::<VarChar>(),
689 ))
690 }
691}
692
693impl<T, U> EscapeExpressionMethods for Grouped<NotSimilarTo<T, U>> {
694 type TextExpression = NotSimilarTo<T, U>;
695
696 fn escape(self, character: char) -> dsl::Escape<Self> {
697 Grouped(crate::expression::operators::Escape::new(
698 self.0,
699 character.to_string().into_sql::<VarChar>(),
700 ))
701 }
702}
703
704/// PostgreSQL specific methods present on range expressions.
705#[cfg(feature = "postgres_backend")]
706pub trait PgRangeExpressionMethods: Expression + Sized {
707 /// Creates a PostgreSQL `@>` expression.
708 ///
709 /// This operator returns whether a range contains an specific element
710 ///
711 /// # Example
712 ///
713 /// ```rust
714 /// # include!("../../doctest_setup.rs");
715 /// #
716 /// # table! {
717 /// # posts {
718 /// # id -> Integer,
719 /// # versions -> Range<Integer>,
720 /// # }
721 /// # }
722 /// #
723 /// # fn main() {
724 /// # run_test().unwrap();
725 /// # }
726 /// #
727 /// # fn run_test() -> QueryResult<()> {
728 /// # use self::posts::dsl::*;
729 /// # use std::collections::Bound;
730 /// # let conn = &mut establish_connection();
731 /// # diesel::sql_query("DROP TABLE IF EXISTS posts").execute(conn).unwrap();
732 /// # diesel::sql_query("CREATE TABLE posts (id SERIAL PRIMARY KEY, versions INT4RANGE NOT NULL)").execute(conn).unwrap();
733 /// #
734 /// diesel::insert_into(posts)
735 /// .values(versions.eq((Bound::Included(5), Bound::Unbounded)))
736 /// .execute(conn)?;
737 ///
738 /// let cool_posts = posts.select(id)
739 /// .filter(versions.contains(42))
740 /// .load::<i32>(conn)?;
741 /// assert_eq!(vec![1], cool_posts);
742 ///
743 /// let amazing_posts = posts.select(id)
744 /// .filter(versions.contains(1))
745 /// .load::<i32>(conn)?;
746 /// assert!(amazing_posts.is_empty());
747 /// # Ok(())
748 /// # }
749 /// ```
750 fn contains<T>(self, other: T) -> dsl::RangeContains<Self, T>
751 where
752 Self::SqlType: RangeHelper,
753 <Self::SqlType as RangeHelper>::Inner: SqlType + TypedExpressionType,
754 T: AsExpression<<Self::SqlType as RangeHelper>::Inner>,
755 {
756 Grouped(Contains::new(self, other.as_expression()))
757 }
758}
759
760impl<T> PgRangeExpressionMethods for T
761where
762 T: Expression,
763 T::SqlType: RangeOrNullableRange,
764{
765}
766
767/// PostgreSQL specific methods present between CIDR/INET expressions
768#[cfg(feature = "postgres_backend")]
769pub trait PgNetExpressionMethods: Expression + Sized {
770 /// Creates a PostgreSQL `>>` expression.
771 ///
772 /// This operator returns whether a subnet strictly contains another subnet or address.
773 ///
774 /// # Example
775 ///
776 /// ```rust
777 /// # include!("../../doctest_setup.rs");
778 /// #
779 /// # table! {
780 /// # hosts {
781 /// # id -> Integer,
782 /// # address -> Inet,
783 /// # }
784 /// # }
785 /// #
786 /// # fn main() {
787 /// # run_test().unwrap();
788 /// # }
789 /// #
790 /// # #[cfg(feature = "ipnetwork")]
791 /// # fn run_test() -> QueryResult<()> {
792 /// # use self::hosts::dsl::*;
793 /// # use ipnetwork::IpNetwork;
794 /// # use std::str::FromStr;
795 /// # let conn = &mut establish_connection();
796 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
797 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
798 /// diesel::insert_into(hosts)
799 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
800 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
801 /// .execute(conn)?;
802 ///
803 /// let my_hosts = hosts.select(id)
804 /// .filter(address.contains(IpNetwork::from_str("10.0.2.5").unwrap()))
805 /// .load::<i32>(conn)?;
806 /// assert_eq!(vec![1, 2], my_hosts);
807 ///
808 /// let my_hosts = hosts.select(id)
809 /// .filter(address.contains(IpNetwork::from_str("10.0.2.5/24").unwrap()))
810 /// .load::<i32>(conn)?;
811 /// assert_eq!(vec![2], my_hosts);
812 ///
813 /// let my_hosts = hosts.select(id)
814 /// .filter(address.contains(IpNetwork::from_str("10.0.3.31").unwrap()))
815 /// .load::<i32>(conn)?;
816 /// assert_eq!(vec![2], my_hosts);
817 /// # Ok(())
818 /// # }
819 /// #
820 /// # #[cfg(not(feature = "ipnetwork"))]
821 /// # fn run_test() -> QueryResult<()> {
822 /// # Ok(())
823 /// # }
824 /// ```
825 fn contains<T>(self, other: T) -> dsl::ContainsNet<Self, T>
826 where
827 T: AsExpression<Inet>,
828 {
829 Grouped(ContainsNet::new(self, other.as_expression()))
830 }
831
832 /// Creates a PostgreSQL `>>=` expression.
833 ///
834 /// This operator returns whether a subnet contains or is equal to another subnet.
835 ///
836 /// # Example
837 ///
838 /// ```rust
839 /// # include!("../../doctest_setup.rs");
840 /// #
841 /// # table! {
842 /// # hosts {
843 /// # id -> Integer,
844 /// # address -> Inet,
845 /// # }
846 /// # }
847 /// #
848 /// # fn main() {
849 /// # run_test().unwrap();
850 /// # }
851 /// #
852 /// # #[cfg(feature = "ipnetwork")]
853 /// # fn run_test() -> QueryResult<()> {
854 /// # use self::hosts::dsl::*;
855 /// # use ipnetwork::IpNetwork;
856 /// # use std::str::FromStr;
857 /// # let conn = &mut establish_connection();
858 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
859 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
860 /// diesel::insert_into(hosts)
861 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
862 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
863 /// .execute(conn)?;
864 ///
865 /// let my_hosts = hosts.select(id)
866 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.2.5").unwrap()))
867 /// .load::<i32>(conn)?;
868 /// assert_eq!(vec![1, 2], my_hosts);
869 ///
870 /// let my_hosts = hosts.select(id)
871 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.2.5/24").unwrap()))
872 /// .load::<i32>(conn)?;
873 /// assert_eq!(vec![1, 2], my_hosts);
874 ///
875 /// let my_hosts = hosts.select(id)
876 /// .filter(address.contains_or_eq(IpNetwork::from_str("10.0.3.31").unwrap()))
877 /// .load::<i32>(conn)?;
878 /// assert_eq!(vec![2], my_hosts);
879 /// # Ok(())
880 /// # }
881 /// #
882 /// # #[cfg(not(feature = "ipnetwork"))]
883 /// # fn run_test() -> QueryResult<()> {
884 /// # Ok(())
885 /// # }
886 /// ```
887 fn contains_or_eq<T>(self, other: T) -> dsl::ContainsNetLoose<Self, T>
888 where
889 T: AsExpression<Inet>,
890 {
891 Grouped(ContainsNetLoose::new(self, other.as_expression()))
892 }
893
894 /// Creates a PostgreSQL `<<` expression.
895 ///
896 /// This operator returns whether a subnet or address is strictly contained by another subnet.
897 ///
898 /// # Example
899 ///
900 /// ```rust
901 /// # include!("../../doctest_setup.rs");
902 /// #
903 /// # table! {
904 /// # hosts {
905 /// # id -> Integer,
906 /// # address -> Inet,
907 /// # }
908 /// # }
909 /// #
910 /// # fn main() {
911 /// # run_test().unwrap();
912 /// # }
913 /// #
914 /// # #[cfg(feature = "ipnetwork")]
915 /// # fn run_test() -> QueryResult<()> {
916 /// # use self::hosts::dsl::*;
917 /// # use ipnetwork::IpNetwork;
918 /// # use std::str::FromStr;
919 /// # let conn = &mut establish_connection();
920 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
921 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
922 /// diesel::insert_into(hosts)
923 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
924 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
925 /// .execute(conn)?;
926 ///
927 /// let my_hosts = hosts.select(id)
928 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.2.5/24").unwrap()))
929 /// .load::<i32>(conn)?;
930 /// assert_eq!(my_hosts.len(), 0);
931 ///
932 /// let my_hosts = hosts.select(id)
933 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.3.31/23").unwrap()))
934 /// .load::<i32>(conn)?;
935 /// assert_eq!(vec![1], my_hosts);
936 ///
937 /// let my_hosts = hosts.select(id)
938 /// .filter(address.is_contained_by(IpNetwork::from_str("10.0.3.31/22").unwrap()))
939 /// .load::<i32>(conn)?;
940 /// assert_eq!(vec![1, 2], my_hosts);
941 /// # Ok(())
942 /// # }
943 /// #
944 /// # #[cfg(not(feature = "ipnetwork"))]
945 /// # fn run_test() -> QueryResult<()> {
946 /// # Ok(())
947 /// # }
948 /// ```
949 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
950 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedByNet<Self, T>
951 where
952 T: AsExpression<Inet>,
953 {
954 Grouped(IsContainedByNet::new(self, other.as_expression()))
955 }
956
957 /// Creates a PostgreSQL `>>=` expression.
958 ///
959 /// This operator returns whether a subnet is contained by or equal to another subnet.
960 ///
961 /// # Example
962 ///
963 /// ```rust
964 /// # include!("../../doctest_setup.rs");
965 /// #
966 /// # table! {
967 /// # hosts {
968 /// # id -> Integer,
969 /// # address -> Inet,
970 /// # }
971 /// # }
972 /// #
973 /// # fn main() {
974 /// # run_test().unwrap();
975 /// # }
976 /// #
977 /// # #[cfg(feature = "ipnetwork")]
978 /// # fn run_test() -> QueryResult<()> {
979 /// # use self::hosts::dsl::*;
980 /// # use ipnetwork::IpNetwork;
981 /// # use std::str::FromStr;
982 /// # let conn = &mut establish_connection();
983 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
984 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
985 /// diesel::insert_into(hosts)
986 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
987 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
988 /// .execute(conn)?;
989 ///
990 /// let my_hosts = hosts.select(id)
991 /// .filter(address.is_contained_by_or_eq(IpNetwork::from_str("10.0.2.5/24").unwrap()))
992 /// .load::<i32>(conn)?;
993 /// assert_eq!(vec![1], my_hosts);
994 ///
995 /// let my_hosts = hosts.select(id)
996 /// .filter(address.is_contained_by_or_eq(IpNetwork::from_str("10.0.3.31/23").unwrap()))
997 /// .load::<i32>(conn)?;
998 /// assert_eq!(vec![1, 2], my_hosts);
999 /// # Ok(())
1000 /// # }
1001 /// #
1002 /// # #[cfg(not(feature = "ipnetwork"))]
1003 /// # fn run_test() -> QueryResult<()> {
1004 /// # Ok(())
1005 /// # }
1006 /// ```
1007 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1008 fn is_contained_by_or_eq<T>(self, other: T) -> dsl::IsContainedByNetLoose<Self, T>
1009 where
1010 T: AsExpression<Inet>,
1011 {
1012 Grouped(IsContainedByNetLoose::new(self, other.as_expression()))
1013 }
1014
1015 /// Creates a PostgreSQL `&&` expression.
1016 ///
1017 /// This operator returns whether a subnet contains or is contained by another subnet.
1018 ///
1019 /// # Example
1020 ///
1021 /// ```rust
1022 /// # include!("../../doctest_setup.rs");
1023 /// #
1024 /// # table! {
1025 /// # hosts {
1026 /// # id -> Integer,
1027 /// # address -> Inet,
1028 /// # }
1029 /// # }
1030 /// #
1031 /// # fn main() {
1032 /// # run_test().unwrap();
1033 /// # }
1034 /// #
1035 /// # #[cfg(feature = "ipnetwork")]
1036 /// # fn run_test() -> QueryResult<()> {
1037 /// # use self::hosts::dsl::*;
1038 /// # use ipnetwork::IpNetwork;
1039 /// # use std::str::FromStr;
1040 /// # let conn = &mut establish_connection();
1041 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
1042 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
1043 /// diesel::insert_into(hosts)
1044 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3/24").unwrap()),
1045 /// address.eq(IpNetwork::from_str("10.0.3.4/23").unwrap())])
1046 /// .execute(conn)?;
1047 ///
1048 /// let my_hosts = hosts.select(id)
1049 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.2.5/24").unwrap()))
1050 /// .load::<i32>(conn)?;
1051 /// assert_eq!(vec![1, 2], my_hosts);
1052 ///
1053 /// let my_hosts = hosts.select(id)
1054 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.3.31/24").unwrap()))
1055 /// .load::<i32>(conn)?;
1056 /// assert_eq!(vec![2], my_hosts);
1057 ///
1058 /// let my_hosts = hosts.select(id)
1059 /// .filter(address.overlaps_with(IpNetwork::from_str("10.0.3.31/23").unwrap()))
1060 /// .load::<i32>(conn)?;
1061 /// assert_eq!(vec![1, 2], my_hosts);
1062 /// # Ok(())
1063 /// # }
1064 /// #
1065 /// # #[cfg(not(feature = "ipnetwork"))]
1066 /// # fn run_test() -> QueryResult<()> {
1067 /// # Ok(())
1068 /// # }
1069 /// ```
1070 fn overlaps_with<T>(self, other: T) -> dsl::OverlapsWithNet<Self, T>
1071 where
1072 T: AsExpression<Inet>,
1073 {
1074 Grouped(OverlapsWith::new(self, other.as_expression()))
1075 }
1076
1077 /// Creates a PostgreSQL `&` expression.
1078 ///
1079 /// This operator computes the bitwise AND between two network addresses.
1080 ///
1081 /// # Example
1082 ///
1083 /// ```rust
1084 /// # include!("../../doctest_setup.rs");
1085 /// #
1086 /// # table! {
1087 /// # hosts {
1088 /// # id -> Integer,
1089 /// # address -> Inet,
1090 /// # }
1091 /// # }
1092 /// #
1093 /// # fn main() {
1094 /// # run_test().unwrap();
1095 /// # }
1096 /// #
1097 /// # #[cfg(feature = "ipnetwork")]
1098 /// # fn run_test() -> QueryResult<()> {
1099 /// # use self::hosts::dsl::*;
1100 /// # use ipnetwork::IpNetwork;
1101 /// # use std::str::FromStr;
1102 /// # let conn = &mut establish_connection();
1103 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
1104 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
1105 /// diesel::insert_into(hosts)
1106 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3").unwrap())])
1107 /// .execute(conn)?;
1108 ///
1109 /// let addr = hosts
1110 /// .select(address.and(IpNetwork::from_str("0.0.0.255").unwrap()))
1111 /// .first::<IpNetwork>(conn)?;
1112 /// assert_eq!(addr, IpNetwork::from_str("0.0.0.3").unwrap());
1113 /// # Ok(())
1114 /// # }
1115 /// #
1116 /// # #[cfg(not(feature = "ipnetwork"))]
1117 /// # fn run_test() -> QueryResult<()> {
1118 /// # Ok(())
1119 /// # }
1120 /// ```
1121 fn and<T>(self, other: T) -> dsl::AndNet<Self, T>
1122 where
1123 T: AsExpression<Inet>,
1124 {
1125 Grouped(AndNet::new(self, other.as_expression()))
1126 }
1127
1128 /// Creates a PostgreSQL `|` expression.
1129 ///
1130 /// This operator computes the bitwise OR between two network addresses.
1131 ///
1132 /// # Example
1133 ///
1134 /// ```rust
1135 /// # include!("../../doctest_setup.rs");
1136 /// #
1137 /// # table! {
1138 /// # hosts {
1139 /// # id -> Integer,
1140 /// # address -> Inet,
1141 /// # }
1142 /// # }
1143 /// #
1144 /// # fn main() {
1145 /// # run_test().unwrap();
1146 /// # }
1147 /// #
1148 /// # #[cfg(feature = "ipnetwork")]
1149 /// # fn run_test() -> QueryResult<()> {
1150 /// # use self::hosts::dsl::*;
1151 /// # use ipnetwork::IpNetwork;
1152 /// # use std::str::FromStr;
1153 /// # let conn = &mut establish_connection();
1154 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
1155 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
1156 /// diesel::insert_into(hosts)
1157 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.3").unwrap())])
1158 /// .execute(conn)?;
1159 ///
1160 /// let addr = hosts
1161 /// .select(address.or(IpNetwork::from_str("0.0.0.255").unwrap()))
1162 /// .first::<IpNetwork>(conn)?;
1163 /// assert_eq!(addr, IpNetwork::from_str("10.0.2.255").unwrap());
1164 /// # Ok(())
1165 /// # }
1166 /// #
1167 /// # #[cfg(not(feature = "ipnetwork"))]
1168 /// # fn run_test() -> QueryResult<()> {
1169 /// # Ok(())
1170 /// # }
1171 /// ```
1172 fn or<T>(self, other: T) -> dsl::OrNet<Self, T>
1173 where
1174 T: AsExpression<Inet>,
1175 {
1176 Grouped(OrNet::new(self, other.as_expression()))
1177 }
1178
1179 /// Creates a PostgreSQL `-` expression.
1180 ///
1181 /// This operator subtracts an address from an address to compute the distance between the two
1182 ///
1183 /// # Example
1184 ///
1185 /// ```rust
1186 /// # include!("../../doctest_setup.rs");
1187 /// #
1188 /// # table! {
1189 /// # hosts {
1190 /// # id -> Integer,
1191 /// # address -> Inet,
1192 /// # }
1193 /// # }
1194 /// #
1195 /// # fn main() {
1196 /// # run_test().unwrap();
1197 /// # }
1198 /// #
1199 /// # #[cfg(feature = "ipnetwork")]
1200 /// # fn run_test() -> QueryResult<()> {
1201 /// # use self::hosts::dsl::*;
1202 /// # use ipnetwork::IpNetwork;
1203 /// # use std::str::FromStr;
1204 /// # let conn = &mut establish_connection();
1205 /// # diesel::sql_query("DROP TABLE IF EXISTS hosts").execute(conn).unwrap();
1206 /// # diesel::sql_query("CREATE TABLE hosts (id SERIAL PRIMARY KEY, address INET NOT NULL)").execute(conn).unwrap();
1207 /// diesel::insert_into(hosts)
1208 /// .values(vec![address.eq(IpNetwork::from_str("10.0.2.53").unwrap())])
1209 /// .execute(conn)?;
1210 ///
1211 /// let offset = hosts
1212 /// .select(address.diff(IpNetwork::from_str("10.0.2.42").unwrap()))
1213 /// .first::<i64>(conn)?;
1214 /// assert_eq!(offset, 11);
1215 /// # Ok(())
1216 /// # }
1217 /// #
1218 /// # #[cfg(not(feature = "ipnetwork"))]
1219 /// # fn run_test() -> QueryResult<()> {
1220 /// # Ok(())
1221 /// # }
1222 /// ```
1223 fn diff<T>(self, other: T) -> dsl::DifferenceNet<Self, T>
1224 where
1225 T: AsExpression<Inet>,
1226 {
1227 Grouped(DifferenceNet::new(self, other.as_expression()))
1228 }
1229}
1230
1231impl<T> PgNetExpressionMethods for T
1232where
1233 T: Expression,
1234 T::SqlType: InetOrCidr,
1235{
1236}
1237
1238/// PostgreSQL specific methods present on JSONB expressions.
1239#[cfg(feature = "postgres_backend")]
1240pub trait PgJsonbExpressionMethods: Expression + Sized {
1241 /// Creates a PostgreSQL `||` expression.
1242 ///
1243 /// This operator concatenates two JSONB values and returns JSONB value
1244 ///
1245 /// # Example
1246 ///
1247 /// ```rust
1248 /// # include!("../../doctest_setup.rs");
1249 /// #
1250 /// # table! {
1251 /// # contacts {
1252 /// # id -> Integer,
1253 /// # name -> VarChar,
1254 /// # address -> Jsonb,
1255 /// # }
1256 /// # }
1257 /// #
1258 /// # fn main() {
1259 /// # run_test().unwrap();
1260 /// # }
1261 ///
1262 /// # #[cfg(feature = "serde_json")]
1263 /// # fn run_test() -> QueryResult<()> {
1264 /// # use self::contacts::dsl::*;
1265 /// # let conn = &mut establish_connection();
1266 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1267 /// # diesel::sql_query("CREATE TABLE contacts (
1268 /// # id SERIAL PRIMARY KEY,
1269 /// # name VARCHAR NOT NULL,
1270 /// # address JSONB NOT NULL
1271 /// # )").execute(conn).unwrap();
1272 /// #
1273 /// let santas_address: serde_json::Value = serde_json::json!({
1274 /// "street": "Article Circle Expressway 1",
1275 /// "city": "North Pole",
1276 /// "postcode": "99705",
1277 /// "state": "Alaska"
1278 /// });
1279 /// diesel::insert_into(contacts)
1280 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1281 /// .execute(conn)?;
1282 ///
1283 /// let to_concatenate: serde_json::Value = serde_json::json!({
1284 /// "continent": "NA",
1285 /// "planet": "Earth"
1286 /// });
1287 ///
1288 /// let final_address: serde_json::Value = serde_json::json!({
1289 /// "street": "Article Circle Expressway 1",
1290 /// "city": "North Pole",
1291 /// "postcode": "99705",
1292 /// "state": "Alaska",
1293 /// "continent": "NA",
1294 /// "planet": "Earth"
1295 /// });
1296 ///
1297 /// let final_address_db = contacts.select(address.concat(&to_concatenate)).get_result::<serde_json::Value>(conn)?;
1298 /// assert_eq!(final_address, final_address_db);
1299 /// # Ok(())
1300 /// # }
1301 /// # #[cfg(not(feature = "serde_json"))]
1302 /// # fn run_test() -> QueryResult<()> {
1303 /// # Ok(())
1304 /// # }
1305 /// ```
1306 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
1307 where
1308 Self::SqlType: SqlType,
1309 T: AsExpression<Self::SqlType>,
1310 {
1311 Grouped(Concat::new(self, other.as_expression()))
1312 }
1313
1314 /// Creates a PostgreSQL `?` expression.
1315 ///
1316 /// This operator checks if the right hand side string exists as a top-level key within the JSONB
1317 ///
1318 /// # Example
1319 ///
1320 /// ```rust
1321 /// # include!("../../doctest_setup.rs");
1322 /// #
1323 /// # table! {
1324 /// # contacts {
1325 /// # id -> Integer,
1326 /// # name -> VarChar,
1327 /// # address -> Jsonb,
1328 /// # }
1329 /// # }
1330 /// #
1331 /// # fn main() {
1332 /// # run_test().unwrap();
1333 /// # }
1334 ///
1335 /// # #[cfg(feature = "serde_json")]
1336 /// # fn run_test() -> QueryResult<()> {
1337 /// # use self::contacts::dsl::*;
1338 /// # let conn = &mut establish_connection();
1339 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1340 /// # diesel::sql_query("CREATE TABLE contacts (
1341 /// # id SERIAL PRIMARY KEY,
1342 /// # name VARCHAR NOT NULL,
1343 /// # address JSONB NOT NULL
1344 /// # )").execute(conn).unwrap();
1345 /// #
1346 /// let santas_address: serde_json::Value = serde_json::json!({
1347 /// "street": "Article Circle Expressway 1",
1348 /// "city": "North Pole",
1349 /// "postcode": "99705",
1350 /// "state": "Alaska"
1351 /// });
1352 /// diesel::insert_into(contacts)
1353 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1354 /// .execute(conn)?;
1355 ///
1356 /// let key_exists = contacts.select(address.has_key("street")).get_result::<bool>(conn)?;
1357 /// assert!(key_exists);
1358 ///
1359 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_key("postcode")).get_result::<i32>(conn)?;
1360 /// assert_eq!(1, santas_with_address_postcode);
1361 /// # Ok(())
1362 /// # }
1363 /// # #[cfg(not(feature = "serde_json"))]
1364 /// # fn run_test() -> QueryResult<()> {
1365 /// # Ok(())
1366 /// # }
1367 /// ```
1368 fn has_key<T>(self, other: T) -> dsl::HasKeyJsonb<Self, T>
1369 where
1370 T: AsExpression<VarChar>,
1371 {
1372 Grouped(HasKeyJsonb::new(self, other.as_expression()))
1373 }
1374
1375 /// Creates a PostgreSQL `?|` expression.
1376 ///
1377 /// This operator checks if any of the strings in the right hand side array exists as top level key in the given JSONB
1378 ///
1379 /// # Example
1380 ///
1381 /// ```rust
1382 /// # include!("../../doctest_setup.rs");
1383 /// #
1384 /// # table! {
1385 /// # contacts {
1386 /// # id -> Integer,
1387 /// # name -> VarChar,
1388 /// # address -> Jsonb,
1389 /// # }
1390 /// # }
1391 /// #
1392 /// # fn main() {
1393 /// # run_test().unwrap();
1394 /// # }
1395 ///
1396 /// # #[cfg(feature = "serde_json")]
1397 /// # fn run_test() -> QueryResult<()> {
1398 /// # use self::contacts::dsl::*;
1399 /// # let conn = &mut establish_connection();
1400 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1401 /// # diesel::sql_query("CREATE TABLE contacts (
1402 /// # id SERIAL PRIMARY KEY,
1403 /// # name VARCHAR NOT NULL,
1404 /// # address JSONB NOT NULL
1405 /// # )").execute(conn).unwrap();
1406 /// #
1407 /// let santas_address: serde_json::Value = serde_json::json!({
1408 /// "street": "Article Circle Expressway 1",
1409 /// "city": "North Pole",
1410 /// "postcode": "99705",
1411 /// "state": "Alaska"
1412 /// });
1413 /// diesel::insert_into(contacts)
1414 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1415 /// .execute(conn)?;
1416 ///
1417 /// let any_key_exists = contacts.select(address.has_any_key(vec!["street", "city", "rudolf"])).get_result::<bool>(conn)?;
1418 /// assert!(any_key_exists);
1419 ///
1420 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_any_key(vec!["street", "city", "rudolf"])).get_result::<i32>(conn)?;
1421 /// assert_eq!(1, santas_with_address_postcode);
1422 /// # Ok(())
1423 /// # }
1424 /// # #[cfg(not(feature = "serde_json"))]
1425 /// # fn run_test() -> QueryResult<()> {
1426 /// # Ok(())
1427 /// # }
1428 /// ``````
1429 fn has_any_key<T>(self, other: T) -> dsl::HasAnyKeyJsonb<Self, T>
1430 where
1431 T: AsExpression<Array<VarChar>>,
1432 {
1433 Grouped(HasAnyKeyJsonb::new(self, other.as_expression()))
1434 }
1435
1436 /// Creates a PostgreSQL `?&` expression.
1437 ///
1438 /// This operator checks if all the strings in the right hand side array exist as top level keys in the given JSONB
1439 ///
1440 /// # Example
1441 ///
1442 /// ```rust
1443 /// # include!("../../doctest_setup.rs");
1444 /// #
1445 /// # table! {
1446 /// # contacts {
1447 /// # id -> Integer,
1448 /// # name -> VarChar,
1449 /// # address -> Jsonb,
1450 /// # }
1451 /// # }
1452 /// #
1453 /// # fn main() {
1454 /// # run_test().unwrap();
1455 /// # }
1456 ///
1457 /// # #[cfg(feature = "serde_json")]
1458 /// # fn run_test() -> QueryResult<()> {
1459 /// # use self::contacts::dsl::*;
1460 /// # let conn = &mut establish_connection();
1461 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1462 /// # diesel::sql_query("CREATE TABLE contacts (
1463 /// # id SERIAL PRIMARY KEY,
1464 /// # name VARCHAR NOT NULL,
1465 /// # address JSONB NOT NULL
1466 /// # )").execute(conn).unwrap();
1467 /// #
1468 /// let santas_address: serde_json::Value = serde_json::json!({
1469 /// "street": "Article Circle Expressway 1",
1470 /// "city": "North Pole",
1471 /// "postcode": "99705",
1472 /// "state": "Alaska"
1473 /// });
1474 /// diesel::insert_into(contacts)
1475 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1476 /// .execute(conn)?;
1477 ///
1478 /// let all_keys_exist = contacts.select(address.has_all_keys(vec!["street", "city", "postcode"])).get_result::<bool>(conn)?;
1479 /// assert!(all_keys_exist);
1480 ///
1481 /// let santas_with_address_postcode = contacts.select(id).filter(address.has_all_keys(vec!["street", "city", "postcode"])).get_result::<i32>(conn)?;
1482 /// assert_eq!(1, santas_with_address_postcode);
1483 /// # Ok(())
1484 /// # }
1485 /// # #[cfg(not(feature = "serde_json"))]
1486 /// # fn run_test() -> QueryResult<()> {
1487 /// # Ok(())
1488 /// # }
1489 /// ``````
1490 fn has_all_keys<T>(self, other: T) -> dsl::HasAllKeysJsonb<Self, T>
1491 where
1492 T: AsExpression<Array<VarChar>>,
1493 {
1494 Grouped(HasAllKeysJsonb::new(self, other.as_expression()))
1495 }
1496
1497 /// Creates a PostgreSQL `@>` expression.
1498 ///
1499 /// This operator checks whether left hand side JSONB value contains right hand side JSONB value
1500 ///
1501 /// # Example
1502 ///
1503 /// ```rust
1504 /// # include!("../../doctest_setup.rs");
1505 /// #
1506 /// # table! {
1507 /// # contacts {
1508 /// # id -> Integer,
1509 /// # name -> VarChar,
1510 /// # address -> Jsonb,
1511 /// # }
1512 /// # }
1513 /// #
1514 /// # fn main() {
1515 /// # run_test().unwrap();
1516 /// # }
1517 /// #
1518 /// # #[cfg(feature = "serde_json")]
1519 /// # fn run_test() -> QueryResult<()> {
1520 /// # use self::contacts::dsl::*;
1521 /// # let conn = &mut establish_connection();
1522 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1523 /// # diesel::sql_query("CREATE TABLE contacts (
1524 /// # id SERIAL PRIMARY KEY,
1525 /// # name VARCHAR NOT NULL,
1526 /// # address JSONB NOT NULL
1527 /// # )").execute(conn).unwrap();
1528 /// #
1529 /// let easter_bunny_address: serde_json::Value = serde_json::json!({
1530 /// "street": "123 Carrot Road",
1531 /// "province": "Easter Island",
1532 /// "region": "ValparaÃso",
1533 /// "country": "Chile",
1534 /// "postcode": "88888",
1535 /// });
1536 /// diesel::insert_into(contacts)
1537 /// .values((name.eq("Bunny"), address.eq(&easter_bunny_address)))
1538 /// .execute(conn)?;
1539 ///
1540 /// let country_chile: serde_json::Value = serde_json::json!({"country": "Chile"});
1541 /// let contains_country_chile = contacts.select(address.contains(&country_chile)).get_result::<bool>(conn)?;
1542 /// assert!(contains_country_chile);
1543 /// # Ok(())
1544 /// # }
1545 /// # #[cfg(not(feature = "serde_json"))]
1546 /// # fn run_test() -> QueryResult<()> {
1547 /// # Ok(())
1548 /// # }
1549 /// ```
1550 fn contains<T>(self, other: T) -> dsl::Contains<Self, T>
1551 where
1552 Self::SqlType: SqlType,
1553 T: AsExpression<Self::SqlType>,
1554 {
1555 Grouped(Contains::new(self, other.as_expression()))
1556 }
1557
1558 /// Creates a PostgreSQL `<@` expression.
1559 ///
1560 /// This operator checks whether left hand side JSONB value is contained by right hand side JSON value.
1561 /// `foo.contains(bar)` is the same as `bar.is_contained_by(foo)`.
1562 ///
1563 /// # Example
1564 ///
1565 /// ```rust
1566 /// # include!("../../doctest_setup.rs");
1567 /// #
1568 /// # table! {
1569 /// # contacts {
1570 /// # id -> Integer,
1571 /// # name -> VarChar,
1572 /// # address -> Jsonb,
1573 /// # }
1574 /// # }
1575 /// #
1576 /// # fn main() {
1577 /// # run_test().unwrap();
1578 /// # }
1579 /// #
1580 /// # #[cfg(feature = "serde_json")]
1581 /// # fn run_test() -> QueryResult<()> {
1582 /// # use self::contacts::dsl::*;
1583 /// # let conn = &mut establish_connection();
1584 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1585 /// # diesel::sql_query("CREATE TABLE contacts (
1586 /// # id SERIAL PRIMARY KEY,
1587 /// # name VARCHAR NOT NULL,
1588 /// # address JSONB NOT NULL
1589 /// # )").execute(conn).unwrap();
1590 /// #
1591 /// let partial_easter_bunny_address: serde_json::Value = serde_json::json!({
1592 /// "street": "123 Carrot Road",
1593 /// "country": "Chile",
1594 /// });
1595 /// diesel::insert_into(contacts)
1596 /// .values((name.eq("Bunny"), address.eq(&partial_easter_bunny_address)))
1597 /// .execute(conn)?;
1598 ///
1599 /// let full_easter_bunny_address: serde_json::Value = serde_json::json!({
1600 /// "street": "123 Carrot Road",
1601 /// "province": "Easter Island",
1602 /// "region": "ValparaÃso",
1603 /// "country": "Chile",
1604 /// "postcode": "88888",
1605 /// });
1606 /// let address_is_contained_by = contacts.select(address.is_contained_by(&full_easter_bunny_address)).get_result::<bool>(conn)?;
1607 /// assert!(address_is_contained_by);
1608 /// # Ok(())
1609 /// # }
1610 /// # #[cfg(not(feature = "serde_json"))]
1611 /// # fn run_test() -> QueryResult<()> {
1612 /// # Ok(())
1613 /// # }
1614 /// ```
1615 #[allow(clippy::wrong_self_convention)] // This is named after the sql operator
1616 fn is_contained_by<T>(self, other: T) -> dsl::IsContainedBy<Self, T>
1617 where
1618 Self::SqlType: SqlType,
1619 T: AsExpression<Self::SqlType>,
1620 {
1621 Grouped(IsContainedBy::new(self, other.as_expression()))
1622 }
1623
1624 /// Creates a PostgreSQL `-` expression.
1625 ///
1626 /// This operator removes the value associated with the given key, that is provided on the
1627 /// Right Hand Side of the operator.
1628 ///
1629 /// # Example
1630 ///
1631 /// ```rust
1632 /// # include!("../../doctest_setup.rs");
1633 /// #
1634 /// # table! {
1635 /// # contacts {
1636 /// # id -> Integer,
1637 /// # name -> VarChar,
1638 /// # address -> Jsonb,
1639 /// # }
1640 /// # }
1641 /// #
1642 /// # fn main() {
1643 /// # run_test().unwrap();
1644 /// # }
1645 ///
1646 /// # #[cfg(feature = "serde_json")]
1647 /// # fn run_test() -> QueryResult<()> {
1648 /// # use self::contacts::dsl::*;
1649 /// # let conn = &mut establish_connection();
1650 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1651 /// # diesel::sql_query("CREATE TABLE contacts (
1652 /// # id SERIAL PRIMARY KEY,
1653 /// # name VARCHAR NOT NULL,
1654 /// # address JSONB NOT NULL
1655 /// # )").execute(conn)
1656 /// # .unwrap();
1657 /// #
1658 /// let santas_address: serde_json::Value = serde_json::json!({
1659 /// "street": "Article Circle Expressway 1",
1660 /// "city": "North Pole",
1661 /// "postcode": "99705",
1662 /// "state": "Alaska"
1663 /// });
1664 /// diesel::insert_into(contacts)
1665 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1666 /// .execute(conn)?;
1667 ///
1668 /// let santas_modified_address = contacts.select(address.remove("postcode")).get_result::<serde_json::Value>(conn)?;
1669 /// assert_eq!(santas_modified_address, serde_json::json!({
1670 /// "street": "Article Circle Expressway 1",
1671 /// "city": "North Pole",
1672 /// "state": "Alaska"
1673 /// }));
1674 /// diesel::insert_into(contacts)
1675 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1676 /// .execute(conn)?;
1677 ///
1678 /// let santas_modified_address = contacts.select(address.remove(vec!["postcode", "state"])).get_result::<serde_json::Value>(conn)?;
1679 /// assert_eq!(santas_modified_address, serde_json::json!({
1680 /// "street": "Article Circle Expressway 1",
1681 /// "city": "North Pole",
1682 /// }));
1683 ///
1684 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
1685 /// {
1686 /// "street": "Somewhere In La 251",
1687 /// "city": "Los Angeles",
1688 /// "postcode": "12231223",
1689 /// "state": "California"
1690 /// },
1691 /// {
1692 /// "street": "Somewhere In Ny 251",
1693 /// "city": "New York",
1694 /// "postcode": "3213212",
1695 /// "state": "New York"
1696 /// }
1697 /// ]);
1698 ///
1699 /// diesel::insert_into(contacts)
1700 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
1701 /// .execute(conn)?;
1702 ///
1703 /// let roberts_address_in_db = contacts
1704 /// .filter(name.eq("Robert Downey Jr."))
1705 /// .select(address.remove(1))
1706 /// .get_result::<serde_json::Value>(conn)?;
1707 ///
1708 /// let roberts_first_address = serde_json::json!([{
1709 /// "street": "Somewhere In La 251",
1710 /// "city": "Los Angeles",
1711 /// "postcode": "12231223",
1712 /// "state": "California"
1713 /// }]);
1714 /// assert_eq!(roberts_first_address, roberts_address_in_db);
1715 /// # Ok(())
1716 /// # }
1717 /// # #[cfg(not(feature = "serde_json"))]
1718 /// # fn run_test() -> QueryResult<()> {
1719 /// # Ok(())
1720 /// # }
1721 ///
1722 fn remove<T>(
1723 self,
1724 other: T,
1725 ) -> dsl::RemoveFromJsonb<Self, T::Expression, <T::Expression as Expression>::SqlType>
1726 where
1727 T: JsonRemoveIndex,
1728 <T::Expression as Expression>::SqlType: SqlType,
1729 {
1730 Grouped(RemoveFromJsonb::new(
1731 self,
1732 other.into_json_index_expression(),
1733 ))
1734 }
1735
1736 /// Creates a PostgreSQL `#-` expression.
1737 ///
1738 /// This operator removes the value associated with the given json path, that is provided on the
1739 /// Right Hand Side of the operator.
1740 ///
1741 /// # Example
1742 ///
1743 /// ```rust
1744 /// # include!("../../doctest_setup.rs");
1745 /// #
1746 /// # table! {
1747 /// # contacts {
1748 /// # id -> Integer,
1749 /// # name -> VarChar,
1750 /// # address -> Jsonb,
1751 /// # }
1752 /// # }
1753 /// #
1754 /// # fn main() {
1755 /// # run_test().unwrap();
1756 /// # }
1757 ///
1758 /// # #[cfg(feature = "serde_json")]
1759 /// # fn run_test() -> QueryResult<()> {
1760 /// # use self::contacts::dsl::*;
1761 /// # let conn = &mut establish_connection();
1762 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1763 /// # diesel::sql_query("CREATE TABLE contacts (
1764 /// # id SERIAL PRIMARY KEY,
1765 /// # name VARCHAR NOT NULL,
1766 /// # address JSONB NOT NULL
1767 /// # )").execute(conn)
1768 /// # .unwrap();
1769 /// #
1770 /// let santas_address: serde_json::Value = serde_json::json!({
1771 /// "street": "Article Circle Expressway 1",
1772 /// "city": "North Pole",
1773 /// "postcode": "99705",
1774 /// "state": "Alaska"
1775 /// });
1776 /// diesel::insert_into(contacts)
1777 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1778 /// .execute(conn)?;
1779 ///
1780 /// let santas_modified_address = contacts.select(address.remove("postcode")).get_result::<serde_json::Value>(conn)?;
1781 /// assert_eq!(santas_modified_address, serde_json::json!({
1782 /// "street": "Article Circle Expressway 1",
1783 /// "city": "North Pole",
1784 /// "state": "Alaska"
1785 /// }));
1786 /// diesel::insert_into(contacts)
1787 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1788 /// .execute(conn)?;
1789 ///
1790 /// let santas_modified_address = contacts.select(address.remove_by_path(vec!["postcode"])).get_result::<serde_json::Value>(conn)?;
1791 /// assert_eq!(santas_modified_address, serde_json::json!({
1792 /// "street": "Article Circle Expressway 1",
1793 /// "city": "North Pole",
1794 /// "state": "Alaska"
1795 /// }));
1796 ///
1797 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
1798 /// {
1799 /// "street": "Somewhere In La 251",
1800 /// "city": "Los Angeles",
1801 /// "postcode": "12231223",
1802 /// "state": "California"
1803 /// },
1804 /// {
1805 /// "street": "Somewhere In Ny 251",
1806 /// "city": "New York",
1807 /// "postcode": "3213212",
1808 /// "state": "New York"
1809 /// }
1810 /// ]);
1811 ///
1812 /// diesel::insert_into(contacts)
1813 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
1814 /// .execute(conn)?;
1815 ///
1816 /// let roberts_address_in_db = contacts
1817 /// .filter(name.eq("Robert Downey Jr."))
1818 /// .select(address.remove_by_path(vec!["1", "postcode"]))
1819 /// .get_result::<serde_json::Value>(conn)?;
1820 ///
1821 /// let roberts_address = serde_json::json!([
1822 /// {
1823 /// "street": "Somewhere In La 251",
1824 /// "city": "Los Angeles",
1825 /// "postcode": "12231223",
1826 /// "state": "California"
1827 /// },
1828 /// {
1829 /// "street": "Somewhere In Ny 251",
1830 /// "city": "New York",
1831 /// "state": "New York"
1832 /// }
1833 /// ]);
1834 /// assert_eq!(roberts_address, roberts_address_in_db);
1835 /// # Ok(())
1836 /// # }
1837 /// # #[cfg(not(feature = "serde_json"))]
1838 /// # fn run_test() -> QueryResult<()> {
1839 /// # Ok(())
1840 /// # }
1841 ///
1842 fn remove_by_path<T>(self, other: T) -> dsl::RemoveByPathFromJsonb<Self, T::Expression>
1843 where
1844 T: AsExpression<Array<Text>>,
1845 {
1846 Grouped(RemoveByPathFromJsonb::new(self, other.as_expression()))
1847 }
1848}
1849
1850impl<T> PgJsonbExpressionMethods for T
1851where
1852 T: Expression,
1853 T::SqlType: JsonbOrNullableJsonb,
1854{
1855}
1856
1857/// PostgreSQL specific methods present on JSON and JSONB expressions.
1858#[cfg(feature = "postgres_backend")]
1859pub trait PgAnyJsonExpressionMethods: Expression + Sized {
1860 /// Creates a PostgreSQL `->` expression.
1861 ///
1862 /// This operator extracts the value associated with the given key, that is provided on the
1863 /// Right Hand Side of the operator.
1864 ///
1865 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
1866 /// Extracts JSON object field with the given key.
1867 /// # Example
1868 ///
1869 /// ```rust
1870 /// # include!("../../doctest_setup.rs");
1871 /// #
1872 /// # table! {
1873 /// # contacts {
1874 /// # id -> Integer,
1875 /// # name -> VarChar,
1876 /// # address -> Jsonb,
1877 /// # }
1878 /// # }
1879 /// #
1880 /// # fn main() {
1881 /// # run_test().unwrap();
1882 /// # }
1883 ///
1884 /// # #[cfg(feature = "serde_json")]
1885 /// # fn run_test() -> QueryResult<()> {
1886 /// # use self::contacts::dsl::*;
1887 /// # let conn = &mut establish_connection();
1888 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1889 /// # diesel::sql_query("CREATE TABLE contacts (
1890 /// # id SERIAL PRIMARY KEY,
1891 /// # name VARCHAR NOT NULL,
1892 /// # address JSONB NOT NULL
1893 /// # )").execute(conn)
1894 /// # .unwrap();
1895 /// #
1896 /// let santas_address: serde_json::Value = serde_json::json!({
1897 /// "street": "Article Circle Expressway 1",
1898 /// "city": "North Pole",
1899 /// "postcode": "99705",
1900 /// "state": "Alaska"
1901 /// });
1902 /// diesel::insert_into(contacts)
1903 /// .values((name.eq("Claus"), address.eq(&santas_address)))
1904 /// .execute(conn)?;
1905 ///
1906 /// let santas_postcode = contacts.select(address.retrieve_as_object("postcode")).get_result::<serde_json::Value>(conn)?;
1907 /// assert_eq!(santas_postcode, serde_json::json!("99705"));
1908 ///
1909 ///
1910 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
1911 /// {
1912 /// "street": "Somewhere In La 251",
1913 /// "city": "Los Angeles",
1914 /// "postcode": "12231223",
1915 /// "state": "California"
1916 /// },
1917 /// {
1918 /// "street": "Somewhere In Ny 251",
1919 /// "city": "New York",
1920 /// "postcode": "3213212",
1921 /// "state": "New York"
1922 /// }
1923 /// ]);
1924 ///
1925 /// diesel::insert_into(contacts)
1926 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
1927 /// .execute(conn)?;
1928 ///
1929 /// let roberts_second_address_in_db = contacts
1930 /// .filter(name.eq("Robert Downey Jr."))
1931 /// .select(address.retrieve_as_object(1))
1932 /// .get_result::<serde_json::Value>(conn)?;
1933 ///
1934 /// let roberts_second_address = serde_json::json!({
1935 /// "street": "Somewhere In Ny 251",
1936 /// "city": "New York",
1937 /// "postcode": "3213212",
1938 /// "state": "New York"
1939 /// });
1940 /// assert_eq!(roberts_second_address, roberts_second_address_in_db);
1941 /// # Ok(())
1942 /// # }
1943 /// # #[cfg(not(feature = "serde_json"))]
1944 /// # fn run_test() -> QueryResult<()> {
1945 /// # Ok(())
1946 /// # }
1947 /// ```
1948 fn retrieve_as_object<T>(
1949 self,
1950 other: T,
1951 ) -> dsl::RetrieveAsObjectJson<Self, T::Expression, <T::Expression as Expression>::SqlType>
1952 where
1953 T: JsonIndex,
1954 <T::Expression as Expression>::SqlType: SqlType,
1955 {
1956 Grouped(RetrieveAsObjectJson::new(
1957 self,
1958 other.into_json_index_expression(),
1959 ))
1960 }
1961
1962 /// Creates a PostgreSQL `->>` expression.
1963 ///
1964 /// This operator extracts the value associated with the given key, that is provided on the
1965 /// Right Hand Side of the operator.
1966 ///
1967 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
1968 /// Extracts JSON object field as Text with the given key.
1969 /// # Example
1970 ///
1971 /// ```rust
1972 /// # include!("../../doctest_setup.rs");
1973 /// #
1974 /// # table! {
1975 /// # contacts {
1976 /// # id -> Integer,
1977 /// # name -> VarChar,
1978 /// # address -> Jsonb,
1979 /// # }
1980 /// # }
1981 /// #
1982 /// # fn main() {
1983 /// # run_test().unwrap();
1984 /// # }
1985 ///
1986 /// # #[cfg(feature = "serde_json")]
1987 /// # fn run_test() -> QueryResult<()> {
1988 /// # use self::contacts::dsl::*;
1989 /// # let conn = &mut establish_connection();
1990 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
1991 /// # diesel::sql_query("CREATE TABLE contacts (
1992 /// # id SERIAL PRIMARY KEY,
1993 /// # name VARCHAR NOT NULL,
1994 /// # address JSONB NOT NULL
1995 /// # )").execute(conn)
1996 /// # .unwrap();
1997 /// #
1998 /// let santas_address: serde_json::Value = serde_json::json!({
1999 /// "street": "Article Circle Expressway 1",
2000 /// "city": "North Pole",
2001 /// "postcode": "99705",
2002 /// "state": "Alaska"
2003 /// });
2004 /// diesel::insert_into(contacts)
2005 /// .values((name.eq("Claus"), address.eq(&santas_address)))
2006 /// .execute(conn)?;
2007 ///
2008 /// let santas_postcode = contacts.select(address.retrieve_as_text("postcode")).get_result::<String>(conn)?;
2009 /// assert_eq!(santas_postcode, "99705");
2010 ///
2011 ///
2012 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
2013 /// {
2014 /// "street": "Somewhere In La 251",
2015 /// "city": "Los Angeles",
2016 /// "postcode": "12231223",
2017 /// "state": "California"
2018 /// },
2019 /// {
2020 /// "street": "Somewhere In Ny 251",
2021 /// "city": "New York",
2022 /// "postcode": "3213212",
2023 /// "state": "New York"
2024 /// }
2025 /// ]);
2026 ///
2027 /// diesel::insert_into(contacts)
2028 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
2029 /// .execute(conn)?;
2030 ///
2031 /// let roberts_second_address_in_db = contacts
2032 /// .filter(name.eq("Robert Downey Jr."))
2033 /// .select(address.retrieve_as_text(1))
2034 /// .get_result::<String>(conn)?;
2035 ///
2036 /// let roberts_second_address = String::from(
2037 /// "{\"city\": \"New York\", \
2038 /// \"state\": \"New York\", \
2039 /// \"street\": \"Somewhere In Ny 251\", \
2040 /// \"postcode\": \"3213212\"}"
2041 /// );
2042 /// assert_eq!(roberts_second_address, roberts_second_address_in_db);
2043 /// # Ok(())
2044 /// # }
2045 /// # #[cfg(not(feature = "serde_json"))]
2046 /// # fn run_test() -> QueryResult<()> {
2047 /// # Ok(())
2048 /// # }
2049 /// ```
2050 fn retrieve_as_text<T>(
2051 self,
2052 other: T,
2053 ) -> dsl::RetrieveAsTextJson<Self, T::Expression, <T::Expression as Expression>::SqlType>
2054 where
2055 T: JsonIndex,
2056 <T::Expression as Expression>::SqlType: SqlType,
2057 {
2058 Grouped(RetrieveAsTextJson::new(
2059 self,
2060 other.into_json_index_expression(),
2061 ))
2062 }
2063
2064 /// Creates a PostgreSQL `#>` expression.
2065 ///
2066 /// This operator extracts the value associated with the given key, that is provided on the
2067 /// Right Hand Side of the operator.
2068 ///
2069 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
2070 /// Extracts JSON object field with the given key.
2071 /// # Example
2072 ///
2073 /// ```rust
2074 /// # include!("../../doctest_setup.rs");
2075 /// #
2076 /// # table! {
2077 /// # contacts {
2078 /// # id -> Integer,
2079 /// # name -> VarChar,
2080 /// # address -> Jsonb,
2081 /// # }
2082 /// # }
2083 /// #
2084 /// # fn main() {
2085 /// # run_test().unwrap();
2086 /// # }
2087 ///
2088 /// # #[cfg(feature = "serde_json")]
2089 /// # fn run_test() -> QueryResult<()> {
2090 /// # use self::contacts::dsl::*;
2091 /// # let conn = &mut establish_connection();
2092 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2093 /// # diesel::sql_query("CREATE TABLE contacts (
2094 /// # id SERIAL PRIMARY KEY,
2095 /// # name VARCHAR NOT NULL,
2096 /// # address JSONB NOT NULL
2097 /// # )").execute(conn)
2098 /// # .unwrap();
2099 /// #
2100 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
2101 /// {
2102 /// "street": "Somewhere In La 251",
2103 /// "city": "Los Angeles",
2104 /// "postcode": "12231223",
2105 /// "state": "California"
2106 /// },
2107 /// {
2108 /// "street": "Somewhere In Ny 251",
2109 /// "city": "New York",
2110 /// "postcode": "3213212",
2111 /// "state": "New York"
2112 /// }
2113 /// ]);
2114 ///
2115 /// diesel::insert_into(contacts)
2116 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
2117 /// .execute(conn)?;
2118 ///
2119 /// let roberts_second_street_in_db = contacts
2120 /// .filter(name.eq("Robert Downey Jr."))
2121 /// .select(address.retrieve_by_path_as_object(vec!["1", "street"]))
2122 /// .get_result::<serde_json::Value>(conn)?;
2123 ///
2124 /// assert_eq!(roberts_second_street_in_db, serde_json::json!("Somewhere In Ny 251"));
2125 /// # Ok(())
2126 /// # }
2127 /// # #[cfg(not(feature = "serde_json"))]
2128 /// # fn run_test() -> QueryResult<()> {
2129 /// # Ok(())
2130 /// # }
2131 /// ```
2132 fn retrieve_by_path_as_object<T>(
2133 self,
2134 other: T,
2135 ) -> dsl::RetrieveByPathAsObjectJson<Self, T::Expression>
2136 where
2137 T: AsExpression<Array<Text>>,
2138 {
2139 Grouped(RetrieveByPathAsObjectJson::new(self, other.as_expression()))
2140 }
2141
2142 /// Creates a PostgreSQL `#>>` expression.
2143 ///
2144 /// This operator extracts the value associated with the given key, that is provided on the
2145 /// Right Hand Side of the operator.
2146 ///
2147 /// Extracts n'th element of JSON array (array elements are indexed from zero, but negative integers count from the end).
2148 /// Extracts JSON object field as Text with the given key.
2149 /// # Example
2150 ///
2151 /// ```rust
2152 /// # include!("../../doctest_setup.rs");
2153 /// #
2154 /// # table! {
2155 /// # contacts {
2156 /// # id -> Integer,
2157 /// # name -> VarChar,
2158 /// # address -> Jsonb,
2159 /// # }
2160 /// # }
2161 /// #
2162 /// # fn main() {
2163 /// # run_test().unwrap();
2164 /// # }
2165 ///
2166 /// # #[cfg(feature = "serde_json")]
2167 /// # fn run_test() -> QueryResult<()> {
2168 /// # use self::contacts::dsl::*;
2169 /// # let conn = &mut establish_connection();
2170 /// # diesel::sql_query("DROP TABLE IF EXISTS contacts").execute(conn).unwrap();
2171 /// # diesel::sql_query("CREATE TABLE contacts (
2172 /// # id SERIAL PRIMARY KEY,
2173 /// # name VARCHAR NOT NULL,
2174 /// # address JSONB NOT NULL
2175 /// # )").execute(conn)
2176 /// # .unwrap();
2177 /// #
2178 /// let robert_downey_jr_addresses: serde_json::Value = serde_json::json!([
2179 /// {
2180 /// "street": "Somewhere In La 251",
2181 /// "city": "Los Angeles",
2182 /// "postcode": "12231223",
2183 /// "state": "California"
2184 /// },
2185 /// {
2186 /// "street": "Somewhere In Ny 251",
2187 /// "city": "New York",
2188 /// "postcode": "3213212",
2189 /// "state": "New York"
2190 /// }
2191 /// ]);
2192 ///
2193 /// diesel::insert_into(contacts)
2194 /// .values((name.eq("Robert Downey Jr."), address.eq(&robert_downey_jr_addresses)))
2195 /// .execute(conn)?;
2196 ///
2197 /// let roberts_second_street_in_db = contacts
2198 /// .filter(name.eq("Robert Downey Jr."))
2199 /// .select(address.retrieve_by_path_as_text(vec!["1", "street"]))
2200 /// .get_result::<String>(conn)?;
2201 ///
2202 /// assert_eq!(roberts_second_street_in_db, "Somewhere In Ny 251");
2203 ///
2204 /// # Ok(())
2205 /// # }
2206 /// # #[cfg(not(feature = "serde_json"))]
2207 /// # fn run_test() -> QueryResult<()> {
2208 /// # Ok(())
2209 /// # }
2210 /// ```
2211 fn retrieve_by_path_as_text<T>(
2212 self,
2213 other: T,
2214 ) -> dsl::RetrieveByPathAsTextJson<Self, T::Expression>
2215 where
2216 T: AsExpression<Array<Text>>,
2217 {
2218 Grouped(RetrieveByPathAsTextJson::new(self, other.as_expression()))
2219 }
2220}
2221
2222#[doc(hidden)]
2223impl<T> PgAnyJsonExpressionMethods for T
2224where
2225 T: Expression,
2226 T::SqlType: JsonOrNullableJsonOrJsonbOrNullableJsonb,
2227{
2228}
2229
2230/// PostgreSQL specific methods present on Binary expressions.
2231#[cfg(feature = "postgres_backend")]
2232pub trait PgBinaryExpressionMethods: Expression + Sized {
2233 /// Concatenates two PostgreSQL byte arrays using the `||` operator.
2234 ///
2235 /// # Example
2236 ///
2237 /// ```rust
2238 /// # include!("../../doctest_setup.rs");
2239 /// #
2240 /// # table! {
2241 /// # users {
2242 /// # id -> Integer,
2243 /// # name -> Binary,
2244 /// # hair_color -> Nullable<Binary>,
2245 /// # }
2246 /// # }
2247 /// #
2248 /// # fn main() {
2249 /// # use self::users::dsl::*;
2250 /// # use diesel::insert_into;
2251 /// #
2252 /// # let connection = &mut connection_no_data();
2253 /// # diesel::sql_query("CREATE TABLE users (
2254 /// # id INTEGER PRIMARY KEY,
2255 /// # name BYTEA NOT NULL,
2256 /// # hair_color BYTEA
2257 /// # )").execute(connection).unwrap();
2258 /// #
2259 /// # insert_into(users)
2260 /// # .values(&vec![
2261 /// # (id.eq(1), name.eq("Sean".as_bytes()), Some(hair_color.eq(Some("Green".as_bytes())))),
2262 /// # (id.eq(2), name.eq("Tess".as_bytes()), None),
2263 /// # ])
2264 /// # .execute(connection)
2265 /// # .unwrap();
2266 /// #
2267 /// let names = users.select(name.concat(" the Greatest".as_bytes())).load(connection);
2268 /// let expected_names = vec![
2269 /// b"Sean the Greatest".to_vec(),
2270 /// b"Tess the Greatest".to_vec()
2271 /// ];
2272 /// assert_eq!(Ok(expected_names), names);
2273 ///
2274 /// // If the value is nullable, the output will be nullable
2275 /// let names = users.select(hair_color.concat("ish".as_bytes())).load(connection);
2276 /// let expected_names = vec![
2277 /// Some(b"Greenish".to_vec()),
2278 /// None,
2279 /// ];
2280 /// assert_eq!(Ok(expected_names), names);
2281 /// # }
2282 /// ```
2283 fn concat<T>(self, other: T) -> dsl::Concat<Self, T>
2284 where
2285 Self::SqlType: SqlType,
2286 T: AsExpression<Self::SqlType>,
2287 {
2288 Grouped(Concat::new(self, other.as_expression()))
2289 }
2290
2291 /// Creates a PostgreSQL binary `LIKE` expression.
2292 ///
2293 /// This method is case sensitive. There is no case-insensitive
2294 /// equivalent as of PostgreSQL 14.
2295 ///
2296 /// # Examples
2297 ///
2298 /// ```rust
2299 /// # include!("../../doctest_setup.rs");
2300 /// #
2301 /// # table! {
2302 /// # users {
2303 /// # id -> Integer,
2304 /// # name -> Binary,
2305 /// # }
2306 /// # }
2307 /// #
2308 /// # fn main() {
2309 /// # use self::users::dsl::*;
2310 /// # use diesel::insert_into;
2311 /// #
2312 /// # let connection = &mut connection_no_data();
2313 /// # diesel::sql_query("CREATE TABLE users (
2314 /// # id INTEGER PRIMARY KEY,
2315 /// # name BYTEA NOT NULL
2316 /// # )").execute(connection).unwrap();
2317 /// #
2318 /// # insert_into(users)
2319 /// # .values(&vec![
2320 /// # (id.eq(1), name.eq("Sean".as_bytes())),
2321 /// # (id.eq(2), name.eq("Tess".as_bytes()))
2322 /// # ])
2323 /// # .execute(connection)
2324 /// # .unwrap();
2325 /// #
2326 /// let starts_with_s = users
2327 /// .select(name)
2328 /// .filter(name.like(b"S%".to_vec()))
2329 /// .load(connection);
2330 /// assert_eq!(Ok(vec![b"Sean".to_vec()]), starts_with_s);
2331 /// # }
2332 /// ```
2333 fn like<T>(self, other: T) -> dsl::Like<Self, T>
2334 where
2335 Self::SqlType: SqlType,
2336 T: AsExpression<Self::SqlType>,
2337 {
2338 Grouped(Like::new(self, other.as_expression()))
2339 }
2340
2341 /// Creates a PostgreSQL binary `LIKE` expression.
2342 ///
2343 /// This method is case sensitive. There is no case-insensitive
2344 /// equivalent as of PostgreSQL 14.
2345 ///
2346 /// # Examples
2347 ///
2348 /// ```rust
2349 /// # include!("../../doctest_setup.rs");
2350 /// #
2351 /// # table! {
2352 /// # users {
2353 /// # id -> Integer,
2354 /// # name -> Binary,
2355 /// # }
2356 /// # }
2357 /// #
2358 /// # fn main() {
2359 /// # use self::users::dsl::*;
2360 /// # use diesel::insert_into;
2361 /// #
2362 /// # let connection = &mut connection_no_data();
2363 /// # diesel::sql_query("CREATE TABLE users (
2364 /// # id INTEGER PRIMARY KEY,
2365 /// # name BYTEA NOT NULL
2366 /// # )").execute(connection).unwrap();
2367 /// #
2368 /// # insert_into(users)
2369 /// # .values(&vec![
2370 /// # (id.eq(1), name.eq("Sean".as_bytes())),
2371 /// # (id.eq(2), name.eq("Tess".as_bytes()))
2372 /// # ])
2373 /// # .execute(connection)
2374 /// # .unwrap();
2375 /// #
2376 /// let starts_with_s = users
2377 /// .select(name)
2378 /// .filter(name.not_like(b"S%".to_vec()))
2379 /// .load(connection);
2380 /// assert_eq!(Ok(vec![b"Tess".to_vec()]), starts_with_s);
2381 /// # }
2382 /// ```
2383 fn not_like<T>(self, other: T) -> dsl::NotLike<Self, T>
2384 where
2385 Self::SqlType: SqlType,
2386 T: AsExpression<Self::SqlType>,
2387 {
2388 Grouped(NotLike::new(self, other.as_expression()))
2389 }
2390}
2391
2392#[doc(hidden)]
2393impl<T> PgBinaryExpressionMethods for T
2394where
2395 T: Expression,
2396 T::SqlType: BinaryOrNullableBinary,
2397{
2398}
2399
2400pub(in crate::pg) mod private {
2401 use crate::sql_types::{
2402 Array, Binary, Cidr, Inet, Integer, Json, Jsonb, Nullable, Range, SqlType, Text,
2403 };
2404 use crate::{Expression, IntoSql};
2405
2406 /// Marker trait used to implement `ArrayExpressionMethods` on the appropriate
2407 /// types. Once coherence takes associated types into account, we can remove
2408 /// this trait.
2409 #[diagnostic::on_unimplemented(
2410 message = "`{Self}` is neither `diesel::sql_types::Array<_>` nor `diesel::sql_types::Nullable<Array<_>>`",
2411 note = "try to provide an expression that produces one of the expected sql types"
2412 )]
2413 pub trait ArrayOrNullableArray {}
2414
2415 impl<T> ArrayOrNullableArray for Array<T> {}
2416 impl<T> ArrayOrNullableArray for Nullable<Array<T>> {}
2417
2418 /// Marker trait used to implement `PgNetExpressionMethods` on the appropriate types.
2419 #[diagnostic::on_unimplemented(
2420 message = "`{Self}` is neither `diesel::sql_types::Inet`, `diesel::sql_types::Cidr`, `diesel::sql_types::Nullable<Inet>` nor `diesel::sql_types::Nullable<Cidr>",
2421 note = "try to provide an expression that produces one of the expected sql types"
2422 )]
2423 pub trait InetOrCidr {}
2424
2425 impl InetOrCidr for Inet {}
2426 impl InetOrCidr for Cidr {}
2427 impl InetOrCidr for Nullable<Inet> {}
2428 impl InetOrCidr for Nullable<Cidr> {}
2429
2430 /// Marker trait used to implement `PgTextExpressionMethods` on the appropriate
2431 /// types. Once coherence takes associated types into account, we can remove
2432 /// this trait.
2433 #[diagnostic::on_unimplemented(
2434 message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Nullable<Text>`",
2435 note = "try to provide an expression that produces one of the expected sql types"
2436 )]
2437 pub trait TextOrNullableText {}
2438
2439 impl TextOrNullableText for Text {}
2440 impl TextOrNullableText for Nullable<Text> {}
2441
2442 /// Marker trait used to extract the inner type
2443 /// of our `Range<T>` sql type, used to implement `PgRangeExpressionMethods`
2444 pub trait RangeHelper: SqlType {
2445 type Inner;
2446 }
2447
2448 impl<ST> RangeHelper for Range<ST>
2449 where
2450 Self: 'static,
2451 {
2452 type Inner = ST;
2453 }
2454
2455 /// Marker trait used to implement `PgRangeExpressionMethods` on the appropriate
2456 /// types. Once coherence takes associated types into account, we can remove
2457 /// this trait.
2458 #[diagnostic::on_unimplemented(
2459 message = "`{Self}` is neither `diesel::sql_types::Range<_>` nor `diesel::sql_types::Nullable<Range<_>>`",
2460 note = "try to provide an expression that produces one of the expected sql types"
2461 )]
2462 pub trait RangeOrNullableRange {}
2463
2464 impl<ST> RangeOrNullableRange for Range<ST> {}
2465 impl<ST> RangeOrNullableRange for Nullable<Range<ST>> {}
2466
2467 /// Marker trait used to implement `PgJsonbExpressionMethods` on the appropriate types.
2468 #[diagnostic::on_unimplemented(
2469 message = "`{Self}` is neither `diesel::sql_types::Jsonb` nor `diesel::sql_types::Nullable<Jsonb>`",
2470 note = "try to provide an expression that produces one of the expected sql types"
2471 )]
2472 pub trait JsonbOrNullableJsonb {}
2473
2474 impl JsonbOrNullableJsonb for Jsonb {}
2475 impl JsonbOrNullableJsonb for Nullable<Jsonb> {}
2476
2477 /// A trait that describes valid json indices used by postgresql
2478 pub trait JsonRemoveIndex {
2479 /// The Expression node created by this index type
2480 type Expression: Expression;
2481
2482 /// Convert a index value into the corresponding index expression
2483 fn into_json_index_expression(self) -> Self::Expression;
2484 }
2485
2486 impl<'a> JsonRemoveIndex for &'a str {
2487 type Expression = crate::dsl::AsExprOf<&'a str, crate::sql_types::Text>;
2488
2489 fn into_json_index_expression(self) -> Self::Expression {
2490 self.into_sql::<Text>()
2491 }
2492 }
2493
2494 impl JsonRemoveIndex for String {
2495 type Expression = crate::dsl::AsExprOf<String, crate::sql_types::Text>;
2496
2497 fn into_json_index_expression(self) -> Self::Expression {
2498 self.into_sql::<Text>()
2499 }
2500 }
2501
2502 impl JsonRemoveIndex for Vec<String> {
2503 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
2504
2505 fn into_json_index_expression(self) -> Self::Expression {
2506 self.into_sql::<Array<Text>>()
2507 }
2508 }
2509
2510 impl JsonRemoveIndex for Vec<&str> {
2511 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
2512
2513 fn into_json_index_expression(self) -> Self::Expression {
2514 self.into_sql::<Array<Text>>()
2515 }
2516 }
2517
2518 impl<'a> JsonRemoveIndex for &'a [&'a str] {
2519 type Expression = crate::dsl::AsExprOf<Self, Array<Text>>;
2520
2521 fn into_json_index_expression(self) -> Self::Expression {
2522 self.into_sql::<Array<Text>>()
2523 }
2524 }
2525
2526 impl JsonRemoveIndex for i32 {
2527 type Expression = crate::dsl::AsExprOf<i32, crate::sql_types::Int4>;
2528
2529 fn into_json_index_expression(self) -> Self::Expression {
2530 self.into_sql::<crate::sql_types::Int4>()
2531 }
2532 }
2533
2534 impl<T> JsonRemoveIndex for T
2535 where
2536 T: Expression,
2537 T::SqlType: TextArrayOrTextOrInteger,
2538 {
2539 type Expression = Self;
2540
2541 fn into_json_index_expression(self) -> Self::Expression {
2542 self
2543 }
2544 }
2545
2546 #[diagnostic::on_unimplemented(
2547 message = "`{Self}` is neither `diesel::sql_types::Text`, `diesel::sql_types::Integer` nor `diesel::sql_types::Array<Text>`",
2548 note = "try to provide an expression that produces one of the expected sql types"
2549 )]
2550 pub trait TextArrayOrTextOrInteger {}
2551
2552 impl TextArrayOrTextOrInteger for Array<Text> {}
2553 impl TextArrayOrTextOrInteger for Text {}
2554 impl TextArrayOrTextOrInteger for Integer {}
2555
2556 /// Marker trait used to implement `PgAnyJsonExpressionMethods` on the appropriate types.
2557 #[diagnostic::on_unimplemented(
2558 message = "`{Self}` is neither `diesel::sql_types::Json`, `diesel::sql_types::Jsonb`, `diesel::sql_types::Nullable<Json>` nor `diesel::sql_types::Nullable<Jsonb>`",
2559 note = "try to provide an expression that produces one of the expected sql types"
2560 )]
2561 pub trait JsonOrNullableJsonOrJsonbOrNullableJsonb {}
2562 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Json {}
2563 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Json> {}
2564 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Jsonb {}
2565 impl JsonOrNullableJsonOrJsonbOrNullableJsonb for Nullable<Jsonb> {}
2566
2567 pub trait JsonIndex {
2568 type Expression: Expression;
2569
2570 fn into_json_index_expression(self) -> Self::Expression;
2571 }
2572
2573 impl<'a> JsonIndex for &'a str {
2574 type Expression = crate::dsl::AsExprOf<&'a str, crate::sql_types::Text>;
2575
2576 fn into_json_index_expression(self) -> Self::Expression {
2577 self.into_sql::<Text>()
2578 }
2579 }
2580
2581 impl JsonIndex for String {
2582 type Expression = crate::dsl::AsExprOf<String, crate::sql_types::Text>;
2583
2584 fn into_json_index_expression(self) -> Self::Expression {
2585 self.into_sql::<Text>()
2586 }
2587 }
2588
2589 impl JsonIndex for i32 {
2590 type Expression = crate::dsl::AsExprOf<i32, crate::sql_types::Int4>;
2591
2592 fn into_json_index_expression(self) -> Self::Expression {
2593 self.into_sql::<crate::sql_types::Int4>()
2594 }
2595 }
2596
2597 impl<T> JsonIndex for T
2598 where
2599 T: Expression,
2600 T::SqlType: TextOrInteger,
2601 {
2602 type Expression = Self;
2603
2604 fn into_json_index_expression(self) -> Self::Expression {
2605 self
2606 }
2607 }
2608
2609 #[diagnostic::on_unimplemented(
2610 message = "`{Self}` is neither `diesel::sql_types::Text` nor `diesel::sql_types::Integer`",
2611 note = "try to provide an expression that produces one of the expected sql types"
2612 )]
2613 pub trait TextOrInteger {}
2614 impl TextOrInteger for Text {}
2615 impl TextOrInteger for Integer {}
2616
2617 #[diagnostic::on_unimplemented(
2618 message = "`{Self}` is neither `diesel::sql_types::Binary` nor `diesel::sql_types::Nullable<Binary>`",
2619 note = "try to provide an expression that produces one of the expected sql types"
2620 )]
2621 pub trait BinaryOrNullableBinary {}
2622
2623 impl BinaryOrNullableBinary for Binary {}
2624 impl BinaryOrNullableBinary for Nullable<Binary> {}
2625}