Refactor and optimize functions and Value operators (#80)
This commit is contained in:
parent
5ca3b74e59
commit
8f6d21c1fc
8 changed files with 55 additions and 160 deletions
|
@ -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
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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!(),
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue