Skip to content

Commit

Permalink
Merge pull request #4314 from meeshal/add_is_json_expression
Browse files Browse the repository at this point in the history
add is_json and is_not_json expression methods
  • Loading branch information
weiznich authored Oct 25, 2024
2 parents 569c684 + c41b5b7 commit 0d4d41b
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
76 changes: 76 additions & 0 deletions diesel/src/pg/expression/expression_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,82 @@ pub trait PgExpressionMethods: Expression + Sized {
{
Grouped(IsContainedBy::new(self, other.as_expression()))
}

/// Creates a PostgreSQL `IS JSON` expression.
/// Requires PostgreSQL>=16
///
/// This operator returns true whether an object is a valid JSON
///
/// # Example
///
/// ```rust,no_run
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// # use std::collections::Bound;
/// # use diesel::sql_types::Text;
/// #
/// # let conn = &mut establish_connection();
/// #
///
/// let res = diesel::select(("1".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, true);
/// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, true);
/// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, true);
/// let res = diesel::select(("(1,2,3)".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, false);
/// #
/// # Ok(())
/// # }
/// ```
#[allow(clippy::wrong_self_convention)] // This is named after the sql operator
fn is_json(self) -> dsl::IsJson<Self> {
IsJson::new(self)
}

/// Creates a PostgreSQL `IS NOT JSON` expression.
/// Requires PostgreSQL>=16
///
/// This operator returns true whether an object is not a valid JSON
///
/// # Example
///
/// ```rust,no_run
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// # use std::collections::Bound;
/// # use diesel::sql_types::Text;
/// #
/// # let conn = &mut establish_connection();
/// #
///
/// let res = diesel::select(("1".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, false);
/// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, false);
/// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, false);
/// let res = diesel::select(("(1,2,3)".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
/// assert_eq!(res, true);
/// #
/// # Ok(())
/// # }
/// ```
#[allow(clippy::wrong_self_convention)] // This is named after the sql operator
fn is_not_json(self) -> dsl::IsNotJson<Self> {
IsNotJson::new(self)
}
}

impl<T: Expression> PgExpressionMethods for T {}
Expand Down
8 changes: 8 additions & 0 deletions diesel/src/pg/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ pub type IntersectionRange<Lhs, Rhs> = Intersection<Lhs, Rhs>;
#[cfg(feature = "postgres_backend")]
pub type NullsFirst<T> = super::operators::NullsFirst<T>;

/// The return type of [`expr.is_json()`](super::expression_methods::PgExpressionMethods::is_json)
#[cfg(feature = "postgres_backend")]
pub type IsJson<T> = super::operators::IsJson<T>;

/// The return type of [`expr.is_not_json()`](super::expression_methods::PgExpressionMethods::is_not_json)
#[cfg(feature = "postgres_backend")]
pub type IsNotJson<T> = super::operators::IsNotJson<T>;

/// The return type of [`expr.nulls_last()`](super::expression_methods::PgSortExpressionMethods::nulls_last)
#[cfg(feature = "postgres_backend")]
pub type NullsLast<T> = super::operators::NullsLast<T>;
Expand Down
2 changes: 2 additions & 0 deletions diesel/src/pg/expression/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ infix_operator!(SimilarTo, " SIMILAR TO ", backend: Pg);
infix_operator!(NotSimilarTo, " NOT SIMILAR TO ", backend: Pg);
postfix_operator!(NullsFirst, " NULLS FIRST", NotSelectable, backend: Pg);
postfix_operator!(NullsLast, " NULLS LAST", NotSelectable, backend: Pg);
postfix_operator!(IsJson, " IS JSON", backend: Pg);
postfix_operator!(IsNotJson, " IS NOT JSON", backend: Pg);
infix_operator!(ContainsNet, " >> ", backend: Pg);
infix_operator!(ContainsNetLoose, " >>= ", backend: Pg);
infix_operator!(IsContainedByNet, " << ", backend: Pg);
Expand Down
2 changes: 2 additions & 0 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ fn test_pg_jsonb_expression_methods() -> _ {
.and(pg_extras::jsonb.remove(1_i32).eq(pg_extras::jsonb))
.and(pg_extras::jsonb.remove_by_path(v).eq(pg_extras::jsonb))
.and(pg_extras::jsonb.is_contained_by(pg_extras::jsonb))
.and(pg_extras::id.is_json())
.and(pg_extras::id.is_not_json())
}

#[cfg(feature = "postgres")]
Expand Down

0 comments on commit 0d4d41b

Please sign in to comment.