Refactor function dispatch (#125)
This commit is contained in:
parent
ffeb56fc7e
commit
de7d9299fd
16 changed files with 970 additions and 1047 deletions
|
@ -1,83 +1,215 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::{Number, Strand};
|
||||
|
||||
pub enum Args {
|
||||
None,
|
||||
Any,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
NoneOne,
|
||||
NoneTwo,
|
||||
NoneOneTwo,
|
||||
OneTwo,
|
||||
/// Implemented by types that are commonly used, in a certain way, as arguments.
|
||||
pub trait FromArg: Sized {
|
||||
/// Potentially fallible conversion from a Value to an argument. Errors will be propagated
|
||||
/// to the caller, although it is also possible to return a none/null Value.
|
||||
fn from_arg(arg: Value) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
pub fn check(
|
||||
ctx: &Context,
|
||||
name: &str,
|
||||
args: Vec<Value>,
|
||||
size: Args,
|
||||
func: fn(&Context, Vec<Value>) -> Result<Value, Error>,
|
||||
) -> Result<Value, Error> {
|
||||
match size {
|
||||
Args::None => match args.len() {
|
||||
0 => func(ctx, args),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
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::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("The function expects 1 argument."),
|
||||
}),
|
||||
},
|
||||
Args::Two => match args.len() {
|
||||
2 => func(ctx, args),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("The function expects 2 arguments."),
|
||||
}),
|
||||
},
|
||||
Args::Three => match args.len() {
|
||||
3 => func(ctx, args),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("The function expects 3 arguments."),
|
||||
}),
|
||||
},
|
||||
Args::NoneOne => match args.len() {
|
||||
0 | 1 => func(ctx, args),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
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::InvalidArguments {
|
||||
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::InvalidArguments {
|
||||
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::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("The function expects 1 or 2 arguments."),
|
||||
}),
|
||||
},
|
||||
Args::Any => func(ctx, args),
|
||||
impl FromArg for Value {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for String {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Strand {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_strand())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for Number {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_number())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for f64 {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_float())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for i64 {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_int())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArg for usize {
|
||||
fn from_arg(arg: Value) -> Result<Self, Error> {
|
||||
Ok(arg.as_int() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FromArgs: Sized {
|
||||
/// Convert a collection of argument values into a certain argument format, failing if there are
|
||||
/// too many or too few arguments, or if one of the arguments could not be converted.
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
// Take ownership of the raw arguments collection, and assume responsibility of validating the
|
||||
// number of arguments and converting them as necessary.
|
||||
impl FromArgs for Vec<Value> {
|
||||
fn from_args(_name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
Ok(args)
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions take a fixed number of arguments.
|
||||
// The len must match the number of type idents that follow.
|
||||
macro_rules! impl_tuple {
|
||||
($len:expr, $( $T:ident ),*) => {
|
||||
impl<$($T:FromArg),*> FromArgs for ($($T,)*) {
|
||||
#[allow(non_snake_case)]
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let [$($T),*]: [Value; $len] = args.try_into().map_err(|_| Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
// This match will be optimized away.
|
||||
message: match $len {
|
||||
0 => String::from("Expected no arguments."),
|
||||
1 => String::from("Expected 1 argument."),
|
||||
_ => format!("Expected {} arguments.", $len),
|
||||
}
|
||||
})?;
|
||||
Ok(($($T::from_arg($T)?,)*))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It is possible to add larger sequences to support higher quantities of fixed arguments.
|
||||
impl_tuple!(0,);
|
||||
impl_tuple!(1, A);
|
||||
impl_tuple!(2, A, B);
|
||||
impl_tuple!(3, A, B, C);
|
||||
|
||||
// Some functions take a single, optional argument, or no arguments at all.
|
||||
impl<A: FromArg> FromArgs for (Option<A>,) {
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let err = || Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("Expected 0 or 1 arguments."),
|
||||
};
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let a = match args.next() {
|
||||
Some(a) => Some(A::from_arg(a)?),
|
||||
None => None,
|
||||
};
|
||||
if args.next().is_some() {
|
||||
// Too many.
|
||||
return Err(err());
|
||||
}
|
||||
Ok((a,))
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions take 1 or 2 arguments, so the second argument is optional.
|
||||
impl<A: FromArg, B: FromArg> FromArgs for (A, Option<B>) {
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let err = || Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("Expected 1 or 2 arguments."),
|
||||
};
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let a = A::from_arg(args.next().ok_or_else(err)?)?;
|
||||
let b = match args.next() {
|
||||
Some(b) => Some(B::from_arg(b)?),
|
||||
None => None,
|
||||
};
|
||||
if args.next().is_some() {
|
||||
// Too many.
|
||||
return Err(err());
|
||||
}
|
||||
Ok((a, b))
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions take 0, 1, or 2 arguments, so both arguments are optional.
|
||||
// It is safe to assume that, if the first argument is None, the second argument will also be None.
|
||||
impl<A: FromArg, B: FromArg> FromArgs for (Option<A>, Option<B>) {
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let err = || Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("Expected 0, 1, or 2 arguments."),
|
||||
};
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let a = match args.next() {
|
||||
Some(a) => Some(A::from_arg(a)?),
|
||||
None => None,
|
||||
};
|
||||
let b = match args.next() {
|
||||
Some(b) => Some(B::from_arg(b)?),
|
||||
None => None,
|
||||
};
|
||||
if args.next().is_some() {
|
||||
// Too many.
|
||||
return Err(err());
|
||||
}
|
||||
Ok((a, b))
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions optionally take 2 arguments, or don't take any at all.
|
||||
impl<A: FromArg, B: FromArg> FromArgs for (Option<(A, B)>,) {
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let err = || Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("Expected 0 or 2 arguments."),
|
||||
};
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let a = match args.next() {
|
||||
Some(a) => Some(A::from_arg(a)?),
|
||||
None => None,
|
||||
};
|
||||
let b = match args.next() {
|
||||
Some(b) => Some(B::from_arg(b)?),
|
||||
None => None,
|
||||
};
|
||||
if a.is_some() != b.is_some() || args.next().is_some() {
|
||||
// One argument, or too many arguments.
|
||||
return Err(err());
|
||||
}
|
||||
Ok((a.zip(b),))
|
||||
}
|
||||
}
|
||||
|
||||
// Some functions take 1, 2, or 3 arguments. It is safe to assume that, if the second argument is
|
||||
// None, the third argument will also be None.
|
||||
impl<A: FromArg, B: FromArg, C: FromArg> FromArgs for (A, Option<B>, Option<C>) {
|
||||
fn from_args(name: &str, args: Vec<Value>) -> Result<Self, Error> {
|
||||
let err = || Error::InvalidArguments {
|
||||
name: name.to_owned(),
|
||||
message: String::from("Expected 1, 2, or 3 arguments."),
|
||||
};
|
||||
|
||||
let mut args = args.into_iter();
|
||||
let a = A::from_arg(args.next().ok_or_else(err)?)?;
|
||||
let b = match args.next() {
|
||||
Some(b) => Some(B::from_arg(b)?),
|
||||
None => None,
|
||||
};
|
||||
let c = match args.next() {
|
||||
Some(c) => Some(C::from_arg(c)?),
|
||||
None => None,
|
||||
};
|
||||
if args.next().is_some() {
|
||||
// Too many.
|
||||
return Err(err());
|
||||
}
|
||||
Ok((a, b, c))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Combine;
|
||||
use crate::sql::array::Concat;
|
||||
|
@ -8,9 +7,9 @@ use crate::sql::array::Union;
|
|||
use crate::sql::array::Uniq;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn concat(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => match args.remove(0) {
|
||||
pub fn concat((left, right): (Value, Value)) -> Result<Value, Error> {
|
||||
match left {
|
||||
Value::Array(v) => match right {
|
||||
Value::Array(w) => Ok(v.concat(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -18,9 +17,9 @@ pub fn concat(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn combine(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => match args.remove(0) {
|
||||
pub fn combine((left, right): (Value, Value)) -> Result<Value, Error> {
|
||||
match left {
|
||||
Value::Array(v) => match right {
|
||||
Value::Array(w) => Ok(v.combine(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -28,9 +27,9 @@ pub fn combine(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn difference(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => match args.remove(0) {
|
||||
pub fn difference((left, right): (Value, Value)) -> Result<Value, Error> {
|
||||
match left {
|
||||
Value::Array(v) => match right {
|
||||
Value::Array(w) => Ok(v.difference(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -38,16 +37,16 @@ pub fn difference(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn distinct(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn distinct((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Array(v) => Ok(v.uniq().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersect(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => match args.remove(0) {
|
||||
pub fn intersect((left, right): (Value, Value)) -> Result<Value, Error> {
|
||||
match left {
|
||||
Value::Array(v) => match right {
|
||||
Value::Array(w) => Ok(v.intersect(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -55,59 +54,49 @@ pub fn intersect(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn len(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn len((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Array(v) => Ok(v.len().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => match args.remove(0) {
|
||||
Value::Array(mut v) => match args.remove(0) {
|
||||
// If "asc", sort ascending
|
||||
Value::Strand(s) if s.as_str() == "asc" => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If "desc", sort descending
|
||||
Value::Strand(s) if s.as_str() == "desc" => {
|
||||
v.sort_unstable_by(|a, b| b.cmp(a));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If true, sort ascending
|
||||
Value::True => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If false, sort descending
|
||||
Value::False => {
|
||||
v.sort_unstable_by(|a, b| b.cmp(a));
|
||||
Ok(v.into())
|
||||
}
|
||||
// Sort ascending by default
|
||||
_ => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
},
|
||||
v => Ok(v),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Array(mut v) => {
|
||||
pub fn sort((array, order): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(mut v) => match order {
|
||||
// If "asc", sort ascending
|
||||
Some(Value::Strand(s)) if s.as_str() == "asc" => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If "desc", sort descending
|
||||
Some(Value::Strand(s)) if s.as_str() == "desc" => {
|
||||
v.sort_unstable_by(|a, b| b.cmp(a));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If true, sort ascending
|
||||
Some(Value::True) => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
// If false, sort descending
|
||||
Some(Value::False) => {
|
||||
v.sort_unstable_by(|a, b| b.cmp(a));
|
||||
Ok(v.into())
|
||||
}
|
||||
// Sort ascending by default
|
||||
_ => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
}
|
||||
v => Ok(v),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
v => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => match args.remove(0) {
|
||||
pub fn union((left, right): (Value, Value)) -> Result<Value, Error> {
|
||||
match left {
|
||||
Value::Array(v) => match right {
|
||||
Value::Array(w) => Ok(v.union(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -117,12 +106,11 @@ pub fn union(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
|
||||
pub mod sort {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn asc(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn asc((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(mut v) => {
|
||||
v.sort_unstable_by(|a, b| a.cmp(b));
|
||||
Ok(v.into())
|
||||
|
@ -131,8 +119,8 @@ pub mod sort {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn desc(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn desc((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(mut v) => {
|
||||
v.sort_unstable_by(|a, b| b.cmp(a));
|
||||
Ok(v.into())
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn count(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
1 => match args.remove(0) {
|
||||
Value::Array(v) => Ok(v.iter().filter(|v| v.is_truthy()).count().into()),
|
||||
v => Ok((v.is_truthy() as i64).into()),
|
||||
},
|
||||
0 => Ok(1.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
pub fn count((arg,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
Ok(arg
|
||||
.map(|val| match val {
|
||||
Value::Array(v) => v.iter().filter(|v| v.is_truthy()).count().into(),
|
||||
v => (v.is_truthy() as i64).into(),
|
||||
})
|
||||
.unwrap_or_else(|| 1.into()))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use md5::Digest;
|
||||
|
@ -7,33 +6,33 @@ use sha1::Sha1;
|
|||
use sha2::Sha256;
|
||||
use sha2::Sha512;
|
||||
|
||||
pub fn md5(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn md5((arg,): (String,)) -> Result<Value, Error> {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(args.remove(0).as_string().as_str());
|
||||
hasher.update(arg.as_str());
|
||||
let val = hasher.finalize();
|
||||
let val = format!("{:x}", val);
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
pub fn sha1(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn sha1((arg,): (String,)) -> Result<Value, Error> {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(args.remove(0).as_string().as_str());
|
||||
hasher.update(arg.as_str());
|
||||
let val = hasher.finalize();
|
||||
let val = format!("{:x}", val);
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
pub fn sha256(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn sha256((arg,): (String,)) -> Result<Value, Error> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(args.remove(0).as_string().as_str());
|
||||
hasher.update(arg.as_str());
|
||||
let val = hasher.finalize();
|
||||
let val = format!("{:x}", val);
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
pub fn sha512(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn sha512((arg,): (String,)) -> Result<Value, Error> {
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.update(args.remove(0).as_string().as_str());
|
||||
hasher.update(arg.as_str());
|
||||
let val = hasher.finalize();
|
||||
let val = format!("{:x}", val);
|
||||
Ok(val.into())
|
||||
|
@ -81,7 +80,6 @@ macro_rules! bounded_verify_password {
|
|||
pub mod argon2 {
|
||||
|
||||
use super::COST_ALLOWANCE;
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use argon2::{
|
||||
|
@ -90,9 +88,7 @@ pub mod argon2 {
|
|||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
pub fn cmp(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [hash, pass] = args.map(Value::as_string);
|
||||
pub fn cmp((hash, pass): (String, String)) -> Result<Value, Error> {
|
||||
type Params<'a> = <Argon2<'a> as PasswordHasher>::Params;
|
||||
Ok(PasswordHash::new(&hash)
|
||||
.ok()
|
||||
|
@ -107,9 +103,8 @@ pub mod argon2 {
|
|||
.into())
|
||||
}
|
||||
|
||||
pub fn gen(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn gen((pass,): (String,)) -> Result<Value, Error> {
|
||||
let algo = Argon2::default();
|
||||
let pass = args.remove(0).as_string();
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let hash = algo.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
|
||||
Ok(hash.into())
|
||||
|
@ -119,7 +114,6 @@ pub mod argon2 {
|
|||
pub mod pbkdf2 {
|
||||
|
||||
use super::COST_ALLOWANCE;
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use pbkdf2::{
|
||||
|
@ -128,9 +122,7 @@ pub mod pbkdf2 {
|
|||
};
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
pub fn cmp(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [hash, pass] = args.map(Value::as_string);
|
||||
pub fn cmp((hash, pass): (String, String)) -> Result<Value, Error> {
|
||||
type Params = <Pbkdf2 as PasswordHasher>::Params;
|
||||
Ok(PasswordHash::new(&hash)
|
||||
.ok()
|
||||
|
@ -147,8 +139,7 @@ pub mod pbkdf2 {
|
|||
.into())
|
||||
}
|
||||
|
||||
pub fn gen(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let pass = args.remove(0).as_string();
|
||||
pub fn gen((pass,): (String,)) -> Result<Value, Error> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let hash = Pbkdf2.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
|
||||
Ok(hash.into())
|
||||
|
@ -157,7 +148,6 @@ pub mod pbkdf2 {
|
|||
|
||||
pub mod scrypt {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use rand::rngs::OsRng;
|
||||
|
@ -166,9 +156,7 @@ pub mod scrypt {
|
|||
Scrypt,
|
||||
};
|
||||
|
||||
pub fn cmp(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [hash, pass] = args.map(Value::as_string);
|
||||
pub fn cmp((hash, pass): (String, String)) -> Result<Value, Error> {
|
||||
type Params = <Scrypt as PasswordHasher>::Params;
|
||||
Ok(PasswordHash::new(&hash)
|
||||
.ok()
|
||||
|
@ -184,8 +172,7 @@ pub mod scrypt {
|
|||
.into())
|
||||
}
|
||||
|
||||
pub fn gen(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let pass = args.remove(0).as_string();
|
||||
pub fn gen((pass,): (String,)) -> Result<Value, Error> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let hash = Scrypt.hash_password(pass.as_ref(), salt.as_ref()).unwrap().to_string();
|
||||
Ok(hash.into())
|
||||
|
@ -194,19 +181,15 @@ pub mod scrypt {
|
|||
|
||||
pub mod bcrypt {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use bcrypt;
|
||||
|
||||
pub fn cmp(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [hash, pass] = args.map(Value::as_string);
|
||||
pub fn cmp((hash, pass): (String, String)) -> Result<Value, Error> {
|
||||
Ok(bcrypt::verify(pass, &hash).unwrap_or(false).into())
|
||||
}
|
||||
|
||||
pub fn gen(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let pass = args.remove(0).as_string();
|
||||
pub fn gen((pass,): (String,)) -> Result<Value, Error> {
|
||||
let hash = bcrypt::hash(pass, bcrypt::DEFAULT_COST).unwrap();
|
||||
Ok(hash.into())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::geometry::Geometry;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -7,8 +6,8 @@ use geo::algorithm::bearing::Bearing;
|
|||
use geo::algorithm::centroid::Centroid;
|
||||
use geo::algorithm::haversine_distance::HaversineDistance;
|
||||
|
||||
pub fn area(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn area((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Geometry(v) => match v {
|
||||
Geometry::Point(v) => Ok(v.signed_area().into()),
|
||||
Geometry::Line(v) => Ok(v.signed_area().into()),
|
||||
|
@ -24,9 +23,9 @@ pub fn area(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn bearing(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Geometry(Geometry::Point(v)) => match args.remove(0) {
|
||||
pub fn bearing((a, b): (Value, Value)) -> Result<Value, Error> {
|
||||
match a {
|
||||
Value::Geometry(Geometry::Point(v)) => match b {
|
||||
Value::Geometry(Geometry::Point(w)) => Ok(v.bearing(w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -34,8 +33,8 @@ pub fn bearing(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn centroid(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn centroid((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Geometry(v) => match v {
|
||||
Geometry::Point(v) => Ok(v.centroid().into()),
|
||||
Geometry::Line(v) => match v.centroid() {
|
||||
|
@ -69,9 +68,9 @@ pub fn centroid(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn distance(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Geometry(Geometry::Point(v)) => match args.remove(0) {
|
||||
pub fn distance((from, to): (Value, Value)) -> Result<Value, Error> {
|
||||
match from {
|
||||
Value::Geometry(Geometry::Point(v)) => match to {
|
||||
Value::Geometry(Geometry::Point(w)) => Ok(v.haversine_distance(&w).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
|
@ -81,34 +80,29 @@ pub fn distance(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
|
||||
pub mod hash {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::fnc::util::geo;
|
||||
use crate::sql::geometry::Geometry;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn encode(_: &Context, 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::InvalidArguments {
|
||||
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).into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
pub fn encode((point, len): (Value, Option<usize>)) -> Result<Value, Error> {
|
||||
let len = match len {
|
||||
Some(len) if (1..=12).contains(&len) => len,
|
||||
None => 12,
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
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(match point {
|
||||
Value::Geometry(Geometry::Point(v)) => geo::encode(v, len).into(),
|
||||
_ => Value::None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn decode(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn decode((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Strand(v) => Ok(geo::decode(v).into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
|
|
|
@ -1,234 +1,156 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Strand;
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn head(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn head((_, _): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn get(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn get((_, _): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn put(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn put((_, _, _): (Value, Option<Value>, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn post(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn post((_, _, _): (Value, Option<Value>, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn patch(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn patch((_, _, _): (Value, Option<Value>, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http"))]
|
||||
pub async fn delete(_: &Context<'_>, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn delete((_, _): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
Err(Error::HttpDisabled)
|
||||
}
|
||||
|
||||
fn try_as_uri(fn_name: &str, value: Value) -> Result<Strand, Error> {
|
||||
match value {
|
||||
Value::Strand(uri) => Ok(uri),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: fn_name.to_owned(),
|
||||
// Assumption is that URI is first argument.
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn head(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => match args.remove(0) {
|
||||
Value::Strand(uri) => match args.remove(0) {
|
||||
Value::Object(opt) => crate::fnc::util::http::head(uri, opt).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::head"),
|
||||
message: String::from("The second argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn head((uri, opts): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::head", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::head"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::head(uri, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::head"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::head"),
|
||||
message: String::from("The function expects 1 or 2 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The second argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::head(uri, opts).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn get(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => match args.remove(0) {
|
||||
Value::Strand(uri) => match args.remove(0) {
|
||||
Value::Object(opt) => crate::fnc::util::http::get(uri, opt).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::get"),
|
||||
message: String::from("The second argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn get((uri, opts): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::get", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::get"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::get(uri, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::get"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::get"),
|
||||
message: String::from("The function expects 1 or 2 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The second argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::get(uri, opts).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn put(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
3 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => match args.remove(0) {
|
||||
Value::Object(opts) => crate::fnc::util::http::put(uri, val, opts).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::put"),
|
||||
message: String::from("The third argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn put((uri, body, opts): (Value, Option<Value>, Option<Value>)) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::put", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::put"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
2 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => crate::fnc::util::http::put(uri, val, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::put"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::put(uri, Value::Null, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::put"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::put"),
|
||||
message: String::from("The function expects 1, 2, or 3 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The third argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::put(uri, body.unwrap_or(Value::Null), opts).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn post(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
3 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => match args.remove(0) {
|
||||
Value::Object(opts) => crate::fnc::util::http::post(uri, val, opts).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::post"),
|
||||
message: String::from("The third argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn post(
|
||||
(uri, body, opts): (Value, Option<Value>, Option<Value>),
|
||||
) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::post", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::post"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
2 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => crate::fnc::util::http::post(uri, val, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::post"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::post(uri, Value::Null, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::post"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::post"),
|
||||
message: String::from("The function expects 1, 2, or 3 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The third argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::post(uri, body.unwrap_or(Value::Null), opts).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn patch(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
3 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => match args.remove(0) {
|
||||
Value::Object(opts) => crate::fnc::util::http::patch(uri, val, opts).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::patch"),
|
||||
message: String::from("The third argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn patch(
|
||||
(uri, body, opts): (Value, Option<Value>, Option<Value>),
|
||||
) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::patch", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::patch"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
2 => match (args.remove(0), args.remove(0)) {
|
||||
(Value::Strand(uri), val) => crate::fnc::util::http::patch(uri, val, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::patch"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::patch(uri, Value::Null, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::patch"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::patch"),
|
||||
message: String::from("The function expects 1, 2, or 3 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The third argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::patch(uri, body.unwrap_or(Value::Null), opts).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "http")]
|
||||
pub async fn delete(_: &Context<'_>, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => match args.remove(0) {
|
||||
Value::Strand(uri) => match args.remove(0) {
|
||||
Value::Object(opt) => crate::fnc::util::http::delete(uri, opt).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::delete"),
|
||||
message: String::from("The second argument should be an object."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub async fn delete((uri, opts): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
let uri = try_as_uri("http::delete", uri)?;
|
||||
|
||||
let opts = match opts {
|
||||
Some(Value::Object(opts)) => Some(opts),
|
||||
None => None,
|
||||
Some(_) => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("http::delete"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0) {
|
||||
Value::Strand(uri) => crate::fnc::util::http::delete(uri, None).await,
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::delete"),
|
||||
message: String::from("The first argument should be a string."),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
name: String::from("http::delete"),
|
||||
message: String::from("The function expects 1 or 2 arguments."),
|
||||
}),
|
||||
}
|
||||
message: String::from("The second argument should be an object."),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
crate::fnc::util::http::delete(uri, opts).await
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -11,58 +10,58 @@ use uuid::Uuid;
|
|||
#[rustfmt::skip] static LONGITUDE_RE: Lazy<Regex> = Lazy::new(|| Regex::new("^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$").unwrap());
|
||||
|
||||
#[inline]
|
||||
pub fn alphanum(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().chars().all(char::is_alphanumeric).into())
|
||||
pub fn alphanum((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(arg.chars().all(char::is_alphanumeric).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn alpha(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().chars().all(char::is_alphabetic).into())
|
||||
pub fn alpha((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(arg.chars().all(char::is_alphabetic).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ascii(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().is_ascii().into())
|
||||
pub fn ascii((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(arg.is_ascii().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn domain(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(addr::parse_domain_name(args.remove(0).as_string().as_str()).is_ok().into())
|
||||
pub fn domain((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(addr::parse_domain_name(arg.as_str()).is_ok().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn email(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(addr::parse_email_address(args.remove(0).as_string().as_str()).is_ok().into())
|
||||
pub fn email((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(addr::parse_email_address(arg.as_str()).is_ok().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hexadecimal(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().chars().all(|x| char::is_ascii_hexdigit(&x)).into())
|
||||
pub fn hexadecimal((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(arg.chars().all(|x| char::is_ascii_hexdigit(&x)).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn latitude(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(LATITUDE_RE.is_match(args.remove(0).as_string().as_str()).into())
|
||||
pub fn latitude((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(LATITUDE_RE.is_match(arg.as_str()).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn longitude(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(LONGITUDE_RE.is_match(args.remove(0).as_string().as_str()).into())
|
||||
pub fn longitude((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(LONGITUDE_RE.is_match(arg.as_str()).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn numeric(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().chars().all(char::is_numeric).into())
|
||||
pub fn numeric((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(arg.chars().all(char::is_numeric).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn semver(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(Version::parse(args.remove(0).as_string().as_str()).is_ok().into())
|
||||
pub fn semver((arg,): (String,)) -> Result<Value, Error> {
|
||||
Ok(Version::parse(arg.as_str()).is_ok().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uuid(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(match args.remove(0) {
|
||||
pub fn uuid((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
Value::Strand(v) => Uuid::parse_str(v.as_string().as_str()).is_ok().into(),
|
||||
Value::Uuid(_) => true.into(),
|
||||
_ => false.into(),
|
||||
|
@ -75,104 +74,104 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn alphanum() {
|
||||
let value = super::alphanum(&Default::default(), vec!["abc123".into()]).unwrap();
|
||||
let value = super::alphanum((String::from("abc123"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::alphanum(&Default::default(), vec!["y%*".into()]).unwrap();
|
||||
let value = super::alphanum((String::from("y%*"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alpha() {
|
||||
let value = super::alpha(&Default::default(), vec!["abc".into()]).unwrap();
|
||||
let value = super::alpha((String::from("abc"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::alpha(&Default::default(), vec!["1234".into()]).unwrap();
|
||||
let value = super::alpha((String::from("1234"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ascii() {
|
||||
let value = super::ascii(&Default::default(), vec!["abc".into()]).unwrap();
|
||||
let value = super::ascii((String::from("abc"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::ascii(&Default::default(), vec!["中国".into()]).unwrap();
|
||||
let value = super::ascii((String::from("中国"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn domain() {
|
||||
let value = super::domain(&Default::default(), vec!["食狮.中国".into()]).unwrap();
|
||||
let value = super::domain((String::from("食狮.中国"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::domain(&Default::default(), vec!["example-.com".into()]).unwrap();
|
||||
let value = super::domain((String::from("example-.com"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn email() {
|
||||
let input = vec!["user@[fd79:cdcb:38cc:9dd:f686:e06d:32f3:c123]".into()];
|
||||
let value = super::email(&Default::default(), input).unwrap();
|
||||
let input = (String::from("user@[fd79:cdcb:38cc:9dd:f686:e06d:32f3:c123]"),);
|
||||
let value = super::email(input).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let input = vec!["john..doe@example.com".into()];
|
||||
let value = super::email(&Default::default(), input).unwrap();
|
||||
let input = (String::from("john..doe@example.com"),);
|
||||
let value = super::email(input).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hexadecimal() {
|
||||
let value = super::hexadecimal(&Default::default(), vec!["00FF00".into()]).unwrap();
|
||||
let value = super::hexadecimal((String::from("00FF00"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::hexadecimal(&Default::default(), vec!["SurrealDB".into()]).unwrap();
|
||||
let value = super::hexadecimal((String::from("SurrealDB"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latitude() {
|
||||
let value = super::latitude(&Default::default(), vec!["-0.118092".into()]).unwrap();
|
||||
let value = super::latitude((String::from("-0.118092"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::latitude(&Default::default(), vec![12345.into()]).unwrap();
|
||||
let value = super::latitude((String::from("12345"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn longitude() {
|
||||
let value = super::longitude(&Default::default(), vec!["51.509865".into()]).unwrap();
|
||||
let value = super::longitude((String::from("51.509865"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::longitude(&Default::default(), vec![12345.into()]).unwrap();
|
||||
let value = super::longitude((String::from("12345"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numeric() {
|
||||
let value = super::numeric(&Default::default(), vec![12345.into()]).unwrap();
|
||||
let value = super::numeric((String::from("12345"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::numeric(&Default::default(), vec!["abcde".into()]).unwrap();
|
||||
let value = super::numeric((String::from("abcde"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn semver() {
|
||||
let value = super::semver(&Default::default(), vec!["1.0.0".into()]).unwrap();
|
||||
let value = super::semver((String::from("1.0.0"),)).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let value = super::semver(&Default::default(), vec!["1.0".into()]).unwrap();
|
||||
let value = super::semver((String::from("1.0"),)).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uuid() {
|
||||
let input = vec!["123e4567-e89b-12d3-a456-426614174000".into()];
|
||||
let value = super::uuid(&Default::default(), input).unwrap();
|
||||
let input = (String::from("123e4567-e89b-12d3-a456-426614174000").into(),);
|
||||
let value = super::uuid(input).unwrap();
|
||||
assert_eq!(value, Value::True);
|
||||
|
||||
let input = vec!["foo-bar".into()];
|
||||
let value = super::uuid(&Default::default(), input).unwrap();
|
||||
let input = (String::from("foo-bar").into(),);
|
||||
let value = super::uuid(input).unwrap();
|
||||
assert_eq!(value, Value::False);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::fnc::util::math::bottom::Bottom;
|
||||
use crate::fnc::util::math::deviation::Deviation;
|
||||
|
@ -16,48 +15,45 @@ use crate::fnc::util::math::variance::Variance;
|
|||
use crate::sql::number::Number;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn abs(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_number().abs().into())
|
||||
pub fn abs((arg,): (Number,)) -> Result<Value, Error> {
|
||||
Ok(arg.abs().into())
|
||||
}
|
||||
|
||||
pub fn bottom(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => {
|
||||
let c = args.remove(0).as_int();
|
||||
Ok(v.as_numbers().bottom(c).into())
|
||||
}
|
||||
pub fn bottom((array, c): (Value, i64)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().bottom(c).into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ceil(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_number().ceil().into())
|
||||
pub fn ceil((arg,): (Number,)) -> Result<Value, Error> {
|
||||
Ok(arg.ceil().into())
|
||||
}
|
||||
|
||||
pub fn fixed(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let v = args.remove(0);
|
||||
match args.remove(0).as_int() {
|
||||
p if p > 0 => Ok(v.as_number().fixed(p as usize).into()),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
pub fn fixed((v, p): (Number, i64)) -> Result<Value, Error> {
|
||||
if p > 0 {
|
||||
Ok(v.fixed(p as usize).into())
|
||||
} else {
|
||||
Err(Error::InvalidArguments {
|
||||
name: String::from("math::fixed"),
|
||||
message: String::from("The second argument must be an integer greater than 0."),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn floor(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_number().floor().into())
|
||||
pub fn floor((arg,): (Number,)) -> Result<Value, Error> {
|
||||
Ok(arg.floor().into())
|
||||
}
|
||||
|
||||
pub fn interquartile(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn interquartile((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().interquartile().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn max((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => match v.as_numbers().into_iter().max() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -66,8 +62,8 @@ pub fn max(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mean(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn mean((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => match v.is_empty() {
|
||||
true => Ok(Value::None),
|
||||
false => Ok(v.as_numbers().mean().into()),
|
||||
|
@ -76,8 +72,8 @@ pub fn mean(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn median(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn median((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => match v.is_empty() {
|
||||
true => Ok(Value::None),
|
||||
false => Ok(v.as_numbers().median().into()),
|
||||
|
@ -86,15 +82,15 @@ pub fn median(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn midhinge(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn midhinge((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().midhinge().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn min((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => match v.as_numbers().into_iter().min() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -103,85 +99,82 @@ pub fn min(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mode(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn mode((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().mode().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nearestrank(_: &Context, 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()),
|
||||
pub fn nearestrank((array, n): (Value, Number)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().nearestrank(n).into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn percentile(_: &Context, 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()),
|
||||
pub fn percentile((array, n): (Value, Number)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().percentile(n).into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn product(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn product((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().into_iter().product::<Number>().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn round(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_number().round().into())
|
||||
pub fn round((arg,): (Number,)) -> Result<Value, Error> {
|
||||
Ok(arg.round().into())
|
||||
}
|
||||
|
||||
pub fn spread(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn spread((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().spread().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sqrt(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0).as_number() {
|
||||
v if v >= Number::Int(0) => Ok(v.sqrt().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
pub fn sqrt((arg,): (Number,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
v if v >= Number::Int(0) => v.sqrt().into(),
|
||||
_ => Value::None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stddev(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn stddev((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().deviation().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sum(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn sum((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().into_iter().sum::<Number>().into()),
|
||||
v => Ok(v.as_number().into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn top(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Array(v) => {
|
||||
let c = args.remove(0).as_int();
|
||||
Ok(v.as_numbers().top(c).into())
|
||||
}
|
||||
pub fn top((array, c): (Value, i64)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().top(c).into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trimean(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn trimean((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().trimean().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn variance(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn variance((array,): (Value,)) -> Result<Value, Error> {
|
||||
match array {
|
||||
Value::Array(v) => Ok(v.as_numbers().variance().into()),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn id(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(match args.remove(0) {
|
||||
pub fn id((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
Value::Thing(v) => v.id.into(),
|
||||
_ => Value::None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tb(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(match args.remove(0) {
|
||||
pub fn tb((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
Value::Thing(v) => v.tb.into(),
|
||||
_ => Value::None,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::fnc::args::Args;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub mod args;
|
||||
|
@ -24,185 +23,177 @@ pub mod time;
|
|||
pub mod r#type;
|
||||
pub mod util;
|
||||
|
||||
// Attempts to run any function
|
||||
/// Attempts to run any function.
|
||||
pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
||||
match name {
|
||||
v if v.starts_with("http") => {
|
||||
// HTTP functions are asynchronous
|
||||
asynchronous(ctx, name, args).await
|
||||
}
|
||||
_ => {
|
||||
// Other functions are synchronous
|
||||
synchronous(ctx, name, args)
|
||||
macro_rules! dispatch {
|
||||
($name: ident, $args: ident, $($function_name: literal => $($function_path: ident)::+ $(($ctx_arg: expr))* $(.$await:tt)*,)+) => {
|
||||
{
|
||||
match $name {
|
||||
$($function_name => $($function_path)::+($($ctx_arg,)* args::FromArgs::from_args($name, $args)?)$(.$await)*,)+
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to run a synchronous function
|
||||
pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
||||
match name {
|
||||
// Each function is specified by its name (a string literal) followed by its path. The path
|
||||
// may be followed by one parenthesized argument, e.g. ctx, which is passed to the function
|
||||
// before the remainder of the arguments. The path may be followed by `.await` to signify that
|
||||
// it is `async`.
|
||||
dispatch!(
|
||||
name,
|
||||
args,
|
||||
"array::combine" => array::combine,
|
||||
"array::concat" => array::concat,
|
||||
"array::difference" => array::difference,
|
||||
"array::distinct" => array::distinct,
|
||||
"array::intersect" => array::intersect,
|
||||
"array::len" => array::len,
|
||||
"array::sort" => array::sort,
|
||||
"array::union" => array::union,
|
||||
"array::sort::asc" => array::sort::asc,
|
||||
"array::sort::desc" => array::sort::desc,
|
||||
//
|
||||
"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::sort" => args::check(ctx, name, args, Args::OneTwo, array::sort),
|
||||
"array::union" => args::check(ctx, name, args, Args::Two, array::union),
|
||||
"array::sort::asc" => args::check(ctx, name, args, Args::One, array::sort::asc),
|
||||
"array::sort::desc" => args::check(ctx, name, args, Args::One, array::sort::desc),
|
||||
"count" => count::count,
|
||||
//
|
||||
"count" => args::check(ctx, name, args, Args::NoneOne, count::count),
|
||||
"crypto::md5" => crypto::md5,
|
||||
"crypto::sha1" => crypto::sha1,
|
||||
"crypto::sha256" => crypto::sha256,
|
||||
"crypto::sha512" => crypto::sha512,
|
||||
"crypto::argon2::compare" => crypto::argon2::cmp,
|
||||
"crypto::argon2::generate" => crypto::argon2::gen,
|
||||
"crypto::bcrypt::compare" => crypto::bcrypt::cmp,
|
||||
"crypto::bcrypt::generate" => crypto::bcrypt::gen,
|
||||
"crypto::pbkdf2::compare" => crypto::pbkdf2::cmp,
|
||||
"crypto::pbkdf2::generate" => crypto::pbkdf2::gen,
|
||||
"crypto::scrypt::compare" => crypto::scrypt::cmp,
|
||||
"crypto::scrypt::generate" => crypto::scrypt::gen,
|
||||
//
|
||||
"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::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),
|
||||
"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),
|
||||
"geo::area" => geo::area,
|
||||
"geo::bearing" => geo::bearing,
|
||||
"geo::centroid" => geo::centroid,
|
||||
"geo::distance" => geo::distance,
|
||||
"geo::hash::decode" => geo::hash::decode,
|
||||
"geo::hash::encode" => geo::hash::encode,
|
||||
//
|
||||
"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" => http::head.await,
|
||||
"http::get" => http::get.await,
|
||||
"http::put" => http::put.await,
|
||||
"http::post" => http::post.await,
|
||||
"http::patch" => http::patch.await,
|
||||
"http::delete" => http::delete.await,
|
||||
//
|
||||
"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),
|
||||
"is::alphanum" => is::alphanum,
|
||||
"is::alpha" => is::alpha,
|
||||
"is::ascii" => is::ascii,
|
||||
"is::domain" => is::domain,
|
||||
"is::email" => is::email,
|
||||
"is::hexadecimal" => is::hexadecimal,
|
||||
"is::latitude" => is::latitude,
|
||||
"is::longitude" => is::longitude,
|
||||
"is::numeric" => is::numeric,
|
||||
"is::semver" => is::semver,
|
||||
"is::uuid" => 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),
|
||||
"math::abs" => math::abs,
|
||||
"math::bottom" => math::bottom,
|
||||
"math::ceil" => math::ceil,
|
||||
"math::fixed" => math::fixed,
|
||||
"math::floor" => math::floor,
|
||||
"math::interquartile" => math::interquartile,
|
||||
"math::max" => math::max,
|
||||
"math::mean" => math::mean,
|
||||
"math::median" => math::median,
|
||||
"math::midhinge" => math::midhinge,
|
||||
"math::min" => math::min,
|
||||
"math::mode" => math::mode,
|
||||
"math::nearestrank" => math::nearestrank,
|
||||
"math::percentile" => math::percentile,
|
||||
"math::product" => math::product,
|
||||
"math::roun" => math::round,
|
||||
"math::spread" => math::spread,
|
||||
"math::sqrt" => math::sqrt,
|
||||
"math::stddev" => math::stddev,
|
||||
"math::sum" => math::sum,
|
||||
"math::top" => math::top,
|
||||
"math::trimean" => math::trimean,
|
||||
"math::variance" => math::variance,
|
||||
//
|
||||
"meta::id" => args::check(ctx, name, args, Args::One, meta::id),
|
||||
"meta::table" => args::check(ctx, name, args, Args::One, meta::tb),
|
||||
"meta::tb" => args::check(ctx, name, args, Args::One, meta::tb),
|
||||
"meta::id" => meta::id,
|
||||
"meta::table" => meta::tb,
|
||||
"meta::tb" => meta::tb,
|
||||
//
|
||||
"parse::email::host" => args::check(ctx, name, args, Args::One, parse::email::host),
|
||||
"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),
|
||||
"parse::email::host" => parse::email::host,
|
||||
"parse::email::user" => parse::email::user,
|
||||
"parse::url::domain" => parse::url::domain,
|
||||
"parse::url::fragment" => parse::url::fragment,
|
||||
"parse::url::host" => parse::url::host,
|
||||
"parse::url::path" => parse::url::path,
|
||||
"parse::url::port" => parse::url::port,
|
||||
"parse::url::query" => 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::NoneOne, 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),
|
||||
"rand::bool" => rand::bool,
|
||||
"rand::enum" => rand::r#enum,
|
||||
"rand::float" => rand::float,
|
||||
"rand::guid" => rand::guid,
|
||||
"rand::int" => rand::int,
|
||||
"rand::string" => rand::string,
|
||||
"rand::time" => rand::time,
|
||||
"rand::uuid" => rand::uuid,
|
||||
"rand" => rand::rand,
|
||||
//
|
||||
"session::db" => args::check(ctx, name, args, Args::None, session::db),
|
||||
"session::id" => args::check(ctx, name, args, Args::None, session::id),
|
||||
"session::ip" => args::check(ctx, name, args, Args::None, session::ip),
|
||||
"session::ns" => args::check(ctx, name, args, Args::None, session::ns),
|
||||
"session::origin" => args::check(ctx, name, args, Args::None, session::origin),
|
||||
"session::sc" => args::check(ctx, name, args, Args::None, session::sc),
|
||||
"session::sd" => args::check(ctx, name, args, Args::None, session::sd),
|
||||
"session::token" => args::check(ctx, name, args, Args::None, session::token),
|
||||
"session::db" => session::db(ctx),
|
||||
"session::id" => session::id(ctx),
|
||||
"session::ip" => session::ip(ctx),
|
||||
"session::ns" => session::ns(ctx),
|
||||
"session::origin" => session::origin(ctx),
|
||||
"session::sc" => session::sc(ctx),
|
||||
"session::sd" => session::sd(ctx),
|
||||
"session::token" => session::token(ctx),
|
||||
//
|
||||
"string::concat" => args::check(ctx, name, args, Args::Any, string::concat),
|
||||
"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::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),
|
||||
"string::concat" => string::concat,
|
||||
"string::endsWith" => string::ends_with,
|
||||
"string::join" => string::join,
|
||||
"string::length" => string::length,
|
||||
"string::lowercase" => string::lowercase,
|
||||
"string::repeat" => string::repeat,
|
||||
"string::replace" => string::replace,
|
||||
"string::reverse" => string::reverse,
|
||||
"string::slice" => string::slice,
|
||||
"string::slug" => string::slug,
|
||||
"string::split" => string::split,
|
||||
"string::startsWith" => string::starts_with,
|
||||
"string::trim" => string::trim,
|
||||
"string::uppercase" => string::uppercase,
|
||||
"string::words" => 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::group" => args::check(ctx, name, args, Args::Two, time::group),
|
||||
"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),
|
||||
"time::day" => time::day,
|
||||
"time::floor" => time::floor,
|
||||
"time::group" => time::group,
|
||||
"time::hour" => time::hour,
|
||||
"time::mins" => time::mins,
|
||||
"time::month" => time::month,
|
||||
"time::nano" => time::nano,
|
||||
"time::now" => time::now,
|
||||
"time::round" => time::round,
|
||||
"time::secs" => time::secs,
|
||||
"time::unix" => time::unix,
|
||||
"time::wday" => time::wday,
|
||||
"time::week" => time::week,
|
||||
"time::yday" => time::yday,
|
||||
"time::year" => 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::OneTwo, r#type::thing),
|
||||
//
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to run an asynchronous function
|
||||
pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
||||
match name {
|
||||
//
|
||||
"http::head" => http::head(ctx, args).await,
|
||||
"http::get" => http::get(ctx, args).await,
|
||||
"http::put" => http::put(ctx, args).await,
|
||||
"http::post" => http::post(ctx, args).await,
|
||||
"http::patch" => http::patch(ctx, args).await,
|
||||
"http::delete" => http::delete(ctx, args).await,
|
||||
//
|
||||
_ => unreachable!(),
|
||||
}
|
||||
"type::bool" => r#type::bool,
|
||||
"type::datetime" => r#type::datetime,
|
||||
"type::decimal" => r#type::decimal,
|
||||
"type::duration" => r#type::duration,
|
||||
"type::float" => r#type::float,
|
||||
"type::int" => r#type::int,
|
||||
"type::number" => r#type::number,
|
||||
"type::point" => r#type::point,
|
||||
"type::regex" => r#type::regex,
|
||||
"type::string" => r#type::string,
|
||||
"type::table" => r#type::table,
|
||||
"type::thing" => r#type::thing,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
pub mod email {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use addr::email::Host;
|
||||
|
||||
pub fn host(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn host((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the email address
|
||||
match addr::parse_email_address(&val) {
|
||||
match addr::parse_email_address(&string) {
|
||||
// Return the host part
|
||||
Ok(v) => match v.host() {
|
||||
Host::Domain(name) => Ok(name.as_str().into()),
|
||||
|
@ -19,10 +16,9 @@ pub mod email {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn user(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn user((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the email address
|
||||
match addr::parse_email_address(&val) {
|
||||
match addr::parse_email_address(&string) {
|
||||
// Return the user part
|
||||
Ok(v) => Ok(v.user().into()),
|
||||
Err(_) => Ok(Value::None),
|
||||
|
@ -33,15 +29,15 @@ pub mod email {
|
|||
mod tests {
|
||||
#[test]
|
||||
fn host() {
|
||||
let input = vec!["john.doe@example.com".into()];
|
||||
let value = super::host(&Default::default(), input).unwrap();
|
||||
let input = (String::from("john.doe@example.com"),);
|
||||
let value = super::host(input).unwrap();
|
||||
assert_eq!(value, "example.com".into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user() {
|
||||
let input = vec!["john.doe@example.com".into()];
|
||||
let value = super::user(&Default::default(), input).unwrap();
|
||||
let input = (String::from("john.doe@example.com"),);
|
||||
let value = super::user(input).unwrap();
|
||||
assert_eq!(value, "john.doe".into());
|
||||
}
|
||||
}
|
||||
|
@ -49,16 +45,12 @@ pub mod email {
|
|||
|
||||
pub mod url {
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use url::Url;
|
||||
|
||||
pub fn domain(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
pub fn domain((string,): (String,)) -> Result<Value, Error> {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => match v.domain() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -67,11 +59,9 @@ pub mod url {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fragment(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn fragment((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => match v.fragment() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -80,11 +70,9 @@ pub mod url {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn host(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn host((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => match v.host_str() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -93,21 +81,17 @@ pub mod url {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn path(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn path((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => Ok(v.path().into()),
|
||||
Err(_) => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn port(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn port((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => match v.port() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
@ -116,11 +100,9 @@ pub mod url {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn query(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
// Convert to a String
|
||||
let val = args.remove(0).as_string();
|
||||
pub fn query((string,): (String,)) -> Result<Value, Error> {
|
||||
// Parse the URL
|
||||
match Url::parse(&val) {
|
||||
match Url::parse(&string) {
|
||||
Ok(v) => match v.query() {
|
||||
Some(v) => Ok(v.into()),
|
||||
None => Ok(Value::None),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::cnf::ID_CHARS;
|
||||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::datetime::Datetime;
|
||||
use crate::sql::uuid::Uuid;
|
||||
|
@ -9,15 +8,15 @@ use rand::distributions::Alphanumeric;
|
|||
use rand::prelude::IteratorRandom;
|
||||
use rand::Rng;
|
||||
|
||||
pub fn rand(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn rand(_: ()) -> Result<Value, Error> {
|
||||
Ok(rand::random::<f64>().into())
|
||||
}
|
||||
|
||||
pub fn bool(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn bool(_: ()) -> Result<Value, Error> {
|
||||
Ok(rand::random::<bool>().into())
|
||||
}
|
||||
|
||||
pub fn r#enum(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn r#enum(mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(match args.len() {
|
||||
0 => Value::None,
|
||||
1 => match args.remove(0) {
|
||||
|
@ -28,127 +27,104 @@ pub fn r#enum(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn float(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => {
|
||||
let min = args.remove(0).as_float();
|
||||
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()),
|
||||
}
|
||||
pub fn float((range,): (Option<(f64, f64)>,)) -> Result<Value, Error> {
|
||||
Ok(if let Some((min, max)) = range {
|
||||
if max < min {
|
||||
rand::thread_rng().gen_range(max..=min)
|
||||
} else {
|
||||
rand::thread_rng().gen_range(min..=max)
|
||||
}
|
||||
0 => Ok(rand::random::<f64>().into()),
|
||||
_ => unreachable!(),
|
||||
} else {
|
||||
rand::random::<f64>()
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
pub fn guid(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
1 => {
|
||||
// Only need 53 to uniquely identify all atoms in observable universe.
|
||||
const LIMIT: usize = 64;
|
||||
let len = args.remove(0).as_int() as usize;
|
||||
if len > LIMIT {
|
||||
Err(Error::InvalidArguments {
|
||||
name: String::from("rand::guid"),
|
||||
message: format!("The maximum length of a GUID is {}.", LIMIT),
|
||||
})
|
||||
} else {
|
||||
Ok(nanoid!(len, &ID_CHARS).into())
|
||||
}
|
||||
pub fn guid((len,): (Option<usize>,)) -> Result<Value, Error> {
|
||||
// Only need 53 to uniquely identify all atoms in observable universe.
|
||||
const LIMIT: usize = 64;
|
||||
|
||||
let len = match len {
|
||||
Some(len) if len <= LIMIT => len,
|
||||
None => 20,
|
||||
_ => {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::guid"),
|
||||
message: format!("The maximum length of a GUID is {}.", LIMIT),
|
||||
})
|
||||
}
|
||||
0 => Ok(nanoid!(20, &ID_CHARS).into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(nanoid!(len, &ID_CHARS).into())
|
||||
}
|
||||
|
||||
pub fn int(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => {
|
||||
let min = args.remove(0).as_int();
|
||||
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()),
|
||||
}
|
||||
pub fn int((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
||||
Ok(if let Some((min, max)) = range {
|
||||
if max < min {
|
||||
rand::thread_rng().gen_range(max..=min)
|
||||
} else {
|
||||
rand::thread_rng().gen_range(min..=max)
|
||||
}
|
||||
0 => Ok(rand::random::<i64>().into()),
|
||||
_ => unreachable!(),
|
||||
} else {
|
||||
rand::random::<i64>()
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
pub fn string(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn string((arg1, arg2): (Option<i64>, Option<i64>)) -> Result<Value, Error> {
|
||||
// Limit how much time and bandwidth is spent.
|
||||
const LIMIT: i64 = 2i64.pow(16);
|
||||
match args.len() {
|
||||
2 => match args.remove(0).as_int() {
|
||||
min if (0..=LIMIT).contains(&min) => match args.remove(0).as_int() {
|
||||
max if min <= max && max <= LIMIT => 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()),
|
||||
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()),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
|
||||
let len = if let Some((min, max)) = arg1.zip(arg2) {
|
||||
match min {
|
||||
min if (0..=LIMIT).contains(&min) => match max {
|
||||
max if min <= max && max <= LIMIT => rand::thread_rng().gen_range(min as usize..=max as usize),
|
||||
max if max >= 0 && max <= min => rand::thread_rng().gen_range(max as usize..=min as usize),
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::string"),
|
||||
message: format!("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
},
|
||||
_ => Err(Error::InvalidArguments {
|
||||
_ => return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::string"),
|
||||
message: format!("To generate a string of between X and Y characters in length, the 2 arguments must be positive numbers and no higher than {}.", LIMIT),
|
||||
}),
|
||||
},
|
||||
1 => match args.remove(0).as_int() {
|
||||
x if (0..=LIMIT).contains(&x) => Ok(rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(x as usize)
|
||||
.map(char::from)
|
||||
.collect::<String>()
|
||||
.into()),
|
||||
_ => Err(Error::InvalidArguments {
|
||||
}
|
||||
} else if let Some(len) = arg1 {
|
||||
if (0..=LIMIT).contains(&len) {
|
||||
len as usize
|
||||
} else {
|
||||
return Err(Error::InvalidArguments {
|
||||
name: String::from("rand::string"),
|
||||
message: format!("To generate a string of X characters in length, the argument must be a positive number and no higher than {}.", LIMIT),
|
||||
}),
|
||||
},
|
||||
0 => Ok(rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect::<String>()
|
||||
.into()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
32
|
||||
};
|
||||
|
||||
Ok(rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(len)
|
||||
.map(char::from)
|
||||
.collect::<String>()
|
||||
.into())
|
||||
}
|
||||
|
||||
pub fn time(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => {
|
||||
let min = args.remove(0).as_int();
|
||||
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::<i32>();
|
||||
Ok(Datetime::from(i as i64).into())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
pub fn time((range,): (Option<(i64, i64)>,)) -> Result<Value, Error> {
|
||||
let i = if let Some((min, max)) = range {
|
||||
let range = if max < min {
|
||||
max..=min
|
||||
} else {
|
||||
min..=max
|
||||
};
|
||||
rand::thread_rng().gen_range(range)
|
||||
} else {
|
||||
rand::random::<i32>() as i64
|
||||
};
|
||||
Ok(Datetime::from(i).into())
|
||||
}
|
||||
|
||||
pub fn uuid(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn uuid(_: ()) -> Result<Value, Error> {
|
||||
Ok(Uuid::new().into())
|
||||
}
|
||||
|
|
|
@ -10,34 +10,34 @@ use crate::sql::paths::SD;
|
|||
use crate::sql::paths::TK;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn db(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn db(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(DB.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn id(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn id(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(ID.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn ip(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn ip(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(IP.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn ns(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn ns(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(NS.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn origin(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn origin(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(OR.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn sc(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn sc(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(SC.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn sd(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn sd(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(SD.as_ref()).ok()
|
||||
}
|
||||
|
||||
pub fn token(ctx: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn token(ctx: &Context, _: ()) -> Result<Value, Error> {
|
||||
ctx.value("session").unwrap_or(&Value::None).pick(TK.as_ref()).ok()
|
||||
}
|
||||
|
|
|
@ -1,41 +1,37 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::fnc::util::string;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
pub fn concat(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn concat(args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.into_iter().map(|x| x.as_string()).collect::<Vec<_>>().concat().into())
|
||||
}
|
||||
|
||||
pub fn ends_with(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [val, chr] = args.map(Value::as_string);
|
||||
pub fn ends_with((val, chr): (String, String)) -> Result<Value, Error> {
|
||||
Ok(val.ends_with(&chr).into())
|
||||
}
|
||||
|
||||
pub fn join(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn join(args: Vec<Value>) -> Result<Value, Error> {
|
||||
let mut args = args.into_iter().map(Value::as_string);
|
||||
let chr = args.next().unwrap();
|
||||
let chr = args.next().ok_or(Error::InvalidArguments {
|
||||
name: String::from("string::join"),
|
||||
message: String::from("Expected at least one argument"),
|
||||
})?;
|
||||
// FIXME: Use intersperse to avoid intermediate allocation once stable
|
||||
// https://github.com/rust-lang/rust/issues/79524
|
||||
let val = args.collect::<Vec<_>>().join(&chr);
|
||||
Ok(val.into())
|
||||
}
|
||||
|
||||
pub fn length(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
let val = args.remove(0).as_string();
|
||||
let num = val.chars().count() as i64;
|
||||
pub fn length((string,): (String,)) -> Result<Value, Error> {
|
||||
let num = string.chars().count() as i64;
|
||||
Ok(num.into())
|
||||
}
|
||||
|
||||
pub fn lowercase(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().to_lowercase().into())
|
||||
pub fn lowercase((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string.to_lowercase().into())
|
||||
}
|
||||
|
||||
pub fn repeat(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let [val_arg, num_arg]: [Value; 2] = args.try_into().unwrap();
|
||||
let val = val_arg.as_string();
|
||||
let num = num_arg.as_int() as usize;
|
||||
pub fn repeat((val, num): (String, usize)) -> Result<Value, Error> {
|
||||
const LIMIT: usize = 2usize.pow(20);
|
||||
if val.len().saturating_mul(num) > LIMIT {
|
||||
Err(Error::InvalidArguments {
|
||||
|
@ -47,50 +43,38 @@ pub fn repeat(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn replace(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 3] = args.try_into().unwrap();
|
||||
let [val, old, new] = args.map(Value::as_string);
|
||||
pub fn replace((val, old, new): (String, String, String)) -> Result<Value, Error> {
|
||||
Ok(val.replace(&old, &new).into())
|
||||
}
|
||||
|
||||
pub fn reverse(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().chars().rev().collect::<String>().into())
|
||||
pub fn reverse((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string.chars().rev().collect::<String>().into())
|
||||
}
|
||||
|
||||
pub fn slice(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let [val_arg, beg_arg, lim_arg]: [Value; 3] = args.try_into().unwrap();
|
||||
let val = val_arg.as_string();
|
||||
let beg = beg_arg.as_int() as usize;
|
||||
let lim = lim_arg.as_int() as usize;
|
||||
let val = val.chars().skip(beg).take(lim).collect::<String>();
|
||||
Ok(val.into())
|
||||
pub fn slice((val, beg, lim): (String, usize, usize)) -> Result<Value, Error> {
|
||||
Ok(val.chars().skip(beg).take(lim).collect::<String>().into())
|
||||
}
|
||||
|
||||
pub fn slug(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(string::slug(&args.remove(0).as_string()).into())
|
||||
pub fn slug((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string::slug(&string).into())
|
||||
}
|
||||
|
||||
pub fn split(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [val, chr] = args.map(Value::as_string);
|
||||
let val = val.split(&chr).collect::<Vec<&str>>();
|
||||
Ok(val.into())
|
||||
pub fn split((val, chr): (String, String)) -> Result<Value, Error> {
|
||||
Ok(val.split(&chr).collect::<Vec<&str>>().into())
|
||||
}
|
||||
|
||||
pub fn starts_with(_: &Context, args: Vec<Value>) -> Result<Value, Error> {
|
||||
let args: [Value; 2] = args.try_into().unwrap();
|
||||
let [val, chr] = args.map(Value::as_string);
|
||||
pub fn starts_with((val, chr): (String, String)) -> Result<Value, Error> {
|
||||
Ok(val.starts_with(&chr).into())
|
||||
}
|
||||
|
||||
pub fn trim(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().trim().into())
|
||||
pub fn trim((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string.trim().into())
|
||||
}
|
||||
|
||||
pub fn uppercase(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().to_uppercase().into())
|
||||
pub fn uppercase((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string.to_uppercase().into())
|
||||
}
|
||||
|
||||
pub fn words(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(args.remove(0).as_string().split_whitespace().collect::<Vec<&str>>().into())
|
||||
pub fn words((string,): (String,)) -> Result<Value, Error> {
|
||||
Ok(string.split_whitespace().collect::<Vec<&str>>().into())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::datetime::Datetime;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -8,19 +7,19 @@ use chrono::DurationRound;
|
|||
use chrono::Timelike;
|
||||
use chrono::Utc;
|
||||
|
||||
pub fn day(_: &Context, 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.day().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn day((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.day().into())
|
||||
}
|
||||
|
||||
pub fn floor(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Datetime(v) => match args.remove(0) {
|
||||
pub fn floor((datetime, duration): (Value, Value)) -> Result<Value, Error> {
|
||||
match datetime {
|
||||
Value::Datetime(v) => match duration {
|
||||
Value::Duration(w) => match chrono::Duration::from_std(*w) {
|
||||
Ok(d) => match v.duration_trunc(d) {
|
||||
Ok(v) => Ok(v.into()),
|
||||
|
@ -34,9 +33,9 @@ pub fn floor(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn group(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Datetime(v) => match args.remove(0) {
|
||||
pub fn group((datetime, strand): (Value, Value)) -> Result<Value, Error> {
|
||||
match datetime {
|
||||
Value::Datetime(v) => match strand {
|
||||
Value::Strand(g) => match g.as_str() {
|
||||
"year" => Ok(Utc.ymd(v.year(), 1, 1).and_hms(0, 0, 0).into()),
|
||||
"month" => Ok(Utc.ymd(v.year(), v.month(), 1).and_hms(0, 0, 0).into()),
|
||||
|
@ -67,53 +66,53 @@ pub fn group(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hour(_: &Context, 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.hour().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn hour((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.hour().into())
|
||||
}
|
||||
|
||||
pub fn mins(_: &Context, 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.minute().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn mins((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.minute().into())
|
||||
}
|
||||
|
||||
pub fn month(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
0 => Ok(Utc::now().month().into()),
|
||||
_ => match args.remove(0) {
|
||||
Value::Datetime(v) => Ok(v.month().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn month((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.month().into())
|
||||
}
|
||||
|
||||
pub fn nano(_: &Context, 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.timestamp_nanos().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn nano((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.timestamp_nanos().into())
|
||||
}
|
||||
|
||||
pub fn now(_: &Context, _: Vec<Value>) -> Result<Value, Error> {
|
||||
pub fn now(_: ()) -> Result<Value, Error> {
|
||||
Ok(Datetime::default().into())
|
||||
}
|
||||
|
||||
pub fn round(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
Value::Datetime(v) => match args.remove(0) {
|
||||
pub fn round((datetime, duration): (Value, Value)) -> Result<Value, Error> {
|
||||
match datetime {
|
||||
Value::Datetime(v) => match duration {
|
||||
Value::Duration(w) => match chrono::Duration::from_std(*w) {
|
||||
Ok(d) => match v.duration_round(d) {
|
||||
Ok(v) => Ok(v.into()),
|
||||
|
@ -127,62 +126,62 @@ pub fn round(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn secs(_: &Context, 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.second().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn secs((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.second().into())
|
||||
}
|
||||
|
||||
pub fn unix(_: &Context, 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.timestamp().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn unix((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.timestamp().into())
|
||||
}
|
||||
|
||||
pub fn wday(_: &Context, 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.weekday().number_from_monday().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn wday((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.weekday().number_from_monday().into())
|
||||
}
|
||||
|
||||
pub fn week(_: &Context, 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.iso_week().week().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn week((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.iso_week().week().into())
|
||||
}
|
||||
|
||||
pub fn yday(_: &Context, 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.ordinal().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn yday((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.ordinal().into())
|
||||
}
|
||||
|
||||
pub fn year(_: &Context, 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.year().into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
}
|
||||
pub fn year((datetime,): (Option<Value>,)) -> Result<Value, Error> {
|
||||
let date = match datetime {
|
||||
Some(Value::Datetime(v)) => v,
|
||||
None => Datetime::default(),
|
||||
Some(_) => return Ok(Value::None),
|
||||
};
|
||||
|
||||
Ok(date.year().into())
|
||||
}
|
||||
|
|
|
@ -1,120 +1,104 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::err::Error;
|
||||
use crate::sql::geometry::Geometry;
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::table::Table;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Strand;
|
||||
|
||||
pub fn bool(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0).is_truthy() {
|
||||
true => Ok(Value::True),
|
||||
false => Ok(Value::False),
|
||||
pub fn bool((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(arg.is_truthy().into())
|
||||
}
|
||||
|
||||
pub fn datetime((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
Value::Datetime(_) => arg,
|
||||
_ => Value::Datetime(arg.as_datetime()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn decimal((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(match arg {
|
||||
Value::Number(Number::Decimal(_)) => arg,
|
||||
_ => Value::Number(Number::Decimal(arg.as_decimal())),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn duration((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Duration(_) => Ok(arg),
|
||||
_ => Ok(Value::Duration(arg.as_duration())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn datetime(_: &Context, 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 float((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Number(Number::Float(_)) => Ok(arg),
|
||||
_ => Ok(Value::Number(Number::Float(arg.as_float()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decimal(_: &Context, 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 int((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Number(Number::Int(_)) => Ok(arg),
|
||||
_ => Ok(Value::Number(Number::Int(arg.as_int()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn duration(_: &Context, 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 number((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Number(_) => Ok(arg),
|
||||
_ => Ok(Value::Number(arg.as_number())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float(_: &Context, 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(_: &Context, 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(_: &Context, 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(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => {
|
||||
let x = args.remove(0);
|
||||
let y = args.remove(0);
|
||||
Ok((x.as_float(), y.as_float()).into())
|
||||
pub fn point((arg1, arg2): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
Ok(if let Some(y) = arg2 {
|
||||
let x = arg1;
|
||||
(x.as_float(), y.as_float()).into()
|
||||
} else {
|
||||
match arg1 {
|
||||
Value::Array(v) if v.len() == 2 => v.as_point().into(),
|
||||
Value::Geometry(Geometry::Point(v)) => v.into(),
|
||||
_ => Value::None,
|
||||
}
|
||||
1 => match args.remove(0) {
|
||||
Value::Array(v) if v.len() == 2 => Ok(v.as_point().into()),
|
||||
Value::Geometry(Geometry::Point(v)) => Ok(v.into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn regex(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.remove(0) {
|
||||
pub fn regex((arg,): (Value,)) -> Result<Value, Error> {
|
||||
match arg {
|
||||
Value::Strand(v) => Ok(Value::Regex(v.as_str().into())),
|
||||
_ => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string(_: &Context, 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 string((arg,): (Strand,)) -> Result<Value, Error> {
|
||||
Ok(arg.into())
|
||||
}
|
||||
|
||||
pub fn table(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
Ok(Value::Table(Table(match args.remove(0) {
|
||||
pub fn table((arg,): (Value,)) -> Result<Value, Error> {
|
||||
Ok(Value::Table(Table(match arg {
|
||||
Value::Thing(t) => t.tb,
|
||||
v => v.as_string(),
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn thing(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
|
||||
match args.len() {
|
||||
2 => Ok(Value::Thing(Thing {
|
||||
tb: args.remove(0).as_string(),
|
||||
id: match args.remove(0) {
|
||||
pub fn thing((arg1, arg2): (Value, Option<Value>)) -> Result<Value, Error> {
|
||||
Ok(if let Some(arg2) = arg2 {
|
||||
Value::Thing(Thing {
|
||||
tb: arg1.as_string(),
|
||||
id: match arg2 {
|
||||
Value::Thing(v) => v.id,
|
||||
Value::Array(v) => v.into(),
|
||||
Value::Object(v) => v.into(),
|
||||
Value::Number(Number::Int(v)) => v.into(),
|
||||
v => v.as_string().into(),
|
||||
},
|
||||
})),
|
||||
1 => match args.remove(0) {
|
||||
Value::Thing(v) => Ok(v.into()),
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
})
|
||||
} else {
|
||||
match arg1 {
|
||||
Value::Thing(v) => v.into(),
|
||||
_ => Value::None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue