diff --git a/lib/src/fnc/array.rs b/lib/src/fnc/array.rs index 09e2b72a..41bd3dbd 100644 --- a/lib/src/fnc/array.rs +++ b/lib/src/fnc/array.rs @@ -143,6 +143,27 @@ pub fn reverse((mut array,): (Array,)) -> Result { Ok(array.into()) } +pub fn slice((array, beg, lim): (Array, Option, Option)) -> Result { + let skip = match beg { + Some(v) if v < 0 => array.len().saturating_sub(v.unsigned_abs()), + Some(v) => v as usize, + None => 0, + }; + + let take = match lim { + Some(v) if v < 0 => array.len().saturating_sub(skip).saturating_sub(v.unsigned_abs()), + Some(v) => v as usize, + None => usize::MAX, + }; + + Ok(if skip > 0 || take < usize::MAX { + array.into_iter().skip(skip).take(take).collect::>().into() + } else { + array + } + .into()) +} + pub fn sort((mut array, order): (Array, Option)) -> Result { match order { // If "asc", sort ascending @@ -193,3 +214,29 @@ pub mod sort { Ok(array.into()) } } + +#[cfg(test)] +mod tests { + use super::slice; + use crate::sql::{Array, Value}; + + #[test] + fn array_slice() { + fn test(initial: &[u8], beg: Option, lim: Option, expected: &[u8]) { + let initial_values = + initial.iter().map(|n| Value::from(*n as i64)).collect::>().into(); + let expected_values: Array = + expected.iter().map(|n| Value::from(*n as i64)).collect::>().into(); + assert_eq!(slice((initial_values, beg, lim)).unwrap(), expected_values.into()); + } + + let array = &[b'a', b'b', b'c', b'd', b'e', b'f', b'g']; + test(array, None, None, array); + test(array, Some(2), None, &array[2..]); + test(array, Some(2), Some(3), &array[2..5]); + test(array, Some(2), Some(-1), &[b'c', b'd', b'e', b'f']); + test(array, Some(-2), None, &[b'f', b'g']); + test(array, Some(-4), Some(2), &[b'd', b'e']); + test(array, Some(-4), Some(-1), &[b'd', b'e', b'f']); + } +} diff --git a/lib/src/fnc/mod.rs b/lib/src/fnc/mod.rs index d5dc2b3e..778430da 100644 --- a/lib/src/fnc/mod.rs +++ b/lib/src/fnc/mod.rs @@ -85,6 +85,7 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec) -> Result array::push, "array::remove" => array::remove, "array::reverse" => array::reverse, + "array::slice" => array::slice, "array::sort" => array::sort, "array::union" => array::union, "array::sort::asc" => array::sort::asc, diff --git a/lib/src/sql/function.rs b/lib/src/sql/function.rs index 6e455318..79789e08 100644 --- a/lib/src/sql/function.rs +++ b/lib/src/sql/function.rs @@ -358,6 +358,7 @@ fn function_array(i: &str) -> IResult<&str, &str> { tag("push"), tag("remove"), tag("reverse"), + tag("slice"), tag("sort::asc"), tag("sort::desc"), tag("sort"),