Skip to content

Commit

Permalink
Merge pull request #4213 from valkrypton/feat/add/array_position
Browse files Browse the repository at this point in the history
implement array_position and array_positions
  • Loading branch information
weiznich authored Aug 30, 2024
2 parents c3adefb + 26aa885 commit 953e555
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 0 deletions.
150 changes: 150 additions & 0 deletions diesel/src/pg/expression/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1211,3 +1211,153 @@ define_sql_function! {
/// ```
fn array_lower<Arr: ArrayOrNullableArray + SingleValue>(array: Arr, dimension: Integer) -> Nullable<Integer>;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Returns the subscript of the first occurrence of the second argument in the array, or NULL if it's not present.
/// If the third argument is given, the search begins at that subscript. This function omits the third argument.
/// See [array_position_with_subscript].
///
/// The array must be one-dimensional. Comparisons are done using IS NOT DISTINCT FROM semantics,
/// so it is possible to search for NULL.
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main(){
/// # run_test().unwrap();
/// # }
/// # fn run_test()->QueryResult<()>{
/// # use diesel::dsl::array_position;
/// # use diesel::sql_types::{Nullable,Array,Integer};
/// # let connection = &mut establish_connection();
///
/// let pos = diesel::select(array_position::<Array<_>, Integer, _, _>(vec![1, 2, 3, 4], 3))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(Some(3), pos);
///
/// let pos = diesel::select(array_position::<Array<_>, Integer, _, _>(vec![1, 2, 3, 4], 5))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(None::<i32>, pos);
///
/// let pos = diesel::select(array_position::<Array<_>, Nullable<Integer>, _, _>(
/// vec![1, 2, 3, 4], None::<i32>))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(None::<i32>, pos);
///
/// let pos = diesel::select(array_position::<Array<_>, Nullable<Integer>, _, _>(
/// vec![None::<i32>, Some(1), Some(2), Some(3)], None::<i32>))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(Some(1), pos);
/// # Ok(())
/// # }
///
fn array_position<Arr: ArrayOrNullableArray<Inner = E> + SingleValue, E: SingleValue>(
a: Arr,
elem: E,
) -> Nullable<Integer>;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Returns the subscript of the first occurrence of the second argument in the array,
/// or NULL if it's not present, beginning at the subscript given as the third argument.
///
/// The array must be one-dimensional.
/// Comparisons are done using IS NOT DISTINCT FROM semantics,
/// so it is possible to search for NULL.
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main(){
/// # run_test().unwrap();
/// # }
/// # fn run_test()->QueryResult<()>{
/// # use diesel::dsl::array_position_with_subscript;
/// # use diesel::sql_types::{Nullable,Array,Integer};
/// # let connection = &mut establish_connection();
///
/// let pos = diesel::select(array_position_with_subscript::<Array<_>, Integer, _, _, _>(
/// vec![1, 2, 3, 4], 3, 2))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(Some(3), pos);
///
/// let pos = diesel::select(array_position_with_subscript::<Array<_>, Integer, _, _, _>(
/// vec![1, 2, 3, 4], 1, 2))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(None::<i32>, pos);
///
/// let pos = diesel::select(array_position_with_subscript::<Array<_>, Nullable<Integer>, _, _, _>(
/// vec![None::<i32>, Some(1), Some(2), Some(3)], None::<i32>, 1))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(Some(1), pos);
///
/// let pos = diesel::select(array_position_with_subscript::<Array<_>, Nullable<Integer>, _, _, _>(
/// vec![None::<i32>, Some(1), Some(2), Some(3)], None::<i32>, 2))
/// .get_result::<Option<i32>>(connection)?;
/// assert_eq!(None::<i32>, pos);
/// # Ok(())
/// # }
///
#[sql_name = "array_position"]
fn array_position_with_subscript<
Arr: ArrayOrNullableArray<Inner = E> + SingleValue,
E: SingleValue,
>(
a: Arr,
elem: E,
subscript: Integer,
) -> Nullable<Integer>;
}

#[cfg(feature = "postgres_backend")]
define_sql_function! {
/// Returns an array of the subscripts of all occurrences of the second argument in the
/// array given as first argument.
///
/// The array must be one-dimensional. Comparisons are done using IS NOT DISTINCT FROM semantics,
/// so it is possible to search for NULL.
/// NULL is returned only if the array is NULL; if the value is not found in the array, an empty array is returned.
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// #
/// # fn main(){
/// # run_test().unwrap();
/// # }
/// # fn run_test()->QueryResult<()>{
/// # use diesel::dsl::array_positions;
/// # use diesel::sql_types::{Nullable,Array,Integer};
/// # let connection = &mut establish_connection();
///
/// let pos = diesel::select(array_positions::<Array<_>, Integer, _, _>(vec![1, 1, 2, 1], 1))
/// .get_result::<Option<Vec<i32>>>(connection)?;
/// assert_eq!(Some(vec![1,2,4]), pos);
///
/// let pos = diesel::select(array_positions::<Array<_>, Integer, _, _>(vec![1, 2, 3, 4], 5))
/// .get_result::<Option<Vec<i32>>>(connection)?;
/// assert_eq!(Some(vec![]), pos);
///
/// let pos = diesel::select(array_positions::<Array<_>, Nullable<Integer>, _, _>(
/// vec![None::<i32>, Some(2), Some(3), None::<i32>], None::<i32>))
/// .get_result::<Option<Vec<i32>>>(connection)?;
/// assert_eq!(Some(vec![1,4]), pos);
///
/// let pos = diesel::select(array_positions::<Nullable<Array<_>>, Integer, _, _>(
/// None::<Vec<i32>>, 1))
/// .get_result::<Option<Vec<i32>>>(connection)?;
/// assert_eq!(None::<Vec<i32>>, pos);
/// # Ok(())
/// # }
///
fn array_positions<Arr: ArrayOrNullableArray<Inner = E> + SingleValue, E: SingleValue>(
a: Arr,
elem: E,
) -> Nullable<Array<Integer>>;
}
17 changes: 17 additions & 0 deletions diesel/src/pg/expression/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,20 @@ pub type array_fill_with_lower_bound<E, A1, A2> =
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type array_lower<A, D> = super::functions::array_lower<SqlTypeOf<A>, A, D>;

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

/// Return type of [`array_position_with_subscript(array,element,subscript)`](super::functions::array_position_with_subscript)
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type array_position_with_subscript<A, E, S> =
super::functions::array_position_with_subscript<SqlTypeOf<A>, SqlTypeOf<E>, A, E, S>;

/// Return type of [`array_positions(array,element)`](super::functions::array_positions)
#[allow(non_camel_case_types)]
#[cfg(feature = "postgres_backend")]
pub type array_positions<A, E> =
super::functions::array_positions<SqlTypeOf<A>, SqlTypeOf<E>, A, E>;
3 changes: 3 additions & 0 deletions diesel_derives/tests/auto_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,9 @@ fn postgres_functions() -> _ {
array_fill(pg_extras::id, pg_extras::array),
array_fill_with_lower_bound(pg_extras::id, pg_extras::array, pg_extras::array),
array_lower(pg_extras::array, 1_i32),
array_position(pg_extras::array, pg_extras::id),
array_position_with_subscript(pg_extras::array, pg_extras::id, pg_extras::id),
array_positions(pg_extras::array, pg_extras::id),
)
}

Expand Down

0 comments on commit 953e555

Please sign in to comment.