2021-03-29 15:43:37 +00:00
|
|
|
use crate::dbs;
|
|
|
|
use crate::dbs::Executor;
|
2021-03-31 12:10:13 +00:00
|
|
|
use crate::dbs::Runtime;
|
2021-03-29 15:43:37 +00:00
|
|
|
use crate::doc::Document;
|
|
|
|
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;
|
2021-05-22 18:21:59 +00:00
|
|
|
use crate::sql::expression::{expression, single, Expression};
|
2021-03-29 15:43:37 +00:00
|
|
|
use crate::sql::literal::Literal;
|
2020-06-29 15:36:01 +00:00
|
|
|
use nom::branch::alt;
|
|
|
|
use nom::bytes::complete::tag;
|
2021-03-29 15:43:37 +00:00
|
|
|
use nom::multi::separated_list0;
|
2020-06-29 15:36:01 +00:00
|
|
|
use nom::IResult;
|
|
|
|
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;
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub enum Function {
|
|
|
|
Future(Expression),
|
|
|
|
Cast(String, Expression),
|
|
|
|
Normal(String, Vec<Expression>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for Function {
|
|
|
|
#[inline]
|
|
|
|
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Function {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2021-03-29 15:43:37 +00:00
|
|
|
match self {
|
|
|
|
Function::Future(ref e) => write!(f, "fn() -> {{ {} }}", e),
|
|
|
|
Function::Cast(ref s, ref e) => write!(f, "<{}>{}", s, e),
|
|
|
|
Function::Normal(ref s, ref e) => write!(
|
2020-06-29 15:36:01 +00:00
|
|
|
f,
|
2021-03-29 15:43:37 +00:00
|
|
|
"{}({})",
|
|
|
|
s,
|
|
|
|
e.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", ")
|
|
|
|
),
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
2021-03-29 15:43:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl dbs::Process for Function {
|
|
|
|
fn process(
|
|
|
|
&self,
|
2021-03-31 12:10:13 +00:00
|
|
|
ctx: &Runtime,
|
2021-03-29 15:43:37 +00:00
|
|
|
exe: &Executor,
|
|
|
|
doc: Option<&Document>,
|
|
|
|
) -> Result<Literal, Error> {
|
|
|
|
match self {
|
|
|
|
Function::Future(ref e) => {
|
|
|
|
let a = e.process(ctx, exe, doc)?;
|
|
|
|
fnc::future::run(ctx, a)
|
|
|
|
}
|
|
|
|
Function::Cast(ref s, ref e) => {
|
|
|
|
let a = e.process(ctx, exe, doc)?;
|
|
|
|
fnc::cast::run(ctx, s, a)
|
|
|
|
}
|
|
|
|
Function::Normal(ref s, ref e) => {
|
|
|
|
let mut a: Vec<Literal> = vec![];
|
|
|
|
for v in e {
|
|
|
|
let v = v.process(ctx, exe, doc)?;
|
|
|
|
a.push(v);
|
|
|
|
}
|
|
|
|
fnc::run(ctx, s, a)
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn function(i: &str) -> IResult<&str, Function> {
|
2021-03-29 15:43:37 +00:00
|
|
|
alt((casts, future, normal))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn future(i: &str) -> IResult<&str, Function> {
|
|
|
|
let (i, _) = tag("fn()")(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = tag("->")(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = tag("{")(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, v) = expression(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = tag("}")(i)?;
|
|
|
|
Ok((i, Function::Future(v)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn casts(i: &str) -> IResult<&str, Function> {
|
|
|
|
let (i, _) = tag("<")(i)?;
|
|
|
|
let (i, s) = function_casts(i)?;
|
|
|
|
let (i, _) = tag(">")(i)?;
|
|
|
|
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 normal(i: &str) -> IResult<&str, Function> {
|
|
|
|
let (i, s) = function_names(i)?;
|
|
|
|
let (i, _) = tag("(")(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, v) = separated_list0(commas, expression)(i)?;
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
let (i, _) = tag(")")(i)?;
|
|
|
|
Ok((i, Function::Normal(s.to_string(), v)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_casts(i: &str) -> IResult<&str, &str> {
|
|
|
|
alt((
|
|
|
|
tag("bool"),
|
|
|
|
tag("int"),
|
|
|
|
tag("float"),
|
|
|
|
tag("string"),
|
|
|
|
tag("number"),
|
|
|
|
tag("decimal"),
|
|
|
|
tag("datetime"),
|
|
|
|
tag("duration"),
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn function_names(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
|
|
|
function_array,
|
|
|
|
function_count,
|
|
|
|
function_geo,
|
|
|
|
function_hash,
|
|
|
|
function_http,
|
|
|
|
function_is,
|
|
|
|
function_math,
|
|
|
|
function_parse,
|
|
|
|
function_rand,
|
|
|
|
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((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("array::difference"),
|
|
|
|
tag("array::distinct"),
|
|
|
|
tag("array::intersect"),
|
|
|
|
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> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("count::all"),
|
|
|
|
tag("count::if"),
|
|
|
|
tag("count::not"),
|
|
|
|
tag("count::oneof"),
|
|
|
|
tag("count::between"),
|
|
|
|
tag("count"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(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::center"),
|
|
|
|
tag("geo::centroid"),
|
|
|
|
tag("geo::circle"),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("geo::distance"),
|
|
|
|
tag("geo::latitude"),
|
|
|
|
tag("geo::longitude"),
|
2021-05-17 16:59:50 +00:00
|
|
|
tag("geo::midpoint"),
|
2021-03-29 15:43:37 +00:00
|
|
|
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_hash(i: &str) -> IResult<&str, &str> {
|
2020-06-29 15:36:01 +00:00
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("hash::md5"),
|
|
|
|
tag("hash::sha1"),
|
|
|
|
tag("hash::sha256"),
|
|
|
|
tag("hash::sha512"),
|
|
|
|
tag("hash::bcrypt::compare"),
|
|
|
|
tag("hash::bcrypt::generate"),
|
|
|
|
tag("hash::scrypt::compare"),
|
|
|
|
tag("hash::scrypt::generate"),
|
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"),
|
|
|
|
tag("http::async::head"),
|
|
|
|
tag("http::async::get"),
|
|
|
|
tag("http::async::put"),
|
|
|
|
tag("http::async::post"),
|
|
|
|
tag("http::async::patch"),
|
|
|
|
tag("http::async::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"),
|
|
|
|
tag("is::domain"),
|
|
|
|
tag("is::email"),
|
|
|
|
tag("is::hexadecimal"),
|
|
|
|
tag("is::latitude"),
|
|
|
|
tag("is::longitude"),
|
|
|
|
tag("is::numeric"),
|
|
|
|
tag("is::semver"),
|
|
|
|
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::correlation"),
|
|
|
|
tag("math::count"),
|
|
|
|
tag("math::covariance"),
|
|
|
|
tag("math::fixed"),
|
|
|
|
tag("math::floor"),
|
|
|
|
tag("math::geometricmean"),
|
|
|
|
tag("math::harmonicmean"),
|
|
|
|
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"),
|
|
|
|
tag("math::round"),
|
|
|
|
tag("math::sample"),
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
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((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("parse::email::domain"),
|
|
|
|
tag("parse::email::user"),
|
|
|
|
tag("parse::url::domain"),
|
|
|
|
tag("parse::url::host"),
|
|
|
|
tag("parse::url::port"),
|
|
|
|
tag("parse::url::path"),
|
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((
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("guid"),
|
|
|
|
tag("uuid"),
|
|
|
|
tag("rand::bool"),
|
|
|
|
tag("rand::guid"),
|
|
|
|
tag("rand::uuid"),
|
|
|
|
tag("rand::enum"),
|
|
|
|
tag("rand::time"),
|
|
|
|
tag("rand::string"),
|
|
|
|
tag("rand::integer"),
|
|
|
|
tag("rand::decimal"),
|
|
|
|
tag("rand::sentence"),
|
|
|
|
tag("rand::paragraph"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("rand::person::email"),
|
|
|
|
tag("rand::person::phone"),
|
|
|
|
tag("rand::person::fullname"),
|
|
|
|
tag("rand::person::firstname"),
|
|
|
|
tag("rand::person::lastname"),
|
|
|
|
tag("rand::person::username"),
|
|
|
|
tag("rand::person::jobtitle"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
|
|
|
alt((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("rand::location::name"),
|
|
|
|
tag("rand::location::address"),
|
|
|
|
tag("rand::location::street"),
|
|
|
|
tag("rand::location::city"),
|
|
|
|
tag("rand::location::state"),
|
|
|
|
tag("rand::location::county"),
|
|
|
|
tag("rand::location::zipcode"),
|
|
|
|
tag("rand::location::postcode"),
|
|
|
|
tag("rand::location::country"),
|
|
|
|
tag("rand::location::altitude"),
|
|
|
|
tag("rand::location::latitude"),
|
|
|
|
tag("rand::location::longitude"),
|
2020-06-29 15:36:01 +00:00
|
|
|
)),
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("rand"),
|
2020-06-29 15:36:01 +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::contains"),
|
|
|
|
tag("string::endsWith"),
|
|
|
|
tag("string::format"),
|
|
|
|
tag("string::includes"),
|
|
|
|
tag("string::join"),
|
|
|
|
tag("string::length"),
|
|
|
|
tag("string::lowercase"),
|
|
|
|
tag("string::repeat"),
|
|
|
|
tag("string::replace"),
|
|
|
|
tag("string::reverse"),
|
|
|
|
tag("string::search"),
|
|
|
|
tag("string::slice"),
|
|
|
|
tag("string::slug"),
|
|
|
|
tag("string::split"),
|
|
|
|
tag("string::startsWith"),
|
|
|
|
tag("string::substr"),
|
|
|
|
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::now"),
|
|
|
|
tag("time::add"),
|
|
|
|
tag("time::age"),
|
|
|
|
tag("time::floor"),
|
|
|
|
tag("time::round"),
|
|
|
|
tag("time::day"),
|
|
|
|
tag("time::hour"),
|
|
|
|
tag("time::mins"),
|
|
|
|
tag("time::month"),
|
|
|
|
tag("time::nano"),
|
|
|
|
tag("time::secs"),
|
|
|
|
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((
|
2021-03-29 15:43:37 +00:00
|
|
|
tag("type::batch"),
|
|
|
|
tag("type::model"),
|
|
|
|
tag("type::point"),
|
|
|
|
tag("type::polygon"),
|
|
|
|
tag("type::regex"),
|
|
|
|
tag("type::table"),
|
|
|
|
tag("type::thing"),
|
2020-06-29 15:36:01 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[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
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_module() {
|
|
|
|
let sql = "count::if()";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("count::if()", format!("{}", out));
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!(out, Function::Normal(String::from("count::if"), 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));
|
|
|
|
assert_eq!(
|
|
|
|
out,
|
2021-03-29 15:43:37 +00:00
|
|
|
Function::Normal(String::from("is::numeric"), vec![Expression::from("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;
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!("<int>1.2345", format!("{}", out));
|
|
|
|
assert_eq!(out, Function::Cast(String::from("int"), Expression::from("1.2345")));
|
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;
|
|
|
|
assert_eq!("<string>1.2345", format!("{}", out));
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!(out, Function::Cast(String::from("string"), Expression::from("1.2345")));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn function_future_expression() {
|
|
|
|
let sql = "fn() -> { 1.2345 + 5.4321 }";
|
|
|
|
let res = function(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("fn() -> { 1.2345 + 5.4321 }", format!("{}", out));
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!(out, Function::Future(Expression::from("1.2345 + 5.4321")));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|