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

Code before:
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use diesel::dsl::array_remove;
    /// #     use diesel::sql_types::{Nullable, Integer, Array};
    /// #     let connection = &mut establish_connection();
    /// let ints = diesel::select(array_remove::<Array<_>, Integer, _, _>(vec![1, 2, 3, 2], 2))
    ///     .get_result::<Option<Vec<i32>>>(connection)?;
    /// assert_eq!(Some(vec![1, 3]), ints);

    /// let ints = diesel::select(array_remove::<Array<_>, Nullable<Integer>, _, _>(vec![None, Some(1), Some(2), None, Some(4)], None::<i32>))
    ///     .get_result::<Option<Vec<Option<i32>>>>(connection)?;
    /// assert_eq!(Some(vec![Some(1), Some(2), Some(4)]), ints);

    /// let ints = diesel::select(array_remove::<Nullable<Array<_>>, Nullable<Integer>, _, _>(None::<Vec<i32>>, None::<i32>))
    ///     .get_result::<Option<Vec<Option<i32>>>>(connection)?;
    /// assert_eq!(None, ints);
    /// #     Ok(())
    /// # }
    /// ```
    fn array_remove<Arr: ArrayOrNullableArray<Inner=T> + SingleValue, T: SingleValue>(a: Arr, e: T) -> Nullable<Array<T>>;
}


Review comment (suggestion):
I think it might seem odd that I specified the return type as `Nullable<Array<T>>` instead of simply `Array<T>`.

The reason is I found that `array_remove` returns a wholly `null` value if both arguments are `null`, unlike `array_append` which returns an `Array<null>`. Therefore, I wrapped the return type in `Nullable` to avoid getting an unexpected null deserialization error if the arguments both happen to be `null`.

Added a screenshot illustrating this point! Let me know if there are any issues with this

![array_remove vs array_append](https://github.com/user-attachments/assets/0ea08275-a0e3-401a-991d-4ecd6f8f961e)


Code after:

#[cfg(feature = "postgres_backend")]
define_sql_function! {
    /// Prepends an element to the beginning of an array
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use diesel::dsl::array_prepend;
    /// #     use diesel::sql_types::{Nullable, Integer, Array};
    /// #     let connection = &mut establish_connection();
    /// let ints = diesel::select(array_prepend::<Integer, Array<_>, _, _>(3, vec![1, 2]))
    ///     .get_result::<Vec<i32>>(connection)?;
    /// assert_eq!(vec![3, 1, 2], ints);
    ///
    /// let ints = diesel::select(array_prepend::<Nullable<Integer>, Array<_>, _, _>(None::<i32>, vec![Some(1), Some(2)]))
    ///     .get_result::<Vec<Option<i32>>>(connection)?;
    /// assert_eq!(vec![None, Some(1), Some(2)], ints);
    ///
    /// let ints = diesel::select(array_prepend::<Integer, Nullable<Array<_>>, _, _>(3, None::<Vec<i32>>))
    ///     .get_result::<Vec<i32>>(connection)?;
    /// assert_eq!(vec![3], ints);
    ///
    /// let ints = diesel::select(array_prepend::<Nullable<Integer>, Nullable<Array<_>>, _, _>(None::<i32>, None::<Vec<i32>>))
    ///     .get_result::<Vec<Option<i32>>>(connection)?;
    /// assert_eq!(vec![None], ints);
    /// #     Ok(())
    /// # }
    /// ```
    fn array_prepend<T: SingleValue, Arr: ArrayOrNullableArray<Inner=T> + SingleValue>(e: T, a: Arr) -> Array<T>;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
    /// Removes all elements equal to the given value from the array
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }