use crate::registry::Registry;
use crate::tremor_const_fn;
use simd_json::{prelude::*, BorrowedValue as Value};
pub fn load(registry: &mut Registry) {
registry
.insert(tremor_const_fn! (array::len(_context, _input: Array) {
Ok(Value::from(_input.len() as i64))
}))
.insert(tremor_const_fn! (array::is_empty(_context, _input: Array) {
Ok(Value::from(_input.is_empty()))
}))
.insert(tremor_const_fn! (array::contains(_context, _input, _contains) {
if let Some(input) = _input.as_array() {
Ok(Value::from(input.contains(&_contains)))
} else {
Err(FunctionError::BadType{mfa: mfa("array", "contains", 2)})
}
}))
.insert(tremor_const_fn! (array::push(_context, _input, _value) {
if let Some(input) = _input.as_array() {
let mut output = input.clone();
let v: Value = (*_value).clone();
output.push(v);
Ok(Value::from(output))
} else {
Err(FunctionError::BadType{mfa: mfa("array", "push", 2)})
}
}))
.insert(tremor_const_fn! (array::unzip(_context, _input: Array) {
let r: FResult<Vec<(Value, Value)>> = _input.iter().map(|a| if let Some(a) = a.as_array() {
if a.len() == 2 {
let second: Value = a[0].clone();
let first: Value = a[1].clone();
Ok((first, second))
} else {
Err(FunctionError::RuntimeError{mfa: this_mfa(), error: format!("Onlay arrays that consist of tuples (arrays of two elements) can be unzipped but this array contained {} elements", a.len())})
}
} else {
Err(FunctionError::RuntimeError{mfa: this_mfa(), error: format!("Onlay arrays that consist of tuples (arrays of two elements) can be unzipped but this array contained: {:?}", a)})
}).collect();
let (r, l): (Vec<_>, Vec<_>) = r?.into_iter().unzip();
Ok(Value::from(vec![l,
r,
]))
}))
.insert(tremor_const_fn!(array::zip(_context, _left: Array, _right: Array) {
if _left.len() != _right.len() {
return Err(FunctionError::RuntimeError{mfa: this_mfa(), error: format!("Zipping two arrays requires them to have the same length, but the first array provided has {} elements while the second one has {} elements", _left.len(), _right.len())});
};
Ok(Value::from(_left.iter()
.zip(_right.iter())
.map(|(l, r)| Value::from(vec![l.clone(), r.clone()]))
.collect::<Vec<_>>()))
}))
.insert(
tremor_const_fn!(array::flatten(_context, _input) {
Ok(Value::from(flatten_value(_input)))
}))
.insert(
tremor_const_fn!(array::join(_context, _input: Array, _sep: String) {
let input: Vec<String> = _input.iter().map(ToString::to_string).collect();
Ok(Value::from(input.join(_sep)))
}),
)
.insert(tremor_const_fn!(array::coalesce(_context, _input: Array) {
Ok(Value::from(_input.iter().filter_map(|v| if v.is_null() {
None
}else {
Some(v.clone())
}).collect::<Vec<_>>()))
}));
}
fn flatten_value<'event>(v: &Value<'event>) -> Vec<Value<'event>> {
if let Some(a) = v.as_array() {
a.iter().flat_map(flatten_value).collect()
} else {
vec![v.clone()]
}
}
#[cfg(test)]
mod test {
use crate::registry::fun;
use simd_json::prelude::*;
use simd_json::BorrowedValue as Value;
macro_rules! assert_val {
($e:expr, $r:expr) => {
assert_eq!($e, Ok(Value::from($r)))
};
}
#[test]
fn len() {
let f = fun("array", "len");
let v = Value::from(vec!["this", "is", "a", "test"]);
assert_val!(f(&[&v]), 4);
let v = Value::Array(vec![]);
assert_val!(f(&[&v]), 0);
}
#[test]
fn is_empty() {
let f = fun("array", "is_empty");
let v = Value::from(vec!["this", "is", "a", "test"]);
assert_val!(f(&[&v]), false);
let v = Value::array();
assert_val!(f(&[&v]), true);
}
#[test]
fn contains() {
let f = fun("array", "contains");
let v1 = Value::from(vec!["this", "is", "a", "test"]);
let v2 = Value::from("is");
assert_val!(f(&[&v1, &v2]), true);
}
#[test]
fn join() {
let f = fun("array", "join");
let v1 = Value::from(vec!["this", "is", "a", "cake"]);
let v2 = Value::from(" ");
assert_val!(f(&[&v1, &v2]), Value::from("this is a cake"));
}
#[test]
fn push() {
let f = fun("array", "push");
let v1 = Value::from(vec!["this", "is", "a", "test"]);
let v2 = Value::from("cake");
assert_val!(
f(&[&v1, &v2]),
Value::from(vec!["this", "is", "a", "test", "cake"])
);
}
#[test]
fn zip() {
let f = fun("array", "zip");
let v1 = Value::from(vec!["this", "is", "a", "test"]);
let v2 = Value::from(vec!["cake", "really", "good", "cake"]);
assert_val!(
f(&[&v1, &v2]),
Value::from(vec![
vec!["this", "cake"],
vec!["is", "really"],
vec!["a", "good"],
vec!["test", "cake"],
])
);
}
#[test]
fn unzip() {
let f = fun("array", "unzip");
let v = Value::from(vec![
vec!["this", "cake"],
vec!["is", "really"],
vec!["a", "good"],
vec!["test", "cake"],
]);
assert_val!(
f(&[&v]),
Value::from(vec![
vec!["this", "is", "a", "test"],
vec!["cake", "really", "good", "cake"],
])
);
}
#[test]
fn flatten() {
let f = fun("array", "flatten");
let v = Value::from(vec![
Value::from(vec!["this", "cake"]),
Value::from(vec!["is", "really"]),
Value::from(vec!["a", "good"]),
Value::from(vec!["test", "cake"]),
Value::from("!"),
]);
assert_val!(
f(&[&v]),
Value::from(vec![
"this", "cake", "is", "really", "a", "good", "test", "cake", "!",
])
);
}
#[test]
fn coalesce() {
let f = fun("array", "coalesce");
let v = Value::from(vec![
Value::from("this"),
Value::null(),
Value::from("cake"),
Value::from("is"),
Value::from("really"),
Value::null(),
Value::from("a"),
Value::from("good"),
Value::from("test"),
Value::null(),
Value::from("cake"),
Value::from("!"),
]);
assert_val!(
f(&[&v]),
Value::from(vec![
"this", "cake", "is", "really", "a", "good", "test", "cake", "!",
])
);
}
}