Refactor and optimize functions and Value operators (#80)

This commit is contained in:
Finn Bear 2022-08-31 17:27:52 -07:00 committed by GitHub
parent 5ca3b74e59
commit 8f6d21c1fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 160 deletions

View file

@ -107,10 +107,6 @@ impl Iterable {
if !res.is_empty() { if !res.is_empty() {
// Get total results // Get total results
let n = res.len(); let n = res.len();
// Exit when settled
if n == 0 {
break;
}
// Loop over results // Loop over results
for (i, (k, v)) in res.into_iter().enumerate() { for (i, (k, v)) in res.into_iter().enumerate() {
// Check the context // Check the context
@ -167,10 +163,6 @@ impl Iterable {
if !res.is_empty() { if !res.is_empty() {
// Get total results // Get total results
let n = res.len(); let n = res.len();
// Exit when settled
if n == 0 {
break;
}
// Loop over results // Loop over results
for (i, (k, v)) in res.into_iter().enumerate() { for (i, (k, v)) in res.into_iter().enumerate() {
// Check the context // Check the context

View file

@ -18,10 +18,7 @@ pub fn run(_: &Context, name: &str, val: Value) -> Result<Value, Error> {
} }
pub fn bool(val: Value) -> Result<Value, Error> { pub fn bool(val: Value) -> Result<Value, Error> {
match val.is_truthy() { Ok(val.is_truthy().into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn int(val: Value) -> Result<Value, Error> { pub fn int(val: Value) -> Result<Value, Error> {

View file

@ -6,10 +6,7 @@ pub fn count(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
match args.len() { match args.len() {
1 => match args.remove(0) { 1 => match args.remove(0) {
Value::Array(v) => Ok(v.iter().filter(|v| v.is_truthy()).count().into()), Value::Array(v) => Ok(v.iter().filter(|v| v.is_truthy()).count().into()),
v => match v.is_truthy() { v => Ok((v.is_truthy() as i64).into()),
true => Ok(1.into()),
false => Ok(0.into()),
},
}, },
0 => Ok(1.into()), 0 => Ok(1.into()),
_ => unreachable!(), _ => unreachable!(),

View file

@ -22,7 +22,7 @@ pub fn alpha(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
} }
pub fn ascii(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> { pub fn ascii(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
Ok(args.remove(0).as_string().chars().all(|x| char::is_ascii(&x)).into()) Ok(args.remove(0).as_string().is_ascii().into())
} }
pub fn domain(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> { pub fn domain(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
@ -30,30 +30,13 @@ pub fn domain(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
} }
pub fn email(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> { pub fn email(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {
// Convert to a String Ok(args
let val = args.remove(0).as_string(); .remove(0)
// Convert to a &str .as_string()
let val = val.as_str(); .rsplit_once('@')
// Check if value is empty .map(|(user, host)| USER_RE.is_match(user) && HOST_RE.is_match(host))
if val.is_empty() { .unwrap_or(false)
return Ok(Value::False); .into())
}
// Ensure the value contains @
if !val.contains('@') {
return Ok(Value::False);
}
// Reverse split the value by @
let parts: Vec<&str> = val.rsplitn(2, '@').collect();
// Check the first part matches
if !USER_RE.is_match(parts[1]) {
return Ok(Value::False);
}
// Check the second part matches
if !HOST_RE.is_match(parts[0]) {
return Ok(Value::False);
}
// The email is valid
Ok(Value::True)
} }
pub fn hexadecimal(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> { pub fn hexadecimal(_: &Context, mut args: Vec<Value>) -> Result<Value, Error> {

View file

@ -6,17 +6,17 @@ use std::ops::Mul;
use std::ops::Sub; use std::ops::Sub;
pub fn or(a: Value, b: Value) -> Result<Value, Error> { pub fn or(a: Value, b: Value) -> Result<Value, Error> {
match a.is_truthy() { Ok(match a.is_truthy() {
true => Ok(a), true => a,
false => Ok(b), false => b,
} })
} }
pub fn and(a: Value, b: Value) -> Result<Value, Error> { pub fn and(a: Value, b: Value) -> Result<Value, Error> {
match a.is_truthy() { Ok(match a.is_truthy() {
true => Ok(b), true => b,
false => Ok(a), false => a,
} })
} }
pub fn add(a: Value, b: Value) -> Result<Value, Error> { pub fn add(a: Value, b: Value) -> Result<Value, Error> {
@ -40,171 +40,99 @@ pub fn exact(a: &Value, b: &Value) -> Result<Value, Error> {
} }
pub fn equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.equal(b) { Ok(a.equal(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn not_equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn not_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.equal(b) { Ok((!a.equal(b)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn all_equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn all_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.all_equal(b) { Ok(a.all_equal(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn any_equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn any_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.any_equal(b) { Ok(a.any_equal(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn like(a: &Value, b: &Value) -> Result<Value, Error> { pub fn like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.fuzzy(b) { Ok(a.fuzzy(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn not_like(a: &Value, b: &Value) -> Result<Value, Error> { pub fn not_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.fuzzy(b) { Ok((!a.fuzzy(b)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn all_like(a: &Value, b: &Value) -> Result<Value, Error> { pub fn all_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.all_fuzzy(b) { Ok(a.all_fuzzy(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn any_like(a: &Value, b: &Value) -> Result<Value, Error> { pub fn any_like(a: &Value, b: &Value) -> Result<Value, Error> {
match a.any_fuzzy(b) { Ok(a.any_fuzzy(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn less_than(a: &Value, b: &Value) -> Result<Value, Error> { pub fn less_than(a: &Value, b: &Value) -> Result<Value, Error> {
match a.lt(b) { Ok(a.lt(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn less_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn less_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.le(b) { Ok(a.le(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn more_than(a: &Value, b: &Value) -> Result<Value, Error> { pub fn more_than(a: &Value, b: &Value) -> Result<Value, Error> {
match a.gt(b) { Ok(a.gt(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn more_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> { pub fn more_than_or_equal(a: &Value, b: &Value) -> Result<Value, Error> {
match a.ge(b) { Ok(a.ge(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn contain(a: &Value, b: &Value) -> Result<Value, Error> { pub fn contain(a: &Value, b: &Value) -> Result<Value, Error> {
match a.contains(b) { Ok(a.contains(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn not_contain(a: &Value, b: &Value) -> Result<Value, Error> { pub fn not_contain(a: &Value, b: &Value) -> Result<Value, Error> {
match a.contains(b) { Ok((!a.contains(b)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn contain_all(a: &Value, b: &Value) -> Result<Value, Error> { pub fn contain_all(a: &Value, b: &Value) -> Result<Value, Error> {
match a.contains_all(b) { Ok(a.contains_all(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn contain_any(a: &Value, b: &Value) -> Result<Value, Error> { pub fn contain_any(a: &Value, b: &Value) -> Result<Value, Error> {
match a.contains_any(b) { Ok(a.contains_any(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn contain_none(a: &Value, b: &Value) -> Result<Value, Error> { pub fn contain_none(a: &Value, b: &Value) -> Result<Value, Error> {
match a.contains_any(b) { Ok((!a.contains_any(b)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn inside(a: &Value, b: &Value) -> Result<Value, Error> { pub fn inside(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains(a) { Ok(b.contains(a).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn not_inside(a: &Value, b: &Value) -> Result<Value, Error> { pub fn not_inside(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains(a) { Ok((!b.contains(a)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn inside_all(a: &Value, b: &Value) -> Result<Value, Error> { pub fn inside_all(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_all(a) { Ok(b.contains_all(a).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn inside_any(a: &Value, b: &Value) -> Result<Value, Error> { pub fn inside_any(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_any(a) { Ok(b.contains_any(a).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
pub fn inside_none(a: &Value, b: &Value) -> Result<Value, Error> { pub fn inside_none(a: &Value, b: &Value) -> Result<Value, Error> {
match b.contains_any(a) { Ok((!b.contains_any(a)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn outside(a: &Value, b: &Value) -> Result<Value, Error> { pub fn outside(a: &Value, b: &Value) -> Result<Value, Error> {
match a.intersects(b) { Ok((!a.intersects(b)).into())
true => Ok(Value::False),
false => Ok(Value::True),
}
} }
pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> { pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> {
match a.intersects(b) { Ok(a.intersects(b).into())
true => Ok(Value::True),
false => Ok(Value::False),
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -49,7 +49,7 @@ impl From<i32> for Number {
impl From<i64> for Number { impl From<i64> for Number {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
Number::Int(i as i64) Number::Int(i)
} }
} }

View file

@ -3,10 +3,7 @@ use crate::sql::value::Value;
impl Value { impl Value {
pub fn single(&self) -> &Self { pub fn single(&self) -> &Self {
match self { match self {
Value::Array(v) => match v.first() { Value::Array(v) => v.first().unwrap_or(&Value::None),
None => &Value::None,
Some(v) => v,
},
v => v, v => v,
} }
} }

View file

@ -137,6 +137,7 @@ impl Default for Value {
} }
impl From<bool> for Value { impl From<bool> for Value {
#[inline]
fn from(v: bool) -> Self { fn from(v: bool) -> Self {
match v { match v {
true => Value::True, true => Value::True,
@ -497,7 +498,7 @@ impl Value {
pub fn is_true(&self) -> bool { pub fn is_true(&self) -> bool {
match self { match self {
Value::True => true, Value::True => true,
Value::Strand(v) => v.to_ascii_lowercase() == "true", Value::Strand(v) => v.eq_ignore_ascii_case("true"),
_ => false, _ => false,
} }
} }
@ -505,7 +506,7 @@ impl Value {
pub fn is_false(&self) -> bool { pub fn is_false(&self) -> bool {
match self { match self {
Value::False => true, Value::False => true,
Value::Strand(v) => v.to_ascii_lowercase() == "false", Value::Strand(v) => v.eq_ignore_ascii_case("false"),
_ => false, _ => false,
} }
} }
@ -518,7 +519,7 @@ impl Value {
Value::Geometry(_) => true, Value::Geometry(_) => true,
Value::Array(v) => !v.is_empty(), Value::Array(v) => !v.is_empty(),
Value::Object(v) => !v.is_empty(), Value::Object(v) => !v.is_empty(),
Value::Strand(v) => !v.is_empty() && v.to_ascii_lowercase() != "false", Value::Strand(v) => !v.is_empty() && !v.eq_ignore_ascii_case("false"),
Value::Number(v) => v.is_truthy(), Value::Number(v) => v.is_truthy(),
Value::Duration(v) => v.as_nanos() > 0, Value::Duration(v) => v.as_nanos() > 0,
Value::Datetime(v) => v.timestamp() > 0, Value::Datetime(v) => v.timestamp() > 0,
@ -556,25 +557,25 @@ impl Value {
pub fn is_type_geometry(&self, types: &[String]) -> bool { pub fn is_type_geometry(&self, types: &[String]) -> bool {
match self { match self {
Value::Geometry(Geometry::Point(_)) => { Value::Geometry(Geometry::Point(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "point") types.iter().any(|t| matches!(t.as_str(), "feature" | "point"))
} }
Value::Geometry(Geometry::Line(_)) => { Value::Geometry(Geometry::Line(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "line") types.iter().any(|t| matches!(t.as_str(), "feature" | "line"))
} }
Value::Geometry(Geometry::Polygon(_)) => { Value::Geometry(Geometry::Polygon(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "polygon") types.iter().any(|t| matches!(t.as_str(), "feature" | "polygon"))
} }
Value::Geometry(Geometry::MultiPoint(_)) => { Value::Geometry(Geometry::MultiPoint(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "multipoint") types.iter().any(|t| matches!(t.as_str(), "feature" | "multipoint"))
} }
Value::Geometry(Geometry::MultiLine(_)) => { Value::Geometry(Geometry::MultiLine(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "multiline") types.iter().any(|t| matches!(t.as_str(), "feature" | "multiline"))
} }
Value::Geometry(Geometry::MultiPolygon(_)) => { Value::Geometry(Geometry::MultiPolygon(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "multipolygon") types.iter().any(|t| matches!(t.as_str(), "feature" | "multipolygon"))
} }
Value::Geometry(Geometry::Collection(_)) => { Value::Geometry(Geometry::Collection(_)) => {
types.iter().any(|t| &t[..] == "feature" || &t[..] == "collection") types.iter().any(|t| matches!(t.as_str(), "feature" | "collection"))
} }
_ => false, _ => false,
} }