Add further SQL function implementations
This commit is contained in:
parent
6e031110bb
commit
f3de9095ae
36 changed files with 2006 additions and 322 deletions
91
src/fnc/args.rs
Normal file
91
src/fnc/args.rs
Normal 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
73
src/fnc/array.rs
Normal 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),
|
||||
}
|
||||
}
|
|
@ -1,48 +1,74 @@
|
|||
use crate::dbs::Runtime;
|
||||
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() {
|
||||
"bool" => bool(ctx, val),
|
||||
"int" => int(ctx, val),
|
||||
"float" => float(ctx, val),
|
||||
"string" => string(ctx, val),
|
||||
"number" => number(ctx, val),
|
||||
"decimal" => number(ctx, val),
|
||||
"decimal" => decimal(ctx, val),
|
||||
"datetime" => datetime(ctx, val),
|
||||
"duration" => duration(ctx, val),
|
||||
_ => Ok(val),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool(ctx: &Runtime, val: Literal) -> Result<Literal, Error> {
|
||||
match val.as_bool() {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
pub fn bool(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
match val.is_truthy() {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int(ctx: &Runtime, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Int(val.as_int()))
|
||||
pub fn int(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
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> {
|
||||
Ok(Literal::Float(val.as_float()))
|
||||
pub fn float(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
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> {
|
||||
Ok(Literal::Strand(val.as_strand()))
|
||||
pub fn number(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
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> {
|
||||
Ok(Literal::Number(val.as_number()))
|
||||
pub fn decimal(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
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> {
|
||||
Ok(Literal::Datetime(val.as_datetime()))
|
||||
pub fn string(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
match val {
|
||||
Value::Strand(_) => Ok(val),
|
||||
_ => Ok(Value::Strand(val.as_strand())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn duration(ctx: &Runtime, val: Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::Duration(val.as_duration()))
|
||||
pub fn datetime(_: &Runtime, val: Value) -> Result<Value, Error> {
|
||||
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
17
src/fnc/count.rs
Normal 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
135
src/fnc/crypto.rs
Normal 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())
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use crate::dbs::Runtime;
|
||||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn run(ctx: &Runtime, args: Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
pub fn run(_: &Runtime, expr: Value) -> Result<Value, Error> {
|
||||
Ok(expr)
|
||||
}
|
||||
|
|
116
src/fnc/geo.rs
Normal file
116
src/fnc/geo.rs
Normal 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
27
src/fnc/http.rs
Normal 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
81
src/fnc/is.rs
Normal 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
178
src/fnc/math.rs
Normal 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),
|
||||
}
|
||||
}
|
163
src/fnc/mod.rs
163
src/fnc/mod.rs
|
@ -1,11 +1,168 @@
|
|||
use crate::dbs::Runtime;
|
||||
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 count;
|
||||
pub mod crypto;
|
||||
pub mod future;
|
||||
pub mod geo;
|
||||
pub mod http;
|
||||
pub mod is;
|
||||
pub mod math;
|
||||
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> {
|
||||
todo!()
|
||||
pub fn run(ctx: &Runtime, name: &String, args: Vec<Value>) -> Result<Value, Error> {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,352 +1,202 @@
|
|||
use crate::err::Error;
|
||||
use crate::sql::literal::Literal;
|
||||
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> {
|
||||
match a.as_bool() {
|
||||
pub fn or(a: Value, b: Value) -> Result<Value, Error> {
|
||||
match a.is_truthy() {
|
||||
true => Ok(a),
|
||||
false => Ok(b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn and(a: Literal, b: Literal) -> Result<Literal, Error> {
|
||||
match a.as_bool() {
|
||||
true => match b.as_bool() {
|
||||
_ => Ok(b),
|
||||
},
|
||||
pub fn and(a: Value, b: Value) -> Result<Value, Error> {
|
||||
match a.is_truthy() {
|
||||
true => Ok(b),
|
||||
false => Ok(a),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a + b))
|
||||
pub fn add(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(a.add(b))
|
||||
}
|
||||
|
||||
pub fn sub(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a - b))
|
||||
pub fn sub(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(a.sub(b))
|
||||
}
|
||||
|
||||
pub fn mul(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a * b))
|
||||
pub fn mul(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(a.mul(b))
|
||||
}
|
||||
|
||||
pub fn div(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
let a = a.as_number();
|
||||
let b = b.as_number();
|
||||
Ok(Literal::from(a / b))
|
||||
pub fn div(a: Value, b: Value) -> Result<Value, Error> {
|
||||
Ok(a.div(b))
|
||||
}
|
||||
|
||||
pub fn exact(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
Ok(Literal::from(a == b))
|
||||
pub fn exact(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
Ok(Value::from(a == b))
|
||||
}
|
||||
|
||||
pub fn equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::None => Ok(Literal::from(b.is_none() == true)),
|
||||
Literal::Null => Ok(Literal::from(b.is_null() == 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::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 equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.equal(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::None => Ok(Literal::from(b.is_none() != true)),
|
||||
Literal::Null => Ok(Literal::from(b.is_null() != 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 not_equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.equal(b) {
|
||||
true => Ok(Value::False),
|
||||
false => Ok(Value::True),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(ref v) => match v.value.iter().all(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => unreachable!(),
|
||||
}) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
},
|
||||
_ => equal(a, b),
|
||||
pub fn all_equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.all_equal(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn any_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(ref v) => match v.value.iter().any(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => unreachable!(),
|
||||
}) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
},
|
||||
_ => equal(a, b),
|
||||
pub fn any_equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.any_equal(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn like(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
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 like(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.fuzzy(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn less_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.le(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
pub fn not_like(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.fuzzy(b) {
|
||||
true => Ok(Value::False),
|
||||
false => Ok(Value::True),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn more_than(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.gt(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
pub fn all_like(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.all_fuzzy(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn more_than_or_equal(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a.ge(&b) {
|
||||
true => Ok(Literal::True),
|
||||
false => Ok(Literal::False),
|
||||
pub fn any_like(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.any_fuzzy(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => match v.value.iter().any(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => 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 less_than(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.lt(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_contain(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => match v.value.iter().any(|x| match x {
|
||||
Value::Literal(v) => equal(v, b).is_ok(),
|
||||
_ => 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 less_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.le(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_all(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn more_than(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.gt(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_some(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn more_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.ge(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contain_none(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match a {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn contain(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.contains(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn not_contain(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.contains(b) {
|
||||
true => Ok(Value::False),
|
||||
false => Ok(Value::True),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not_inside(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn contain_all(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.contains_all(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_all(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn contain_any(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.contains_any(b) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_some(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn contain_none(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match a.contains_any(b) {
|
||||
true => Ok(Value::False),
|
||||
false => Ok(Value::True),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inside_none(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Array(v) => todo!(),
|
||||
Literal::Strand(v) => todo!(),
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn inside(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match b.contains(a) {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersects(a: &Literal, b: &Literal) -> Result<Literal, Error> {
|
||||
match b {
|
||||
Literal::Polygon(v) => todo!(),
|
||||
_ => Ok(Literal::False),
|
||||
pub fn not_inside(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||
match b.contains(a) {
|
||||
true => Ok(Value::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]
|
||||
fn or_true() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(2);
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(2);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -367,8 +217,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn or_false_one() {
|
||||
let one = Literal::from(0);
|
||||
let two = Literal::from(1);
|
||||
let one = Value::from(0);
|
||||
let two = Value::from(1);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -377,8 +227,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn or_false_two() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(0);
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(0);
|
||||
let res = or(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -387,8 +237,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn and_true() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(2);
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(2);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -397,8 +247,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn and_false_one() {
|
||||
let one = Literal::from(0);
|
||||
let two = Literal::from(1);
|
||||
let one = Value::from(0);
|
||||
let two = Value::from(1);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -407,8 +257,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn and_false_two() {
|
||||
let one = Literal::from(1);
|
||||
let two = Literal::from(0);
|
||||
let one = Value::from(1);
|
||||
let two = Value::from(0);
|
||||
let res = and(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
|
@ -417,9 +267,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn add_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = add(&one, &two);
|
||||
let one = Value::from(5);
|
||||
let two = Value::from(4);
|
||||
let res = add(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("9", format!("{}", out));
|
||||
|
@ -427,9 +277,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn sub_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = sub(&one, &two);
|
||||
let one = Value::from(5);
|
||||
let two = Value::from(4);
|
||||
let res = sub(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1", format!("{}", out));
|
||||
|
@ -437,9 +287,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn mul_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = mul(&one, &two);
|
||||
let one = Value::from(5);
|
||||
let two = Value::from(4);
|
||||
let res = mul(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("20", format!("{}", out));
|
||||
|
@ -447,9 +297,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn div_basic() {
|
||||
let one = Literal::from(5);
|
||||
let two = Literal::from(4);
|
||||
let res = div(&one, &two);
|
||||
let one = Value::from(5);
|
||||
let two = Value::from(4);
|
||||
let res = div(one, two);
|
||||
assert!(res.is_ok());
|
||||
let out = res.unwrap();
|
||||
assert_eq!("1.25", format!("{}", out));
|
||||
|
|
144
src/fnc/parse.rs
Normal file
144
src/fnc/parse.rs
Normal 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
140
src/fnc/rand.rs
Normal 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
10
src/fnc/script.rs
Normal 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
99
src/fnc/string.rs
Normal 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
154
src/fnc/time.rs
Normal 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
106
src/fnc/type.rs
Normal 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
101
src/fnc/util/geo/mod.rs
Normal 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
1
src/fnc/util/http/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
11
src/fnc/util/math/bottom.rs
Normal file
11
src/fnc/util/math/bottom.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/deviation.rs
Normal file
11
src/fnc/util/math/deviation.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/interquartile.rs
Normal file
11
src/fnc/util/math/interquartile.rs
Normal 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
13
src/fnc/util/math/mean.rs
Normal 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
|
||||
}
|
||||
}
|
12
src/fnc/util/math/median.rs
Normal file
12
src/fnc/util/math/median.rs
Normal 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)
|
||||
}
|
||||
}
|
11
src/fnc/util/math/midhinge.rs
Normal file
11
src/fnc/util/math/midhinge.rs
Normal 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
18
src/fnc/util/math/mod.rs
Normal 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
11
src/fnc/util/math/mode.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/nearestrank.rs
Normal file
11
src/fnc/util/math/nearestrank.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/percentile.rs
Normal file
11
src/fnc/util/math/percentile.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/quartile.rs
Normal file
11
src/fnc/util/math/quartile.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/spread.rs
Normal file
11
src/fnc/util/math/spread.rs
Normal 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
11
src/fnc/util/math/top.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/trimean.rs
Normal file
11
src/fnc/util/math/trimean.rs
Normal 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!()
|
||||
}
|
||||
}
|
11
src/fnc/util/math/variance.rs
Normal file
11
src/fnc/util/math/variance.rs
Normal 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
3
src/fnc/util/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod geo;
|
||||
pub mod http;
|
||||
pub mod math;
|
Loading…
Reference in a new issue