diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs index f7836c682235..ce1664543cb6 100644 --- a/diesel/src/pg/expression/expression_methods.rs +++ b/diesel/src/pg/expression/expression_methods.rs @@ -1,10 +1,10 @@ //! PostgreSQL specific expression methods pub(in crate::pg) use self::private::{ - ArrayOrNullableArray, InetOrCidr, JsonIndex, JsonOrNullableJsonOrJsonbOrNullableJsonb, - JsonRemoveIndex, JsonbOrNullableJsonb, MaybeNullableValue, MultirangeOrNullableMultirange, - MultirangeOrRangeMaybeNullable, RangeHelper, RangeOrNullableRange, - TextArrayOrNullableTextArray, TextOrNullableText, + ArrayOrNullableArray, InetOrCidr, JsonIndex, JsonOrNullableJson, + JsonOrNullableJsonOrJsonbOrNullableJsonb, JsonRemoveIndex, JsonbOrNullableJsonb, + MaybeNullableValue, MultirangeOrNullableMultirange, MultirangeOrRangeMaybeNullable, + RangeHelper, RangeOrNullableRange, TextArrayOrNullableTextArray, TextOrNullableText, }; use super::date_and_time::{AtTimeZone, DateTimeLike}; use super::operators::*; @@ -3552,6 +3552,11 @@ pub(in crate::pg) mod private { impl JsonbOrNullableJsonb for Jsonb {} impl JsonbOrNullableJsonb for Nullable {} + pub trait JsonOrNullableJson {} + + impl JsonOrNullableJson for Json {} + impl JsonOrNullableJson for Nullable {} + /// A trait that describes valid json indices used by postgresql pub trait JsonRemoveIndex { /// The Expression node created by this index type diff --git a/diesel/src/pg/expression/functions.rs b/diesel/src/pg/expression/functions.rs index bc851a5258e5..6039b02995a2 100644 --- a/diesel/src/pg/expression/functions.rs +++ b/diesel/src/pg/expression/functions.rs @@ -3,6 +3,8 @@ use super::expression_methods::InetOrCidr; use crate::expression::functions::define_sql_function; use crate::pg::expression::expression_methods::ArrayOrNullableArray; +use crate::pg::expression::expression_methods::JsonOrNullableJson; +use crate::pg::expression::expression_methods::JsonbOrNullableJsonb; use crate::pg::expression::expression_methods::MaybeNullableValue; use crate::pg::expression::expression_methods::MultirangeOrNullableMultirange; use crate::pg::expression::expression_methods::MultirangeOrRangeMaybeNullable; @@ -1634,3 +1636,123 @@ define_sql_function! { text_array: Arr, ) -> Arr::Out; } + +#[cfg(feature = "postgres_backend")] +define_sql_function! { + /// Returns the type of the top-level json value as a text-string + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # #[cfg(feature = "serde_json")] + /// # run_test().unwrap(); + /// # } + /// # + /// # #[cfg(feature = "serde_json")] + /// # fn run_test() -> QueryResult<()> { + /// # use diesel::dsl::json_typeof; + /// # use serde_json::{json, Value}; + /// # use diesel::sql_types::{Json, Nullable}; + /// # let connection = &mut establish_connection(); + /// let result = diesel::select(json_typeof::(json!({"a": "b", "c": 1}))) + /// .get_result::(connection)?; + /// + /// assert_eq!("object".to_string(), result); + /// + /// let result = diesel::select(json_typeof::(json!([1,2,3]))) + /// .get_result::(connection)?; + /// + /// assert_eq!("array".to_string(), result); + /// + /// let result = diesel::select(json_typeof::(json!("abc"))) + /// .get_result::(connection)?; + /// + /// assert_eq!("string".to_string(), result); + /// + /// let result = diesel::select(json_typeof::(json!(-123.4))) + /// .get_result::(connection)?; + /// + /// assert_eq!("number".to_string(), result); + /// + /// let result = diesel::select(json_typeof::(json!(true))) + /// .get_result::(connection)?; + /// + /// assert_eq!("boolean".to_string(), result); + /// + /// let result = diesel::select(json_typeof::(json!(null))) + /// .get_result::(connection)?; + /// + /// assert_eq!("null".to_string(), result); + /// + /// let result = diesel::select(json_typeof::, _>(None::)) + /// .get_result::>(connection)?; + /// + /// assert!(result.is_none()); + /// # Ok(()) + /// # } + /// ``` + fn json_typeof>(e: E) -> E::Out; +} + +#[cfg(feature = "postgres_backend")] +define_sql_function! { + /// Returns the type of the top-level jsonb value as a text-string + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # #[cfg(feature = "serde_json")] + /// # run_test().unwrap(); + /// # } + /// # + /// # #[cfg(feature = "serde_json")] + /// # fn run_test() -> QueryResult<()> { + /// # use diesel::dsl::jsonb_typeof; + /// # use serde_json::{json, Value}; + /// # use diesel::sql_types::{Jsonb, Nullable}; + /// # let connection = &mut establish_connection(); + /// let result = diesel::select(jsonb_typeof::(json!({"a": "b", "c": 1}))) + /// .get_result::(connection)?; + /// + /// assert_eq!("object".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::(json!([1,2,3]))) + /// .get_result::(connection)?; + /// + /// assert_eq!("array".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::(json!("abc"))) + /// .get_result::(connection)?; + /// + /// assert_eq!("string".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::(json!(-123.4))) + /// .get_result::(connection)?; + /// + /// assert_eq!("number".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::(json!(true))) + /// .get_result::(connection)?; + /// + /// assert_eq!("boolean".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::(json!(null))) + /// .get_result::(connection)?; + /// + /// assert_eq!("null".to_string(), result); + /// + /// let result = diesel::select(jsonb_typeof::, _>(None::)) + /// .get_result::>(connection)?; + /// + /// assert!(result.is_none()); + /// # Ok(()) + /// # } + /// ``` + fn jsonb_typeof>(e: E) -> E::Out; +} diff --git a/diesel/src/pg/expression/helper_types.rs b/diesel/src/pg/expression/helper_types.rs index 81cd81bd10a1..3e757b08872b 100644 --- a/diesel/src/pg/expression/helper_types.rs +++ b/diesel/src/pg/expression/helper_types.rs @@ -486,3 +486,13 @@ pub type to_jsonb = super::functions::to_jsonb, E>; #[allow(non_camel_case_types)] #[cfg(feature = "postgres_backend")] pub type json_object = super::functions::json_object, A>; + +/// Return type of [`json_typeof(json)`](super::functions::json_typeof()) +#[allow(non_camel_case_types)] +#[cfg(feature = "postgres_backend")] +pub type json_typeof = super::functions::json_typeof, E>; + +/// Return type of [`jsonb_typeof(jsonb)`](super::functions::jsonb_typeof()) +#[allow(non_camel_case_types)] +#[cfg(feature = "postgres_backend")] +pub type jsonb_typeof = super::functions::jsonb_typeof, E>; diff --git a/diesel_derives/tests/auto_type.rs b/diesel_derives/tests/auto_type.rs index 6c96ad2b20b4..7fc1ffa133cb 100644 --- a/diesel_derives/tests/auto_type.rs +++ b/diesel_derives/tests/auto_type.rs @@ -438,6 +438,8 @@ fn postgres_functions() -> _ { to_json(pg_extras::id), to_jsonb(pg_extras::id), json_object(pg_extras::text_array), + json_typeof(pg_extras::json), + jsonb_typeof(pg_extras::jsonb), ) }