Skip to content

Commit 0d4d41b

Browse files
authored
Merge pull request diesel-rs#4314 from meeshal/add_is_json_expression
add is_json and is_not_json expression methods
2 parents 569c684 + c41b5b7 commit 0d4d41b

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

diesel/src/pg/expression/expression_methods.rs

+76
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,82 @@ pub trait PgExpressionMethods: Expression + Sized {
158158
{
159159
Grouped(IsContainedBy::new(self, other.as_expression()))
160160
}
161+
162+
/// Creates a PostgreSQL `IS JSON` expression.
163+
/// Requires PostgreSQL>=16
164+
///
165+
/// This operator returns true whether an object is a valid JSON
166+
///
167+
/// # Example
168+
///
169+
/// ```rust,no_run
170+
/// # include!("../../doctest_setup.rs");
171+
/// #
172+
/// # fn main() {
173+
/// # run_test().unwrap();
174+
/// # }
175+
/// #
176+
/// # fn run_test() -> QueryResult<()> {
177+
/// # use std::collections::Bound;
178+
/// # use diesel::sql_types::Text;
179+
/// #
180+
/// # let conn = &mut establish_connection();
181+
/// #
182+
///
183+
/// let res = diesel::select(("1".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
184+
/// assert_eq!(res, true);
185+
/// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
186+
/// assert_eq!(res, true);
187+
/// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
188+
/// assert_eq!(res, true);
189+
/// let res = diesel::select(("(1,2,3)".into_sql::<Text>().is_json())).get_result::<bool>(conn)?;
190+
/// assert_eq!(res, false);
191+
/// #
192+
/// # Ok(())
193+
/// # }
194+
/// ```
195+
#[allow(clippy::wrong_self_convention)] // This is named after the sql operator
196+
fn is_json(self) -> dsl::IsJson<Self> {
197+
IsJson::new(self)
198+
}
199+
200+
/// Creates a PostgreSQL `IS NOT JSON` expression.
201+
/// Requires PostgreSQL>=16
202+
///
203+
/// This operator returns true whether an object is not a valid JSON
204+
///
205+
/// # Example
206+
///
207+
/// ```rust,no_run
208+
/// # include!("../../doctest_setup.rs");
209+
/// #
210+
/// # fn main() {
211+
/// # run_test().unwrap();
212+
/// # }
213+
/// #
214+
/// # fn run_test() -> QueryResult<()> {
215+
/// # use std::collections::Bound;
216+
/// # use diesel::sql_types::Text;
217+
/// #
218+
/// # let conn = &mut establish_connection();
219+
/// #
220+
///
221+
/// let res = diesel::select(("1".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
222+
/// assert_eq!(res, false);
223+
/// let res = diesel::select(("[1,2,3]".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
224+
/// assert_eq!(res, false);
225+
/// let res = diesel::select(("{\"products\": [1,2,3]}".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
226+
/// assert_eq!(res, false);
227+
/// let res = diesel::select(("(1,2,3)".into_sql::<Text>().is_not_json())).get_result::<bool>(conn)?;
228+
/// assert_eq!(res, true);
229+
/// #
230+
/// # Ok(())
231+
/// # }
232+
/// ```
233+
#[allow(clippy::wrong_self_convention)] // This is named after the sql operator
234+
fn is_not_json(self) -> dsl::IsNotJson<Self> {
235+
IsNotJson::new(self)
236+
}
161237
}
162238

163239
impl<T: Expression> PgExpressionMethods for T {}

diesel/src/pg/expression/helper_types.rs

+8
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ pub type IntersectionRange<Lhs, Rhs> = Intersection<Lhs, Rhs>;
130130
#[cfg(feature = "postgres_backend")]
131131
pub type NullsFirst<T> = super::operators::NullsFirst<T>;
132132

133+
/// The return type of [`expr.is_json()`](super::expression_methods::PgExpressionMethods::is_json)
134+
#[cfg(feature = "postgres_backend")]
135+
pub type IsJson<T> = super::operators::IsJson<T>;
136+
137+
/// The return type of [`expr.is_not_json()`](super::expression_methods::PgExpressionMethods::is_not_json)
138+
#[cfg(feature = "postgres_backend")]
139+
pub type IsNotJson<T> = super::operators::IsNotJson<T>;
140+
133141
/// The return type of [`expr.nulls_last()`](super::expression_methods::PgSortExpressionMethods::nulls_last)
134142
#[cfg(feature = "postgres_backend")]
135143
pub type NullsLast<T> = super::operators::NullsLast<T>;

diesel/src/pg/expression/operators.rs

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ infix_operator!(SimilarTo, " SIMILAR TO ", backend: Pg);
2323
infix_operator!(NotSimilarTo, " NOT SIMILAR TO ", backend: Pg);
2424
postfix_operator!(NullsFirst, " NULLS FIRST", NotSelectable, backend: Pg);
2525
postfix_operator!(NullsLast, " NULLS LAST", NotSelectable, backend: Pg);
26+
postfix_operator!(IsJson, " IS JSON", backend: Pg);
27+
postfix_operator!(IsNotJson, " IS NOT JSON", backend: Pg);
2628
infix_operator!(ContainsNet, " >> ", backend: Pg);
2729
infix_operator!(ContainsNetLoose, " >>= ", backend: Pg);
2830
infix_operator!(IsContainedByNet, " << ", backend: Pg);

diesel_derives/tests/auto_type.rs

+2
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ fn test_pg_jsonb_expression_methods() -> _ {
282282
.and(pg_extras::jsonb.remove(1_i32).eq(pg_extras::jsonb))
283283
.and(pg_extras::jsonb.remove_by_path(v).eq(pg_extras::jsonb))
284284
.and(pg_extras::jsonb.is_contained_by(pg_extras::jsonb))
285+
.and(pg_extras::id.is_json())
286+
.and(pg_extras::id.is_not_json())
285287
}
286288

287289
#[cfg(feature = "postgres")]

0 commit comments

Comments
 (0)