From e172494a250d7978269c4da2e5fb2ae49bcba8b4 Mon Sep 17 00:00:00 2001 From: Ali Tariq Date: Tue, 3 Sep 2024 17:06:51 +0500 Subject: [PATCH 1/4] implement json_object --- diesel/src/pg/expression/functions.rs | 35 +++++++++++++++++++++++++++ diesel_derives/tests/auto_type.rs | 1 + 2 files changed, 36 insertions(+) diff --git a/diesel/src/pg/expression/functions.rs b/diesel/src/pg/expression/functions.rs index 5eb92d4046f8..ff6df9937e6d 100644 --- a/diesel/src/pg/expression/functions.rs +++ b/diesel/src/pg/expression/functions.rs @@ -1546,3 +1546,38 @@ define_sql_function! { /// ``` fn to_jsonb>(e: E) -> E::Out; } + +define_sql_function! { + /// Builds a JSON object out of a text array. The array must have an even number of members, + /// in which case they are taken as alternating key/value pairs + /// + /// # Example + /// + /// ```rust + /// # include!("../../doctest_setup.rs"); + /// # + /// # fn main() { + /// # run_test().unwrap(); + /// # } + /// # + /// # fn run_test() -> QueryResult<()> { + /// # use diesel::dsl::json_object; + /// # use diesel::sql_types::{Json}; + /// # use serde_json::Value; + /// # let connection = &mut establish_connection(); + /// let json = diesel::select(json_object(vec!["hello","world"])).get_result::(connection)?; + /// let expected:Value = serde_json::from_str(r#"{"hello":"world"}"#).unwrap(); + /// assert_eq!(expected,json); + /// + /// let json = diesel::select(json_object(vec!["hello","world","John","Doe"])).get_result::(connection)?; + /// let expected:Value = serde_json::from_str(r#"{"hello":"world","John":"Doe"}"#).unwrap(); + /// assert_eq!(expected,json); + /// + /// let json = diesel::select(json_object(vec!["hello","world","John"])).get_result::(connection); + /// assert!(json.is_err()); + /// + /// # Ok(()) + /// # } + /// ``` + fn json_object(text_array:Array)->Json; +} diff --git a/diesel_derives/tests/auto_type.rs b/diesel_derives/tests/auto_type.rs index 170af4a6265a..f59a2b2137e5 100644 --- a/diesel_derives/tests/auto_type.rs +++ b/diesel_derives/tests/auto_type.rs @@ -435,6 +435,7 @@ fn postgres_functions() -> _ { array_shuffle(pg_extras::array), to_json(pg_extras::id), to_jsonb(pg_extras::id), + json_object(pg_extras::array), ) } From e16542b4dbbf2094a66c77606e12b7ab46150997 Mon Sep 17 00:00:00 2001 From: Ali Tariq Date: Fri, 6 Sep 2024 12:54:57 +0500 Subject: [PATCH 2/4] fixed auto_type.rs --- diesel/src/pg/expression/functions.rs | 20 ++++++++++++++------ diesel_derives/tests/auto_type.rs | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/diesel/src/pg/expression/functions.rs b/diesel/src/pg/expression/functions.rs index ff6df9937e6d..4096ae3aa31c 100644 --- a/diesel/src/pg/expression/functions.rs +++ b/diesel/src/pg/expression/functions.rs @@ -1565,19 +1565,27 @@ define_sql_function! { /// # use diesel::sql_types::{Json}; /// # use serde_json::Value; /// # let connection = &mut establish_connection(); - /// let json = diesel::select(json_object(vec!["hello","world"])).get_result::(connection)?; - /// let expected:Value = serde_json::from_str(r#"{"hello":"world"}"#).unwrap(); + /// let json = diesel::select(json_object(vec!["hello","world"])) + /// .get_result::(connection)?; + /// let expected:Value = serde_json::json!({"hello":"world"}); /// assert_eq!(expected,json); /// - /// let json = diesel::select(json_object(vec!["hello","world","John","Doe"])).get_result::(connection)?; - /// let expected:Value = serde_json::from_str(r#"{"hello":"world","John":"Doe"}"#).unwrap(); + /// let json = diesel::select(json_object(vec!["hello","world","John","Doe"])) + /// .get_result::(connection)?; + /// let expected:Value = serde_json::json!({"hello":"world","John":"Doe"}); /// assert_eq!(expected,json); /// - /// let json = diesel::select(json_object(vec!["hello","world","John"])).get_result::(connection); + /// let json = diesel::select(json_object(vec!["hello","world","John"])) + /// .get_result::(connection); + /// assert!(json.is_err()); + /// + /// let empty:Vec = Vec::new(); + /// let json = diesel::select(json_object(empty)) + /// .get_result::(connection); /// assert!(json.is_err()); /// /// # Ok(()) /// # } /// ``` - fn json_object(text_array:Array)->Json; + fn json_object(text_array:Nullable>)->Json; } diff --git a/diesel_derives/tests/auto_type.rs b/diesel_derives/tests/auto_type.rs index f59a2b2137e5..286ccfb5159c 100644 --- a/diesel_derives/tests/auto_type.rs +++ b/diesel_derives/tests/auto_type.rs @@ -51,7 +51,8 @@ table! { range -> Range, multirange -> Multirange, timestamptz -> Timestamptz, - name -> Text + name -> Text, + text_array -> Array } } @@ -435,7 +436,7 @@ fn postgres_functions() -> _ { array_shuffle(pg_extras::array), to_json(pg_extras::id), to_jsonb(pg_extras::id), - json_object(pg_extras::array), + json_object(pg_extras::text_array), ) } From 2c9b3c636ac331a50df2836fc4127863b7357155 Mon Sep 17 00:00:00 2001 From: "ali.tariq" Date: Tue, 10 Sep 2024 12:21:13 +0500 Subject: [PATCH 3/4] fixed type signature --- diesel/src/pg/expression/expression_methods.rs | 9 ++++++++- diesel/src/pg/expression/functions.rs | 13 +++++++------ diesel/src/pg/expression/helper_types.rs | 5 +++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs index e5dfdfdb58d8..677797115d1c 100644 --- a/diesel/src/pg/expression/expression_methods.rs +++ b/diesel/src/pg/expression/expression_methods.rs @@ -3,7 +3,7 @@ pub(in crate::pg) use self::private::{ ArrayOrNullableArray, InetOrCidr, JsonIndex, JsonOrNullableJsonOrJsonbOrNullableJsonb, JsonRemoveIndex, JsonbOrNullableJsonb, MaybeNullableValue, MultirangeOrNullableMultirange, - MultirangeOrRangeMaybeNullable, RangeHelper, RangeOrNullableRange, TextOrNullableText, + MultirangeOrRangeMaybeNullable, RangeHelper, RangeOrNullableRange, TextArrayOrNullableTextArray, TextOrNullableText, }; use super::date_and_time::{AtTimeZone, DateTimeLike}; use super::operators::*; @@ -3712,4 +3712,11 @@ pub(in crate::pg) mod private { { type Out = >::Out; } + + pub trait TextArrayOrNullableTextArray {} + + impl TextArrayOrNullableTextArray for Array {} + impl TextArrayOrNullableTextArray for Array> {} + impl TextArrayOrNullableTextArray for Nullable> {} + impl TextArrayOrNullableTextArray for Nullable>> {} } diff --git a/diesel/src/pg/expression/functions.rs b/diesel/src/pg/expression/functions.rs index 4096ae3aa31c..629d36d959c7 100644 --- a/diesel/src/pg/expression/functions.rs +++ b/diesel/src/pg/expression/functions.rs @@ -5,6 +5,7 @@ use crate::expression::functions::define_sql_function; use crate::pg::expression::expression_methods::ArrayOrNullableArray; use crate::pg::expression::expression_methods::MaybeNullableValue; use crate::pg::expression::expression_methods::MultirangeOrNullableMultirange; +use crate::pg::expression::expression_methods::TextArrayOrNullableTextArray; use crate::pg::expression::expression_methods::MultirangeOrRangeMaybeNullable; use crate::pg::expression::expression_methods::RangeOrNullableRange; use crate::sql_types::*; @@ -1562,30 +1563,30 @@ define_sql_function! { /// # /// # fn run_test() -> QueryResult<()> { /// # use diesel::dsl::json_object; - /// # use diesel::sql_types::{Json}; + /// # use diesel::sql_types::{Array, Json, Nullable, Text}; /// # use serde_json::Value; /// # let connection = &mut establish_connection(); - /// let json = diesel::select(json_object(vec!["hello","world"])) + /// let json = diesel::select(json_object::,_>(vec!["hello","world"])) /// .get_result::(connection)?; /// let expected:Value = serde_json::json!({"hello":"world"}); /// assert_eq!(expected,json); /// - /// let json = diesel::select(json_object(vec!["hello","world","John","Doe"])) + /// let json = diesel::select(json_object::,_>(vec!["hello","world","John","Doe"])) /// .get_result::(connection)?; /// let expected:Value = serde_json::json!({"hello":"world","John":"Doe"}); /// assert_eq!(expected,json); /// - /// let json = diesel::select(json_object(vec!["hello","world","John"])) + /// let json = diesel::select(json_object::,_>(vec!["hello","world","John"])) /// .get_result::(connection); /// assert!(json.is_err()); /// /// let empty:Vec = Vec::new(); - /// let json = diesel::select(json_object(empty)) + /// let json = diesel::select(json_object::>,_>(empty)) /// .get_result::(connection); /// assert!(json.is_err()); /// /// # Ok(()) /// # } /// ``` - fn json_object(text_array:Nullable>)->Json; + fn json_object>(text_array: Arr) -> Arr::Out; } diff --git a/diesel/src/pg/expression/helper_types.rs b/diesel/src/pg/expression/helper_types.rs index fd199cc4d026..899d8fd2c1b4 100644 --- a/diesel/src/pg/expression/helper_types.rs +++ b/diesel/src/pg/expression/helper_types.rs @@ -476,3 +476,8 @@ pub type to_json = super::functions::to_json, E>; #[allow(non_camel_case_types)] #[cfg(feature = "postgres_backend")] pub type to_jsonb = super::functions::to_jsonb, E>; + +/// Return type of [`json_object(text_array)`](super::functions::json_object()) +#[allow(non_camel_case_types)] +#[cfg(feature = "postgres_backend")] +pub type json_object = super::functions::json_object,A>; From 24612bab530fe1661bd6d7e69009ccaef5cbfe68 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Tue, 10 Sep 2024 18:12:06 +0200 Subject: [PATCH 4/4] Minor cleanup * Add `#[diagnostic::on_unimplemented]` for new helper trait * Fix formatting --- diesel/src/pg/expression/expression_methods.rs | 8 +++++++- diesel/src/pg/expression/functions.rs | 6 ++++-- diesel/src/pg/expression/helper_types.rs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/diesel/src/pg/expression/expression_methods.rs b/diesel/src/pg/expression/expression_methods.rs index 677797115d1c..f7836c682235 100644 --- a/diesel/src/pg/expression/expression_methods.rs +++ b/diesel/src/pg/expression/expression_methods.rs @@ -3,7 +3,8 @@ pub(in crate::pg) use self::private::{ ArrayOrNullableArray, InetOrCidr, JsonIndex, JsonOrNullableJsonOrJsonbOrNullableJsonb, JsonRemoveIndex, JsonbOrNullableJsonb, MaybeNullableValue, MultirangeOrNullableMultirange, - MultirangeOrRangeMaybeNullable, RangeHelper, RangeOrNullableRange, TextArrayOrNullableTextArray, TextOrNullableText, + MultirangeOrRangeMaybeNullable, RangeHelper, RangeOrNullableRange, + TextArrayOrNullableTextArray, TextOrNullableText, }; use super::date_and_time::{AtTimeZone, DateTimeLike}; use super::operators::*; @@ -3713,6 +3714,11 @@ pub(in crate::pg) mod private { type Out = >::Out; } + #[diagnostic::on_unimplemented( + message = "`{Self}` is neither `Array`, `Array>`,\ + `Nullable>` nor `diesel::sql_types::Nullable>>`", + note = "try to provide an expression that produces one of the expected sql types" + )] pub trait TextArrayOrNullableTextArray {} impl TextArrayOrNullableTextArray for Array {} diff --git a/diesel/src/pg/expression/functions.rs b/diesel/src/pg/expression/functions.rs index 629d36d959c7..c03d1d7fd007 100644 --- a/diesel/src/pg/expression/functions.rs +++ b/diesel/src/pg/expression/functions.rs @@ -5,9 +5,9 @@ use crate::expression::functions::define_sql_function; use crate::pg::expression::expression_methods::ArrayOrNullableArray; use crate::pg::expression::expression_methods::MaybeNullableValue; use crate::pg::expression::expression_methods::MultirangeOrNullableMultirange; -use crate::pg::expression::expression_methods::TextArrayOrNullableTextArray; use crate::pg::expression::expression_methods::MultirangeOrRangeMaybeNullable; use crate::pg::expression::expression_methods::RangeOrNullableRange; +use crate::pg::expression::expression_methods::TextArrayOrNullableTextArray; use crate::sql_types::*; define_sql_function! { @@ -1588,5 +1588,7 @@ define_sql_function! { /// # Ok(()) /// # } /// ``` - fn json_object>(text_array: Arr) -> Arr::Out; + fn json_object>( + text_array: Arr, + ) -> Arr::Out; } diff --git a/diesel/src/pg/expression/helper_types.rs b/diesel/src/pg/expression/helper_types.rs index 899d8fd2c1b4..d53f54805d43 100644 --- a/diesel/src/pg/expression/helper_types.rs +++ b/diesel/src/pg/expression/helper_types.rs @@ -480,4 +480,4 @@ pub type to_jsonb = super::functions::to_jsonb, E>; /// Return type of [`json_object(text_array)`](super::functions::json_object()) #[allow(non_camel_case_types)] #[cfg(feature = "postgres_backend")] -pub type json_object = super::functions::json_object,A>; +pub type json_object = super::functions::json_object, A>;