Skip to content

Commit

Permalink
Merge pull request #4256 from valkrypton/feat/add/jsonb_object
Browse files Browse the repository at this point in the history
implement jsonb_object (both variants)
  • Loading branch information
weiznich authored Sep 18, 2024
2 parents 810c3e3 + 307e9db commit 2b394ca
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
113 changes: 113 additions & 0 deletions diesel/src/pg/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,9 +1669,11 @@ define_sql_function! {
/// # 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_object_with_keys_and_values;
/// # use diesel::sql_types::{Array, Json, Nullable, Text};
Expand Down Expand Up @@ -1913,9 +1915,11 @@ define_sql_function! {
/// # 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_strip_nulls;
/// # use diesel::sql_types::{Json, Nullable};
Expand Down Expand Up @@ -1957,9 +1961,11 @@ define_sql_function! {
/// # 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_strip_nulls;
/// # use diesel::sql_types::{Jsonb, Nullable};
Expand Down Expand Up @@ -2078,3 +2084,110 @@ define_sql_function! {

fn jsonb_array_length<E: JsonbOrNullableJsonb + MaybeNullableValue<Integer>>(jsonb: E) -> E::Out;
}

#[cfg(feature = "postgres_backend")]
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. This function also has a form that
/// that takes keys and values as separate text array arguments.
/// See [jsonb_object_with_keys_and_values]
///
/// # 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_object;
/// # use diesel::sql_types::{Array, Json, Nullable, Text};
/// # use serde_json::Value;
/// # let connection = &mut establish_connection();
/// let jsonb = diesel::select(jsonb_object::<Array<Text>,_>(vec!["hello","world"]))
/// .get_result::<Value>(connection)?;
/// let expected:Value = serde_json::json!({"hello":"world"});
/// assert_eq!(expected, jsonb);
///
/// let jsonb = diesel::select(jsonb_object::<Array<Text>, _>(vec!["hello","world","John","Doe"]))
/// .get_result::<Value>(connection)?;
/// let expected:Value = serde_json::json!({"hello": "world","John": "Doe"});
/// assert_eq!(expected, jsonb);
///
/// let jsonb = diesel::select(jsonb_object::<Nullable<Array<Text>>, _>(None::<Vec<String>>))
/// .get_result::<Option<Value>>(connection)?;
/// assert!(jsonb.is_none());
///
/// let empty:Vec<String> = Vec::new();
/// let jsonb = diesel::select(jsonb_object::<Array<Nullable<Text>>,_>(empty))
/// .get_result::<Value>(connection)?;
/// let expected = serde_json::json!({});
/// assert_eq!(expected, jsonb);
///
/// let jsonb = diesel::select(jsonb_object::<Array<Text>, _>(vec!["hello","world","John"]))
/// .get_result::<Value>(connection);
/// assert!(jsonb.is_err());
///
///
/// # Ok(())
/// # }
/// ```
fn jsonb_object<Arr: TextArrayOrNullableTextArray + MaybeNullableValue<Jsonb>>(
text_array: Arr,
) -> Arr::Out;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// This form of jsonb_object takes keys and values pairwise from two separate arrays.
/// In all other respects it is identical to the one-argument form.
///
/// # 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_object_with_keys_and_values;
/// # use diesel::sql_types::{Array, Nullable, Text};
/// # use serde_json::Value;
/// # let connection = &mut establish_connection();
/// let jsonb = diesel::select(jsonb_object_with_keys_and_values::<Array<Text>, Array<Text>, _, _>(
/// vec!["hello","John"],vec!["world","Doe"]))
/// .get_result::<Value>(connection)?;
/// let expected:Value = serde_json::json!({"hello":"world","John":"Doe"});
/// assert_eq!(expected, jsonb);
///
/// let jsonb = diesel::select(jsonb_object_with_keys_and_values::<Nullable<Array<Text>>, Nullable<Array<Text>>, _, _>(
/// Some(vec!["hello","John"]),None::<Vec<String>>))
/// .get_result::<Option<Value>>(connection)?;
/// assert_eq!(None::<Value>,jsonb);
///
/// let empty: Vec<String> = Vec::new();
/// let jsonb = diesel::select(jsonb_object_with_keys_and_values::<Array<Text>, Array<Text>, _, _>(
/// vec!["hello","John"],empty))
/// .get_result::<Value>(connection);
/// assert!(jsonb.is_err());
///
/// # Ok(())
/// # }
/// ```
#[sql_name = "jsonb_object"]
fn jsonb_object_with_keys_and_values<
Arr1: TextArrayOrNullableTextArray + SingleValue,
Arr2: TextArrayOrNullableTextArray + CombinedNullableValue<Arr1, Jsonb>
>(
keys: Arr1,
values: Arr2
) -> Arr2::Out;
}
11 changes: 11 additions & 0 deletions diesel/src/pg/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,3 +527,14 @@ pub type json_array_length<E> = super::functions::json_array_length<SqlTypeOf<E>
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type jsonb_array_length<E> = super::functions::jsonb_array_length<SqlTypeOf<E>, E>;

/// Return type of [`jsonb_object(text_array)`](super::functions::jsonb_object())
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type jsonb_object<A> = super::functions::jsonb_object<SqlTypeOf<A>, A>;

/// Return type of [`jsonb_object_with_keys_and_values(text_array, text_array)`](super::functions::jsonb_object_with_keys_and_values())
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type jsonb_object_with_keys_and_values<K, V> =
super::functions::jsonb_object_with_keys_and_values<SqlTypeOf<K>, SqlTypeOf<V>, K, V>;
2 changes: 2 additions & 0 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ fn postgres_functions() -> _ {
jsonb_strip_nulls(pg_extras::jsonb),
json_array_length(pg_extras::json),
jsonb_array_length(pg_extras::jsonb),
jsonb_object(pg_extras::text_array),
jsonb_object_with_keys_and_values(pg_extras::text_array, pg_extras::text_array),
)
}

Expand Down

0 comments on commit 2b394ca

Please sign in to comment.