Merge pull request #2272 from weiznich/feature/pg_range_ops
Add a `contains` method for postgres range types
diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs
index bd43a75..8b89318 100644
--- a/diesel/src/pg/expression/expression_methods.rs
+++ b/diesel/src/pg/expression/expression_methods.rs
@@ -2,7 +2,7 @@
use super::operators::*;
use crate::expression::{AsExpression, Expression};
-use crate::sql_types::{Array, Nullable, Text};
+use crate::sql_types::{Array, Nullable, Range, Text};
/// PostgreSQL specific methods which are present on all expressions.
pub trait PgExpressionMethods: Expression + Sized {
@@ -486,3 +486,71 @@
T::SqlType: TextOrNullableText,
{
}
+
+#[doc(hidden)]
+/// Marker trait used to extract the inner type
+/// of our `Range<T>` sql type, used to implement `PgRangeExpressionMethods`
+pub trait RangeHelper {
+ type Inner;
+}
+
+impl<ST> RangeHelper for Range<ST> {
+ type Inner = ST;
+}
+
+/// PostgreSQL specific methods present on range expressions.
+pub trait PgRangeExpressionMethods: Expression + Sized {
+ /// Creates a PostgreSQL `@>` expression.
+ ///
+ /// This operator returns whether a range contains an specific element
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # #[macro_use] extern crate diesel;
+ /// # include!("../../doctest_setup.rs");
+ /// #
+ /// # table! {
+ /// # posts {
+ /// # id -> Integer,
+ /// # versions -> Range<Integer>,
+ /// # }
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # run_test().unwrap();
+ /// # }
+ /// #
+ /// # fn run_test() -> QueryResult<()> {
+ /// # use self::posts::dsl::*;
+ /// # use std::collections::Bound;
+ /// # let conn = establish_connection();
+ /// # conn.execute("DROP TABLE IF EXISTS posts").unwrap();
+ /// # conn.execute("CREATE TABLE posts (id SERIAL PRIMARY KEY, versions INT4RANGE NOT NULL)").unwrap();
+ /// #
+ /// diesel::insert_into(posts)
+ /// .values(versions.eq((Bound::Included(5), Bound::Unbounded)))
+ /// .execute(&conn)?;
+ ///
+ /// let cool_posts = posts.select(id)
+ /// .filter(versions.contains(42))
+ /// .load::<i32>(&conn)?;
+ /// assert_eq!(vec![1], cool_posts);
+ ///
+ /// let amazing_posts = posts.select(id)
+ /// .filter(versions.contains(1))
+ /// .load::<i32>(&conn)?;
+ /// assert!(amazing_posts.is_empty());
+ /// # Ok(())
+ /// # }
+ /// ```
+ fn contains<T>(self, other: T) -> Contains<Self, T::Expression>
+ where
+ Self::SqlType: RangeHelper,
+ T: AsExpression<<Self::SqlType as RangeHelper>::Inner>,
+ {
+ Contains::new(self, other.as_expression())
+ }
+}
+
+impl<T, ST> PgRangeExpressionMethods for T where T: Expression<SqlType = Range<ST>> {}