Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added to_json function #4229

Merged
merged 6 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions diesel/src/pg/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1423,3 +1423,56 @@ define_sql_function! {
/// ```
fn array_upper<Arr: ArrayOrNullableArray + SingleValue>(array: Arr, dimension: Integer) -> Nullable<Integer>;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Converts any SQL value to json
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// # use diesel::dsl::to_json;
/// # use serde_json::Value;
/// # use diesel::sql_types::{Integer, Array, Json, Text, Nullable};
/// # let connection = &mut establish_connection();
/// let result = diesel::select(to_json::<Integer, _>(1))
/// .get_result::<Value>(connection)?;
///
/// let expected: Value = serde_json::from_str("1").unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use the serde_json::json! macro instead to construct the expected values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// assert_eq!(expected, result);
///
/// let result = diesel::select(to_json::<Array<Integer>, _>(vec![1, 2, 3]))
/// .get_result::<Value>(connection)?;
///
/// let expected: Value = serde_json::from_str("[1, 2, 3]").unwrap();
/// assert_eq!(expected, result);
///
/// let result = diesel::select(to_json::<Array<Text>, _>(vec!["abcd", "xyz"]))
/// .get_result::<Value>(connection)?;
///
/// let expected: Value = serde_json::from_str(r#"["abcd", "xyz"]"#).unwrap();
/// assert_eq!(expected, result);
///
/// let result = diesel::select(to_json::<Array<Nullable<Text>>, _>(Vec::<String>::new()))
/// .get_result::<Value>(connection)?;
///
/// let expected: Value = serde_json::from_str("[]").unwrap();
/// assert_eq!(expected, result);
///
/// let result = diesel::select(to_json::<Nullable<Array<Text>>, _>(None::<Vec<String>>))
/// .get_result::<Value>(connection);
///
/// assert!(result.is_err());
///
/// # Ok(())
/// # }
/// ```
fn to_json<E: SingleValue>(e: E) -> Json;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function seems to return null if you pass in a null values. We want to have a doc test demonstrating that this is correctly propagated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ive changed the last test a bit, let me know if its okay

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's not what I had in mind. My idea was to make the return type Nullable<Json> if the argument is nullable and Json for non-null arguments. As I did not know without a quick experiment how to do that I've pushed 8089dff to change it. (I needed to try it myself anyway).

To explain what's going on there:

  • The SqlType trait as a IsNull associated type that indicates whether the current type is nullable or not. We can access it as it's a super trait of SingleValue
  • The IsNull type implements MaybeNullableType<T> which wraps T into Nullable if the input type was nullable, otherwise it will just result in T.

By using that as return type we enforce that we return a non-nullable value for non-nullable inputs and nullable types otherwise, which allows us to correctly write the last test case.

}
5 changes: 5 additions & 0 deletions diesel/src/pg/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,8 @@ pub type array_positions<A, E> =
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type array_ndims<A> = super::functions::array_ndims<SqlTypeOf<A>, A>;

/// Return type of [`to_json(element)`](super::functions::to_json())
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type to_json<E> = super::functions::to_json<SqlTypeOf<E>, E>;
1 change: 1 addition & 0 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ fn postgres_functions() -> _ {
array_position_with_subscript(pg_extras::array, pg_extras::id, pg_extras::id),
array_positions(pg_extras::array, pg_extras::id),
array_ndims(pg_extras::array),
to_json(pg_extras::id),
)
}

Expand Down
Loading