Add first, last functions to array (#2285)

This commit is contained in:
hchockarprasad 2023-07-19 19:53:07 +05:30 committed by GitHub
parent 87dee375a8
commit eef9b755cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 103 additions and 1 deletions

View file

@ -163,11 +163,13 @@
"array::distinct("
"array::filter_index("
"array::find_index("
"array::first("
"array::flatten("
"array::group("
"array::insert("
"array::intersect("
"array::join("
"array::last("
"array::len("
"array::logical_and("
"array::logical_or("

View file

@ -163,11 +163,13 @@
"array::distinct("
"array::filter_index("
"array::find_index("
"array::first("
"array::flatten("
"array::group("
"array::insert("
"array::intersect("
"array::join("
"array::last("
"array::len("
"array::logical_and("
"array::logical_or("

View file

@ -136,6 +136,14 @@ pub fn find_index((array, value): (Array, Value)) -> Result<Value, Error> {
.map_or(Value::Null, |(i, _v)| i.into()))
}
pub fn first((array,): (Array,)) -> Result<Value, Error> {
if let [first, ..] = &array[0..] {
Ok(first.to_owned())
} else {
Ok(Value::None)
}
}
pub fn flatten((array,): (Array,)) -> Result<Value, Error> {
Ok(array.flatten().into())
}
@ -175,6 +183,14 @@ pub fn join((arr, sep): (Array, String)) -> Result<Value, Error> {
Ok(arr.into_iter().map(Value::as_raw_string).collect::<Vec<_>>().join(&sep).into())
}
pub fn last((array,): (Array,)) -> Result<Value, Error> {
if let [.., last] = &array[0..] {
Ok(last.to_owned())
} else {
Ok(Value::None)
}
}
pub fn len((array,): (Array,)) -> Result<Value, Error> {
Ok(array.len().into())
}
@ -375,7 +391,7 @@ pub mod sort {
#[cfg(test)]
mod tests {
use super::{join, slice};
use super::{first, join, last, slice};
use crate::sql::{Array, Value};
#[test]
@ -419,4 +435,24 @@ mod tests {
"3.56f is not 2.72f is not 1.61f",
);
}
#[test]
fn array_first() {
fn test(arr: Array, expected: Value) {
assert_eq!(first((arr,)).unwrap(), expected);
}
test(vec!["hello", "world"].into(), "hello".into());
test(Array::new(), Value::None);
}
#[test]
fn array_last() {
fn test(arr: Array, expected: Value) {
assert_eq!(last((arr,)).unwrap(), expected);
}
test(vec!["hello", "world"].into(), "world".into());
test(Array::new(), Value::None);
}
}

View file

@ -94,11 +94,13 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
"array::distinct" => array::distinct,
"array::filter_index" => array::filter_index,
"array::find_index" => array::find_index,
"array::first" => array::first,
"array::flatten" => array::flatten,
"array::group" => array::group,
"array::insert" => array::insert,
"array::intersect" => array::intersect,
"array::join" => array::join,
"array::last" => array::last,
"array::len" => array::len,
"array::logical_and" => array::logical_and,
"array::logical_or" => array::logical_or,

View file

@ -23,11 +23,13 @@ impl_module_def!(
"distinct" => run,
"filter_index" => run,
"find_index" => run,
"first" => run,
"flatten" => run,
"group" => run,
"insert" => run,
"intersect" => run,
"join" => run,
"last" => run,
"len" => run,
"logical_and" => run,
"logical_or" => run,

View file

@ -104,7 +104,9 @@ impl Function {
pub fn is_aggregate(&self) -> bool {
match self {
Self::Normal(f, _) if f == "array::distinct" => true,
Self::Normal(f, _) if f == "array::first" => true,
Self::Normal(f, _) if f == "array::group" => true,
Self::Normal(f, _) if f == "array::last" => true,
Self::Normal(f, _) if f == "count" => true,
Self::Normal(f, _) if f == "math::bottom" => true,
Self::Normal(f, _) if f == "math::interquartile" => true,
@ -291,6 +293,7 @@ fn function_array(i: &str) -> IResult<&str, &str> {
tag("distinct"),
tag("filter_index"),
tag("find_index"),
tag("first"),
tag("flatten"),
tag("group"),
tag("insert"),
@ -298,6 +301,7 @@ fn function_array(i: &str) -> IResult<&str, &str> {
alt((
tag("intersect"),
tag("join"),
tag("last"),
tag("len"),
tag("logical_and"),
tag("logical_or"),

View file

@ -450,6 +450,33 @@ RETURN array::find_index([0, 1, 2], 3);"#;
Ok(())
}
#[tokio::test]
async fn function_array_first() -> Result<(), Error> {
let sql = r#"
RETURN array::first(["hello", "world"]);
RETURN array::first([["hello", "world"], 10]);
RETURN array::first([]);
"#;
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).await?;
assert_eq!(res.len(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::Strand("hello".into());
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::Array(vec!["hello", "world"].into());
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn function_array_flatten() -> Result<(), Error> {
let sql = r#"
@ -615,6 +642,33 @@ async fn function_string_join_arr() -> Result<(), Error> {
Ok(())
}
#[tokio::test]
async fn function_array_last() -> Result<(), Error> {
let sql = r#"
RETURN array::last(["hello", "world"]);
RETURN array::last([["hello", "world"], 10]);
RETURN array::last([]);
"#;
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).await?;
assert_eq!(res.len(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::Strand("world".into());
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = 10.into();
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn function_array_len() -> Result<(), Error> {
let sql = r#"