Skip to content

Commit

Permalink
Add the row_to_json behavior for diesel postgres
Browse files Browse the repository at this point in the history
  • Loading branch information
PratikFandade committed Oct 10, 2024
1 parent 381be19 commit 738bf0a
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 3 deletions.
17 changes: 15 additions & 2 deletions diesel/src/pg/expression/expression_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ pub(in crate::pg) use self::private::{
ArrayOrNullableArray, CombinedNullableValue, InetOrCidr, JsonIndex, JsonOrNullableJson,
JsonOrNullableJsonOrJsonbOrNullableJsonb, JsonRemoveIndex, JsonbOrNullableJsonb,
MaybeNullableValue, MultirangeOrNullableMultirange, MultirangeOrRangeMaybeNullable,
RangeHelper, RangeOrNullableRange, TextArrayOrNullableTextArray, TextOrNullableText,
RangeHelper, RangeOrNullableRange, RecordOrNullableRecord, TextArrayOrNullableTextArray,
TextOrNullableText,
};
use super::date_and_time::{AtTimeZone, DateTimeLike};
use super::operators::*;
Expand Down Expand Up @@ -3419,7 +3420,7 @@ where
pub(in crate::pg) mod private {
use crate::sql_types::{
Array, Binary, Cidr, Inet, Integer, Json, Jsonb, MaybeNullableType, Multirange, Nullable,
OneIsNullable, Range, SingleValue, SqlType, Text,
OneIsNullable, Range, Record, SingleValue, SqlType, Text,
};
use crate::{Expression, IntoSql};

Expand Down Expand Up @@ -3749,4 +3750,16 @@ pub(in crate::pg) mod private {
impl TextArrayOrNullableTextArray for Array<Nullable<Text>> {}
impl TextArrayOrNullableTextArray for Nullable<Array<Text>> {}
impl TextArrayOrNullableTextArray for Nullable<Array<Nullable<Text>>> {}

#[diagnostic::on_unimplemented(
message = "`{Self}` is neither `Record<Text>`, `Record<Nullable<Text>>`,\
`Nullable<Record<Text>>` nor `diesel::sql_types::Nullable<Record<Nullable<Text>>>`",
note = "try to provide an expression that produces one of the expected sql types"
)]
pub trait RecordOrNullableRecord {}

impl RecordOrNullableRecord for Record<Text> {}
impl RecordOrNullableRecord for Record<Nullable<Text>> {}
impl RecordOrNullableRecord for Nullable<Record<Text>> {}
impl RecordOrNullableRecord for Nullable<Record<Nullable<Text>>> {}
}
51 changes: 51 additions & 0 deletions diesel/src/pg/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::pg::expression::expression_methods::MaybeNullableValue;
use crate::pg::expression::expression_methods::MultirangeOrNullableMultirange;
use crate::pg::expression::expression_methods::MultirangeOrRangeMaybeNullable;
use crate::pg::expression::expression_methods::RangeOrNullableRange;
use crate::pg::expression::expression_methods::RecordOrNullableRecord;
use crate::pg::expression::expression_methods::TextArrayOrNullableTextArray;
use crate::sql_types::*;

Expand Down Expand Up @@ -2191,3 +2192,53 @@ define_sql_function! {
values: Arr2
) -> Arr2::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::sql;
/// # use diesel::sql_types::{Record, Text, Integer};
/// # use serde_json::Value;
/// # let connection = &mut establish_connection();
///
/// // Example SQL query selecting a custom record type
/// let query = diesel::select(sql::<Record<(Text, Integer)>>("ROW('John', 30)::record"));
///
/// // Running the query and fetching the result as JSON
/// let (name, age): (String, i32) = query.get_result(connection)?;
///
/// // Create a Json Value
/// let json_value: Value = serde_json::json!({
/// "name": name,
/// "age": age
/// });
///
/// // Expected JSON output from the Record type
/// let expected: Value = serde_json::json!({
/// "name": "John",
/// "age": 30
/// });
///
/// // Asserting the result
/// assert_eq!(expected, json_value);
///
/// Ok(())
/// # }
/// ```
#[sql_name = "jsonb_object"]
fn row_to_json<R: RecordOrNullableRecord + SingleValue + CombinedNullableValue<Record<Text>, Jsonb>>(record: R) -> R::Out;
}
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 @@ -538,3 +538,8 @@ pub type jsonb_object<A> = super::functions::jsonb_object<SqlTypeOf<A>, A>;
#[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>;

/// Return type of [`row_to_json(record)`](super::functions::row_to_json())
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type row_to_json<R> = super::functions::row_to_json<SqlTypeOf<R>, R>;
4 changes: 3 additions & 1 deletion diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ table! {
multirange -> Multirange<Integer>,
timestamptz -> Timestamptz,
name -> Text,
text_array -> Array<Text>
text_array -> Array<Text>,
record -> Record,
}
}

Expand Down Expand Up @@ -448,6 +449,7 @@ fn postgres_functions() -> _ {
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),
row_to_json(pg_extras::record),
)
}

Expand Down

0 comments on commit 738bf0a

Please sign in to comment.