Repository: diesel-rs/diesel
File: diesel/src/pg/expression/functions.rs (Rust)

Code before:
    /// #     use diesel::dsl::json_object_with_keys_and_values;
    /// #     use diesel::sql_types::{Array, Json, Nullable, Text};
    /// #     use serde_json::Value;
    /// #     let connection = &mut establish_connection();
    /// let json = diesel::select(json_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,json);
    ///
    /// let json = diesel::select(json_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>,json);
    ///
    /// let empty: Vec<String> = Vec::new();
    /// let json = diesel::select(json_object_with_keys_and_values::<Array<Text>, Array<Text>, _, _>(
    ///             vec!["hello","John"],empty))
    ///             .get_result::<Value>(connection);
    /// assert!(json.is_err());
    ///
    /// #     Ok(())
    /// # }
    /// ```
    #[sql_name = "json_object"]
    fn json_object_with_keys_and_values<K: TextArrayOrNullableTextArray + MaybeNullableValue<Json>, V: TextArrayOrNullableTextArray + MaybeNullableValue<Json>>(
        keys: K, values: V
    ) -> K::Out;
}


Review comment (suggestion):
Unfortunately that's still not 100% correct as it only couples the nullability of the return value onto the first argument, but this function seems to return also `Null` if you pass in `Null` as second argument. (I'm sorry that null value handling is such a mess. I also feel that postgres doesn't document this in a good fashion at all.)

I cannot say without further experimentation how to solve this. I will update the comment as soon as I know more.



Code after:
        text_array: Arr,
    ) -> Arr::Out;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
    /// This form of json_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() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use diesel::dsl::json_object_with_keys_and_values;
    /// #     use diesel::sql_types::{Array, Json, Nullable, Text};
    /// #     use serde_json::Value;
    /// #     let connection = &mut establish_connection();
    /// let json = diesel::select(json_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,json);
    ///
    /// let json = diesel::select(json_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>,json);
    ///
    /// let empty: Vec<String> = Vec::new();
    /// let json = diesel::select(json_object_with_keys_and_values::<Array<Text>, Array<Text>, _, _>(
    ///             vec!["hello","John"], empty))
    ///             .get_result::<Value>(connection);
    /// assert!(json.is_err());
    ///
    /// #     Ok(())
    /// # }
    /// ```
    #[sql_name = "json_object"]
    fn json_object_with_keys_and_values<
        Arr1: TextArrayOrNullableTextArray + SingleValue,
        Arr2: TextArrayOrNullableTextArray + CombinedNullableValue<Arr1, Json>,
    >(
        keys: Arr1,
        values: Arr2,
    ) -> Arr2::Out;