2022-05-14 12:35:08 +00:00
|
|
|
use crate::ctx::Context;
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::dbs::Options;
|
2022-02-15 01:00:30 +00:00
|
|
|
use crate::dbs::Transaction;
|
2021-03-29 15:43:37 +00:00
|
|
|
use crate::err::Error;
|
|
|
|
use crate::fnc;
|
2020-06-29 15:36:01 +00:00
|
|
|
use crate::sql::comment::mightbespace;
|
|
|
|
use crate::sql::common::commas;
|
2023-03-25 19:44:03 +00:00
|
|
|
use crate::sql::common::val_char;
|
2022-01-16 20:31:50 +00:00
|
|
|
use crate::sql::error::IResult;
|
2022-10-04 21:51:18 +00:00
|
|
|
use crate::sql::fmt::Fmt;
|
2023-03-25 19:44:03 +00:00
|
|
|
use crate::sql::idiom::Idiom;
|
2022-06-27 15:57:11 +00:00
|
|
|
use crate::sql::script::{script as func, Script};
|
2023-03-30 10:41:44 +00:00
|
|
|
use crate::sql::serde::is_internal_serialization;
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::value::{single, value, Value};
|
2023-03-25 19:44:03 +00:00
|
|
|
use async_recursion::async_recursion;
|
2023-02-12 12:18:47 +00:00
|
|
|
use futures::future::try_join_all;
|
2020-06-29 15:36:01 +00:00
|
|
|
use nom::branch::alt;
|
|
|
|
use nom::bytes::complete::tag;
|
2023-03-25 19:44:03 +00:00
|
|
|
use nom::bytes::complete::take_while1;
|
2022-03-16 23:52:25 +00:00
|
|
|
use nom::character::complete::char;
|
2021-03-29 15:43:37 +00:00
|
|
|
use nom::multi::separated_list0;
|
2023-03-30 10:41:44 +00:00
|
|
|
use serde::ser::SerializeTupleVariant;
|
2020-06-29 15:36:01 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-03-29 15:43:37 +00:00
|
|
|
use std::cmp::Ordering;
|
2020-06-29 15:36:01 +00:00
|
|
|
use std::fmt;
|
|
|
|
|
2023-03-30 10:41:44 +00:00
|
|
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Function";
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Hash)]
|
2021-03-29 15:43:37 +00:00
|
|
|
pub enum Function {
|
2022-01-13 17:36:41 +00:00
|
|
|
Cast(String, Value),
|
|
|
|
Normal(String, Vec<Value>),
|
2023-03-25 19:44:03 +00:00
|
|
|
Custom(String, Vec<Value>),
|
2022-06-27 15:57:11 +00:00
|
|
|
Script(Script, Vec<Value>),
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for Function {
|
|
|
|
#[inline]
|
|
|
|
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
|
2022-03-23 11:56:39 +00:00
|
|
|
None
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-03-25 18:43:22 +00:00
|
|
|
impl Function {
|
2022-11-23 09:42:59 +00:00
|
|
|
/// Get function name if applicable
|
2022-07-16 22:23:13 +00:00
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(n, _) => n.as_str(),
|
2023-03-25 19:44:03 +00:00
|
|
|
Self::Custom(n, _) => n.as_str(),
|
2022-07-16 22:23:13 +00:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2022-11-23 09:42:59 +00:00
|
|
|
/// Get function arguments if applicable
|
2022-03-25 18:43:22 +00:00
|
|
|
pub fn args(&self) -> &[Value] {
|
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(_, a) => a,
|
2023-03-25 19:44:03 +00:00
|
|
|
Self::Custom(_, a) => a,
|
2022-03-25 18:43:22 +00:00
|
|
|
_ => &[],
|
|
|
|
}
|
|
|
|
}
|
2023-03-25 19:44:03 +00:00
|
|
|
/// Convert function call to a field name
|
|
|
|
pub fn to_idiom(&self) -> Idiom {
|
|
|
|
match self {
|
|
|
|
Self::Script(_, _) => "function".to_string().into(),
|
|
|
|
Self::Normal(f, _) => f.to_owned().into(),
|
|
|
|
Self::Custom(f, _) => format!("fn::{f}").into(),
|
|
|
|
Self::Cast(_, v) => v.to_idiom(),
|
|
|
|
}
|
|
|
|
}
|
2022-11-23 09:42:59 +00:00
|
|
|
/// Convert this function to an aggregate
|
2022-10-04 21:51:18 +00:00
|
|
|
pub fn aggregate(&self, val: Value) -> Self {
|
2022-03-25 18:43:22 +00:00
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(n, a) => {
|
2022-03-25 18:43:22 +00:00
|
|
|
let mut a = a.to_owned();
|
|
|
|
match a.len() {
|
|
|
|
0 => a.insert(0, val),
|
|
|
|
_ => {
|
|
|
|
a.remove(0);
|
|
|
|
a.insert(0, val);
|
|
|
|
}
|
|
|
|
}
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(n.to_owned(), a)
|
2022-03-25 18:43:22 +00:00
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
2022-11-23 09:42:59 +00:00
|
|
|
/// Check if this function is a rolling function
|
2022-03-25 18:43:22 +00:00
|
|
|
pub fn is_rolling(&self) -> bool {
|
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(f, _) if f == "count" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::max" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::mean" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::min" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::sum" => true,
|
2022-03-25 18:43:22 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
2022-11-23 09:42:59 +00:00
|
|
|
/// Check if this function is a grouping function
|
2022-03-25 18:43:22 +00:00
|
|
|
pub fn is_aggregate(&self) -> bool {
|
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(f, _) if f == "array::distinct" => true,
|
2023-01-07 19:40:56 +00:00
|
|
|
Self::Normal(f, _) if f == "array::group" => true,
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(f, _) if f == "count" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::bottom" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::interquartile" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::max" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::mean" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::median" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::midhinge" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::min" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::mode" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::nearestrank" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::percentile" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::sample" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::spread" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::stddev" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::sum" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::top" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::trimean" => true,
|
|
|
|
Self::Normal(f, _) if f == "math::variance" => true,
|
2022-03-25 18:43:22 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 08:12:56 +00:00
|
|
|
impl Function {
|
2023-03-25 19:44:03 +00:00
|
|
|
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
|
|
|
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
2022-05-01 22:25:53 +00:00
|
|
|
pub(crate) async fn compute(
|
2021-03-29 15:43:37 +00:00
|
|
|
&self,
|
2022-05-14 12:35:08 +00:00
|
|
|
ctx: &Context<'_>,
|
2022-02-06 21:06:52 +00:00
|
|
|
opt: &Options,
|
2022-02-15 03:33:16 +00:00
|
|
|
txn: &Transaction,
|
2023-03-25 19:44:03 +00:00
|
|
|
doc: Option<&'async_recursion Value>,
|
2022-01-13 17:36:41 +00:00
|
|
|
) -> Result<Value, Error> {
|
2022-10-06 16:35:03 +00:00
|
|
|
// Prevent long function chains
|
|
|
|
let opt = &opt.dive(1)?;
|
2022-12-22 08:33:57 +00:00
|
|
|
// Ensure futures are run
|
|
|
|
let opt = &opt.futures(true);
|
2022-10-06 16:35:03 +00:00
|
|
|
// Process the function type
|
2021-03-29 15:43:37 +00:00
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Cast(s, x) => {
|
2023-02-12 12:18:47 +00:00
|
|
|
// Compute the value to be cast
|
|
|
|
let a = x.compute(ctx, opt, txn, doc).await?;
|
|
|
|
// Run the cast function
|
|
|
|
fnc::cast::run(ctx, s, a)
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Normal(s, x) => {
|
2023-02-12 12:18:47 +00:00
|
|
|
// Compute the function arguments
|
|
|
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
|
|
|
// Run the normal function
|
2022-01-19 12:51:28 +00:00
|
|
|
fnc::run(ctx, s, a).await
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
2023-03-25 19:44:03 +00:00
|
|
|
Self::Custom(s, x) => {
|
|
|
|
// Get the function definition
|
|
|
|
let val = {
|
|
|
|
// Clone transaction
|
|
|
|
let run = txn.clone();
|
|
|
|
// Claim transaction
|
|
|
|
let mut run = run.lock().await;
|
|
|
|
// Get the function definition
|
|
|
|
run.get_fc(opt.ns(), opt.db(), s).await?
|
|
|
|
};
|
|
|
|
// Check the function arguments
|
|
|
|
if x.len() != val.args.len() {
|
|
|
|
return Err(Error::InvalidArguments {
|
|
|
|
name: format!("fn::{}", val.name),
|
|
|
|
message: match val.args.len() {
|
|
|
|
1 => String::from("The function expects 1 argument."),
|
|
|
|
l => format!("The function expects {l} arguments."),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// Compute the function arguments
|
|
|
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
|
|
|
// Duplicate context
|
|
|
|
let mut ctx = Context::new(ctx);
|
|
|
|
// Process the function arguments
|
|
|
|
for (val, (name, kind)) in a.into_iter().zip(val.args) {
|
|
|
|
ctx.add_value(
|
|
|
|
name.to_raw(),
|
|
|
|
match val {
|
|
|
|
Value::None => val,
|
|
|
|
Value::Null => val,
|
|
|
|
_ => val.convert_to(&kind),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
// Run the custom function
|
|
|
|
val.block.compute(&ctx, opt, txn, doc).await
|
|
|
|
}
|
2022-07-03 09:43:23 +00:00
|
|
|
#[allow(unused_variables)]
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Script(s, x) => {
|
2022-07-03 09:43:23 +00:00
|
|
|
#[cfg(feature = "scripting")]
|
|
|
|
{
|
2023-02-12 12:18:47 +00:00
|
|
|
// Compute the function arguments
|
|
|
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
|
|
|
// Run the script function
|
|
|
|
fnc::script::run(ctx, opt, txn, doc, s, a).await
|
2022-07-03 09:43:23 +00:00
|
|
|
}
|
|
|
|
#[cfg(not(feature = "scripting"))]
|
|
|
|
{
|
2022-06-27 15:57:11 +00:00
|
|
|
Err(Error::InvalidScript {
|
|
|
|
message: String::from("Embedded functions are not enabled."),
|
|
|
|
})
|
2022-05-20 21:16:25 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 08:12:56 +00:00
|
|
|
impl fmt::Display for Function {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2023-03-25 19:44:03 +00:00
|
|
|
Self::Cast(s, e) => write!(f, "<{s}> {e}"),
|
|
|
|
Self::Normal(s, e) => write!(f, "{s}({})", Fmt::comma_separated(e)),
|
|
|
|
Self::Custom(s, e) => write!(f, "fn::{s}({})", Fmt::comma_separated(e)),
|
|
|
|
Self::Script(s, e) => write!(f, "function({}) {{{s}}}", Fmt::comma_separated(e)),
|
2022-01-14 08:12:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-30 10:41:44 +00:00
|
|
|
impl Serialize for Function {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::Serializer,
|
|
|
|
{
|
|
|
|
if is_internal_serialization() {
|
|
|
|
match self {
|
|
|
|
Self::Cast(s, e) => {
|
|
|
|
let mut serializer = serializer.serialize_tuple_variant(TOKEN, 0, "Cast", 2)?;
|
|
|
|
serializer.serialize_field(s)?;
|
|
|
|
serializer.serialize_field(e)?;
|
|
|
|
serializer.end()
|
|
|
|
}
|
|
|
|
Self::Normal(s, e) => {
|
|
|
|
let mut serializer =
|
|
|
|
serializer.serialize_tuple_variant(TOKEN, 1, "Normal", 2)?;
|
|
|
|
serializer.serialize_field(s)?;
|
|
|
|
serializer.serialize_field(e)?;
|
|
|
|
serializer.end()
|
|
|
|
}
|
|
|
|
Self::Custom(s, e) => {
|
|
|
|
let mut serializer =
|
|
|
|
serializer.serialize_tuple_variant(TOKEN, 2, "Custom", 2)?;
|
|
|
|
serializer.serialize_field(s)?;
|
|
|
|
serializer.serialize_field(e)?;
|
|
|
|
serializer.end()
|
|
|
|
}
|
|
|
|
Self::Script(s, e) => {
|
|
|
|
let mut serializer =
|
|
|
|
serializer.serialize_tuple_variant(TOKEN, 3, "Script", 2)?;
|
|
|
|
serializer.serialize_field(s)?;
|
|
|
|
serializer.serialize_field(e)?;
|
|
|
|
serializer.end()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
serializer.serialize_none()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
pub fn function(i: &str) -> IResult<&str, Function> {
|
2023-03-25 19:44:03 +00:00
|
|
|
alt((normal, custom, script, cast))(i)
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
|
|
|
|
2023-03-31 15:42:29 +00:00
|
|
|
pub fn normal(i: &str) -> IResult<&str, Function> {
|
2022-06-27 15:57:11 +00:00
|
|
|
let (i, s) = function_names(i)?;
|
|
|
|
let (i, _) = char('(')(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, a) = separated_list0(commas, value)(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = char(')')(i)?;
|
|
|
|
Ok((i, Function::Normal(s.to_string(), a)))
|
|
|
|
}
|
|
|
|
|
2023-03-31 15:42:29 +00:00
|
|
|
pub fn custom(i: &str) -> IResult<&str, Function> {
|
2023-03-25 19:44:03 +00:00
|
|
|
let (i, _) = tag("fn::")(i)?;
|
|
|
|
let (i, s) = take_while1(val_char)(i)?;
|
|
|
|
let (i, _) = char('(')(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, a) = separated_list0(commas, value)(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = char(')')(i)?;
|
|
|
|
Ok((i, Function::Custom(s.to_string(), a)))
|
|
|
|
}
|
|
|
|
|
2022-06-27 15:57:11 +00:00
|
|
|
fn script(i: &str) -> IResult<&str, Function> {
|
2023-03-30 14:19:18 +00:00
|
|
|
let (i, _) = tag("function")(i)?;
|
2022-01-13 17:36:41 +00:00
|
|
|
let (i, _) = mightbespace(i)?;
|
2022-06-27 15:57:11 +00:00
|
|
|
let (i, _) = tag("(")(i)?;
|
2022-12-17 16:23:20 +00:00
|
|
|
let (i, _) = mightbespace(i)?;
|
2022-06-27 15:57:11 +00:00
|
|
|
let (i, a) = separated_list0(commas, value)(i)?;
|
2022-12-17 16:23:20 +00:00
|
|
|
let (i, _) = mightbespace(i)?;
|
2022-06-27 15:57:11 +00:00
|
|
|
let (i, _) = tag(")")(i)?;
|
2022-01-13 17:36:41 +00:00
|
|
|
let (i, _) = mightbespace(i)?;
|
2022-06-27 15:57:11 +00:00
|
|
|
let (i, _) = char('{')(i)?;
|
|
|
|
let (i, v) = func(i)?;
|
2022-03-16 23:52:25 +00:00
|
|
|
let (i, _) = char('}')(i)?;
|
2022-06-27 15:57:11 +00:00
|
|
|
Ok((i, Function::Script(v, a)))
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 15:57:11 +00:00
|
|
|
fn cast(i: &str) -> IResult<&str, Function> {
|
2022-03-16 23:52:25 +00:00
|
|
|
let (i, _) = char('<')(i)?;
|
2021-03-29 15:43:37 +00:00
|
|
|
let (i, s) = function_casts(i)?;
|
2022-03-16 23:52:25 +00:00
|
|
|
let (i, _) = char('>')(i)?;
|
2021-03-29 15:43:37 +00:00
|
|
|
let (i, _) = mightbespace(i)?;
|
2021-05-22 18:21:59 +00:00
|
|
|
let (i, v) = single(i)?;
|
2021-03-29 15:43:37 +00:00
|
|
|
Ok((i, Function::Cast(s.to_string(), v)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_casts(i: &str) -> IResult<&str, &str> {
|
|
|
|
alt((
|
|
|
|
tag("bool"),
|
|
|
|
tag("datetime"),
|
2023-03-18 20:08:06 +00:00
|
|
|
tag("decimal"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("duration"),
|
2023-03-18 20:08:06 +00:00
|
|
|
tag("float"),
|
|
|
|
tag("int"),
|
|
|
|
tag("number"),
|
|
|
|
tag("string"),
|
2021-03-29 15:43:37 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_names(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
|
|
|
function_array,
|
|
|
|
function_count,
|
2022-01-13 17:36:41 +00:00
|
|
|
function_crypto,
|
2022-09-22 23:48:49 +00:00
|
|
|
function_duration,
|
2020-06-29 15:36:01 +00:00
|
|
|
function_geo,
|
|
|
|
function_http,
|
|
|
|
function_is,
|
|
|
|
function_math,
|
2022-09-19 02:56:59 +00:00
|
|
|
function_meta,
|
2022-12-30 09:34:46 +00:00
|
|
|
function_not,
|
2020-06-29 15:36:01 +00:00
|
|
|
function_parse,
|
|
|
|
function_rand,
|
2022-08-17 14:09:08 +00:00
|
|
|
function_session,
|
2023-03-10 15:24:27 +00:00
|
|
|
function_sleep,
|
2020-06-29 15:36:01 +00:00
|
|
|
function_string,
|
|
|
|
function_time,
|
|
|
|
function_type,
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_array(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2023-03-25 22:35:55 +00:00
|
|
|
alt((
|
2023-03-26 07:53:19 +00:00
|
|
|
tag("array::add"),
|
2023-03-25 22:35:55 +00:00
|
|
|
tag("array::all"),
|
|
|
|
tag("array::any"),
|
|
|
|
tag("array::append"),
|
|
|
|
tag("array::combine"),
|
|
|
|
tag("array::complement"),
|
|
|
|
tag("array::concat"),
|
|
|
|
tag("array::difference"),
|
|
|
|
tag("array::distinct"),
|
|
|
|
tag("array::flatten"),
|
|
|
|
tag("array::group"),
|
|
|
|
tag("array::insert"),
|
|
|
|
)),
|
|
|
|
alt((
|
|
|
|
tag("array::intersect"),
|
|
|
|
tag("array::len"),
|
|
|
|
tag("array::max"),
|
|
|
|
tag("array::min"),
|
|
|
|
tag("array::pop"),
|
|
|
|
tag("array::prepend"),
|
|
|
|
tag("array::push"),
|
|
|
|
tag("array::remove"),
|
|
|
|
tag("array::reverse"),
|
|
|
|
tag("array::sort::asc"),
|
|
|
|
tag("array::sort::desc"),
|
|
|
|
tag("array::sort"),
|
|
|
|
tag("array::union"),
|
|
|
|
)),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_count(i: &str) -> IResult<&str, &str> {
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("count")(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_crypto(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("crypto::argon2::compare"),
|
|
|
|
tag("crypto::argon2::generate"),
|
2022-09-20 07:14:58 +00:00
|
|
|
tag("crypto::bcrypt::compare"),
|
|
|
|
tag("crypto::bcrypt::generate"),
|
2022-08-11 15:16:42 +00:00
|
|
|
tag("crypto::md5"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("crypto::pbkdf2::compare"),
|
|
|
|
tag("crypto::pbkdf2::generate"),
|
|
|
|
tag("crypto::scrypt::compare"),
|
|
|
|
tag("crypto::scrypt::generate"),
|
2022-08-11 15:16:42 +00:00
|
|
|
tag("crypto::sha1"),
|
|
|
|
tag("crypto::sha256"),
|
|
|
|
tag("crypto::sha512"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2022-09-22 23:48:49 +00:00
|
|
|
fn function_duration(i: &str) -> IResult<&str, &str> {
|
|
|
|
alt((
|
|
|
|
tag("duration::days"),
|
|
|
|
tag("duration::hours"),
|
|
|
|
tag("duration::mins"),
|
|
|
|
tag("duration::secs"),
|
|
|
|
tag("duration::weeks"),
|
|
|
|
tag("duration::years"),
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_geo(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-05-17 16:59:50 +00:00
|
|
|
tag("geo::area"),
|
|
|
|
tag("geo::bearing"),
|
|
|
|
tag("geo::centroid"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("geo::distance"),
|
|
|
|
tag("geo::hash::decode"),
|
|
|
|
tag("geo::hash::encode"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_http(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("http::head"),
|
|
|
|
tag("http::get"),
|
|
|
|
tag("http::put"),
|
|
|
|
tag("http::post"),
|
|
|
|
tag("http::patch"),
|
|
|
|
tag("http::delete"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_is(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("is::alphanum"),
|
|
|
|
tag("is::alpha"),
|
|
|
|
tag("is::ascii"),
|
2023-01-09 09:48:46 +00:00
|
|
|
tag("is::datetime"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("is::domain"),
|
|
|
|
tag("is::email"),
|
|
|
|
tag("is::hexadecimal"),
|
|
|
|
tag("is::latitude"),
|
|
|
|
tag("is::longitude"),
|
|
|
|
tag("is::numeric"),
|
|
|
|
tag("is::semver"),
|
2022-11-02 10:37:36 +00:00
|
|
|
tag("is::url"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("is::uuid"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_math(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("math::abs"),
|
|
|
|
tag("math::bottom"),
|
|
|
|
tag("math::ceil"),
|
|
|
|
tag("math::fixed"),
|
|
|
|
tag("math::floor"),
|
|
|
|
tag("math::interquartile"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("math::max"),
|
|
|
|
tag("math::mean"),
|
|
|
|
tag("math::median"),
|
|
|
|
tag("math::midhinge"),
|
|
|
|
tag("math::min"),
|
|
|
|
tag("math::mode"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("math::nearestrank"),
|
|
|
|
tag("math::percentile"),
|
2022-12-18 14:56:07 +00:00
|
|
|
tag("math::pow"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("math::product"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("math::round"),
|
|
|
|
tag("math::spread"),
|
|
|
|
tag("math::sqrt"),
|
|
|
|
tag("math::stddev"),
|
|
|
|
tag("math::sum"),
|
|
|
|
tag("math::top"),
|
|
|
|
tag("math::trimean"),
|
|
|
|
tag("math::variance"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2022-09-19 02:56:59 +00:00
|
|
|
fn function_meta(i: &str) -> IResult<&str, &str> {
|
|
|
|
alt((tag("meta::id"), tag("meta::table"), tag("meta::tb")))(i)
|
|
|
|
}
|
|
|
|
|
2022-12-30 09:34:46 +00:00
|
|
|
fn function_not(i: &str) -> IResult<&str, &str> {
|
|
|
|
tag("not")(i)
|
|
|
|
}
|
|
|
|
|
2023-03-10 15:24:27 +00:00
|
|
|
fn function_sleep(i: &str) -> IResult<&str, &str> {
|
|
|
|
tag("sleep")(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_parse(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2022-09-01 17:46:36 +00:00
|
|
|
tag("parse::email::host"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("parse::email::user"),
|
|
|
|
tag("parse::url::domain"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("parse::url::fragment"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("parse::url::host"),
|
|
|
|
tag("parse::url::path"),
|
2023-01-04 07:51:21 +00:00
|
|
|
tag("parse::url::port"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("parse::url::query"),
|
2022-10-03 23:28:30 +00:00
|
|
|
tag("parse::url::scheme"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_rand(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("rand::bool"),
|
|
|
|
tag("rand::enum"),
|
|
|
|
tag("rand::float"),
|
|
|
|
tag("rand::guid"),
|
|
|
|
tag("rand::int"),
|
|
|
|
tag("rand::string"),
|
|
|
|
tag("rand::time"),
|
2023-01-17 09:02:01 +00:00
|
|
|
tag("rand::ulid"),
|
2022-10-16 22:22:34 +00:00
|
|
|
tag("rand::uuid::v4"),
|
|
|
|
tag("rand::uuid::v7"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("rand::uuid"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("rand"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2022-08-17 14:09:08 +00:00
|
|
|
fn function_session(i: &str) -> IResult<&str, &str> {
|
|
|
|
alt((
|
|
|
|
tag("session::db"),
|
|
|
|
tag("session::id"),
|
|
|
|
tag("session::ip"),
|
|
|
|
tag("session::ns"),
|
|
|
|
tag("session::origin"),
|
|
|
|
tag("session::sc"),
|
2022-09-04 23:56:23 +00:00
|
|
|
tag("session::sd"),
|
2022-09-17 01:44:39 +00:00
|
|
|
tag("session::token"),
|
2022-08-17 14:09:08 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_string(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("string::concat"),
|
|
|
|
tag("string::endsWith"),
|
|
|
|
tag("string::join"),
|
2023-02-18 21:07:37 +00:00
|
|
|
tag("string::len"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("string::lowercase"),
|
|
|
|
tag("string::repeat"),
|
|
|
|
tag("string::replace"),
|
|
|
|
tag("string::reverse"),
|
|
|
|
tag("string::slice"),
|
|
|
|
tag("string::slug"),
|
|
|
|
tag("string::split"),
|
|
|
|
tag("string::startsWith"),
|
|
|
|
tag("string::trim"),
|
|
|
|
tag("string::uppercase"),
|
|
|
|
tag("string::words"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_time(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("time::day"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("time::floor"),
|
2022-10-04 21:09:24 +00:00
|
|
|
tag("time::format"),
|
2022-01-18 22:23:46 +00:00
|
|
|
tag("time::group"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("time::hour"),
|
2022-11-03 10:50:51 +00:00
|
|
|
tag("time::minute"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("time::month"),
|
|
|
|
tag("time::nano"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("time::now"),
|
|
|
|
tag("time::round"),
|
2022-11-03 10:50:51 +00:00
|
|
|
tag("time::second"),
|
2023-01-08 20:56:59 +00:00
|
|
|
tag("time::timezone"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("time::unix"),
|
|
|
|
tag("time::wday"),
|
|
|
|
tag("time::week"),
|
|
|
|
tag("time::yday"),
|
|
|
|
tag("time::year"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
fn function_type(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("type::bool"),
|
|
|
|
tag("type::datetime"),
|
|
|
|
tag("type::decimal"),
|
|
|
|
tag("type::duration"),
|
|
|
|
tag("type::float"),
|
|
|
|
tag("type::int"),
|
|
|
|
tag("type::number"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("type::point"),
|
|
|
|
tag("type::regex"),
|
2022-01-13 17:36:41 +00:00
|
|
|
tag("type::string"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("type::table"),
|
|
|
|
tag("type::thing"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::test::Parse;
|
2020-06-29 15:36:01 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_single() {
|
|
|
|
let sql = "count()";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("count()", format!("{}", out));
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!(out, Function::Normal(String::from("count"), vec![]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-12-30 09:34:46 +00:00
|
|
|
#[test]
|
|
|
|
fn function_single_not() {
|
|
|
|
let sql = "not(1.2345)";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("not(1.2345)", format!("{}", out));
|
|
|
|
assert_eq!(out, Function::Normal("not".to_owned(), vec![1.2345.into()]));
|
|
|
|
}
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
#[test]
|
|
|
|
fn function_module() {
|
2022-01-13 17:36:41 +00:00
|
|
|
let sql = "rand::uuid()";
|
2020-06-29 15:36:01 +00:00
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
2022-01-13 17:36:41 +00:00
|
|
|
assert_eq!("rand::uuid()", format!("{}", out));
|
|
|
|
assert_eq!(out, Function::Normal(String::from("rand::uuid"), vec![]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_arguments() {
|
|
|
|
let sql = "is::numeric(null)";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("is::numeric(NULL)", format!("{}", out));
|
2022-01-13 17:36:41 +00:00
|
|
|
assert_eq!(out, Function::Normal(String::from("is::numeric"), vec![Value::Null]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_casting_number() {
|
2021-03-29 15:43:37 +00:00
|
|
|
let sql = "<int>1.2345";
|
2020-06-29 15:36:01 +00:00
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
2022-01-14 08:12:56 +00:00
|
|
|
assert_eq!("<int> 1.2345", format!("{}", out));
|
2022-01-13 17:36:41 +00:00
|
|
|
assert_eq!(out, Function::Cast(String::from("int"), 1.2345.into()));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_casting_string() {
|
|
|
|
let sql = "<string>1.2345";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
2022-01-14 08:12:56 +00:00
|
|
|
assert_eq!("<string> 1.2345", format!("{}", out));
|
2022-01-13 17:36:41 +00:00
|
|
|
assert_eq!(out, Function::Cast(String::from("string"), 1.2345.into()));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 21:16:25 +00:00
|
|
|
#[test]
|
|
|
|
fn function_script_expression() {
|
2022-07-23 18:53:49 +00:00
|
|
|
let sql = "function() { return this.tags.filter(t => { return t.length > 3; }); }";
|
2022-05-20 21:16:25 +00:00
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!(
|
2022-07-23 18:53:49 +00:00
|
|
|
"function() { return this.tags.filter(t => { return t.length > 3; }); }",
|
2022-05-20 21:16:25 +00:00
|
|
|
format!("{}", out)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
out,
|
2022-06-27 15:57:11 +00:00
|
|
|
Function::Script(
|
|
|
|
Script::parse(" return this.tags.filter(t => { return t.length > 3; }); "),
|
|
|
|
vec![]
|
|
|
|
)
|
2022-05-20 21:16:25 +00:00
|
|
|
);
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|