diff --git a/lib/fuzz/fuzz_targets/fuzz_executor.dict b/lib/fuzz/fuzz_targets/fuzz_executor.dict index dade6a18..e4014df7 100644 --- a/lib/fuzz/fuzz_targets/fuzz_executor.dict +++ b/lib/fuzz/fuzz_targets/fuzz_executor.dict @@ -160,6 +160,7 @@ "array::group(" "array::insert(" "array::intersect(" +"array::join(" "array::len(" "array::max(" "array::min(" diff --git a/lib/fuzz/fuzz_targets/fuzz_sql_parser.dict b/lib/fuzz/fuzz_targets/fuzz_sql_parser.dict index daa4892b..47628f9c 100644 --- a/lib/fuzz/fuzz_targets/fuzz_sql_parser.dict +++ b/lib/fuzz/fuzz_targets/fuzz_sql_parser.dict @@ -160,6 +160,7 @@ "array::group(" "array::insert(" "array::intersect(" +"array::join(" "array::len(" "array::max(" "array::min(" diff --git a/lib/src/fnc/array.rs b/lib/src/fnc/array.rs index 91faf77f..67551e5c 100644 --- a/lib/src/fnc/array.rs +++ b/lib/src/fnc/array.rs @@ -97,6 +97,10 @@ pub fn intersect((array, other): (Array, Array)) -> Result { Ok(array.intersect(other).into()) } +pub fn join((arr, sep): (Array, String)) -> Result { + Ok(arr.into_iter().map(|s| s.to_raw_string()).collect::>().join(&sep).into()) +} + pub fn len((array,): (Array,)) -> Result { Ok(array.len().into()) } @@ -217,7 +221,7 @@ pub mod sort { #[cfg(test)] mod tests { - use super::slice; + use super::{join, slice}; use crate::sql::{Array, Value}; #[test] @@ -239,4 +243,26 @@ mod tests { test(array, Some(-4), Some(2), &[b'd', b'e']); test(array, Some(-4), Some(-1), &[b'd', b'e', b'f']); } + + #[test] + fn array_join() { + fn test(arr: Array, sep: &str, expected: &str) { + assert_eq!(join((arr, sep.to_string())).unwrap(), expected.into()); + } + + test(Vec::::new().into(), ",", ""); + test(vec!["hello"].into(), ",", "hello"); + test(vec!["hello", "world"].into(), ",", "hello,world"); + test(vec!["again"; 512].into(), " and ", &vec!["again"; 512].join(" and ")); + test( + vec![Value::from(true), Value::from(false), Value::from(true)].into(), + " is ", + "true is false is true", + ); + test( + vec![Value::from(3.14), Value::from(2.72), Value::from(1.61)].into(), + " is not ", + "3.14 is not 2.72 is not 1.61", + ); + } } diff --git a/lib/src/fnc/mod.rs b/lib/src/fnc/mod.rs index 0e5cad7b..c49ffe85 100644 --- a/lib/src/fnc/mod.rs +++ b/lib/src/fnc/mod.rs @@ -77,6 +77,7 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec) -> Result array::group, "array::insert" => array::insert, "array::intersect" => array::intersect, + "array::join" => array::join, "array::len" => array::len, "array::max" => array::max, "array::min" => array::min, diff --git a/lib/src/sql/function.rs b/lib/src/sql/function.rs index 862e6274..d8f07142 100644 --- a/lib/src/sql/function.rs +++ b/lib/src/sql/function.rs @@ -309,6 +309,7 @@ fn function_array(i: &str) -> IResult<&str, &str> { )), alt(( tag("intersect"), + tag("join"), tag("len"), tag("max"), tag("min"), diff --git a/lib/tests/function.rs b/lib/tests/function.rs index fb5d92a9..94dce8d3 100644 --- a/lib/tests/function.rs +++ b/lib/tests/function.rs @@ -403,6 +403,38 @@ async fn function_array_intersect() -> Result<(), Error> { Ok(()) } +#[tokio::test] +async fn function_string_join_arr() -> Result<(), Error> { + let sql = r#" + RETURN array::join([], ""); + RETURN array::join(["hello", "world"], ", "); + RETURN array::join(["again", "again", "again"], " and "); + RETURN array::join([42, 3.14, 2.72, 1.61], " and "); + "#; + let dbs = Datastore::new("memory").await?; + let ses = Session::for_kv().with_ns("test").with_db("test"); + let res = &mut dbs.execute(&sql, &ses, None, false).await?; + assert_eq!(res.len(), 4); + // + let tmp = res.remove(0).result?; + let val = Value::from(""); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::from("hello, world"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::from("again and again and again"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result?; + let val = Value::from("42 and 3.14 and 2.72 and 1.61"); + assert_eq!(tmp, val); + // + Ok(()) +} + #[tokio::test] async fn function_array_len() -> Result<(), Error> { let sql = r#"