use serialize::{Condition, Constraint, ConstraintValue, FinalType, Operator, QueryTree};
use crate::{
operations::serialize::JsonObject,
utils::{sql_ilike, sql_like},
};
pub mod display;
pub mod serialize;
impl FinalType {
pub fn compare(&self, other: &FinalType, operator: &Operator) -> bool {
match operator {
Operator::Equal => self.equals(other),
Operator::LessThan => self.less_than(other),
Operator::GreaterThan => self.greater_than(other),
Operator::LessThanOrEqual => self.less_than_or_equal(other),
Operator::GreaterThanOrEqual => self.greater_than_or_equal(other),
Operator::NotEqual => !self.equals(other),
Operator::Like => match (self, other) {
(FinalType::String(s), FinalType::String(t)) => sql_like(t, s),
_ => false,
},
Operator::ILike => match (self, other) {
(FinalType::String(s), FinalType::String(t)) => sql_ilike(t, s),
_ => false,
},
_ => panic!("Invalid operator {} for comparison", operator),
}
}
pub fn equals(&self, other: &FinalType) -> bool {
match (self, other) {
(FinalType::Number(n), FinalType::Number(m)) => {
if n.is_f64() && m.is_f64() {
n.as_f64().unwrap() == m.as_f64().unwrap()
} else if n.is_i64() && m.is_i64() {
n.as_i64().unwrap() == m.as_i64().unwrap()
} else {
false
}
}
(FinalType::String(s), FinalType::String(t)) => s == t,
(FinalType::Bool(b), FinalType::Bool(c)) => b == c,
(FinalType::Null, FinalType::Null) => true,
_ => false,
}
}
pub fn less_than(&self, other: &FinalType) -> bool {
match (self, other) {
(FinalType::Number(n), FinalType::Number(m)) => {
if n.is_f64() && m.is_f64() {
n.as_f64().unwrap() < m.as_f64().unwrap()
} else if n.is_i64() && m.is_i64() {
n.as_i64().unwrap() < m.as_i64().unwrap()
} else {
false
}
}
(FinalType::String(s), FinalType::String(t)) => s < t,
(FinalType::Bool(b), FinalType::Bool(c)) => b < c,
_ => false,
}
}
pub fn greater_than(&self, other: &FinalType) -> bool {
match (self, other) {
(FinalType::Number(n), FinalType::Number(m)) => {
if n.is_f64() && m.is_f64() {
n.as_f64().unwrap() > m.as_f64().unwrap()
} else if n.is_i64() && m.is_i64() {
n.as_i64().unwrap() > m.as_i64().unwrap()
} else {
false
}
}
(FinalType::String(s), FinalType::String(t)) => s > t,
(FinalType::Bool(b), FinalType::Bool(c)) => b > c,
_ => false,
}
}
pub fn less_than_or_equal(&self, other: &FinalType) -> bool {
self.less_than(other) || self.equals(other)
}
pub fn greater_than_or_equal(&self, other: &FinalType) -> bool {
self.greater_than(other) || self.equals(other)
}
}
impl ConstraintValue {
pub fn compare(&self, other: &FinalType, operator: &Operator) -> bool {
match self {
ConstraintValue::Final(final_type) => final_type.compare(other, operator),
ConstraintValue::List(list) => match operator {
Operator::In => {
for value in list {
if value.compare(other, &Operator::Equal) {
return true;
}
}
false
}
_ => panic!("Invalid operator {} for list comparison", operator),
},
}
}
}
pub trait Checkable {
fn check(&self, object: &JsonObject) -> bool;
}
impl Checkable for Constraint {
fn check(&self, object: &JsonObject) -> bool {
let value = object
.get(&self.column)
.expect("Column not found in JSON object");
let final_type = FinalType::try_from(value.clone())
.expect(format!("Incompatible value for column: {value}").as_str());
self.value.compare(&final_type, &self.operator)
}
}
impl Checkable for Condition {
fn check(&self, object: &JsonObject) -> bool {
match self {
Condition::Single { constraint } => constraint.check(object),
Condition::And { conditions } => {
for condition in conditions {
if !condition.check(object) {
return false;
}
}
true
}
Condition::Or { conditions } => {
for condition in conditions {
if condition.check(object) {
return true;
}
}
false
}
}
}
}
impl Checkable for QueryTree {
fn check(&self, object: &JsonObject) -> bool {
if let Some(condition) = &self.condition {
condition.check(object)
} else {
true
}
}
}