Add further SQL function implementations

This commit is contained in:
Tobie Morgan Hitchcock 2022-01-13 17:37:46 +00:00
parent 6e031110bb
commit f3de9095ae
36 changed files with 2006 additions and 322 deletions

91
src/fnc/args.rs Normal file
View file

@ -0,0 +1,91 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
pub enum Args {
None,
Any,
One,
Two,
Three,
NoneOne,
NoneTwo,
NoneOneTwo,
OneTwo,
OneTwoThree,
}
pub fn check(
ctx: &Runtime,
name: &String,
args: Vec<Value>,
size: Args,
func: fn(&Runtime, Vec<Value>) -> Result<Value, Error>,
) -> Result<Value, Error> {
match size {
Args::None => match args.len() {
0 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function does not expect any arguments."),
}),
},
Args::One => match args.len() {
1 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 1 argument."),
}),
},
Args::Two => match args.len() {
2 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 2 arguments."),
}),
},
Args::Three => match args.len() {
3 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 3 arguments."),
}),
},
Args::NoneOne => match args.len() {
0 | 1 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 0 or 1 arguments."),
}),
},
Args::NoneTwo => match args.len() {
0 | 2 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 0 or 2 arguments."),
}),
},
Args::NoneOneTwo => match args.len() {
0 | 1 | 2 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 0, 1, or 2 arguments."),
}),
},
Args::OneTwo => match args.len() {
1 | 2 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 1 or 2 arguments."),
}),
},
Args::OneTwoThree => match args.len() {
1 | 2 | 3 => func(ctx, args),
_ => Err(Error::ArgumentsError {
name: name.to_owned(),
message: String::from("The function expects 1, 2, or 3 arguments."),
}),
},
Args::Any => func(ctx, args),
}
}

73
src/fnc/array.rs Normal file
View file

@ -0,0 +1,73 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::array::Combine;
use crate::sql::array::Concat;
use crate::sql::array::Difference;
use crate::sql::array::Intersect;
use crate::sql::array::Union;
use crate::sql::array::Uniq;
use crate::sql::value::Value;
pub fn concat(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0) {
Value::Array(w) => Ok(v.value.concat(w.value).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn combine(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0) {
Value::Array(w) => Ok(v.value.combine(w.value).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn difference(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0) {
Value::Array(w) => Ok(v.value.difference(w.value).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn distinct(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.value.uniq().into()),
_ => Ok(Value::None),
}
}
pub fn intersect(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0) {
Value::Array(w) => Ok(v.value.intersect(w.value).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn len(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.value.len().into()),
_ => Ok(Value::None),
}
}
pub fn union(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0) {
Value::Array(w) => Ok(v.value.union(w.value).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}

View file

@ -1,48 +1,74 @@
use crate::dbs::Runtime; use crate::dbs::Runtime;
use crate::err::Error; use crate::err::Error;
use crate::sql::literal::Literal; use crate::sql::number::Number;
use crate::sql::value::Value;
pub fn run(ctx: &Runtime, name: &String, val: Literal) -> Result<Literal, Error> { pub fn run(ctx: &Runtime, name: &String, val: Value) -> Result<Value, Error> {
match name.as_str() { match name.as_str() {
"bool" => bool(ctx, val), "bool" => bool(ctx, val),
"int" => int(ctx, val), "int" => int(ctx, val),
"float" => float(ctx, val), "float" => float(ctx, val),
"string" => string(ctx, val), "string" => string(ctx, val),
"number" => number(ctx, val), "number" => number(ctx, val),
"decimal" => number(ctx, val), "decimal" => decimal(ctx, val),
"datetime" => datetime(ctx, val), "datetime" => datetime(ctx, val),
"duration" => duration(ctx, val), "duration" => duration(ctx, val),
_ => Ok(val), _ => Ok(val),
} }
} }
pub fn bool(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn bool(_: &Runtime, val: Value) -> Result<Value, Error> {
match val.as_bool() { match val.is_truthy() {
true => Ok(Literal::True), true => Ok(Value::True),
false => Ok(Literal::False), false => Ok(Value::False),
} }
} }
pub fn int(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn int(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Int(val.as_int())) match val {
Value::Number(Number::Int(_)) => Ok(val),
_ => Ok(Value::Number(Number::Int(val.as_int()))),
}
} }
pub fn float(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn float(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Float(val.as_float())) match val {
Value::Number(Number::Float(_)) => Ok(val),
_ => Ok(Value::Number(Number::Float(val.as_float()))),
}
} }
pub fn string(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn number(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Strand(val.as_strand())) match val {
Value::Number(Number::Decimal(_)) => Ok(val),
_ => Ok(Value::Number(Number::Decimal(val.as_decimal()))),
}
} }
pub fn number(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn decimal(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Number(val.as_number())) match val {
Value::Number(Number::Decimal(_)) => Ok(val),
_ => Ok(Value::Number(Number::Decimal(val.as_decimal()))),
}
} }
pub fn datetime(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn string(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Datetime(val.as_datetime())) match val {
Value::Strand(_) => Ok(val),
_ => Ok(Value::Strand(val.as_strand())),
}
} }
pub fn duration(ctx: &Runtime, val: Literal) -> Result<Literal, Error> { pub fn datetime(_: &Runtime, val: Value) -> Result<Value, Error> {
Ok(Literal::Duration(val.as_duration())) match val {
Value::Datetime(_) => Ok(val),
_ => Ok(Value::Datetime(val.as_datetime())),
}
}
pub fn duration(_: &Runtime, val: Value) -> Result<Value, Error> {
match val {
Value::Duration(_) => Ok(val),
_ => Ok(Value::Duration(val.as_duration())),
}
} }

17
src/fnc/count.rs Normal file
View file

@ -0,0 +1,17 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
pub fn count(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
1 => match args.remove(0) {
Value::Array(v) => Ok(v.value.iter().filter(|v| v.is_truthy()).count().into()),
v => match v.is_truthy() {
true => Ok(1.into()),
false => Ok(0.into()),
},
},
0 => Ok(1.into()),
_ => unreachable!(),
}
}

135
src/fnc/crypto.rs Normal file
View file

@ -0,0 +1,135 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use md5::Digest;
use md5::Md5;
use sha1::Sha1;
use sha2::Sha256;
use sha2::Sha512;
pub fn md5(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Md5::new();
hasher.update(args.remove(0).as_strand().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
}
pub fn sha1(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha1::new();
hasher.update(args.remove(0).as_strand().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
}
pub fn sha256(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha256::new();
hasher.update(args.remove(0).as_strand().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
}
pub fn sha512(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let mut hasher = Sha512::new();
hasher.update(args.remove(0).as_strand().as_str());
let val = hasher.finalize();
let val = format!("{:x}", val);
Ok(val.into())
}
pub mod argon2 {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use argon2::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
use rand::rngs::OsRng;
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default();
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let test = PasswordHash::new(&hash).unwrap();
Ok(algo.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let algo = Argon2::default();
let pass = args.remove(0).as_strand().value;
let salt = SaltString::generate(&mut OsRng);
let hash = algo.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())
}
}
pub mod bcrypt {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
pub fn cmp(_: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn gen(_: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
}
pub mod pbkdf2 {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use pbkdf2::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Pbkdf2,
};
use rand::rngs::OsRng;
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let test = PasswordHash::new(&hash).unwrap();
Ok(Pbkdf2.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let pass = args.remove(0).as_strand().value;
let salt = SaltString::generate(&mut OsRng);
let hash = Pbkdf2.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())
}
}
pub mod scrypt {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use rand::rngs::OsRng;
use scrypt::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Scrypt,
};
pub fn cmp(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let hash = args.remove(0).as_strand().value;
let pass = args.remove(0).as_strand().value;
let test = PasswordHash::new(&hash).unwrap();
Ok(Scrypt.verify_password(pass.as_ref(), &test).is_ok().into())
}
pub fn gen(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let pass = args.remove(0).as_strand().value;
let salt = SaltString::generate(&mut OsRng);
let hash = Scrypt.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
Ok(hash.into())
}
}

View file

@ -1,7 +1,7 @@
use crate::dbs::Runtime; use crate::dbs::Runtime;
use crate::err::Error; use crate::err::Error;
use crate::sql::literal::Literal; use crate::sql::value::Value;
pub fn run(ctx: &Runtime, args: Literal) -> Result<Literal, Error> { pub fn run(_: &Runtime, expr: Value) -> Result<Value, Error> {
todo!() Ok(expr)
} }

116
src/fnc/geo.rs Normal file
View file

@ -0,0 +1,116 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::geometry::Geometry;
use crate::sql::value::Value;
use geo::algorithm::area::Area;
use geo::algorithm::bearing::Bearing;
use geo::algorithm::centroid::Centroid;
use geo::algorithm::haversine_distance::HaversineDistance;
pub fn area(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Geometry(v) => match v {
Geometry::Point(v) => Ok(v.signed_area().into()),
Geometry::Line(v) => Ok(v.signed_area().into()),
Geometry::Polygon(v) => Ok(v.signed_area().into()),
Geometry::MultiPoint(v) => Ok(v.signed_area().into()),
Geometry::MultiLine(v) => Ok(v.signed_area().into()),
Geometry::MultiPolygon(v) => Ok(v.signed_area().into()),
Geometry::Collection(v) => {
Ok(v.into_iter().collect::<geo::Geometry<f64>>().signed_area().into())
}
},
_ => Ok(Value::None),
}
}
pub fn bearing(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Geometry(Geometry::Point(v)) => match args.remove(0) {
Value::Geometry(Geometry::Point(w)) => Ok(v.bearing(w).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn centroid(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Geometry(v) => match v {
Geometry::Point(v) => Ok(v.centroid().into()),
Geometry::Line(v) => match v.centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
},
Geometry::Polygon(v) => match v.centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
},
Geometry::MultiPoint(v) => match v.centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
},
Geometry::MultiLine(v) => match v.centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
},
Geometry::MultiPolygon(v) => match v.centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
},
Geometry::Collection(v) => {
match v.into_iter().collect::<geo::Geometry<f64>>().centroid() {
Some(x) => Ok(x.into()),
None => Ok(Value::None),
}
}
},
_ => Ok(Value::None),
}
}
pub fn distance(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Geometry(Geometry::Point(v)) => match args.remove(0) {
Value::Geometry(Geometry::Point(w)) => Ok(v.haversine_distance(&w).into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub mod hash {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::fnc::util::geo;
use crate::sql::geometry::Geometry;
use crate::sql::value::Value;
pub fn encode(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0) {
Value::Geometry(Geometry::Point(v)) => match args.remove(0).as_int() {
l if l > 0 && l <= 12 => Ok(geo::encode(v, l as usize).into()),
_ => Err(Error::ArgumentsError {
name: String::from("geo::encode"),
message: String::from("The second argument must be an integer greater than 0 and less than or equal to 12."),
}),
},
_ => Ok(Value::None),
},
1 => match args.remove(0) {
Value::Geometry(Geometry::Point(v)) => Ok(geo::encode(v, 12 as usize).into()),
_ => Ok(Value::None),
},
_ => unreachable!(),
}
}
pub fn decode(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Strand(v) => Ok(geo::decode(v).into()),
_ => Ok(Value::None),
}
}
}

27
src/fnc/http.rs Normal file
View file

@ -0,0 +1,27 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
pub fn head(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn get(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn put(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn post(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn patch(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}
pub fn delete(_ctx: &Runtime, _args: Vec<Value>) -> Result<Value, Error> {
todo!()
}

81
src/fnc/is.rs Normal file
View file

@ -0,0 +1,81 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use once_cell::sync::Lazy;
use regex::Regex;
use std::char;
#[rustfmt::skip] static UUID_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$").unwrap());
#[rustfmt::skip] static USER_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(?i)[a-z0-9.!#$%&'*+/=?^_`{|}~-]+\z").unwrap());
#[rustfmt::skip] static HOST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$").unwrap());
#[rustfmt::skip] static DOMAIN_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$",).unwrap());
#[rustfmt::skip] static SEMVER_RE: Lazy<Regex> = Lazy::new(|| Regex::new("^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$").unwrap());
#[rustfmt::skip] static LATITUDE_RE: Lazy<Regex> = Lazy::new(|| Regex::new("^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$").unwrap());
#[rustfmt::skip] static LONGITUDE_RE: Lazy<Regex> = Lazy::new(|| Regex::new("^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$").unwrap());
pub fn alphanum(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_alphanumeric).into())
}
pub fn alpha(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_alphabetic).into())
}
pub fn ascii(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(|x| char::is_ascii(&x)).into())
}
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(DOMAIN_RE.is_match(args.remove(0).as_strand().as_str()).into())
}
pub fn email(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Convert to a &str
let val = val.as_str();
// Check if value is empty
if val.is_empty() {
return Ok(Value::False);
}
// Ensure the value contains @
if !val.contains('@') {
return Ok(Value::False);
}
// Reverse split the value by @
let parts: Vec<&str> = val.rsplitn(2, '@').collect();
// Check the first part matches
if !USER_RE.is_match(parts[1]) {
return Ok(Value::False);
}
// Check the second part matches
if !HOST_RE.is_match(parts[0]) {
return Ok(Value::False);
}
// The email is valid
Ok(Value::True)
}
pub fn hexadecimal(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(|x| char::is_ascii_hexdigit(&x)).into())
}
pub fn latitude(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(LATITUDE_RE.is_match(args.remove(0).as_strand().as_str()).into())
}
pub fn longitude(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(LONGITUDE_RE.is_match(args.remove(0).as_strand().as_str()).into())
}
pub fn numeric(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().all(char::is_numeric).into())
}
pub fn semver(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(SEMVER_RE.is_match(args.remove(0).as_strand().as_str()).into())
}
pub fn uuid(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(UUID_RE.is_match(args.remove(0).as_strand().as_str()).into())
}

178
src/fnc/math.rs Normal file
View file

@ -0,0 +1,178 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::fnc::util::math::bottom::Bottom;
use crate::fnc::util::math::deviation::Deviation;
use crate::fnc::util::math::interquartile::Interquartile;
use crate::fnc::util::math::mean::Mean;
use crate::fnc::util::math::median::Median;
use crate::fnc::util::math::midhinge::Midhinge;
use crate::fnc::util::math::mode::Mode;
use crate::fnc::util::math::nearestrank::Nearestrank;
use crate::fnc::util::math::percentile::Percentile;
use crate::fnc::util::math::spread::Spread;
use crate::fnc::util::math::top::Top;
use crate::fnc::util::math::trimean::Trimean;
use crate::fnc::util::math::variance::Variance;
use crate::sql::number::Number;
use crate::sql::value::Value;
pub fn abs(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_number().abs().into())
}
pub fn bottom(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0).as_int() {
c => Ok(v.as_numbers().bottom(c).into()),
},
_ => Ok(Value::None),
}
}
pub fn ceil(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_number().ceil().into())
}
pub fn fixed(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
v => match args.remove(0).as_int() {
p if p > 0 => Ok(v.as_number().fixed(p as usize).into()),
_ => Err(Error::ArgumentsError {
name: String::from("math::fixed"),
message: String::from("The second argument must be an integer greater than 0."),
}),
},
}
}
pub fn floor(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_number().floor().into())
}
pub fn interquartile(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().interquartile().into()),
_ => Ok(Value::None),
}
}
pub fn max(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match v.as_numbers().into_iter().max() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
v => Ok(v),
}
}
pub fn mean(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().mean().into()),
_ => Ok(Value::None),
}
}
pub fn median(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().median().into()),
_ => Ok(Value::None),
}
}
pub fn midhinge(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().midhinge().into()),
_ => Ok(Value::None),
}
}
pub fn min(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match v.as_numbers().into_iter().min() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
v => Ok(v),
}
}
pub fn mode(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().mode().into()),
_ => Ok(Value::None),
}
}
pub fn nearestrank(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().nearestrank(args.remove(0).as_number()).into()),
_ => Ok(Value::None),
}
}
pub fn percentile(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().percentile(args.remove(0).as_number()).into()),
_ => Ok(Value::None),
}
}
pub fn product(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().into_iter().product::<Number>().into()),
_ => Ok(Value::None),
}
}
pub fn round(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_number().round().into())
}
pub fn spread(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().spread().into()),
_ => Ok(Value::None),
}
}
pub fn sqrt(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_number().sqrt().into())
}
pub fn stddev(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().deviation().into()),
_ => Ok(Value::None),
}
}
pub fn sum(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().into_iter().sum::<Number>().into()),
_ => Ok(Value::None),
}
}
pub fn top(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => match args.remove(0).as_int() {
c => Ok(v.as_numbers().top(c).into()),
},
_ => Ok(Value::None),
}
}
pub fn trimean(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().trimean().into()),
_ => Ok(Value::None),
}
}
pub fn variance(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Array(v) => Ok(v.as_numbers().variance().into()),
_ => Ok(Value::None),
}
}

View file

@ -1,11 +1,168 @@
use crate::dbs::Runtime; use crate::dbs::Runtime;
use crate::err::Error; use crate::err::Error;
use crate::sql::literal::Literal; use crate::fnc::args::Args;
use crate::sql::value::Value;
pub mod args;
pub mod array;
pub mod cast; pub mod cast;
pub mod count;
pub mod crypto;
pub mod future; pub mod future;
pub mod geo;
pub mod http;
pub mod is;
pub mod math;
pub mod operate; pub mod operate;
pub mod parse;
pub mod rand;
pub mod script;
pub mod string;
pub mod time;
pub mod r#type;
pub mod util;
pub fn run(ctx: &Runtime, name: &String, args: Vec<Literal>) -> Result<Literal, Error> { pub fn run(ctx: &Runtime, name: &String, args: Vec<Value>) -> Result<Value, Error> {
todo!() match name.as_ref() {
//
"array::combine" => args::check(ctx, name, args, Args::Two, array::combine),
"array::concat" => args::check(ctx, name, args, Args::Two, array::concat),
"array::difference" => args::check(ctx, name, args, Args::Two, array::difference),
"array::distinct" => args::check(ctx, name, args, Args::One, array::distinct),
"array::intersect" => args::check(ctx, name, args, Args::Two, array::intersect),
"array::len" => args::check(ctx, name, args, Args::One, array::len),
"array::union" => args::check(ctx, name, args, Args::Two, array::union),
//
"count" => args::check(ctx, name, args, Args::NoneOne, count::count),
//
"crypto::md5" => args::check(ctx, name, args, Args::One, crypto::md5),
"crypto::sha1" => args::check(ctx, name, args, Args::One, crypto::sha1),
"crypto::sha256" => args::check(ctx, name, args, Args::One, crypto::sha256),
"crypto::sha512" => args::check(ctx, name, args, Args::One, crypto::sha512),
"crypto::argon2::compare" => args::check(ctx, name, args, Args::Two, crypto::argon2::cmp),
"crypto::argon2::generate" => args::check(ctx, name, args, Args::One, crypto::argon2::gen),
"crypto::bcrypt::compare" => args::check(ctx, name, args, Args::Two, crypto::bcrypt::cmp),
"crypto::bcrypt::generate" => args::check(ctx, name, args, Args::One, crypto::bcrypt::gen),
"crypto::pbkdf2::compare" => args::check(ctx, name, args, Args::Two, crypto::pbkdf2::cmp),
"crypto::pbkdf2::generate" => args::check(ctx, name, args, Args::One, crypto::pbkdf2::gen),
"crypto::scrypt::compare" => args::check(ctx, name, args, Args::Two, crypto::scrypt::cmp),
"crypto::scrypt::generate" => args::check(ctx, name, args, Args::One, crypto::scrypt::gen),
//
"geo::area" => args::check(ctx, name, args, Args::One, geo::area),
"geo::bearing" => args::check(ctx, name, args, Args::Two, geo::bearing),
"geo::centroid" => args::check(ctx, name, args, Args::One, geo::centroid),
"geo::distance" => args::check(ctx, name, args, Args::Two, geo::distance),
"geo::hash::decode" => args::check(ctx, name, args, Args::One, geo::hash::decode),
"geo::hash::encode" => args::check(ctx, name, args, Args::OneTwo, geo::hash::encode),
//
"http::head" => args::check(ctx, name, args, Args::OneTwo, http::head),
"http::get" => args::check(ctx, name, args, Args::OneTwo, http::get),
"http::put" => args::check(ctx, name, args, Args::OneTwoThree, http::put),
"http::post" => args::check(ctx, name, args, Args::OneTwoThree, http::post),
"http::patch" => args::check(ctx, name, args, Args::OneTwoThree, http::patch),
"http::delete" => args::check(ctx, name, args, Args::OneTwo, http::delete),
//
"is::alphanum" => args::check(ctx, name, args, Args::One, is::alphanum),
"is::alpha" => args::check(ctx, name, args, Args::One, is::alpha),
"is::ascii" => args::check(ctx, name, args, Args::One, is::ascii),
"is::domain" => args::check(ctx, name, args, Args::One, is::domain),
"is::email" => args::check(ctx, name, args, Args::One, is::email),
"is::hexadecimal" => args::check(ctx, name, args, Args::One, is::hexadecimal),
"is::latitude" => args::check(ctx, name, args, Args::One, is::latitude),
"is::longitude" => args::check(ctx, name, args, Args::One, is::longitude),
"is::numeric" => args::check(ctx, name, args, Args::One, is::numeric),
"is::semver" => args::check(ctx, name, args, Args::One, is::semver),
"is::uuid" => args::check(ctx, name, args, Args::One, is::uuid),
//
"math::abs" => args::check(ctx, name, args, Args::One, math::abs),
"math::bottom" => args::check(ctx, name, args, Args::Two, math::bottom),
"math::ceil" => args::check(ctx, name, args, Args::One, math::ceil),
"math::fixed" => args::check(ctx, name, args, Args::Two, math::fixed),
"math::floor" => args::check(ctx, name, args, Args::One, math::floor),
"math::interquartile" => args::check(ctx, name, args, Args::One, math::interquartile),
"math::max" => args::check(ctx, name, args, Args::One, math::max),
"math::mean" => args::check(ctx, name, args, Args::One, math::mean),
"math::median" => args::check(ctx, name, args, Args::One, math::median),
"math::midhinge" => args::check(ctx, name, args, Args::One, math::midhinge),
"math::min" => args::check(ctx, name, args, Args::One, math::min),
"math::mode" => args::check(ctx, name, args, Args::One, math::mode),
"math::nearestrank" => args::check(ctx, name, args, Args::Two, math::nearestrank),
"math::percentile" => args::check(ctx, name, args, Args::Two, math::percentile),
"math::product" => args::check(ctx, name, args, Args::One, math::product),
"math::round" => args::check(ctx, name, args, Args::One, math::round),
"math::spread" => args::check(ctx, name, args, Args::One, math::spread),
"math::sqrt" => args::check(ctx, name, args, Args::One, math::sqrt),
"math::stddev" => args::check(ctx, name, args, Args::One, math::stddev),
"math::sum" => args::check(ctx, name, args, Args::One, math::sum),
"math::top" => args::check(ctx, name, args, Args::Two, math::top),
"math::trimean" => args::check(ctx, name, args, Args::One, math::trimean),
"math::variance" => args::check(ctx, name, args, Args::One, math::variance),
//
"parse::email::domain" => args::check(ctx, name, args, Args::One, parse::email::domain),
"parse::email::user" => args::check(ctx, name, args, Args::One, parse::email::user),
"parse::url::domain" => args::check(ctx, name, args, Args::One, parse::url::domain),
"parse::url::fragment" => args::check(ctx, name, args, Args::One, parse::url::fragment),
"parse::url::host" => args::check(ctx, name, args, Args::One, parse::url::host),
"parse::url::path" => args::check(ctx, name, args, Args::One, parse::url::path),
"parse::url::port" => args::check(ctx, name, args, Args::One, parse::url::port),
"parse::url::query" => args::check(ctx, name, args, Args::One, parse::url::query),
//
"rand::bool" => args::check(ctx, name, args, Args::None, rand::bool),
"rand::enum" => args::check(ctx, name, args, Args::Any, rand::r#enum),
"rand::float" => args::check(ctx, name, args, Args::NoneTwo, rand::float),
"rand::guid" => args::check(ctx, name, args, Args::None, rand::guid),
"rand::int" => args::check(ctx, name, args, Args::NoneTwo, rand::int),
"rand::string" => args::check(ctx, name, args, Args::NoneOneTwo, rand::string),
"rand::time" => args::check(ctx, name, args, Args::NoneTwo, rand::time),
"rand::uuid" => args::check(ctx, name, args, Args::None, rand::uuid),
"rand" => args::check(ctx, name, args, Args::None, rand::rand),
//
"string::concat" => args::check(ctx, name, args, Args::Any, string::concat),
"string::contains" => args::check(ctx, name, args, Args::Two, string::contains),
"string::endsWith" => args::check(ctx, name, args, Args::Two, string::ends_with),
"string::join" => args::check(ctx, name, args, Args::Any, string::join),
"string::length" => args::check(ctx, name, args, Args::One, string::length),
"string::lowercase" => args::check(ctx, name, args, Args::One, string::lowercase),
"string::repeat" => args::check(ctx, name, args, Args::Two, string::repeat),
"string::replace" => args::check(ctx, name, args, Args::Three, string::replace),
"string::reverse" => args::check(ctx, name, args, Args::One, string::reverse),
"string::slice" => args::check(ctx, name, args, Args::Three, string::slice),
"string::slug" => args::check(ctx, name, args, Args::OneTwo, string::slug),
"string::split" => args::check(ctx, name, args, Args::Two, string::split),
"string::startsWith" => args::check(ctx, name, args, Args::Two, string::starts_with),
"string::substr" => args::check(ctx, name, args, Args::Three, string::substr),
"string::trim" => args::check(ctx, name, args, Args::One, string::trim),
"string::uppercase" => args::check(ctx, name, args, Args::One, string::uppercase),
"string::words" => args::check(ctx, name, args, Args::One, string::words),
//
"time::day" => args::check(ctx, name, args, Args::NoneOne, time::day),
"time::floor" => args::check(ctx, name, args, Args::Two, time::floor),
"time::hour" => args::check(ctx, name, args, Args::NoneOne, time::hour),
"time::mins" => args::check(ctx, name, args, Args::NoneOne, time::mins),
"time::month" => args::check(ctx, name, args, Args::NoneOne, time::month),
"time::nano" => args::check(ctx, name, args, Args::NoneOne, time::nano),
"time::now" => args::check(ctx, name, args, Args::None, time::now),
"time::round" => args::check(ctx, name, args, Args::Two, time::round),
"time::secs" => args::check(ctx, name, args, Args::NoneOne, time::secs),
"time::unix" => args::check(ctx, name, args, Args::NoneOne, time::unix),
"time::wday" => args::check(ctx, name, args, Args::NoneOne, time::wday),
"time::week" => args::check(ctx, name, args, Args::NoneOne, time::week),
"time::yday" => args::check(ctx, name, args, Args::NoneOne, time::yday),
"time::year" => args::check(ctx, name, args, Args::NoneOne, time::year),
//
"type::bool" => args::check(ctx, name, args, Args::One, r#type::bool),
"type::datetime" => args::check(ctx, name, args, Args::One, r#type::datetime),
"type::decimal" => args::check(ctx, name, args, Args::One, r#type::decimal),
"type::duration" => args::check(ctx, name, args, Args::One, r#type::duration),
"type::float" => args::check(ctx, name, args, Args::One, r#type::float),
"type::int" => args::check(ctx, name, args, Args::One, r#type::int),
"type::number" => args::check(ctx, name, args, Args::One, r#type::number),
"type::point" => args::check(ctx, name, args, Args::OneTwo, r#type::point),
"type::regex" => args::check(ctx, name, args, Args::One, r#type::regex),
"type::string" => args::check(ctx, name, args, Args::One, r#type::string),
"type::table" => args::check(ctx, name, args, Args::One, r#type::table),
"type::thing" => args::check(ctx, name, args, Args::Two, r#type::thing),
//
_ => unreachable!(),
}
} }

View file

@ -1,352 +1,202 @@
use crate::err::Error; use crate::err::Error;
use crate::sql::literal::Literal;
use crate::sql::value::Value; use crate::sql::value::Value;
use std::ops::Add;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Sub;
pub fn or(a: Literal, b: Literal) -> Result<Literal, Error> { pub fn or(a: Value, b: Value) -> Result<Value, Error> {
match a.as_bool() { match a.is_truthy() {
true => Ok(a), true => Ok(a),
false => Ok(b), false => Ok(b),
} }
} }
pub fn and(a: Literal, b: Literal) -> Result<Literal, Error> { pub fn and(a: Value, b: Value) -> Result<Value, Error> {
match a.as_bool() { match a.is_truthy() {
true => match b.as_bool() { true => Ok(b),
_ => Ok(b),
},
false => Ok(a), false => Ok(a),
} }
} }
pub fn add(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn add(a: Value, b: Value) -> Result<Value, Error> {
let a = a.as_number(); Ok(a.add(b))
let b = b.as_number();
Ok(Literal::from(a + b))
} }
pub fn sub(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn sub(a: Value, b: Value) -> Result<Value, Error> {
let a = a.as_number(); Ok(a.sub(b))
let b = b.as_number();
Ok(Literal::from(a - b))
} }
pub fn mul(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn mul(a: Value, b: Value) -> Result<Value, Error> {
let a = a.as_number(); Ok(a.mul(b))
let b = b.as_number();
Ok(Literal::from(a * b))
} }
pub fn div(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn div(a: Value, b: Value) -> Result<Value, Error> {
let a = a.as_number(); Ok(a.div(b))
let b = b.as_number();
Ok(Literal::from(a / b))
} }
pub fn exact(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn exact(a: &Value, b: &Value) -> Result<Value, Error> {
Ok(Literal::from(a == b)) Ok(Value::from(a == b))
} }
pub fn equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.equal(b) {
Literal::None => Ok(Literal::from(b.is_none() == true)), true => Ok(Value::True),
Literal::Null => Ok(Literal::from(b.is_null() == true)), false => Ok(Value::False),
Literal::Void => Ok(Literal::from(b.is_void() == true)),
Literal::True => Ok(Literal::from(b.is_true() == true)),
Literal::False => Ok(Literal::from(b.is_false() == true)),
Literal::Int(v) => Ok(Literal::from(v == &b.as_int())),
Literal::Float(v) => Ok(Literal::from(v == &b.as_float())),
Literal::Thing(v) => match b {
Literal::Thing(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::True),
},
Literal::Regex(v) => match b {
Literal::Regex(w) => Ok(Literal::from(v == w)),
Literal::Strand(w) => match v.value {
Some(ref r) => Ok(Literal::from(r.is_match(w.value.as_str()) == true)),
None => Ok(Literal::False),
},
_ => Ok(Literal::False),
},
Literal::Point(v) => match b {
Literal::Point(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
Literal::Array(v) => match b {
Literal::Array(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
Literal::Object(v) => match b {
Literal::Object(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
Literal::Strand(v) => match b {
Literal::Strand(w) => Ok(Literal::from(v == w)),
Literal::Regex(w) => match w.value {
Some(ref r) => Ok(Literal::from(r.is_match(v.value.as_str()) == true)),
None => Ok(Literal::False),
},
_ => Ok(Literal::from(v == &b.as_strand())),
},
Literal::Number(v) => Ok(Literal::from(v == &b.as_number())),
Literal::Polygon(v) => match b {
Literal::Polygon(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
Literal::Duration(v) => match b {
Literal::Duration(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
Literal::Datetime(v) => match b {
Literal::Datetime(w) => Ok(Literal::from(v == w)),
_ => Ok(Literal::False),
},
_ => unreachable!(),
} }
} }
pub fn not_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn not_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.equal(b) {
Literal::None => Ok(Literal::from(b.is_none() != true)), true => Ok(Value::False),
Literal::Null => Ok(Literal::from(b.is_null() != true)), false => Ok(Value::True),
Literal::Void => Ok(Literal::from(b.is_void() != true)),
Literal::True => Ok(Literal::from(b.is_true() != true)),
Literal::False => Ok(Literal::from(b.is_false() != true)),
Literal::Int(v) => Ok(Literal::from(v != &b.as_int())),
Literal::Float(v) => Ok(Literal::from(v != &b.as_float())),
Literal::Thing(v) => match b {
Literal::Thing(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Regex(v) => match b {
Literal::Regex(w) => Ok(Literal::from(v != w)),
Literal::Strand(w) => match v.value {
Some(ref r) => Ok(Literal::from(r.is_match(w.value.as_str()) != true)),
None => Ok(Literal::True),
},
_ => Ok(Literal::True),
},
Literal::Point(v) => match b {
Literal::Point(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Array(v) => match b {
Literal::Array(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Object(v) => match b {
Literal::Object(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Number(v) => match b {
Literal::Number(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Strand(v) => match b {
Literal::Strand(w) => Ok(Literal::from(v != w)),
Literal::Regex(w) => match w.value {
Some(ref r) => Ok(Literal::from(r.is_match(v.value.as_str()) != true)),
None => Ok(Literal::False),
},
_ => Ok(Literal::from(v != &b.as_strand())),
},
Literal::Polygon(v) => match b {
Literal::Polygon(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Duration(v) => match b {
Literal::Duration(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
Literal::Datetime(v) => match b {
Literal::Datetime(w) => Ok(Literal::from(v != w)),
_ => Ok(Literal::True),
},
_ => unreachable!(),
} }
} }
pub fn all_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn all_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.all_equal(b) {
Literal::Array(ref v) => match v.value.iter().all(|x| match x { true => Ok(Value::True),
Value::Literal(v) => equal(v, b).is_ok(), false => Ok(Value::False),
_ => unreachable!(),
}) {
true => Ok(Literal::True),
false => Ok(Literal::False),
},
_ => equal(a, b),
} }
} }
pub fn any_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn any_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.any_equal(b) {
Literal::Array(ref v) => match v.value.iter().any(|x| match x { true => Ok(Value::True),
Value::Literal(v) => equal(v, b).is_ok(), false => Ok(Value::False),
_ => unreachable!(),
}) {
true => Ok(Literal::True),
false => Ok(Literal::False),
},
_ => equal(a, b),
} }
} }
pub fn like(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn like(a: &Value, b: &Value) -> Result<Value, Error> {
todo!() match a.fuzzy(b) {
} true => Ok(Value::True),
false => Ok(Value::False),
pub fn not_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
todo!()
}
pub fn all_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
todo!()
}
pub fn any_like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
todo!()
}
pub fn less_than(a: &Literal, b: &Literal) -> Result<Literal, Error> {
match a.lt(&b) {
true => Ok(Literal::True),
false => Ok(Literal::False),
} }
} }
pub fn less_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn not_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.le(&b) { match a.fuzzy(b) {
true => Ok(Literal::True), true => Ok(Value::False),
false => Ok(Literal::False), false => Ok(Value::True),
} }
} }
pub fn more_than(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn all_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.gt(&b) { match a.all_fuzzy(b) {
true => Ok(Literal::True), true => Ok(Value::True),
false => Ok(Literal::False), false => Ok(Value::False),
} }
} }
pub fn more_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn any_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.ge(&b) { match a.any_fuzzy(b) {
true => Ok(Literal::True), true => Ok(Value::True),
false => Ok(Literal::False), false => Ok(Value::False),
} }
} }
pub fn contain(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn less_than(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.lt(b) {
Literal::Array(v) => match v.value.iter().any(|x| match x { true => Ok(Value::True),
Value::Literal(v) => equal(v, b).is_ok(), false => Ok(Value::False),
_ => unreachable!(),
}) {
true => Ok(Literal::True),
false => Ok(Literal::False),
},
Literal::Strand(v) => match b {
Literal::Strand(w) => Ok(Literal::from(v.value.contains(w.value.as_str()) == true)),
_ => Ok(Literal::from(v.value.contains(&b.as_strand().value.as_str()) == true)),
},
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn not_contain(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn less_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.le(b) {
Literal::Array(v) => match v.value.iter().any(|x| match x { true => Ok(Value::True),
Value::Literal(v) => equal(v, b).is_ok(), false => Ok(Value::False),
_ => unreachable!(),
}) {
true => Ok(Literal::False),
false => Ok(Literal::True),
},
Literal::Strand(v) => match b {
Literal::Strand(w) => Ok(Literal::from(v.value.contains(w.value.as_str()) == false)),
_ => Ok(Literal::from(v.value.contains(&b.as_strand().value.as_str()) == false)),
},
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn contain_all(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn more_than(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.gt(b) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn contain_some(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn more_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.ge(b) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn contain_none(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn contain(a: &Value, b: &Value) -> Result<Value, Error> {
match a { match a.contains(b) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn inside(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn not_contain(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match a.contains(b) {
Literal::Array(v) => todo!(), true => Ok(Value::False),
Literal::Strand(v) => todo!(), false => Ok(Value::True),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn not_inside(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn contain_all(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match a.contains_all(b) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn inside_all(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn contain_any(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match a.contains_any(b) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn inside_some(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn contain_none(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match a.contains_any(b) {
Literal::Array(v) => todo!(), true => Ok(Value::False),
Literal::Strand(v) => todo!(), false => Ok(Value::True),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn inside_none(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn inside(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match b.contains(a) {
Literal::Array(v) => todo!(), true => Ok(Value::True),
Literal::Strand(v) => todo!(), false => Ok(Value::False),
Literal::Polygon(v) => todo!(),
_ => Ok(Literal::False),
} }
} }
pub fn intersects(a: &Literal, b: &Literal) -> Result<Literal, Error> { pub fn not_inside(a: &Value, b: &Value) -> Result<Value, Error> {
match b { match b.contains(a) {
Literal::Polygon(v) => todo!(), true => Ok(Value::False),
_ => Ok(Literal::False), false => Ok(Value::True),
}
}
pub fn inside_all(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_all(a) {
true => Ok(Value::True),
false => Ok(Value::False),
}
}
pub fn inside_any(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_any(a) {
true => Ok(Value::True),
false => Ok(Value::False),
}
}
pub fn inside_none(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_any(a) {
true => Ok(Value::False),
false => Ok(Value::True),
}
}
pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> {
match a.intersects(b) {
true => Ok(Value::True),
false => Ok(Value::False),
} }
} }
@ -357,8 +207,8 @@ mod tests {
#[test] #[test]
fn or_true() { fn or_true() {
let one = Literal::from(1); let one = Value::from(1);
let two = Literal::from(2); let two = Value::from(2);
let res = or(one, two); let res = or(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -367,8 +217,8 @@ mod tests {
#[test] #[test]
fn or_false_one() { fn or_false_one() {
let one = Literal::from(0); let one = Value::from(0);
let two = Literal::from(1); let two = Value::from(1);
let res = or(one, two); let res = or(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -377,8 +227,8 @@ mod tests {
#[test] #[test]
fn or_false_two() { fn or_false_two() {
let one = Literal::from(1); let one = Value::from(1);
let two = Literal::from(0); let two = Value::from(0);
let res = or(one, two); let res = or(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -387,8 +237,8 @@ mod tests {
#[test] #[test]
fn and_true() { fn and_true() {
let one = Literal::from(1); let one = Value::from(1);
let two = Literal::from(2); let two = Value::from(2);
let res = and(one, two); let res = and(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -397,8 +247,8 @@ mod tests {
#[test] #[test]
fn and_false_one() { fn and_false_one() {
let one = Literal::from(0); let one = Value::from(0);
let two = Literal::from(1); let two = Value::from(1);
let res = and(one, two); let res = and(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -407,8 +257,8 @@ mod tests {
#[test] #[test]
fn and_false_two() { fn and_false_two() {
let one = Literal::from(1); let one = Value::from(1);
let two = Literal::from(0); let two = Value::from(0);
let res = and(one, two); let res = and(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
@ -417,9 +267,9 @@ mod tests {
#[test] #[test]
fn add_basic() { fn add_basic() {
let one = Literal::from(5); let one = Value::from(5);
let two = Literal::from(4); let two = Value::from(4);
let res = add(&one, &two); let res = add(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
assert_eq!("9", format!("{}", out)); assert_eq!("9", format!("{}", out));
@ -427,9 +277,9 @@ mod tests {
#[test] #[test]
fn sub_basic() { fn sub_basic() {
let one = Literal::from(5); let one = Value::from(5);
let two = Literal::from(4); let two = Value::from(4);
let res = sub(&one, &two); let res = sub(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
assert_eq!("1", format!("{}", out)); assert_eq!("1", format!("{}", out));
@ -437,9 +287,9 @@ mod tests {
#[test] #[test]
fn mul_basic() { fn mul_basic() {
let one = Literal::from(5); let one = Value::from(5);
let two = Literal::from(4); let two = Value::from(4);
let res = mul(&one, &two); let res = mul(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
assert_eq!("20", format!("{}", out)); assert_eq!("20", format!("{}", out));
@ -447,9 +297,9 @@ mod tests {
#[test] #[test]
fn div_basic() { fn div_basic() {
let one = Literal::from(5); let one = Value::from(5);
let two = Literal::from(4); let two = Value::from(4);
let res = div(&one, &two); let res = div(one, two);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap(); let out = res.unwrap();
assert_eq!("1.25", format!("{}", out)); assert_eq!("1.25", format!("{}", out));

144
src/fnc/parse.rs Normal file
View file

@ -0,0 +1,144 @@
pub mod email {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use once_cell::sync::Lazy;
use regex::Regex;
#[rustfmt::skip] static USER_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(?i)[a-z0-9.!#$%&'*+/=?^_`{|}~-]+\z").unwrap());
#[rustfmt::skip] static HOST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$",).unwrap());
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Check if value is empty
if val.is_empty() {
return Ok(Value::None);
}
// Ensure the value contains @
if !val.contains('@') {
return Ok(Value::None);
}
// Reverse split the value by @
let parts: Vec<&str> = val.rsplitn(2, '@').collect();
// Check the first part matches
if !USER_RE.is_match(parts[1]) {
return Ok(Value::None);
}
// Check the second part matches
if !HOST_RE.is_match(parts[0]) {
return Ok(Value::None);
}
// Return the domain
Ok(parts[0].into())
}
pub fn user(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Check if value is empty
if val.is_empty() {
return Ok(Value::None);
}
// Ensure the value contains @
if !val.contains('@') {
return Ok(Value::None);
}
// Reverse split the value by @
let parts: Vec<&str> = val.rsplitn(2, '@').collect();
// Check the first part matches
if !USER_RE.is_match(parts[1]) {
return Ok(Value::None);
}
// Check the second part matches
if !HOST_RE.is_match(parts[0]) {
return Ok(Value::None);
}
// Return the domain
Ok(parts[1].into())
}
}
pub mod url {
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use url::Url;
pub fn domain(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.domain() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
Err(_) => Ok(Value::None),
}
}
pub fn fragment(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.fragment() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
Err(_) => Ok(Value::None),
}
}
pub fn host(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.host_str() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
Err(_) => Ok(Value::None),
}
}
pub fn path(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => Ok(v.path().into()),
Err(_) => Ok(Value::None),
}
}
pub fn port(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.port() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
Err(_) => Ok(Value::None),
}
}
pub fn query(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String
let val = args.remove(0).as_strand().value;
// Parse the URL
match Url::parse(&val) {
Ok(v) => match v.query() {
Some(v) => Ok(v.into()),
None => Ok(Value::None),
},
Err(_) => Ok(Value::None),
}
}
}

140
src/fnc/rand.rs Normal file
View file

@ -0,0 +1,140 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::datetime::Datetime;
use crate::sql::value::Value;
use rand::distributions::Alphanumeric;
use rand::Rng;
use uuid::Uuid;
use xid;
pub fn rand(_: &Runtime, _: Vec<Value>) -> Result<Value, Error> {
Ok(rand::random::<f64>().into())
}
pub fn bool(_: &Runtime, _: Vec<Value>) -> Result<Value, Error> {
Ok(rand::random::<bool>().into())
}
pub fn r#enum(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Value::None),
1 => match args.remove(0) {
Value::Array(mut v) => match v.value.len() {
0 => Ok(Value::None),
n => {
let i = rand::thread_rng().gen_range(0..n);
Ok(v.value.remove(i))
}
},
v => Ok(v),
},
n => {
let i = rand::thread_rng().gen_range(0..n);
Ok(args.remove(i))
}
}
}
pub fn float(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0).as_float() {
min => match args.remove(0).as_float() {
max if max < min => Ok(rand::thread_rng().gen_range(max..=min).into()),
max => Ok(rand::thread_rng().gen_range(min..=max).into()),
},
},
0 => Ok(rand::random::<f64>().into()),
_ => unreachable!(),
}
}
pub fn guid(_: &Runtime, _: Vec<Value>) -> Result<Value, Error> {
Ok(xid::new().to_string().into())
}
pub fn int(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0).as_int() {
min => match args.remove(0).as_int() {
max if max < min => Ok(rand::thread_rng().gen_range(max..=min).into()),
max => Ok(rand::thread_rng().gen_range(min..=max).into()),
},
},
0 => Ok(rand::random::<i64>().into()),
_ => unreachable!(),
}
}
pub fn string(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0).as_int() {
min if min >= 0 => match args.remove(0).as_int() {
max if max >= 0 && max < min => Ok(rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(rand::thread_rng().gen_range(max as usize..=min as usize))
.map(char::from)
.collect::<String>()
.into()),
max if max >= 0 => Ok(rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(rand::thread_rng().gen_range(min as usize..=max as usize))
.map(char::from)
.collect::<String>()
.into()),
_ => Err(Error::ArgumentsError {
name: String::from("rand::string"),
message: String::from("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers."),
}),
},
_ => Err(Error::ArgumentsError {
name: String::from("rand::string"),
message: String::from("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers."),
}),
},
1 => match args.remove(0).as_int() {
x if x >= 0 => Ok(rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(x as usize)
.map(char::from)
.collect::<String>()
.into()),
_ => Err(Error::ArgumentsError {
name: String::from("rand::string"),
message: String::from("To generate a string of X characters in length, the argument must be a positive number."),
}),
},
0 => Ok(rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(32)
.map(char::from)
.collect::<String>()
.into()),
_ => unreachable!(),
}
}
pub fn time(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0).as_int() {
min => match args.remove(0).as_int() {
max if max < min => {
let i = rand::thread_rng().gen_range(max..=min);
Ok(Datetime::from(i).into())
}
max => {
let i = rand::thread_rng().gen_range(min..=max);
Ok(Datetime::from(i).into())
}
},
},
0 => {
let i = rand::random::<i64>();
Ok(Datetime::from(i).into())
}
_ => unreachable!(),
}
}
pub fn uuid(_: &Runtime, _: Vec<Value>) -> Result<Value, Error> {
Ok(Uuid::new_v4().to_string().into())
}

10
src/fnc/script.rs Normal file
View file

@ -0,0 +1,10 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::script::Script;
use crate::sql::value::Value;
pub fn run(ctx: &Runtime, expr: Script) -> Result<Value, Error> {
Err(Error::LanguageError {
message: String::from("Embedded functions are not yet supported."),
})
}

99
src/fnc/string.rs Normal file
View file

@ -0,0 +1,99 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::value::Value;
use slug::slugify;
pub fn concat(_: &Runtime, args: Vec<Value>) -> Result<Value, Error> {
Ok(args.into_iter().map(|x| x.as_strand().value).collect::<Vec<_>>().concat().into())
}
pub fn contains(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let str = args.remove(0).as_strand().value;
Ok(val.contains(&str).into())
}
pub fn ends_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
Ok(val.ends_with(&chr).into())
}
pub fn join(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let chr = args.remove(0).as_strand().value;
let val = args.into_iter().map(|x| x.as_strand().value);
let val = val.collect::<Vec<_>>().join(&chr);
Ok(val.into())
}
pub fn length(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let num = val.chars().count() as i64;
Ok(num.into())
}
pub fn lowercase(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.to_lowercase().into())
}
pub fn repeat(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let num = args.remove(0).as_int() as usize;
Ok(val.repeat(num).into())
}
pub fn replace(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let old = args.remove(0).as_strand().value;
let new = args.remove(0).as_strand().value;
Ok(val.replace(&old, &new).into())
}
pub fn reverse(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.chars().rev().collect::<String>().into())
}
pub fn slice(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let beg = args.remove(0).as_int() as usize;
let lim = args.remove(0).as_int() as usize;
let val = val.chars().skip(beg).take(lim).collect::<String>();
Ok(val.into())
}
pub fn slug(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(slugify(&args.remove(0).as_strand().value).into())
}
pub fn split(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
let val = val.split(&chr).collect::<Vec<&str>>();
Ok(val.into())
}
pub fn starts_with(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand().value;
let chr = args.remove(0).as_strand().value;
Ok(val.starts_with(&chr).into())
}
pub fn substr(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0).as_strand();
let beg = args.remove(0).as_int() as usize;
let lim = args.remove(0).as_int() as usize;
let val = val.value.chars().skip(beg).take(lim).collect::<String>();
Ok(val.into())
}
pub fn trim(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.trim().into())
}
pub fn uppercase(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.to_uppercase().into())
}
pub fn words(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_strand().value.split(" ").collect::<Vec<&str>>().into())
}

154
src/fnc/time.rs Normal file
View file

@ -0,0 +1,154 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::datetime::Datetime;
use crate::sql::value::Value;
use chrono::Datelike;
use chrono::DurationRound;
use chrono::Timelike;
use chrono::Utc;
pub fn day(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().day().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.day().into()),
_ => Ok(Value::None),
},
}
}
pub fn floor(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Datetime(v) => match args.remove(0) {
Value::Duration(w) => match chrono::Duration::from_std(w.value) {
Ok(d) => match v.value.duration_trunc(d) {
Ok(v) => Ok(v.into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
},
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn hour(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().hour().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.hour().into()),
_ => Ok(Value::None),
},
}
}
pub fn mins(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().minute().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.minute().into()),
_ => Ok(Value::None),
},
}
}
pub fn month(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().day().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.day().into()),
_ => Ok(Value::None),
},
}
}
pub fn nano(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().timestamp_nanos().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.timestamp_nanos().into()),
_ => Ok(Value::None),
},
}
}
pub fn now(_: &Runtime, _: Vec<Value>) -> Result<Value, Error> {
Ok(Datetime::default().into())
}
pub fn round(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Datetime(v) => match args.remove(0) {
Value::Duration(w) => match chrono::Duration::from_std(w.value) {
Ok(d) => match v.value.duration_round(d) {
Ok(v) => Ok(v.into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
},
_ => Ok(Value::None),
},
_ => Ok(Value::None),
}
}
pub fn secs(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().second().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.second().into()),
_ => Ok(Value::None),
},
}
}
pub fn unix(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().timestamp().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.timestamp().into()),
_ => Ok(Value::None),
},
}
}
pub fn wday(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().weekday().number_from_monday().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.weekday().number_from_monday().into()),
_ => Ok(Value::None),
},
}
}
pub fn week(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().iso_week().week().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.iso_week().week().into()),
_ => Ok(Value::None),
},
}
}
pub fn yday(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().ordinal().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.ordinal().into()),
_ => Ok(Value::None),
},
}
}
pub fn year(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
0 => Ok(Utc::now().year().into()),
_ => match args.remove(0) {
Value::Datetime(v) => Ok(v.value.year().into()),
_ => Ok(Value::None),
},
}
}

106
src/fnc/type.rs Normal file
View file

@ -0,0 +1,106 @@
use crate::dbs::Runtime;
use crate::err::Error;
use crate::sql::geometry::Geometry;
use crate::sql::number::Number;
use crate::sql::thing::Thing;
use crate::sql::value::Value;
pub fn bool(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0).is_truthy() {
true => Ok(Value::True),
false => Ok(Value::False),
}
}
pub fn datetime(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Datetime(_) => Ok(val),
_ => Ok(Value::Datetime(val.as_datetime())),
}
}
pub fn decimal(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Number(Number::Decimal(_)) => Ok(val),
_ => Ok(Value::Number(Number::Decimal(val.as_decimal()))),
}
}
pub fn duration(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Duration(_) => Ok(val),
_ => Ok(Value::Duration(val.as_duration())),
}
}
pub fn float(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Number(Number::Float(_)) => Ok(val),
_ => Ok(Value::Number(Number::Float(val.as_float()))),
}
}
pub fn int(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Number(Number::Int(_)) => Ok(val),
_ => Ok(Value::Number(Number::Int(val.as_int()))),
}
}
pub fn number(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Number(_) => Ok(val),
_ => Ok(Value::Number(val.as_number())),
}
}
pub fn point(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() {
2 => match args.remove(0) {
x => match args.remove(0) {
y => Ok((x.as_float(), y.as_float()).into()),
},
},
1 => match args.remove(0) {
Value::Array(v) if v.len() == 2 => Ok(v.as_point().into()),
Value::Geometry(v) => match v {
Geometry::Point(v) => Ok(v.into()),
_ => Ok(Value::None),
},
_ => Ok(Value::None),
},
_ => unreachable!(),
}
}
pub fn regex(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
match args.remove(0) {
Value::Strand(v) => Ok(Value::Regex(v.as_str().into())),
_ => Ok(Value::None),
}
}
pub fn string(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
let val = args.remove(0);
match val {
Value::Strand(_) => Ok(val),
_ => Ok(Value::Strand(val.as_strand())),
}
}
pub fn table(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(Value::Table(args.remove(0).as_strand().value.into()))
}
pub fn thing(_: &Runtime, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(Value::Thing(Thing {
tb: args.remove(0).as_strand().value,
id: args.remove(0).as_strand().value,
}))
}

101
src/fnc/util/geo/mod.rs Normal file
View file

@ -0,0 +1,101 @@
use crate::sql::geometry::Geometry;
use crate::sql::strand::Strand;
use geo::Point;
static BASE32: &[char] = &[
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k',
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
];
pub fn encode(v: Point<f64>, l: usize) -> Strand {
let mut max_lat = 90f64;
let mut min_lat = -90f64;
let mut max_lon = 180f64;
let mut min_lon = -180f64;
let mut bits: i8 = 0;
let mut hash: usize = 0;
let mut out = String::with_capacity(l);
while out.len() < l {
for _ in 0..5 {
if bits % 2 == 0 {
let mid = (max_lon + min_lon) / 2f64;
if v.x() > mid {
hash = (hash << 1) + 1usize;
min_lon = mid;
} else {
hash <<= 1;
max_lon = mid;
}
} else {
let mid = (max_lat + min_lat) / 2f64;
if v.y() > mid {
hash = (hash << 1) + 1usize;
min_lat = mid;
} else {
hash <<= 1;
max_lat = mid;
}
}
bits += 1;
}
out.push(BASE32[hash]);
hash = 0;
}
Strand::from(out)
}
pub fn decode(v: Strand) -> Geometry {
let mut max_lat = 90f64;
let mut min_lat = -90f64;
let mut max_lon = 180f64;
let mut min_lon = -180f64;
let mut mid: f64;
let mut long: bool = true;
for c in v.as_str().chars() {
let ord = c as usize;
let val = if (48..=57).contains(&ord) {
ord - 48
} else if (98..=104).contains(&ord) {
ord - 88
} else if (106..=107).contains(&ord) {
ord - 89
} else if (109..=110).contains(&ord) {
ord - 90
} else if (112..=122).contains(&ord) {
ord - 91
} else {
ord
};
for i in 0..5 {
let bit = (val >> (4 - i)) & 1usize;
if long {
mid = (max_lon + min_lon) / 2f64;
if bit == 1 {
min_lon = mid;
} else {
max_lon = mid;
}
} else {
mid = (max_lat + min_lat) / 2f64;
if bit == 1 {
min_lat = mid;
} else {
max_lat = mid;
}
}
long = !long;
}
}
let x = (min_lon + max_lon) / 2f64;
let y = (min_lat + max_lat) / 2f64;
(x, y).into()
}

1
src/fnc/util/http/mod.rs Normal file
View file

@ -0,0 +1 @@

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Bottom {
fn bottom(self, _c: i64) -> Number;
}
impl Bottom for Vec<Number> {
fn bottom(self, _c: i64) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Deviation {
fn deviation(self) -> Number;
}
impl Deviation for Vec<Number> {
fn deviation(self) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Interquartile {
fn interquartile(self) -> Number;
}
impl Interquartile for Vec<Number> {
fn interquartile(self) -> Number {
todo!()
}
}

13
src/fnc/util/math/mean.rs Normal file
View file

@ -0,0 +1,13 @@
use crate::sql::number::Number;
pub trait Mean {
fn mean(&self) -> Number;
}
impl Mean for Vec<Number> {
fn mean(&self) -> Number {
let len = Number::from(self.len());
let sum = self.iter().sum::<Number>();
sum / len
}
}

View file

@ -0,0 +1,12 @@
use crate::sql::number::Number;
pub trait Median {
fn median(&mut self) -> Number;
}
impl Median for Vec<Number> {
fn median(&mut self) -> Number {
self.sort();
self.remove(self.len() / 2)
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Midhinge {
fn midhinge(self) -> Number;
}
impl Midhinge for Vec<Number> {
fn midhinge(self) -> Number {
todo!()
}
}

18
src/fnc/util/math/mod.rs Normal file
View file

@ -0,0 +1,18 @@
// TODO
// https://docs.rs/statistical/1.0.0/src/statistical/stats_.rs.html
// https://rust-lang-nursery.github.io/rust-cookbook/science/mathematics/statistics.html
pub mod bottom;
pub mod deviation;
pub mod interquartile;
pub mod mean;
pub mod median;
pub mod midhinge;
pub mod mode;
pub mod nearestrank;
pub mod percentile;
pub mod quartile;
pub mod spread;
pub mod top;
pub mod trimean;
pub mod variance;

11
src/fnc/util/math/mode.rs Normal file
View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Mode {
fn mode(self) -> Number;
}
impl Mode for Vec<Number> {
fn mode(self) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Nearestrank {
fn nearestrank(self, _: Number) -> Number;
}
impl Nearestrank for Vec<Number> {
fn nearestrank(self, _: Number) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Percentile {
fn percentile(self, _: Number) -> Number;
}
impl Percentile for Vec<Number> {
fn percentile(self, _: Number) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Quartile {
fn quartile(self) -> Number;
}
impl Quartile for Vec<Number> {
fn quartile(self) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Spread {
fn spread(self) -> Number;
}
impl Spread for Vec<Number> {
fn spread(self) -> Number {
todo!()
}
}

11
src/fnc/util/math/top.rs Normal file
View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Top {
fn top(self, _c: i64) -> Number;
}
impl Top for Vec<Number> {
fn top(self, _c: i64) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Trimean {
fn trimean(self) -> Number;
}
impl Trimean for Vec<Number> {
fn trimean(self) -> Number {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::sql::number::Number;
pub trait Variance {
fn variance(self) -> Number;
}
impl Variance for Vec<Number> {
fn variance(self) -> Number {
todo!()
}
}

3
src/fnc/util/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod geo;
pub mod http;
pub mod math;