use anyhow::Result;
use reblessive::tree::TreeStack;
use crate::exec::function::{FunctionRegistry, ScalarFunction, Signature};
use crate::exec::physical_expr::EvalContext;
use crate::expr::Kind;
use crate::fnc::args::FromArgs;
use crate::val::Value;
use crate::{define_pure_function, register_functions};
define_pure_function!(ArrayDistinct, "array::distinct", (array: Any) -> Any, crate::fnc::array::distinct);
define_pure_function!(ArrayFirst, "array::first", (array: Any) -> Any, crate::fnc::array::first);
define_pure_function!(ArrayFlatten, "array::flatten", (array: Any) -> Any, crate::fnc::array::flatten);
define_pure_function!(ArrayGroup, "array::group", (array: Any) -> Any, crate::fnc::array::group);
define_pure_function!(ArrayIsEmpty, "array::is_empty", (array: Any) -> Bool, crate::fnc::array::is_empty);
define_pure_function!(ArrayLast, "array::last", (array: Any) -> Any, crate::fnc::array::last);
define_pure_function!(ArrayLen, "array::len", (array: Any) -> Int, crate::fnc::array::len);
define_pure_function!(ArrayMax, "array::max", (array: Any) -> Any, crate::fnc::array::max);
define_pure_function!(ArrayMin, "array::min", (array: Any) -> Any, crate::fnc::array::min);
define_pure_function!(ArrayPop, "array::pop", (array: Any) -> Any, crate::fnc::array::pop);
define_pure_function!(ArrayReverse, "array::reverse", (array: Any) -> Any, crate::fnc::array::reverse);
define_pure_function!(ArrayShuffle, "array::shuffle", (array: Any) -> Any, crate::fnc::array::shuffle);
define_pure_function!(ArraySort, "array::sort", (array: Any) -> Any, crate::fnc::array::sort);
define_pure_function!(ArraySortNatural, "array::sort_natural", (array: Any) -> Any, crate::fnc::array::sort_natural);
define_pure_function!(ArraySortLexical, "array::sort_lexical", (array: Any) -> Any, crate::fnc::array::sort_lexical);
define_pure_function!(ArraySortNaturalLexical, "array::sort_natural_lexical", (array: Any) -> Any, crate::fnc::array::sort_natural_lexical);
define_pure_function!(ArrayTranspose, "array::transpose", (array: Any) -> Any, crate::fnc::array::transpose);
define_pure_function!(ArrayBooleanNot, "array::boolean_not", (array: Any) -> Any, crate::fnc::array::boolean_not);
define_pure_function!(ArrayAdd, "array::add", (array: Any, value: Any) -> Any, crate::fnc::array::add);
define_pure_function!(ArrayAppend, "array::append", (array: Any, value: Any) -> Any, crate::fnc::array::append);
define_pure_function!(ArrayAt, "array::at", (array: Any, index: Int) -> Any, crate::fnc::array::at);
define_pure_function!(ArrayBooleanAnd, "array::boolean_and", (a: Any, b: Any) -> Any, crate::fnc::array::boolean_and);
define_pure_function!(ArrayBooleanOr, "array::boolean_or", (a: Any, b: Any) -> Any, crate::fnc::array::boolean_or);
define_pure_function!(ArrayBooleanXor, "array::boolean_xor", (a: Any, b: Any) -> Any, crate::fnc::array::boolean_xor);
define_pure_function!(ArrayClump, "array::clump", (array: Any, size: Int) -> Any, crate::fnc::array::clump);
define_pure_function!(ArrayCombine, "array::combine", (a: Any, b: Any) -> Any, crate::fnc::array::combine);
define_pure_function!(ArrayComplement, "array::complement", (a: Any, b: Any) -> Any, crate::fnc::array::complement);
define_pure_function!(ArrayConcat, "array::concat", (a: Any, b: Any) -> Any, crate::fnc::array::concat);
define_pure_function!(ArrayDifference, "array::difference", (a: Any, b: Any) -> Any, crate::fnc::array::difference);
define_pure_function!(ArrayIntersect, "array::intersect", (a: Any, b: Any) -> Any, crate::fnc::array::intersect);
define_pure_function!(ArrayJoin, "array::join", (array: Any, separator: String) -> String, crate::fnc::array::join);
define_pure_function!(ArrayLogicalAnd, "array::logical_and", (a: Any, b: Any) -> Any, crate::fnc::array::logical_and);
define_pure_function!(ArrayLogicalOr, "array::logical_or", (a: Any, b: Any) -> Any, crate::fnc::array::logical_or);
define_pure_function!(ArrayLogicalXor, "array::logical_xor", (a: Any, b: Any) -> Any, crate::fnc::array::logical_xor);
define_pure_function!(ArrayMatches, "array::matches", (array: Any, value: Any) -> Any, crate::fnc::array::matches);
define_pure_function!(ArrayPrepend, "array::prepend", (array: Any, value: Any) -> Any, crate::fnc::array::prepend);
define_pure_function!(ArrayPush, "array::push", (array: Any, value: Any) -> Any, crate::fnc::array::push);
define_pure_function!(ArrayRemove, "array::remove", (array: Any, index: Int) -> Any, crate::fnc::array::remove);
define_pure_function!(ArrayRepeat, "array::repeat", (value: Any, count: Int) -> Any, crate::fnc::array::repeat);
define_pure_function!(ArrayUnion, "array::union", (a: Any, b: Any) -> Any, crate::fnc::array::union);
define_pure_function!(ArrayWindows, "array::windows", (array: Any, size: Int) -> Any, crate::fnc::array::windows);
define_pure_function!(ArraySequence, "array::sequence", (start: Int, end: Int) -> Any, crate::fnc::array::sequence);
define_pure_function!(ArrayFill, "array::fill", (array: Any, value: Any, ?index: Int) -> Any, crate::fnc::array::fill);
define_pure_function!(ArrayInsert, "array::insert", (array: Any, value: Any, index: Int) -> Any, crate::fnc::array::insert);
define_pure_function!(ArrayRange, "array::range", (array: Any, start: Int, end: Int) -> Any, crate::fnc::array::range);
define_pure_function!(ArraySlice, "array::slice", (array: Any, start: Int, ?length: Int) -> Any, crate::fnc::array::slice);
define_pure_function!(ArraySwap, "array::swap", (array: Any, i: Int, j: Int) -> Any, crate::fnc::array::swap);
define_pure_function!(ArraySortAsc, "array::sort::asc", (array: Any) -> Any, crate::fnc::array::sort::asc);
define_pure_function!(ArraySortDesc, "array::sort::desc", (array: Any) -> Any, crate::fnc::array::sort::desc);
macro_rules! define_array_closure_function {
($struct_name:ident, $func_name:literal, $impl_path:path, $($arg:ident: $kind:ident),+ => $ret:ident) => {
#[derive(Debug, Clone, Copy, Default)]
pub struct $struct_name;
impl ScalarFunction for $struct_name {
fn name(&self) -> &'static str {
$func_name
}
fn signature(&self) -> Signature {
Signature::new()
$(.arg(stringify!($arg), Kind::$kind))+
.returns(Kind::$ret)
}
fn is_pure(&self) -> bool {
false
}
fn is_async(&self) -> bool {
true
}
fn invoke(&self, _args: Vec<Value>) -> Result<Value> {
Err(anyhow::anyhow!("Function '{}' requires async execution", self.name()))
}
fn invoke_async<'a>(
&'a self,
ctx: &'a EvalContext<'_>,
args: Vec<Value>,
) -> crate::exec::BoxFut<'a, Result<Value>> {
Box::pin(async move {
use crate::doc::CursorDoc;
let args = FromArgs::from_args($func_name, args)?;
let frozen = ctx.exec_ctx.ctx();
let opt = ctx.exec_ctx.options();
let doc = ctx.document_root.or(ctx.current_value)
.map(|v| CursorDoc::new(None, None, v.clone()));
let mut stack = TreeStack::new();
stack
.enter(|stk| async move {
$impl_path((stk, frozen, opt, doc.as_ref()), args).await
})
.finish()
.await
})
}
}
};
}
define_array_closure_function!(ArrayAll, "array::all", crate::fnc::array::all, array: Any, check: Any => Any);
define_array_closure_function!(ArrayAny, "array::any", crate::fnc::array::any, array: Any, check: Any => Any);
define_array_closure_function!(ArrayFilter, "array::filter", crate::fnc::array::filter, array: Any, check: Any => Any);
define_array_closure_function!(ArrayFilterIndex, "array::filter_index", crate::fnc::array::filter_index, array: Any, check: Any => Any);
define_array_closure_function!(ArrayFind, "array::find", crate::fnc::array::find, array: Any, check: Any => Any);
define_array_closure_function!(ArrayFindIndex, "array::find_index", crate::fnc::array::find_index, array: Any, check: Any => Any);
define_array_closure_function!(ArrayFold, "array::fold", crate::fnc::array::fold, array: Any, init: Any, mapper: Any => Any);
define_array_closure_function!(ArrayMap, "array::map", crate::fnc::array::map, array: Any, mapper: Any => Any);
define_array_closure_function!(ArrayReduce, "array::reduce", crate::fnc::array::reduce, array: Any, mapper: Any => Any);
pub fn register(registry: &mut FunctionRegistry) {
register_functions!(
registry,
ArrayAdd,
ArrayAppend,
ArrayAt,
ArrayBooleanAnd,
ArrayBooleanNot,
ArrayBooleanOr,
ArrayBooleanXor,
ArrayClump,
ArrayCombine,
ArrayComplement,
ArrayConcat,
ArrayDifference,
ArrayDistinct,
ArrayFill,
ArrayFirst,
ArrayFlatten,
ArrayGroup,
ArrayInsert,
ArrayIntersect,
ArrayIsEmpty,
ArrayJoin,
ArrayLast,
ArrayLen,
ArrayLogicalAnd,
ArrayLogicalOr,
ArrayLogicalXor,
ArrayMatches,
ArrayMax,
ArrayMin,
ArrayPop,
ArrayPrepend,
ArrayPush,
ArrayRange,
ArrayRemove,
ArrayRepeat,
ArrayReverse,
ArraySequence,
ArrayShuffle,
ArraySlice,
ArraySort,
ArraySortAsc,
ArraySortDesc,
ArraySortNatural,
ArraySortLexical,
ArraySortNaturalLexical,
ArraySwap,
ArrayTranspose,
ArrayUnion,
ArrayWindows,
);
registry.register(ArrayAll);
registry.register(ArrayAny);
registry.register(ArrayFilter);
registry.register(ArrayFilterIndex);
registry.register(ArrayFind);
registry.register(ArrayFindIndex);
registry.register(ArrayFold);
registry.register(ArrayMap);
registry.register(ArrayReduce);
}