Add SQL array::all(), array::any(), array::min(), and array::max() functions

Closes #1588
This commit is contained in:
Tobie Morgan Hitchcock 2023-01-15 09:48:20 +00:00
parent 8f89f8729c
commit 3a1294029e
4 changed files with 144 additions and 0 deletions

View file

@ -9,6 +9,20 @@ use crate::sql::array::Union;
use crate::sql::array::Uniq; use crate::sql::array::Uniq;
use crate::sql::value::Value; use crate::sql::value::Value;
pub fn all((arg,): (Value,)) -> Result<Value, Error> {
match arg {
Value::Array(v) => Ok(v.iter().all(Value::is_truthy).into()),
_ => Ok(Value::False),
}
}
pub fn any((arg,): (Value,)) -> Result<Value, Error> {
match arg {
Value::Array(v) => Ok(v.iter().any(Value::is_truthy).into()),
_ => Ok(Value::False),
}
}
pub fn combine(arrays: (Value, Value)) -> Result<Value, Error> { pub fn combine(arrays: (Value, Value)) -> Result<Value, Error> {
Ok(match arrays { Ok(match arrays {
(Value::Array(v), Value::Array(w)) => v.combine(w).into(), (Value::Array(v), Value::Array(w)) => v.combine(w).into(),
@ -96,6 +110,20 @@ pub fn len((arg,): (Value,)) -> Result<Value, Error> {
} }
} }
pub fn max((arg,): (Value,)) -> Result<Value, Error> {
match arg {
Value::Array(v) => Ok(v.into_iter().max().unwrap_or(Value::None)),
_ => Ok(Value::None),
}
}
pub fn min((arg,): (Value,)) -> Result<Value, Error> {
match arg {
Value::Array(v) => Ok(v.into_iter().min().unwrap_or(Value::None)),
_ => Ok(Value::None),
}
}
pub fn sort((array, order): (Value, Option<Value>)) -> Result<Value, Error> { pub fn sort((array, order): (Value, Option<Value>)) -> Result<Value, Error> {
match array { match array {
Value::Array(mut v) => match order { Value::Array(mut v) => match order {

View file

@ -60,6 +60,8 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
dispatch!( dispatch!(
name, name,
args, args,
"array::all" => array::all,
"array::any" => array::any,
"array::combine" => array::combine, "array::combine" => array::combine,
"array::complement" => array::complement, "array::complement" => array::complement,
"array::concat" => array::concat, "array::concat" => array::concat,
@ -70,6 +72,8 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
"array::insert" => array::insert, "array::insert" => array::insert,
"array::intersect" => array::intersect, "array::intersect" => array::intersect,
"array::len" => array::len, "array::len" => array::len,
"array::max" => array::max,
"array::min" => array::min,
"array::sort" => array::sort, "array::sort" => array::sort,
"array::union" => array::union, "array::union" => array::union,
"array::sort::asc" => array::sort::asc, "array::sort::asc" => array::sort::asc,

View file

@ -234,6 +234,8 @@ fn function_names(i: &str) -> IResult<&str, &str> {
fn function_array(i: &str) -> IResult<&str, &str> { fn function_array(i: &str) -> IResult<&str, &str> {
alt(( alt((
tag("array::all"),
tag("array::any"),
tag("array::combine"), tag("array::combine"),
tag("array::complement"), tag("array::complement"),
tag("array::concat"), tag("array::concat"),
@ -244,6 +246,8 @@ fn function_array(i: &str) -> IResult<&str, &str> {
tag("array::insert"), tag("array::insert"),
tag("array::intersect"), tag("array::intersect"),
tag("array::len"), tag("array::len"),
tag("array::max"),
tag("array::min"),
tag("array::sort::asc"), tag("array::sort::asc"),
tag("array::sort::desc"), tag("array::sort::desc"),
tag("array::sort"), tag("array::sort"),

View file

@ -5,6 +5,60 @@ use surrealdb::err::Error;
use surrealdb::kvs::Datastore; use surrealdb::kvs::Datastore;
use surrealdb::sql::Value; use surrealdb::sql::Value;
#[tokio::test]
async fn function_array_all() -> Result<(), Error> {
let sql = r#"
RETURN array::all([]);
RETURN array::all("some text");
RETURN array::all([1,2,"text",3,NONE,3,4]);
"#;
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(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::True;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::False;
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn function_array_any() -> Result<(), Error> {
let sql = r#"
RETURN array::any([]);
RETURN array::any("some text");
RETURN array::any([1,2,"text",3,NONE,3,4]);
"#;
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(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::True;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::True;
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test] #[tokio::test]
async fn function_array_combine() -> Result<(), Error> { async fn function_array_combine() -> Result<(), Error> {
let sql = r#" let sql = r#"
@ -253,6 +307,60 @@ async fn function_array_intersect() -> Result<(), Error> {
Ok(()) Ok(())
} }
#[tokio::test]
async fn function_array_max() -> Result<(), Error> {
let sql = r#"
RETURN array::max([]);
RETURN array::max("some text");
RETURN array::max([1,2,"text",3,3,4]);
"#;
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(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("4");
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn function_array_min() -> Result<(), Error> {
let sql = r#"
RETURN array::min([]);
RETURN array::min("some text");
RETURN array::min([1,2,"text",3,3,4]);
"#;
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(), 3);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("1");
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test] #[tokio::test]
async fn function_array_union() -> Result<(), Error> { async fn function_array_union() -> Result<(), Error> {
let sql = r#" let sql = r#"